2011-10-25 32 views
6

Tôi đang làm việc thông qua việc tạo một máy chủ hỗ trợ SSL trong Ruby, cùng với một máy khách Ruby tương ứng để sử dụng với máy chủ. Để kiểm tra, tôi đã tạo chứng chỉ Root CA của riêng mình bằng các lệnh sau.Tại sao thử nghiệm máy chủ/máy khách hỗ trợ SSL SSL này hoạt động?

$:~/devel/ssl-test/ssl/CA$ openssl genrsa -out TestCA.key 2048 
Generating RSA private key, 2048 bit long modulus 
............+++ 
...........................+++ 
e is 65537 (0x10001) 

$:~/devel/ssl-test/ssl/CA$ openssl req -new -key TestCA.key -out TestCA.csr 
You are about to be asked to enter information that will be incorporated 
into your certificate request. 
What you are about to enter is what is called a Distinguished Name or a DN. 
There are quite a few fields but you can leave some blank 
For some fields there will be a default value, 
If you enter '.', the field will be left blank. 
----- 
Country Name (2 letter code) [AU]: 
State or Province Name (full name) [Some-State]: 
Locality Name (eg, city) []: 
Organization Name (eg, company) [Internet Widgits Pty Ltd]: 
Organizational Unit Name (eg, section) []: 
Common Name (eg, YOUR name) []: 
Email Address []: 

Please enter the following 'extra' attributes 
to be sent with your certificate request 
A challenge password []: 
An optional company name []: 

$:~/devel/ssl-test/ssl/CA$ openssl x509 -req -days 365 -in TestCA.csr -out TestCA.crt -signkey TestCA.key 
Signature ok 
subject=/C=AU/ST=Some-State/O=Internet Widgits Pty Ltd 
Getting Private key 

sau đó tôi tạo ra một chứng chỉ SSL cho máy chủ của tôi:

$:~/devel/ssl-test/ssl/keys$ openssl genrsa -out server.key 2048 
Generating RSA private key, 2048 bit long modulus 
.+++ 
............................................+++ 
e is 65537 (0x10001) 

$:~/devel/ssl-test/ssl/keys$ cd ../csrs/ 
$:~/devel/ssl-test/ssl/csrs$ openssl req -new -key ../keys/server.key -out server.csr 
You are about to be asked to enter information that will be incorporated 
into your certificate request. 
What you are about to enter is what is called a Distinguished Name or a DN. 
There are quite a few fields but you can leave some blank 
For some fields there will be a default value, 
If you enter '.', the field will be left blank. 
----- 
Country Name (2 letter code) [AU]: 
State or Province Name (full name) [Some-State]: 
Locality Name (eg, city) []: 
Organization Name (eg, company) [Internet Widgits Pty Ltd]: 
Organizational Unit Name (eg, section) []: 
Common Name (eg, YOUR name) []:my.secure.test 
Email Address []: 

Please enter the following 'extra' attributes 
to be sent with your certificate request 
A challenge password []: 
An optional company name []: 
$:~/devel/ssl-test/ssl/csrs$ cd ../certs/ 
$:~/devel/ssl-test/ssl/certs$ openssl ca -in ../csrs/server.csr -cert ../CA/TestCA.crt -keyfile ../CA/TestCA.key -out server.crt 
Using configuration from /usr/lib/ssl/openssl.cnf 
I am unable to access the ./demoCA/newcerts directory 
./demoCA/newcerts: No such file or directory 
$:~/devel/ssl-test/ssl/certs$ mkdir -p demoCA/newcerts 
$:~/devel/ssl-test/ssl/certs$ touch demoCA/index.txt 
$:~/devel/ssl-test/ssl/certs$ echo "01" > demoCA/serial 
$:~/devel/ssl-test/ssl/certs$ openssl ca -in ../csrs/server.csr -cert ../CA/TestCA.crt -keyfile ../CA/TestCA.key -out server.crt 
Using configuration from /usr/lib/ssl/openssl.cnf 
Check that the request matches the signature 
Signature ok 
Certificate Details: 
     Serial Number: 1 (0x1) 
     Validity 
      Not Before: Oct 25 16:25:05 2011 GMT 
      Not After : Oct 24 16:25:05 2012 GMT 
     Subject: 
      countryName    = AU 
      stateOrProvinceName  = Some-State 
      organizationName   = Internet Widgits Pty Ltd 
      commonName    = my.secure.test 
     X509v3 extensions: 
      X509v3 Basic Constraints: 
       CA:FALSE 
      Netscape Comment: 
       OpenSSL Generated Certificate 
      X509v3 Subject Key Identifier: 
       48:50:B5:04:11:02:F1:40:97:58:BF:5F:8B:27:50:10:C0:3F:EE:D9 
      X509v3 Authority Key Identifier: 
       DirName:/C=AU/ST=Some-State/O=Internet Widgits Pty Ltd 
       serial:81:44:16:06:5C:EB:5E:71 

Certificate is to be certified until Oct 24 16:25:05 2012 GMT (365 days) 
Sign the certificate? [y/n]:y 


1 out of 1 certificate requests certified, commit? [y/n]y 
Write out database with 1 new entries 
Data Base Updated 

Sau đó, tôi đã tạo ra một máy chủ SSL-kích hoạt đơn giản để sử dụng chứng chỉ SSL tôi vừa tạo ra.

require 'socket' 
require 'openssl' 
require 'thread' 

server = TCPServer.new(1337) 
context = OpenSSL::SSL::SSLContext.new 

context.cert = OpenSSL::X509::Certificate.new(File.open('ssl/certs/server.crt')) 
context.key = OpenSSL::PKey::RSA.new(File.open('ssl/keys/server.key')) 

secure = OpenSSL::SSL::SSLServer.new(server, context) 

