为什么这个支持 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
为什么会起作用?我假设它会失败,因为我认为客户端不会了解我创建并签署服务器 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
根据您使用的 Ruby 版本,SSLContext 对象的默认验证模式可能不会强制执行证书验证。您可以通过以下方式强制验证模式:
这应该会导致客户端的连接尝试失败,如预期的那样。
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:
This should cause the client's connection attempt to fail, as expected.