Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9112917e authored by Janis Danisevskis's avatar Janis Danisevskis Committed by Automerger Merge Worker
Browse files

Merge "Adding device ID attestation to KeyGenParameterSpec" am: 3faed136 am: 0072df0d

Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/1554667

MUST ONLY BE SUBMITTED BY AUTOMERGER

Change-Id: I2847baa64bdc5c2b949c5e87f6bffb1ad4986bea
parents 68c83e63 0072df0d
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -8435,10 +8435,12 @@ package android.security.keystore {
  }
  public final class KeyGenParameterSpec implements java.security.spec.AlgorithmParameterSpec {
    method @Nullable public int[] getAttestationIds();
    method public int getNamespace();
  }
  public static final class KeyGenParameterSpec.Builder {
    method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setAttestationIds(@NonNull int[]);
    method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setNamespace(int);
    method @Deprecated @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setUid(int);
  }
+64 −6
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package android.security.keystore;

import android.annotation.Nullable;
import android.content.Context;
import android.os.Build;
import android.security.Credentials;
import android.security.KeyPairGeneratorSpec;
@@ -25,6 +26,8 @@ import android.security.keymaster.KeyCharacteristics;
import android.security.keymaster.KeymasterArguments;
import android.security.keymaster.KeymasterCertificateChain;
import android.security.keymaster.KeymasterDefs;
import android.telephony.TelephonyManager;
import android.util.ArraySet;

import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
import com.android.internal.org.bouncycastle.asn1.ASN1InputStream;
@@ -477,11 +480,11 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato

            success = true;
            return keyPair;
        } catch (ProviderException e) {
        } catch (ProviderException | IllegalArgumentException | DeviceIdAttestationException e) {
          if ((mSpec.getPurposes() & KeyProperties.PURPOSE_WRAP_KEY) != 0) {
              throw new SecureKeyImportUnavailableException(e);
          } else {
              throw e;
                throw new ProviderException(e);
          }
        } finally {
            if (!success) {
@@ -491,7 +494,7 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
    }

    private Iterable<byte[]> createCertificateChain(final String privateKeyAlias, KeyPair keyPair)
            throws ProviderException {
            throws ProviderException, DeviceIdAttestationException {
        byte[] challenge = mSpec.getAttestationChallenge();
        if (challenge != null) {
            KeymasterArguments args = new KeymasterArguments();
@@ -510,6 +513,60 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
                        Build.MODEL.getBytes(StandardCharsets.UTF_8));
            }

            int[] idTypes = mSpec.getAttestationIds();
            if (idTypes != null) {
                final Set<Integer> idTypesSet = new ArraySet<>(idTypes.length);
                for (int idType : idTypes) {
                    idTypesSet.add(idType);
                }
                TelephonyManager telephonyService = null;
                if (idTypesSet.contains(AttestationUtils.ID_TYPE_IMEI)
                        || idTypesSet.contains(AttestationUtils.ID_TYPE_MEID)) {
                    telephonyService =
                            (TelephonyManager) KeyStore.getApplicationContext().getSystemService(
                                    Context.TELEPHONY_SERVICE);
                    if (telephonyService == null) {
                        throw new DeviceIdAttestationException(
                                "Unable to access telephony service");
                    }
                }
                for (final Integer idType : idTypesSet) {
                    switch (idType) {
                        case AttestationUtils.ID_TYPE_SERIAL:
                            args.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_ID_SERIAL,
                                    Build.getSerial().getBytes(StandardCharsets.UTF_8)
                            );
                            break;
                        case AttestationUtils.ID_TYPE_IMEI: {
                            final String imei = telephonyService.getImei(0);
                            if (imei == null) {
                                throw new DeviceIdAttestationException("Unable to retrieve IMEI");
                            }
                            args.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_ID_IMEI,
                                    imei.getBytes(StandardCharsets.UTF_8)
                            );
                            break;
                        }
                        case AttestationUtils.ID_TYPE_MEID: {
                            final String meid = telephonyService.getMeid(0);
                            if (meid == null) {
                                throw new DeviceIdAttestationException("Unable to retrieve MEID");
                            }
                            args.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_ID_MEID,
                                    meid.getBytes(StandardCharsets.UTF_8)
                            );
                            break;
                        }
                        case AttestationUtils.USE_INDIVIDUAL_ATTESTATION: {
                            args.addBoolean(KeymasterDefs.KM_TAG_DEVICE_UNIQUE_ATTESTATION);
                            break;
                        }
                        default:
                            throw new IllegalArgumentException("Unknown device ID type " + idType);
                    }
                }
            }

            return getAttestationChain(privateKeyAlias, keyPair, args);
        }

