How to Set Tls Context Options in Ruby (Like Openssl::Ssl::Ssl_Op_No_Sslv2)

How to set TLS context options in Ruby (like OpenSSL::SSL::SSL_OP_NO_SSLv2)

In the Ruby OpenSSL library the option constants aren't prefixed with 'SSL_'. You can see a list of the option constants by running something like this in irb/console: OpenSSL::SSL.constants.grep(/OP_/). Here is the relevant ruby C source where they are defined: https://github.com/ruby/ruby/blob/trunk/ext/openssl/ossl_ssl.c#L2225.

Edit:
There doesn't appear to be a way, out of the box, to set the SSL options for net http.
See https://bugs.ruby-lang.org/issues/9450.

However for the time being you can use this little hack:

(Net::HTTP::SSL_IVNAMES << :@ssl_options).uniq!
(Net::HTTP::SSL_ATTRIBUTES << :options).uniq!

Net::HTTP.class_eval do
attr_accessor :ssl_options
end

Now just set the ssl_options accessor on the instance of Net::HTTP. Example usage:

uri = URI('https://google.com:443')

options_mask = OpenSSL::SSL::OP_NO_SSLv2 + OpenSSL::SSL::OP_NO_SSLv3 +
OpenSSL::SSL::OP_NO_COMPRESSION

http = Net::HTTP.new(uri.host, uri.port)
request = Net::HTTP::Get.new(uri.request_uri)

if uri.scheme == "https"
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
http.ssl_options = options_mask
end

response = http.request request

# To Test
ssl_context = http.instance_variable_get(:@ssl_context)
ssl_context.options == options_mask # => true

I was testing with ruby 2.1.2 so your mileage on other versions of ruby may vary. Let me know if it doesn't work on your preferred version.

For those interested, the relevant part of the ruby code I looked at to create this hack: https://github.com/ruby/ruby/blob/e9dce8d1b482200685996f64cc2c3bd6ba790110/lib/net/http.rb#L886

How to set SSLContext options in Ruby

Example:

ctx = OpenSSL::SSL::SSLContext.new

ctx.set_params(:options => OpenSSL::SSL::OP_EPHEMERAL_RSA | OpenSSL::SSL::OP_NO_SSLv2)
# or
ctx.options = OpenSSL::SSL::OP_EPHEMERAL_RSA | OpenSSL::SSL::OP_NO_SSLv2

Getting OpenSSL::SSL::SSLError: SSL_set_tlsext_host_name when trying to make a post request through https

http.ssl_version = 'SSLv2'

Server Name Indication, or SNI, is a TLS extension. Extensions were not available until TLS 1.0.

And SSLv2 is insecure. You should probably avoid it (and SSLv3) in 2015. Also see How to set TLS context options in Ruby (like OpenSSL::SSL::SSL_OP_NO_SSLv2).

OpenSSL::SSL::SSLContext SNI servername_cb Not Working

Naturally you use the undocumented 'hostname' method for OpenSSL::SSLSocket!

tcp_client = TCPSocket.new("#{instance["domain"]}", 443)
ssl_context = OpenSSL::SSL::SSLContext.new()
ssl_context.ssl_version = :TLSv1
ssl_client = OpenSSL::SSL::SSLSocket.new(tcp_client, ssl_context)
ssl_client.hostname = instance["domain"]
ssl_client.connect
cert = OpenSSL::X509::Certificate.new(ssl_client.peer_cert)
ssl_client.sysclose
tcp_client.close

I discovered that here while writing code with a similar goal.

Ruby not getting any cipher from openssl

With newer Ruby versions (>= 2.4), and when using OpenSSL 1.1 or newer, Ruby doesn't explicitly override OpenSSL's default set of ciphers anymore as was done in previous versions. Previously, this was necessary since older OpenSSL versions included some insecure ciphers by default.

With newer versions, Ruby relies on OpenSSL's default ciphers unless explicitly overwritten by yourself. You can get those by e.g. running openssl ciphers -v 'DEFAULT:!PSK:!SRP' on your shell.

This behavior was changed (and explained) in the respective pull request at https://github.com/ruby/openssl/pull/66.

Use Client Cert and TLS_RSA_WITH_AES_256_CBC_SHA and other cipher suites

They ciphers they support are:

TLS_RSA_WITH_AES_256_CBC_SHA
SSL_RSA_WITH_3DES_EDE_CBC_SHA
TLS_RSA_WITH_AES_128_CBC_SHA

And:

http.ciphers = ['need-to-figure-out']

You can map the IANA cipher suite names like TLS_RSA_WITH_AES_128_CBC_SHA, to OpenSSL cipher string names, like AES128-SHA, using the openssl ciphers man page. Its a simple lookup - just search the page for the IANA registry name and you will land on OpenSSL's name eventually.

I believe the cipher string you should use is:

http.ciphers = ["AES256-SHA:AES128-SHA:DES-CBC3-SHA"]

... does anyone know what I can change http.ssl_version = :TLSv1_2 ... to make it also allow TLSv3?

For this in OpenSSL, you need to set context options. In Ruby, you need to set OpenSSL::SSL::SSL_OP_NO_SSLv2 throughOpenSSL::SSL::SSL_OP_NO_TLSv1_1. That will leave TLS 1.2 and TLS 1.3 (when TLS 1.3 becomes available). Also see How to set TLS context options in Ruby (like OpenSSL::SSL::SSL_OP_NO_SSLv2).

The TLS_RSA_WITH_* schemes are RSA key transport schemes. TLS 1.3 will not offer them. They have been removed in favor of schemes that provide forward secrecy. Schemes that provide forward secrecy are the Diffie-Hellman ones, like TLS_DHE_* and TLS_ECDHE_*.

Even the banking industry could not get the IETF to change the decision. Hat's off to the IETF for holding their ground. I think they are a bit too accommodating at times and that often leads to weaker security. But I think they made the right decision in the post-Snowed era, where we have a good idea of the extent of the snooping and spying.

Change ssl version with Net::HTTP and Ruby 1.8.7

In fact, it seems that the client is switching to TLSv1 if the server doesn't support SSLv3

It is more the other way around. Inside the SSL handshake the client shows to the server what it can (protocol, ciphers) and the server then picks from this the best it can too. Usually the client is just defaulting to SSLv23 which does not restrict the client itself to a specific protocol. If the server then offers TLSv1 they will continue with it, if the server only offers SSLv3 they will use SSL 3.0.

If you want to restrict the client to pick the best but not allowing SSL 3.0 anymore have a look at https://stackoverflow.com/a/24237525/3081018 on how to disable SSLv3 by setting the ssl_options.



Related Topics



Leave a reply



Submit