Fix for “sslv3 alert handshake failure (OpenSSL::SSL::SSLError)”

If you are using the ruby httpclient library (v2.1.2) and getting an SSL error similar to

/path/to/httpclient-2.1.2/lib/httpclient.rb:1039:in `connect': sslv3 alert handshake failure (OpenSSL::SSL::SSLError)

then there are (at least) two possible solutions to this.

Solution #1

If you are accessing a secure site (https://) that works fine in your browser and doesn’t give you any authentication warnings, then try setting the ciphers property of the HTTPClient#ssl_config instance to ‘ALL’. Specifically,

client = HTTPClient.new
client.ssl_config.ciphers = 'ALL'
response = client.get 'https://www.example.com/'

If that fixes the problem, then find the default value of @ciphers within your local /path/to/httpclient-2.1.2/lib/httpclient.rb file and adjust it to a less insecure value in your code. For example, line 162 of my /usr/local/lib/ruby/gems/1.8/gems/httpclient-2.1.2/lib/httpclient.rb is

    @ciphers = "ALL:!ADH:!LOW:!EXP:!MD5:+SSLv2:@STRENGTH"

After verifying that setting client.ssl_config.ciphers = ‘ALL’ fixed the problem, I experimented with the default setting above and found that leaving off only the “:!MD5″ option from the cipher string fixed the problem, without sacrificing any additional security:

client = HTTPClient.new
client.ssl_config.ciphers = 'ALL:!ADH:!LOW:!EXP:+SSLv2:@STRENGTH'
response = client.get 'https://www.example.com/'

Presumably the author of httpclient disabled security protocols that use MD5 due to the discovery of its weaknesses over the past decade. However if the website you are connecting to offers no other option, and the security risk is worth the value obtained in the transmissions, then this is how to enable it.

Solution #2

If you are accessing a secure site (https://) that you are the administrator of, and it doesn’t have its SSL server certificate signed by a trusted certificate authority (CA), then you will need to sign it yourself and pass the public key of the CA to HTTPClient. Here’s how to generate the server key, sign it, and pass it to HTTPClient:

# Generate the public/private key
openssl req -new -x509 -days 3652 -nodes \
-out yoursite.example.com.pem \
-keyout yoursite.example.com.pem
# Self-sign and export the public key
openssl x509 -days 3652 \
-in yoursite.example.com.pem \
-signkey yoursite.example.com.pem \
-out yoursite.example.com.crt
# Note the following fingerprint, and
# compare it when verifying it through your browser.
openssl x509 -fingerprint < yoursite.example.com.crt

The yoursite.example.com.pem needs to be installed in a secure location on the server, and the web server needs to be told where to find it. Copy the yoursite.example.com.crt file to your client machine. HTTPClient can use it via

client = HTTPClient.new
client.ssl_config.set_trust_ca('yoursite.example.com.crt')
response = client.get 'https://yoursite.example.com/'

This should fix the error, assuming this issue was the source of it. The “sslv3 alert handshake failure” is a rather generic error message, so it is quite possible it can be caused by other issues not covered here.

Disclaimer: The above two recipes are not intended to guarantee security once implemented. In general, the only way to achieve security in a system is for the administrator to understand the underlying security protocols, and use these tools as appropriate. Bruce Schneier’s Applied Cryptography is a very good place to start.

Share:
  • del.icio.us
  • Reddit
  • Technorati
  • Twitter
  • Facebook
  • Google Bookmarks
  • HackerNews
  • PDF
  • RSS
This entry was posted in programming and tagged , , , , . Bookmark the permalink. Post a comment or leave a trackback: Trackback URL.