@@ -547,7 +604,8 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
        }
    }

    private KeymasterArguments constructKeyGenerationArguments() {
    private KeymasterArguments constructKeyGenerationArguments()
            throws IllegalArgumentException, DeviceIdAttestationException {
        KeymasterArguments args = new KeymasterArguments();
        args.addUnsignedInt(KeymasterDefs.KM_TAG_KEY_SIZE, mKeySizeBits);
        args.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, mKeymasterAlgorithm);
@@ -565,9 +623,9 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
                mSpec.getKeyValidityForConsumptionEnd());
        addAlgorithmSpecificParameters(args);

        if (mSpec.isUniqueIdIncluded())
        if (mSpec.isUniqueIdIncluded()) {
            args.addBoolean(KeymasterDefs.KM_TAG_INCLUDE_UNIQUE_ID);

        }
        return args;
    }

+8 −0
Original line number Diff line number Diff line
@@ -34,6 +34,14 @@ public abstract class ArrayUtils {
        return ((array != null) && (array.length > 0)) ? array.clone() : array;
    }

    /**
     * Clones an array if it is not null and has a length greater than 0. Otherwise, returns the
     * array.
     */
    public static int[] cloneIfNotEmpty(int[] array) {
        return ((array != null) && (array.length > 0)) ? array.clone() : array;
    }

    public static byte[] cloneIfNotEmpty(byte[] array) {
        return ((array != null) && (array.length > 0)) ? array.clone() : array;
    }
+45 −0
Original line number Diff line number Diff line
@@ -267,6 +267,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu
    private final boolean mUserPresenceRequired;
    private final byte[] mAttestationChallenge;
    private final boolean mDevicePropertiesAttestationIncluded;
    private final int[] mAttestationIds;
    private final boolean mUniqueIdIncluded;
    private final boolean mUserAuthenticationValidWhileOnBody;
    private final boolean mInvalidatedByBiometricEnrollment;
@@ -308,6 +309,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu
            boolean userPresenceRequired,
            byte[] attestationChallenge,
            boolean devicePropertiesAttestationIncluded,
            int[] attestationIds,
            boolean uniqueIdIncluded,
            boolean userAuthenticationValidWhileOnBody,
            boolean invalidatedByBiometricEnrollment,
@@ -361,6 +363,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu
        mUserAuthenticationType = userAuthenticationType;
        mAttestationChallenge = Utils.cloneIfNotNull(attestationChallenge);
        mDevicePropertiesAttestationIncluded = devicePropertiesAttestationIncluded;
        mAttestationIds = attestationIds;
        mUniqueIdIncluded = uniqueIdIncluded;
        mUserAuthenticationValidWhileOnBody = userAuthenticationValidWhileOnBody;
        mInvalidatedByBiometricEnrollment = invalidatedByBiometricEnrollment;
