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

Commit 5d5fa514 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "DPM: Implement Device ID attestation"

parents 596a199d 94d56761
Loading
Loading
Loading
Loading
+5 −1
Original line number Diff line number Diff line
@@ -6338,7 +6338,7 @@ package android.app.admin {
    method public android.os.UserHandle createAndManageUser(android.content.ComponentName, java.lang.String, android.content.ComponentName, android.os.PersistableBundle, int);
    method public void enableSystemApp(android.content.ComponentName, java.lang.String);
    method public int enableSystemApp(android.content.ComponentName, android.content.Intent);
    method public android.security.AttestedKeyPair generateKeyPair(android.content.ComponentName, java.lang.String, android.security.keystore.KeyGenParameterSpec);
    method public android.security.AttestedKeyPair generateKeyPair(android.content.ComponentName, java.lang.String, android.security.keystore.KeyGenParameterSpec, int);
    method public java.lang.String[] getAccountTypesWithManagementDisabled();
    method public java.util.List<android.content.ComponentName> getActiveAdmins();
    method public java.util.Set<java.lang.String> getAffiliationIds(android.content.ComponentName);
@@ -6572,6 +6572,10 @@ package android.app.admin {
    field public static final int FLAG_EVICT_CREDENTIAL_ENCRYPTION_KEY = 1; // 0x1
    field public static final int FLAG_MANAGED_CAN_ACCESS_PARENT = 2; // 0x2
    field public static final int FLAG_PARENT_CAN_ACCESS_MANAGED = 1; // 0x1
    field public static final int ID_TYPE_BASE_INFO = 1; // 0x1
    field public static final int ID_TYPE_IMEI = 4; // 0x4
    field public static final int ID_TYPE_MEID = 8; // 0x8
    field public static final int ID_TYPE_SERIAL = 2; // 0x2
    field public static final int KEYGUARD_DISABLE_FEATURES_ALL = 2147483647; // 0x7fffffff
    field public static final int KEYGUARD_DISABLE_FEATURES_NONE = 0; // 0x0
    field public static final int KEYGUARD_DISABLE_FINGERPRINT = 32; // 0x20
+69 −5
Original line number Diff line number Diff line
@@ -1668,6 +1668,46 @@ public class DevicePolicyManager {
    public static final String ACTION_DEVICE_ADMIN_SERVICE
            = "android.app.action.DEVICE_ADMIN_SERVICE";

    /** @hide */
    @Retention(RetentionPolicy.SOURCE)
    @IntDef(flag = true, prefix = {"ID_TYPE_"}, value = {
        ID_TYPE_BASE_INFO,
        ID_TYPE_SERIAL,
        ID_TYPE_IMEI,
        ID_TYPE_MEID
    })
    public @interface AttestationIdType {}

    /**
     * Specifies that the device should attest its manufacturer details. For use with
     * {@link #generateKeyPair}.
     *
     * @see #generateKeyPair
     */
    public static final int ID_TYPE_BASE_INFO = 1;

    /**
     * Specifies that the device should attest its serial number. For use with
     * {@link #generateKeyPair}.
     *
     * @see #generateKeyPair
     */
    public static final int ID_TYPE_SERIAL = 2;

    /**
     * Specifies that the device should attest its IMEI. For use with {@link #generateKeyPair}.
     *
     * @see #generateKeyPair
     */
    public static final int ID_TYPE_IMEI = 4;

    /**
     * Specifies that the device should attest its MEID. For use with {@link #generateKeyPair}.
     *
     * @see #generateKeyPair
     */
    public static final int ID_TYPE_MEID = 8;

    /**
     * Return true if the given administrator component is currently active (enabled) in the system.
     *
@@ -4106,22 +4146,46 @@ public class DevicePolicyManager {
     * @param algorithm The key generation algorithm, see {@link java.security.KeyPairGenerator}.
     * @param keySpec Specification of the key to generate, see
     * {@link java.security.KeyPairGenerator}.
     * @param idAttestationFlags A bitmask of all the identifiers that should be included in the
     *        attestation record ({@code ID_TYPE_BASE_INFO}, {@code ID_TYPE_SERIAL},
     *        {@code ID_TYPE_IMEI} and {@code ID_TYPE_MEID}), or {@code 0} if no device
     *        identification is required in the attestation record.
     *        Device owner, profile owner and their delegated certificate installer can use
     *        {@link #ID_TYPE_BASE_INFO} to request inclusion of the general device information
     *        including manufacturer, model, brand, device and product in the attestation record.
     *        Only device owner and their delegated certificate installer can use
     *        {@link #ID_TYPE_SERIAL}, {@link #ID_TYPE_IMEI} and {@link #ID_TYPE_MEID} to request
     *        unique device identifiers to be attested.
     *        <p>
     *        If any of {@link #ID_TYPE_SERIAL}, {@link #ID_TYPE_IMEI} and {@link #ID_TYPE_MEID}
     *        is set, it is implicitly assumed that {@link #ID_TYPE_BASE_INFO} is also set.
     *        <p>
     *        If any flag is specified, then an attestation challenge must be included in the
     *        {@code keySpec}.
     * @return A non-null {@code AttestedKeyPair} if the key generation succeeded, null otherwise.
     * @throws SecurityException if {@code admin} is not {@code null} and not a device or profile
     *         owner.
     * @throws IllegalArgumentException if the alias in {@code keySpec} is empty, or if the
     *         owner. If Device ID attestation is requested (using {@link #ID_TYPE_SERIAL},
     *         {@link #ID_TYPE_IMEI} or {@link #ID_TYPE_MEID}), the caller must be the Device Owner
     *         or the Certificate Installer delegate.
     * @throws IllegalArgumentException if the alias in {@code keySpec} is empty, if the
     *         algorithm specification in {@code keySpec} is not {@code RSAKeyGenParameterSpec}
     *         or {@code ECGenParameterSpec}.
     *         or {@code ECGenParameterSpec}, or if Device ID attestation was requested but the
     *         {@code keySpec} does not contain an attestation challenge.
     * @see KeyGenParameterSpec.Builder#setAttestationChallenge(byte[])
     */
    public AttestedKeyPair generateKeyPair(@Nullable ComponentName admin,
            @NonNull String algorithm, @NonNull KeyGenParameterSpec keySpec) {
            @NonNull String algorithm, @NonNull KeyGenParameterSpec keySpec,
            @AttestationIdType int idAttestationFlags) {
        throwIfParentInstance("generateKeyPair");
        try {
            final ParcelableKeyGenParameterSpec parcelableSpec =
                    new ParcelableKeyGenParameterSpec(keySpec);
            KeymasterCertificateChain attestationChain = new KeymasterCertificateChain();

            // Translate ID attestation flags to values used by AttestationUtils
            final boolean success = mService.generateKeyPair(
                    admin, mContext.getPackageName(), algorithm, parcelableSpec, attestationChain);
                    admin, mContext.getPackageName(), algorithm, parcelableSpec,
                    idAttestationFlags, attestationChain);
            if (!success) {
                Log.e(TAG, "Error generating key via DevicePolicyManagerService.");
                return null;
+1 −1
Original line number Diff line number Diff line
@@ -173,7 +173,7 @@ interface IDevicePolicyManager {
    boolean removeKeyPair(in ComponentName who, in String callerPackage, String alias);
    boolean generateKeyPair(in ComponentName who, in String callerPackage, in String algorithm,
            in ParcelableKeyGenParameterSpec keySpec,
            out KeymasterCertificateChain attestationChain);
            in int idAttestationFlags, out KeymasterCertificateChain attestationChain);
    boolean setKeyPairCertificate(in ComponentName who, in String callerPackage, in String alias,
            in byte[] certBuffer, in byte[] certChainBuffer, boolean isUserSelectable);
    void choosePrivateKeyAlias(int uid, in Uri uri, in String alias, IBinder aliasCallback);
+2 −1
Original line number Diff line number Diff line
@@ -34,7 +34,8 @@ interface IKeyChainService {
    void setUserSelectable(String alias, boolean isUserSelectable);

    boolean generateKeyPair(in String algorithm, in ParcelableKeyGenParameterSpec spec);
    boolean attestKey(in String alias, in byte[] challenge, out KeymasterCertificateChain chain);
    boolean attestKey(in String alias, in byte[] challenge, in int[] idAttestationFlags,
            out KeymasterCertificateChain chain);
    boolean setKeyPairCertificate(String alias, in byte[] userCert, in byte[] certChain);

    // APIs used by CertInstaller and DevicePolicyManager
+57 −32
Original line number Diff line number Diff line
@@ -99,48 +99,35 @@ 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);
    }

    /**
     * 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
     * manufacturer, model, brand, device and product are always also included in the attestation.
     * If the device supports attestation in secure hardware, the chain will be rooted at a
     * trustworthy CA key. Otherwise, the chain will be rooted at an untrusted certificate. See
     * <a href="https://developer.android.com/training/articles/security-key-attestation.html">
     * Key Attestation</a> for the format of the certificate extension.
     * <p>
     * Attestation will only be successful when all of the following are true:
     * 1) The device has been set up to support device identifier attestation at the factory.
     * 2) The user has not permanently disabled device identifier attestation.
     * 3) You have permission to access the device identifiers you are requesting attestation for.
     * <p>
     * For privacy reasons, you cannot distinguish between (1) and (2). If attestation is
     * unsuccessful, the device may not support it in general or the user may have permanently
     * disabled it.
     *
     * @param context the context to use for retrieving device identifiers.
     * @param idTypes the types of device identifiers to attest.
     * @param attestationChallenge a blob to include in the certificate alongside the device
     * identifiers.
     *
     * @return a certificate chain containing the requested device identifiers in the first element
     *
     * @exception SecurityException if you are not permitted to obtain an attestation of the
     * device's identifiers.
     * @exception DeviceIdAttestationException if the attestation operation fails.
     * Prepares Keymaster Arguments with attestation data.
     * @hide should only be used by KeyChain.
     */
    @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
    @NonNull public static X509Certificate[] attestDeviceIds(Context context,
    @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 (idTypes == null) {
            throw new NullPointerException("Missing id types");
        }
        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);
@@ -191,6 +178,44 @@ public abstract class AttestationUtils {
                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
     * whose first element contains the requested device identifiers in an extension. The device's
     * manufacturer, model, brand, device and product are always also included in the attestation.
     * If the device supports attestation in secure hardware, the chain will be rooted at a
     * trustworthy CA key. Otherwise, the chain will be rooted at an untrusted certificate. See
     * <a href="https://developer.android.com/training/articles/security-key-attestation.html">
     * Key Attestation</a> for the format of the certificate extension.
     * <p>
     * Attestation will only be successful when all of the following are true:
     * 1) The device has been set up to support device identifier attestation at the factory.
     * 2) The user has not permanently disabled device identifier attestation.
     * 3) You have permission to access the device identifiers you are requesting attestation for.
     * <p>
     * For privacy reasons, you cannot distinguish between (1) and (2). If attestation is
     * unsuccessful, the device may not support it in general or the user may have permanently
     * disabled it.
     *
     * @param context the context to use for retrieving device identifiers.
     * @param idTypes the types of device identifiers to attest.
     * @param attestationChallenge a blob to include in the certificate alongside the device
     * identifiers.
     *
     * @return a certificate chain containing the requested device identifiers in the first element
     *
     * @exception SecurityException if you are not permitted to obtain an attestation of the
     * device's identifiers.
     * @exception DeviceIdAttestationException if the attestation operation fails.
     */
    @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
    @NonNull public static X509Certificate[] attestDeviceIds(Context context,
            @NonNull int[] idTypes, @NonNull byte[] attestationChallenge) throws
            DeviceIdAttestationException {
        final KeymasterArguments attestArgs = prepareAttestationArgumentsForDeviceId(
                context, idTypes, attestationChallenge);

        // Perform attestation.
        final KeymasterCertificateChain outChain = new KeymasterCertificateChain();
Loading