jruby / jruby-openssl

JRuby's OpenSSL gem
http://www.jruby.org
Other
45 stars 80 forks source link

jruby-openssl 0.9.7 enables EXPORT cipher suites by default, and it prefers them before better cipher suites #50

Open aetherknight opened 9 years ago

aetherknight commented 9 years ago

Out of the box, without calling set_params, jruby-openssl's SSLContext supports EXPORT cipher suites, and it prefers them over better cipher suites. Admittedly, MRI requires you to call set_params to remove all the cruft from the complete list of cipher suites (to get the Ruby defaults, not that this is well documented anywhere outside of https://www.ruby-lang.org/en/news/2014/10/27/changing-default-settings-of-ext-openssl/), but MRI no longer includes EXPORT cipher suites in the default cipher suite list (or perhaps this is due to newer OpenSSL versions).

I performed all of my MRI testing against openssl-1.0.1o.

JRuby 1.7.20.1 and jruby-openssl 0.9.7

$ java -version
java version "1.7.0_55"
Java(TM) SE Runtime Environment (build 1.7.0_55-b13)
Java HotSpot(TM) 64-Bit Server VM (build 24.55-b03, mixed mode)

$ jruby --version
jruby 1.7.20.1 (1.9.3p551) 2015-06-10 d7c8c27 on Java HotSpot(TM) 64-Bit Server VM 1.7.0_55-b13 +jit [darwin-x86_64]

$ jruby -ropenssl -e 'puts Jopenssl::Version::VERSION'
0.9.7

$ jruby -ropenssl -e 'OpenSSL::SSL::SSLContext.new.ciphers.each { |c| p c}'
["EXP-DES-CBC-SHA", "TLSv1/SSLv3", 40, 56]
["EXP-EDH-RSA-DES-CBC-SHA", "TLSv1/SSLv3", 40, 56]
["EXP-EDH-DSS-DES-CBC-SHA", "TLSv1/SSLv3", 40, 56]
["EXP-RC4-MD5", "TLSv1/SSLv3", 40, 128]
["DES-CBC-SHA", "TLSv1/SSLv3", 56, 56]
["EDH-RSA-DES-CBC-SHA", "TLSv1/SSLv3", 56, 56]
["ECDHE-ECDSA-AES128-SHA256", "TLSv1/SSLv3", 128, 256]
["ECDHE-RSA-AES128-SHA256", "TLSv1/SSLv3", 128, 256]
["ECDH-ECDSA-AES128-SHA256", "TLSv1/SSLv3", 128, 256]
["ECDH-RSA-AES128-SHA256", "TLSv1/SSLv3", 128, 256]
["ECDHE-ECDSA-AES128-SHA", "TLSv1/SSLv3", 128, 128]
["ECDHE-RSA-AES128-SHA", "TLSv1/SSLv3", 128, 128]
["AES128-SHA", "TLSv1/SSLv3", 128, 128]
["ECDH-ECDSA-AES128-SHA", "TLSv1/SSLv3", 128, 128]
["ECDH-RSA-AES128-SHA", "TLSv1/SSLv3", 128, 128]
["DHE-RSA-AES128-SHA", "TLSv1/SSLv3", 128, 128]
["DHE-DSS-AES128-SHA", "TLSv1/SSLv3", 128, 128]
["RC4-SHA", "TLSv1/SSLv3", 128, 128]
["RC4-MD5", "TLSv1/SSLv3", 128, 128]
["DES-CBC3-SHA", "TLSv1/SSLv3", 168, 168]
["EDH-RSA-DES-CBC3-SHA", "TLSv1/SSLv3", 168, 168]
["EDH-DSS-DES-CBC3-SHA", "TLSv1/SSLv3", 168, 168]
["ECDHE-ECDSA-AES256-SHA", "TLSv1/SSLv3", 256, 256]
["ECDHE-RSA-AES256-SHA", "TLSv1/SSLv3", 256, 256]
["AES256-SHA", "TLSv1/SSLv3", 256, 256]
["ECDH-ECDSA-AES256-SHA", "TLSv1/SSLv3", 256, 256]
["ECDH-RSA-AES256-SHA", "TLSv1/SSLv3", 256, 256]
["DHE-RSA-AES256-SHA", "TLSv1/SSLv3", 256, 256]
["DHE-DSS-AES256-SHA", "TLSv1/SSLv3", 256, 256]

