Skip to content

Commit e24d02f

Browse files
committed
[fix] revert readPrivateKey so public key is not lost (#292)
1 parent d0f11af commit e24d02f

File tree

2 files changed

+69
-65
lines changed

2 files changed

+69
-65
lines changed

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

Lines changed: 58 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,10 @@
3939
import java.security.interfaces.DSAPrivateKey;
4040
import java.security.interfaces.DSAPublicKey;
4141
import java.security.interfaces.ECPrivateKey;
42-
import java.security.interfaces.ECPublicKey;
4342
import java.security.interfaces.RSAPrivateCrtKey;
4443
import java.security.interfaces.RSAPublicKey;
4544
import java.security.spec.DSAPrivateKeySpec;
4645
import java.security.spec.DSAPublicKeySpec;
47-
import java.security.spec.ECParameterSpec;
48-
import java.security.spec.ECPrivateKeySpec;
4946
import java.security.spec.InvalidKeySpecException;
5047
import java.security.spec.KeySpec;
5148
import java.security.spec.PKCS8EncodedKeySpec;
@@ -67,14 +64,10 @@
6764
import org.bouncycastle.asn1.DLSequence;
6865
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
6966
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
70-
import org.bouncycastle.asn1.sec.ECPrivateKeyStructure;
7167
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
7268
import org.bouncycastle.asn1.x509.DSAParameter;
7369
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
7470
import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
75-
import org.bouncycastle.jce.ECNamedCurveTable;
76-
import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec;
77-
import org.bouncycastle.jce.spec.ECPublicKeySpec;
7871
import org.bouncycastle.jcajce.provider.asymmetric.util.KeyUtil;
7972

8073
import org.jruby.ext.openssl.SecurityHelper;
@@ -87,44 +80,54 @@
8780
*/
8881
public class PKey {
8982

90-
public static KeyPair readPrivateKey(final byte[] input, final String type)
83+
public enum Type { RSA, DSA, EC; }
84+
85+
public static KeyPair readPrivateKey(final Type type, final byte[] input)
9186
throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {
92-
return readPrivateKey((ASN1Sequence) new ASN1InputStream(input).readObject(), type);
87+
return readPrivateKey(type, mockPrivateKeyInfo(type, input));
88+
}
89+
90+
private static PrivateKeyInfo mockPrivateKeyInfo(final Type type, final byte[] input) throws IOException {
91+
return new PrivateKeyInfo(null, new ASN1InputStream(input).readObject());
9392
}
9493

95-
public static KeyPair readPrivateKey(final ASN1Sequence seq, final String type)
94+
public static KeyPair readPrivateKey(final Type type, final PrivateKeyInfo keyInfo)
9695
throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {
97-
KeySpec pubSpec; KeySpec privSpec;
98-
if ( type.equals("RSA") ) {
99-
ASN1Integer mod = (ASN1Integer) seq.getObjectAt(1);
100-
ASN1Integer pubExp = (ASN1Integer) seq.getObjectAt(2);
101-
ASN1Integer privExp = (ASN1Integer) seq.getObjectAt(3);
102-
ASN1Integer p1 = (ASN1Integer) seq.getObjectAt(4);
103-
ASN1Integer p2 = (ASN1Integer) seq.getObjectAt(5);
104-
ASN1Integer exp1 = (ASN1Integer) seq.getObjectAt(6);
105-
ASN1Integer exp2 = (ASN1Integer) seq.getObjectAt(7);
106-
ASN1Integer crtCoef = (ASN1Integer) seq.getObjectAt(8);
107-
pubSpec = new RSAPublicKeySpec(mod.getValue(), pubExp.getValue());
108-
privSpec = new RSAPrivateCrtKeySpec(mod.getValue(), pubExp.getValue(), privExp.getValue(), p1.getValue(), p2.getValue(), exp1.getValue(),
109-
exp2.getValue(), crtCoef.getValue());
110-
}
111-
else if ( type.equals("DSA") ) {
112-
ASN1Integer p = (ASN1Integer) seq.getObjectAt(1);
113-
ASN1Integer q = (ASN1Integer) seq.getObjectAt(2);
114-
ASN1Integer g = (ASN1Integer) seq.getObjectAt(3);
115-
ASN1Integer y = (ASN1Integer) seq.getObjectAt(4);
116-
ASN1Integer x = (ASN1Integer) seq.getObjectAt(5);
117-
privSpec = new DSAPrivateKeySpec(x.getValue(), p.getValue(), q.getValue(), g.getValue());
118-
pubSpec = new DSAPublicKeySpec(y.getValue(), p.getValue(), q.getValue(), g.getValue());
96+
KeySpec pubSpec; KeySpec privSpec; ASN1Sequence seq;
97+
switch (type) {
98+
case RSA:
99+
seq = (ASN1Sequence) keyInfo.parsePrivateKey();
100+
ASN1Integer mod = (ASN1Integer) seq.getObjectAt(1);
101+
ASN1Integer pubExp = (ASN1Integer) seq.getObjectAt(2);
102+
ASN1Integer privExp = (ASN1Integer) seq.getObjectAt(3);
103+
ASN1Integer p1 = (ASN1Integer) seq.getObjectAt(4);
104+
ASN1Integer p2 = (ASN1Integer) seq.getObjectAt(5);
105+
ASN1Integer exp1 = (ASN1Integer) seq.getObjectAt(6);
106+
ASN1Integer exp2 = (ASN1Integer) seq.getObjectAt(7);
107+
ASN1Integer crtCoef = (ASN1Integer) seq.getObjectAt(8);
108+
pubSpec = new RSAPublicKeySpec(mod.getValue(), pubExp.getValue());
109+
privSpec = new RSAPrivateCrtKeySpec(
110+
mod.getValue(), pubExp.getValue(), privExp.getValue(),
111+
p1.getValue(), p2.getValue(),
112+
exp1.getValue(), exp2.getValue(), crtCoef.getValue());
113+
break;
114+
case DSA:
115+
seq = (ASN1Sequence) keyInfo.parsePrivateKey();
116+
ASN1Integer p = (ASN1Integer) seq.getObjectAt(1);
117+
ASN1Integer q = (ASN1Integer) seq.getObjectAt(2);
118+
ASN1Integer g = (ASN1Integer) seq.getObjectAt(3);
119+
ASN1Integer y = (ASN1Integer) seq.getObjectAt(4);
120+
ASN1Integer x = (ASN1Integer) seq.getObjectAt(5);
121+
privSpec = new DSAPrivateKeySpec(x.getValue(), p.getValue(), q.getValue(), g.getValue());
122+
pubSpec = new DSAPublicKeySpec(y.getValue(), p.getValue(), q.getValue(), g.getValue());
123+
break;
124+
case EC:
125+
return readECPrivateKey(SecurityHelper.getKeyFactory("EC"), keyInfo);
126+
default:
127+
throw new AssertionError("unexpected key type: " + type);
119128
}
120-
else if ( type.equals("EC") ) {
121-
return readECPrivateKey(SecurityHelper.getKeyFactory("EC"), seq);
122-
}
123-
else {
124-
throw new IllegalStateException("unsupported type: " + type);
125-
}
126-
KeyFactory fact = SecurityHelper.getKeyFactory(type);
127-
return new KeyPair(fact.generatePublic(pubSpec), fact.generatePrivate(privSpec));
129+
final KeyFactory keyFactory = SecurityHelper.getKeyFactory(type.name());
130+
return new KeyPair(keyFactory.generatePublic(pubSpec), keyFactory.generatePrivate(privSpec));
128131
}
129132

130133
// d2i_PUBKEY_bio
@@ -264,21 +267,23 @@ public static KeyPair readECPrivateKey(final byte[] input)
264267

265268
public static KeyPair readECPrivateKey(final KeyFactory keyFactory, final byte[] input)
266269
throws IOException, InvalidKeySpecException {
267-
return readECPrivateKey(keyFactory, (ASN1Sequence) ASN1Primitive.fromByteArray(input));
270+
return readECPrivateKey(keyFactory, mockPrivateKeyInfo(Type.EC, input));
268271
}
269272

270-
public static KeyPair readECPrivateKey(final KeyFactory keyFactory, final ASN1Sequence input)
273+
public static KeyPair readECPrivateKey(final KeyFactory keyFactory, final PrivateKeyInfo keyInfo)
271274
throws IOException, InvalidKeySpecException {
272275
try {
273-
org.bouncycastle.asn1.sec.ECPrivateKey pKey = org.bouncycastle.asn1.sec.ECPrivateKey.getInstance(input);
274-
AlgorithmIdentifier algId = new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, pKey.getParametersObject().toASN1Primitive());
275-
PrivateKeyInfo privInfo = new PrivateKeyInfo(algId, pKey.toASN1Primitive());
276-
SubjectPublicKeyInfo pubInfo = new SubjectPublicKeyInfo(algId, pKey.getPublicKey().getBytes());
277-
PKCS8EncodedKeySpec privSpec = new PKCS8EncodedKeySpec(privInfo.getEncoded());
278-
X509EncodedKeySpec pubSpec = new X509EncodedKeySpec(pubInfo.getEncoded());
276+
org.bouncycastle.asn1.sec.ECPrivateKey key = org.bouncycastle.asn1.sec.ECPrivateKey.getInstance(keyInfo.parsePrivateKey());
277+
AlgorithmIdentifier algId = keyInfo.getPrivateKeyAlgorithm();
278+
// NOTE: should only happen when using mockPrivateKeyInfo(Type, byte[])
279+
if (algId == null) algId = new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey);
280+
281+
SubjectPublicKeyInfo pubInfo = new SubjectPublicKeyInfo(algId, key.getPublicKey().getBytes());
282+
PKCS8EncodedKeySpec privSpec = new PKCS8EncodedKeySpec(keyInfo.getEncoded());
283+
X509EncodedKeySpec pubSpec = new X509EncodedKeySpec(pubInfo.getEncoded());
279284

280285
ECPrivateKey privateKey = (ECPrivateKey) keyFactory.generatePrivate(privSpec);
281-
if ( algId.getParameters() instanceof ASN1ObjectIdentifier ) {
286+
if (algId.getParameters() instanceof ASN1ObjectIdentifier) {
282287
privateKey = ECPrivateKeyWithName.wrap(privateKey, (ASN1ObjectIdentifier) algId.getParameters());
283288
}
284289
return new KeyPair(keyFactory.generatePublic(pubSpec), privateKey);
@@ -311,10 +316,11 @@ public static byte[] toDerRSAKey(RSAPublicKey pubKey, RSAPrivateCrtKey privKey)
311316
return new DERSequence(vec).toASN1Primitive().getEncoded(ASN1Encoding.DER);
312317
}
313318

314-
public static ASN1Sequence toASN1Primitive(RSAPublicKey pubKey) {
319+
public static ASN1Sequence toASN1Primitive(final RSAPublicKey publicKey) {
320+
assert publicKey != null : "null public key";
315321
ASN1EncodableVector vec = new ASN1EncodableVector();
316-
vec.add(new ASN1Integer(pubKey.getModulus()));
317-
vec.add(new ASN1Integer(pubKey.getPublicExponent()));
322+
vec.add(new ASN1Integer(publicKey.getModulus()));
323+
vec.add(new ASN1Integer(publicKey.getPublicExponent()));
318324
return new DERSequence(vec);
319325
}
320326

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

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -81,12 +81,10 @@
8181
import javax.crypto.spec.PBEParameterSpec;
8282
import javax.crypto.spec.SecretKeySpec;
8383

84-
import org.bouncycastle.asn1.ASN1Encoding;
8584
import org.bouncycastle.asn1.ASN1TaggedObject;
8685
import org.bouncycastle.asn1.pkcs.PKCS12PBEParams;
8786
import org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo;
8887
import org.bouncycastle.asn1.ASN1Encodable;
89-
import org.bouncycastle.asn1.ASN1Object;
9088
import org.bouncycastle.asn1.ASN1InputStream;
9189
import org.bouncycastle.asn1.ASN1OctetString;
9290
import org.bouncycastle.asn1.ASN1OutputStream;
@@ -129,6 +127,7 @@
129127
import org.jruby.ext.openssl.Cipher.Algorithm;
130128
import org.jruby.ext.openssl.impl.ASN1Registry;
131129
import org.jruby.ext.openssl.impl.CipherSpec;
130+
import org.jruby.ext.openssl.impl.PKey.Type;
132131
import org.jruby.ext.openssl.impl.PKCS10Request;
133132
import org.jruby.ext.openssl.SecurityHelper;
134133
import org.jruby.ext.openssl.util.ByteArrayOutputStream;
@@ -349,10 +348,9 @@ else if ( line.indexOf(BEG_STRING_ECPRIVATEKEY) != -1) {
349348
else if ( line.indexOf(BEG_STRING_PKCS8INF) != -1) {
350349
try {
351350
byte[] bytes = readBase64Bytes(reader, BEF_E + PEM_STRING_PKCS8INF);
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);
351+
final PrivateKeyInfo keyInfo = PrivateKeyInfo.getInstance(bytes);
352+
final Type type = getPrivateKeyType(keyInfo.getPrivateKeyAlgorithm());
353+
return org.jruby.ext.openssl.impl.PKey.readPrivateKey(type, keyInfo);
356354
}
357355
catch (Exception e) {
358356
throw mapReadException("problem creating private key: ", e);
@@ -1270,7 +1268,7 @@ else if ( line.contains(endMarker) ) {
12701268
} else {
12711269
keyBytes = decoded;
12721270
}
1273-
return org.jruby.ext.openssl.impl.PKey.readPrivateKey(keyBytes, type);
1271+
return org.jruby.ext.openssl.impl.PKey.readPrivateKey(Type.valueOf(type), keyBytes);
12741272
}
12751273

12761274
private static byte[] decrypt(byte[] decoded, String dekInfo, char[] passwd)
@@ -1486,23 +1484,23 @@ private static CMSSignedData readPKCS7(BufferedReader in, char[] p, String endMa
14861484

14871485
public static KeyFactory getKeyFactory(final AlgorithmIdentifier algId)
14881486
throws NoSuchAlgorithmException {
1489-
return SecurityHelper.getKeyFactory(getPrivateKeyType(algId));
1487+
return SecurityHelper.getKeyFactory(getPrivateKeyType(algId).name());
14901488
}
14911489

1492-
private static String getPrivateKeyType(final AlgorithmIdentifier algId) {
1490+
private static Type getPrivateKeyType(final AlgorithmIdentifier algId) {
14931491
final ASN1ObjectIdentifier algIdentifier = algId.getAlgorithm();
14941492

14951493
if (X9ObjectIdentifiers.id_ecPublicKey.equals(algIdentifier)) {
1496-
return "EC";
1494+
return Type.EC;
14971495
}
14981496
if (PKCSObjectIdentifiers.rsaEncryption.equals(algIdentifier)) {
1499-
return "RSA";
1497+
return Type.RSA;
15001498
}
15011499
if (X9ObjectIdentifiers.id_dsa.equals(algIdentifier)) {
1502-
return "DSA";
1500+
return Type.DSA;
15031501
}
15041502

1505-
return algIdentifier.getId();
1503+
return Type.valueOf(algIdentifier.getId());
15061504
}
15071505

15081506
private static CertificateFactory getX509CertificateFactory() {

0 commit comments

Comments
 (0)