Skip to content

Commit a7994b3

Browse files
authored
[fix] for PKCS8 EC private key support (#267)
Signed-off-by: Tero Saarni <[email protected]>
1 parent 78813d4 commit a7994b3

File tree

7 files changed

+48
-29
lines changed

7 files changed

+48
-29
lines changed

src/main/java/org/jruby/ext/openssl/PKey.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ public static IRubyObject read(final ThreadContext context, IRubyObject recv, IR
129129
(DSAPrivateKey) keyPair.getPrivate(), (DSAPublicKey) keyPair.getPublic()
130130
);
131131
}
132-
if ( "ECDSA".equals(alg) ) {
132+
if ( "EC".equals(alg) ) {
133133
return new PKeyEC(runtime, _PKey(runtime).getClass("EC"),
134134
(PrivateKey) keyPair.getPrivate(), (PublicKey) keyPair.getPublic()
135135
);
@@ -165,7 +165,7 @@ public static IRubyObject read(final ThreadContext context, IRubyObject recv, IR
165165
if ( "DSA".equals(pubKey.getAlgorithm()) ) {
166166
return new PKeyDSA(runtime, (DSAPublicKey) pubKey);
167167
}
168-
if ( "ECDSA".equals(pubKey.getAlgorithm()) ) {
168+
if ( "EC".equals(pubKey.getAlgorithm()) ) {
169169
return new PKeyEC(runtime, pubKey);
170170
}
171171
}
@@ -197,6 +197,8 @@ public IRubyObject initialize(ThreadContext context) {
197197

198198
public String getAlgorithm() { return "NONE"; }
199199

200+
public String getKeyType() { return getAlgorithm(); }
201+
200202
public boolean isPrivateKey() { return getPrivateKey() != null; }
201203

202204
public abstract RubyString to_der() ;

src/main/java/org/jruby/ext/openssl/PKeyEC.java

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,9 @@ public PKeyEC(Ruby runtime, RubyClass type) {
222222
@Override
223223
public String getAlgorithm() { return "ECDSA"; }
224224

225+
@Override
226+
public String getKeyType() { return "EC"; }
227+
225228
@JRubyMethod(rest = true, visibility = Visibility.PRIVATE)
226229
public IRubyObject initialize(final ThreadContext context, final IRubyObject[] args, Block block) {
227230
final Ruby runtime = context.runtime;
@@ -254,13 +257,13 @@ public IRubyObject initialize(final ThreadContext context, final IRubyObject[] a
254257
Object key = null;
255258
final KeyFactory ecdsaFactory;
256259
try {
257-
ecdsaFactory = SecurityHelper.getKeyFactory("ECDSA");
260+
ecdsaFactory = SecurityHelper.getKeyFactory("EC");
258261
}
259262
catch (NoSuchAlgorithmException e) {
260-
throw runtime.newRuntimeError("unsupported key algorithm (ECDSA)");
263+
throw runtime.newRuntimeError("unsupported key algorithm (EC)");
261264
}
262265
catch (RuntimeException e) {
263-
throw runtime.newRuntimeError("unsupported key algorithm (ECDSA) " + e);
266+
throw runtime.newRuntimeError("unsupported key algorithm (EC) " + e);
264267
}
265268
// TODO: ugly NoClassDefFoundError catching for no BC env. How can we remove this?
266269
boolean noClassDef = false;
@@ -380,7 +383,7 @@ public PKeyEC generate_key(final ThreadContext context) {
380383
// final ECDomainParameters params = getDomainParameters();
381384
try {
382385
ECGenParameterSpec genSpec = new ECGenParameterSpec(getCurveName());
383-
KeyPairGenerator gen = SecurityHelper.getKeyPairGenerator("ECDSA"); // "BC"
386+
KeyPairGenerator gen = SecurityHelper.getKeyPairGenerator("EC"); // "BC"
384387
gen.initialize(genSpec, new SecureRandom());
385388
KeyPair pair = gen.generateKeyPair();
386389
this.publicKey = (ECPublicKey) pair.getPublic();
@@ -517,7 +520,7 @@ public IRubyObject set_public_key(final ThreadContext context, final IRubyObject
517520
final Point point = (Point) arg;
518521
ECPublicKeySpec keySpec = new ECPublicKeySpec(point.asECPoint(), getParamSpec());
519522
try {
520-
this.publicKey = (ECPublicKey) SecurityHelper.getKeyFactory("ECDSA").generatePublic(keySpec);
523+
this.publicKey = (ECPublicKey) SecurityHelper.getKeyFactory("EC").generatePublic(keySpec);
521524
return arg;
522525
}
523526
catch (GeneralSecurityException ex) {
@@ -555,7 +558,7 @@ public IRubyObject set_private_key(final ThreadContext context, final IRubyObjec
555558
}
556559
ECPrivateKeySpec keySpec = new ECPrivateKeySpec(s, getParamSpec());
557560
try {
558-
this.privateKey = SecurityHelper.getKeyFactory("ECDSA").generatePrivate(keySpec);
561+
this.privateKey = SecurityHelper.getKeyFactory("EC").generatePrivate(keySpec);
559562
return arg;
560563
}
561564
catch (GeneralSecurityException ex) {
@@ -942,4 +945,4 @@ else if (length > bytes.length) {
942945
}
943946
}
944947

945-
}
948+
}

src/main/java/org/jruby/ext/openssl/SSLContext.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -994,12 +994,12 @@ private class InternalContext {
994994

995995
if ( pKey != null && xCert != null ) {
996996
this.privateKey = pKey.getPrivateKey();
997-
this.keyAlgorithm = pKey.getAlgorithm();
997+
this.keyType = pKey.getKeyType();
998998
this.cert = xCert.getAuxCert();
999999
}
10001000
else {
10011001
this.privateKey = null;
1002-
this.keyAlgorithm = null;
1002+
this.keyType = null;
10031003
this.cert = null;
10041004
}
10051005

@@ -1047,7 +1047,7 @@ void initSSLContext(final ThreadContext context) throws KeyManagementException {
10471047

10481048
final Store store;
10491049
final X509AuxCertificate cert;
1050-
final String keyAlgorithm;
1050+
final String keyType;
10511051
final PrivateKey privateKey;
10521052

10531053
final int verifyMode;
@@ -1098,7 +1098,7 @@ public String chooseEngineClientAlias(String[] keyType, java.security.Principal[
10981098
if (internalContext.privateKey == null) return null;
10991099

11001100
for (int i = 0; i < keyType.length; i++) {
1101-
if (keyType[i].equalsIgnoreCase(internalContext.keyAlgorithm)) {
1101+
if (keyType[i].equalsIgnoreCase(internalContext.keyType)) {
11021102
return keyType[i];
11031103
}
11041104
}
@@ -1109,7 +1109,7 @@ public String chooseEngineClientAlias(String[] keyType, java.security.Principal[
11091109
public String chooseEngineServerAlias(String keyType, java.security.Principal[] issuers, javax.net.ssl.SSLEngine engine) {
11101110
if (internalContext.privateKey == null) return null;
11111111

1112-
if (keyType.equalsIgnoreCase(internalContext.keyAlgorithm)) {
1112+
if (keyType.equalsIgnoreCase(internalContext.keyType)) {
11131113
return keyType;
11141114
}
11151115
return null;

src/main/java/org/jruby/ext/openssl/impl/PKey.java

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ else if ( type.equals("DSA") ) {
113113
privSpec = new DSAPrivateKeySpec(x.getValue(), p.getValue(), q.getValue(), g.getValue());
114114
pubSpec = new DSAPublicKeySpec(y.getValue(), p.getValue(), q.getValue(), g.getValue());
115115
}
116-
else if ( type.equals("ECDSA") ) {
116+
else if ( type.equals("EC") ) {
117117
return readECPrivateKey(input);
118118
}
119119
else {
@@ -278,7 +278,7 @@ public static DHParameterSpec readDHParameter(final byte[] input) throws IOExcep
278278

279279
public static KeyPair readECPrivateKey(final byte[] input)
280280
throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {
281-
return readECPrivateKey(SecurityHelper.getKeyFactory("ECDSA"), input);
281+
return readECPrivateKey(SecurityHelper.getKeyFactory("EC"), input);
282282
}
283283

284284
public static KeyPair readECPrivateKey(final KeyFactory ecFactory, final byte[] input)
@@ -290,7 +290,7 @@ public static KeyPair readECPrivateKey(final KeyFactory ecFactory, final byte[]
290290
SubjectPublicKeyInfo pubInfo = new SubjectPublicKeyInfo(algId, pKey.getPublicKey().getBytes());
291291
PKCS8EncodedKeySpec privSpec = new PKCS8EncodedKeySpec(privInfo.getEncoded());
292292
X509EncodedKeySpec pubSpec = new X509EncodedKeySpec(pubInfo.getEncoded());
293-
//KeyFactory fact = KeyFactory.getInstance("ECDSA", provider);
293+
//KeyFactory fact = KeyFactory.getInstance("EC", provider);
294294

295295
ECPrivateKey privateKey = (ECPrivateKey) ecFactory.generatePrivate(privSpec);
296296
if ( algId.getParameters() instanceof ASN1ObjectIdentifier ) {
@@ -383,5 +383,3 @@ public static byte[] toDerDHKey(BigInteger p, BigInteger g) throws IOException {
383383
return new DLSequence(vec).getEncoded();
384384
}
385385
}
386-
387-

src/main/java/org/jruby/ext/openssl/x509store/PEMInputOutput.java

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -340,7 +340,7 @@ else if ( line.indexOf(BEG_STRING_DSA) != -1 ) {
340340
}
341341
else if ( line.indexOf(BEG_STRING_ECPRIVATEKEY) != -1) {
342342
try {
343-
return readKeyPair(reader, passwd, "ECDSA", BEF_E + PEM_STRING_ECPRIVATEKEY);
343+
return readKeyPair(reader, passwd, "EC", BEF_E + PEM_STRING_ECPRIVATEKEY);
344344
}
345345
catch (Exception e) {
346346
throw mapReadException("problem creating DSA private key: ", e);
@@ -349,9 +349,10 @@ else if ( line.indexOf(BEG_STRING_ECPRIVATEKEY) != -1) {
349349
else if ( line.indexOf(BEG_STRING_PKCS8INF) != -1) {
350350
try {
351351
byte[] bytes = readBase64Bytes(reader, BEF_E + PEM_STRING_PKCS8INF);
352-
PrivateKeyInfo info = PrivateKeyInfo.getInstance(bytes);
353-
String type = getPrivateKeyTypeFromObjectId(info.getPrivateKeyAlgorithm().getAlgorithm());
354-
return org.jruby.ext.openssl.impl.PKey.readPrivateKey(((ASN1Object) info.parsePrivateKey()).getEncoded(ASN1Encoding.DER), type);
352+
PrivateKeyInfo pInfo = PrivateKeyInfo.getInstance(bytes);
353+
KeyFactory keyFactory = getKeyFactory( pInfo.getPrivateKeyAlgorithm() );
354+
PrivateKey pKey = keyFactory.generatePrivate(new PKCS8EncodedKeySpec(pInfo.getEncoded()));
355+
return new KeyPair(null, pKey);
355356
}
356357
catch (Exception e) {
357358
throw mapReadException("problem creating private key: ", e);
@@ -605,7 +606,7 @@ public static ECPublicKey readECPubKey(Reader in) throws IOException {
605606
while ( ( line = reader.readLine() ) != null ) {
606607
if ( line.indexOf(BEG_STRING_EC_PUBLIC) != -1 ) {
607608
try {
608-
return (ECPublicKey) readPublicKey(reader, "ECDSA", BEF_E + "EC PUBLIC KEY");
609+
return (ECPublicKey) readPublicKey(reader, "EC", BEF_E + "EC PUBLIC KEY");
609610
}
610611
catch (Exception e) {
611612
throw mapReadException("problem creating ECDSA public key: ", e);
@@ -621,7 +622,7 @@ public static ECPublicKey readECPublicKey(final Reader in, final char[] passwd)
621622
while ( ( line = reader.readLine() ) != null ) {
622623
if ( line.indexOf(BEG_STRING_PUBLIC) != -1 ) {
623624
try {
624-
return (ECPublicKey) readPublicKey(reader, "ECDSA", BEF_E + PEM_STRING_PUBLIC);
625+
return (ECPublicKey) readPublicKey(reader, "EC", BEF_E + PEM_STRING_PUBLIC);
625626
}
626627
catch (Exception e) {
627628
throw mapReadException("problem creating ECDSA public key: ", e);
@@ -638,7 +639,7 @@ public static KeyPair readECPrivateKey(final Reader in, final char[] passwd)
638639
while ( ( line = reader.readLine() ) != null ) {
639640
if ( line.indexOf(BEG_STRING_EC) != -1 ) {
640641
try {
641-
return readKeyPair(reader, passwd, "ECDSA", BEF_E + "EC PRIVATE KEY");
642+
return readKeyPair(reader, passwd, "EC", BEF_E + "EC PRIVATE KEY");
642643
}
643644
catch (Exception e) {
644645
throw mapReadException("problem creating ECDSA private key: ", e);
@@ -1171,6 +1172,8 @@ public static void writeDHParameters(Writer _out, DHParameterSpec params) throws
11711172
private static String getPrivateKeyTypeFromObjectId(ASN1ObjectIdentifier oid) {
11721173
if ( ASN1Registry.oid2nid(oid) == ASN1Registry.NID_rsaEncryption ) {
11731174
return "RSA";
1175+
} else if ( ASN1Registry.oid2nid(oid) == ASN1Registry.NID_X9_62_id_ecPublicKey ) {
1176+
return "EC";
11741177
} else {
11751178
return "DSA";
11761179
}
@@ -1226,7 +1229,7 @@ private static PublicKey readPublicKey(BufferedReader in, String alg, String end
12261229

12271230
private static PublicKey readPublicKey(BufferedReader in, String endMarker) throws IOException {
12281231
byte[] input = readBase64Bytes(in, endMarker);
1229-
String[] algs = { "RSA", "DSA", "ECDSA" };
1232+
String[] algs = { "RSA", "DSA", "EC" };
12301233
for (int i = 0; i < algs.length; i++) {
12311234
PublicKey key = readPublicKey(input, algs[i], endMarker);
12321235
if (key != null) {
@@ -1488,7 +1491,7 @@ public static KeyFactory getKeyFactory(final AlgorithmIdentifier algId)
14881491

14891492
String algorithm = null;
14901493
if ( X9ObjectIdentifiers.id_ecPublicKey.equals(algIdentifier) ) {
1491-
algorithm = "ECDSA";
1494+
algorithm = "EC";
14921495
}
14931496
else if ( PKCSObjectIdentifiers.rsaEncryption.equals(algIdentifier) ) {
14941497
algorithm = "RSA";
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
-----BEGIN PRIVATE KEY-----
2+
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgUmgU1rG7E9WJmB4A
3+
D1RZ+PP+aYEH2ZZxWTGVR0gDr/qhRANCAAR5d0hOX+W8RznN62sAzIeozl4OBl6K
4+
nKdpKKiZTAua05NCaWJR5mGnrCyn4g+sQV4pUgmp9NzSMwmXAzJt3GK9
5+
-----END PRIVATE KEY-----

src/test/ruby/ec/test_ec.rb

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,14 @@ def test_read_pem2
5151
#puts signature.inspect
5252
end
5353

54+
def test_read_pkcs8_with_ec
55+
key_file = File.join(File.dirname(__FILE__), 'private_key_pkcs8.pem')
56+
57+
key = OpenSSL::PKey::read(File.read(key_file))
58+
assert_equal '37273549501637553234010607973347901861080883009977847480473501706546896416762', key.private_key.to_s
59+
assert_empty key.public_key.to_s
60+
end
61+
5462
def test_point
5563
group = OpenSSL::PKey::EC::Group.new('prime256v1')
5664
client_public_key_bn = OpenSSL::BN.new('58089019511196532477248433747314139754458690644712400444716868601190212265537817278966641566813745621284958192417192818318052462970895792919572995957754854')
@@ -311,4 +319,4 @@ def test_dsa_sign_verify
311319
# end
312320
# end
313321

314-
end
322+
end

0 commit comments

Comments
 (0)