RFR: 8263404: RsaPrivateKeySpec is always recognized as RSAPrivateCrtKeySpec in RSAKeyFactory.engineGetKeySpec [v4]
SalusaSecondus
github.com+829871+salusasecondus at openjdk.java.net
Sat Mar 20 17:44:54 UTC 2021
On Fri, 19 Mar 2021 19:42:10 GMT, SalusaSecondus <github.com+829871+SalusaSecondus at openjdk.org> wrote:
>> Well, for `P11RSAKeyFactory`, I think some minor modification may be needed given the additional P11PrivateKey type.
>> I'd expect it to be something like:
>> // must be either RSAPrivateKeySpec or RSAPrivateCrtKeySpec
>> if (keySpec.isAssignableFrom(RSAPrivateCrtKeySpec.class)) {
>> session[0] = token.getObjSession();
>> CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
>> new CK_ATTRIBUTE(CKA_MODULUS),
>> new CK_ATTRIBUTE(CKA_PUBLIC_EXPONENT),
>> new CK_ATTRIBUTE(CKA_PRIVATE_EXPONENT),
>> new CK_ATTRIBUTE(CKA_PRIME_1),
>> new CK_ATTRIBUTE(CKA_PRIME_2),
>> new CK_ATTRIBUTE(CKA_EXPONENT_1),
>> new CK_ATTRIBUTE(CKA_EXPONENT_2),
>> new CK_ATTRIBUTE(CKA_COEFFICIENT),
>> };
>> long keyID = key.getKeyID();
>> try {
>> token.p11.C_GetAttributeValue(session[0].id(), keyID, attributes);
>> KeySpec spec = new RSAPrivateCrtKeySpec(
>> attributes[0].getBigInteger(),
>> attributes[1].getBigInteger(),
>> attributes[2].getBigInteger(),
>> attributes[3].getBigInteger(),
>> attributes[4].getBigInteger(),
>> attributes[5].getBigInteger(),
>> attributes[6].getBigInteger(),
>> attributes[7].getBigInteger()
>> );
>> return keySpec.cast(spec);
>> } catch (final PKCS11Exception ex) {
>> // bubble this up if RSAPrivateCrtKeySpec is specified
>> // otherwise fall through to RSAPrivateKeySpec
>> if (!keySpec.isAssignableFrom(RSAPrivateKeySpec.class)) {
>> throw ex;
>> }
>> } finally {
>> key.releaseKeyID();
>> }
>>
>> attributes = new CK_ATTRIBUTE[] {
>> new CK_ATTRIBUTE(CKA_MODULUS),
>> new CK_ATTRIBUTE(CKA_PRIVATE_EXPONENT),
>> };
>> keyID = key.getKeyID();
>> try {
>> token.p11.C_GetAttributeValue(session[0].id(), keyID, attributes);
>> } finally {
>> key.releaseKeyID();
>> }
>>
>> KeySpec spec = new RSAPrivateKeySpec(
>> attributes[0].getBigInteger(),
>> attributes[1].getBigInteger()
>> );
>> return keySpec.cast(spec);
>> } else { // PKCS#8 handled in superclass
>> throw new InvalidKeySpecException("Only RSAPrivate(Crt)KeySpec "
>> + "and PKCS8EncodedKeySpec supported for RSA private keys");
>> }
>> }
>
> I think that this code will work, but since there already is [P11RSAPrivateKey and P11RSAPrivateNonCRTKey](https://github.com/openjdk/jdk/blob/master/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Key.java#L375-L406) (both of which implement the standard `RSAPrivateKey` and `RSAPrivateCrtKey` interfaces respectively), can we just depend on and simplify our code? (My concern is that there is some unknown reason for calling `C_GetAttributeValue` directly here.)
>
> For example (based on the non-P11 code above)
> } else if (key instanceof RSAPrivateKey) {
> if (keySpec.isAssignableFrom(PKCS8_KEYSPEC_CLS)) {
> return keySpec.cast(new PKCS8EncodedKeySpec(key.getEncoded()));
> } else if (keySpec.isAssignableFrom(RSA_PRIVCRT_KEYSPEC_CLS)) {
> if (key instanceof RSAPrivateCrtKey) {
> RSAPrivateCrtKey crtKey = (RSAPrivateCrtKey)key;
> return keySpec.cast(new RSAPrivateCrtKeySpec(
> crtKey.getModulus(),
> crtKey.getPublicExponent(),
> crtKey.getPrivateExponent(),
> crtKey.getPrimeP(),
> crtKey.getPrimeQ(),
> crtKey.getPrimeExponentP(),
> crtKey.getPrimeExponentQ(),
> crtKey.getCrtCoefficient(),
> crtKey.getParams()
> ));
> } else if (key instanceof RSAPrivateKey) {
> if (!keySpec.isAssignableFrom(RSA_PRIV_KEYSPEC_CLS)) {
> throw new InvalidKeySpecException
> ("RSAPrivateCrtKeySpec can only be used with CRT keys");
> }
>
> // fall through to RSAPrivateKey (non-CRT)
> RSAPrivateKey rsaKey = (RSAPrivateKey) key;
> return keySpec.cast(new RSAPrivateKeySpec(
> rsaKey.getModulus(),
> rsaKey.getPrivateExponent(),
> rsaKey.getParams()
> ));
> } else { // New P11 code starts here and handles the P11PrivateKey case
> throw new InvalidKeySpecException("RSA Private key is not extractable");
> } // End new P11 code
> } else {
> throw new InvalidKeySpecException
> ("KeySpec must be RSAPrivate(Crt)KeySpec or "
> + "PKCS8EncodedKeySpec for RSA private keys");
> }
I've used your code for both because it looks like a good solution.
One thing which puzzles me is that the following implementation for the P11 code passes all tests and avoids any interaction with P11 library at all. I didn't want to use it because I'm concerned that there is an untested edge-case we'd bump into.
<T extends KeySpec> T implGetPrivateKeySpec(P11Key key, Class<T> keySpec,
Session[] session) throws PKCS11Exception, InvalidKeySpecException {
if (key instanceof RSAPrivateKey) {
try {
return implGetSoftwareFactory().getKeySpec(key, keySpec);
} catch (final InvalidKeySpecException e) {
throw e;
} catch (final GeneralSecurityException e) {
throw new InvalidKeySpecException("Could not generate KeySpec", e);
}
} else {
throw new InvalidKeySpecException("Key is not extractable");
}
}
-------------
PR: https://git.openjdk.java.net/jdk/pull/2949
More information about the security-dev
mailing list