2011-10-25 27 views
6

我正在通過在Ruby中創建一個啓用了SSL的服務器,以及與服務器一起使用相應的Ruby客戶端。爲了測試,我使用以下命令創建了自己的根CA證書。爲什麼這個啓用Ruby SSL的服務器/客戶端測試工作?

$:~/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 

然後我產生了我的服務器的SSL證書:

$:~/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 

在那之後,我創建了一個簡單的啓用了SSL的服務器使用我剛剛創建的SSL證書。

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 

啓動時,它似乎好工作......

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

然後我創建了一個非SSL的客戶端只是爲了確保它被拒絕連接。相應地

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

,我得到了來自服務器的以下內容::

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 

當我通過以下運行此

$:~/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>' 

這是所有預期。接下來,我修改了客戶端代碼以使用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 

我完全可以預料在握手過程中這也失敗,但它沒有...我得到以下結果:

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

爲什麼這項工作?我認爲它會失敗,因爲我不認爲客戶端會對我創建的根CA以及服務器SSL證書籤名有任何想法,因此無法驗證服務器的證書。我錯過了什麼?當我創建並簽署了服務器的證書並且它已被「提交」時,是否以某種方式將它提供給OpenSSL庫?我期待不得不告訴客戶端在哪裏尋找我爲測試目的而創建的根CA的上下文...

作爲後續測試,我將客戶端代碼複製到另一臺機器上那對我爲此測試創建的根CA完全一無所知,改變了客戶端連接到的IP地址,並再次運行測試。該測試產生了相同的結果 - 當我認爲客戶端無法與服務器進行通信時,客戶端能夠與服務器進行通信。有任何想法嗎?

回答

5

根據您使用的Ruby版本,SSLContext對象的默認驗證模式可能不會執行證書驗證。您可以強制驗證模式:

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

這應該會導致客戶端的連接嘗試失敗,如預期的那樣。

+0

啊,是的,這是訣竅。謝謝伊恩!現在,我該怎麼做才能通知客戶端的SSL上下文關於在哪裏查找我的自定義根CA,以便可以驗證服務器的證書? – Bryan

+0

奇怪的是,根據http://rubydoc.info/stdlib/openssl/1.9.2/OpenSSL/SSL/SSLContext#DEFAULT_PARAMS-constant VERIFY_PEER應該是一個默認參數,但顯然默認值沒有正確應用。 –

+0

@Bryan你會想要在'SSLContext'對象上使用'ca_file'或'ca_path'設置。 'ca_file'可能是最簡單的,因爲你只需將它指向.pem文件,或者你有什麼。 'ca_path'需要一個被openssl正確散列的目錄。我有一段時間沒有這樣做,但我會看看我能否挖掘出一個鏈接。 –

相關問題