jruby-openssl 0.9.7 enables EXPORT cipher suites by default, and it prefers them before better cipher suites
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:

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.
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
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.
Hey there any update on this?