Merge "Keystore 2.0 SPI: Add EC_CURVE tag on key generation." into sc-dev

This commit is contained in:
TreeHugger Robot
2021-07-08 16:11:06 +00:00
committed by Android (Google) Code Review

View File

@ -20,6 +20,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable; import android.annotation.Nullable;
import android.app.ActivityThread; import android.app.ActivityThread;
import android.content.Context; import android.content.Context;
import android.hardware.security.keymint.EcCurve;
import android.hardware.security.keymint.KeyParameter; import android.hardware.security.keymint.KeyParameter;
import android.hardware.security.keymint.KeyPurpose; import android.hardware.security.keymint.KeyPurpose;
import android.hardware.security.keymint.SecurityLevel; import android.hardware.security.keymint.SecurityLevel;
@ -122,6 +123,7 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
new HashMap<String, Integer>(); new HashMap<String, Integer>();
private static final List<String> SUPPORTED_EC_NIST_CURVE_NAMES = new ArrayList<String>(); private static final List<String> SUPPORTED_EC_NIST_CURVE_NAMES = new ArrayList<String>();
private static final List<Integer> SUPPORTED_EC_NIST_CURVE_SIZES = new ArrayList<Integer>(); private static final List<Integer> SUPPORTED_EC_NIST_CURVE_SIZES = new ArrayList<Integer>();
static { static {
// Aliases for NIST P-224 // Aliases for NIST P-224
SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("p-224", 224); SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("p-224", 224);
@ -175,12 +177,29 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
mOriginalKeymasterAlgorithm = keymasterAlgorithm; mOriginalKeymasterAlgorithm = keymasterAlgorithm;
} }
private @EcCurve int keySize2EcCurve(int keySizeBits)
throws InvalidAlgorithmParameterException {
switch (keySizeBits) {
case 224:
return EcCurve.P_224;
case 256:
return EcCurve.P_256;
case 384:
return EcCurve.P_384;
case 521:
return EcCurve.P_521;
default:
throw new InvalidAlgorithmParameterException(
"Unsupported EC curve keysize: " + keySizeBits);
}
}
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
@Override @Override
public void initialize(int keysize, SecureRandom random) { public void initialize(int keysize, SecureRandom random) {
throw new IllegalArgumentException( throw new IllegalArgumentException(
KeyGenParameterSpec.class.getName() + " or " + KeyPairGeneratorSpec.class.getName() KeyGenParameterSpec.class.getName() + " or " + KeyPairGeneratorSpec.class.getName()
+ " required to initialize this KeyPairGenerator"); + " required to initialize this KeyPairGenerator");
} }
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
@ -194,7 +213,7 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
if (params == null) { if (params == null) {
throw new InvalidAlgorithmParameterException( throw new InvalidAlgorithmParameterException(
"Must supply params of type " + KeyGenParameterSpec.class.getName() "Must supply params of type " + KeyGenParameterSpec.class.getName()
+ " or " + KeyPairGeneratorSpec.class.getName()); + " or " + KeyPairGeneratorSpec.class.getName());
} }
KeyGenParameterSpec spec; KeyGenParameterSpec spec;
@ -215,8 +234,8 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
} else { } else {
throw new InvalidAlgorithmParameterException( throw new InvalidAlgorithmParameterException(
"Unsupported params class: " + params.getClass().getName() "Unsupported params class: " + params.getClass().getName()
+ ". Supported: " + KeyGenParameterSpec.class.getName() + ". Supported: " + KeyGenParameterSpec.class.getName()
+ ", " + KeyPairGeneratorSpec.class.getName()); + ", " + KeyPairGeneratorSpec.class.getName());
} }
mEntryAlias = spec.getKeystoreAlias(); mEntryAlias = spec.getKeystoreAlias();
@ -250,11 +269,11 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
keymasterPadding)) { keymasterPadding)) {
throw new InvalidAlgorithmParameterException( throw new InvalidAlgorithmParameterException(
"Randomized encryption (IND-CPA) required but may be violated" "Randomized encryption (IND-CPA) required but may be violated"
+ " by padding scheme: " + " by padding scheme: "
+ KeyProperties.EncryptionPadding.fromKeymaster( + KeyProperties.EncryptionPadding.fromKeymaster(
keymasterPadding) keymasterPadding)
+ ". See " + KeyGenParameterSpec.class.getName() + ". See " + KeyGenParameterSpec.class.getName()
+ " documentation."); + " documentation.");
} }
} }
} }
@ -378,7 +397,7 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
specBuilder = new KeyGenParameterSpec.Builder( specBuilder = new KeyGenParameterSpec.Builder(
legacySpec.getKeystoreAlias(), legacySpec.getKeystoreAlias(),
KeyProperties.PURPOSE_SIGN KeyProperties.PURPOSE_SIGN
| KeyProperties.PURPOSE_VERIFY); | KeyProperties.PURPOSE_VERIFY);
// Authorized to be used with any digest (including no digest). // Authorized to be used with any digest (including no digest).
// MD5 was never offered for Android Keystore for ECDSA. // MD5 was never offered for Android Keystore for ECDSA.
specBuilder.setDigests( specBuilder.setDigests(
@ -393,9 +412,9 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
specBuilder = new KeyGenParameterSpec.Builder( specBuilder = new KeyGenParameterSpec.Builder(
legacySpec.getKeystoreAlias(), legacySpec.getKeystoreAlias(),
KeyProperties.PURPOSE_ENCRYPT KeyProperties.PURPOSE_ENCRYPT
| KeyProperties.PURPOSE_DECRYPT | KeyProperties.PURPOSE_DECRYPT
| KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_SIGN
| KeyProperties.PURPOSE_VERIFY); | KeyProperties.PURPOSE_VERIFY);
// Authorized to be used with any digest (including no digest). // Authorized to be used with any digest (including no digest).
specBuilder.setDigests( specBuilder.setDigests(
KeyProperties.DIGEST_NONE, KeyProperties.DIGEST_NONE,
@ -459,8 +478,7 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
private void initAlgorithmSpecificParameters() throws InvalidAlgorithmParameterException { private void initAlgorithmSpecificParameters() throws InvalidAlgorithmParameterException {
AlgorithmParameterSpec algSpecificSpec = mSpec.getAlgorithmParameterSpec(); AlgorithmParameterSpec algSpecificSpec = mSpec.getAlgorithmParameterSpec();
switch (mKeymasterAlgorithm) { switch (mKeymasterAlgorithm) {
case KeymasterDefs.KM_ALGORITHM_RSA: case KeymasterDefs.KM_ALGORITHM_RSA: {
{
BigInteger publicExponent = null; BigInteger publicExponent = null;
if (algSpecificSpec instanceof RSAKeyGenParameterSpec) { if (algSpecificSpec instanceof RSAKeyGenParameterSpec) {
RSAKeyGenParameterSpec rsaSpec = (RSAKeyGenParameterSpec) algSpecificSpec; RSAKeyGenParameterSpec rsaSpec = (RSAKeyGenParameterSpec) algSpecificSpec;
@ -474,7 +492,7 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
publicExponent = rsaSpec.getPublicExponent(); publicExponent = rsaSpec.getPublicExponent();
} else if (algSpecificSpec != null) { } else if (algSpecificSpec != null) {
throw new InvalidAlgorithmParameterException( throw new InvalidAlgorithmParameterException(
"RSA may only use RSAKeyGenParameterSpec"); "RSA may only use RSAKeyGenParameterSpec");
} }
if (publicExponent == null) { if (publicExponent == null) {
publicExponent = RSAKeyGenParameterSpec.F4; publicExponent = RSAKeyGenParameterSpec.F4;
@ -487,7 +505,8 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
|| (publicExponent.compareTo(KeymasterArguments.UINT64_MAX_VALUE) > 0)) { || (publicExponent.compareTo(KeymasterArguments.UINT64_MAX_VALUE) > 0)) {
throw new InvalidAlgorithmParameterException( throw new InvalidAlgorithmParameterException(
"Unsupported RSA public exponent: " + publicExponent "Unsupported RSA public exponent: " + publicExponent
+ ". Maximum supported value: " + KeymasterArguments.UINT64_MAX_VALUE); + ". Maximum supported value: "
+ KeymasterArguments.UINT64_MAX_VALUE);
} }
mRSAPublicExponent = publicExponent.longValue(); mRSAPublicExponent = publicExponent.longValue();
break; break;
@ -501,7 +520,7 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
if (ecSpecKeySizeBits == null) { if (ecSpecKeySizeBits == null) {
throw new InvalidAlgorithmParameterException( throw new InvalidAlgorithmParameterException(
"Unsupported EC curve name: " + curveName "Unsupported EC curve name: " + curveName
+ ". Supported: " + SUPPORTED_EC_NIST_CURVE_NAMES); + ". Supported: " + SUPPORTED_EC_NIST_CURVE_NAMES);
} }
if (mKeySizeBits == -1) { if (mKeySizeBits == -1) {
mKeySizeBits = ecSpecKeySizeBits; mKeySizeBits = ecSpecKeySizeBits;
@ -512,7 +531,7 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
} }
} else if (algSpecificSpec != null) { } else if (algSpecificSpec != null) {
throw new InvalidAlgorithmParameterException( throw new InvalidAlgorithmParameterException(
"EC may only use ECGenParameterSpec"); "EC may only use ECGenParameterSpec");
} }
break; break;
default: default:
@ -546,7 +565,7 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
final int flags = final int flags =
mSpec.isCriticalToDeviceEncryption() mSpec.isCriticalToDeviceEncryption()
? IKeystoreSecurityLevel ? IKeystoreSecurityLevel
.KEY_FLAG_AUTH_BOUND_WITHOUT_CRYPTOGRAPHIC_LSKF_BINDING .KEY_FLAG_AUTH_BOUND_WITHOUT_CRYPTOGRAPHIC_LSKF_BINDING
: 0; : 0;
byte[] additionalEntropy = byte[] additionalEntropy =
@ -585,7 +604,7 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
success = true; success = true;
return new KeyPair(publicKey, publicKey.getPrivateKey()); return new KeyPair(publicKey, publicKey.getPrivateKey());
} catch (android.security.KeyStoreException e) { } catch (android.security.KeyStoreException e) {
switch(e.getErrorCode()) { switch (e.getErrorCode()) {
case KeymasterDefs.KM_ERROR_HARDWARE_TYPE_UNAVAILABLE: case KeymasterDefs.KM_ERROR_HARDWARE_TYPE_UNAVAILABLE:
throw new StrongBoxUnavailableException("Failed to generated key pair.", e); throw new StrongBoxUnavailableException("Failed to generated key pair.", e);
case ResponseCode.OUT_OF_KEYS: case ResponseCode.OUT_OF_KEYS:
@ -605,7 +624,7 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
throw p; throw p;
} }
} catch (UnrecoverableKeyException | IllegalArgumentException } catch (UnrecoverableKeyException | IllegalArgumentException
| DeviceIdAttestationException e) { | DeviceIdAttestationException | InvalidAlgorithmParameterException e) {
throw new ProviderException( throw new ProviderException(
"Failed to construct key object from newly generated key pair.", e); "Failed to construct key object from newly generated key pair.", e);
} finally { } finally {
@ -666,8 +685,8 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
if (idTypesSet.contains(AttestationUtils.ID_TYPE_IMEI) if (idTypesSet.contains(AttestationUtils.ID_TYPE_IMEI)
|| idTypesSet.contains(AttestationUtils.ID_TYPE_MEID)) { || idTypesSet.contains(AttestationUtils.ID_TYPE_MEID)) {
telephonyService = telephonyService =
(TelephonyManager) android.app.AppGlobals.getInitialApplication() (TelephonyManager) android.app.AppGlobals.getInitialApplication()
.getSystemService(Context.TELEPHONY_SERVICE); .getSystemService(Context.TELEPHONY_SERVICE);
if (telephonyService == null) { if (telephonyService == null) {
throw new DeviceIdAttestationException("Unable to access telephony service"); throw new DeviceIdAttestationException("Unable to access telephony service");
} }
@ -715,12 +734,20 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
} }
private Collection<KeyParameter> constructKeyGenerationArguments() private Collection<KeyParameter> constructKeyGenerationArguments()
throws DeviceIdAttestationException, IllegalArgumentException { throws DeviceIdAttestationException, IllegalArgumentException,
InvalidAlgorithmParameterException {
List<KeyParameter> params = new ArrayList<>(); List<KeyParameter> params = new ArrayList<>();
params.add(KeyStore2ParameterUtils.makeInt(KeymasterDefs.KM_TAG_KEY_SIZE, mKeySizeBits)); params.add(KeyStore2ParameterUtils.makeInt(KeymasterDefs.KM_TAG_KEY_SIZE, mKeySizeBits));
params.add(KeyStore2ParameterUtils.makeEnum( params.add(KeyStore2ParameterUtils.makeEnum(
KeymasterDefs.KM_TAG_ALGORITHM, mKeymasterAlgorithm KeymasterDefs.KM_TAG_ALGORITHM, mKeymasterAlgorithm
)); ));
if (mKeymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_EC) {
params.add(KeyStore2ParameterUtils.makeEnum(
Tag.EC_CURVE, keySize2EcCurve(mKeySizeBits)
));
}
ArrayUtils.forEach(mKeymasterPurposes, (purpose) -> { ArrayUtils.forEach(mKeymasterPurposes, (purpose) -> {
params.add(KeyStore2ParameterUtils.makeEnum( params.add(KeyStore2ParameterUtils.makeEnum(
KeymasterDefs.KM_TAG_PURPOSE, purpose KeymasterDefs.KM_TAG_PURPOSE, purpose
@ -844,7 +871,7 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
if (isStrongBoxBacked && keySize != 256) { if (isStrongBoxBacked && keySize != 256) {
throw new InvalidAlgorithmParameterException( throw new InvalidAlgorithmParameterException(
"Unsupported StrongBox EC key size: " "Unsupported StrongBox EC key size: "
+ keySize + " bits. Supported: 256"); + keySize + " bits. Supported: 256");
} }
if (!SUPPORTED_EC_NIST_CURVE_SIZES.contains(keySize)) { if (!SUPPORTED_EC_NIST_CURVE_SIZES.contains(keySize)) {
throw new InvalidAlgorithmParameterException("Unsupported EC key size: " throw new InvalidAlgorithmParameterException("Unsupported EC key size: "
@ -892,8 +919,7 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
return null; return null;
} }
switch (keymasterAlgorithm) { switch (keymasterAlgorithm) {
case KeymasterDefs.KM_ALGORITHM_EC: case KeymasterDefs.KM_ALGORITHM_EC: {
{
Set<Integer> availableKeymasterDigests = getAvailableKeymasterSignatureDigests( Set<Integer> availableKeymasterDigests = getAvailableKeymasterSignatureDigests(
spec.getDigests(), spec.getDigests(),
AndroidKeyStoreBCWorkaroundProvider.getSupportedEcdsaSignatureDigests()); AndroidKeyStoreBCWorkaroundProvider.getSupportedEcdsaSignatureDigests());
@ -940,8 +966,7 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
return KeyProperties.Digest.fromKeymasterToSignatureAlgorithmDigest( return KeyProperties.Digest.fromKeymasterToSignatureAlgorithmDigest(
bestKeymasterDigest) + "WithECDSA"; bestKeymasterDigest) + "WithECDSA";
} }
case KeymasterDefs.KM_ALGORITHM_RSA: case KeymasterDefs.KM_ALGORITHM_RSA: {
{
// Check whether this key is authorized for PKCS#1 signature padding. // Check whether this key is authorized for PKCS#1 signature padding.
// We use Bouncy Castle to generate self-signed RSA certificates. Bouncy Castle // We use Bouncy Castle to generate self-signed RSA certificates. Bouncy Castle
// only supports RSA certificates signed using PKCS#1 padding scheme. The key needs // only supports RSA certificates signed using PKCS#1 padding scheme. The key needs