To verify the cipher suite ordering, I ran the following command:

$ jruby -ropenssl -rsocket -e "context=OpenSSL::SSL::SSLContext.new;tcp=TCPSocket.new('www.aedifice.org',443);ssl=OpenSSL::SSL::SSLSocket.new(tcp,context);ssl.connect"

And I monitored my network traffic with wireshark: jruby-cipher-suite-ordering

This matches the order shown by OpenSSL::SSL::SSLContext.new.ciphers. It shows that it prefers export ciphers first, then single DES, then finally ECDHE cipher suites. In fact, the default ordering does not seem to follow any general guidelines for cipher suite ordering.

Expected Behavior

MRI 2.2.2

MRI unfortunately still supports bad cipher suites out of the box. However, it does not support EXPORT ciphers, and it prefers some good cipher suites before it gets into any older/bad cipher suites.

$ ruby --version
ruby 2.2.2p95 (2015-04-13 revision 50295) [x86_64-darwin14]

$ ruby -ropenssl -e 'context=OpenSSL::SSL::SSLContext.new; context.ciphers.each { |c| p c}'
["ECDHE-RSA-AES256-GCM-SHA384", "TLSv1/SSLv3", 256, 256]
["ECDHE-ECDSA-AES256-GCM-SHA384", "TLSv1/SSLv3", 256, 256]
["ECDHE-RSA-AES256-SHA384", "TLSv1/SSLv3", 256, 256]
["ECDHE-ECDSA-AES256-SHA384", "TLSv1/SSLv3", 256, 256]
["ECDHE-RSA-AES256-SHA", "TLSv1/SSLv3", 256, 256]
["ECDHE-ECDSA-AES256-SHA", "TLSv1/SSLv3", 256, 256]
["SRP-DSS-AES-256-CBC-SHA", "TLSv1/SSLv3", 256, 256]
["SRP-RSA-AES-256-CBC-SHA", "TLSv1/SSLv3", 256, 256]
["SRP-AES-256-CBC-SHA", "TLSv1/SSLv3", 256, 256]
["DHE-DSS-AES256-GCM-SHA384", "TLSv1/SSLv3", 256, 256]
["DHE-RSA-AES256-GCM-SHA384", "TLSv1/SSLv3", 256, 256]
["DHE-RSA-AES256-SHA256", "TLSv1/SSLv3", 256, 256]
["DHE-DSS-AES256-SHA256", "TLSv1/SSLv3", 256, 256]
["DHE-RSA-AES256-SHA", "TLSv1/SSLv3", 256, 256]
["DHE-DSS-AES256-SHA", "TLSv1/SSLv3", 256, 256]
["DHE-RSA-CAMELLIA256-SHA", "TLSv1/SSLv3", 256, 256]
["DHE-DSS-CAMELLIA256-SHA", "TLSv1/SSLv3", 256, 256]
["ECDH-RSA-AES256-GCM-SHA384", "TLSv1/SSLv3", 256, 256]
["ECDH-ECDSA-AES256-GCM-SHA384", "TLSv1/SSLv3", 256, 256]
["ECDH-RSA-AES256-SHA384", "TLSv1/SSLv3", 256, 256]
["ECDH-ECDSA-AES256-SHA384", "TLSv1/SSLv3", 256, 256]
["ECDH-RSA-AES256-SHA", "TLSv1/SSLv3", 256, 256]
["ECDH-ECDSA-AES256-SHA", "TLSv1/SSLv3", 256, 256]
["AES256-GCM-SHA384", "TLSv1/SSLv3", 256, 256]
["AES256-SHA256", "TLSv1/SSLv3", 256, 256]
["AES256-SHA", "TLSv1/SSLv3", 256, 256]
["CAMELLIA256-SHA", "TLSv1/SSLv3", 256, 256]
["PSK-AES256-CBC-SHA", "TLSv1/SSLv3", 256, 256]
["ECDHE-RSA-AES128-GCM-SHA256", "TLSv1/SSLv3", 128, 128]
["ECDHE-ECDSA-AES128-GCM-SHA256", "TLSv1/SSLv3", 128, 128]
["ECDHE-RSA-AES128-SHA256", "TLSv1/SSLv3", 128, 128]
["ECDHE-ECDSA-AES128-SHA256", "TLSv1/SSLv3", 128, 128]
["ECDHE-RSA-AES128-SHA", "TLSv1/SSLv3", 128, 128]
["ECDHE-ECDSA-AES128-SHA", "TLSv1/SSLv3", 128, 128]
["SRP-DSS-AES-128-CBC-SHA", "TLSv1/SSLv3", 128, 128]
["SRP-RSA-AES-128-CBC-SHA", "TLSv1/SSLv3", 128, 128]
["SRP-AES-128-CBC-SHA", "TLSv1/SSLv3", 128, 128]
["DHE-DSS-AES128-GCM-SHA256", "TLSv1/SSLv3", 128, 128]
["DHE-RSA-AES128-GCM-SHA256", "TLSv1/SSLv3", 128, 128]
["DHE-RSA-AES128-SHA256", "TLSv1/SSLv3", 128, 128]
["DHE-DSS-AES128-SHA256", "TLSv1/SSLv3", 128, 128]
["DHE-RSA-AES128-SHA", "TLSv1/SSLv3", 128, 128]
["DHE-DSS-AES128-SHA", "TLSv1/SSLv3", 128, 128]
["DHE-RSA-SEED-SHA", "TLSv1/SSLv3", 128, 128]
["DHE-DSS-SEED-SHA", "TLSv1/SSLv3", 128, 128]
["DHE-RSA-CAMELLIA128-SHA", "TLSv1/SSLv3", 128, 128]
["DHE-DSS-CAMELLIA128-SHA", "TLSv1/SSLv3", 128, 128]
["ECDH-RSA-AES128-GCM-SHA256", "TLSv1/SSLv3", 128, 128]
["ECDH-ECDSA-AES128-GCM-SHA256", "TLSv1/SSLv3", 128, 128]
["ECDH-RSA-AES128-SHA256", "TLSv1/SSLv3", 128, 128]
["ECDH-ECDSA-AES128-SHA256", "TLSv1/SSLv3", 128, 128]
["ECDH-RSA-AES128-SHA", "TLSv1/SSLv3", 128, 128]
["ECDH-ECDSA-AES128-SHA", "TLSv1/SSLv3", 128, 128]
["AES128-GCM-SHA256", "TLSv1/SSLv3", 128, 128]
["AES128-SHA256", "TLSv1/SSLv3", 128, 128]
["AES128-SHA", "TLSv1/SSLv3", 128, 128]
["SEED-SHA", "TLSv1/SSLv3", 128, 128]
["CAMELLIA128-SHA", "TLSv1/SSLv3", 128, 128]
["IDEA-CBC-SHA", "TLSv1/SSLv3", 128, 128]
["PSK-AES128-CBC-SHA", "TLSv1/SSLv3", 128, 128]
["ECDHE-RSA-RC4-SHA", "TLSv1/SSLv3", 128, 128]
["ECDHE-ECDSA-RC4-SHA", "TLSv1/SSLv3", 128, 128]
["ECDH-RSA-RC4-SHA", "TLSv1/SSLv3", 128, 128]
["ECDH-ECDSA-RC4-SHA", "TLSv1/SSLv3", 128, 128]
["RC4-SHA", "TLSv1/SSLv3", 128, 128]
["RC4-MD5", "TLSv1/SSLv3", 128, 128]
["PSK-RC4-SHA", "TLSv1/SSLv3", 128, 128]
["ECDHE-RSA-DES-CBC3-SHA", "TLSv1/SSLv3", 112, 168]
["ECDHE-ECDSA-DES-CBC3-SHA", "TLSv1/SSLv3", 112, 168]
["SRP-DSS-3DES-EDE-CBC-SHA", "TLSv1/SSLv3", 112, 168]
["SRP-RSA-3DES-EDE-CBC-SHA", "TLSv1/SSLv3", 112, 168]
["SRP-3DES-EDE-CBC-SHA", "TLSv1/SSLv3", 112, 168]
["EDH-RSA-DES-CBC3-SHA", "TLSv1/SSLv3", 112, 168]
["EDH-DSS-DES-CBC3-SHA", "TLSv1/SSLv3", 112, 168]
["ECDH-RSA-DES-CBC3-SHA", "TLSv1/SSLv3", 112, 168]
["ECDH-ECDSA-DES-CBC3-SHA", "TLSv1/SSLv3", 112, 168]
["DES-CBC3-SHA", "TLSv1/SSLv3", 112, 168]
["PSK-3DES-EDE-CBC-SHA", "TLSv1/SSLv3", 112, 168]
["EDH-RSA-DES-CBC-SHA", "TLSv1/SSLv3", 56, 56]
["EDH-DSS-DES-CBC-SHA", "TLSv1/SSLv3", 56, 56]
["DES-CBC-SHA", "TLSv1/SSLv3", 56, 56]

