diff --git a/src/main/java/org/jruby/ext/openssl/PKey.java b/src/main/java/org/jruby/ext/openssl/PKey.java index ef612eb1..417ec087 100644 --- a/src/main/java/org/jruby/ext/openssl/PKey.java +++ b/src/main/java/org/jruby/ext/openssl/PKey.java @@ -147,6 +147,14 @@ public static IRubyObject read(final ThreadContext context, IRubyObject recv, IR debugStackTrace(runtime, "PKey readPrivateKeyFromDER", e); /* ignore */ } } + // d2i_PrivateKey_bio - PKCS#1 RSA, DSA and SEC1 EC keys (as written by #to_der) + if (keyPair == null) { + try { + keyPair = org.jruby.ext.openssl.impl.PKey.readPrivateKeyDER(str.getBytes()); + } catch (IOException e) { + debugStackTrace(runtime, "PKey readPrivateKeyDER", e); /* ignore */ + } + } // PEM_read_bio_PrivateKey if (keyPair != null) { final String alg = getAlgorithm(keyPair); diff --git a/src/main/java/org/jruby/ext/openssl/impl/PKey.java b/src/main/java/org/jruby/ext/openssl/impl/PKey.java index 25d28faa..92859244 100644 --- a/src/main/java/org/jruby/ext/openssl/impl/PKey.java +++ b/src/main/java/org/jruby/ext/openssl/impl/PKey.java @@ -209,6 +209,20 @@ public static KeyPair readRSAPrivateKey(final KeyFactory rsaFactory, final byte[ return null; } + // d2i_PrivateKey_bio - type specific DER encodings (PKCS#1 RSA, DSA, SEC1 EC) + public static KeyPair readPrivateKeyDER(final byte[] input) throws IOException { + try { + // each reader matches on sequence shape so order does not matter + KeyPair keyPair = readRSAPrivateKey(input); + if (keyPair == null) keyPair = readDSAPrivateKey(input); + if (keyPair == null) keyPair = readECPrivateKey(input); + return keyPair; + } + catch (Exception e) { // the EC reader mocks up a PrivateKeyInfo and blows up in all sorts of ways + throw new IOException("Could not parse private key: " + e.getMessage(), e); + } + } + // d2i_RSAPublicKey_bio public static PublicKey readRSAPublicKey(final byte[] input) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException { diff --git a/src/test/ruby/test_pkey.rb b/src/test/ruby/test_pkey.rb index 10b831f1..a7d5d6ad 100644 --- a/src/test/ruby/test_pkey.rb +++ b/src/test/ruby/test_pkey.rb @@ -67,6 +67,16 @@ def test_pkey_read_pkcs8_and_check_with_cert assert_true cert.check_private_key(pkey) end + # #to_der writes PKCS#1 (RSA, DSA) or SEC1 (EC), PKey.read only handled PKCS#8 + def test_pkey_read_der_round_trip + %w[rsa2048 dsa2048 p256].each do |name| + key = Fixtures.pkey(name) + read = OpenSSL::PKey.read(key.to_der) + assert_instance_of key.class, read + assert_equal key.to_der, read.to_der + end + end + def test_pkey_pem_file_error begin ret = OpenSSL::PKey.read('not a PEM file')