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

发布于 2024-12-11 14:16:39 字数 7136 浏览 0 评论 0原文

我正在用 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

为什么会起作用?我假设它会失败,因为我认为客户端不会了解我创建并签署服务器 SSL 证书的根 CA,因此无法验证服务器的证书。我缺少什么?当我创建并签署服务器的证书并且它被“提交”时,这是否以某种方式使其可供 OpenSSL 库使用?我期望必须以某种方式告诉客户端中的 SSL 上下文在哪里查找我为测试目的而创建的根 CA...

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

I'm working through creating an SSL-enabled server in Ruby, along with a corresponding Ruby client to use with the server. In order to test, I created my own Root CA certificate with the following commands.

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

I then generated an SSL certificate for my server:

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

After that, I created a simplistic SSL-enabled server to use the SSL certificate I just created.

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

When started, it seems to work fine...

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

I then created a non-SSL capable client just to ensure it was denied connectivity.

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

When I run this via the following:

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

Correspondingly, I get the following from the server:

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

This was all expected. Next, I modified the client code to use an SSL context.

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

I fully expected this to fail as well during the handshake process, but it did not... I got the following result:

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

Why did this work? I was assuming it would fail because I didn't think the client would have any idea about the Root CA I created and signed the server SSL certificate with, and therefore wouldn't be able to verify the server's certificate. What am I missing? When I created and signed the server's certificate and it was "committed", did this somehow make it available to the OpenSSL library? I was expecting to have to somehow tell the SSL context in the client where to look for the Root CA I created for testing purposes...

As a follow-up test, I copied my client code over to a different machine that definitely knows nothing about the Root CA I created for this test, changed the IP address the client connects to, and ran the test again. This test produced the same results - the client was able to communicate with the server when I assumed it wouldn't be able to. Any ideas?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

沧桑㈠ 2024-12-18 14:16:39

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

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

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

Depending on the version of Ruby you are using, the default verify mode for the SSLContext object may not be enforcing certificate verification. You can force the verify mode with:

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

This should cause the client's connection attempt to fail, as expected.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文