Skip to content

Commit a5d7de2

Browse files
ziyiluoSalusaSecondus
authored andcommitted
8263404: RsaPrivateKeySpec is always recognized as RSAPrivateCrtKeySpec in RSAKeyFactory.engineGetKeySpec
Co-authored-by: Greg Rubin <rubin@amazon.com> Reviewed-by: valeriep
1 parent 128c0c9 commit a5d7de2

File tree

6 files changed

+287
-58
lines changed

6 files changed

+287
-58
lines changed

src/java.base/share/classes/sun/security/rsa/RSAKeyFactory.java

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -406,6 +406,7 @@ protected <T extends KeySpec> T engineGetKeySpec(Key key, Class<T> keySpec)
406406
if (keySpec.isAssignableFrom(PKCS8_KEYSPEC_CLS)) {
407407
return keySpec.cast(new PKCS8EncodedKeySpec(key.getEncoded()));
408408
} else if (keySpec.isAssignableFrom(RSA_PRIVCRT_KEYSPEC_CLS)) {
409+
// All supported keyspecs (other than PKCS8_KEYSPEC_CLS) descend from RSA_PRIVCRT_KEYSPEC_CLS
409410
if (key instanceof RSAPrivateCrtKey) {
410411
RSAPrivateCrtKey crtKey = (RSAPrivateCrtKey)key;
411412
return keySpec.cast(new RSAPrivateCrtKeySpec(
@@ -419,17 +420,20 @@ protected <T extends KeySpec> T engineGetKeySpec(Key key, Class<T> keySpec)
419420
crtKey.getCrtCoefficient(),
420421
crtKey.getParams()
421422
));
422-
} else {
423-
throw new InvalidKeySpecException
424-
("RSAPrivateCrtKeySpec can only be used with CRT keys");
423+
} else { // RSAPrivateKey (non-CRT)
424+
if (!keySpec.isAssignableFrom(RSA_PRIV_KEYSPEC_CLS)) {
425+
throw new InvalidKeySpecException
426+
("RSAPrivateCrtKeySpec can only be used with CRT keys");
427+
}
428+
429+
// fall through to RSAPrivateKey (non-CRT)
430+
RSAPrivateKey rsaKey = (RSAPrivateKey) key;
431+
return keySpec.cast(new RSAPrivateKeySpec(
432+
rsaKey.getModulus(),
433+
rsaKey.getPrivateExponent(),
434+
rsaKey.getParams()
435+
));
425436
}
426-
} else if (keySpec.isAssignableFrom(RSA_PRIV_KEYSPEC_CLS)) {
427-
RSAPrivateKey rsaKey = (RSAPrivateKey)key;
428-
return keySpec.cast(new RSAPrivateKeySpec(
429-
rsaKey.getModulus(),
430-
rsaKey.getPrivateExponent(),
431-
rsaKey.getParams()
432-
));
433437
} else {
434438
throw new InvalidKeySpecException
435439
("KeySpec must be RSAPrivate(Crt)KeySpec or "

src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11RSAKeyFactory.java

Lines changed: 42 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -277,54 +277,51 @@ <T extends KeySpec> T implGetPublicKeySpec(P11Key key, Class<T> keySpec,
277277

278278
<T extends KeySpec> T implGetPrivateKeySpec(P11Key key, Class<T> keySpec,
279279
Session[] session) throws PKCS11Exception, InvalidKeySpecException {
280+
if (key.sensitive || !key.extractable) {
281+
throw new InvalidKeySpecException("Key is sensitive or not extractable");
282+
}
283+
// If the key is both extractable and not sensitive, then when it was converted into a P11Key
284+
// it was also converted into subclass of RSAPrivateKey which encapsulates all of the logic
285+
// necessary to retrieve the attributes we need. This sub-class will also cache these attributes
286+
// so that we do not need to query them more than once.
287+
// Rather than rewrite this logic and make possibly slow calls to the token, we'll just use
288+
// that existing logic.
280289
if (keySpec.isAssignableFrom(RSAPrivateCrtKeySpec.class)) {
281-
session[0] = token.getObjSession();
282-
CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
283-
new CK_ATTRIBUTE(CKA_MODULUS),
284-
new CK_ATTRIBUTE(CKA_PUBLIC_EXPONENT),
285-
new CK_ATTRIBUTE(CKA_PRIVATE_EXPONENT),
286-
new CK_ATTRIBUTE(CKA_PRIME_1),
287-
new CK_ATTRIBUTE(CKA_PRIME_2),
288-
new CK_ATTRIBUTE(CKA_EXPONENT_1),
289-
new CK_ATTRIBUTE(CKA_EXPONENT_2),
290-
new CK_ATTRIBUTE(CKA_COEFFICIENT),
291-
};
292-
long keyID = key.getKeyID();
293-
try {
294-
token.p11.C_GetAttributeValue(session[0].id(), keyID, attributes);
295-
} finally {
296-
key.releaseKeyID();
297-
}
290+
// All supported keyspecs (other than PKCS8EncodedKeySpec) descend from RSAPrivateCrtKeySpec
291+
if (key instanceof RSAPrivateCrtKey) {
292+
RSAPrivateCrtKey crtKey = (RSAPrivateCrtKey)key;
293+
return keySpec.cast(new RSAPrivateCrtKeySpec(
294+
crtKey.getModulus(),
295+
crtKey.getPublicExponent(),
296+
crtKey.getPrivateExponent(),
297+
crtKey.getPrimeP(),
298+
crtKey.getPrimeQ(),
299+
crtKey.getPrimeExponentP(),
300+
crtKey.getPrimeExponentQ(),
301+
crtKey.getCrtCoefficient(),
302+
crtKey.getParams()
303+
));
304+
} else { // RSAPrivateKey (non-CRT)
305+
if (!keySpec.isAssignableFrom(RSAPrivateKeySpec.class)) {
306+
throw new InvalidKeySpecException
307+
("RSAPrivateCrtKeySpec can only be used with CRT keys");
308+
}
298309

299-
KeySpec spec = new RSAPrivateCrtKeySpec(
300-
attributes[0].getBigInteger(),
301-
attributes[1].getBigInteger(),
302-
attributes[2].getBigInteger(),
303-
attributes[3].getBigInteger(),
304-
attributes[4].getBigInteger(),
305-
attributes[5].getBigInteger(),
306-
attributes[6].getBigInteger(),
307-
attributes[7].getBigInteger()
308-
);
309-
return keySpec.cast(spec);
310-
} else if (keySpec.isAssignableFrom(RSAPrivateKeySpec.class)) {
311-
session[0] = token.getObjSession();
312-
CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
313-
new CK_ATTRIBUTE(CKA_MODULUS),
314-
new CK_ATTRIBUTE(CKA_PRIVATE_EXPONENT),
315-
};
316-
long keyID = key.getKeyID();
317-
try {
318-
token.p11.C_GetAttributeValue(session[0].id(), keyID, attributes);
319-
} finally {
320-
key.releaseKeyID();
321-
}
310+
if (!(key instanceof RSAPrivateKey)) {
311+
// We should never reach here as P11Key.privateKey() should always produce an instance
312+
// of RSAPrivateKey when the RSA key is both extractable and non-sensitive.
313+
throw new InvalidKeySpecException
314+
("Key must be an instance of RSAPrivateKeySpec. Was " + key.getClass());
315+
}
322316

323-
KeySpec spec = new RSAPrivateKeySpec(
324-
attributes[0].getBigInteger(),
325-
attributes[1].getBigInteger()
326-
);
327-
return keySpec.cast(spec);
317+
// fall through to RSAPrivateKey (non-CRT)
318+
RSAPrivateKey rsaKey = (RSAPrivateKey) key;
319+
return keySpec.cast(new RSAPrivateKeySpec(
320+
rsaKey.getModulus(),
321+
rsaKey.getPrivateExponent(),
322+
rsaKey.getParams()
323+
));
324+
}
328325
} else { // PKCS#8 handled in superclass
329326
throw new InvalidKeySpecException("Only RSAPrivate(Crt)KeySpec "
330327
+ "and PKCS8EncodedKeySpec supported for RSA private keys");

test/jdk/java/security/KeyFactory/KeyFactoryGetKeySpecForInvalidSpec.java

Lines changed: 66 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,31 +23,95 @@
2323

2424
/**
2525
* @test
26-
* @bug 8254717
26+
* @bug 8254717 8263404
2727
* @summary isAssignableFrom checks in KeyFactorySpi.engineGetKeySpec appear to be backwards.
2828
* @author Greg Rubin, Ziyi Luo
2929
*/
3030

31+
import java.math.BigInteger;
3132
import java.security.KeyFactory;
3233
import java.security.KeyPair;
3334
import java.security.KeyPairGenerator;
35+
import java.security.interfaces.RSAPrivateCrtKey;
36+
import java.security.interfaces.RSAPrivateKey;
3437
import java.security.spec.*;
3538

3639
public class KeyFactoryGetKeySpecForInvalidSpec {
40+
41+
// Test for 8263404: This method generates RSAPrivateKey (without Crt info) from a RSAPrivateCrtKey
42+
public static RSAPrivateKey privateCrtToPrivate(RSAPrivateCrtKey crtKey) {
43+
return new RSAPrivateKey() {
44+
@Override
45+
public BigInteger getPrivateExponent() {
46+
return crtKey.getPrivateExponent();
47+
}
48+
49+
@Override
50+
public String getAlgorithm() {
51+
return crtKey.getAlgorithm();
52+
}
53+
54+
@Override
55+
public String getFormat() {
56+
return crtKey.getFormat();
57+
}
58+
59+
@Override
60+
public byte[] getEncoded() {
61+
return crtKey.getEncoded();
62+
}
63+
64+
@Override
65+
public BigInteger getModulus() {
66+
return crtKey.getModulus();
67+
}
68+
};
69+
}
70+
3771
public static void main(String[] args) throws Exception {
38-
KeyPairGenerator kg = KeyPairGenerator.getInstance("RSA");
72+
KeyPairGenerator kg = KeyPairGenerator.getInstance("RSA", "SunRsaSign");
3973
kg.initialize(2048);
4074
KeyPair pair = kg.generateKeyPair();
4175

4276
KeyFactory factory = KeyFactory.getInstance("RSA");
4377

78+
// === Case 1: private key is RSAPrivateCrtKey, keySpec is RSAPrivateKeySpec
79+
// === Expected: return RSAPrivateCrtKeySpec
4480
// Since RSAPrivateCrtKeySpec inherits from RSAPrivateKeySpec, we'd expect this next line to return an instance of RSAPrivateKeySpec
4581
// (because the private key has CRT parts).
4682
KeySpec spec = factory.getKeySpec(pair.getPrivate(), RSAPrivateKeySpec.class);
4783
if (!(spec instanceof RSAPrivateCrtKeySpec)) {
4884
throw new Exception("Spec should be an instance of RSAPrivateCrtKeySpec");
4985
}
5086

87+
// === Case 2: private key is RSAPrivateCrtKey, keySpec is RSAPrivateCrtKeySpec
88+
// === Expected: return RSAPrivateCrtKeySpec
89+
spec = factory.getKeySpec(pair.getPrivate(), RSAPrivateCrtKeySpec.class);
90+
if (!(spec instanceof RSAPrivateCrtKeySpec)) {
91+
throw new Exception("Spec should be an instance of RSAPrivateCrtKeySpec");
92+
}
93+
94+
// === Case 3: private key is RSAPrivateKey, keySpec is RSAPrivateKeySpec
95+
// === Expected: return RSAPrivateKeySpec not RSAPrivateCrtKeySpec
96+
RSAPrivateKey notCrtKey = privateCrtToPrivate((RSAPrivateCrtKey)pair.getPrivate());
97+
// InvalidKeySpecException should not be thrown
98+
KeySpec notCrtSpec = factory.getKeySpec(notCrtKey, RSAPrivateKeySpec.class);
99+
if (notCrtSpec instanceof RSAPrivateCrtKeySpec) {
100+
throw new Exception("Spec should be an instance of RSAPrivateKeySpec not RSAPrivateCrtKeySpec");
101+
}
102+
if (!(notCrtSpec instanceof RSAPrivateKeySpec)) {
103+
throw new Exception("Spec should be an instance of RSAPrivateKeySpec");
104+
}
105+
106+
// === Case 4: private key is RSAPrivateKey, keySpec is RSAPrivateCrtKeySpec
107+
// === Expected: throw InvalidKeySpecException
108+
try {
109+
factory.getKeySpec(notCrtKey, RSAPrivateCrtKeySpec.class);
110+
throw new Exception("InvalidKeySpecException is expected but not thrown");
111+
} catch (InvalidKeySpecException e) {
112+
// continue;
113+
}
114+
51115
// This next line should give an InvalidKeySpec exception
52116
try {
53117
spec = factory.getKeySpec(pair.getPublic(), FakeX509Spec.class);

test/jdk/sun/security/pkcs11/PKCS11Test.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ public static void main(PKCS11Test test, String[] args) throws Exception {
190190
test.enableSM = true;
191191
} else {
192192
throw new RuntimeException("Unknown Command, use 'sm' as "
193-
+ "first arguemtn to enable security manager");
193+
+ "first argument to enable security manager");
194194
}
195195
}
196196
if (test.enableSM) {
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
2+
# Configuration to run unit tests with NSS
3+
# Marks private and secret keys as sensitive
4+
5+
name = NSS
6+
7+
slot = 1
8+
9+
#showInfo = true
10+
11+
library = ${pkcs11test.nss.lib}
12+
13+
nssArgs = "configdir='${pkcs11test.nss.db}' certPrefix='' keyPrefix='' secmod='secmod.db' flags=readOnly"
14+
15+
disabledMechanisms = {
16+
CKM_DSA_SHA224
17+
CKM_DSA_SHA256
18+
CKM_DSA_SHA384
19+
CKM_DSA_SHA512
20+
CKM_DSA_SHA3_224
21+
CKM_DSA_SHA3_256
22+
CKM_DSA_SHA3_384
23+
CKM_DSA_SHA3_512
24+
CKM_ECDSA_SHA224
25+
CKM_ECDSA_SHA256
26+
CKM_ECDSA_SHA384
27+
CKM_ECDSA_SHA512
28+
CKM_ECDSA_SHA3_224
29+
CKM_ECDSA_SHA3_256
30+
CKM_ECDSA_SHA3_384
31+
CKM_ECDSA_SHA3_512
32+
}
33+
34+
attributes = compatibility
35+
36+
# NSS needs CKA_NETSCAPE_DB for DSA and DH private keys
37+
# just put an arbitrary value in there to make it happy
38+
39+
attributes(*,CKO_PRIVATE_KEY,CKK_DSA) = {
40+
CKA_NETSCAPE_DB = 0h00
41+
}
42+
43+
attributes(*,CKO_PRIVATE_KEY,CKK_DH) = {
44+
CKA_NETSCAPE_DB = 0h00
45+
}
46+
47+
# Everything above this line (with the exception of the comment at the top) is copy/pasted from p11-nss.txt
48+
49+
# Make all private keys sensitive
50+
attributes(*,CKO_PRIVATE_KEY,*) = {
51+
CKA_SENSITIVE = true
52+
}
53+
54+
55+
# Make all secret keys sensitive
56+
attributes(*,CKO_SECRET_KEY,*) = {
57+
CKA_SENSITIVE = true
58+
}

0 commit comments

Comments
 (0)