From 782325c5b5e41ea507c7d233988f5221f382df8c Mon Sep 17 00:00:00 2001 From: MSP-Greg Date: Mon, 20 Jul 2020 15:43:34 -0500 Subject: [PATCH 1/2] Update MiniSSL.java and minissl.rb for JRuby Add Puma::MiniSSL::Engine#init? and #teardown methods --- ext/puma_http11/org/jruby/puma/MiniSSL.java | 41 ++++++++++++++++++--- lib/puma/minissl.rb | 3 ++ test/test_puma_server_ssl.rb | 15 ++++++-- 3 files changed, 50 insertions(+), 9 deletions(-) diff --git a/ext/puma_http11/org/jruby/puma/MiniSSL.java b/ext/puma_http11/org/jruby/puma/MiniSSL.java index 33b6d91a4c..be5b442ea9 100644 --- a/ext/puma_http11/org/jruby/puma/MiniSSL.java +++ b/ext/puma_http11/org/jruby/puma/MiniSSL.java @@ -120,6 +120,8 @@ public ByteList asByteList() { } private SSLEngine engine; + private boolean closed; + private boolean handshake; private MiniSSLBuffer inboundNetData; private MiniSSLBuffer outboundAppData; private MiniSSLBuffer outboundNetData; @@ -157,6 +159,8 @@ public IRubyObject initialize(ThreadContext threadContext, IRubyObject miniSSLCo SSLContext sslCtx = SSLContext.getInstance("TLS"); sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); + closed = false; + handshake = false; engine = sslCtx.createSSLEngine(); String[] protocols; @@ -240,14 +244,21 @@ private SSLEngineResult doOp(SSLOperation sslOp, MiniSSLBuffer src, MiniSSLBuffe // need to wait for more data to come in before we retry retryOp = false; break; + case CLOSED: + closed = true; + retryOp = false; + break; default: - // other cases are OK and CLOSED. We're done here. + // other case is OK. We're done here. retryOp = false; } + if (res.getHandshakeStatus() == HandshakeStatus.FINISHED) { + handshake = true; + } } // after each op, run any delegated tasks if needed - if(engine.getHandshakeStatus() == HandshakeStatus.NEED_TASK) { + if(res.getHandshakeStatus() == HandshakeStatus.NEED_TASK) { Runnable runnable; while ((runnable = engine.getDelegatedTask()) != null) { runnable.run(); @@ -271,13 +282,14 @@ public IRubyObject read() throws Exception { HandshakeStatus handshakeStatus = engine.getHandshakeStatus(); boolean done = false; + SSLEngineResult res = null; while (!done) { switch (handshakeStatus) { case NEED_WRAP: - doOp(SSLOperation.WRAP, inboundAppData, outboundNetData); + res = doOp(SSLOperation.WRAP, inboundAppData, outboundNetData); break; case NEED_UNWRAP: - SSLEngineResult res = doOp(SSLOperation.UNWRAP, inboundNetData, inboundAppData); + res = doOp(SSLOperation.UNWRAP, inboundNetData, inboundAppData); if (res.getStatus() == Status.BUFFER_UNDERFLOW) { // need more data before we can shake more hands done = true; @@ -286,7 +298,9 @@ public IRubyObject read() throws Exception { default: done = true; } - handshakeStatus = engine.getHandshakeStatus(); + if (!done) { + handshakeStatus = res.getHandshakeStatus(); + } } if (inboundNetData.hasRemaining()) { @@ -360,4 +374,21 @@ public IRubyObject peercert() throws CertificateEncodingException { return getRuntime().getNil(); } } + + @JRubyMethod(name = "init?") + public IRubyObject isInit(ThreadContext context) { + return handshake ? getRuntime().getFalse() : getRuntime().getTrue(); + } + + @JRubyMethod + public IRubyObject shutdown() { + if (closed || engine.isInboundDone() && engine.isOutboundDone()) { + if (engine.isOutboundDone()) { + engine.closeOutbound(); + } + return getRuntime().getTrue(); + } else { + return getRuntime().getFalse(); + } + } } diff --git a/lib/puma/minissl.rb b/lib/puma/minissl.rb index 4d5c8d68ba..b0f5847f8c 100644 --- a/lib/puma/minissl.rb +++ b/lib/puma/minissl.rb @@ -197,6 +197,9 @@ def peercert end if IS_JRUBY + OPENSSL_NO_SSL3 = false + OPENSSL_NO_TLS1 = false + class SSLError < StandardError # Define this for jruby even though it isn't used. end diff --git a/test/test_puma_server_ssl.rb b/test/test_puma_server_ssl.rb index 584ab44f5c..d52297f087 100644 --- a/test/test_puma_server_ssl.rb +++ b/test/test_puma_server_ssl.rb @@ -23,10 +23,17 @@ def ssl_error(error, peeraddr, peercert) Puma::MiniSSL.check # net/http (loaded in helper) does not necessarily load OpenSSL require "openssl" unless Object.const_defined? :OpenSSL - puts "", RUBY_DESCRIPTION, "RUBYOPT: #{ENV['RUBYOPT']}", - " Puma::MiniSSL OpenSSL", - "OPENSSL_LIBRARY_VERSION: #{Puma::MiniSSL::OPENSSL_LIBRARY_VERSION.ljust 32}#{OpenSSL::OPENSSL_LIBRARY_VERSION}", - " OPENSSL_VERSION: #{Puma::MiniSSL::OPENSSL_VERSION.ljust 32}#{OpenSSL::OPENSSL_VERSION}", "" + if Puma::IS_JRUBY + puts "", RUBY_DESCRIPTION, "RUBYOPT: #{ENV['RUBYOPT']}", + " OpenSSL", + "OPENSSL_LIBRARY_VERSION: #{OpenSSL::OPENSSL_LIBRARY_VERSION}", + " OPENSSL_VERSION: #{OpenSSL::OPENSSL_VERSION}", "" + else + puts "", RUBY_DESCRIPTION, "RUBYOPT: #{ENV['RUBYOPT']}", + " Puma::MiniSSL OpenSSL", + "OPENSSL_LIBRARY_VERSION: #{Puma::MiniSSL::OPENSSL_LIBRARY_VERSION.ljust 32}#{OpenSSL::OPENSSL_LIBRARY_VERSION}", + " OPENSSL_VERSION: #{Puma::MiniSSL::OPENSSL_VERSION.ljust 32}#{OpenSSL::OPENSSL_VERSION}", "" + end rescue true else From bcdf1535e09c899fa494a0d93c869fdf8dfd5efc Mon Sep 17 00:00:00 2001 From: MSP-Greg Date: Tue, 21 Jul 2020 19:09:07 -0500 Subject: [PATCH 2/2] Update History.md --- History.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/History.md b/History.md index fbb1ffe73b..47ce7a1b9c 100644 --- a/History.md +++ b/History.md @@ -1,5 +1,7 @@ ### Master * Bugfixes + * JRuby - Add Puma::MiniSSL::Engine#init? and #teardown methods, run all SSL tests (#2317) + * Improve shutdown reliability (#2312) * Resolve issue with threadpool waiting counter decrement when thread is killed * Constrain rake-compiler version to 0.9.4 to fix `ClassNotFound` exception when using MiniSSL with Java8. * Ensure that TCP_CORK is usable