diff options
8 files changed, 241 insertions, 84 deletions
| diff --git a/core/api/current.txt b/core/api/current.txt index f3ea44a8e543..39f330f468a8 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -12135,6 +12135,7 @@ package android.content.pm {      field public static final String FEATURE_INPUT_METHODS = "android.software.input_methods";      field public static final String FEATURE_IPSEC_TUNNELS = "android.software.ipsec_tunnels";      field public static final String FEATURE_IRIS = "android.hardware.biometrics.iris"; +    field public static final String FEATURE_KEYSTORE_APP_ATTEST_KEY = "android.hardware.keystore.app_attest_key";      field public static final String FEATURE_KEYSTORE_LIMITED_USE_KEY = "android.hardware.keystore.limited_use_key";      field public static final String FEATURE_KEYSTORE_SINGLE_USE_KEY = "android.hardware.keystore.single_use_key";      field public static final String FEATURE_LEANBACK = "android.software.leanback"; @@ -36290,6 +36291,7 @@ package android.security.keystore {    public final class KeyGenParameterSpec implements java.security.spec.AlgorithmParameterSpec {      method @Nullable public java.security.spec.AlgorithmParameterSpec getAlgorithmParameterSpec(); +    method @Nullable public String getAttestKeyAlias();      method public byte[] getAttestationChallenge();      method @NonNull public String[] getBlockModes();      method @NonNull public java.util.Date getCertificateNotAfter(); @@ -36324,6 +36326,7 @@ package android.security.keystore {      ctor public KeyGenParameterSpec.Builder(@NonNull String, int);      method @NonNull public android.security.keystore.KeyGenParameterSpec build();      method public android.security.keystore.KeyGenParameterSpec.Builder setAlgorithmParameterSpec(@NonNull java.security.spec.AlgorithmParameterSpec); +    method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setAttestKeyAlias(@Nullable String);      method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setAttestationChallenge(byte[]);      method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setBlockModes(java.lang.String...);      method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setCertificateNotAfter(@NonNull java.util.Date); @@ -36421,6 +36424,7 @@ package android.security.keystore {      field public static final int ORIGIN_SECURELY_IMPORTED = 8; // 0x8      field public static final int ORIGIN_UNKNOWN = 4; // 0x4      field public static final int PURPOSE_AGREE_KEY = 64; // 0x40 +    field public static final int PURPOSE_ATTEST_KEY = 128; // 0x80      field public static final int PURPOSE_DECRYPT = 2; // 0x2      field public static final int PURPOSE_ENCRYPT = 1; // 0x1      field public static final int PURPOSE_SIGN = 4; // 0x4 diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 2a28ea7a5c51..443ae358b8cd 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -3272,6 +3272,15 @@ public abstract class PackageManager {      public static final String FEATURE_KEYSTORE_LIMITED_USE_KEY =              "android.hardware.keystore.limited_use_key"; +    /** +     * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: The device has +     * a Keystore implementation that can create application-specific attestation keys. +     * See {@link android.security.keystore.KeyGenParameterSpec.Builder#setAttestKeyAlias}. +     */ +    @SdkConstant(SdkConstantType.FEATURE) +    public static final String FEATURE_KEYSTORE_APP_ATTEST_KEY = +            "android.hardware.keystore.app_attest_key"; +      /** @hide */      public static final boolean APP_ENUMERATION_ENABLED_BY_DEFAULT = true; diff --git a/core/java/android/security/keymaster/KeymasterDefs.java b/core/java/android/security/keymaster/KeymasterDefs.java index a79b197d3faa..5a89cdf1d340 100644 --- a/core/java/android/security/keymaster/KeymasterDefs.java +++ b/core/java/android/security/keymaster/KeymasterDefs.java @@ -188,6 +188,7 @@ public final class KeymasterDefs {      public static final int KM_PURPOSE_VERIFY = KeyPurpose.VERIFY;      public static final int KM_PURPOSE_WRAP = KeyPurpose.WRAP_KEY;      public static final int KM_PURPOSE_AGREE_KEY = KeyPurpose.AGREE_KEY; +    public static final int KM_PURPOSE_ATTEST_KEY = KeyPurpose.ATTEST_KEY;      // Key formats.      public static final int KM_KEY_FORMAT_X509 = KeyFormat.X509; diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java index 2b0d7e53b749..c79c12cd3343 100644 --- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java +++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java @@ -279,8 +279,8 @@ import javax.security.auth.x500.X500Principal;   * }   */  public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAuthArgs { - -    private static final X500Principal DEFAULT_CERT_SUBJECT = new X500Principal("CN=fake"); +    private static final X500Principal DEFAULT_CERT_SUBJECT = +            new X500Principal("CN=Android Keystore Key");      private static final BigInteger DEFAULT_CERT_SERIAL_NUMBER = new BigInteger("1");      private static final Date DEFAULT_CERT_NOT_BEFORE = new Date(0L); // Jan 1 1970      private static final Date DEFAULT_CERT_NOT_AFTER = new Date(2461449600000L); // Jan 1 2048 @@ -317,6 +317,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu      private final boolean mUnlockedDeviceRequired;      private final boolean mCriticalToDeviceEncryption;      private final int mMaxUsageCount; +    private final String mAttestKeyAlias;      /*       * ***NOTE***: All new fields MUST also be added to the following:       * ParcelableKeyGenParameterSpec class. @@ -358,7 +359,8 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu              boolean userConfirmationRequired,              boolean unlockedDeviceRequired,              boolean criticalToDeviceEncryption, -            int maxUsageCount) { +            int maxUsageCount, +            String attestKeyAlias) {          if (TextUtils.isEmpty(keyStoreAlias)) {              throw new IllegalArgumentException("keyStoreAlias must not be empty");          } @@ -413,6 +415,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu          mUnlockedDeviceRequired = unlockedDeviceRequired;          mCriticalToDeviceEncryption = criticalToDeviceEncryption;          mMaxUsageCount = maxUsageCount; +        mAttestKeyAlias = attestKeyAlias;      }      /** @@ -869,6 +872,18 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu      }      /** +     * Returns the alias of the attestation key that will be used to sign the attestation +     * certificate of the generated key.  Note that an attestation certificate will only be +     * generated if an attestation challenge is set. +     * +     * @see Builder#setAttestKeyAlias(String) +     */ +    @Nullable +    public String getAttestKeyAlias() { +        return mAttestKeyAlias; +    } + +    /**       * Builder of {@link KeyGenParameterSpec} instances.       */      public final static class Builder { @@ -906,6 +921,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu          private boolean mUnlockedDeviceRequired = false;          private boolean mCriticalToDeviceEncryption = false;          private int mMaxUsageCount = KeyProperties.UNRESTRICTED_USAGE_COUNT; +        private String mAttestKeyAlias = null;          /**           * Creates a new instance of the {@code Builder}. @@ -975,6 +991,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu              mUnlockedDeviceRequired = sourceSpec.isUnlockedDeviceRequired();              mCriticalToDeviceEncryption = sourceSpec.isCriticalToDeviceEncryption();              mMaxUsageCount = sourceSpec.getMaxUsageCount(); +            mAttestKeyAlias = sourceSpec.getAttestKeyAlias();          }          /** @@ -1695,6 +1712,28 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu          }          /** +         * Sets the alias of the attestation key that will be used to sign the attestation +         * certificate for the generated key pair, if an attestation challenge is set with {@link +         * #setAttestationChallenge}.  If an attestKeyAlias is set but no challenge, {@link +         * java.security.KeyPairGenerator#initialize} will throw {@link +         * java.security.InvalidAlgorithmParameterException}. +         * +         * <p>If the attestKeyAlias is set to null (the default), Android Keystore will select an +         * appropriate system-provided attestation signing key.  If not null, the alias must +         * reference an Android Keystore Key that was created with {@link +         * android.security.keystore.KeyProperties#PURPOSE_ATTEST_KEY}, or key generation will throw +         * {@link java.security.InvalidAlgorithmParameterException}. +         * +         * @param attestKeyAlias the alias of the attestation key to be used to sign the +         *        attestation certificate. +         */ +        @NonNull +        public Builder setAttestKeyAlias(@Nullable String attestKeyAlias) { +            mAttestKeyAlias = attestKeyAlias; +            return this; +        } + +        /**           * Builds an instance of {@code KeyGenParameterSpec}.           */          @NonNull @@ -1731,7 +1770,8 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu                      mUserConfirmationRequired,                      mUnlockedDeviceRequired,                      mCriticalToDeviceEncryption, -                    mMaxUsageCount); +                    mMaxUsageCount, +                    mAttestKeyAlias);          }      }  } diff --git a/keystore/java/android/security/keystore/KeyProperties.java b/keystore/java/android/security/keystore/KeyProperties.java index 293ab05e0b10..7b0fa91380e1 100644 --- a/keystore/java/android/security/keystore/KeyProperties.java +++ b/keystore/java/android/security/keystore/KeyProperties.java @@ -70,6 +70,7 @@ public abstract class KeyProperties {              PURPOSE_VERIFY,              PURPOSE_WRAP_KEY,              PURPOSE_AGREE_KEY, +            PURPOSE_ATTEST_KEY,      })      public @interface PurposeEnum {} @@ -113,6 +114,13 @@ public abstract class KeyProperties {      public static final int PURPOSE_AGREE_KEY = 1 << 6;      /** +     * Purpose of key: Signing attestaions. This purpose is incompatible with all others, meaning +     * that when generating a key with PURPOSE_ATTEST_KEY, no other purposes may be specified. In +     * addition, PURPOSE_ATTEST_KEY may not be specified for imported keys. +     */ +    public static final int PURPOSE_ATTEST_KEY = 1 << 7; + +    /**       * @hide       */      public static abstract class Purpose { @@ -132,6 +140,8 @@ public abstract class KeyProperties {                      return KeymasterDefs.KM_PURPOSE_WRAP;                  case PURPOSE_AGREE_KEY:                      return KeymasterDefs.KM_PURPOSE_AGREE_KEY; +                case PURPOSE_ATTEST_KEY: +                    return KeymasterDefs.KM_PURPOSE_ATTEST_KEY;                  default:                      throw new IllegalArgumentException("Unknown purpose: " + purpose);              } @@ -151,6 +161,8 @@ public abstract class KeyProperties {                      return PURPOSE_WRAP_KEY;                  case KeymasterDefs.KM_PURPOSE_AGREE_KEY:                      return PURPOSE_AGREE_KEY; +                case KeymasterDefs.KM_PURPOSE_ATTEST_KEY: +                    return PURPOSE_ATTEST_KEY;                  default:                      throw new IllegalArgumentException("Unknown purpose: " + purpose);              } diff --git a/keystore/java/android/security/keystore/KeyProtection.java b/keystore/java/android/security/keystore/KeyProtection.java index 76ce23efd05b..673491ef523e 100644 --- a/keystore/java/android/security/keystore/KeyProtection.java +++ b/keystore/java/android/security/keystore/KeyProtection.java @@ -588,7 +588,8 @@ public final class KeyProtection implements ProtectionParameter, UserAuthArgs {          private long mBoundToSecureUserId = GateKeeper.INVALID_SECURE_USER_ID;          private boolean mCriticalToDeviceEncryption = false;          private boolean mIsStrongBoxBacked = false; -        private  int mMaxUsageCount = KeyProperties.UNRESTRICTED_USAGE_COUNT; +        private int mMaxUsageCount = KeyProperties.UNRESTRICTED_USAGE_COUNT; +        private String mAttestKeyAlias = null;          /**           * Creates a new instance of the {@code Builder}. diff --git a/keystore/java/android/security/keystore/ParcelableKeyGenParameterSpec.java b/keystore/java/android/security/keystore/ParcelableKeyGenParameterSpec.java index 1f2f853b67a8..c20cf01a993e 100644 --- a/keystore/java/android/security/keystore/ParcelableKeyGenParameterSpec.java +++ b/keystore/java/android/security/keystore/ParcelableKeyGenParameterSpec.java @@ -110,6 +110,7 @@ public final class ParcelableKeyGenParameterSpec implements Parcelable {          out.writeBoolean(mSpec.isUnlockedDeviceRequired());          out.writeBoolean(mSpec.isCriticalToDeviceEncryption());          out.writeInt(mSpec.getMaxUsageCount()); +        out.writeString(mSpec.getAttestKeyAlias());      }      private static Date readDateOrNull(Parcel in) { @@ -170,6 +171,7 @@ public final class ParcelableKeyGenParameterSpec implements Parcelable {          final boolean unlockedDeviceRequired = in.readBoolean();          final boolean criticalToDeviceEncryption = in.readBoolean();          final int maxUsageCount = in.readInt(); +        final String attestKeyAlias = in.readString();          // The KeyGenParameterSpec is intentionally not constructed using a Builder here:          // The intention is for this class to break if new parameters are added to the          // KeyGenParameterSpec constructor (whereas using a builder would silently drop them). @@ -205,7 +207,8 @@ public final class ParcelableKeyGenParameterSpec implements Parcelable {                  userConfirmationRequired,                  unlockedDeviceRequired,                  criticalToDeviceEncryption, -                maxUsageCount); +                maxUsageCount, +                attestKeyAlias);      }      public static final @android.annotation.NonNull Creator<ParcelableKeyGenParameterSpec> CREATOR = new Creator<ParcelableKeyGenParameterSpec>() { diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java index 4d27c3454a84..b3bfd6a3a97a 100644 --- a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java +++ b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java @@ -20,7 +20,9 @@ import android.annotation.NonNull;  import android.annotation.Nullable;  import android.content.Context;  import android.hardware.security.keymint.KeyParameter; +import android.hardware.security.keymint.KeyPurpose;  import android.hardware.security.keymint.SecurityLevel; +import android.hardware.security.keymint.Tag;  import android.os.Build;  import android.security.KeyPairGeneratorSpec;  import android.security.KeyStore; @@ -37,9 +39,11 @@ import android.security.keystore.KeyProperties;  import android.security.keystore.KeymasterUtils;  import android.security.keystore.SecureKeyImportUnavailableException;  import android.security.keystore.StrongBoxUnavailableException; +import android.system.keystore2.Authorization;  import android.system.keystore2.Domain;  import android.system.keystore2.IKeystoreSecurityLevel;  import android.system.keystore2.KeyDescriptor; +import android.system.keystore2.KeyEntryResponse;  import android.system.keystore2.KeyMetadata;  import android.system.keystore2.ResponseCode;  import android.telephony.TelephonyManager; @@ -61,6 +65,7 @@ import java.security.spec.AlgorithmParameterSpec;  import java.security.spec.ECGenParameterSpec;  import java.security.spec.RSAKeyGenParameterSpec;  import java.util.ArrayList; +import java.util.Arrays;  import java.util.Collection;  import java.util.Collections;  import java.util.HashMap; @@ -69,6 +74,7 @@ import java.util.List;  import java.util.Locale;  import java.util.Map;  import java.util.Set; +import java.util.function.Predicate;  /**   * Provides a way to create instances of a KeyPair which will be placed in the @@ -153,6 +159,7 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato      private int mKeymasterAlgorithm = -1;      private int mKeySizeBits;      private SecureRandom mRng; +    private KeyDescriptor mAttestKeyDescriptor;      private int[] mKeymasterPurposes;      private int[] mKeymasterBlockModes; @@ -197,83 +204,9 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato                  // Legacy/deprecated spec                  KeyPairGeneratorSpec legacySpec = (KeyPairGeneratorSpec) params;                  try { -                    KeyGenParameterSpec.Builder specBuilder; -                    String specKeyAlgorithm = legacySpec.getKeyType(); -                    if (specKeyAlgorithm != null) { -                        // Spec overrides the generator's default key algorithm -                        try { -                            keymasterAlgorithm = -                                    KeyProperties.KeyAlgorithm.toKeymasterAsymmetricKeyAlgorithm( -                                            specKeyAlgorithm); -                        } catch (IllegalArgumentException e) { -                            throw new InvalidAlgorithmParameterException( -                                    "Invalid key type in parameters", e); -                        } -                    } -                    switch (keymasterAlgorithm) { -                        case KeymasterDefs.KM_ALGORITHM_EC: -                            specBuilder = new KeyGenParameterSpec.Builder( -                                    legacySpec.getKeystoreAlias(), -                                    KeyProperties.PURPOSE_SIGN -                                    | KeyProperties.PURPOSE_VERIFY); -                            // Authorized to be used with any digest (including no digest). -                            // MD5 was never offered for Android Keystore for ECDSA. -                            specBuilder.setDigests( -                                    KeyProperties.DIGEST_NONE, -                                    KeyProperties.DIGEST_SHA1, -                                    KeyProperties.DIGEST_SHA224, -                                    KeyProperties.DIGEST_SHA256, -                                    KeyProperties.DIGEST_SHA384, -                                    KeyProperties.DIGEST_SHA512); -                            break; -                        case KeymasterDefs.KM_ALGORITHM_RSA: -                            specBuilder = new KeyGenParameterSpec.Builder( -                                    legacySpec.getKeystoreAlias(), -                                    KeyProperties.PURPOSE_ENCRYPT -                                    | KeyProperties.PURPOSE_DECRYPT -                                    | KeyProperties.PURPOSE_SIGN -                                    | KeyProperties.PURPOSE_VERIFY); -                            // Authorized to be used with any digest (including no digest). -                            specBuilder.setDigests( -                                    KeyProperties.DIGEST_NONE, -                                    KeyProperties.DIGEST_MD5, -                                    KeyProperties.DIGEST_SHA1, -                                    KeyProperties.DIGEST_SHA224, -                                    KeyProperties.DIGEST_SHA256, -                                    KeyProperties.DIGEST_SHA384, -                                    KeyProperties.DIGEST_SHA512); -                            // Authorized to be used with any encryption and signature padding -                            // schemes (including no padding). -                            specBuilder.setEncryptionPaddings( -                                    KeyProperties.ENCRYPTION_PADDING_NONE, -                                    KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1, -                                    KeyProperties.ENCRYPTION_PADDING_RSA_OAEP); -                            specBuilder.setSignaturePaddings( -                                    KeyProperties.SIGNATURE_PADDING_RSA_PKCS1, -                                    KeyProperties.SIGNATURE_PADDING_RSA_PSS); -                            // Disable randomized encryption requirement to support encryption -                            // padding NONE above. -                            specBuilder.setRandomizedEncryptionRequired(false); -                            break; -                        default: -                            throw new ProviderException( -                                    "Unsupported algorithm: " + mKeymasterAlgorithm); -                    } - -                    if (legacySpec.getKeySize() != -1) { -                        specBuilder.setKeySize(legacySpec.getKeySize()); -                    } -                    if (legacySpec.getAlgorithmParameterSpec() != null) { -                        specBuilder.setAlgorithmParameterSpec( -                                legacySpec.getAlgorithmParameterSpec()); -                    } -                    specBuilder.setCertificateSubject(legacySpec.getSubjectDN()); -                    specBuilder.setCertificateSerialNumber(legacySpec.getSerialNumber()); -                    specBuilder.setCertificateNotBefore(legacySpec.getStartDate()); -                    specBuilder.setCertificateNotAfter(legacySpec.getEndDate()); -                    specBuilder.setUserAuthenticationRequired(false); - -                    spec = specBuilder.build(); +                    keymasterAlgorithm = getKeymasterAlgorithmFromLegacy(keymasterAlgorithm, +                            legacySpec); +                    spec = buildKeyGenParameterSpecFromLegacy(legacySpec, keymasterAlgorithm);                  } catch (NullPointerException | IllegalArgumentException e) {                      throw new InvalidAlgorithmParameterException(e);                  } @@ -342,6 +275,10 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato              mJcaKeyAlgorithm = jcaKeyAlgorithm;              mRng = random;              mKeyStore = KeyStore2.getInstance(); + +            mAttestKeyDescriptor = buildAndCheckAttestKeyDescriptor(spec); +            checkAttestKeyPurpose(spec); +              success = true;          } finally {              if (!success) { @@ -350,6 +287,156 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato          }      } +    private void checkAttestKeyPurpose(KeyGenParameterSpec spec) +            throws InvalidAlgorithmParameterException { +        if ((spec.getPurposes() & KeyProperties.PURPOSE_ATTEST_KEY) != 0 +                && spec.getPurposes() != KeyProperties.PURPOSE_ATTEST_KEY) { +            throw new InvalidAlgorithmParameterException( +                    "PURPOSE_ATTEST_KEY may not be specified with any other purposes"); +        } +    } + +    private KeyDescriptor buildAndCheckAttestKeyDescriptor(KeyGenParameterSpec spec) +            throws InvalidAlgorithmParameterException { +        if (spec.getAttestKeyAlias() != null) { +            KeyDescriptor attestKeyDescriptor = new KeyDescriptor(); +            attestKeyDescriptor.domain = Domain.APP; +            attestKeyDescriptor.alias = spec.getAttestKeyAlias(); +            try { +                KeyEntryResponse attestKey = mKeyStore.getKeyEntry(attestKeyDescriptor); +                checkAttestKeyChallenge(spec); +                checkAttestKeyPurpose(attestKey.metadata.authorizations); +                checkAttestKeySecurityLevel(spec, attestKey); +            } catch (KeyStoreException e) { +                throw new InvalidAlgorithmParameterException("Invalid attestKeyAlias", e); +            } +            return attestKeyDescriptor; +        } +        return null; +    } + +    private void checkAttestKeyChallenge(KeyGenParameterSpec spec) +            throws InvalidAlgorithmParameterException { +        if (spec.getAttestationChallenge() == null) { +            throw new InvalidAlgorithmParameterException( +                    "AttestKey specified but no attestation challenge provided"); +        } +    } + +    private void checkAttestKeyPurpose(Authorization[] keyAuths) +            throws InvalidAlgorithmParameterException { +        Predicate<Authorization> isAttestKeyPurpose = x -> x.keyParameter.tag == Tag.PURPOSE +                && x.keyParameter.value.getKeyPurpose() == KeyPurpose.ATTEST_KEY; + +        if (Arrays.stream(keyAuths).noneMatch(isAttestKeyPurpose)) { +            throw new InvalidAlgorithmParameterException( +                    ("Invalid attestKey, does not have PURPOSE_ATTEST_KEY")); +        } +    } + +    private void checkAttestKeySecurityLevel(KeyGenParameterSpec spec, KeyEntryResponse key) +            throws InvalidAlgorithmParameterException { +        boolean attestKeyInStrongBox = key.metadata.keySecurityLevel == SecurityLevel.STRONGBOX; +        if (spec.isStrongBoxBacked() != attestKeyInStrongBox) { +            if (attestKeyInStrongBox) { +                throw new InvalidAlgorithmParameterException( +                        "Invalid security level: Cannot sign non-StrongBox key with " +                                + "StrongBox attestKey"); + +            } else { +                throw new InvalidAlgorithmParameterException( +                        "Invalid security level: Cannot sign StrongBox key with " +                                + "non-StrongBox attestKey"); +            } +        } +    } + +    private int getKeymasterAlgorithmFromLegacy(int keymasterAlgorithm, +            KeyPairGeneratorSpec legacySpec) throws InvalidAlgorithmParameterException { +        String specKeyAlgorithm = legacySpec.getKeyType(); +        if (specKeyAlgorithm != null) { +            // Spec overrides the generator's default key algorithm +            try { +                keymasterAlgorithm = +                        KeyProperties.KeyAlgorithm.toKeymasterAsymmetricKeyAlgorithm( +                                specKeyAlgorithm); +            } catch (IllegalArgumentException e) { +                throw new InvalidAlgorithmParameterException( +                        "Invalid key type in parameters", e); +            } +        } +        return keymasterAlgorithm; +    } + +    private KeyGenParameterSpec buildKeyGenParameterSpecFromLegacy(KeyPairGeneratorSpec legacySpec, +            int keymasterAlgorithm) { +        KeyGenParameterSpec.Builder specBuilder; +        switch (keymasterAlgorithm) { +            case KeymasterDefs.KM_ALGORITHM_EC: +                specBuilder = new KeyGenParameterSpec.Builder( +                        legacySpec.getKeystoreAlias(), +                        KeyProperties.PURPOSE_SIGN +                        | KeyProperties.PURPOSE_VERIFY); +                // Authorized to be used with any digest (including no digest). +                // MD5 was never offered for Android Keystore for ECDSA. +                specBuilder.setDigests( +                        KeyProperties.DIGEST_NONE, +                        KeyProperties.DIGEST_SHA1, +                        KeyProperties.DIGEST_SHA224, +                        KeyProperties.DIGEST_SHA256, +                        KeyProperties.DIGEST_SHA384, +                        KeyProperties.DIGEST_SHA512); +                break; +            case KeymasterDefs.KM_ALGORITHM_RSA: +                specBuilder = new KeyGenParameterSpec.Builder( +                        legacySpec.getKeystoreAlias(), +                        KeyProperties.PURPOSE_ENCRYPT +                        | KeyProperties.PURPOSE_DECRYPT +                        | KeyProperties.PURPOSE_SIGN +                        | KeyProperties.PURPOSE_VERIFY); +                // Authorized to be used with any digest (including no digest). +                specBuilder.setDigests( +                        KeyProperties.DIGEST_NONE, +                        KeyProperties.DIGEST_MD5, +                        KeyProperties.DIGEST_SHA1, +                        KeyProperties.DIGEST_SHA224, +                        KeyProperties.DIGEST_SHA256, +                        KeyProperties.DIGEST_SHA384, +                        KeyProperties.DIGEST_SHA512); +                // Authorized to be used with any encryption and signature padding +                // schemes (including no padding). +                specBuilder.setEncryptionPaddings( +                        KeyProperties.ENCRYPTION_PADDING_NONE, +                        KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1, +                        KeyProperties.ENCRYPTION_PADDING_RSA_OAEP); +                specBuilder.setSignaturePaddings( +                        KeyProperties.SIGNATURE_PADDING_RSA_PKCS1, +                        KeyProperties.SIGNATURE_PADDING_RSA_PSS); +                // Disable randomized encryption requirement to support encryption +                // padding NONE above. +                specBuilder.setRandomizedEncryptionRequired(false); +                break; +            default: +                throw new ProviderException( +                        "Unsupported algorithm: " + mKeymasterAlgorithm); +        } + +        if (legacySpec.getKeySize() != -1) { +            specBuilder.setKeySize(legacySpec.getKeySize()); +        } +        if (legacySpec.getAlgorithmParameterSpec() != null) { +            specBuilder.setAlgorithmParameterSpec( +                    legacySpec.getAlgorithmParameterSpec()); +        } +        specBuilder.setCertificateSubject(legacySpec.getSubjectDN()); +        specBuilder.setCertificateSerialNumber(legacySpec.getSerialNumber()); +        specBuilder.setCertificateNotBefore(legacySpec.getStartDate()); +        specBuilder.setCertificateNotAfter(legacySpec.getEndDate()); +        specBuilder.setUserAuthenticationRequired(false); + +        return specBuilder.build(); +    } +      private void resetAll() {          mEntryAlias = null;          mEntryUid = KeyProperties.NAMESPACE_APPLICATION; @@ -464,7 +551,7 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato          try {              KeyStoreSecurityLevel iSecurityLevel = mKeyStore.getSecurityLevel(securityLevel); -            KeyMetadata metadata = iSecurityLevel.generateKey(descriptor, null, +            KeyMetadata metadata = iSecurityLevel.generateKey(descriptor, mAttestKeyDescriptor,                      constructKeyGenerationArguments(), flags, additionalEntropy);              AndroidKeyStorePublicKey publicKey = |