Merge "Refactor collector to improve readability." into main
diff --git a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/KeystoreAttestationDeviceInfo.java b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/KeystoreAttestationDeviceInfo.java
index f3b5506..ed20899 100644
--- a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/KeystoreAttestationDeviceInfo.java
+++ b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/KeystoreAttestationDeviceInfo.java
@@ -18,192 +18,144 @@
 import static android.security.keystore.KeyProperties.DIGEST_SHA256;
 import static android.security.keystore.KeyProperties.KEY_ALGORITHM_EC;
 import static android.security.keystore.KeyProperties.PURPOSE_SIGN;
-import static android.security.keystore.KeyProperties.PURPOSE_VERIFY;
 
 import static com.android.bedstead.nene.packages.CommonPackages.FEATURE_DEVICE_ID_ATTESTATION;
 
 import static com.google.android.attestation.ParsedAttestationRecord.createParsedAttestationRecord;
 
 import android.content.pm.PackageManager;
-import android.security.keystore.DeviceIdAttestationException;
 import android.security.keystore.KeyGenParameterSpec;
-import android.util.Log;
 
 import com.android.compatibility.common.util.DeviceInfoStore;
 
 import com.google.android.attestation.AuthorizationList;
-import com.google.android.attestation.ParsedAttestationRecord;
 import com.google.android.attestation.RootOfTrust;
 
-import java.io.IOException;
-import java.security.InvalidAlgorithmParameterException;
 import java.security.KeyPair;
 import java.security.KeyPairGenerator;
 import java.security.KeyStore;
-import java.security.NoSuchAlgorithmException;
-import java.security.NoSuchProviderException;
 import java.security.cert.Certificate;
 import java.security.cert.X509Certificate;
 import java.security.spec.ECGenParameterSpec;
 import java.util.ArrayList;
 import java.util.List;
