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

Commit 7a46c3c1 authored by Janis Danisevskis's avatar Janis Danisevskis Committed by Gerrit Code Review
Browse files

Merge "Modify AttestationUtils to use public Keystore API"

parents 6c165b2d 0306b1ce
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();
    }

    /**