diff --git a/History.md b/History.md index e5a4c3bd..e61e7d20 100644 --- a/History.md +++ b/History.md @@ -1,6 +1,15 @@ +## 0.14.6 + +* [compat] OpenSSL::ConfigError and DEFAULT_CONFIG_FILE (#304) +* [fix] `OpenSSL::PKey::DH#set_pqg` regression (#300) +* Convert `IOException` to Ruby exception correctly (#242) +* [refactor] add exception debugging within SSLSocket#waitSelect +* [fix] sync `SSLContext#setup` as it could be shared (#302) +* [refactor] organize i-var sets (set `@context` after setup) + ## 0.14.5 -* [fix] OpenSSL::X509::Request#verify with DSA public key +* [fix] `OpenSSL::X509::Request#verify` with DSA public key (this was a regression introduced in JOSSL 0.14.4) ## 0.14.4 diff --git a/lib/jopenssl/_compat23.rb b/lib/jopenssl/_compat23.rb index 8da642c6..78f9d0ef 100644 --- a/lib/jopenssl/_compat23.rb +++ b/lib/jopenssl/_compat23.rb @@ -14,9 +14,9 @@ def set_key(pub_key, priv_key) def set_pqg(p, q, g) self.p = p - if respond_to?(:q) + if respond_to?(:q=) self.q = q - else # TODO self.q = q + else OpenSSL.warn "JRuby-OpenSSL does not support setting q param on #{inspect}" if q end self.g = g diff --git a/lib/jopenssl/load.rb b/lib/jopenssl/load.rb index db90cdf4..ab224c27 100644 --- a/lib/jopenssl/load.rb +++ b/lib/jopenssl/load.rb @@ -43,6 +43,7 @@ module OpenSSL autoload :Config, 'openssl/config' unless const_defined?(:Config, false) + autoload :ConfigError, 'openssl/config' unless const_defined?(:ConfigError, false) autoload :PKCS12, 'openssl/pkcs12' end diff --git a/lib/openssl/config.rb b/lib/openssl/config.rb index 9a0b7874..547b08f2 100644 --- a/lib/openssl/config.rb +++ b/lib/openssl/config.rb @@ -14,6 +14,7 @@ require 'stringio' module OpenSSL + class ConfigError < OpenSSLError; end ## # = OpenSSL::Config # @@ -27,6 +28,8 @@ module OpenSSL class Config include Enumerable + DEFAULT_CONFIG_FILE = nil # JRuby: compatibility (we do not read openssl.cnf) + class << self ## diff --git a/src/main/java/org/jruby/ext/openssl/SSLContext.java b/src/main/java/org/jruby/ext/openssl/SSLContext.java index 76380b5d..1d7729e5 100644 --- a/src/main/java/org/jruby/ext/openssl/SSLContext.java +++ b/src/main/java/org/jruby/ext/openssl/SSLContext.java @@ -315,7 +315,7 @@ public SSLContext(Ruby runtime, RubyClass type) { //private int sessionCacheMode; // 2 default on MRI private int sessionCacheSize; // 20480 - private InternalContext internalContext; + private volatile InternalContext internalContext; @JRubyMethod(required = 0, optional = 1, visibility = Visibility.PRIVATE) public IRubyObject initialize(IRubyObject[] args) { @@ -334,16 +334,11 @@ public IRubyObject initialize_copy(IRubyObject original) { final SSLContext initializeImpl() { return this; } @JRubyMethod - public IRubyObject setup(final ThreadContext context) { + public synchronized IRubyObject setup(final ThreadContext context) { final Ruby runtime = context.runtime; if ( isFrozen() ) return runtime.getNil(); - synchronized(this) { - if ( isFrozen() ) return runtime.getNil(); - this.freeze(context); - } - final X509Store certStore = getCertStore(); // TODO: handle tmp_dh_callback : @@ -513,6 +508,8 @@ public IRubyObject setup(final ThreadContext context) { throw newSSLError(runtime, e); } + this.freeze(context); + return runtime.getTrue(); } diff --git a/src/main/java/org/jruby/ext/openssl/SSLSocket.java b/src/main/java/org/jruby/ext/openssl/SSLSocket.java index f817d1a3..ed336bdb 100644 --- a/src/main/java/org/jruby/ext/openssl/SSLSocket.java +++ b/src/main/java/org/jruby/ext/openssl/SSLSocket.java @@ -162,19 +162,18 @@ public IRubyObject initialize(final ThreadContext context, final IRubyObject[] a final Ruby runtime = context.runtime; if (Arity.checkArgumentCount(runtime, args, 1, 2) == 1) { - sslContext = new SSLContext(runtime).initializeImpl(); + this.sslContext = new SSLContext(runtime).initializeImpl(); } else { if (!(args[1] instanceof SSLContext)) { throw runtime.newTypeError(args[1], "OpenSSL::SSL::SSLContext"); } - sslContext = (SSLContext) args[1]; + this.sslContext = (SSLContext) args[1]; } if (!(args[0] instanceof RubyIO)) { throw runtime.newTypeError("IO expected but got " + args[0].getMetaClass().getName()); } - setInstanceVariable("@context", this.sslContext); // only compat (we do not use @context) - setInstanceVariable("@io", this.io = (RubyIO) args[0]); + setInstanceVariable("@io", this.io = (RubyIO) args[0]); // RubyBasicSocket extends RubyIO set_io_nonblock_checked(context, runtime.getTrue()); // This is a bit of a hack: SSLSocket should share code with // RubyBasicSocket, which always sets sync to true. @@ -182,6 +181,7 @@ public IRubyObject initialize(final ThreadContext context, final IRubyObject[] a set_sync(context, runtime.getTrue()); // io.sync = true setInstanceVariable("@sync_close", runtime.getFalse()); // self.sync_close = false sslContext.setup(context); + setInstanceVariable("@context", sslContext); // only compat (we do not use @context) this.initializeTime = System.currentTimeMillis(); @@ -471,8 +471,8 @@ else if ((operations & SelectionKey.OP_WRITE) != 0) { writeWouldBlock(runtime, exception, result); } } - } - catch (IOException ioe) { + } catch (IOException ioe) { + debugStackTrace(runtime, "SSLSocket.waitSelect", ioe); throw runtime.newRuntimeError("Error with selector: " + ioe.getMessage()); } } else { @@ -483,6 +483,7 @@ public void run() throws InterruptedException { result[0] = selector.select(); } catch (IOException ioe) { + debugStackTrace(runtime, "SSLSocket.waitSelect", ioe); throw runtime.newRuntimeError("Error with selector: " + ioe.getMessage()); } } @@ -505,32 +506,27 @@ public void wakeup() { //JRuby <= 9.1.2.0 that makes this not always the case, so we have to check return selector.selectedKeys().contains(key) ? Boolean.TRUE : Boolean.FALSE; } - } - catch (InterruptedException interrupt) { return Boolean.FALSE; } - finally { - // Note: I don't like ignoring these exceptions, but it's - // unclear how likely they are to happen or what damage we - // might do by ignoring them. Note that the pieces are separate - // so that we can ensure one failing does not affect the others - // running. + } catch (InterruptedException interrupt) { + debug(runtime, "SSLSocket.waitSelect", interrupt); + return Boolean.FALSE; + } finally { + // Note: I don't like ignoring these exceptions, but it's unclear how likely they are to happen or what + // damage we might do by ignoring them. Note that the pieces are separate so that we can ensure one failing + // does not affect the others running. // clean up the key in the selector try { if ( key != null ) key.cancel(); if ( selector != null ) selector.selectNow(); - } - catch (Exception e) { // ignore - debugStackTrace(runtime, e); + } catch (Exception e) { // ignore + debugStackTrace(runtime, "SSLSocket.waitSelect (ignored)", e); } // shut down and null out the selector try { - if ( selector != null ) { - runtime.getSelectorPool().put(selector); - } - } - catch (Exception e) { // ignore - debugStackTrace(runtime, e); + if ( selector != null ) runtime.getSelectorPool().put(selector); + } catch (Exception e) { // ignore + debugStackTrace(runtime, "SSLSocket.waitSelect (ignored)", e); } if (blocking) { @@ -810,8 +806,11 @@ private void doShutdown() throws IOException { flushData(true); } - private IRubyObject sysreadImpl(final ThreadContext context, - IRubyObject len, IRubyObject buff, final boolean blocking, final boolean exception) { + /** + * @return the (@link RubyString} buffer or :wait_readable / :wait_writeable {@link RubySymbol} + */ + private IRubyObject sysreadImpl(final ThreadContext context, final IRubyObject len, final IRubyObject buff, + final boolean blocking, final boolean exception) { final Ruby runtime = context.runtime; final int length = RubyNumeric.fix2int(len); diff --git a/src/test/ruby/test_pkey.rb b/src/test/ruby/test_pkey.rb index 30b83489..2a0f0e12 100644 --- a/src/test/ruby/test_pkey.rb +++ b/src/test/ruby/test_pkey.rb @@ -83,6 +83,20 @@ def test_pkey_pem_file_error end end + def test_pkey_dh + dh = OpenSSL::PKey::DH.new + assert_equal nil, dh.p + assert_equal nil, dh.priv_key + + # OpenSSL::PKey::PKeyError: dh#set_pqg= is incompatible with OpenSSL 3.0 + if defined? JRUBY_VERSION + dh.set_pqg(1_000_000, nil, 10) + assert_equal 1_000_000, dh.p + assert_equal 10, dh.g + end + assert_equal nil, dh.q + end + def test_to_java pkey = OpenSSL::PKey.read(KEY) assert_kind_of java.security.PublicKey, pkey.to_java