Final thoughts

Admittedly, the actual defaults that Ruby uses are only applied if you explicitly call set_params at some point. Neither MRI nor JRuby initialize the SSLContext with the defaults until set_params is called.

JRuby with set_params

Note that it removes the ECDHE cipher suites that it supports. I will file another ticket to track this.

$ jruby -ropenssl -e 'context=OpenSSL::SSL::SSLContext.new; context.set_params; context.ciphers.each { |c| p c}'
["AES256-SHA", "TLSv1/SSLv3", 256, 256]
["DHE-RSA-AES256-SHA", "TLSv1/SSLv3", 256, 256]
["DHE-DSS-AES256-SHA", "TLSv1/SSLv3", 256, 256]
["AES128-SHA", "TLSv1/SSLv3", 128, 128]
["DHE-RSA-AES128-SHA", "TLSv1/SSLv3", 128, 128]
["DHE-DSS-AES128-SHA", "TLSv1/SSLv3", 128, 128]
["DES-CBC3-SHA", "TLSv1/SSLv3", 168, 168]
["EDH-RSA-DES-CBC3-SHA", "TLSv1/SSLv3", 168, 168]
["EDH-DSS-DES-CBC3-SHA", "TLSv1/SSLv3", 168, 168]
["RC4-SHA", "TLSv1/SSLv3", 128, 128]
["RC4-MD5", "TLSv1/SSLv3", 128, 128]
["DES-CBC-SHA", "TLSv1/SSLv3", 56, 56]
["EDH-RSA-DES-CBC-SHA", "TLSv1/SSLv3", 56, 56]

