13

I have a test environment that uses Ruby to drive a server over an https connection. Since the latest versions of Ruby refuse to connect to an https server with an invalid certificate (see this earlier question of mine) and I would like to start using a newer version of Ruby, I am trying to set up a valid certificate.

I have created a CA certificate to use (there are multiple servers being tested so this seems the easier way), and have successfully used it to sign a new certificate which has been installed on a server and is being used. I have added the CA certificate to the browser store and it (the browser) will now connect to the server without complaint. So I am confident my certificates are valid and set up correctly.

I know that Ruby does not use the same store as the browser. I have used the CA file available here to test connecting to other (public) servers (set using the Net::HTTP#ca_file= method) and this also works.

What I cannot get to work is Ruby connecting to my server using my certificate. I have tried various ways of pointing it at my certificate (including adding my certificate to the file linked above) and it always gives the same error:

SSL_connect SYSCALL returned=5 errno=0 state=SSLv2/v3 read server hello A (OpenSSL::SSL::SSLError)

What do I have to do to convince Ruby to accept my certificate and connect to my server?

The code I am using is:

require 'net/https'

uri = URI.parse("https://hostname/index.html")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
http.ca_file = "My CA cert file"
request = Net::HTTP::Get.new(uri.path)
response = http.request(request)

I'm assuming this is wrong somehow. What I want to know is, what should I do to use my CA certificate?

Community
  • 1
  • 1
Jonathan
  • 3,203
  • 2
  • 23
  • 25
  • You say you run your server with Ruby, too? Could you please post the relevant code snippets for client and server? – emboss Feb 12 '12 at 10:03
  • @emboss the server is not Ruby (it's actually tomcat although I don't think that matters). I'm not sure what code you would want to see. I'm just using the standard Ruby https library. – Jonathan Feb 13 '12 at 09:58
  • @Jonathan, pasting the client code that you are using to connect to your server would be a starting point. – Anand Shah Feb 13 '12 at 13:21

3 Answers3

21

I assume that your Tomcat doesn't like the protocol version that Ruby tries to negotiate. Ruby uses SSLv23 by default, but I've heard other cases where this was a problem for Java-based web servers. The error message you are getting indicates that the handshake fails while setting up the connection and trying to read the server's response. Try adding either

http.ssl_version = :TLSv1

or

http.ssl_version = :SSLv3

and see if that already helps.

If this does not fix the problem yet, it would be very interesting to see why your server rejects the connection attempt. Try running your Tomcat with -Djavax.net.debug=ssl and please post the relevant parts (connection information, exception stacktrace) as to why the attempt fails.

emboss
  • 38,880
  • 7
  • 101
  • 108
  • This works! Thank you so much. I knew it had to be something simple I was missing! – Jonathan Feb 13 '12 at 14:55
  • You're welcome! Actually, you could help me, too. I need to figure out whether this is a real bug on the Java side. Using SSLv23 on the client side is like telling the server "I can do any protocol you want me to, just name it", so Tomcat shouldn't have rejected in the first place. What exact Tomcat version are you using, which JDK? – emboss Feb 13 '12 at 15:10
  • Out of interest, if you happen to know, was this default changed recently? This problem only occurs with the latest releases (1.8.7-p352 and 1.9.2p290). Earlier versions are fine. – Jonathan Feb 13 '12 at 15:10
  • Java version is 1.6.0_05-b13. Tomcat version is 6.0.35. – Jonathan Feb 13 '12 at 15:13
  • @Jonathan Hmm, not that I know. Git blame says we use SSLv23 since 2003: https://github.com/ruby/ruby/blame/trunk/ext/openssl/ossl_ssl.c, L149. Could it be that you changed OpenSSL itself in the meantime? – emboss Feb 13 '12 at 15:26
  • @Jonathan Thanks for the version infos! – emboss Feb 13 '12 at 15:27
2

I am using ruby 1.9.3 and faced the same error while using nokogiri to parse some secure urls.

OpenSSL::SSL::SSLError: SSL_connect returned=1 errno=0 state=SSLv2/v3 read server hello A: (null)

The above answer provided by emboss is correct but make sure the ssl error generated is this one that is mentioned above. I have followed the same and found a solution like this mentioned below.

uri = URI(url)
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.ssl_version = :SSLv3
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
response = http.get(url)

now the response is having the correct html parsed for the secured url that is passed to the codes in the url .

Amit
  • 174
  • 1
  • 7
0

Make sure that the your certificate file is in PEM format, not CRT (so the documentation for Net::HTTP in Ruby 1.9.3 says).

Update it looks like the documentation is not up to date, Ruby 1.9.3 will accept any kind of certificate.

gioele
  • 9,748
  • 5
  • 55
  • 80
  • This doesn't matter. Ruby can deal with (bundled) PEM certificate files as well as with DER-encoded certificates. That's one of its convenient features actually, you don't need to care what format your certificates have. – emboss Feb 13 '12 at 14:37
  • The documentation says otherwise http://www.ruby-doc.org/stdlib-1.9.3/libdoc/net/http/rdoc/Net/HTTP.html#attribute-i-ca_file but I will believe you, I never tried with non-PEM certificates. – gioele Feb 13 '12 at 14:46
  • Oops, I'm sorry, then I need to update the documentation :) My bad, can you do a micro edit, so that I can take the downvote away? – emboss Feb 13 '12 at 14:59
  • I added a link to the documentation (I should have added it right from the beginning). – gioele Feb 13 '12 at 15:16