2011-10-25 5 views
6

私は、RubyでSSL対応のサーバーを作成し、サーバーで使用する対応するRubyクライアントを作成しています。テストするために、私は自分のルートCA証明書を次のコマンドで作成しました。私は、私が作成したSSL証明書を使用するには、単純なSSL対応のサーバーを作成し、その後このRuby 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 

$:~/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証明書を生成しました。

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 

始めたとき、私はその後、ちょうどそれは接続を拒否されたことを確認するために、非SSL対応のクライアントを作成し

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

...正常に動作するようです。

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 client.rb 
hello 
Error from client: Connection reset by peer 

対応して、私は、サーバーから、次を得る:

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

を?クライアントがサーバーSSL証明書を作成して署名したルートCAについて考えていないと思ってサーバーの証明書を確認できないため、失敗すると想定していました。私は何が欠けていますか?サーバーの証明書を作成して署名し、それが「コミット」されたとき、これは何とかOpenSSLライブラリで利用できるようにしましたか?私は何らかの理由でクライアントのSSLコンテキストを伝えて、テスト目的のために作成したルート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

ああ、そのトリックでした。ありがとうイアン!今、サーバーの証明書を検証できるように自分のカスタムルートCAを探す場所についてクライアントのSSLコンテキストに通知するにはどうすればよいですか? – 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によって適切にハッシュされたディレクトリを必要とします。私はしばらくそれをしていないが、私はそれにリンクを掘ることができるかどうかがわかります。 –

関連する問題