-import java.util.Objects;
 
 /**
- * Feature Keystore Attestation device info collector. Collector collects information from the
- * device's KeyMint implementation as reflected by the data in the key attestation record. These
- * will be collected across devices and do not collect and PII outside of the device information.
+ * Key attestation collector. Collects a subset of the information attested by the device's
+ * trusted execution environment (TEE) and by its StrongBox chip (if it has one).
  */
 public final class KeystoreAttestationDeviceInfo extends DeviceInfo {
-    private static final String LOG_TAG = "KeystoreAttestationDeviceInfo";
-    private static final String TEST_ALIAS_KEYSTORE = "testKeystore";
-    private static final String TEST_ALIAS_STRONG_BOX = "testStrongBox";
-    private static final byte[] CHALLENGE = "challenge".getBytes();
+    private static final String TEST_ALIAS_TEE = "testTeeKeyAlias";
+    private static final String TEST_ALIAS_STRONGBOX = "testStrongBoxKeyAlias";
+    private static final byte[] TEST_CHALLENGE = "challenge".getBytes();
 
     @Override
     protected void collectDeviceInfo(DeviceInfoStore store) throws Exception {
-        collectKeystoreAttestation(store);
+        collectAttestation(
+                store, "keymint_key_attestation", TEST_ALIAS_TEE,
+                /* strongBoxBacked= */ false);
         if (getContext()
                 .getPackageManager()
                 .hasSystemFeature(PackageManager.FEATURE_STRONGBOX_KEYSTORE)) {
-            collectStrongBoxAttestation(store);
+            collectAttestation(
+                    store, "strong_box_key_attestation",
+                    TEST_ALIAS_STRONGBOX, /* strongBoxBacked= */ true);
         }
     }
 
-    private void generateKeyPair(String algorithm, KeyGenParameterSpec spec)
-            throws NoSuchAlgorithmException,
-            NoSuchProviderException,
-            InvalidAlgorithmParameterException {
-        KeyPairGenerator keyPairGenerator =
-                KeyPairGenerator.getInstance(algorithm, "AndroidKeyStore");
-        keyPairGenerator.initialize(spec);
-        KeyPair kp = keyPairGenerator.generateKeyPair();
-
-        if (kp == null) {
-            Log.e(LOG_TAG, "Key generation failed");
-            return;
-        }
-    }
-
-    private void collectKeystoreAttestation(DeviceInfoStore localStore) throws Exception {
-        KeyStore mKeyStore = KeyStore.getInstance("AndroidKeyStore");
-        mKeyStore.load(null);
-        mKeyStore.deleteEntry(TEST_ALIAS_KEYSTORE);
-
-        localStore.startGroup("keymint_key_attestation");
-        loadCertAndCollectAttestation(mKeyStore, localStore, TEST_ALIAS_KEYSTORE, false);
-        localStore.endGroup();
-    }
-
-    private void collectStrongBoxAttestation(DeviceInfoStore localStore) throws Exception {
-        KeyStore mKeyStore = KeyStore.getInstance("AndroidKeyStore");
-        mKeyStore.load(null);
-        mKeyStore.deleteEntry(TEST_ALIAS_STRONG_BOX);
-
-        localStore.startGroup("strong_box_key_attestation");
-        loadCertAndCollectAttestation(mKeyStore, localStore, TEST_ALIAS_STRONG_BOX, true);
-        localStore.endGroup();
-    }
-
-    private void loadCertAndCollectAttestation(
-            KeyStore keystore,
-            DeviceInfoStore localStore,
-            String testAlias,
-            boolean isStrongBoxBacked)
+    private void collectAttestation(
+            DeviceInfoStore store,
+            String resultGroupName,
+            String keyAlias,
+            boolean strongBoxBacked)
             throws Exception {
-        Objects.requireNonNull(keystore);
+        KeyStore mKeyStore = KeyStore.getInstance("AndroidKeyStore");
+        mKeyStore.load(null);
+
+        // If this collector ran on this device before, there might already be a key
+        // with this alias, so delete it before trying to generate a fresh key with
+        // the same alias.
+        mKeyStore.deleteEntry(keyAlias);
+
         KeyGenParameterSpec spec =
-                new KeyGenParameterSpec.Builder(testAlias, PURPOSE_SIGN | PURPOSE_VERIFY)
+                new KeyGenParameterSpec.Builder(keyAlias, PURPOSE_SIGN)
                         .setAlgorithmParameterSpec(new ECGenParameterSpec("secp256r1"))
                         .setDigests(DIGEST_SHA256)
                         .setDevicePropertiesAttestationIncluded(
                                 getContext()
                                         .getPackageManager()
                                         .hasSystemFeature(FEATURE_DEVICE_ID_ATTESTATION))
-                        .setAttestationChallenge(CHALLENGE)
-                        .setIsStrongBoxBacked(isStrongBoxBacked)
+                        .setAttestationChallenge(TEST_CHALLENGE)
+                        .setIsStrongBoxBacked(strongBoxBacked)
                         .build();
 
-        generateKeyPair(KEY_ALGORITHM_EC, spec);
+        KeyPairGenerator keyPairGenerator =
+                KeyPairGenerator.getInstance(KEY_ALGORITHM_EC, "AndroidKeyStore");
+        keyPairGenerator.initialize(spec);
+        KeyPair kp = keyPairGenerator.generateKeyPair();
 
-        Certificate[] certificates = keystore.getCertificateChain(testAlias);
-        assertTrue(certificates.length >= 1);
-
-        final AuthorizationList keyDetailsList;
-
-        /* convert Certificate to List of X509Certificate */
         List<X509Certificate> x509Certificates = new ArrayList<>();
-        for (Certificate certificate : certificates) {
+        for (Certificate certificate : mKeyStore.getCertificateChain(keyAlias)) {
             if (certificate instanceof X509Certificate) {
                 x509Certificates.add((X509Certificate) certificate);
             }
         }
-        assertTrue(x509Certificates.size() >= 1);
+        assertTrue(!x509Certificates.isEmpty());
 
-        ParsedAttestationRecord parsedAttestationRecord =
-                createParsedAttestationRecord(x509Certificates);
+        AuthorizationList authorizationList = createParsedAttestationRecord(
+                x509Certificates).teeEnforced;
 
-        keyDetailsList = parsedAttestationRecord.teeEnforced;
-
-        collectStoredInformation(localStore, keyDetailsList);
-    }
-
-    private static void collectStoredInformation(
-            DeviceInfoStore localStore, AuthorizationList keyDetailsList)
-            throws DeviceIdAttestationException, IOException {
-        if (keyDetailsList.osVersion.isPresent()) {
-            localStore.addResult("os_version", keyDetailsList.osVersion.get());
+        store.startGroup(resultGroupName);
+        if (authorizationList.osVersion.isPresent()) {
+            store.addResult("os_version", authorizationList.osVersion.get());
         }
-        if (keyDetailsList.osPatchLevel.isPresent()) {
-            localStore.addResult("os_patch_level", keyDetailsList.osPatchLevel.get());
+        if (authorizationList.osPatchLevel.isPresent()) {
+            store.addResult("os_patch_level", authorizationList.osPatchLevel.get());
         }
-        if (keyDetailsList.attestationIdBrand.isPresent()) {
-            localStore.addBytesResult(
+        if (authorizationList.attestationIdBrand.isPresent()) {
+            store.addBytesResult(
                     "attestation_id_brand",
-                    keyDetailsList.attestationIdBrand.get());
+                    authorizationList.attestationIdBrand.get());
         }
-        if (keyDetailsList.attestationIdDevice.isPresent()) {
-            localStore.addBytesResult(
+        if (authorizationList.attestationIdDevice.isPresent()) {
+            store.addBytesResult(
                     "attestation_id_device",
-                    keyDetailsList.attestationIdDevice.get());
+                    authorizationList.attestationIdDevice.get());
         }
-        if (keyDetailsList.attestationIdProduct.isPresent()) {
-            localStore.addBytesResult(
+        if (authorizationList.attestationIdProduct.isPresent()) {
+            store.addBytesResult(
                     "attestation_id_product",
-                    keyDetailsList.attestationIdProduct.get());
+                    authorizationList.attestationIdProduct.get());
         }
-        if (keyDetailsList.attestationIdManufacturer.isPresent()) {
-            localStore.addBytesResult(
+        if (authorizationList.attestationIdManufacturer.isPresent()) {
+            store.addBytesResult(
                     "attestation_id_manufacturer",
-                    keyDetailsList.attestationIdManufacturer.get());
+                    authorizationList.attestationIdManufacturer.get());
         }
-        if (keyDetailsList.attestationIdModel.isPresent()) {
-            localStore.addBytesResult(
+        if (authorizationList.attestationIdModel.isPresent()) {
+            store.addBytesResult(
                     "attestation_id_model",
-                    keyDetailsList.attestationIdModel.get());
+                    authorizationList.attestationIdModel.get());
         }
-        if (keyDetailsList.vendorPatchLevel.isPresent()) {
-            localStore.addResult("vendor_patch_level", keyDetailsList.vendorPatchLevel.get());
+        if (authorizationList.vendorPatchLevel.isPresent()) {
+            store.addResult("vendor_patch_level", authorizationList.vendorPatchLevel.get());
         }
-        if (keyDetailsList.bootPatchLevel.isPresent()) {
-            localStore.addResult("boot_patch_level", keyDetailsList.bootPatchLevel.get());
+        if (authorizationList.bootPatchLevel.isPresent()) {
+            store.addResult("boot_patch_level", authorizationList.bootPatchLevel.get());
         }
-        if (keyDetailsList.rootOfTrust.isPresent()) {
-            collectRootOfTrust(keyDetailsList.rootOfTrust.get(), localStore);
+        if (authorizationList.rootOfTrust.isPresent()) {
+            RootOfTrust rootOfTrust = authorizationList.rootOfTrust.get();
+            store.startGroup("root_of_trust");
+            store.addBytesResult(
+                    "verified_boot_key",
+                    rootOfTrust.verifiedBootKey);
+            store.addResult("device_locked", rootOfTrust.deviceLocked);
+            store.addResult("verified_boot_state", rootOfTrust.verifiedBootState.name());
+            store.addBytesResult(
+                    "verified_boot_hash",
+                    rootOfTrust.verifiedBootHash);
+            store.endGroup();
         }
-    }
-
-    private static void collectRootOfTrust(
-            RootOfTrust rootOfTrust, DeviceInfoStore localStore) throws IOException {
-        localStore.startGroup("root_of_trust");
-        localStore.addBytesResult(
-                "verified_boot_key",
-                rootOfTrust.verifiedBootKey);
-        localStore.addResult("device_locked", rootOfTrust.deviceLocked);
-        localStore.addResult("verified_boot_state", rootOfTrust.verifiedBootState.name());
-        localStore.addBytesResult(
-                "verified_boot_hash",
-                rootOfTrust.verifiedBootHash);
-        localStore.endGroup();
+        store.endGroup();
     }
 }