puts 'Listening securely on port 1337...' 

loop do 
    Thread.new(secure.accept) do |conn| 
    begin 
     while request = conn.gets 
     $stdout.puts '=> ' + request 
     response = "You said: #{request}" 
     $stdout.puts '<= ' + response 
     conn.puts response 
     end 
    rescue 
     $stderr.puts $! 
    end 
    end 
end 

Khi bắt đầu, có vẻ như để làm việc tốt ...

$:~/devel/ssl-test$ ruby server.rb 
Listening securely on port 1337... 

Sau đó tôi tạo một tổ chức phi SSL client có khả năng chỉ để đảm bảo nó đã bị từ chối kết nối.

require 'socket' 
require 'thread' 

client = TCPSocket.new('127.0.0.1', 1337) 

Thread.new do 
    begin 
    while response = client.gets 
     $stdout.puts response 
    end 
    rescue 
    $stderr.puts "Error from client: #{$!}" 
    end 
end 

while request = $stdin.gets 
    request = request.chomp 
    client.puts request 
end 

Khi tôi chạy qua như sau:

$:~/devel/ssl-test$ ruby client.rb 
hello 
Error from client: Connection reset by peer 

Vì lẽ đó, tôi nhận được những điều sau đây từ máy chủ:

$:~/devel/ssl-test$ ruby server.rb 
Listening securely on port 1337... 
/usr/local/rvm/rubies/ruby-1.9.2-head/lib/ruby/1.9.1/openssl/ssl-internal.rb:164:in `accept': SSL_accept returned=1 errno=0 state=SSLv2/v3 read client hello A: unknown protocol (OpenSSL::SSL::SSLError) 
    from /usr/local/rvm/rubies/ruby-1.9.2-head/lib/ruby/1.9.1/openssl/ssl-internal.rb:164:in `accept' 
    from server.rb:16:in `block in <main>' 
    from server.rb:15:in `loop' 
    from server.rb:15:in `<main>' 

này được tất cả mong đợi. Tiếp theo, tôi đã sửa đổi mã máy khách để sử dụng ngữ cảnh SSL.

require 'socket' 
require 'openssl' 
require 'thread' 

client = TCPSocket.new('127.0.0.1', 1337) 
context = OpenSSL::SSL::SSLContext.new 

secure = OpenSSL::SSL::SSLSocket.new(client, context) 
secure.sync_close = true 
secure.connect 

Thread.new do 
    begin 
    while response = secure.gets 
     $stdout.puts response 
    end 
    rescue 
    $stderr.puts "Error from client: #{$!}" 
    end 
end 

while request = $stdin.gets 
    request = request.chomp 
    secure.puts request 
end 

tôi mong đợi đầy đủ này thất bại cũng trong quá trình bắt tay, nhưng nó không ... Tôi có kết quả sau:

$:~/devel/ssl-test$ ruby client.rb 
hello 
You Said: hello 

Tại sao công việc này? Tôi đã giả định nó sẽ thất bại vì tôi không nghĩ rằng khách hàng sẽ có bất kỳ ý tưởng về Root CA tôi tạo ra và ký chứng chỉ SSL máy chủ với, và do đó sẽ không thể xác minh chứng chỉ của máy chủ. Tôi đang thiếu gì? Khi tôi tạo và ký chứng chỉ của máy chủ và nó đã được "cam kết", đã làm điều này bằng cách nào đó làm cho nó có sẵn cho thư viện OpenSSL? Tôi đã mong đợi phải bằng cách nào đó nói cho bối cảnh SSL trong khách hàng nơi để tìm CA gốc tôi tạo ra cho mục đích thử nghiệm ...

Như một bài kiểm tra tiếp theo, tôi sao chép mã khách hàng của tôi sang một máy khác chắc chắn không biết gì về Root CA mà tôi đã tạo cho bài kiểm tra này, đã thay đổi địa chỉ IP mà máy khách kết nối và chạy lại kiểm tra. Thử nghiệm này tạo ra kết quả tương tự - khách hàng có thể giao tiếp với máy chủ khi tôi cho rằng nó sẽ không thể. Bất kỳ ý tưởng?

Trả lời

5

Tùy thuộc vào phiên bản Ruby bạn đang sử dụng, chế độ xác minh mặc định cho đối tượng SSLContext có thể không thực thi xác minh chứng chỉ. Bạn có thể buộc chế độ xác minh bằng:

context = OpenSSL::SSL::SSLContext.new 
context.verify_mode = OpenSSL::SSL::VERIFY_PEER | OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT

Điều này sẽ làm cho kết nối của khách hàng thất bại, như mong đợi.

+0

Ah vâng, điều đó đã xảy ra. Cảm ơn Ian! Bây giờ, tôi phải làm gì để thông báo cho bối cảnh SSL trong máy khách về nơi để tìm Root CA tùy chỉnh của tôi sao cho chứng chỉ của máy chủ có thể được xác minh? – Bryan

+0

Rất kỳ quặc, theo http://rubydoc.info/stdlib/openssl/1.9.2/OpenSSL/SSL/SSLContext#DEFAULT_PARAMS-constant VERIFY_PEER phải là tham số mặc định, nhưng dường như các giá trị mặc định không được áp dụng đúng. –

+0

@Bryan Bạn sẽ muốn sử dụng cài đặt 'ca_file' hoặc' ca_path' trên đối tượng 'SSLContext'. 'ca_file' có lẽ là dễ nhất vì bạn chỉ trỏ nó vào tệp .pem, hoặc bạn có gì. 'ca_path' yêu cầu một thư mục được hash băm đúng cách. Tôi đã không làm điều đó trong một thời gian nhưng tôi sẽ xem nếu tôi có thể đào lên một liên kết trên đó. –

Các vấn đề liên quan