MRI 2.2 (and 2.0-p645) with set_params

$ ruby -ropenssl -e 'context=OpenSSL::SSL::SSLContext.new; context.set_params; context.ciphers.each { |c| p c}'
["ECDHE-ECDSA-AES128-GCM-SHA256", "TLSv1/SSLv3", 128, 128]
["ECDHE-RSA-AES128-GCM-SHA256", "TLSv1/SSLv3", 128, 128]
["ECDHE-ECDSA-AES256-GCM-SHA384", "TLSv1/SSLv3", 256, 256]
["ECDHE-RSA-AES256-GCM-SHA384", "TLSv1/SSLv3", 256, 256]
["DHE-RSA-AES128-GCM-SHA256", "TLSv1/SSLv3", 128, 128]
["DHE-DSS-AES128-GCM-SHA256", "TLSv1/SSLv3", 128, 128]
["DHE-RSA-AES256-GCM-SHA384", "TLSv1/SSLv3", 256, 256]
["DHE-DSS-AES256-GCM-SHA384", "TLSv1/SSLv3", 256, 256]
["ECDHE-ECDSA-AES128-SHA256", "TLSv1/SSLv3", 128, 128]
["ECDHE-RSA-AES128-SHA256", "TLSv1/SSLv3", 128, 128]
["ECDHE-ECDSA-AES128-SHA", "TLSv1/SSLv3", 128, 128]
["ECDHE-RSA-AES128-SHA", "TLSv1/SSLv3", 128, 128]
["ECDHE-ECDSA-AES256-SHA384", "TLSv1/SSLv3", 256, 256]
["ECDHE-RSA-AES256-SHA384", "TLSv1/SSLv3", 256, 256]
["ECDHE-ECDSA-AES256-SHA", "TLSv1/SSLv3", 256, 256]
["ECDHE-RSA-AES256-SHA", "TLSv1/SSLv3", 256, 256]
["DHE-RSA-AES128-SHA256", "TLSv1/SSLv3", 128, 128]
["DHE-RSA-AES256-SHA256", "TLSv1/SSLv3", 256, 256]
["DHE-RSA-AES128-SHA", "TLSv1/SSLv3", 128, 128]
["DHE-RSA-AES256-SHA", "TLSv1/SSLv3", 256, 256]
["DHE-DSS-AES128-SHA256", "TLSv1/SSLv3", 128, 128]
["DHE-DSS-AES256-SHA256", "TLSv1/SSLv3", 256, 256]
["DHE-DSS-AES128-SHA", "TLSv1/SSLv3", 128, 128]
["DHE-DSS-AES256-SHA", "TLSv1/SSLv3", 256, 256]
["AES128-GCM-SHA256", "TLSv1/SSLv3", 128, 128]
["AES256-GCM-SHA384", "TLSv1/SSLv3", 256, 256]
["AES128-SHA256", "TLSv1/SSLv3", 128, 128]
["AES256-SHA256", "TLSv1/SSLv3", 256, 256]
["AES128-SHA", "TLSv1/SSLv3", 128, 128]
["AES256-SHA", "TLSv1/SSLv3", 256, 256]
["ECDHE-ECDSA-RC4-SHA", "TLSv1/SSLv3", 128, 128]
["ECDHE-RSA-RC4-SHA", "TLSv1/SSLv3", 128, 128]
["RC4-SHA", "TLSv1/SSLv3", 128, 128]

