Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JRuby - Add Puma::MiniSSL::Engine#init? and #teardown methods, run all SSL tests #2317

Merged
merged 2 commits into from Sep 1, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions 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
Expand Down
41 changes: 36 additions & 5 deletions ext/puma_http11/org/jruby/puma/MiniSSL.java
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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();
Expand All @@ -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;
Expand All @@ -286,7 +298,9 @@ public IRubyObject read() throws Exception {
default:
done = true;
}
handshakeStatus = engine.getHandshakeStatus();
if (!done) {
handshakeStatus = res.getHandshakeStatus();
}
}

if (inboundNetData.hasRemaining()) {
Expand Down Expand Up @@ -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();
}
}
}
3 changes: 3 additions & 0 deletions lib/puma/minissl.rb
Expand Up @@ -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
Expand Down
15 changes: 11 additions & 4 deletions test/test_puma_server_ssl.rb
Expand Up @@ -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
Expand Down