summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTreehugger Robot <android-test-infra-autosubmit@system.gserviceaccount.com>2024-05-17 20:43:30 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2024-05-17 20:43:30 +0000
commitab80b933f51d662c2e811cb19ebaa9f60d31739a (patch)
tree95e5ed440f9e95ffa47bb3266b20c2cf86d6fdcc
parent6ccb9739db74be2e3ecd23f9b5af99e8fdd25c0f (diff)
parent2dfde193e378e97a953402c5e9bf40d75d65b26f (diff)
downloadcts-android14-tests-dev.tar.gz
Merge changes from topic "cherrypicker-L97700030003622837:N07800030057406848" into android14-tests-devandroid14-tests-dev
* changes: RESTRICT AUTOMERGE Updated KM-Version check against FEATURE_HARDWARE_KEYSTORE based on VSR API level. RESTRICT AUTOMERGE Updated the logic to determine the VSR API level for Keystore CTS tests. RESTRICT AUTOMERGE Skipping test on GSI + first_api_level < U
-rw-r--r--tests/tests/keystore/src/android/keystore/cts/DeviceOwnerKeyManagementTest.java126
-rw-r--r--tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java10
-rw-r--r--tests/tests/keystore/src/android/keystore/cts/util/TestUtils.java37
3 files changed, 159 insertions, 14 deletions
diff --git a/tests/tests/keystore/src/android/keystore/cts/DeviceOwnerKeyManagementTest.java b/tests/tests/keystore/src/android/keystore/cts/DeviceOwnerKeyManagementTest.java
index c57b7dde2d3..e5244005534 100644
--- a/tests/tests/keystore/src/android/keystore/cts/DeviceOwnerKeyManagementTest.java
+++ b/tests/tests/keystore/src/android/keystore/cts/DeviceOwnerKeyManagementTest.java
@@ -20,17 +20,35 @@ import static android.app.admin.DevicePolicyManager.ID_TYPE_BASE_INFO;
import static android.app.admin.DevicePolicyManager.ID_TYPE_IMEI;
import static android.app.admin.DevicePolicyManager.ID_TYPE_MEID;
import static android.app.admin.DevicePolicyManager.ID_TYPE_SERIAL;
+import static android.keystore.cts.Attestation.KM_SECURITY_LEVEL_SOFTWARE;
+import static android.keystore.cts.Attestation.KM_SECURITY_LEVEL_STRONG_BOX;
+import static android.keystore.cts.Attestation.KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT;
+import static android.keystore.cts.KeyAttestationTest.verifyCertificateChain;
+import static android.keystore.cts.RootOfTrust.KM_VERIFIED_BOOT_VERIFIED;
+import static android.security.keystore.KeyProperties.DIGEST_NONE;
+import static android.security.keystore.KeyProperties.DIGEST_SHA256;
+import static android.security.keystore.KeyProperties.DIGEST_SHA512;
+import static android.security.keystore.KeyProperties.KEY_ALGORITHM_EC;
+import static android.security.keystore.KeyProperties.PURPOSE_SIGN;
+
import static com.google.android.attestation.ParsedAttestationRecord.createParsedAttestationRecord;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.greaterThanOrEqualTo;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeFalse;
+
import android.app.admin.DevicePolicyManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.PackageManager;
import android.keystore.cts.util.TestUtils;
import android.os.Build;
-import android.os.SystemProperties;
import android.security.AttestedKeyPair;
import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.KeyProperties;
@@ -44,6 +62,7 @@ import com.android.bedstead.harrier.annotations.RequireFeature;
import com.android.bedstead.harrier.annotations.RequireRunOnSystemUser;
import com.android.bedstead.nene.TestApis;
import com.android.bedstead.nene.devicepolicy.DeviceOwner;
+import com.android.bedstead.nene.exceptions.NeneException;
import com.android.bedstead.nene.permissions.PermissionContext;
import com.android.compatibility.common.util.ApiTest;
@@ -56,12 +75,15 @@ import org.junit.Test;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.cert.Certificate;
import java.security.cert.CertificateParsingException;
import java.security.cert.X509Certificate;
+import java.security.spec.ECGenParameterSpec;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -120,10 +142,6 @@ public class DeviceOwnerKeyManagementTest {
signDataWithKey(algoIdentifier, keyPair.getPrivate()));
}
- int getDeviceFirstSdkLevel() {
- return SystemProperties.getInt("ro.board.first_api_level", 0);
- }
-
private void validateDeviceIdAttestationData(Certificate[] certs,
String expectedSerial,
String expectedImei,
@@ -200,7 +218,7 @@ public class DeviceOwnerKeyManagementTest {
TestUtils.getFeatureVersionKeystore(sContext, useStrongbox) >= 300;
final boolean emptySecondImei = TextUtils.isEmpty(expectedSecondImei);
final boolean deviceShippedWithKeyMint3 =
- getDeviceFirstSdkLevel() >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE;
+ TestUtils.getVendorApiLevel() >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE;
if (!isKeyMintV3) {
// Earlier versions of KeyMint must not attest to second IMEI values as they are not
@@ -510,6 +528,68 @@ public class DeviceOwnerKeyManagementTest {
}
}
+ private boolean checkRootOfTrustForLockedDevice(Attestation attestation) {
+ RootOfTrust rootOfTrust = attestation.getRootOfTrust();
+ assertNotNull(rootOfTrust);
+ assertNotNull(rootOfTrust.getVerifiedBootKey());
+ assertTrue("Verified boot key is only " + rootOfTrust.getVerifiedBootKey().length
+ + " bytes long", rootOfTrust.getVerifiedBootKey().length >= 32);
+ return (rootOfTrust.isDeviceLocked()
+ && (rootOfTrust.getVerifiedBootState() == KM_VERIFIED_BOOT_VERIFIED));
+ }
+
+ private boolean isDeviceLockedAccordingToAttestation(Attestation attestation) {
+ assertThat("Attestation version must be >= 1",
+ attestation.getAttestationVersion(), greaterThanOrEqualTo(1));
+
+ int attestationSecurityLevel = attestation.getAttestationSecurityLevel();
+ switch (attestationSecurityLevel) {
+ case KM_SECURITY_LEVEL_STRONG_BOX:
+ case KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT:
+ assertThat("Attestation security level doesn't match keymaster security level",
+ attestation.getKeymasterSecurityLevel(), is(attestationSecurityLevel));
+ assertThat("Keymaster version should be greater than or equal to 2.",
+ attestation.getKeymasterVersion(), greaterThanOrEqualTo(2));
+
+ return checkRootOfTrustForLockedDevice(attestation);
+ case KM_SECURITY_LEVEL_SOFTWARE:
+ default:
+ // TEE attestation has been required since Android 7.0.
+ fail("Unexpected attestation security level: "
+ + attestation.securityLevelToString(attestationSecurityLevel));
+ break;
+ }
+ return false;
+ }
+
+ private boolean checkDeviceLocked() throws Exception {
+ String keystoreAlias = "check_device_state";
+ KeyGenParameterSpec.Builder builder =
+ new KeyGenParameterSpec.Builder(keystoreAlias, PURPOSE_SIGN)
+ .setAlgorithmParameterSpec(new ECGenParameterSpec("secp256r1"))
+ .setAttestationChallenge(new byte[128])
+ .setDigests(DIGEST_NONE, DIGEST_SHA256, DIGEST_SHA512);
+
+ KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_ALGORITHM_EC,
+ "AndroidKeyStore");
+ keyPairGenerator.initialize(builder.build());
+ keyPairGenerator.generateKeyPair();
+ KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
+ keyStore.load(null);
+
+ try {
+ Certificate []certificates = keyStore.getCertificateChain(keystoreAlias);
+ verifyCertificateChain(certificates, false);
+
+ X509Certificate attestationCert = (X509Certificate) certificates[0];
+
+ return isDeviceLockedAccordingToAttestation(
+ Attestation.loadFromCertificate(attestationCert));
+ } finally {
+ keyStore.deleteEntry(keystoreAlias);
+ }
+ }
+
@Test
@ApiTest(apis = {"android.app.admin.DevicePolicyManager#generateKeyPair",
"android.app.admin.DevicePolicyManager#ID_TYPE_IMEI",
@@ -519,8 +599,25 @@ public class DeviceOwnerKeyManagementTest {
@RequireFeature(PackageManager.FEATURE_DEVICE_ADMIN)
@RequireFeature(PackageManager.FEATURE_DEVICE_ID_ATTESTATION)
public void testAllVariationsOfDeviceIdAttestation() throws Exception {
+ // b/298586194, there are some devices launched with Android T, and they will be receiving
+ // only system update and not vendor update, newly added attestation properties
+ // (ro.product.*_for_attestation) reading logic would not be available for such devices
+ // hence skipping this test for such scenario.
+ assumeFalse("This test is not applicable for device running GSI image and"
+ + " first_api_level < 14", TestUtils.isGsiImage()
+ && TestUtils.getVendorApiLevel() < Build.VERSION_CODES.UPSIDE_DOWN_CAKE);
+
+ final boolean isDeviceLocked = checkDeviceLocked();
try (DeviceOwner o = TestApis.devicePolicy().setDeviceOwner(DEVICE_ADMIN_COMPONENT_NAME)) {
assertAllVariantsOfDeviceIdAttestation(false /* useStrongBox */);
+ } catch (NeneException e) {
+ // b/291069162, some devices do not allow to set DeviceOwner in an unlocked state. And
+ // unlocked state is allowed while testing on GSI image. If this condition not match
+ // throw the exception.
+ assumeFalse("It is acceptable to fail setting DeviceOwner on GSI build running on"
+ + " unlocked devices.", (e.getMessage().contains("Error setting device owner")
+ && TestUtils.isGsiImage() && !isDeviceLocked));
+ throw new Exception(e);
}
}
@@ -533,8 +630,25 @@ public class DeviceOwnerKeyManagementTest {
@RequireFeature(PackageManager.FEATURE_DEVICE_ADMIN)
@RequireFeature(PackageManager.FEATURE_DEVICE_ID_ATTESTATION)
public void testAllVariationsOfDeviceIdAttestationUsingStrongBox() throws Exception {
+ // b/298586194, there are some devices launched with Android T, and they will be receiving
+ // only system update and not vendor update, newly added attestation properties
+ // (ro.product.*_for_attestation) reading logic would not be available for such devices
+ // hence skipping this test for such scenario.
+ assumeFalse("This test is not applicable for device running GSI image and"
+ + " first_api_level < 14", TestUtils.isGsiImage()
+ && TestUtils.getVendorApiLevel() < Build.VERSION_CODES.UPSIDE_DOWN_CAKE);
+
+ final boolean isDeviceLocked = checkDeviceLocked();
try (DeviceOwner o = TestApis.devicePolicy().setDeviceOwner(DEVICE_ADMIN_COMPONENT_NAME)) {
assertAllVariantsOfDeviceIdAttestation(true /* useStrongBox */);
+ } catch (NeneException e) {
+ // b/291069162, some devices do not allow to set DeviceOwner in an unlocked state. And
+ // unlocked state is allowed while testing on GSI image. If this condition not match
+ // throw the exception.
+ assumeFalse("It is acceptable to fail setting DeviceOwner on GSI build running on"
+ + " unlocked devices.", (e.getMessage().contains("Error setting device owner")
+ && TestUtils.isGsiImage() && !isDeviceLocked));
+ throw new Exception(e);
}
}
diff --git a/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java b/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
index 5135c9f5ab1..80fa6385e1f 100644
--- a/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
+++ b/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
@@ -94,7 +94,6 @@ import org.bouncycastle.cert.jcajce.JcaX509CertificateHolder;
import org.junit.Test;
import org.junit.runner.RunWith;
-import java.io.File;
import java.security.GeneralSecurityException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
@@ -420,7 +419,7 @@ public class KeyAttestationTest {
// Feature Version is required on devices launching with Android 12 (API Level
// 31) but may be reported on devices launching with an earlier version. If it's
// present, it must match what is reported in attestation.
- if (PropertyUtil.getFirstApiLevel() >= 31) {
+ if (TestUtils.getVendorApiLevel() >= 31) {
assertNotEquals(0, keyStoreFeatureVersion);
}
if (keyStoreFeatureVersion != 0) {
@@ -1276,13 +1275,8 @@ public class KeyAttestationTest {
return expectedPurposes;
}
- private boolean isGsiImage() {
- final File initGsiRc= new File("/system/system_ext/etc/init/init.gsi.rc");
- return initGsiRc.exists();
- }
-
private void checkSystemPatchLevel(int teeOsPatchLevel, int systemPatchLevel) {
- if (isGsiImage()) {
+ if (TestUtils.isGsiImage()) {
// b/168663786: When using a GSI image, the system patch level might be
// greater than or equal to the OS patch level reported from TEE.
assertThat("For GSI image TEE os patch level should be less than or equal to system"
diff --git a/tests/tests/keystore/src/android/keystore/cts/util/TestUtils.java b/tests/tests/keystore/src/android/keystore/cts/util/TestUtils.java
index 890ab61b4d7..1b928500084 100644
--- a/tests/tests/keystore/src/android/keystore/cts/util/TestUtils.java
+++ b/tests/tests/keystore/src/android/keystore/cts/util/TestUtils.java
@@ -42,6 +42,7 @@ import com.android.internal.util.HexDump;
import org.junit.Assert;
import java.io.ByteArrayOutputStream;
+import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigInteger;
@@ -207,6 +208,33 @@ public class TestUtils {
}
/**
+ * Returns VSR API level.
+ */
+ public static int getVendorApiLevel() {
+ int vendorApiLevel = SystemProperties.getInt("ro.vendor.api_level", -1);
+ if (vendorApiLevel != -1) {
+ return vendorApiLevel;
+ }
+
+ // Android S and older devices do not define ro.vendor.api_level
+ vendorApiLevel = SystemProperties.getInt("ro.board.api_level", -1);
+ if (vendorApiLevel == -1) {
+ vendorApiLevel = SystemProperties.getInt("ro.board.first_api_level", -1);
+ }
+
+ int productApiLevel = SystemProperties.getInt("ro.product.first_api_level", -1);
+ if (productApiLevel == -1) {
+ productApiLevel = Build.VERSION.SDK_INT;
+ }
+
+ // VSR API level is the minimum of vendorApiLevel and productApiLevel.
+ if (vendorApiLevel == -1 || vendorApiLevel > productApiLevel) {
+ return productApiLevel;
+ }
+ return vendorApiLevel;
+ }
+
+ /**
* Returns whether the device has a StrongBox backed KeyStore.
*/
public static boolean hasStrongBox(Context context) {
@@ -1182,4 +1210,13 @@ public class TestUtils {
PackageManager pm = context.getPackageManager();
return (pm != null && pm.hasSystemFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN));
}
+
+ /**
+ * Determines whether running build is GSI or not.
+ * @return true if running build is GSI, false otherwise.
+ */
+ public static boolean isGsiImage() {
+ final File initGsiRc = new File("/system/system_ext/etc/init/init.gsi.rc");
+ return initGsiRc.exists();
+ }
}