Want to see this issue fixed? Post a bounty on it! We accept bounties via Bountysource.

--- Want to back this issue? **[Post a bounty on it!](https://www.bountysource.com/issues/22431558-jruby-openssl-0-9-7-enables-export-cipher-suites-by-default-and-it-prefers-them-before-better-cipher-suites?utm_campaign=plugin&utm_content=tracker%2F136995&utm_medium=issues&utm_source=github)** We accept bounties via [Bountysource](https://www.bountysource.com/?utm_campaign=plugin&utm_content=tracker%2F136995&utm_medium=issues&utm_source=github).
kares commented 9 years ago

thanks, we need someone to "match" with OpenSSL's matching as that code has not seem to have been updated/touched since the initial working version ... mentioned that here as well

jordansissel commented 9 years ago

I found this while investigating a similar problem with EXPORT ciphers. Reading the code for jruby-openssl 0.9.6 finds that !EXPORT is part of the defaults, but the defaults aren't used by default - hah!

[1] pry(main)> OpenSSL::SSL::SSLContext.new.tap { |c| x = c.ciphers.clone; c.ciphers = "ALL:!ADH:!EXPORT:!SSLv2:RC4+RSA:+HIGH:+MEDIUM:+LOW"; p x - c.ciphers }
[["EXP-DES-CBC-SHA", "TLSv1/SSLv3", 40, 56], ["EXP-EDH-RSA-DES-CBC-SHA", "TLSv1/SSLv3", 40, 56], ["EXP-EDH-DSS-DES-CBC-SHA", "TLSv1/SSLv3", 40, 56], ["EXP-RC4-MD5", "TLSv1/SSLv3", 40, 128]]

^^ The above showing export ciphers are indeed included by default, but are removed if I explicitly set what I thought was the default cipher selection. I can confirm @kares' report that SSLContext#set_params call will kind of resolve this.

Here's what JRuby says about the defaults:

[3] pry(main)> OpenSSL::SSL::SSLContext::DEFAULT_PARAMS
=> {:ssl_version=>"SSLv23", :verify_mode=>1, :ciphers=>"ALL:!ADH:!EXPORT:!SSLv2:RC4+RSA:+HIGH:+MEDIUM:+LOW", :options=>4095}

Strange indeed that the defaults aren't used until set_params is invoked. The 'set_params' affects me because I never actually call it; I have historically always used accessor methods directly SSLContext#ciphers=, SSLContext#version=, etc.

delwaterman commented 8 years ago

Hey there any update on this?