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

Commit 0306b1ce authored by Shawn Willden's avatar Shawn Willden
Browse files

Modify AttestationUtils to use public Keystore API

AttestationUtils calls directly into keystore1 to generate ID
attesations.  This needs to change prior to keystore2 being enabled
and keystore1 deleted.  This CL changes the AttestationUtils to use
the public API (and one SystemAPI method) to generate ID attestations,
allowing the lower layers to handle the transition between keystore1
and keystore2.

Test: CtsKeystoreTestCases
Change-Id: I64a230b9983cc90767a60d6e7cf2abcf5dfb0108
parent c7de4a23
Loading
Loading
Loading
Loading
+41 −12
Original line number Diff line number Diff line
@@ -23,7 +23,6 @@ import android.annotation.SystemApi;
import android.content.Context;
import android.content.res.Resources;
import android.os.Build;
import android.security.KeyStore;
import android.security.keymaster.KeymasterArguments;
import android.security.keymaster.KeymasterCertificateChain;
import android.security.keymaster.KeymasterDefs;
@@ -34,9 +33,14 @@ import android.util.ArraySet;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.nio.charset.StandardCharsets;
import java.security.KeyPairGenerator;
import java.security.KeyStore;
import java.security.SecureRandom;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.spec.ECGenParameterSpec;
import java.util.Collection;
import java.util.Random;
import java.util.Set;

/**
@@ -256,22 +260,47 @@ public abstract class AttestationUtils {
    @NonNull public static X509Certificate[] attestDeviceIds(Context context,
            @NonNull int[] idTypes, @NonNull byte[] attestationChallenge) throws
            DeviceIdAttestationException {
        final KeymasterArguments attestArgs = prepareAttestationArgumentsForDeviceId(
                context, idTypes, attestationChallenge);
        String keystoreAlias = generateRandomAlias();
        KeyGenParameterSpec.Builder builder =
                new KeyGenParameterSpec.Builder(keystoreAlias, KeyProperties.PURPOSE_SIGN)
                        .setAlgorithmParameterSpec(new ECGenParameterSpec("secp256r1"))
                        .setDigests(KeyProperties.DIGEST_SHA256)
                        .setAttestationChallenge(attestationChallenge);

        // Perform attestation.
        final KeymasterCertificateChain outChain = new KeymasterCertificateChain();
        final int errorCode = KeyStore.getInstance().attestDeviceIds(attestArgs, outChain);
        if (errorCode != KeyStore.NO_ERROR) {
            throw new DeviceIdAttestationException("Unable to perform attestation",
                    KeyStore.getKeyStoreException(errorCode));
        if (idTypes != null) {
            builder.setAttestationIds(idTypes);
            builder.setDevicePropertiesAttestationIncluded(true);
        }

        try {
            return parseCertificateChain(outChain);
        } catch (KeyAttestationException e) {
            throw new DeviceIdAttestationException(e.getMessage(), e);
            KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(
                    KeyProperties.KEY_ALGORITHM_EC, "AndroidKeyStore");
            keyPairGenerator.initialize(builder.build());
            keyPairGenerator.generateKeyPair();

            KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
            keyStore.load(null);

            X509Certificate[] certificateChain =
                    (X509Certificate[]) keyStore.getCertificateChain(keystoreAlias);

            keyStore.deleteEntry(keystoreAlias);

            return certificateChain;
        } catch (Exception e) {
            throw new DeviceIdAttestationException("Unable to perform attestation", e);
        }
    }

    private static String generateRandomAlias() {
        Random random = new SecureRandom();
        StringBuilder builder = new StringBuilder();
        // Pick random uppercase letters, A-Z.  20 of them gives us ~94 bits of entropy, which
        // should prevent any conflicts with app-selected aliases, even for very unlucky users.
        for (int i = 0; i < 20; ++i) {
            builder.append(random.nextInt(26) + 'A');
        }
        return builder.toString();
    }

    /**