@@ -719,6 +722,25 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu
        return mDevicePropertiesAttestationIncluded;
    }

    /**
     * @hide
     * Allows the caller to specify device IDs to be attested to in the certificate for the
     * generated key pair. These values are the enums specified in
     * {@link android.security.keystore.AttestationUtils}
     *
     * @see android.security.keystore.AttestationUtils#ID_TYPE_SERIAL
     * @see android.security.keystore.AttestationUtils#ID_TYPE_IMEI
     * @see android.security.keystore.AttestationUtils#ID_TYPE_MEID
     * @see android.security.keystore.AttestationUtils#USE_INDIVIDUAL_ATTESTATION
     *
     * @return integer array representing the requested device IDs to attest.
     */
    @SystemApi
    @Nullable
    public int[] getAttestationIds() {
        return Utils.cloneIfNotNull(mAttestationIds);
    }

    /**
     * @hide This is a system-only API
     *
@@ -834,6 +856,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu
        private boolean mUserPresenceRequired = false;
        private byte[] mAttestationChallenge = null;
        private boolean mDevicePropertiesAttestationIncluded = false;
        private int[] mAttestationIds = null;
        private boolean mUniqueIdIncluded = false;
        private boolean mUserAuthenticationValidWhileOnBody;
        private boolean mInvalidatedByBiometricEnrollment = true;
@@ -902,6 +925,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu
            mAttestationChallenge = sourceSpec.getAttestationChallenge();
            mDevicePropertiesAttestationIncluded =
                    sourceSpec.isDevicePropertiesAttestationIncluded();
            mAttestationIds = sourceSpec.getAttestationIds();
            mUniqueIdIncluded = sourceSpec.isUniqueIdIncluded();
            mUserAuthenticationValidWhileOnBody = sourceSpec.isUserAuthenticationValidWhileOnBody();
            mInvalidatedByBiometricEnrollment = sourceSpec.isInvalidatedByBiometricEnrollment();
@@ -1472,6 +1496,26 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu
            return this;
        }

        /**
         * @hide
         * Sets which IDs to attest in the attestation certificate for the key. The acceptable
         * values in this integer array are the enums specified in
         * {@link android.security.keystore.AttestationUtils}
         *
         * @param attestationIds the array of ID types to attest to in the certificate.
         *
         * @see android.security.keystore.AttestationUtils#ID_TYPE_SERIAL
         * @see android.security.keystore.AttestationUtils#ID_TYPE_IMEI
         * @see android.security.keystore.AttestationUtils#ID_TYPE_MEID
         * @see android.security.keystore.AttestationUtils#USE_INDIVIDUAL_ATTESTATION
         */
        @SystemApi
        @NonNull
        public Builder setAttestationIds(@NonNull int[] attestationIds) {
            mAttestationIds = attestationIds;
            return this;
        }

        /**
         * @hide Only system apps can use this method.
         *
@@ -1638,6 +1682,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu
                    mUserPresenceRequired,
                    mAttestationChallenge,
                    mDevicePropertiesAttestationIncluded,
                    mAttestationIds,
                    mUniqueIdIncluded,
                    mUserAuthenticationValidWhileOnBody,
                    mInvalidatedByBiometricEnrollment,
+3 −0
Original line number Diff line number Diff line
@@ -101,6 +101,7 @@ public final class ParcelableKeyGenParameterSpec implements Parcelable {
        out.writeBoolean(mSpec.isUserPresenceRequired());
        out.writeByteArray(mSpec.getAttestationChallenge());
        out.writeBoolean(mSpec.isDevicePropertiesAttestationIncluded());
        out.writeIntArray(mSpec.getAttestationIds());
        out.writeBoolean(mSpec.isUniqueIdIncluded());
        out.writeBoolean(mSpec.isUserAuthenticationValidWhileOnBody());
        out.writeBoolean(mSpec.isInvalidatedByBiometricEnrollment());
@@ -160,6 +161,7 @@ public final class ParcelableKeyGenParameterSpec implements Parcelable {
        final boolean userPresenceRequired = in.readBoolean();
        final byte[] attestationChallenge = in.createByteArray();
        final boolean devicePropertiesAttestationIncluded = in.readBoolean();
        final int[] attestationIds = in.createIntArray();
        final boolean uniqueIdIncluded = in.readBoolean();
        final boolean userAuthenticationValidWhileOnBody = in.readBoolean();
        final boolean invalidatedByBiometricEnrollment = in.readBoolean();
@@ -195,6 +197,7 @@ public final class ParcelableKeyGenParameterSpec implements Parcelable {
                userPresenceRequired,
                attestationChallenge,
                devicePropertiesAttestationIncluded,
                attestationIds,
                uniqueIdIncluded,
                userAuthenticationValidWhileOnBody,
                invalidatedByBiometricEnrollment,
Loading