Why does this Ruby SSL server / client test work?

I am working on creating an SSL-enabled server in Ruby with the appropriate Ruby client for use with the server. For testing, I created my own CA root 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 

Then I 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 simplified server with SSL support to use the newly created SSL certificate.

 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 it is running, it is working fine ...

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

Then I created a client that does not support SSL to make sure that it was denied a connection.

 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 ran this, follow these steps:

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

Accordingly, 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>' 

All of this was expected. Then I changed the client code to use the 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 that this would also fail during the handshake process, but this is not ... I got the following result:

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

Why did it work? I assumed that this would fail, because I did not think that the client would have an idea of ​​the Root CA that I created and signed the SSL server certificate, and therefore could not verify the server certificate. What am I missing? When I created and signed the server certificate and it was β€œcommitted”, did it somehow make it available for the OpenSSL library? I expected that I should somehow specify the SSL context in the client, where to look for the Root CA that I created for testing purposes ...

As a follow-up test, I copied my client code to another machine that definitely does not know anything about the root CA created for this test, changed the IP address to which the client connects, and ran the test again. This test gave the same results - the client was able to contact the server when I assumed that it could not. Any ideas?

+6
source share
1 answer

Depending on the version of Ruby you are using, the default validation mode for the SSLContext object cannot provide certificate validation. You can force the validation mode using:

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

This will result in a failed client connection attempt, as expected.

+5
source

Source: https://habr.com/ru/post/900066/


All Articles