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

Commit 3faed136 authored by Janis Danisevskis's avatar Janis Danisevskis Committed by Gerrit Code Review
Browse files

Merge "Adding device ID attestation to KeyGenParameterSpec"

parents 2d29d2d8 84cd6f22
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