jruby-openssl icon indicating copy to clipboard operation
jruby-openssl copied to clipboard

Net::SMTP behaves differently in JRuby than in MRI

Open ylansegal opened this issue 9 years ago • 16 comments

Sometime after jruby-1.7.19 a change was introduced that changes the Net::SMTP behavior with respect with MRI.

Repro:

require "net/smtp"

message = <<-END_OF_MESSAGE
From: Your Name <[email protected]>
To: Destination Address <[email protected]>
Subject: test message
Date: Sat, 23 Jun 2001 16:26:43 +0900
Message-Id: <[email protected]>

This is a test message.
END_OF_MESSAGE

smtp = Net::SMTP.new("smtp.somewhere.com", 25)

# This is weird, since we are not using TLS but done by default in the "mail" gem
# In any case, in MRI it doesn't cause any issue.
smtp.enable_starttls_auto

smtp.start("localhost") do |smtp_obj|
 response = smtp_obj.send_message(message, "[email protected]", "[email protected]")
end

In jruby-1.7.22 and jruby-9.0.1.0 I get a Java stack-trace:

$ ruby repro.rb
Handshaker.java:1429:in `checkThrown': java.lang.RuntimeException: Algorithm NONE not available
    from SSLEngineImpl.java:535:in `checkTaskThrown'
    from SSLEngineImpl.java:813:in `readNetRecord'
    from SSLEngineImpl.java:781:in `unwrap'
    from SSLEngine.java:624:in `unwrap'
    from SSLSocket.java:605:in `readAndUnwrap'
    from SSLSocket.java:483:in `doHandshake'
    from SSLSocket.java:233:in `connectImpl'
    from SSLSocket.java:210:in `connect'

I can confirm that in jruby-1.7.19 and MRI (2.2.3) the mail message is sent as expected.

I think it's a little weird that the mail gem call enable_starttls_auto by default, unless explicitly told not to (https://github.com/mikel/mail/blob/master/lib/mail/network/delivery_methods/smtp.rb), but in any case, I believe the difference in behavior of the current JRuby release and MRI is worth addressing.

Please do let me know if more information is needed.

Thanks.

ylansegal avatar Sep 28 '15 23:09 ylansegal

I can confirm we hit the same thing after upgrading to jruby-1.7.22. In our case, the SMTP server was also over port 25, but should be supporting STARTTLS (it's Mandrill's SMTP server if that helps).

As one other data point, we were actually getting a slightly different error messages in our default jruby-1.7.22 installation originally:

OpenSSL::SSL::SSLError: RSA ServerKeyExchange does not comply to algorithm constraints
    from org/jruby/ext/openssl/SSLSocket.java:210:in `connect'
    from /opt/rbenv/versions/jruby-1.7.22/lib/ruby/1.9/net/smtp.rb:584:in `tlsconnect'
    from /opt/rbenv/versions/jruby-1.7.22/lib/ruby/1.9/net/smtp.rb:561:in `do_start'
    from /opt/rbenv/versions/jruby-1.7.22/lib/ruby/1.9/net/smtp.rb:520:in `start'
    from /srv/data/apps/shared/vendor/bundle/jruby/1.9/gems/mail-2.6.3/lib/mail/network/delivery_methods/smtp.rb:112:in `deliver!'
    from /srv/data/apps/shared/vendor/bundle/jruby/1.9/gems/mail-2.6.3/lib/mail/message.rb:2141:in `do_delivery'
    from /srv/data/apps/shared/vendor/bundle/jruby/1.9/gems/mail-2.6.3/lib/mail/message.rb:236:in `deliver'
    from /srv/data/apps/shared/vendor/bundle/jruby/1.9/gems/actionmailer-4.0.13/lib/action_mailer/base.rb:456:in `deliver_mail'
    from /srv/data/apps/shared/vendor/bundle/jruby/1.9/gems/activesupport-4.0.13/lib/active_support/notifications.rb:159:in `instrument'
    from /srv/data/apps/shared/vendor/bundle/jruby/1.9/gems/activesupport-4.0.13/lib/active_support/notifications/instrumenter.rb:20:in `instrument'
    from /srv/data/apps/shared/vendor/bundle/jruby/1.9/gems/activesupport-4.0.13/lib/active_support/notifications.rb:159:in `instrument'
    from /srv/data/apps/shared/vendor/bundle/jruby/1.9/gems/actionmailer-4.0.13/lib/action_mailer/base.rb:454:in `deliver_mail'
    from /srv/data/apps/shared/vendor/bundle/jruby/1.9/gems/mail-2.6.3/lib/mail/message.rb:236:in `deliver'
    from (irb):3:in `evaluate'
    from org/jruby/RubyKernel.java:1079:in `eval'
    from org/jruby/RubyKernel.java:1479:in `loop'
    from org/jruby/RubyKernel.java:1242:in `catch'
    from org/jruby/RubyKernel.java:1242:in `catch'
    from /srv/data/apps/shared/vendor/bundle/jruby/1.9/gems/railties-4.0.13/lib/rails/commands/console.rb:90:in `start'
    from /srv/data/apps/shared/vendor/bundle/jruby/1.9/gems/railties-4.0.13/lib/rails/commands/console.rb:9:in `start'
    from /srv/data/apps/shared/vendor/bundle/jruby/1.9/gems/railties-4.0.13/lib/rails/commands.rb:62:in `(root)'
    from org/jruby/RubyKernel.java:1040:in `require'

However, after adding the latest jruby-openssl v0.9.12 gem to our Gemfile, then we started getting this same Algorithm NONE not available error instead.

GUI avatar Oct 30 '15 02:10 GUI

We are seeing the same Algorithm NONE not available error in our application using jruby v.1.7.22 (and not v.1.7.19), even without starttls.

bartkamphorst avatar Nov 13 '15 17:11 bartkamphorst

I cannot reproduce using jruby-1.7.22. What version of Java are you using?

k77ch7 avatar Nov 14 '15 13:11 k77ch7

For me it's java version "1.7.0_85": OpenJDK Runtime Environment (IcedTea 2.6.1) (7u85-2.6.1-6~deb7u1) OpenJDK 64-Bit Server VM (build 24.85-b03, mixed mode)

bartkamphorst avatar Nov 14 '15 22:11 bartkamphorst

The original report was using Oracle's java 8:

$ java -version
java version "1.8.0_66"
Java(TM) SE Runtime Environment (build 1.8.0_66-b17)
Java HotSpot(TM) 64-Bit Server VM (build 25.66-b17, mixed mode)

ylansegal avatar Nov 16 '15 17:11 ylansegal

It seems to me that this is a failure to negotiate SSL handshake with the server in question.

[1] pry(main)> RUBY_DESCRIPTION
=> "jruby 9.0.4.0 (2.2.2) 2015-11-12 b9fb7aa Java HotSpot(TM) 64-Bit Server VM 25.40-b25 on 1.8.0_40-b25 +jit [darwin-x86_64]"
[2] pry(main)> require 'net/smtp'
=> true
[3] pry(main)> smtp = Net::SMTP.new('smtp.mandrillapp.com', 587)
=> #<Net::SMTP smtp.mandrillapp.com:587 started=false>
[4] pry(main)> smtp.enable_starttls_auto
=> #<OpenSSL::SSL::SSLContext:0x65c86db8>
[5] pry(main)> smtp.start
Java::JavaLang::RuntimeException: Algorithm NONE not available
from sun.security.ssl.Handshaker.checkThrown(Handshaker.java:1419)
[6] pry(main)> smtp = Net::SMTP.new('smtp.gmail.com', 587)
=> #<Net::SMTP smtp.gmail.com:587 started=false>
[7] pry(main)> smtp.enable_starttls_auto
=> #<OpenSSL::SSL::SSLContext:0x66273da0>
[8] pry(main)> smtp.start
=> #<Net::SMTP smtp.gmail.com:587 started=true>

In the above, you see that the negotiation fails with our SMTP service provider, but the same procedure works with Gmail. It is not clear to me what ciphers are tried and what ciphers problematic ones support, but whatever Gmail is using, JRuby 9k can use. (This happens with both 0.9.11 and 0.9.12 jruby-openssl gem.)

BanzaiMan avatar Nov 18 '15 17:11 BanzaiMan

I was debugging with -J-Djavax.net.debug=ssl option.

  • Gmail ; cipher is TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
  • Mandrill ; cipher is SSL_RSA_EXPORT_WITH_DES40_CBC_SHA

My Env

jruby 1.7.22 (1.9.3p551) 2015-08-20 c28f492 on Java HotSpot(TM) 64-Bit Server VM 1.8.0_66-b17 +jit [darwin-x86_64]

k77ch7 avatar Nov 20 '15 22:11 k77ch7

I've done some digging as well, and it turns out (no real surprise) that TLS is attempted in my case as well and that the cipher suite for my local postfix is the same as Mandrill's. My bet is that DES 40 is simply not supported anymore.

bartkamphorst avatar Nov 20 '15 23:11 bartkamphorst

Since I am also having the same issue and the culprit is mandrill, has anyone been able to fix this yet? I tried changing my port to 465 and now have this:

2015-11-26T00:31:19.379Z 28509 TID-afw WARN: org/jruby/ext/socket/RubyTCPSocket.java:111:in `initialize'
org/jruby/RubyIO.java:1179:in `open'
/home/func01admin/.rbenv/versions/jruby-1.7.23/lib/ruby/1.9/net/smtp.rb:541:in `tcp_socket'
/home/func01admin/.rbenv/versions/jruby-1.7.23/lib/ruby/1.9/net/smtp.rb:550:in `do_start'
org/jruby/ext/timeout/Timeout.java:115:in `timeout'
/home/func01admin/.rbenv/versions/jruby-1.7.23/lib/ruby/1.9/net/smtp.rb:550:in `do_start'
/home/func01admin/.rbenv/versions/jruby-1.7.23/lib/ruby/1.9/net/smtp.rb:520:in `start'
/srv/www/reppro/shared/bundle/jruby/1.9/gems/mail-2.6.3/lib/mail/network/delivery_methods/smtp.rb:112:in `deliver!'
/srv/www/reppro/shared/bundle/jruby/1.9/gems/mail-2.6.3/lib/mail/message.rb:2141:in `do_delivery'
/srv/www/reppro/shared/bundle/jruby/1.9/gems/mail-2.6.3/lib/mail/message.rb:236:in `deliver'
/srv/www/reppro/shared/bundle/jruby/1.9/gems/actionmailer-4.1.14/lib/action_mailer/base.rb:527:in `deliver_mail'
/srv/www/reppro/shared/bundle/jruby/1.9/gems/activesupport-4.1.14/lib/active_support/notifications.rb:159:in `instrument'
/srv/www/reppro/shared/bundle/jruby/1.9/gems/activesupport-4.1.14/lib/active_support/notifications/instrumenter.rb:20:in `instrument'
/srv/www/reppro/shared/bundle/jruby/1.9/gems/activesupport-4.1.14/lib/active_support/notifications.rb:159:in `instrument'
/srv/www/reppro/shared/bundle/jruby/1.9/gems/actionmailer-4.1.14/lib/action_mailer/base.rb:525:in `deliver_mail'
/srv/www/reppro/shared/bundle/jruby/1.9/gems/mail-2.6.3/lib/mail/message.rb:236:in `deliver'
/srv/www/reppro/shared/bundle/jruby/1.9/gems/sidekiq_mailer-0.0.8/lib/sidekiq_mailer/proxy.rb:24:in `deliver!'
/srv/www/reppro/shared/bundle/jruby/1.9/gems/sidekiq_mailer-0.0.8/lib/sidekiq_mailer/worker.rb:5:in `perform'
/srv/www/reppro/shared/bundle/jruby/1.9/gems/sidekiq-3.4.2/lib/sidekiq/processor.rb:75:in `execute_job'
/srv/www/reppro/shared/bundle/jruby/1.9/gems/sidekiq-3.4.2/lib/sidekiq/processor.rb:52:in `process'
/srv/www/reppro/shared/bundle/jruby/1.9/gems/sidekiq-3.4.2/lib/sidekiq/middleware/chain.rb:127:in `invoke'
/srv/www/reppro/shared/bundle/jruby/1.9/gems/newrelic_rpm-3.11.1.284/lib/new_relic/agent/instrumentation/sidekiq.rb:33:in `call'
/srv/www/reppro/shared/bundle/jruby/1.9/gems/newrelic_rpm-3.11.1.284/lib/new_relic/agent/instrumentation/controller_instrumentation.rb:353:in `perform_action_with_newrelic_trace'
/srv/www/reppro/shared/bundle/jruby/1.9/gems/newrelic_rpm-3.11.1.284/lib/new_relic/agent/instrumentation/sidekiq.rb:29:in `call'
/srv/www/reppro/shared/bundle/jruby/1.9/gems/sidekiq-3.4.2/lib/sidekiq/middleware/chain.rb:129:in `invoke'
/srv/www/reppro/shared/bundle/jruby/1.9/gems/sidekiq-3.4.2/lib/sidekiq/middleware/server/active_record.rb:6:in `call'
/srv/www/reppro/shared/bundle/jruby/1.9/gems/sidekiq-3.4.2/lib/sidekiq/middleware/chain.rb:129:in `invoke'
/srv/www/reppro/shared/bundle/jruby/1.9/gems/sidekiq-3.4.2/lib/sidekiq/middleware/server/retry_jobs.rb:74:in `call'
/srv/www/reppro/shared/bundle/jruby/1.9/gems/sidekiq-3.4.2/lib/sidekiq/middleware/chain.rb:129:in `invoke'
/srv/www/reppro/shared/bundle/jruby/1.9/gems/sidekiq-3.4.2/lib/sidekiq/middleware/server/logging.rb:15:in `call'
/srv/www/reppro/shared/bundle/jruby/1.9/gems/sidekiq-3.4.2/lib/sidekiq/logging.rb:30:in `with_context'
/srv/www/reppro/shared/bundle/jruby/1.9/gems/sidekiq-3.4.2/lib/sidekiq/middleware/server/logging.rb:11:in `call'
/srv/www/reppro/shared/bundle/jruby/1.9/gems/sidekiq-3.4.2/lib/sidekiq/middleware/chain.rb:129:in `invoke'
org/jruby/RubyProc.java:281:in `call'
/srv/www/reppro/shared/bundle/jruby/1.9/gems/sidekiq-3.4.2/lib/sidekiq/middleware/chain.rb:132:in `invoke'
/srv/www/reppro/shared/bundle/jruby/1.9/gems/sidekiq-3.4.2/lib/sidekiq/processor.rb:51:in `process'
/srv/www/reppro/shared/bundle/jruby/1.9/gems/sidekiq-3.4.2/lib/sidekiq/processor.rb:98:in `stats'
/srv/www/reppro/shared/bundle/jruby/1.9/gems/sidekiq-3.4.2/lib/sidekiq/processor.rb:50:in `process'
org/jruby/RubyKernel.java:1930:in `public_send'
/srv/www/reppro/shared/bundle/jruby/1.9/gems/celluloid-0.16.0/lib/celluloid/calls.rb:26:in `dispatch'
/srv/www/reppro/shared/bundle/jruby/1.9/gems/celluloid-0.16.0/lib/celluloid/calls.rb:122:in `dispatch'
/srv/www/reppro/shared/bundle/jruby/1.9/gems/celluloid-0.16.0/lib/celluloid/cell.rb:60:in `invoke'
/srv/www/reppro/shared/bundle/jruby/1.9/gems/celluloid-0.16.0/lib/celluloid/cell.rb:71:in `task'
/srv/www/reppro/shared/bundle/jruby/1.9/gems/celluloid-0.16.0/lib/celluloid/actor.rb:357:in `task'
/srv/www/reppro/shared/bundle/jruby/1.9/gems/celluloid-0.16.0/lib/celluloid/tasks.rb:57:in `initialize'
/srv/www/reppro/shared/bundle/jruby/1.9/gems/celluloid-0.16.0/lib/celluloid/tasks/task_fiber.rb:15:in `create'

TheKidCoder avatar Nov 26 '15 03:11 TheKidCoder

Workaround: using smtp.enable_starttls_auto OpenSSL::SSL::SSLContext.new("TLSv1_2_client").

k77ch7 avatar Dec 04 '15 14:12 k77ch7

@TheKidCoder : I had the same issue after changing the port to 465, It's because you need to start Postfix on your mac and also enable port 465, which is disabled by default:

  • First edit the master.conf: sudo vim /etc/postfix/master.cf
  • Remove the '#' comment from line 465 inet n - n - - smtpd
  • now start postfix, or reload it: sudo postfix reload or sudo postfix start

rahulmeena13 avatar Mar 26 '16 17:03 rahulmeena13

To follow up on @k77ch7 's workaround, the following monkey patch works for me:

require 'net/smtp'

class << Net::SMTP
  remove_method :default_ssl_context # if defined?(Net::SMTP.default_ssl_context)
end

module Net
  class SMTP
    def SMTP.default_ssl_context
      OpenSSL::SSL::SSLContext.new('TLSv1_2_client')
    end
  end
end

This will globally change SMTP to use a TLS v1.2 cipher suite, which avoids this issue.

kgx avatar Jun 07 '16 20:06 kgx

I encountered this error when using Rails with Postfix configured as a gmail relay on Ubuntu.

The solution was to ensure that the default "TLS Parameters" are commented out or removed from /etc/postfix/main.cf after configuring the relay settings. Restart postfix after modifications to main.cf

maccharlesnmx avatar Jun 23 '17 14:06 maccharlesnmx

@maccharlesnmx Did you have this issue on a recent version of JRuby? The most recent replies here were all (somewhat older) versions of JRuby 1.7.

headius avatar Jun 23 '17 18:06 headius

@headius I'm using JRuby 9.1.12.0

To be clear, I was able to resolve the "Algorithm NONE not available" error by adjusting my Postfix configuration and no monkey patching. I posted my case here because it seemed like a very specific error message, and searching for it leads directly to this issue, so it might help others.

I can't be certain that my case is the same as the original setup from @ylansegal, but it seems related to those who mention using JRuby with Postfix.

maccharlesnmx avatar Jun 23 '17 20:06 maccharlesnmx

I'm pretty sure this is really an OpenSSL bug so I'm transferring the issue there.

Perhaps someone can test against a more recent JRuby? We expanded support for ciphers since this bug was last updated.

headius avatar Jul 18 '20 03:07 headius