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

Commit 20651aba authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Automerger Merge Worker
Browse files

Merge "Check for invalid device attestation parameters" into sc-dev am: d8be4517

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

Change-Id: I9cc2ed97f91da080bb6ce8febb70fe7308e50a5f
parents dd27fede d8be4517
Loading
Loading
Loading
Loading
+14 −93
Original line number Original line Diff line number Diff line
@@ -21,18 +21,13 @@ import android.annotation.NonNull;
import android.annotation.RequiresPermission;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.SystemApi;
import android.content.Context;
import android.content.Context;
import android.os.Build;
import android.security.keymaster.KeymasterArguments;
import android.security.keymaster.KeymasterCertificateChain;
import android.security.keymaster.KeymasterCertificateChain;
import android.security.keymaster.KeymasterDefs;
import android.telephony.TelephonyManager;
import android.util.ArraySet;


import java.io.ByteArrayInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ByteArrayOutputStream;
import java.nio.charset.StandardCharsets;
import java.security.KeyPairGenerator;
import java.security.KeyPairGenerator;
import java.security.KeyStore;
import java.security.KeyStore;
import java.security.ProviderException;
import java.security.SecureRandom;
import java.security.SecureRandom;
import java.security.cert.Certificate;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.CertificateFactory;
@@ -41,7 +36,6 @@ import java.security.spec.ECGenParameterSpec;
import java.util.Arrays;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collection;
import java.util.Random;
import java.util.Random;
import java.util.Set;


/**
/**
 * Utilities for attesting the device's hardware identifiers.
 * Utilities for attesting the device's hardware identifiers.
@@ -110,92 +104,6 @@ public abstract class AttestationUtils {
        }
        }
    }
    }


    @NonNull private static KeymasterArguments prepareAttestationArgumentsForDeviceId(
            Context context, @NonNull int[] idTypes, @NonNull byte[] attestationChallenge) throws
            DeviceIdAttestationException {
        // Verify that device ID attestation types are provided.
        if (idTypes == null) {
            throw new NullPointerException("Missing id types");
        }

        return prepareAttestationArguments(context, idTypes, attestationChallenge);
    }

    /**
     * Prepares Keymaster Arguments with attestation data.
     * @hide should only be used by KeyChain.
     */
    @NonNull public static KeymasterArguments prepareAttestationArguments(Context context,
            @NonNull int[] idTypes, @NonNull byte[] attestationChallenge) throws
            DeviceIdAttestationException {
        // Check method arguments, retrieve requested device IDs and prepare attestation arguments.
        if (attestationChallenge == null) {
            throw new NullPointerException("Missing attestation challenge");
        }
        final KeymasterArguments attestArgs = new KeymasterArguments();
        attestArgs.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_CHALLENGE, attestationChallenge);
        // Return early if the caller did not request any device identifiers to be included in the
        // attestation record.
        if (idTypes == null) {
            return attestArgs;
        }
        final Set<Integer> idTypesSet = new ArraySet<>(idTypes.length);
        for (int idType : idTypes) {
            idTypesSet.add(idType);
        }
        TelephonyManager telephonyService = null;
        if (idTypesSet.contains(ID_TYPE_IMEI) || idTypesSet.contains(ID_TYPE_MEID)) {
            telephonyService = (TelephonyManager) context.getSystemService(
                    Context.TELEPHONY_SERVICE);
            if (telephonyService == null) {
                throw new DeviceIdAttestationException("Unable to access telephony service");
            }
        }
        for (final Integer idType : idTypesSet) {
            switch (idType) {
                case ID_TYPE_SERIAL:
                    attestArgs.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_ID_SERIAL,
                            Build.getSerial().getBytes(StandardCharsets.UTF_8));
                    break;
                case ID_TYPE_IMEI: {
                    final String imei = telephonyService.getImei(0);
                    if (imei == null) {
                        throw new DeviceIdAttestationException("Unable to retrieve IMEI");
                    }
                    attestArgs.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_ID_IMEI,
                            imei.getBytes(StandardCharsets.UTF_8));
                    break;
                }
                case ID_TYPE_MEID: {
                    final String meid = telephonyService.getMeid(0);
                    if (meid == null) {
                        throw new DeviceIdAttestationException("Unable to retrieve MEID");
                    }
                    attestArgs.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_ID_MEID,
                            meid.getBytes(StandardCharsets.UTF_8));
                    break;
                }
                case USE_INDIVIDUAL_ATTESTATION: {
                    attestArgs.addBoolean(KeymasterDefs.KM_TAG_DEVICE_UNIQUE_ATTESTATION);
                    break;
                }
                default:
                    throw new IllegalArgumentException("Unknown device ID type " + idType);
            }
        }
        attestArgs.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_ID_BRAND,
                Build.BRAND.getBytes(StandardCharsets.UTF_8));
        attestArgs.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_ID_DEVICE,
                Build.DEVICE.getBytes(StandardCharsets.UTF_8));
        attestArgs.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_ID_PRODUCT,
                Build.PRODUCT.getBytes(StandardCharsets.UTF_8));
        attestArgs.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_ID_MANUFACTURER,
                Build.MANUFACTURER.getBytes(StandardCharsets.UTF_8));
        attestArgs.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_ID_MODEL,
                Build.MODEL.getBytes(StandardCharsets.UTF_8));
        return attestArgs;
    }

    /**
    /**
     * Performs attestation of the device's identifiers. This method returns a certificate chain
     * Performs attestation of the device's identifiers. This method returns a certificate chain
     * whose first element contains the requested device identifiers in an extension. The device's
     * whose first element contains the requested device identifiers in an extension. The device's
@@ -229,6 +137,13 @@ public abstract class AttestationUtils {
    @NonNull public static X509Certificate[] attestDeviceIds(Context context,
    @NonNull public static X509Certificate[] attestDeviceIds(Context context,
            @NonNull int[] idTypes, @NonNull byte[] attestationChallenge) throws
            @NonNull int[] idTypes, @NonNull byte[] attestationChallenge) throws
            DeviceIdAttestationException {
            DeviceIdAttestationException {
        if (attestationChallenge == null) {
            throw new NullPointerException("Missing attestation challenge");
        }
        if (idTypes == null) {
            throw new NullPointerException("Missing id types");
        }

        String keystoreAlias = generateRandomAlias();
        String keystoreAlias = generateRandomAlias();
        KeyGenParameterSpec.Builder builder =
        KeyGenParameterSpec.Builder builder =
                new KeyGenParameterSpec.Builder(keystoreAlias, KeyProperties.PURPOSE_SIGN)
                new KeyGenParameterSpec.Builder(keystoreAlias, KeyProperties.PURPOSE_SIGN)
@@ -265,6 +180,12 @@ public abstract class AttestationUtils {
            if (e.getCause() instanceof DeviceIdAttestationException) {
            if (e.getCause() instanceof DeviceIdAttestationException) {
                throw (DeviceIdAttestationException) e.getCause();
                throw (DeviceIdAttestationException) e.getCause();
            }
            }
            // Illegal argument errors are wrapped up by a ProviderException. Catch those so that
            // we can unwrap them into a more meaningful exception type for the caller.
            if (e instanceof ProviderException
                    && e.getCause() instanceof IllegalArgumentException) {
                throw (IllegalArgumentException) e.getCause();
            }
            throw new DeviceIdAttestationException("Unable to perform attestation", e);
            throw new DeviceIdAttestationException("Unable to perform attestation", e);
        }
        }
    }
    }