为什么这个支持Ruby SSL的服务器/客户端测试有效?

时间:2011-10-25 17:08:27

标签: ruby ssl

我正在努力在Ruby中创建一个支持SSL的服务器,以及一个与服务器一起使用的相应Ruby客户端。为了测试,我使用以下命令创建了自己的根CA证书。

$:~/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的客户端,以确保它被拒绝连接。

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

为什么这样做?我假设它会失败,因为我不认为客户端会对我创建的根CA有任何想法并签署服务器SSL证书,因此无法验证服务器的证书。我错过了什么?当我创建并签署服务器的证书并且它已“提交”时,是否以某种方式将其提供给OpenSSL库?我希望不得不以某种方式告诉客户端中的SSL上下文在哪里查找我为测试目的而创建的根CA ...

作为后续测试,我将客户端代码复制到另一台机器上,该机器对我为此测试创建的根CA一无所知,更改了客户端连接的IP地址,并再次运行测试。此测试产生了相同的结果 - 当我认为客户端无法与服务器通信时,客户端能够与服务器进行通信。有什么想法吗?

1 个答案:

答案 0 :(得分:5)

根据您使用的Ruby版本,SSLContext对象的默认验证模式可能不会强制执行证书验证。您可以使用以下命令强制验证模式:

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

这会导致客户端的连接尝试失败,如预期的那样。