8023980: JCE doesn't provide any class to handle RSA private key in PKCS#1

Reviewed-by: weijun
This commit is contained in:
Valerie Peng 2021-01-18 02:26:17 +00:00
parent 5dc5d9401e
commit 68cf65d284
6 changed files with 409 additions and 161 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -43,13 +43,15 @@ import sun.security.rsa.RSAUtil.KeyType;
* between the following:
*
* For public keys:
* . PublicKey with an X.509 encoding
* . RSA PublicKey with an X.509 encoding
* . RSA PublicKey with an PKCS#1 encoding
* . RSAPublicKey
* . RSAPublicKeySpec
* . X509EncodedKeySpec
*
* For private keys:
* . PrivateKey with a PKCS#8 encoding
* . RSA PrivateKey with a PKCS#8 encoding
* . RSA PrivateKey with a PKCS#1 encoding
* . RSAPrivateKey
* . RSAPrivateCrtKey
* . RSAPrivateKeySpec
@ -95,8 +97,8 @@ public class RSAKeyFactory extends KeyFactorySpi {
return new RSAKeyFactory(type);
}
// Internal utility method for checking key algorithm
private static void checkKeyAlgo(Key key, String expectedAlg)
// pkg-private utility method for checking key algorithm
static void checkKeyAlgo(Key key, String expectedAlg)
throws InvalidKeyException {
String keyAlg = key.getAlgorithm();
if (keyAlg == null || !(keyAlg.equalsIgnoreCase(expectedAlg))) {
@ -265,14 +267,10 @@ public class RSAKeyFactory extends KeyFactorySpi {
// catch providers that incorrectly implement RSAPublicKey
throw new InvalidKeyException("Invalid key", e);
}
} else if ("X.509".equals(key.getFormat())) {
RSAPublicKey translated = new RSAPublicKeyImpl(key.getEncoded());
// ensure the key algorithm matches the current KeyFactory instance
checkKeyAlgo(translated, type.keyAlgo);
return translated;
} else {
throw new InvalidKeyException("Public keys must be instance "
+ "of RSAPublicKey or have X.509 encoding");
// create new key based on the format and encoding of current 'key'
return RSAPublicKeyImpl.newKey(type, key.getFormat(),
key.getEncoded());
}
}
@ -309,15 +307,9 @@ public class RSAKeyFactory extends KeyFactorySpi {
// catch providers that incorrectly implement RSAPrivateKey
throw new InvalidKeyException("Invalid key", e);
}
} else if ("PKCS#8".equals(key.getFormat())) {
RSAPrivateKey translated =
RSAPrivateCrtKeyImpl.newKey(key.getEncoded());
// ensure the key algorithm matches the current KeyFactory instance
checkKeyAlgo(translated, type.keyAlgo);
return translated;
} else {
throw new InvalidKeyException("Private keys must be instance "
+ "of RSAPrivate(Crt)Key or have PKCS#8 encoding");
return RSAPrivateCrtKeyImpl.newKey(type, key.getFormat(),
key.getEncoded());
}
}
@ -325,11 +317,8 @@ public class RSAKeyFactory extends KeyFactorySpi {
private PublicKey generatePublic(KeySpec keySpec)
throws GeneralSecurityException {
if (keySpec instanceof X509EncodedKeySpec) {
X509EncodedKeySpec x509Spec = (X509EncodedKeySpec)keySpec;
RSAPublicKey generated = new RSAPublicKeyImpl(x509Spec.getEncoded());
// ensure the key algorithm matches the current KeyFactory instance
checkKeyAlgo(generated, type.keyAlgo);
return generated;
return RSAPublicKeyImpl.newKey(type, "X.509",
((X509EncodedKeySpec)keySpec).getEncoded());
} else if (keySpec instanceof RSAPublicKeySpec) {
RSAPublicKeySpec rsaSpec = (RSAPublicKeySpec)keySpec;
try {
@ -351,11 +340,8 @@ public class RSAKeyFactory extends KeyFactorySpi {
private PrivateKey generatePrivate(KeySpec keySpec)
throws GeneralSecurityException {
if (keySpec instanceof PKCS8EncodedKeySpec) {
PKCS8EncodedKeySpec pkcsSpec = (PKCS8EncodedKeySpec)keySpec;
RSAPrivateKey generated = RSAPrivateCrtKeyImpl.newKey(pkcsSpec.getEncoded());
// ensure the key algorithm matches the current KeyFactory instance
checkKeyAlgo(generated, type.keyAlgo);
return generated;
return RSAPrivateCrtKeyImpl.newKey(type, "PKCS#8",
((PKCS8EncodedKeySpec)keySpec).getEncoded());
} else if (keySpec instanceof RSAPrivateCrtKeySpec) {
RSAPrivateCrtKeySpec rsaSpec = (RSAPrivateCrtKeySpec)keySpec;
try {
@ -395,7 +381,8 @@ public class RSAKeyFactory extends KeyFactorySpi {
try {
// convert key to one of our keys
// this also verifies that the key is a valid RSA key and ensures
// that the encoding is X.509/PKCS#8 for public/private keys
// that the encoding is X.509/PKCS#8 or PKCS#1 for public/private
// keys
key = engineTranslateKey(key);
} catch (InvalidKeyException e) {
throw new InvalidKeySpecException(e);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -74,30 +74,52 @@ public final class RSAPrivateCrtKeyImpl
private transient AlgorithmParameterSpec keyParams;
/**
* Generate a new key from its encoding. Returns a CRT key if possible
* and a non-CRT key otherwise. Used by RSAKeyFactory.
* Generate a new RSAPrivate(Crt)Key from the specified type,
* format and encoding. Returns a CRT key if possible and a non-CRT
* key otherwise.
* Also used by SunPKCS11 provider.
*/
public static RSAPrivateKey newKey(byte[] encoded)
throws InvalidKeyException {
public static RSAPrivateKey newKey(KeyType type, String format,
byte[] encoded) throws InvalidKeyException {
if (encoded == null || encoded.length == 0) {
throw new InvalidKeyException("Missing key encoding");
}
RSAPrivateCrtKeyImpl key = new RSAPrivateCrtKeyImpl(encoded);
// check all CRT-specific components are available, if any one
// missing, return a non-CRT key instead
if ((key.getPublicExponent().signum() == 0) ||
(key.getPrimeExponentP().signum() == 0) ||
(key.getPrimeExponentQ().signum() == 0) ||
(key.getPrimeP().signum() == 0) ||
(key.getPrimeQ().signum() == 0) ||
(key.getCrtCoefficient().signum() == 0)) {
return new RSAPrivateKeyImpl(
key.type, key.keyParams,
key.getModulus(),
key.getPrivateExponent()
);
} else {
return key;
switch (format) {
case "PKCS#8":
RSAPrivateCrtKeyImpl key = new RSAPrivateCrtKeyImpl(encoded);
RSAKeyFactory.checkKeyAlgo(key, type.keyAlgo);
// check all CRT-specific components are available, if any one
// missing, return a non-CRT key instead
if ((key.getPublicExponent().signum() == 0) ||
(key.getPrimeExponentP().signum() == 0) ||
(key.getPrimeExponentQ().signum() == 0) ||
(key.getPrimeP().signum() == 0) ||
(key.getPrimeQ().signum() == 0) ||
(key.getCrtCoefficient().signum() == 0)) {
return new RSAPrivateKeyImpl(key.type, key.keyParams,
key.getModulus(), key.getPrivateExponent());
} else {
return key;
}
case "PKCS#1":
try {
BigInteger[] comps = parseASN1(encoded);
if ((comps[1].signum() == 0) || (comps[3].signum() == 0) ||
(comps[4].signum() == 0) || (comps[5].signum() == 0) ||
(comps[6].signum() == 0) || (comps[7].signum() == 0)) {
return new RSAPrivateKeyImpl(type, null, comps[0],
comps[2]);
} else {
return new RSAPrivateCrtKeyImpl(type, null, comps[0],
comps[1], comps[2], comps[3], comps[4], comps[5],
comps[6], comps[7]);
}
} catch (IOException ioe) {
throw new InvalidKeyException("Invalid PKCS#1 encoding", ioe);
}
default:
throw new InvalidKeyException("Unsupported RSA Private(Crt)Key "
+ "format: " + format);
}
}
@ -126,7 +148,7 @@ public final class RSAPrivateCrtKeyImpl
/**
* Construct a key from its encoding. Called from newKey above.
*/
RSAPrivateCrtKeyImpl(byte[] encoded) throws InvalidKeyException {
private RSAPrivateCrtKeyImpl(byte[] encoded) throws InvalidKeyException {
super(encoded);
parseKeyBits();
RSAKeyFactory.checkRSAProviderKeyLengths(n.bitLength(), e);
@ -258,37 +280,47 @@ public final class RSAPrivateCrtKeyImpl
+ "\n modulus: " + n + "\n private exponent: " + d;
}
// utility method for parsing DER encoding of RSA private keys in PKCS#1
// format as defined in RFC 8017 Appendix A.1.2, i.e. SEQ of version, n,
// e, d, p, q, pe, qe, and coeff, and return the parsed components.
private static BigInteger[] parseASN1(byte[] raw) throws IOException {
DerValue derValue = new DerValue(raw);
if (derValue.tag != DerValue.tag_Sequence) {
throw new IOException("Not a SEQUENCE");
}
int version = derValue.data.getInteger();
if (version != 0) {
throw new IOException("Version must be 0");
}
BigInteger[] result = new BigInteger[8]; // n, e, d, p, q, pe, qe, coeff
/*
* Some implementations do not correctly encode ASN.1 INTEGER values
* in 2's complement format, resulting in a negative integer when
* decoded. Correct the error by converting it to a positive integer.
*
* See CR 6255949
*/
for (int i = 0; i < result.length; i++) {
result[i] = derValue.data.getPositiveBigInteger();
}
if (derValue.data.available() != 0) {
throw new IOException("Extra data available");
}
return result;
}
private void parseKeyBits() throws InvalidKeyException {
try {
DerInputStream in = new DerInputStream(key);
DerValue derValue = in.getDerValue();
if (derValue.tag != DerValue.tag_Sequence) {
throw new IOException("Not a SEQUENCE");
}
DerInputStream data = derValue.data;
int version = data.getInteger();
if (version != 0) {
throw new IOException("Version must be 0");
}
/*
* Some implementations do not correctly encode ASN.1 INTEGER values
* in 2's complement format, resulting in a negative integer when
* decoded. Correct the error by converting it to a positive integer.
*
* See CR 6255949
*/
n = data.getPositiveBigInteger();
e = data.getPositiveBigInteger();
d = data.getPositiveBigInteger();
p = data.getPositiveBigInteger();
q = data.getPositiveBigInteger();
pe = data.getPositiveBigInteger();
qe = data.getPositiveBigInteger();
coeff = data.getPositiveBigInteger();
if (derValue.data.available() != 0) {
throw new IOException("Extra data available");
}
BigInteger[] comps = parseASN1(key);
n = comps[0];
e = comps[1];
d = comps[2];
p = comps[3];
q = comps[4];
pe = comps[5];
qe = comps[6];
coeff = comps[7];
} catch (IOException e) {
throw new InvalidKeyException("Invalid RSA private key", e);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -66,17 +66,36 @@ public final class RSAPublicKeyImpl extends X509Key implements RSAPublicKey {
private transient AlgorithmParameterSpec keyParams;
/**
* Generate a new RSAPublicKey from the specified encoding.
* Used by SunPKCS11 provider.
* Generate a new RSAPublicKey from the specified type, format, and
* encoding.
* Also used by SunPKCS11 provider.
*/
public static RSAPublicKey newKey(byte[] encoded)
throws InvalidKeyException {
return new RSAPublicKeyImpl(encoded);
public static RSAPublicKey newKey(KeyType type, String format,
byte[] encoded) throws InvalidKeyException {
RSAPublicKey key;
switch (format) {
case "X.509":
key = new RSAPublicKeyImpl(encoded);
RSAKeyFactory.checkKeyAlgo(key, type.keyAlgo);
break;
case "PKCS#1":
try {
BigInteger[] comps = parseASN1(encoded);
key = new RSAPublicKeyImpl(type, null, comps[0], comps[1]);
} catch (IOException ioe) {
throw new InvalidKeyException("Invalid PKCS#1 encoding", ioe);
}
break;
default:
throw new InvalidKeyException("Unsupported RSA PublicKey format: " +
format);
}
return key;
}
/**
* Generate a new RSAPublicKey from the specified type and components.
* Used by SunPKCS11 provider.
* Also used by SunPKCS11 provider.
*/
public static RSAPublicKey newKey(KeyType type,
AlgorithmParameterSpec params, BigInteger n, BigInteger e)
@ -123,9 +142,9 @@ public final class RSAPublicKeyImpl extends X509Key implements RSAPublicKey {
}
/**
* Construct a key from its encoding. Used by RSAKeyFactory.
* Construct a key from its encoding.
*/
RSAPublicKeyImpl(byte[] encoded) throws InvalidKeyException {
private RSAPublicKeyImpl(byte[] encoded) throws InvalidKeyException {
if (encoded == null || encoded.length == 0) {
throw new InvalidKeyException("Missing key encoding");
}
@ -181,22 +200,30 @@ public final class RSAPublicKeyImpl extends X509Key implements RSAPublicKey {
return keyParams;
}
// utility method for parsing DER encoding of RSA public keys in PKCS#1
// format as defined in RFC 8017 Appendix A.1.1, i.e. SEQ of n and e.
private static BigInteger[] parseASN1(byte[] raw) throws IOException {
DerValue derValue = new DerValue(raw);
if (derValue.tag != DerValue.tag_Sequence) {
throw new IOException("Not a SEQUENCE");
}
BigInteger[] result = new BigInteger[2]; // n, e
result[0] = derValue.data.getPositiveBigInteger();
result[1] = derValue.data.getPositiveBigInteger();
if (derValue.data.available() != 0) {
throw new IOException("Extra data available");
}
return result;
}
/**
* Parse the key. Called by X509Key.
*/
protected void parseKeyBits() throws InvalidKeyException {
try {
DerInputStream in = new DerInputStream(getKey().toByteArray());
DerValue derValue = in.getDerValue();
if (derValue.tag != DerValue.tag_Sequence) {
throw new IOException("Not a SEQUENCE");
}
DerInputStream data = derValue.data;
n = data.getPositiveBigInteger();
e = data.getPositiveBigInteger();
if (derValue.data.available() != 0) {
throw new IOException("Extra data available");
}
BigInteger[] comps = parseASN1(getKey().toByteArray());
n = comps[0];
e = comps[1];
} catch (IOException e) {
throw new InvalidKeyException("Invalid RSA public key", e);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -32,6 +32,8 @@ import java.security.interfaces.*;
import java.security.spec.*;
import sun.security.rsa.RSAPublicKeyImpl;
import sun.security.rsa.RSAPrivateCrtKeyImpl;
import sun.security.rsa.RSAUtil.KeyType;
import static sun.security.pkcs11.TemplateManager.*;
import sun.security.pkcs11.wrapper.*;
import static sun.security.pkcs11.wrapper.PKCS11Constants.*;
@ -58,14 +60,11 @@ final class P11RSAKeyFactory extends P11KeyFactory {
rsaKey.getModulus(),
rsaKey.getPublicExponent()
);
} else if ("X.509".equals(key.getFormat())) {
// let SunRsaSign provider parse for us, then recurse
byte[] encoded = key.getEncoded();
key = RSAPublicKeyImpl.newKey(encoded);
return implTranslatePublicKey(key);
} else {
throw new InvalidKeyException("PublicKey must be instance "
+ "of RSAPublicKey or have X.509 encoding");
// let SunRsaSign provider parse for us, then recurse
key = RSAPublicKeyImpl.newKey(KeyType.RSA, key.getFormat(),
key.getEncoded());
return implTranslatePublicKey(key);
}
} catch (PKCS11Exception e) {
throw new InvalidKeyException("Could not create RSA public key", e);
@ -93,14 +92,11 @@ final class P11RSAKeyFactory extends P11KeyFactory {
rsaKey.getModulus(),
rsaKey.getPrivateExponent()
);
} else if ("PKCS#8".equals(key.getFormat())) {
// let SunRsaSign provider parse for us, then recurse
byte[] encoded = key.getEncoded();
key = sun.security.rsa.RSAPrivateCrtKeyImpl.newKey(encoded);
return implTranslatePrivateKey(key);
} else {
throw new InvalidKeyException("Private key must be instance "
+ "of RSAPrivate(Crt)Key or have PKCS#8 encoding");
// let SunRsaSign provider parse for us, then recurse
key = RSAPrivateCrtKeyImpl.newKey(KeyType.RSA, key.getFormat(),
key.getEncoded());
return implTranslatePrivateKey(key);
}
} catch (PKCS11Exception e) {
throw new InvalidKeyException("Could not create RSA private key", e);
@ -113,8 +109,8 @@ final class P11RSAKeyFactory extends P11KeyFactory {
token.ensureValid();
if (keySpec instanceof X509EncodedKeySpec) {
try {
byte[] encoded = ((X509EncodedKeySpec)keySpec).getEncoded();
PublicKey key = RSAPublicKeyImpl.newKey(encoded);
PublicKey key = RSAPublicKeyImpl.newKey(KeyType.RSA, "X.509",
((X509EncodedKeySpec)keySpec).getEncoded());
return implTranslatePublicKey(key);
} catch (InvalidKeyException e) {
throw new InvalidKeySpecException
@ -143,9 +139,8 @@ final class P11RSAKeyFactory extends P11KeyFactory {
token.ensureValid();
if (keySpec instanceof PKCS8EncodedKeySpec) {
try {
byte[] encoded = ((PKCS8EncodedKeySpec)keySpec).getEncoded();
PrivateKey key =
sun.security.rsa.RSAPrivateCrtKeyImpl.newKey(encoded);
PrivateKey key = RSAPrivateCrtKeyImpl.newKey(KeyType.RSA,
"PKCS#8", ((PKCS8EncodedKeySpec)keySpec).getEncoded());
return implTranslatePrivateKey(key);
} catch (GeneralSecurityException e) {
throw new InvalidKeySpecException

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -23,7 +23,7 @@
/*
* @test
* @bug 4856966
* @bug 4856966 8023980
* @summary Test KeyFactory of the new RSA provider
* @author Andreas Sterbenz
* @library /test/lib ..
@ -42,6 +42,84 @@ public class TestKeyFactory extends PKCS11Test {
private static final char[] password = "test12".toCharArray();
private static final String PKCS1_PRIV_STR =
// the BASE64 string between -----BEGIN RSA PRIVATE KEY-----
// and -----END RSA PRIVATE KEY-----
"MIIEowIBAAKCAQEA0OIArlYES4X1XMTLDordtN/XIWFE1wvhl40RsHWM2n99+Stp" +
"CCJCcUb5FJ2/kefj/XRwB6p5IMpIZrHZqC8XXzlX5fpiFaSu2xnk17oWUKoErW27" +
"Stm098pU2RoUxWPKVl+42a8iVp8tijNElBNFALCGi0zXOhcTxMh0q1Wk0UhMJqam" +
"v5YnCKmT4THwwGYn/KeK3M7Qa+o5MoVBHLbeT9LJgEmSluVzIh44Lh6weX0bw72P" +
"8X2praOhbzg2B343MqS/rMLw6On+0i7ccEgp23vX9G5w85q4A5FSIrk4S/pyv5sO" +
"rwjCQKBW1TS0/2iB9zNkFMj5/+h7l2oqTT7sSQIDAQABAoIBADn6sXOynoiUC1IP" +
"sck8lGOTSjSSujfyrVCSsJlJV6qCfuX9va6rS8QDjjnBu531PtxoSHxoPizy2Pvg" +
"W+kKATPGR/am9DjLuFlKq7GRjoYfWyMEdVtGaKvq9ng4fBF6LHyjHz0VFrPyhQJ6" +
"TovHeXzCguYBkzAlnbAeb/vqzs/kABbOuSHVi7DsaixCoEX9zOptFYQw/l8rh68+" +
"UF2bpNNH3jOC1uN3vZtuSwCupqtN+2Mpkx2h04Rk75vWIhrnPeMgmcd3yP4LNZMR" +
"mfaynb63RRzVkNis7+NVk016SQ1oL79mrBvy5rBg3HeCeArwvqZAmOaWsLSWHzCy" +
"zlVlMTECgYEA6JlnMpC956Qi8HX5ye4Hu2ovBdbNGtH/TMkZmColJz9P7CvNkNIb" +
"Od6mvLMydbPHkhdBUDWD4rhiCKHrf5zKju1i24YqWcvuSGotWj4/KQ3+87mLZM+7" +
"daBsJBmSEVB80sgA9ItqSgOyNoNFpiDgFnlszAfb0n9XXEzB/pwSw1UCgYEA5eXI" +
"d+eKugugP+n6CluQfyxfN6WWCzfqWToCTTxPn2i12AiEssXy+kyLjupJVLWSivdo" +
"83wD5LuxFRGc9P+aKQERPhb0AFaxf1llUCXla65/x2So5xjMvtuzgQ0OktPJqJXq" +
"hYGunctsr5rje33+7vlx4xWkrL2PrQWzJabn7SUCgYEAqw3FesY/Ik7u8u+P1xSZ" +
"0xXvptek1oiAu7NYgzLbR9WjrQc5kbsyEojPDg6qmSyxI5q+iYIRj3YRgk+xpJNl" +
"0154SQCNvKPghJiw6aDFSifkytA01tp9/a8QWCwF433RjiFPsoekjvHQ6Y34dofO" +
"xDhf7lwJKPBFCrfYIqocklECgYAIPI9OHHGP8NKw94UJ0fX/WGug5sHVbQ9sWvOy" +
"KLMBlxLMxqFadlUaOpvVZvdxnX++ktajwpGxJDhX9OWWsYGobm1buB7N1E1Prrg+" +
"gt0RWpMhZa3Xeb/8Jorr2Lfo8sWK0LQyTE8hQCSIthfoWL9FeJJn/GKF/dSj8kxU" +
"0QIGMQKBgG/8U/zZ87DzfXS81P1p+CmH474wmou4KD2/zXp/lDR9+dlIUeijlIbU" +
"P6Y5xJvT33Y40giW9irShgDHjZgw0ap11K3b2HzLImdPEaBiENo735rpLs8WLK9H" +
"+yeRbiP2y9To7sTihm9Jrkctzp6sqFtKyye1+S21X1tMz8NGfXen";
private static final String PKCS1_PUB_STR =
// the BASE64 string between -----BEGIN RSA PUBLIC KEY-----
// and -----END RSA PUBLIC KEY-----
"MIIBCgKCAQEA0OIArlYES4X1XMTLDordtN/XIWFE1wvhl40RsHWM2n99+StpCCJC" +
"cUb5FJ2/kefj/XRwB6p5IMpIZrHZqC8XXzlX5fpiFaSu2xnk17oWUKoErW27Stm0" +
"98pU2RoUxWPKVl+42a8iVp8tijNElBNFALCGi0zXOhcTxMh0q1Wk0UhMJqamv5Yn" +
"CKmT4THwwGYn/KeK3M7Qa+o5MoVBHLbeT9LJgEmSluVzIh44Lh6weX0bw72P8X2p" +
"raOhbzg2B343MqS/rMLw6On+0i7ccEgp23vX9G5w85q4A5FSIrk4S/pyv5sOrwjC" +
"QKBW1TS0/2iB9zNkFMj5/+h7l2oqTT7sSQIDAQAB";
private static final PrivateKey CUSTOM_PRIV;
private static final PublicKey CUSTOM_PUB;
static {
byte[] encodedPriv = Base64.getDecoder().decode(PKCS1_PRIV_STR);
CUSTOM_PRIV = new PrivateKey() {
@Override
public String getAlgorithm() {
return "RSA";
}
@Override
public String getFormat() {
return "PKCS#1";
}
@Override
public byte[] getEncoded() {
// skip cloning for testing key.
return encodedPriv;
}
};
byte[] encodedPub = Base64.getDecoder().decode(PKCS1_PUB_STR);
CUSTOM_PUB = new PublicKey() {
@Override
public String getAlgorithm() {
return "RSA";
}
@Override
public String getFormat() {
return "PKCS#1";
}
@Override
public byte[] getEncoded() {
// skip cloning for testing key.
return encodedPub;
}
};
}
static KeyStore getKeyStore() throws Exception {
KeyStore ks;
try (InputStream in = new FileInputStream(new File(BASE, "rsakeys.ks"))) {
@ -68,44 +146,64 @@ public class TestKeyFactory extends PKCS11Test {
throw new Exception("Format not PKCS#8");
}
}
if (key1.equals(key2) == false) {
throw new Exception("Keys not equal");
// skip equals check when key1 is custom key
if (key1 != CUSTOM_PRIV && key1 != CUSTOM_PUB) {
if (!key1.equals(key2)) {
throw new Exception("Keys not equal");
}
}
if (Arrays.equals(key1.getEncoded(), key2.getEncoded()) == false) {
// only compare encodings if keys are of the same format
if (key1.getFormat().equals(key2.getFormat()) &&
!Arrays.equals(key1.getEncoded(), key2.getEncoded())) {
throw new Exception("Encodings not equal");
}
}
private static void testPublic(KeyFactory kf, PublicKey key) throws Exception {
System.out.println("Testing public key...");
private static void testPublic(KeyFactory kf, PublicKey key)
throws Exception {
System.out.println("Testing " + (key == CUSTOM_PUB? "PKCS#1" : "") +
" public key...");
PublicKey key2 = (PublicKey)kf.translateKey(key);
KeySpec rsaSpec = kf.getKeySpec(key, RSAPublicKeySpec.class);
PublicKey key3 = kf.generatePublic(rsaSpec);
KeySpec x509Spec = kf.getKeySpec(key, X509EncodedKeySpec.class);
PublicKey key4 = kf.generatePublic(x509Spec);
KeySpec x509Spec2 = new X509EncodedKeySpec(key.getEncoded());
PublicKey key5 = kf.generatePublic(x509Spec2);
testKey(key, key);
if (key != CUSTOM_PUB) {
testKey(key, key);
}
testKey(key, key2);
testKey(key, key3);
testKey(key, key4);
testKey(key, key5);
if (key.getFormat().equalsIgnoreCase("X.509")) {
KeySpec x509Spec2 = new X509EncodedKeySpec(key.getEncoded());
PublicKey key5 = kf.generatePublic(x509Spec2);
testKey(key, key5);
}
}
private static void testPrivate(KeyFactory kf, PrivateKey key) throws Exception {
System.out.println("Testing private key...");
private static void testPrivate(KeyFactory kf, PrivateKey key)
throws Exception {
System.out.println("Testing " + (key == CUSTOM_PRIV? "PKCS#1" : "") +
" private key...");
PrivateKey key2 = (PrivateKey)kf.translateKey(key);
KeySpec rsaSpec = kf.getKeySpec(key, RSAPrivateCrtKeySpec.class);
PrivateKey key3 = kf.generatePrivate(rsaSpec);
KeySpec pkcs8Spec = kf.getKeySpec(key, PKCS8EncodedKeySpec.class);
PrivateKey key4 = kf.generatePrivate(pkcs8Spec);
KeySpec pkcs8Spec2 = new PKCS8EncodedKeySpec(key.getEncoded());
PrivateKey key5 = kf.generatePrivate(pkcs8Spec2);
testKey(key, key);
if (key != CUSTOM_PRIV) {
testKey(key, key);
}
testKey(key, key2);
testKey(key, key3);
testKey(key, key4);
testKey(key, key5);
if (key.getFormat().equalsIgnoreCase("PKCS#8")) {
KeySpec pkcs8Spec2 = new PKCS8EncodedKeySpec(key.getEncoded());
PrivateKey key5 = kf.generatePrivate(pkcs8Spec2);
testKey(key, key5);
}
// XXX PKCS#11 providers may not support non-CRT keys (e.g. NSS)
// KeySpec rsaSpec2 = kf.getKeySpec(key, RSAPrivateKeySpec.class);
@ -145,6 +243,10 @@ public class TestKeyFactory extends PKCS11Test {
test(kf, ks.getCertificate(alias).getPublicKey());
}
}
// repeat the test w/ PKCS#1 RSA Private Key
test(kf, CUSTOM_PRIV);
test(kf, CUSTOM_PUB);
long stop = System.currentTimeMillis();
System.out.println("All tests passed (" + (stop - start) + " ms).");
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -23,7 +23,7 @@
/**
* @test
* @bug 4853305
* @bug 4853305 8023980
* @summary Test KeyFactory of the new RSA provider
* @author Andreas Sterbenz
*/
@ -41,6 +41,84 @@ public class TestKeyFactory {
private static final char[] password = "test12".toCharArray();
private static final String PKCS1_PRIV_STR =
// the BASE64 string between -----BEGIN RSA PRIVATE KEY-----
// and -----END RSA PRIVATE KEY-----
"MIIEowIBAAKCAQEA0OIArlYES4X1XMTLDordtN/XIWFE1wvhl40RsHWM2n99+Stp" +
"CCJCcUb5FJ2/kefj/XRwB6p5IMpIZrHZqC8XXzlX5fpiFaSu2xnk17oWUKoErW27" +
"Stm098pU2RoUxWPKVl+42a8iVp8tijNElBNFALCGi0zXOhcTxMh0q1Wk0UhMJqam" +
"v5YnCKmT4THwwGYn/KeK3M7Qa+o5MoVBHLbeT9LJgEmSluVzIh44Lh6weX0bw72P" +
"8X2praOhbzg2B343MqS/rMLw6On+0i7ccEgp23vX9G5w85q4A5FSIrk4S/pyv5sO" +
"rwjCQKBW1TS0/2iB9zNkFMj5/+h7l2oqTT7sSQIDAQABAoIBADn6sXOynoiUC1IP" +
"sck8lGOTSjSSujfyrVCSsJlJV6qCfuX9va6rS8QDjjnBu531PtxoSHxoPizy2Pvg" +
"W+kKATPGR/am9DjLuFlKq7GRjoYfWyMEdVtGaKvq9ng4fBF6LHyjHz0VFrPyhQJ6" +
"TovHeXzCguYBkzAlnbAeb/vqzs/kABbOuSHVi7DsaixCoEX9zOptFYQw/l8rh68+" +
"UF2bpNNH3jOC1uN3vZtuSwCupqtN+2Mpkx2h04Rk75vWIhrnPeMgmcd3yP4LNZMR" +
"mfaynb63RRzVkNis7+NVk016SQ1oL79mrBvy5rBg3HeCeArwvqZAmOaWsLSWHzCy" +
"zlVlMTECgYEA6JlnMpC956Qi8HX5ye4Hu2ovBdbNGtH/TMkZmColJz9P7CvNkNIb" +
"Od6mvLMydbPHkhdBUDWD4rhiCKHrf5zKju1i24YqWcvuSGotWj4/KQ3+87mLZM+7" +
"daBsJBmSEVB80sgA9ItqSgOyNoNFpiDgFnlszAfb0n9XXEzB/pwSw1UCgYEA5eXI" +
"d+eKugugP+n6CluQfyxfN6WWCzfqWToCTTxPn2i12AiEssXy+kyLjupJVLWSivdo" +
"83wD5LuxFRGc9P+aKQERPhb0AFaxf1llUCXla65/x2So5xjMvtuzgQ0OktPJqJXq" +
"hYGunctsr5rje33+7vlx4xWkrL2PrQWzJabn7SUCgYEAqw3FesY/Ik7u8u+P1xSZ" +
"0xXvptek1oiAu7NYgzLbR9WjrQc5kbsyEojPDg6qmSyxI5q+iYIRj3YRgk+xpJNl" +
"0154SQCNvKPghJiw6aDFSifkytA01tp9/a8QWCwF433RjiFPsoekjvHQ6Y34dofO" +
"xDhf7lwJKPBFCrfYIqocklECgYAIPI9OHHGP8NKw94UJ0fX/WGug5sHVbQ9sWvOy" +
"KLMBlxLMxqFadlUaOpvVZvdxnX++ktajwpGxJDhX9OWWsYGobm1buB7N1E1Prrg+" +
"gt0RWpMhZa3Xeb/8Jorr2Lfo8sWK0LQyTE8hQCSIthfoWL9FeJJn/GKF/dSj8kxU" +
"0QIGMQKBgG/8U/zZ87DzfXS81P1p+CmH474wmou4KD2/zXp/lDR9+dlIUeijlIbU" +
"P6Y5xJvT33Y40giW9irShgDHjZgw0ap11K3b2HzLImdPEaBiENo735rpLs8WLK9H" +
"+yeRbiP2y9To7sTihm9Jrkctzp6sqFtKyye1+S21X1tMz8NGfXen";
private static final String PKCS1_PUB_STR =
// the BASE64 string between -----BEGIN RSA PUBLIC KEY-----
// and -----END RSA PUBLIC KEY-----
"MIIBCgKCAQEA0OIArlYES4X1XMTLDordtN/XIWFE1wvhl40RsHWM2n99+StpCCJC" +
"cUb5FJ2/kefj/XRwB6p5IMpIZrHZqC8XXzlX5fpiFaSu2xnk17oWUKoErW27Stm0" +
"98pU2RoUxWPKVl+42a8iVp8tijNElBNFALCGi0zXOhcTxMh0q1Wk0UhMJqamv5Yn" +
"CKmT4THwwGYn/KeK3M7Qa+o5MoVBHLbeT9LJgEmSluVzIh44Lh6weX0bw72P8X2p" +
"raOhbzg2B343MqS/rMLw6On+0i7ccEgp23vX9G5w85q4A5FSIrk4S/pyv5sOrwjC" +
"QKBW1TS0/2iB9zNkFMj5/+h7l2oqTT7sSQIDAQAB";
private static final PrivateKey P1_PRIV;
private static final PublicKey P1_PUB;
static {
byte[] encodedPriv = Base64.getDecoder().decode(PKCS1_PRIV_STR);
P1_PRIV = new PrivateKey() {
@Override
public String getAlgorithm() {
return "RSA";
}
@Override
public String getFormat() {
return "PKCS#1";
}
@Override
public byte[] getEncoded() {
// skip cloning for testing key.
return encodedPriv;
}
};
byte[] encodedPub = Base64.getDecoder().decode(PKCS1_PUB_STR);
P1_PUB = new PublicKey() {
@Override
public String getAlgorithm() {
return "RSA";
}
@Override
public String getFormat() {
return "PKCS#1";
}
@Override
public byte[] getEncoded() {
// skip cloning for testing key.
return encodedPub;
}
};
}
static KeyStore getKeyStore() throws Exception {
InputStream in = new FileInputStream(new File(BASE, "rsakeys.ks"));
KeyStore ks = KeyStore.getInstance("JKS");
@ -63,55 +141,78 @@ public class TestKeyFactory {
}
} else if (key1 instanceof PrivateKey) {
if (key2.getFormat().equals("PKCS#8") == false) {
throw new Exception("Format not PKCS#8");
throw new Exception("Format not PKCS#8: " + key2.getFormat());
}
}
if (key1.equals(key2) == false) {
throw new Exception("Keys not equal");
// skip equals check when key1 is custom key
if (key1 != P1_PRIV && key1 != P1_PUB) {
if (!key1.equals(key2)) {
throw new Exception("Keys not equal");
}
}
if (Arrays.equals(key1.getEncoded(), key2.getEncoded()) == false) {
// only compare encodings if keys are of the same format
if (key1.getFormat().equals(key2.getFormat()) &&
!Arrays.equals(key1.getEncoded(), key2.getEncoded())) {
throw new Exception("Encodings not equal");
}
}
private static void testPublic(KeyFactory kf, PublicKey key) throws Exception {
System.out.println("Testing public key...");
private static void testPublic(KeyFactory kf, PublicKey key)
throws Exception {
System.out.println("Testing " + (key == P1_PUB? "PKCS#1" : "") +
" public key...");
PublicKey key2 = (PublicKey)kf.translateKey(key);
KeySpec rsaSpec = kf.getKeySpec(key, RSAPublicKeySpec.class);
PublicKey key3 = kf.generatePublic(rsaSpec);
KeySpec x509Spec = kf.getKeySpec(key, X509EncodedKeySpec.class);
PublicKey key4 = kf.generatePublic(x509Spec);
KeySpec x509Spec2 = new X509EncodedKeySpec(key.getEncoded());
PublicKey key5 = kf.generatePublic(x509Spec2);
testKey(key, key);
if (key != P1_PUB) {
testKey(key, key);
}
testKey(key, key2);
testKey(key, key3);
testKey(key, key4);
testKey(key, key5);
if (key.getFormat().equalsIgnoreCase("X.509")) {
KeySpec x509Spec2 = new X509EncodedKeySpec(key.getEncoded());
PublicKey key5 = kf.generatePublic(x509Spec2);
testKey(key, key5);
}
}
private static void testPrivate(KeyFactory kf, PrivateKey key) throws Exception {
System.out.println("Testing private key...");
private static void testPrivate(KeyFactory kf, PrivateKey key)
throws Exception {
System.out.println("Testing " + (key == P1_PRIV? "PKCS#1" : "") +
" private key...");
PrivateKey key2 = (PrivateKey)kf.translateKey(key);
KeySpec rsaSpec = kf.getKeySpec(key, RSAPrivateCrtKeySpec.class);
PrivateKey key3 = kf.generatePrivate(rsaSpec);
KeySpec pkcs8Spec = kf.getKeySpec(key, PKCS8EncodedKeySpec.class);
PrivateKey key4 = kf.generatePrivate(pkcs8Spec);
KeySpec pkcs8Spec2 = new PKCS8EncodedKeySpec(key.getEncoded());
PrivateKey key5 = kf.generatePrivate(pkcs8Spec2);
testKey(key, key);
if (key != P1_PRIV) {
testKey(key, key);
}
testKey(key, key2);
testKey(key, key3);
testKey(key, key4);
testKey(key, key5);
if (key.getFormat().equalsIgnoreCase("PKCS#8")) {
KeySpec pkcs8Spec2 = new PKCS8EncodedKeySpec(key.getEncoded());
PrivateKey key5 = kf.generatePrivate(pkcs8Spec2);
testKey(key, key5);
}
KeySpec rsaSpec2 = kf.getKeySpec(key, RSAPrivateKeySpec.class);
PrivateKey key6 = kf.generatePrivate(rsaSpec2);
RSAPrivateKey rsaKey = (RSAPrivateKey)key;
KeySpec rsaSpec3 = new RSAPrivateKeySpec(rsaKey.getModulus(), rsaKey.getPrivateExponent());
PrivateKey key7 = kf.generatePrivate(rsaSpec3);
testKey(key6, key6);
testKey(key6, key7);
if (key instanceof RSAPrivateKey) {
KeySpec rsaSpec3 =
new RSAPrivateKeySpec(((RSAPrivateKey)key).getModulus(),
((RSAPrivateKey)key).getPrivateExponent());
PrivateKey key7 = kf.generatePrivate(rsaSpec3);
testKey(key6, key7);
}
}
private static void test(KeyFactory kf, Key key) throws Exception {
@ -137,6 +238,10 @@ public class TestKeyFactory {
test(kf, ks.getCertificate(alias).getPublicKey());
}
}
// repeat the test w/ PKCS#1 RSA Private Key
test(kf, P1_PRIV);
test(kf, P1_PUB);
long stop = System.currentTimeMillis();
System.out.println("All tests passed (" + (stop - start) + " ms).");
}