summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--keystore/java/android/security/keystore2/AndroidKeyStoreKeyGeneratorSpi.java186
-rw-r--r--keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java439
2 files changed, 285 insertions, 340 deletions
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyGeneratorSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyGeneratorSpi.java
index 7d18be553122..ccd0a4bf92ff 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyGeneratorSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyGeneratorSpi.java
@@ -16,15 +16,22 @@
package android.security.keystore2;
-import android.security.Credentials;
-import android.security.KeyStore;
-import android.security.keymaster.KeyCharacteristics;
+import android.security.KeyStore2;
+import android.security.KeyStoreSecurityLevel;
import android.security.keymaster.KeymasterArguments;
import android.security.keymaster.KeymasterDefs;
+import android.security.keystore.ArrayUtils;
import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.KeyProperties;
import android.security.keystore.KeymasterUtils;
import android.security.keystore.StrongBoxUnavailableException;
+import android.system.keystore2.Domain;
+import android.system.keystore2.IKeystoreSecurityLevel;
+import android.system.keystore2.KeyDescriptor;
+import android.system.keystore2.KeyMetadata;
+import android.system.keystore2.KeyParameter;
+import android.system.keystore2.SecurityLevel;
+import android.util.Log;
import libcore.util.EmptyArray;
@@ -32,7 +39,9 @@ import java.security.InvalidAlgorithmParameterException;
import java.security.ProviderException;
import java.security.SecureRandom;
import java.security.spec.AlgorithmParameterSpec;
+import java.util.ArrayList;
import java.util.Arrays;
+import java.util.List;
import javax.crypto.KeyGeneratorSpi;
import javax.crypto.SecretKey;
@@ -43,6 +52,7 @@ import javax.crypto.SecretKey;
* @hide
*/
public abstract class AndroidKeyStoreKeyGeneratorSpi extends KeyGeneratorSpi {
+ private static final String TAG = "AndroidKeyStoreKeyGeneratorSpi";
public static class AES extends AndroidKeyStoreKeyGeneratorSpi {
public AES() {
@@ -105,7 +115,7 @@ public abstract class AndroidKeyStoreKeyGeneratorSpi extends KeyGeneratorSpi {
}
}
- private final KeyStore mKeyStore = KeyStore.getInstance();
+ private final KeyStore2 mKeyStore = KeyStore2.getInstance();
private final int mKeymasterAlgorithm;
private final int mKeymasterDigest;
private final int mDefaultKeySizeBits;
@@ -278,77 +288,141 @@ public abstract class AndroidKeyStoreKeyGeneratorSpi extends KeyGeneratorSpi {
throw new IllegalStateException("Not initialized");
}
- KeymasterArguments args = new KeymasterArguments();
- args.addUnsignedInt(KeymasterDefs.KM_TAG_KEY_SIZE, mKeySizeBits);
- args.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, mKeymasterAlgorithm);
- args.addEnums(KeymasterDefs.KM_TAG_PURPOSE, mKeymasterPurposes);
- args.addEnums(KeymasterDefs.KM_TAG_BLOCK_MODE, mKeymasterBlockModes);
- args.addEnums(KeymasterDefs.KM_TAG_PADDING, mKeymasterPaddings);
- args.addEnums(KeymasterDefs.KM_TAG_DIGEST, mKeymasterDigests);
- KeymasterUtils.addUserAuthArgs(args, spec);
- KeymasterUtils.addMinMacLengthAuthorizationIfNecessary(
- args,
- mKeymasterAlgorithm,
- mKeymasterBlockModes,
- mKeymasterDigests);
- args.addDateIfNotNull(KeymasterDefs.KM_TAG_ACTIVE_DATETIME, spec.getKeyValidityStart());
- args.addDateIfNotNull(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME,
- spec.getKeyValidityForOriginationEnd());
- args.addDateIfNotNull(KeymasterDefs.KM_TAG_USAGE_EXPIRE_DATETIME,
- spec.getKeyValidityForConsumptionEnd());
+ List<KeyParameter> params = new ArrayList<>();
+
+ params.add(KeyStore2ParameterUtils.makeInt(
+ KeymasterDefs.KM_TAG_KEY_SIZE, mKeySizeBits
+ ));
+ params.add(KeyStore2ParameterUtils.makeEnum(
+ KeymasterDefs.KM_TAG_ALGORITHM, mKeymasterAlgorithm
+ ));
+ ArrayUtils.forEach(mKeymasterPurposes, (purpose) -> {
+ params.add(KeyStore2ParameterUtils.makeEnum(
+ KeymasterDefs.KM_TAG_PURPOSE, purpose
+ ));
+ });
+ ArrayUtils.forEach(mKeymasterBlockModes, (blockMode) -> {
+ if (blockMode == KeymasterDefs.KM_MODE_GCM
+ && mKeymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_AES) {
+ params.add(KeyStore2ParameterUtils.makeInt(
+ KeymasterDefs.KM_TAG_MIN_MAC_LENGTH,
+ AndroidKeyStoreAuthenticatedAESCipherSpi.GCM
+ .MIN_SUPPORTED_TAG_LENGTH_BITS
+ ));
+ }
+ params.add(KeyStore2ParameterUtils.makeEnum(
+ KeymasterDefs.KM_TAG_BLOCK_MODE, blockMode
+ ));
+ });
+ ArrayUtils.forEach(mKeymasterPaddings, (padding) -> {
+ params.add(KeyStore2ParameterUtils.makeEnum(
+ KeymasterDefs.KM_TAG_PADDING, padding
+ ));
+ });
+ ArrayUtils.forEach(mKeymasterDigests, (digest) -> {
+ params.add(KeyStore2ParameterUtils.makeEnum(
+ KeymasterDefs.KM_TAG_DIGEST, digest
+ ));
+ });
+
+ if (mKeymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_HMAC
+ && mKeymasterDigests.length != 0) {
+ int digestOutputSizeBits = KeymasterUtils.getDigestOutputSizeBits(mKeymasterDigests[0]);
+ if (digestOutputSizeBits == -1) {
+ throw new ProviderException(
+ "HMAC key authorized for unsupported digest: "
+ + KeyProperties.Digest.fromKeymaster(mKeymasterDigests[0]));
+ }
+ params.add(KeyStore2ParameterUtils.makeInt(
+ KeymasterDefs.KM_TAG_MIN_MAC_LENGTH, digestOutputSizeBits
+ ));
+ }
+
+ KeyStore2ParameterUtils.addUserAuthArgs(params, spec);
+
+ if (spec.getKeyValidityStart() != null) {
+ params.add(KeyStore2ParameterUtils.makeDate(
+ KeymasterDefs.KM_TAG_ACTIVE_DATETIME, spec.getKeyValidityStart()
+ ));
+ }
+ if (spec.getKeyValidityForOriginationEnd() != null) {
+ params.add(KeyStore2ParameterUtils.makeDate(
+ KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME,
+ spec.getKeyValidityForOriginationEnd()
+ ));
+ }
+ if (spec.getKeyValidityForConsumptionEnd() != null) {
+ params.add(KeyStore2ParameterUtils.makeDate(
+ KeymasterDefs.KM_TAG_USAGE_EXPIRE_DATETIME,
+ spec.getKeyValidityForConsumptionEnd()
+ ));
+ }
if (((spec.getPurposes() & KeyProperties.PURPOSE_ENCRYPT) != 0)
&& (!spec.isRandomizedEncryptionRequired())) {
// Permit caller-provided IV when encrypting with this key
- args.addBoolean(KeymasterDefs.KM_TAG_CALLER_NONCE);
+ params.add(KeyStore2ParameterUtils.makeBool(
+ KeymasterDefs.KM_TAG_CALLER_NONCE
+ ));
}
byte[] additionalEntropy =
KeyStoreCryptoOperationUtils.getRandomBytesToMixIntoKeystoreRng(
mRng, (mKeySizeBits + 7) / 8);
- int flags = 0;
+
+ @SecurityLevel int securityLevel = SecurityLevel.TRUSTED_ENVIRONMENT;
if (spec.isStrongBoxBacked()) {
- flags |= KeyStore.FLAG_STRONGBOX;
+ securityLevel = SecurityLevel.STRONGBOX;
}
+
+ int flags = 0;
if (spec.isCriticalToDeviceEncryption()) {
- flags |= KeyStore.FLAG_CRITICAL_TO_DEVICE_ENCRYPTION;
+ flags |= IKeystoreSecurityLevel.KEY_FLAG_AUTH_BOUND_WITHOUT_CRYPTOGRAPHIC_LSKF_BINDING;
}
- String keyAliasInKeystore = Credentials.USER_PRIVATE_KEY + spec.getKeystoreAlias();
- KeyCharacteristics resultingKeyCharacteristics = new KeyCharacteristics();
- boolean success = false;
+
+ KeyDescriptor descriptor = new KeyDescriptor();
+ descriptor.alias = spec.getKeystoreAlias();
+ descriptor.nspace = spec.getNamespace();
+ descriptor.domain = descriptor.nspace == KeyProperties.NAMESPACE_APPLICATION
+ ? Domain.APP
+ : Domain.SELINUX;
+ descriptor.blob = null;
+
+ KeyMetadata metadata = null;
+ KeyStoreSecurityLevel iSecurityLevel = null;
try {
- Credentials.deleteAllTypesForAlias(mKeyStore, spec.getKeystoreAlias(), spec.getUid());
- int errorCode = mKeyStore.generateKey(
- keyAliasInKeystore,
- args,
- additionalEntropy,
- spec.getUid(),
+ iSecurityLevel = mKeyStore.getSecurityLevel(securityLevel);
+ metadata = iSecurityLevel.generateKey(
+ descriptor,
+ null, /* Attestation key not applicable to symmetric keys. */
+ params,
flags,
- resultingKeyCharacteristics);
- if (errorCode != KeyStore.NO_ERROR) {
- if (errorCode == KeyStore.HARDWARE_TYPE_UNAVAILABLE) {
+ additionalEntropy);
+ } catch (android.security.KeyStoreException e) {
+ switch (e.getErrorCode()) {
+ // TODO replace with ErrorCode.HARDWARE_TYPE_UNAVAILABLE when KeyMint spec
+ // becomes available.
+ case KeymasterDefs.KM_ERROR_HARDWARE_TYPE_UNAVAILABLE:
throw new StrongBoxUnavailableException("Failed to generate key");
- } else {
- throw new ProviderException(
- "Keystore operation failed", KeyStore.getKeyStoreException(errorCode));
- }
+ default:
+ throw new ProviderException("Keystore key generation failed", e);
}
- @KeyProperties.KeyAlgorithmEnum String keyAlgorithmJCA;
+ }
+ @KeyProperties.KeyAlgorithmEnum String keyAlgorithmJCA;
+ try {
+ keyAlgorithmJCA = KeyProperties.KeyAlgorithm.fromKeymasterSecretKeyAlgorithm(
+ mKeymasterAlgorithm, mKeymasterDigest);
+ } catch (IllegalArgumentException e) {
try {
- keyAlgorithmJCA = KeyProperties.KeyAlgorithm.fromKeymasterSecretKeyAlgorithm(
- mKeymasterAlgorithm, mKeymasterDigest);
- } catch (IllegalArgumentException e) {
- throw new ProviderException("Failed to obtain JCA secret key algorithm name", e);
- }
- SecretKey result = new AndroidKeyStoreSecretKey(
- keyAliasInKeystore, spec.getUid(), keyAlgorithmJCA);
- success = true;
- return result;
- } finally {
- if (!success) {
- Credentials.deleteAllTypesForAlias(
- mKeyStore, spec.getKeystoreAlias(), spec.getUid());
+ mKeyStore.deleteKey(descriptor);
+ } catch (android.security.KeyStoreException kse) {
+ Log.e(TAG, "Failed to delete key after generating successfully but"
+ + " failed to get the algorithm string.", kse);
}
+ throw new ProviderException("Failed to obtain JCA secret key algorithm name", e);
}
+ SecretKey result = new AndroidKeyStoreSecretKey(descriptor, metadata, keyAlgorithmJCA,
+ iSecurityLevel);
+ return result;
}
}
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
index ff40c1586212..a747a0e727d8 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
@@ -16,58 +16,41 @@
package android.security.keystore2;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.Build;
-import android.security.Credentials;
import android.security.KeyPairGeneratorSpec;
-import android.security.KeyStore;
-import android.security.keymaster.KeyCharacteristics;
+import android.security.KeyStore2;
+import android.security.KeyStoreException;
+import android.security.KeyStoreSecurityLevel;
import android.security.keymaster.KeymasterArguments;
-import android.security.keymaster.KeymasterCertificateChain;
import android.security.keymaster.KeymasterDefs;
+import android.security.keystore.ArrayUtils;
import android.security.keystore.KeyGenParameterSpec;
-import android.security.keystore.KeyPermanentlyInvalidatedException;
+import android.security.keystore.KeyProperties;
import android.security.keystore.KeymasterUtils;
import android.security.keystore.SecureKeyImportUnavailableException;
import android.security.keystore.StrongBoxUnavailableException;
-
-import com.android.org.bouncycastle.asn1.ASN1EncodableVector;
-import com.android.org.bouncycastle.asn1.ASN1InputStream;
-import com.android.org.bouncycastle.asn1.ASN1Integer;
-import com.android.org.bouncycastle.asn1.ASN1ObjectIdentifier;
-import com.android.org.bouncycastle.asn1.DERBitString;
-import com.android.org.bouncycastle.asn1.DERNull;
-import com.android.org.bouncycastle.asn1.DERSequence;
-import com.android.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
-import com.android.org.bouncycastle.asn1.x509.AlgorithmIdentifier;
-import com.android.org.bouncycastle.asn1.x509.Certificate;
-import com.android.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
-import com.android.org.bouncycastle.asn1.x509.TBSCertificate;
-import com.android.org.bouncycastle.asn1.x509.Time;
-import com.android.org.bouncycastle.asn1.x509.V3TBSCertificateGenerator;
-import com.android.org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
-import com.android.org.bouncycastle.jce.X509Principal;
-import com.android.org.bouncycastle.jce.provider.X509CertificateObject;
-import com.android.org.bouncycastle.x509.X509V3CertificateGenerator;
+import android.system.keystore2.Domain;
+import android.system.keystore2.IKeystoreSecurityLevel;
+import android.system.keystore2.KeyDescriptor;
+import android.system.keystore2.KeyMetadata;
+import android.system.keystore2.KeyParameter;
+import android.system.keystore2.ResponseCode;
+import android.system.keystore2.SecurityLevel;
+import android.util.Log;
import libcore.util.EmptyArray;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.InvalidAlgorithmParameterException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.KeyPairGeneratorSpi;
-import java.security.PrivateKey;
import java.security.ProviderException;
-import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.UnrecoverableKeyException;
-import java.security.cert.CertificateEncodingException;
-import java.security.cert.CertificateParsingException;
-import java.security.cert.X509Certificate;
import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.ECGenParameterSpec;
import java.security.spec.RSAKeyGenParameterSpec;
@@ -76,7 +59,6 @@ import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
-import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
@@ -96,6 +78,7 @@ import java.util.Set;
* @hide
*/
public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGeneratorSpi {
+ private static final String TAG = "AndroidKeyStoreKeyPairGeneratorSpi";
public static class RSA extends AndroidKeyStoreKeyPairGeneratorSpi {
public RSA() {
@@ -154,13 +137,12 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
private final int mOriginalKeymasterAlgorithm;
- private KeyStore mKeyStore;
+ private KeyStore2 mKeyStore;
private KeyGenParameterSpec mSpec;
private String mEntryAlias;
private int mEntryUid;
- private boolean mEncryptionAtRestRequired;
private @KeyProperties.KeyAlgorithmEnum String mJcaKeyAlgorithm;
private int mKeymasterAlgorithm = -1;
private int mKeySizeBits;
@@ -172,7 +154,7 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
private int[] mKeymasterSignaturePaddings;
private int[] mKeymasterDigests;
- private BigInteger mRSAPublicExponent;
+ private Long mRSAPublicExponent;
protected AndroidKeyStoreKeyPairGeneratorSpi(int keymasterAlgorithm) {
mOriginalKeymasterAlgorithm = keymasterAlgorithm;
@@ -283,7 +265,6 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
specBuilder.setCertificateSerialNumber(legacySpec.getSerialNumber());
specBuilder.setCertificateNotBefore(legacySpec.getStartDate());
specBuilder.setCertificateNotAfter(legacySpec.getEndDate());
- encryptionAtRestRequired = legacySpec.isEncryptionRequired();
specBuilder.setUserAuthenticationRequired(false);
spec = specBuilder.build();
@@ -301,7 +282,6 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
mEntryUid = spec.getUid();
mSpec = spec;
mKeymasterAlgorithm = keymasterAlgorithm;
- mEncryptionAtRestRequired = encryptionAtRestRequired;
mKeySizeBits = spec.getKeySize();
initAlgorithmSpecificParameters();
if (mKeySizeBits == -1) {
@@ -355,7 +335,7 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
mJcaKeyAlgorithm = jcaKeyAlgorithm;
mRng = random;
- mKeyStore = KeyStore.getInstance();
+ mKeyStore = KeyStore2.getInstance();
success = true;
} finally {
if (!success) {
@@ -366,7 +346,7 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
private void resetAll() {
mEntryAlias = null;
- mEntryUid = KeyStore.UID_SELF;
+ mEntryUid = KeyProperties.NAMESPACE_APPLICATION;
mJcaKeyAlgorithm = null;
mKeymasterAlgorithm = -1;
mKeymasterPurposes = null;
@@ -377,7 +357,6 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
mKeySizeBits = 0;
mSpec = null;
mRSAPublicExponent = null;
- mEncryptionAtRestRequired = false;
mRng = null;
mKeyStore = null;
}
@@ -409,12 +388,13 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
throw new InvalidAlgorithmParameterException(
"RSA public exponent must be positive: " + publicExponent);
}
- if (publicExponent.compareTo(KeymasterArguments.UINT64_MAX_VALUE) > 0) {
+ if ((publicExponent.signum() == -1)
+ || (publicExponent.compareTo(KeymasterArguments.UINT64_MAX_VALUE) > 0)) {
throw new InvalidAlgorithmParameterException(
"Unsupported RSA public exponent: " + publicExponent
+ ". Maximum supported value: " + KeymasterArguments.UINT64_MAX_VALUE);
}
- mRSAPublicExponent = publicExponent;
+ mRSAPublicExponent = publicExponent.longValue();
break;
}
case KeymasterDefs.KM_ALGORITHM_EC:
@@ -451,204 +431,178 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
throw new IllegalStateException("Not initialized");
}
- int flags = (mEncryptionAtRestRequired) ? KeyStore.FLAG_ENCRYPTED : 0;
- if (((flags & KeyStore.FLAG_ENCRYPTED) != 0)
- && (mKeyStore.state() != KeyStore.State.UNLOCKED)) {
- throw new IllegalStateException(
- "Encryption at rest using secure lock screen credential requested for key pair"
- + ", but the user has not yet entered the credential");
- }
+ final @SecurityLevel int securityLevel =
+ mSpec.isStrongBoxBacked()
+ ? SecurityLevel.STRONGBOX
+ : SecurityLevel.TRUSTED_ENVIRONMENT;
- if (mSpec.isStrongBoxBacked()) {
- flags |= KeyStore.FLAG_STRONGBOX;
- }
- if (mSpec.isCriticalToDeviceEncryption()) {
- flags |= KeyStore.FLAG_CRITICAL_TO_DEVICE_ENCRYPTION;
- }
+ final int flags =
+ mSpec.isCriticalToDeviceEncryption()
+ ? IKeystoreSecurityLevel
+ .KEY_FLAG_AUTH_BOUND_WITHOUT_CRYPTOGRAPHIC_LSKF_BINDING
+ : 0;
byte[] additionalEntropy =
KeyStoreCryptoOperationUtils.getRandomBytesToMixIntoKeystoreRng(
mRng, (mKeySizeBits + 7) / 8);
- Credentials.deleteAllTypesForAlias(mKeyStore, mEntryAlias, mEntryUid);
- final String privateKeyAlias = Credentials.USER_PRIVATE_KEY + mEntryAlias;
+ KeyDescriptor descriptor = new KeyDescriptor();
+ descriptor.alias = mEntryAlias;
+ descriptor.domain = mEntryUid == KeyProperties.NAMESPACE_APPLICATION
+ ? Domain.APP
+ : Domain.SELINUX;
+ descriptor.nspace = mEntryUid;
+ descriptor.blob = null;
+
boolean success = false;
try {
- generateKeystoreKeyPair(
- privateKeyAlias, constructKeyGenerationArguments(), additionalEntropy, flags);
- KeyPair keyPair = loadKeystoreKeyPair(privateKeyAlias);
+ KeyStoreSecurityLevel iSecurityLevel = mKeyStore.getSecurityLevel(securityLevel);
+
+ KeyMetadata metadata = iSecurityLevel.generateKey(descriptor, null,
+ constructKeyGenerationArguments(), flags, additionalEntropy);
- storeCertificateChain(flags, createCertificateChain(privateKeyAlias, keyPair));
+ AndroidKeyStorePublicKey publicKey =
+ AndroidKeyStoreProvider.makeAndroidKeyStorePublicKeyFromKeyEntryResponse(
+ descriptor, metadata, iSecurityLevel, mKeymasterAlgorithm);
success = true;
- return keyPair;
- } catch (ProviderException e) {
- if ((mSpec.getPurposes() & KeyProperties.PURPOSE_WRAP_KEY) != 0) {
- throw new SecureKeyImportUnavailableException(e);
- } else {
- throw e;
- }
+ return new KeyPair(publicKey, publicKey.getPrivateKey());
+ } catch (android.security.KeyStoreException e) {
+ switch(e.getErrorCode()) {
+ case KeymasterDefs.KM_ERROR_HARDWARE_TYPE_UNAVAILABLE:
+ throw new StrongBoxUnavailableException("Failed to generated key pair.", e);
+ default:
+ ProviderException p = new ProviderException("Failed to generate key pair.", e);
+ if ((mSpec.getPurposes() & KeyProperties.PURPOSE_WRAP_KEY) != 0) {
+ throw new SecureKeyImportUnavailableException(p);
+ }
+ throw p;
+ }
+ } catch (UnrecoverableKeyException e) {
+ throw new ProviderException(
+ "Failed to construct key object from newly generated key pair.", e);
} finally {
if (!success) {
- Credentials.deleteAllTypesForAlias(mKeyStore, mEntryAlias, mEntryUid);
+ try {
+ mKeyStore.deleteKey(descriptor);
+ } catch (KeyStoreException e) {
+ if (e.getErrorCode() != ResponseCode.KEY_NOT_FOUND) {
+ Log.e(TAG, "Failed to delete newly generated key after "
+ + "generation failed unexpectedly.", e);
+ }
+ }
}
}
}
- private Iterable<byte[]> createCertificateChain(final String privateKeyAlias, KeyPair keyPair)
+ private void addAttestationParameters(@NonNull List<KeyParameter> params)
throws ProviderException {
byte[] challenge = mSpec.getAttestationChallenge();
+
if (challenge != null) {
- KeymasterArguments args = new KeymasterArguments();
- args.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_CHALLENGE, challenge);
+ params.add(KeyStore2ParameterUtils.makeBytes(
+ KeymasterDefs.KM_TAG_ATTESTATION_CHALLENGE, challenge
+ ));
if (mSpec.isDevicePropertiesAttestationIncluded()) {
- args.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_ID_BRAND,
- Build.BRAND.getBytes(StandardCharsets.UTF_8));
- args.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_ID_DEVICE,
- Build.DEVICE.getBytes(StandardCharsets.UTF_8));
- args.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_ID_PRODUCT,
- Build.PRODUCT.getBytes(StandardCharsets.UTF_8));
- args.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_ID_MANUFACTURER,
- Build.MANUFACTURER.getBytes(StandardCharsets.UTF_8));
- args.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_ID_MODEL,
- Build.MODEL.getBytes(StandardCharsets.UTF_8));
+ params.add(KeyStore2ParameterUtils.makeBytes(
+ KeymasterDefs.KM_TAG_ATTESTATION_ID_BRAND,
+ Build.BRAND.getBytes(StandardCharsets.UTF_8)
+ ));
+ params.add(KeyStore2ParameterUtils.makeBytes(
+ KeymasterDefs.KM_TAG_ATTESTATION_ID_DEVICE,
+ Build.DEVICE.getBytes(StandardCharsets.UTF_8)
+ ));
+ params.add(KeyStore2ParameterUtils.makeBytes(
+ KeymasterDefs.KM_TAG_ATTESTATION_ID_PRODUCT,
+ Build.PRODUCT.getBytes(StandardCharsets.UTF_8)
+ ));
+ params.add(KeyStore2ParameterUtils.makeBytes(
+ KeymasterDefs.KM_TAG_ATTESTATION_ID_MANUFACTURER,
+ Build.MANUFACTURER.getBytes(StandardCharsets.UTF_8)
+ ));
+ params.add(KeyStore2ParameterUtils.makeBytes(
+ KeymasterDefs.KM_TAG_ATTESTATION_ID_MODEL,
+ Build.MODEL.getBytes(StandardCharsets.UTF_8)
+ ));
}
-
- return getAttestationChain(privateKeyAlias, keyPair, args);
- }
-
- // Very short certificate chain in the non-attestation case.
- return Collections.singleton(generateSelfSignedCertificateBytes(keyPair));
- }
-
- private void generateKeystoreKeyPair(final String privateKeyAlias, KeymasterArguments args,
- byte[] additionalEntropy, final int flags) throws ProviderException {
- KeyCharacteristics resultingKeyCharacteristics = new KeyCharacteristics();
- int errorCode = mKeyStore.generateKey(privateKeyAlias, args, additionalEntropy,
- mEntryUid, flags, resultingKeyCharacteristics);
- if (errorCode != KeyStore.NO_ERROR) {
- if (errorCode == KeyStore.HARDWARE_TYPE_UNAVAILABLE) {
- throw new StrongBoxUnavailableException("Failed to generate key pair");
- } else {
- throw new ProviderException(
- "Failed to generate key pair", KeyStore.getKeyStoreException(errorCode));
+ } else {
+ if (mSpec.isDevicePropertiesAttestationIncluded()) {
+ throw new ProviderException("An attestation challenge must be provided when "
+ + "requesting device properties attestation.");
}
}
}
- private KeyPair loadKeystoreKeyPair(final String privateKeyAlias) throws ProviderException {
- try {
- KeyPair result = AndroidKeyStoreProvider.loadAndroidKeyStoreKeyPairFromKeystore(
- mKeyStore, privateKeyAlias, mEntryUid);
- if (!mJcaKeyAlgorithm.equalsIgnoreCase(result.getPrivate().getAlgorithm())) {
- throw new ProviderException(
- "Generated key pair algorithm does not match requested algorithm: "
- + result.getPrivate().getAlgorithm() + " vs " + mJcaKeyAlgorithm);
- }
- return result;
- } catch (UnrecoverableKeyException | KeyPermanentlyInvalidatedException e) {
- throw new ProviderException("Failed to load generated key pair from keystore", e);
+ private Collection<KeyParameter> constructKeyGenerationArguments() {
+ List<KeyParameter> params = new ArrayList<>();
+ params.add(KeyStore2ParameterUtils.makeInt(KeymasterDefs.KM_TAG_KEY_SIZE, mKeySizeBits));
+ params.add(KeyStore2ParameterUtils.makeEnum(
+ KeymasterDefs.KM_TAG_ALGORITHM, mKeymasterAlgorithm
+ ));
+ ArrayUtils.forEach(mKeymasterPurposes, (purpose) -> {
+ params.add(KeyStore2ParameterUtils.makeEnum(
+ KeymasterDefs.KM_TAG_PURPOSE, purpose
+ ));
+ });
+ ArrayUtils.forEach(mKeymasterBlockModes, (blockMode) -> {
+ params.add(KeyStore2ParameterUtils.makeEnum(
+ KeymasterDefs.KM_TAG_BLOCK_MODE, blockMode
+ ));
+ });
+ ArrayUtils.forEach(mKeymasterEncryptionPaddings, (padding) -> {
+ params.add(KeyStore2ParameterUtils.makeEnum(
+ KeymasterDefs.KM_TAG_PADDING, padding
+ ));
+ });
+ ArrayUtils.forEach(mKeymasterSignaturePaddings, (padding) -> {
+ params.add(KeyStore2ParameterUtils.makeEnum(
+ KeymasterDefs.KM_TAG_PADDING, padding
+ ));
+ });
+ ArrayUtils.forEach(mKeymasterDigests, (digest) -> {
+ params.add(KeyStore2ParameterUtils.makeEnum(
+ KeymasterDefs.KM_TAG_DIGEST, digest
+ ));
+ });
+
+ KeyStore2ParameterUtils.addUserAuthArgs(params, mSpec);
+
+ if (mSpec.getKeyValidityStart() != null) {
+ params.add(KeyStore2ParameterUtils.makeDate(
+ KeymasterDefs.KM_TAG_ACTIVE_DATETIME, mSpec.getKeyValidityStart()
+ ));
}
- }
-
- private KeymasterArguments constructKeyGenerationArguments() {
- KeymasterArguments args = new KeymasterArguments();
- args.addUnsignedInt(KeymasterDefs.KM_TAG_KEY_SIZE, mKeySizeBits);
- args.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, mKeymasterAlgorithm);
- args.addEnums(KeymasterDefs.KM_TAG_PURPOSE, mKeymasterPurposes);
- args.addEnums(KeymasterDefs.KM_TAG_BLOCK_MODE, mKeymasterBlockModes);
- args.addEnums(KeymasterDefs.KM_TAG_PADDING, mKeymasterEncryptionPaddings);
- args.addEnums(KeymasterDefs.KM_TAG_PADDING, mKeymasterSignaturePaddings);
- args.addEnums(KeymasterDefs.KM_TAG_DIGEST, mKeymasterDigests);
-
- KeymasterUtils.addUserAuthArgs(args, mSpec);
- args.addDateIfNotNull(KeymasterDefs.KM_TAG_ACTIVE_DATETIME, mSpec.getKeyValidityStart());
- args.addDateIfNotNull(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME,
- mSpec.getKeyValidityForOriginationEnd());
- args.addDateIfNotNull(KeymasterDefs.KM_TAG_USAGE_EXPIRE_DATETIME,
- mSpec.getKeyValidityForConsumptionEnd());
- addAlgorithmSpecificParameters(args);
-
- if (mSpec.isUniqueIdIncluded())
- args.addBoolean(KeymasterDefs.KM_TAG_INCLUDE_UNIQUE_ID);
-
- return args;
- }
-
- private void storeCertificateChain(final int flags, Iterable<byte[]> iterable)
- throws ProviderException {
- Iterator<byte[]> iter = iterable.iterator();
- storeCertificate(
- Credentials.USER_CERTIFICATE, iter.next(), flags, "Failed to store certificate");
-
- if (!iter.hasNext()) {
- return;
+ if (mSpec.getKeyValidityForOriginationEnd() != null) {
+ params.add(KeyStore2ParameterUtils.makeDate(
+ KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME,
+ mSpec.getKeyValidityForOriginationEnd()
+ ));
}
-
- ByteArrayOutputStream certificateConcatenationStream = new ByteArrayOutputStream();
- while (iter.hasNext()) {
- byte[] data = iter.next();
- certificateConcatenationStream.write(data, 0, data.length);
+ if (mSpec.getKeyValidityForConsumptionEnd() != null) {
+ params.add(KeyStore2ParameterUtils.makeDate(
+ KeymasterDefs.KM_TAG_USAGE_EXPIRE_DATETIME,
+ mSpec.getKeyValidityForConsumptionEnd()
+ ));
}
- storeCertificate(Credentials.CA_CERTIFICATE, certificateConcatenationStream.toByteArray(),
- flags, "Failed to store attestation CA certificate");
- }
+ addAlgorithmSpecificParameters(params);
- private void storeCertificate(String prefix, byte[] certificateBytes, final int flags,
- String failureMessage) throws ProviderException {
- int insertErrorCode = mKeyStore.insert(
- prefix + mEntryAlias,
- certificateBytes,
- mEntryUid,
- flags);
- if (insertErrorCode != KeyStore.NO_ERROR) {
- throw new ProviderException(failureMessage,
- KeyStore.getKeyStoreException(insertErrorCode));
+ if (mSpec.isUniqueIdIncluded()) {
+ params.add(KeyStore2ParameterUtils.makeBool(KeymasterDefs.KM_TAG_INCLUDE_UNIQUE_ID));
}
- }
- private byte[] generateSelfSignedCertificateBytes(KeyPair keyPair) throws ProviderException {
- try {
- return generateSelfSignedCertificate(keyPair.getPrivate(), keyPair.getPublic())
- .getEncoded();
- } catch (IOException | CertificateParsingException e) {
- throw new ProviderException("Failed to generate self-signed certificate", e);
- } catch (CertificateEncodingException e) {
- throw new ProviderException(
- "Failed to obtain encoded form of self-signed certificate", e);
- }
- }
+ addAttestationParameters(params);
- private Iterable<byte[]> getAttestationChain(String privateKeyAlias,
- KeyPair keyPair, KeymasterArguments args)
- throws ProviderException {
- final KeymasterCertificateChain outChain = new KeymasterCertificateChain();
- final int errorCode;
- if (mSpec.isDevicePropertiesAttestationIncluded()
- && mSpec.getAttestationChallenge() == null) {
- throw new ProviderException("An attestation challenge must be provided when requesting "
- + "device properties attestation.");
- }
- errorCode = mKeyStore.attestKey(privateKeyAlias, args, outChain);
- if (errorCode != KeyStore.NO_ERROR) {
- throw new ProviderException("Failed to generate attestation certificate chain",
- KeyStore.getKeyStoreException(errorCode));
- }
- Collection<byte[]> chain = outChain.getCertificates();
- if (chain.size() < 2) {
- throw new ProviderException("Attestation certificate chain contained "
- + chain.size() + " entries. At least two are required.");
- }
- return chain;
+ return params;
}
- private void addAlgorithmSpecificParameters(KeymasterArguments keymasterArgs) {
+ private void addAlgorithmSpecificParameters(List<KeyParameter> params) {
switch (mKeymasterAlgorithm) {
case KeymasterDefs.KM_ALGORITHM_RSA:
- keymasterArgs.addUnsignedLong(
- KeymasterDefs.KM_TAG_RSA_PUBLIC_EXPONENT, mRSAPublicExponent);
+ params.add(KeyStore2ParameterUtils.makeLong(
+ KeymasterDefs.KM_TAG_RSA_PUBLIC_EXPONENT, mRSAPublicExponent
+ ));
break;
case KeymasterDefs.KM_ALGORITHM_EC:
break;
@@ -657,89 +611,6 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
}
}
- private X509Certificate generateSelfSignedCertificate(PrivateKey privateKey,
- PublicKey publicKey) throws CertificateParsingException, IOException {
- String signatureAlgorithm =
- getCertificateSignatureAlgorithm(mKeymasterAlgorithm, mKeySizeBits, mSpec);
- if (signatureAlgorithm == null) {
- // Key cannot be used to sign a certificate
- return generateSelfSignedCertificateWithFakeSignature(publicKey);
- } else {
- // Key can be used to sign a certificate
- try {
- return generateSelfSignedCertificateWithValidSignature(
- privateKey, publicKey, signatureAlgorithm);
- } catch (Exception e) {
- // Failed to generate the self-signed certificate with valid signature. Fall back
- // to generating a self-signed certificate with a fake signature. This is done for
- // all exception types because we prefer key pair generation to succeed and end up
- // producing a self-signed certificate with an invalid signature to key pair
- // generation failing.
- return generateSelfSignedCertificateWithFakeSignature(publicKey);
- }
- }
- }
-
- @SuppressWarnings("deprecation")
- private X509Certificate generateSelfSignedCertificateWithValidSignature(
- PrivateKey privateKey, PublicKey publicKey, String signatureAlgorithm) throws Exception {
- final X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();
- certGen.setPublicKey(publicKey);
- certGen.setSerialNumber(mSpec.getCertificateSerialNumber());
- certGen.setSubjectDN(mSpec.getCertificateSubject());
- certGen.setIssuerDN(mSpec.getCertificateSubject());
- certGen.setNotBefore(mSpec.getCertificateNotBefore());
- certGen.setNotAfter(mSpec.getCertificateNotAfter());
- certGen.setSignatureAlgorithm(signatureAlgorithm);
- return certGen.generate(privateKey);
- }
-
- @SuppressWarnings("deprecation")
- private X509Certificate generateSelfSignedCertificateWithFakeSignature(
- PublicKey publicKey) throws IOException, CertificateParsingException {
- V3TBSCertificateGenerator tbsGenerator = new V3TBSCertificateGenerator();
- ASN1ObjectIdentifier sigAlgOid;
- AlgorithmIdentifier sigAlgId;
- byte[] signature;
- switch (mKeymasterAlgorithm) {
- case KeymasterDefs.KM_ALGORITHM_EC:
- sigAlgOid = X9ObjectIdentifiers.ecdsa_with_SHA256;
- sigAlgId = new AlgorithmIdentifier(sigAlgOid);
- ASN1EncodableVector v = new ASN1EncodableVector();
- v.add(new ASN1Integer(BigInteger.valueOf(0)));
- v.add(new ASN1Integer(BigInteger.valueOf(0)));
- signature = new DERSequence().getEncoded();
- break;
- case KeymasterDefs.KM_ALGORITHM_RSA:
- sigAlgOid = PKCSObjectIdentifiers.sha256WithRSAEncryption;
- sigAlgId = new AlgorithmIdentifier(sigAlgOid, DERNull.INSTANCE);
- signature = new byte[1];
- break;
- default:
- throw new ProviderException("Unsupported key algorithm: " + mKeymasterAlgorithm);
- }
-
- try (ASN1InputStream publicKeyInfoIn = new ASN1InputStream(publicKey.getEncoded())) {
- tbsGenerator.setSubjectPublicKeyInfo(
- SubjectPublicKeyInfo.getInstance(publicKeyInfoIn.readObject()));
- }
- tbsGenerator.setSerialNumber(new ASN1Integer(mSpec.getCertificateSerialNumber()));
- X509Principal subject =
- new X509Principal(mSpec.getCertificateSubject().getEncoded());
- tbsGenerator.setSubject(subject);
- tbsGenerator.setIssuer(subject);
- tbsGenerator.setStartDate(new Time(mSpec.getCertificateNotBefore()));
- tbsGenerator.setEndDate(new Time(mSpec.getCertificateNotAfter()));
- tbsGenerator.setSignature(sigAlgId);
- TBSCertificate tbsCertificate = tbsGenerator.generateTBSCertificate();
-
- ASN1EncodableVector result = new ASN1EncodableVector();
- result.add(tbsCertificate);
- result.add(sigAlgId);
- result.add(new DERBitString(signature));
- return new X509CertificateObject(Certificate.getInstance(new DERSequence(result)));
- }
-
private static int getDefaultKeySize(int keymasterAlgorithm) {
switch (keymasterAlgorithm) {
case KeymasterDefs.KM_ALGORITHM_EC: