1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.keystore.cts; 18 19 import static android.keystore.cts.Attestation.KM_SECURITY_LEVEL_SOFTWARE; 20 import static android.keystore.cts.Attestation.KM_SECURITY_LEVEL_STRONG_BOX; 21 import static android.keystore.cts.Attestation.KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT; 22 import static android.keystore.cts.AuthorizationList.KM_ALGORITHM_EC; 23 import static android.keystore.cts.AuthorizationList.KM_ALGORITHM_RSA; 24 import static android.keystore.cts.AuthorizationList.KM_DIGEST_NONE; 25 import static android.keystore.cts.AuthorizationList.KM_DIGEST_SHA_2_256; 26 import static android.keystore.cts.AuthorizationList.KM_DIGEST_SHA_2_512; 27 import static android.keystore.cts.AuthorizationList.KM_ORIGIN_GENERATED; 28 import static android.keystore.cts.AuthorizationList.KM_ORIGIN_UNKNOWN; 29 import static android.keystore.cts.AuthorizationList.KM_PURPOSE_DECRYPT; 30 import static android.keystore.cts.AuthorizationList.KM_PURPOSE_ENCRYPT; 31 import static android.keystore.cts.AuthorizationList.KM_PURPOSE_SIGN; 32 import static android.keystore.cts.AuthorizationList.KM_PURPOSE_VERIFY; 33 import static android.keystore.cts.RootOfTrust.KM_VERIFIED_BOOT_VERIFIED; 34 import static android.security.keymaster.KeymasterDefs.KM_PURPOSE_AGREE_KEY; 35 import static android.security.keystore.KeyProperties.DIGEST_SHA256; 36 import static android.security.keystore.KeyProperties.ENCRYPTION_PADDING_NONE; 37 import static android.security.keystore.KeyProperties.ENCRYPTION_PADDING_RSA_OAEP; 38 import static android.security.keystore.KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1; 39 import static android.security.keystore.KeyProperties.KEY_ALGORITHM_EC; 40 import static android.security.keystore.KeyProperties.KEY_ALGORITHM_RSA; 41 import static android.security.keystore.KeyProperties.PURPOSE_AGREE_KEY; 42 import static android.security.keystore.KeyProperties.PURPOSE_DECRYPT; 43 import static android.security.keystore.KeyProperties.PURPOSE_ENCRYPT; 44 import static android.security.keystore.KeyProperties.PURPOSE_SIGN; 45 import static android.security.keystore.KeyProperties.PURPOSE_VERIFY; 46 import static android.security.keystore.KeyProperties.SIGNATURE_PADDING_RSA_PKCS1; 47 import static android.security.keystore.KeyProperties.SIGNATURE_PADDING_RSA_PSS; 48 49 import static com.google.common.truth.Truth.assertThat; 50 51 import static org.hamcrest.CoreMatchers.is; 52 import static org.hamcrest.MatcherAssert.assertThat; 53 import static org.hamcrest.Matchers.either; 54 import static org.hamcrest.Matchers.empty; 55 import static org.hamcrest.Matchers.greaterThanOrEqualTo; 56 import static org.hamcrest.Matchers.hasItems; 57 import static org.hamcrest.Matchers.lessThanOrEqualTo; 58 import static org.junit.Assert.assertArrayEquals; 59 import static org.junit.Assert.assertEquals; 60 import static org.junit.Assert.assertFalse; 61 import static org.junit.Assert.assertNotEquals; 62 import static org.junit.Assert.assertNotNull; 63 import static org.junit.Assert.assertNull; 64 import static org.junit.Assert.assertTrue; 65 import static org.junit.Assert.fail; 66 import static org.junit.Assume.assumeTrue; 67 68 import android.content.Context; 69 import android.content.pm.PackageManager; 70 import android.content.pm.PackageManager.NameNotFoundException; 71 import android.keystore.cts.util.TestUtils; 72 import android.os.Build; 73 import android.os.SystemProperties; 74 import android.platform.test.annotations.RestrictedBuildTest; 75 import android.security.KeyStoreException; 76 import android.security.keystore.AttestationUtils; 77 import android.security.keystore.DeviceIdAttestationException; 78 import android.security.keystore.KeyGenParameterSpec; 79 import android.security.keystore.KeyProperties; 80 import android.util.ArraySet; 81 import android.util.Log; 82 83 import androidx.test.InstrumentationRegistry; 84 import androidx.test.filters.RequiresDevice; 85 import androidx.test.runner.AndroidJUnit4; 86 87 import com.android.bedstead.nene.TestApis; 88 import com.android.bedstead.permissions.PermissionContext; 89 import com.android.compatibility.common.util.CddTest; 90 import com.android.compatibility.common.util.PropertyUtil; 91 92 import com.google.common.collect.ImmutableSet; 93 94 import org.bouncycastle.asn1.x500.X500Name; 95 import org.bouncycastle.cert.jcajce.JcaX509CertificateHolder; 96 import org.junit.Test; 97 import org.junit.runner.RunWith; 98 99 import java.security.GeneralSecurityException; 100 import java.security.InvalidAlgorithmParameterException; 101 import java.security.InvalidKeyException; 102 import java.security.KeyPairGenerator; 103 import java.security.KeyStore; 104 import java.security.NoSuchAlgorithmException; 105 import java.security.NoSuchProviderException; 106 import java.security.ProviderException; 107 import java.security.PublicKey; 108 import java.security.SignatureException; 109 import java.security.cert.Certificate; 110 import java.security.cert.CertificateException; 111 import java.security.cert.CertificateParsingException; 112 import java.security.cert.X509Certificate; 113 import java.security.spec.ECGenParameterSpec; 114 import java.util.ArrayList; 115 import java.util.Arrays; 116 import java.util.Date; 117 import java.util.HashSet; 118 import java.util.List; 119 import java.util.Set; 120 import java.util.regex.Matcher; 121 import java.util.regex.Pattern; 122 123 import javax.crypto.KeyGenerator; 124 125 /** 126 * Tests for Android Keystore attestation. 127 */ 128 @RunWith(AndroidJUnit4.class) 129 public class KeyAttestationTest { 130 131 private static final String TAG = AndroidKeyStoreTest.class.getSimpleName(); 132 133 private static final int ORIGINATION_TIME_OFFSET = 1000000; 134 private static final int CONSUMPTION_TIME_OFFSET = 2000000; 135 136 private static final int KEY_USAGE_BITSTRING_LENGTH = 9; 137 private static final int KEY_USAGE_DIGITAL_SIGNATURE_BIT_OFFSET = 0; 138 private static final int KEY_USAGE_KEY_ENCIPHERMENT_BIT_OFFSET = 2; 139 private static final int KEY_USAGE_DATA_ENCIPHERMENT_BIT_OFFSET = 3; 140 private static final int KEY_USAGE_KEY_AGREE_BIT_OFFSET = 4; 141 142 private static final int OS_MAJOR_VERSION_MATCH_GROUP_NAME = 1; 143 private static final int OS_MINOR_VERSION_MATCH_GROUP_NAME = 2; 144 private static final int OS_SUBMINOR_VERSION_MATCH_GROUP_NAME = 3; 145 private static final Pattern OS_VERSION_STRING_PATTERN = Pattern 146 .compile("([0-9]{1,2})(?:\\.([0-9]{1,2}))?(?:\\.([0-9]{1,2}))?(?:[^0-9.]+.*)?"); 147 148 private static final int OS_PATCH_LEVEL_YEAR_GROUP_NAME = 1; 149 private static final int OS_PATCH_LEVEL_MONTH_GROUP_NAME = 2; 150 private static final Pattern OS_PATCH_LEVEL_STRING_PATTERN = Pattern 151 .compile("([0-9]{4})-([0-9]{2})-[0-9]{2}"); 152 153 private static final int KM_ERROR_CANNOT_ATTEST_IDS = -66; 154 private static final int KM_ERROR_INVALID_INPUT_LENGTH = -21; 155 private static final int KM_ERROR_UNKNOWN_ERROR = -1000; 156 private static final int KM_ERROR_PERMISSION_DENIED = 6; 157 getContext()158 private Context getContext() { 159 return InstrumentationRegistry.getInstrumentation().getTargetContext(); 160 } 161 162 @Test testVersionParser()163 public void testVersionParser() throws Exception { 164 // Non-numerics/empty give version 0 165 assertEquals(0, parseSystemOsVersion("")); 166 assertEquals(0, parseSystemOsVersion("N")); 167 168 // Should support one, two or three version number values. 169 assertEquals(10000, parseSystemOsVersion("1")); 170 assertEquals(10200, parseSystemOsVersion("1.2")); 171 assertEquals(10203, parseSystemOsVersion("1.2.3")); 172 173 // It's fine to append other stuff to the dotted numeric version. 174 assertEquals(10000, parseSystemOsVersion("1stuff")); 175 assertEquals(10200, parseSystemOsVersion("1.2garbage.32")); 176 assertEquals(10203, parseSystemOsVersion("1.2.3-stuff")); 177 178 // Two digits per version field are supported 179 assertEquals(152536, parseSystemOsVersion("15.25.36")); 180 assertEquals(999999, parseSystemOsVersion("99.99.99")); 181 assertEquals(0, parseSystemOsVersion("100.99.99")); 182 assertEquals(0, parseSystemOsVersion("99.100.99")); 183 assertEquals(0, parseSystemOsVersion("99.99.100")); 184 } 185 186 @RequiresDevice 187 @Test testEcAttestation()188 public void testEcAttestation() throws Exception { 189 testEcAttestation(false); 190 } 191 192 @RequiresDevice 193 @Test testEcAttestation_StrongBox()194 public void testEcAttestation_StrongBox() throws Exception { 195 assumeTrue("This test is only applicable to devices with StrongBox", 196 TestUtils.hasStrongBox(getContext())); 197 198 testEcAttestation(true); 199 } 200 testEcAttestation(boolean isStrongBox)201 private void testEcAttestation(boolean isStrongBox) throws Exception { 202 if (!TestUtils.isAttestationSupported()) { 203 return; 204 } 205 206 if (getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_PC)) 207 return; 208 209 final int[] purposes = { 210 KM_PURPOSE_SIGN, KM_PURPOSE_VERIFY, KM_PURPOSE_SIGN | KM_PURPOSE_VERIFY 211 }; 212 final boolean[] devicePropertiesAttestationValues = {true, false}; 213 final boolean[] includeValidityDatesValues = {true, false}; 214 final String[] curves; 215 final int[] keySizes; 216 final byte[][] challenges; 217 218 if (isStrongBox) { 219 // StrongBox only supports secp256r1 keys. 220 curves = new String[] {"secp256r1"}; 221 keySizes = new int[] {256}; 222 challenges = new byte[][] { 223 // Empty challange is not accepted by StrongBox. 224 "challenge".getBytes(), // short challenge 225 new byte[128], // long challenge 226 }; 227 } else { 228 curves = new String[] { 229 "secp224r1", "secp256r1", "secp384r1", "secp521r1" 230 }; 231 keySizes = new int[]{ 232 224, 256, 384, 521 233 }; 234 challenges = new byte[][]{ 235 new byte[0], // empty challenge 236 "challenge".getBytes(), // short challenge 237 new byte[128], // long challenge 238 }; 239 } 240 241 for (int curveIndex = 0; curveIndex < curves.length; ++curveIndex) { 242 for (int challengeIndex = 0; challengeIndex < challenges.length; ++challengeIndex) { 243 for (int purposeIndex = 0; purposeIndex < purposes.length; ++purposeIndex) { 244 for (boolean includeValidityDates : includeValidityDatesValues) { 245 for (boolean devicePropertiesAttestation : devicePropertiesAttestationValues) { 246 try { 247 testEcAttestation(challenges[challengeIndex], includeValidityDates, 248 curves[curveIndex], keySizes[curveIndex], 249 purposes[purposeIndex], devicePropertiesAttestation, 250 isStrongBox); 251 } catch (Throwable e) { 252 boolean isIdAttestationFailure = 253 (e.getCause() instanceof KeyStoreException) 254 && KeyStoreException.ERROR_ID_ATTESTATION_FAILURE 255 == ((KeyStoreException) e.getCause()).getNumericErrorCode(); 256 if (devicePropertiesAttestation && isIdAttestationFailure) { 257 if (getContext().getPackageManager().hasSystemFeature( 258 PackageManager.FEATURE_DEVICE_ID_ATTESTATION)) { 259 throw new Exception("Unexpected failure while generating" 260 + " key.\nIn case of AOSP/GSI builds, system " 261 + "provided properties could be different from " 262 + "provisioned properties in KeyMaster/KeyMint. " 263 + "In such cases, make sure attestation specific " 264 + "properties (Build.*_FOR_ATTESTATION) are " 265 + "configured correctly.", e); 266 } else { 267 Log.i(TAG, "key attestation with device IDs not supported;" 268 + " test skipped"); 269 continue; 270 } 271 } 272 throw new Exception("Failed on curve " + curveIndex + 273 " challenge " + challengeIndex + " purpose " + 274 purposeIndex + " includeValidityDates " + 275 includeValidityDates + " and devicePropertiesAttestation " + 276 devicePropertiesAttestation, e); 277 } 278 } 279 } 280 } 281 } 282 } 283 } 284 assertAttestationKeyMintError(KeyStoreException keyStoreException, boolean devicePropertiesAttestation)285 private void assertAttestationKeyMintError(KeyStoreException keyStoreException, 286 boolean devicePropertiesAttestation) { 287 int errorCode = keyStoreException.getErrorCode(); 288 List<Integer> expectedErrs = new ArrayList<Integer>(); 289 expectedErrs.add(KM_ERROR_INVALID_INPUT_LENGTH); 290 if (devicePropertiesAttestation) { 291 expectedErrs.add(KM_ERROR_CANNOT_ATTEST_IDS); 292 } 293 if (TestUtils.getVendorApiLevel() < 35) { 294 // b/337427860, some devices returns UNKNOWN_ERROR if large challenge is 295 // passed. So allow an extra error code for earlier devices. 296 expectedErrs.add(KM_ERROR_UNKNOWN_ERROR); 297 } 298 String assertMessage = String.format( 299 "The KeyMint implementation may only return INVALID_INPUT_LENGTH or " 300 + "CANNOT_ATTEST_IDSs as errors when the attestation challenge is " 301 + "too large (error code was %d, attestation properties %b)", 302 errorCode, devicePropertiesAttestation); 303 assertTrue(assertMessage, expectedErrs.contains(errorCode)); 304 } 305 assertPublicAttestationError(KeyStoreException keyStoreException, boolean devicePropertiesAttestation)306 private void assertPublicAttestationError(KeyStoreException keyStoreException, 307 boolean devicePropertiesAttestation) { 308 // Assert public failure information. 309 int errorCode = keyStoreException.getNumericErrorCode(); 310 List<Integer> expectedErrs = new ArrayList<Integer>(); 311 expectedErrs.add(KeyStoreException.ERROR_INCORRECT_USAGE); 312 if (devicePropertiesAttestation) { 313 expectedErrs.add(KeyStoreException.ERROR_ID_ATTESTATION_FAILURE); 314 } 315 if (TestUtils.getVendorApiLevel() < 35) { 316 // b/337427860, some devices returns UNKNOWN_ERROR if large challenge is 317 // passed. So allow an extra error code for earlier devices. 318 expectedErrs.add(KeyStoreException.ERROR_KEYMINT_FAILURE); 319 } 320 String assertMessage = String.format( 321 "Error code was %d, device properties attestation? %b", 322 errorCode, devicePropertiesAttestation); 323 assertTrue(assertMessage, expectedErrs.contains(errorCode)); 324 assertFalse("Unexpected transient failure.", keyStoreException.isTransientFailure()); 325 } 326 327 @Test testEcAttestation_TooLargeChallenge()328 public void testEcAttestation_TooLargeChallenge() throws Exception { 329 testEcAttestation_TooLargeChallenge(false); 330 } 331 332 @Test testEcAttestation_TooLargeChallenge_StrongBox()333 public void testEcAttestation_TooLargeChallenge_StrongBox() throws Exception { 334 assumeTrue("This test is only applicable to devices with StrongBox", 335 TestUtils.hasStrongBox(getContext())); 336 testEcAttestation_TooLargeChallenge(true); 337 } 338 testEcAttestation_TooLargeChallenge(boolean isStrongBox)339 private void testEcAttestation_TooLargeChallenge(boolean isStrongBox) throws Exception { 340 if (!TestUtils.isAttestationSupported()) { 341 return; 342 } 343 344 boolean[] devicePropertiesAttestationValues = {true, false}; 345 for (boolean devicePropertiesAttestation : devicePropertiesAttestationValues) { 346 try { 347 testEcAttestation(new byte[129], true /* includeValidityDates */, "secp256r1", 256, 348 KM_PURPOSE_SIGN, devicePropertiesAttestation, isStrongBox); 349 fail("Attestation challenges larger than 128 bytes should be rejected"); 350 } catch (ProviderException e) { 351 KeyStoreException cause = (KeyStoreException) e.getCause(); 352 assertAttestationKeyMintError(cause, devicePropertiesAttestation); 353 assertPublicAttestationError(cause, devicePropertiesAttestation); 354 } 355 } 356 } 357 358 @Test testEcAttestation_NoChallenge()359 public void testEcAttestation_NoChallenge() throws Exception { 360 testEcAttestation_NoChallenge(false); 361 } 362 363 @Test testEcAttestation_NoChallenge_StrongBox()364 public void testEcAttestation_NoChallenge_StrongBox() throws Exception { 365 assumeTrue("This test is only applicable to devices with StrongBox", 366 TestUtils.hasStrongBox(getContext())); 367 testEcAttestation_NoChallenge(true); 368 } 369 testEcAttestation_NoChallenge(boolean isStrongBox)370 public void testEcAttestation_NoChallenge(boolean isStrongBox) throws Exception { 371 boolean[] devicePropertiesAttestationValues = {true, false}; 372 for (boolean devicePropertiesAttestation : devicePropertiesAttestationValues) { 373 String keystoreAlias = "test_key"; 374 Date now = new Date(); 375 Date originationEnd = new Date(now.getTime() + ORIGINATION_TIME_OFFSET); 376 Date consumptionEnd = new Date(now.getTime() + CONSUMPTION_TIME_OFFSET); 377 KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(keystoreAlias, PURPOSE_SIGN) 378 .setAlgorithmParameterSpec(new ECGenParameterSpec("secp256r1")) 379 .setDigests(TestUtils.getDigestsForKeyMintImplementation(isStrongBox)) 380 .setAttestationChallenge(null) 381 .setKeyValidityStart(now) 382 .setKeyValidityForOriginationEnd(originationEnd) 383 .setKeyValidityForConsumptionEnd(consumptionEnd) 384 .setDevicePropertiesAttestationIncluded(devicePropertiesAttestation) 385 .setIsStrongBoxBacked(isStrongBox) 386 .build(); 387 388 generateKeyPair(KEY_ALGORITHM_EC, spec); 389 390 KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); 391 keyStore.load(null); 392 393 try { 394 Certificate certificates[] = keyStore.getCertificateChain(keystoreAlias); 395 assertEquals(1, certificates.length); 396 397 X509Certificate attestationCert = (X509Certificate) certificates[0]; 398 assertNull(attestationCert.getExtensionValue(Attestation.ASN1_OID)); 399 assertNull(attestationCert.getExtensionValue(Attestation.EAT_OID)); 400 } finally { 401 keyStore.deleteEntry(keystoreAlias); 402 } 403 } 404 } 405 testEcAttestation_DeviceLocked(Boolean expectStrongBox)406 private void testEcAttestation_DeviceLocked(Boolean expectStrongBox) throws Exception { 407 if (!TestUtils.isAttestationSupported()) { 408 return; 409 } 410 411 if (getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_PC)) 412 return; 413 414 String keystoreAlias = "test_key"; 415 Date now = new Date(); 416 Date originationEnd = new Date(now.getTime() + ORIGINATION_TIME_OFFSET); 417 Date consumptionEnd = new Date(now.getTime() + CONSUMPTION_TIME_OFFSET); 418 KeyGenParameterSpec.Builder builder = 419 new KeyGenParameterSpec.Builder(keystoreAlias, PURPOSE_SIGN) 420 .setAlgorithmParameterSpec(new ECGenParameterSpec("secp256r1")) 421 .setDigests(TestUtils.getDigestsForKeyMintImplementation(expectStrongBox)) 422 .setAttestationChallenge(new byte[128]) 423 .setKeyValidityStart(now) 424 .setKeyValidityForOriginationEnd(originationEnd) 425 .setKeyValidityForConsumptionEnd(consumptionEnd) 426 .setIsStrongBoxBacked(expectStrongBox); 427 428 generateKeyPair(KEY_ALGORITHM_EC, builder.build()); 429 430 KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); 431 keyStore.load(null); 432 433 try { 434 Certificate certificates[] = keyStore.getCertificateChain(keystoreAlias); 435 verifyCertificateChain(certificates, expectStrongBox); 436 437 X509Certificate attestationCert = (X509Certificate) certificates[0]; 438 checkDeviceLocked(Attestation.loadFromCertificate(attestationCert)); 439 } finally { 440 keyStore.deleteEntry(keystoreAlias); 441 } 442 } 443 444 @RestrictedBuildTest 445 @RequiresDevice 446 @Test 447 @CddTest(requirements = {"9.10/C-0-1", "9.10/C-1-3"}) testEcAttestation_DeviceLocked()448 public void testEcAttestation_DeviceLocked() throws Exception { 449 testEcAttestation_DeviceLocked(false /* expectStrongBox */); 450 } 451 452 @RestrictedBuildTest 453 @RequiresDevice 454 @Test 455 @CddTest(requirements = {"9.10/C-0-1", "9.10/C-1-3"}) testEcAttestation_DeviceLockedStrongbox()456 public void testEcAttestation_DeviceLockedStrongbox() throws Exception { 457 if (!TestUtils.hasStrongBox(getContext())) 458 return; 459 testEcAttestation_DeviceLocked(true /* expectStrongBox */); 460 } 461 462 @Test testAttestationKmVersionMatchesFeatureVersion()463 public void testAttestationKmVersionMatchesFeatureVersion() throws Exception { 464 if (getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_PC)) 465 return; 466 assumeTrue("Device does not support attestation", TestUtils.isAttestationSupported()); 467 468 testAttestationKmVersionMatchesFeatureVersion(false); 469 } 470 471 @Test testAttestationKmVersionMatchesFeatureVersionStrongBox()472 public void testAttestationKmVersionMatchesFeatureVersionStrongBox() throws Exception { 473 if (getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_PC)) 474 return; 475 assumeTrue("Device does not support attestation", TestUtils.isAttestationSupported()); 476 477 int keyStoreFeatureVersionStrongBox = 478 TestUtils.getFeatureVersionKeystoreStrongBox(getContext()); 479 480 if (!TestUtils.hasStrongBox(getContext())) { 481 // If there's no StrongBox, ensure there's no feature version for it. 482 assertEquals(0, keyStoreFeatureVersionStrongBox); 483 return; 484 } 485 486 testAttestationKmVersionMatchesFeatureVersion(true); 487 } 488 testAttestationKmVersionMatchesFeatureVersion(boolean isStrongBox)489 private void testAttestationKmVersionMatchesFeatureVersion(boolean isStrongBox) 490 throws Exception { 491 assumeTrue("Device does not support attestation", TestUtils.isAttestationSupported()); 492 493 String keystoreAlias = "test_key"; 494 Date now = new Date(); 495 Date originationEnd = new Date(now.getTime() + ORIGINATION_TIME_OFFSET); 496 Date consumptionEnd = new Date(now.getTime() + CONSUMPTION_TIME_OFFSET); 497 KeyGenParameterSpec.Builder builder = 498 new KeyGenParameterSpec.Builder(keystoreAlias, PURPOSE_SIGN) 499 .setAlgorithmParameterSpec(new ECGenParameterSpec("secp256r1")) 500 .setAttestationChallenge(new byte[128]) 501 .setKeyValidityStart(now) 502 .setKeyValidityForOriginationEnd(originationEnd) 503 .setKeyValidityForConsumptionEnd(consumptionEnd) 504 .setIsStrongBoxBacked(isStrongBox); 505 506 generateKeyPair(KEY_ALGORITHM_EC, builder.build()); 507 508 KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); 509 keyStore.load(null); 510 511 try { 512 Certificate certificates[] = keyStore.getCertificateChain(keystoreAlias); 513 verifyCertificateChain(certificates, isStrongBox /* expectStrongBox */); 514 X509Certificate attestationCert = (X509Certificate) certificates[0]; 515 Attestation attestation = Attestation.loadFromCertificate(attestationCert); 516 int kmVersionFromAttestation = attestation.keymasterVersion; 517 int keyStoreFeatureVersion; 518 519 if (isStrongBox) { 520 keyStoreFeatureVersion = 521 TestUtils.getFeatureVersionKeystoreStrongBox(getContext()); 522 } else { 523 keyStoreFeatureVersion = 524 TestUtils.getFeatureVersionKeystore(getContext()); 525 } 526 // Feature Version is required on devices launching with Android 12 (API Level 527 // 31) but may be reported on devices launching with an earlier version. If it's 528 // present, it must match what is reported in attestation. 529 if (TestUtils.getVendorApiLevel() >= 31) { 530 assertNotEquals(0, keyStoreFeatureVersion); 531 } 532 if (keyStoreFeatureVersion != 0) { 533 assertEquals(kmVersionFromAttestation, keyStoreFeatureVersion); 534 } 535 } finally { 536 keyStore.deleteEntry(keystoreAlias); 537 } 538 } 539 540 @Test testEcAttestation_KeyStoreExceptionWhenRequestingUniqueId()541 public void testEcAttestation_KeyStoreExceptionWhenRequestingUniqueId() throws Exception { 542 testEcAttestation_KeyStoreExceptionWhenRequestingUniqueId(false); 543 } 544 545 @Test testEcAttestation_KeyStoreExceptionWhenRequestingUniqueId_StrongBox()546 public void testEcAttestation_KeyStoreExceptionWhenRequestingUniqueId_StrongBox() 547 throws Exception { 548 assumeTrue("This test is only applicable to devices with StrongBox", 549 TestUtils.hasStrongBox(getContext())); 550 testEcAttestation_KeyStoreExceptionWhenRequestingUniqueId(true); 551 } 552 testEcAttestation_KeyStoreExceptionWhenRequestingUniqueId( boolean isStrongBox)553 private void testEcAttestation_KeyStoreExceptionWhenRequestingUniqueId( 554 boolean isStrongBox) throws Exception { 555 String keystoreAlias = "test_key"; 556 KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(keystoreAlias, PURPOSE_SIGN) 557 .setAlgorithmParameterSpec(new ECGenParameterSpec("secp256r1")) 558 .setDigests(TestUtils.getDigestsForKeyMintImplementation(isStrongBox)) 559 .setAttestationChallenge(new byte[128]) 560 .setUniqueIdIncluded(true) 561 .setIsStrongBoxBacked(isStrongBox) 562 .build(); 563 564 try { 565 generateKeyPair(KEY_ALGORITHM_EC, spec); 566 fail("Attestation should have failed."); 567 } catch (ProviderException e) { 568 // Attestation is expected to fail because of lack of permissions. 569 KeyStoreException cause = (KeyStoreException) e.getCause(); 570 assertEquals(KM_ERROR_PERMISSION_DENIED, cause.getErrorCode()); 571 // Assert public failure information. 572 assertEquals(KeyStoreException.ERROR_PERMISSION_DENIED, cause.getNumericErrorCode()); 573 assertFalse("Unexpected transient failure in generate key.", 574 cause.isTransientFailure()); 575 } finally { 576 KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); 577 keyStore.load(null); 578 keyStore.deleteEntry(keystoreAlias); 579 } 580 } 581 582 @Test testEcAttestation_UniqueIdWorksWithCorrectPermission()583 public void testEcAttestation_UniqueIdWorksWithCorrectPermission() throws Exception { 584 testEcAttestation_UniqueIdWorksWithCorrectPermission(false); 585 } 586 @Test testEcAttestation_UniqueIdWorksWithCorrectPermission_StrongBox()587 public void testEcAttestation_UniqueIdWorksWithCorrectPermission_StrongBox() 588 throws Exception { 589 assumeTrue("This test is only applicable to devices with StrongBox", 590 TestUtils.hasStrongBox(getContext())); 591 testEcAttestation_UniqueIdWorksWithCorrectPermission(true); 592 } 593 testEcAttestation_UniqueIdWorksWithCorrectPermission(boolean isStrongBox)594 private void testEcAttestation_UniqueIdWorksWithCorrectPermission(boolean isStrongBox) 595 throws Exception { 596 assumeTrue("Device doesn't have secure lock screen", 597 TestUtils.hasSecureLockScreen(getContext())); 598 assumeTrue("Device does not support attestation", TestUtils.isAttestationSupported()); 599 600 String keystoreAlias = "test_key"; 601 KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(keystoreAlias, PURPOSE_SIGN) 602 .setAlgorithmParameterSpec(new ECGenParameterSpec("secp256r1")) 603 .setDigests(TestUtils.getDigestsForKeyMintImplementation(isStrongBox)) 604 .setAttestationChallenge(new byte[128]) 605 .setUniqueIdIncluded(true) 606 .setIsStrongBoxBacked(isStrongBox) 607 .build(); 608 609 KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); 610 keyStore.load(null); 611 612 try (PermissionContext c = TestApis.permissions().withPermission( 613 "android.permission.REQUEST_UNIQUE_ID_ATTESTATION")) { 614 generateKeyPair(KEY_ALGORITHM_EC, spec); 615 Certificate certificates[] = keyStore.getCertificateChain(keystoreAlias); 616 Attestation attestation = Attestation.loadFromCertificate((X509Certificate) certificates[0]); 617 byte[] firstUniqueId = attestation.getUniqueId(); 618 assertTrue("UniqueId must not be empty", firstUniqueId.length > 0); 619 620 // The unique id rotates (30 days in the default implementation), and it's possible to 621 // get a spurious failure if the test runs exactly when the rotation occurs. Allow a 622 // single retry, just in case. 623 byte[] secondUniqueId = null; 624 for (int i = 0; i < 2; ++i) { 625 keyStore.deleteEntry(keystoreAlias); 626 627 generateKeyPair(KEY_ALGORITHM_EC, spec); 628 certificates = keyStore.getCertificateChain(keystoreAlias); 629 attestation = Attestation.loadFromCertificate((X509Certificate) certificates[0]); 630 secondUniqueId = attestation.getUniqueId(); 631 632 if (Arrays.equals(firstUniqueId, secondUniqueId)) { 633 break; 634 } else { 635 firstUniqueId = secondUniqueId; 636 secondUniqueId = null; 637 } 638 } 639 assertTrue("UniqueIds must be consistent", 640 Arrays.equals(firstUniqueId, secondUniqueId)); 641 642 } finally { 643 keyStore.deleteEntry(keystoreAlias); 644 } 645 } 646 647 @RequiresDevice 648 @Test testRsaAttestation()649 public void testRsaAttestation() throws Exception { 650 testRsaAttestation(false); 651 } 652 653 @RequiresDevice 654 @Test testRsaAttestation_StrongBox()655 public void testRsaAttestation_StrongBox() throws Exception { 656 assumeTrue("This test is only applicable to devices with StrongBox", 657 TestUtils.hasStrongBox(getContext())); 658 testRsaAttestation(true); 659 } 660 testRsaAttestation(boolean isStrongBox)661 private void testRsaAttestation(boolean isStrongBox) throws Exception { 662 if (!TestUtils.isAttestationSupported()) { 663 return; 664 } 665 666 if (getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_PC)) 667 return; 668 669 final int[] purposes = { 670 PURPOSE_SIGN | PURPOSE_VERIFY, 671 PURPOSE_ENCRYPT | PURPOSE_DECRYPT, 672 }; 673 final String[][] signaturePaddingModes = { 674 { 675 SIGNATURE_PADDING_RSA_PKCS1, 676 }, 677 { 678 SIGNATURE_PADDING_RSA_PSS, 679 }, 680 { 681 SIGNATURE_PADDING_RSA_PKCS1, 682 SIGNATURE_PADDING_RSA_PSS, 683 }, 684 }; 685 final boolean[] devicePropertiesAttestationValues = {true, false}; 686 final int[] keySizes; 687 final byte[][] challenges; 688 final String[][] encryptionPaddingModes; 689 690 if (isStrongBox) { 691 // StrongBox has to support 2048 bit key. 692 keySizes = new int[] {2048}; 693 challenges = new byte[][] { 694 "challenge".getBytes(), // short challenge 695 new byte[128] // long challenge 696 }; 697 encryptionPaddingModes = new String [][] { 698 { 699 ENCRYPTION_PADDING_RSA_OAEP, 700 }, 701 { 702 ENCRYPTION_PADDING_RSA_PKCS1, 703 }, 704 { 705 ENCRYPTION_PADDING_RSA_OAEP, 706 ENCRYPTION_PADDING_RSA_PKCS1, 707 }, 708 }; 709 } else { 710 keySizes = new int[]{ // Smallish sizes to keep test runtimes down. 711 512, 768, 1024 712 }; 713 challenges = new byte[][]{ 714 new byte[0], // empty challenge 715 "challenge".getBytes(), // short challenge 716 new byte[128] // long challenge 717 }; 718 encryptionPaddingModes = new String[][]{ 719 { 720 ENCRYPTION_PADDING_NONE 721 }, 722 { 723 ENCRYPTION_PADDING_RSA_OAEP, 724 }, 725 { 726 ENCRYPTION_PADDING_RSA_PKCS1, 727 }, 728 { 729 ENCRYPTION_PADDING_RSA_OAEP, 730 ENCRYPTION_PADDING_RSA_PKCS1, 731 }, 732 }; 733 } 734 735 for (boolean devicePropertiesAttestation : devicePropertiesAttestationValues) { 736 for (int keySize : keySizes) { 737 for (byte[] challenge : challenges) { 738 for (int purpose : purposes) { 739 if (isEncryptionPurpose(purpose)) { 740 testRsaAttestations(keySize, challenge, purpose, encryptionPaddingModes, 741 devicePropertiesAttestation, isStrongBox); 742 } else { 743 testRsaAttestations(keySize, challenge, purpose, signaturePaddingModes, 744 devicePropertiesAttestation, isStrongBox); 745 } 746 } 747 } 748 } 749 } 750 } 751 752 @Test testRsaAttestation_TooLargeChallenge()753 public void testRsaAttestation_TooLargeChallenge() throws Exception { 754 testRsaAttestation_TooLargeChallenge(512, false); 755 } 756 757 @Test testRsaAttestation_TooLargeChallenge_StrongBox()758 public void testRsaAttestation_TooLargeChallenge_StrongBox() throws Exception { 759 assumeTrue("This test is only applicable to devices with StrongBox", 760 TestUtils.hasStrongBox(getContext())); 761 testRsaAttestation_TooLargeChallenge(2048, true); 762 } 763 testRsaAttestation_TooLargeChallenge(int keySize, boolean isStrongBox)764 private void testRsaAttestation_TooLargeChallenge(int keySize, boolean isStrongBox) 765 throws Exception { 766 if (!TestUtils.isAttestationSupported()) { 767 return; 768 } 769 770 boolean[] devicePropertiesAttestationValues = {true, false}; 771 for (boolean devicePropertiesAttestation : devicePropertiesAttestationValues) { 772 try { 773 testRsaAttestation(new byte[129], true /* includeValidityDates */, keySize, 774 PURPOSE_SIGN, 775 null /* paddingModes; may be empty because we'll never test them */, 776 devicePropertiesAttestation, isStrongBox); 777 fail("Attestation challenges larger than 128 bytes should be rejected"); 778 } catch(ProviderException e){ 779 KeyStoreException cause = (KeyStoreException) e.getCause(); 780 assertAttestationKeyMintError(cause, devicePropertiesAttestation); 781 assertPublicAttestationError(cause, devicePropertiesAttestation); 782 } 783 } 784 } 785 786 @Test testRsaAttestation_NoChallenge()787 public void testRsaAttestation_NoChallenge() throws Exception { 788 testRsaAttestation_NoChallenge(false); 789 } 790 791 @Test testRsaAttestation_NoChallenge_StrongBox()792 public void testRsaAttestation_NoChallenge_StrongBox() throws Exception { 793 assumeTrue("This test is only applicable to devices with StrongBox", 794 TestUtils.hasStrongBox(getContext())); 795 testRsaAttestation_NoChallenge(true); 796 } 797 testRsaAttestation_NoChallenge(boolean isStrongBox)798 private void testRsaAttestation_NoChallenge(boolean isStrongBox) throws Exception { 799 boolean[] devicePropertiesAttestationValues = {true, false}; 800 for (boolean devicePropertiesAttestation : devicePropertiesAttestationValues) { 801 String keystoreAlias = "test_key"; 802 Date now = new Date(); 803 Date originationEnd = new Date(now.getTime() + ORIGINATION_TIME_OFFSET); 804 Date consumptionEnd = new Date(now.getTime() + CONSUMPTION_TIME_OFFSET); 805 KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(keystoreAlias, PURPOSE_SIGN) 806 .setDigests(TestUtils.getDigestsForKeyMintImplementation(isStrongBox)) 807 .setAttestationChallenge(null) 808 .setKeyValidityStart(now) 809 .setKeyValidityForOriginationEnd(originationEnd) 810 .setKeyValidityForConsumptionEnd(consumptionEnd) 811 .setDevicePropertiesAttestationIncluded(devicePropertiesAttestation) 812 .setIsStrongBoxBacked(isStrongBox) 813 .build(); 814 815 generateKeyPair(KEY_ALGORITHM_RSA, spec); 816 817 KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); 818 keyStore.load(null); 819 820 try { 821 Certificate certificates[] = keyStore.getCertificateChain(keystoreAlias); 822 assertEquals(1, certificates.length); 823 824 X509Certificate attestationCert = (X509Certificate) certificates[0]; 825 assertNull(attestationCert.getExtensionValue(Attestation.ASN1_OID)); 826 } finally { 827 keyStore.deleteEntry(keystoreAlias); 828 } 829 } 830 } 831 testRsaAttestation_DeviceLocked(Boolean expectStrongBox)832 private void testRsaAttestation_DeviceLocked(Boolean expectStrongBox) throws Exception { 833 if (!TestUtils.isAttestationSupported()) { 834 return; 835 } 836 837 if (getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_PC)) 838 return; 839 840 String keystoreAlias = "test_key"; 841 Date now = new Date(); 842 Date originationEnd = new Date(now.getTime() + ORIGINATION_TIME_OFFSET); 843 Date consumptionEnd = new Date(now.getTime() + CONSUMPTION_TIME_OFFSET); 844 KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(keystoreAlias, PURPOSE_SIGN) 845 .setDigests(TestUtils.getDigestsForKeyMintImplementation(expectStrongBox)) 846 .setAttestationChallenge("challenge".getBytes()) 847 .setKeyValidityStart(now) 848 .setKeyValidityForOriginationEnd(originationEnd) 849 .setKeyValidityForConsumptionEnd(consumptionEnd) 850 .setIsStrongBoxBacked(expectStrongBox) 851 .build(); 852 853 generateKeyPair(KEY_ALGORITHM_RSA, spec); 854 855 KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); 856 keyStore.load(null); 857 858 try { 859 Certificate certificates[] = keyStore.getCertificateChain(keystoreAlias); 860 verifyCertificateChain(certificates, expectStrongBox); 861 862 X509Certificate attestationCert = (X509Certificate) certificates[0]; 863 checkDeviceLocked(Attestation.loadFromCertificate(attestationCert)); 864 } finally { 865 keyStore.deleteEntry(keystoreAlias); 866 } 867 } 868 869 @RestrictedBuildTest 870 @RequiresDevice // Emulators have no place to store the needed key 871 @Test 872 @CddTest(requirements = {"9.10/C-0-1", "9.10/C-1-3"}) testRsaAttestation_DeviceLocked()873 public void testRsaAttestation_DeviceLocked() throws Exception { 874 testRsaAttestation_DeviceLocked(false /* expectStrongbox */); 875 } 876 877 @RestrictedBuildTest 878 @RequiresDevice // Emulators have no place to store the needed key 879 @Test 880 @CddTest(requirements = {"9.10/C-0-1", "9.10/C-1-3"}) testRsaAttestation_DeviceLockedStrongbox()881 public void testRsaAttestation_DeviceLockedStrongbox() throws Exception { 882 if (!TestUtils.hasStrongBox(getContext())) 883 return; 884 885 testRsaAttestation_DeviceLocked(true /* expectStrongbox */); 886 } 887 888 @Test testAesAttestation()889 public void testAesAttestation() throws Exception { 890 testAesAttestation(false); 891 } 892 893 @Test testAesAttestation_StrongBox()894 public void testAesAttestation_StrongBox() throws Exception { 895 assumeTrue("This test is only applicable to devices with StrongBox", 896 TestUtils.hasStrongBox(getContext())); 897 testAesAttestation(true); 898 } 899 testAesAttestation(boolean isStrongBox)900 private void testAesAttestation(boolean isStrongBox) throws Exception { 901 boolean[] devicePropertiesAttestationValues = {true, false}; 902 for (boolean devicePropertiesAttestation : devicePropertiesAttestationValues) { 903 String keystoreAlias = "test_key"; 904 KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(keystoreAlias, 905 PURPOSE_ENCRYPT) 906 .setBlockModes(KeyProperties.BLOCK_MODE_GCM) 907 .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE) 908 .setAttestationChallenge(new byte[0]) 909 .setDevicePropertiesAttestationIncluded(devicePropertiesAttestation) 910 .setIsStrongBoxBacked(isStrongBox) 911 .build(); 912 generateKey(spec, KeyProperties.KEY_ALGORITHM_AES); 913 914 KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); 915 keyStore.load(null); 916 try { 917 assertNull(keyStore.getCertificateChain(keystoreAlias)); 918 } finally { 919 keyStore.deleteEntry(keystoreAlias); 920 } 921 } 922 } 923 924 @Test testHmacAttestation()925 public void testHmacAttestation() throws Exception { 926 testHmacAttestation(false); 927 } 928 929 @Test testHmacAttestation_StrongBox()930 public void testHmacAttestation_StrongBox() throws Exception { 931 assumeTrue("This test is only applicable to devices with StrongBox", 932 TestUtils.hasStrongBox(getContext())); 933 testHmacAttestation(true); 934 } 935 testHmacAttestation(boolean isStrongBox)936 private void testHmacAttestation(boolean isStrongBox) throws Exception { 937 boolean[] devicePropertiesAttestationValues = {true, false}; 938 for (boolean devicePropertiesAttestation : devicePropertiesAttestationValues) { 939 String keystoreAlias = "test_key"; 940 KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(keystoreAlias, PURPOSE_SIGN) 941 .setDevicePropertiesAttestationIncluded(devicePropertiesAttestation) 942 .setIsStrongBoxBacked(isStrongBox) 943 .build(); 944 945 generateKey(spec, KeyProperties.KEY_ALGORITHM_HMAC_SHA256); 946 947 KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); 948 keyStore.load(null); 949 try { 950 assertNull(keyStore.getCertificateChain(keystoreAlias)); 951 } finally { 952 keyStore.deleteEntry(keystoreAlias); 953 } 954 } 955 } 956 testRsaAttestations(int keySize, byte[] challenge, int purpose, String[][] paddingModes, boolean devicePropertiesAttestation, boolean isStrongBox)957 private void testRsaAttestations(int keySize, byte[] challenge, int purpose, 958 String[][] paddingModes, boolean devicePropertiesAttestation, 959 boolean isStrongBox) throws Exception { 960 for (String[] paddings : paddingModes) { 961 try { 962 testRsaAttestation(challenge, true /* includeValidityDates */, keySize, purpose, 963 paddings, devicePropertiesAttestation, isStrongBox); 964 testRsaAttestation(challenge, false /* includeValidityDates */, keySize, purpose, 965 paddings, devicePropertiesAttestation, isStrongBox); 966 } catch (Throwable e) { 967 boolean isIdAttestationFailure = 968 (e.getCause() instanceof KeyStoreException) 969 && KeyStoreException.ERROR_ID_ATTESTATION_FAILURE 970 == ((KeyStoreException) e.getCause()).getNumericErrorCode(); 971 if (devicePropertiesAttestation && isIdAttestationFailure) { 972 if (getContext().getPackageManager().hasSystemFeature( 973 PackageManager.FEATURE_DEVICE_ID_ATTESTATION)) { 974 throw new Exception("Unexpected failure while generating key." 975 + "\nIn case of AOSP/GSI builds, system provided properties could be" 976 + " different from provisioned properties in KeyMaster/KeyMint. In" 977 + " such cases, make sure attestation specific properties" 978 + " (Build.*_FOR_ATTESTATION) are configured correctly.", e); 979 } else { 980 Log.i(TAG, "key attestation with device IDs not supported; test skipped"); 981 continue; 982 } 983 } 984 throw new Exception("Failed on key size " + keySize + " challenge [" + 985 new String(challenge) + "], purposes " + 986 buildPurposeSet(purpose) + " paddings " + 987 ImmutableSet.copyOf(paddings) + " and devicePropertiesAttestation " 988 + devicePropertiesAttestation, 989 e); 990 } 991 } 992 } 993 994 @Test testDeviceIdAttestation()995 public void testDeviceIdAttestation() throws Exception { 996 testDeviceIdAttestationFailure(AttestationUtils.ID_TYPE_SERIAL, null); 997 testDeviceIdAttestationFailure(AttestationUtils.ID_TYPE_IMEI, "Unable to retrieve IMEI"); 998 testDeviceIdAttestationFailure(AttestationUtils.ID_TYPE_MEID, "Unable to retrieve MEID"); 999 } 1000 1001 @Test testAttestedRoTAcrossKeymints()1002 public void testAttestedRoTAcrossKeymints() throws Exception { 1003 assumeTrue("This test requires a device supporting key attestation", 1004 TestUtils.isAttestationSupported()); 1005 assumeTrue("This test is not applicable for PC", 1006 !getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_PC)); 1007 assumeTrue("This test is only applicable to devices with StrongBox", 1008 TestUtils.hasStrongBox(getContext())); 1009 1010 RootOfTrust teeRootOfTrust = generateAttestationAndExtractRoT("tee_test_key", false); 1011 RootOfTrust sbRootOfTrust = generateAttestationAndExtractRoT("sb_test_key", true); 1012 1013 assertNotNull("RootOfTrust should not be null for TEE", teeRootOfTrust); 1014 assertNotNull("RootOfTrust should not be null for StrongBox", sbRootOfTrust); 1015 assertArrayEquals("Verified boot hash in TEE and StrongBox issued certificates must be" 1016 + " same.", teeRootOfTrust.getVerifiedBootHash(), 1017 sbRootOfTrust.getVerifiedBootHash()); 1018 assertArrayEquals("Verified boot key in TEE and StrongBox issued certificates must be" 1019 + " same.", teeRootOfTrust.getVerifiedBootKey(), 1020 sbRootOfTrust.getVerifiedBootKey()); 1021 assertEquals("Verified boot state in TEE and StrongBox issued certificates must be same.", 1022 teeRootOfTrust.getVerifiedBootState(), 1023 sbRootOfTrust.getVerifiedBootState()); 1024 assertEquals("Device locked state in TEE and StrongBox issued certificates must be same.", 1025 teeRootOfTrust.isDeviceLocked(), sbRootOfTrust.isDeviceLocked()); 1026 } 1027 generateAttestationAndExtractRoT(String alias, boolean isStrongBox)1028 private RootOfTrust generateAttestationAndExtractRoT(String alias, boolean isStrongBox) 1029 throws Exception { 1030 KeyGenParameterSpec.Builder specBuilder = 1031 new KeyGenParameterSpec.Builder(alias, PURPOSE_SIGN | PURPOSE_VERIFY) 1032 .setIsStrongBoxBacked(isStrongBox) 1033 .setAlgorithmParameterSpec(new ECGenParameterSpec("secp256r1")) 1034 .setDigests(DIGEST_SHA256) 1035 .setAttestationChallenge("challenge".getBytes()); 1036 generateKeyPair(KEY_ALGORITHM_EC, specBuilder.build()); 1037 1038 KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); 1039 keyStore.load(null); 1040 1041 Certificate[] certificates = keyStore.getCertificateChain(alias); 1042 verifyCertificateChain(certificates, isStrongBox); 1043 1044 Attestation attestation = 1045 Attestation.loadFromCertificate((X509Certificate) certificates[0]); 1046 return attestation.getRootOfTrust(); 1047 } 1048 1049 @RequiresDevice 1050 @Test testCurve25519Attestation()1051 public void testCurve25519Attestation() throws Exception { 1052 if (!TestUtils.isAttestationSupported()) { 1053 return; 1054 } 1055 assumeTrue("Curve25519 Key attestation supported from KeyMint v2 and above.", 1056 TestUtils.hasKeystoreVersion(false /*isStrongBoxBased*/, 1057 Attestation.KM_VERSION_KEYMINT_2)); 1058 1059 if (getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_PC)) { 1060 return; 1061 } 1062 1063 byte[][] challenges = { 1064 new byte[0], // empty challenge 1065 "challenge".getBytes(), // short challenge 1066 new byte[128] // long challenge 1067 }; 1068 boolean[] devicePropertiesAttestationValues = {true, false}; 1069 1070 for (boolean devicePropertiesAttestation : devicePropertiesAttestationValues) { 1071 for (byte[] challenge : challenges) { 1072 testCurve25519Attestations("ed25519", challenge, PURPOSE_SIGN | PURPOSE_VERIFY, 1073 devicePropertiesAttestation); 1074 testCurve25519Attestations("x25519", challenge, PURPOSE_AGREE_KEY, 1075 devicePropertiesAttestation); 1076 } 1077 } 1078 } 1079 1080 @SuppressWarnings("deprecation") testCurve25519Attestations(String curve, byte[] challenge, int purpose, boolean devicePropertiesAttestation)1081 private void testCurve25519Attestations(String curve, byte[] challenge, 1082 int purpose, boolean devicePropertiesAttestation) 1083 throws Exception { 1084 Log.i(TAG, curve + " curve key attestation with: " 1085 + " / challenge " + Arrays.toString(challenge) 1086 + " / purposes " + purpose 1087 + " / devicePropertiesAttestation " + devicePropertiesAttestation); 1088 1089 String keystoreAlias = "test_key"; 1090 Date startTime = new Date(); 1091 KeyGenParameterSpec.Builder builder = 1092 new KeyGenParameterSpec.Builder(keystoreAlias, purpose) 1093 .setAlgorithmParameterSpec(new ECGenParameterSpec(curve)) 1094 .setDigests(KeyProperties.DIGEST_NONE) 1095 .setAttestationChallenge(challenge) 1096 .setDevicePropertiesAttestationIncluded(devicePropertiesAttestation); 1097 1098 generateKeyPair(KEY_ALGORITHM_EC, builder.build()); 1099 1100 KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); 1101 keyStore.load(null); 1102 1103 try { 1104 Certificate []certificates = keyStore.getCertificateChain(keystoreAlias); 1105 verifyCertificateChain(certificates, false /* expectStrongBox */); 1106 1107 X509Certificate attestationCert = (X509Certificate) certificates[0]; 1108 Attestation attestation = Attestation.loadFromCertificate(attestationCert); 1109 1110 checkEcKeyDetails(attestation, "CURVE_25519", 256); 1111 checkKeyUsage(attestationCert, purpose); 1112 checkKeyIndependentAttestationInfo(challenge, purpose, 1113 ImmutableSet.of(KM_DIGEST_NONE), startTime, false, 1114 devicePropertiesAttestation, attestation); 1115 } finally { 1116 keyStore.deleteEntry(keystoreAlias); 1117 } 1118 } 1119 1120 @SuppressWarnings("deprecation") testRsaAttestation(byte[] challenge, boolean includeValidityDates, int keySize, int purposes, String[] paddingModes, boolean devicePropertiesAttestation, boolean isStrongBox)1121 private void testRsaAttestation(byte[] challenge, boolean includeValidityDates, int keySize, 1122 int purposes, String[] paddingModes, boolean devicePropertiesAttestation, 1123 boolean isStrongBox) throws Exception { 1124 Log.i(TAG, "RSA key attestation with: challenge " + Arrays.toString(challenge) + 1125 " / includeValidityDates " + includeValidityDates + " / keySize " + keySize + 1126 " / purposes " + purposes + " / paddingModes " + Arrays.toString(paddingModes) + 1127 " / devicePropertiesAttestation " + devicePropertiesAttestation); 1128 1129 String keystoreAlias = "test_key"; 1130 Date startTime = new Date(); 1131 Date originationEnd = new Date(startTime.getTime() + ORIGINATION_TIME_OFFSET); 1132 Date consumptionEnd = new Date(startTime.getTime() + CONSUMPTION_TIME_OFFSET); 1133 KeyGenParameterSpec.Builder builder = 1134 new KeyGenParameterSpec.Builder(keystoreAlias, purposes) 1135 .setKeySize(keySize) 1136 .setDigests(TestUtils.getDigestsForKeyMintImplementation(isStrongBox)) 1137 .setAttestationChallenge(challenge) 1138 .setDevicePropertiesAttestationIncluded(devicePropertiesAttestation) 1139 .setIsStrongBoxBacked(isStrongBox); 1140 1141 if (includeValidityDates) { 1142 builder.setKeyValidityStart(startTime) 1143 .setKeyValidityForOriginationEnd(originationEnd) 1144 .setKeyValidityForConsumptionEnd(consumptionEnd); 1145 } 1146 if (isEncryptionPurpose(purposes)) { 1147 builder.setEncryptionPaddings(paddingModes); 1148 // Because we sometimes set "no padding", allow non-randomized encryption. 1149 builder.setRandomizedEncryptionRequired(false); 1150 } 1151 if (isSignaturePurpose(purposes)) { 1152 builder.setSignaturePaddings(paddingModes); 1153 } 1154 1155 generateKeyPair(KEY_ALGORITHM_RSA, builder.build()); 1156 1157 KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); 1158 keyStore.load(null); 1159 1160 try { 1161 Certificate certificates[] = keyStore.getCertificateChain(keystoreAlias); 1162 verifyCertificateChain(certificates, isStrongBox /* expectStrongBox */); 1163 1164 X509Certificate attestationCert = (X509Certificate) certificates[0]; 1165 Attestation attestation = Attestation.loadFromCertificate(attestationCert); 1166 1167 checkRsaKeyDetails(attestation, keySize, purposes, 1168 (paddingModes == null) 1169 ? new HashSet<String>() : ImmutableSet.copyOf(paddingModes)); 1170 checkKeyUsage(attestationCert, purposes); 1171 checkKeyIndependentAttestationInfo(challenge, purposes, startTime, 1172 includeValidityDates, devicePropertiesAttestation, attestation); 1173 } finally { 1174 keyStore.deleteEntry(keystoreAlias); 1175 } 1176 } 1177 checkKeyUsage(X509Certificate attestationCert, int purposes)1178 private void checkKeyUsage(X509Certificate attestationCert, int purposes) { 1179 1180 boolean[] expectedKeyUsage = new boolean[KEY_USAGE_BITSTRING_LENGTH]; 1181 if (isSignaturePurpose(purposes)) { 1182 expectedKeyUsage[KEY_USAGE_DIGITAL_SIGNATURE_BIT_OFFSET] = true; 1183 } 1184 if (isEncryptionPurpose(purposes)) { 1185 expectedKeyUsage[KEY_USAGE_KEY_ENCIPHERMENT_BIT_OFFSET] = true; 1186 expectedKeyUsage[KEY_USAGE_DATA_ENCIPHERMENT_BIT_OFFSET] = true; 1187 } 1188 if (isAgreeKeyPurpose(purposes)) { 1189 expectedKeyUsage[KEY_USAGE_KEY_AGREE_BIT_OFFSET] = true; 1190 } 1191 assertThat("Attested certificate has unexpected key usage.", 1192 attestationCert.getKeyUsage(), is(expectedKeyUsage)); 1193 } 1194 1195 @SuppressWarnings("deprecation") testEcAttestation(byte[] challenge, boolean includeValidityDates, String ecCurve, int keySize, int purposes, boolean devicePropertiesAttestation, boolean isStrongBox)1196 private void testEcAttestation(byte[] challenge, boolean includeValidityDates, String ecCurve, 1197 int keySize, int purposes, boolean devicePropertiesAttestation, 1198 boolean isStrongBox) throws Exception { 1199 Log.i(TAG, "EC key attestation with: challenge " + Arrays.toString(challenge) + 1200 " / includeValidityDates " + includeValidityDates + " / ecCurve " + ecCurve + 1201 " / keySize " + keySize + " / purposes " + purposes + 1202 " / devicePropertiesAttestation " + devicePropertiesAttestation); 1203 1204 String keystoreAlias = "test_key"; 1205 Date startTime = new Date(); 1206 Date originationEnd = new Date(startTime.getTime() + ORIGINATION_TIME_OFFSET); 1207 Date consumptionEnd = new Date(startTime.getTime() + CONSUMPTION_TIME_OFFSET); 1208 KeyGenParameterSpec.Builder builder = new KeyGenParameterSpec.Builder(keystoreAlias, 1209 purposes) 1210 .setAlgorithmParameterSpec(new ECGenParameterSpec(ecCurve)) 1211 .setDigests(TestUtils.getDigestsForKeyMintImplementation(isStrongBox)) 1212 .setAttestationChallenge(challenge) 1213 .setDevicePropertiesAttestationIncluded(devicePropertiesAttestation) 1214 .setIsStrongBoxBacked(isStrongBox); 1215 1216 if (includeValidityDates) { 1217 builder.setKeyValidityStart(startTime) 1218 .setKeyValidityForOriginationEnd(originationEnd) 1219 .setKeyValidityForConsumptionEnd(consumptionEnd); 1220 } 1221 1222 generateKeyPair(KEY_ALGORITHM_EC, builder.build()); 1223 1224 KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); 1225 keyStore.load(null); 1226 1227 try { 1228 Certificate certificates[] = keyStore.getCertificateChain(keystoreAlias); 1229 verifyCertificateChain(certificates, isStrongBox /* expectStrongBox */); 1230 1231 X509Certificate attestationCert = (X509Certificate) certificates[0]; 1232 Attestation attestation = Attestation.loadFromCertificate(attestationCert); 1233 1234 checkEcKeyDetails(attestation, ecCurve, keySize); 1235 checkKeyUsage(attestationCert, purposes); 1236 checkKeyIndependentAttestationInfo(challenge, purposes, startTime, 1237 includeValidityDates, devicePropertiesAttestation, attestation); 1238 } finally { 1239 keyStore.deleteEntry(keystoreAlias); 1240 } 1241 } 1242 checkAttestationApplicationId(Attestation attestation)1243 private void checkAttestationApplicationId(Attestation attestation) 1244 throws NoSuchAlgorithmException, NameNotFoundException { 1245 AttestationApplicationId aaid = null; 1246 int kmVersion = attestation.getKeymasterVersion(); 1247 assertNull(attestation.getTeeEnforced().getAttestationApplicationId()); 1248 aaid = attestation.getSoftwareEnforced().getAttestationApplicationId(); 1249 1250 if (kmVersion >= 3) { 1251 // must be present and correct 1252 assertNotNull(aaid); 1253 assertEquals(new AttestationApplicationId(getContext()), aaid); 1254 } else { 1255 // may be present and 1256 // must be correct if present 1257 if (aaid != null) { 1258 assertEquals(new AttestationApplicationId(getContext()), aaid); 1259 } 1260 } 1261 } 1262 checkAttestationDeviceProperties(boolean devicePropertiesAttestation, Attestation attestation)1263 private void checkAttestationDeviceProperties(boolean devicePropertiesAttestation, 1264 Attestation attestation) { 1265 final AuthorizationList keyDetailsList; 1266 final AuthorizationList nonKeyDetailsList; 1267 if (attestation.getKeymasterSecurityLevel() == KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT 1268 || attestation.getKeymasterSecurityLevel() == KM_SECURITY_LEVEL_STRONG_BOX) { 1269 keyDetailsList = attestation.getTeeEnforced(); 1270 nonKeyDetailsList = attestation.getSoftwareEnforced(); 1271 } else { 1272 keyDetailsList = attestation.getSoftwareEnforced(); 1273 nonKeyDetailsList = attestation.getTeeEnforced(); 1274 } 1275 1276 if (devicePropertiesAttestation) { 1277 final String platformReportedBrand = 1278 TestUtils.isPropertyEmptyOrUnknown(Build.BRAND_FOR_ATTESTATION) 1279 ? Build.BRAND : Build.BRAND_FOR_ATTESTATION; 1280 assertThat(keyDetailsList.getBrand()).isEqualTo(platformReportedBrand); 1281 final String platformReportedDevice = 1282 TestUtils.isPropertyEmptyOrUnknown(Build.DEVICE_FOR_ATTESTATION) 1283 ? Build.DEVICE : Build.DEVICE_FOR_ATTESTATION; 1284 assertThat(keyDetailsList.getDevice()).isEqualTo(platformReportedDevice); 1285 final String platformReportedProduct = 1286 TestUtils.isPropertyEmptyOrUnknown(Build.PRODUCT_FOR_ATTESTATION) 1287 ? Build.PRODUCT : Build.PRODUCT_FOR_ATTESTATION; 1288 assertThat(keyDetailsList.getProduct()).isEqualTo(platformReportedProduct); 1289 final String platformReportedManufacturer = 1290 TestUtils.isPropertyEmptyOrUnknown(Build.MANUFACTURER_FOR_ATTESTATION) 1291 ? Build.MANUFACTURER : Build.MANUFACTURER_FOR_ATTESTATION; 1292 assertThat(keyDetailsList.getManufacturer()).isEqualTo(platformReportedManufacturer); 1293 final String platformReportedModel = 1294 TestUtils.isPropertyEmptyOrUnknown(Build.MODEL_FOR_ATTESTATION) 1295 ? Build.MODEL : Build.MODEL_FOR_ATTESTATION; 1296 assertThat(keyDetailsList.getModel()).isEqualTo(platformReportedModel); 1297 } else { 1298 assertNull(keyDetailsList.getBrand()); 1299 assertNull(keyDetailsList.getDevice()); 1300 assertNull(keyDetailsList.getProduct()); 1301 assertNull(keyDetailsList.getManufacturer()); 1302 assertNull(keyDetailsList.getModel()); 1303 } 1304 assertNull(nonKeyDetailsList.getBrand()); 1305 assertNull(nonKeyDetailsList.getDevice()); 1306 assertNull(nonKeyDetailsList.getProduct()); 1307 assertNull(nonKeyDetailsList.getManufacturer()); 1308 assertNull(nonKeyDetailsList.getModel()); 1309 } 1310 checkAttestationNoUniqueIds(Attestation attestation)1311 private void checkAttestationNoUniqueIds(Attestation attestation) { 1312 assertNull(attestation.getTeeEnforced().getImei()); 1313 assertNull(attestation.getTeeEnforced().getMeid()); 1314 assertNull(attestation.getTeeEnforced().getSerialNumber()); 1315 assertNull(attestation.getSoftwareEnforced().getImei()); 1316 assertNull(attestation.getSoftwareEnforced().getMeid()); 1317 assertNull(attestation.getSoftwareEnforced().getSerialNumber()); 1318 } 1319 checkKeyIndependentAttestationInfo(byte[] challenge, int purposes, Date startTime, boolean includesValidityDates, boolean devicePropertiesAttestation, Attestation attestation)1320 private void checkKeyIndependentAttestationInfo(byte[] challenge, int purposes, 1321 Date startTime, boolean includesValidityDates, 1322 boolean devicePropertiesAttestation, Attestation attestation) 1323 throws NoSuchAlgorithmException, NameNotFoundException { 1324 Set digests = ImmutableSet.of(KM_DIGEST_NONE, KM_DIGEST_SHA_2_256, KM_DIGEST_SHA_2_512); 1325 if (attestation.getAttestationSecurityLevel() == KM_SECURITY_LEVEL_STRONG_BOX) { 1326 digests = ImmutableSet.of(KM_DIGEST_NONE, KM_DIGEST_SHA_2_256); 1327 } 1328 checkKeyIndependentAttestationInfo(challenge, purposes, digests, 1329 startTime, includesValidityDates, 1330 devicePropertiesAttestation, attestation); 1331 } 1332 checkKeyIndependentAttestationInfo(byte[] challenge, int purposes, Set digests, Date startTime, boolean includesValidityDates, boolean devicePropertiesAttestation, Attestation attestation)1333 private void checkKeyIndependentAttestationInfo(byte[] challenge, int purposes, 1334 Set digests, Date startTime, boolean includesValidityDates, 1335 boolean devicePropertiesAttestation, Attestation attestation) 1336 throws NoSuchAlgorithmException, NameNotFoundException { 1337 checkUnexpectedOids(attestation); 1338 checkAttestationSecurityLevelDependentParams(attestation); 1339 assertNotNull("Attestation challenge must not be null.", 1340 attestation.getAttestationChallenge()); 1341 assertThat("Attestation challenge not matching with provided challenge.", 1342 attestation.getAttestationChallenge(), is(challenge)); 1343 // In EAT, this is null if not filled in. In ASN.1, this is an array with length 0. 1344 if (attestation.getUniqueId() != null) { 1345 assertEquals("Unique ID must not be empty if present.", 1346 0, attestation.getUniqueId().length); 1347 } 1348 checkPurposes(attestation, purposes); 1349 checkDigests(attestation, digests); 1350 checkValidityPeriod(attestation, startTime, includesValidityDates); 1351 checkFlags(attestation); 1352 checkOrigin(attestation); 1353 checkAttestationApplicationId(attestation); 1354 checkAttestationDeviceProperties(devicePropertiesAttestation, attestation); 1355 checkAttestationNoUniqueIds(attestation); 1356 } 1357 checkUnexpectedOids(Attestation attestation)1358 private void checkUnexpectedOids(Attestation attestation) { 1359 assertThat("Attestations must not contain any extra data", 1360 attestation.getUnexpectedExtensionOids(), is(empty())); 1361 } 1362 getSystemPatchLevel()1363 private int getSystemPatchLevel() { 1364 Matcher matcher = OS_PATCH_LEVEL_STRING_PATTERN.matcher(Build.VERSION.SECURITY_PATCH); 1365 String invalidPatternMessage = "Invalid pattern for security path level string " 1366 + Build.VERSION.SECURITY_PATCH; 1367 assertTrue(invalidPatternMessage, matcher.matches()); 1368 String year_string = matcher.group(OS_PATCH_LEVEL_YEAR_GROUP_NAME); 1369 String month_string = matcher.group(OS_PATCH_LEVEL_MONTH_GROUP_NAME); 1370 int patch_level = Integer.parseInt(year_string) * 100 + Integer.parseInt(month_string); 1371 return patch_level; 1372 } 1373 getSystemOsVersion()1374 private int getSystemOsVersion() { 1375 return parseSystemOsVersion(Build.VERSION.RELEASE); 1376 } 1377 parseSystemOsVersion(String versionString)1378 private int parseSystemOsVersion(String versionString) { 1379 Matcher matcher = OS_VERSION_STRING_PATTERN.matcher(versionString); 1380 if (!matcher.matches()) { 1381 return 0; 1382 } 1383 1384 int version = 0; 1385 String major_string = matcher.group(OS_MAJOR_VERSION_MATCH_GROUP_NAME); 1386 String minor_string = matcher.group(OS_MINOR_VERSION_MATCH_GROUP_NAME); 1387 String subminor_string = matcher.group(OS_SUBMINOR_VERSION_MATCH_GROUP_NAME); 1388 if (major_string != null) { 1389 version += Integer.parseInt(major_string) * 10000; 1390 } 1391 if (minor_string != null) { 1392 version += Integer.parseInt(minor_string) * 100; 1393 } 1394 if (subminor_string != null) { 1395 version += Integer.parseInt(subminor_string); 1396 } 1397 return version; 1398 } 1399 checkOrigin(Attestation attestation)1400 private void checkOrigin(Attestation attestation) { 1401 assertTrue("Origin must be defined", 1402 attestation.getSoftwareEnforced().getOrigin() != null || 1403 attestation.getTeeEnforced().getOrigin() != null); 1404 if (attestation.getKeymasterVersion() != 0) { 1405 assertTrue("Origin may not be defined in both SW and TEE, except on keymaster0", 1406 attestation.getSoftwareEnforced().getOrigin() == null || 1407 attestation.getTeeEnforced().getOrigin() == null); 1408 } 1409 1410 if (attestation.getKeymasterSecurityLevel() == KM_SECURITY_LEVEL_SOFTWARE) { 1411 assertThat("For security level software," 1412 + " SoftwareEnforced origin must be " + KM_ORIGIN_GENERATED, 1413 attestation.getSoftwareEnforced().getOrigin(), is(KM_ORIGIN_GENERATED)); 1414 } else if (attestation.getKeymasterVersion() == 0) { 1415 assertThat("For KeyMaster version 0," 1416 + "TeeEnforced origin must be " + KM_ORIGIN_UNKNOWN, 1417 attestation.getTeeEnforced().getOrigin(), is(KM_ORIGIN_UNKNOWN)); 1418 } else { 1419 assertThat("TeeEnforced origin must be " + KM_ORIGIN_GENERATED, 1420 attestation.getTeeEnforced().getOrigin(), is(KM_ORIGIN_GENERATED)); 1421 } 1422 } 1423 checkFlags(Attestation attestation)1424 private void checkFlags(Attestation attestation) { 1425 assertFalse("All applications was not requested", 1426 attestation.getSoftwareEnforced().isAllApplications()); 1427 assertFalse("All applications was not requested", 1428 attestation.getTeeEnforced().isAllApplications()); 1429 assertFalse("Allow while on body was not requested", 1430 attestation.getSoftwareEnforced().isAllowWhileOnBody()); 1431 assertFalse("Allow while on body was not requested", 1432 attestation.getTeeEnforced().isAllowWhileOnBody()); 1433 assertNull("Auth binding was not requiested", 1434 attestation.getSoftwareEnforced().getUserAuthType()); 1435 assertNull("Auth binding was not requiested", 1436 attestation.getTeeEnforced().getUserAuthType()); 1437 assertTrue("noAuthRequired must be true", 1438 attestation.getSoftwareEnforced().isNoAuthRequired() 1439 || attestation.getTeeEnforced().isNoAuthRequired()); 1440 assertFalse("auth is either software or TEE", 1441 attestation.getSoftwareEnforced().isNoAuthRequired() 1442 && attestation.getTeeEnforced().isNoAuthRequired()); 1443 assertFalse("Software cannot implement rollback resistance", 1444 attestation.getSoftwareEnforced().isRollbackResistant()); 1445 } 1446 checkValidityPeriod(Attestation attestation, Date startTime, boolean includesValidityDates)1447 private void checkValidityPeriod(Attestation attestation, Date startTime, 1448 boolean includesValidityDates) { 1449 AuthorizationList validityPeriodList = attestation.getSoftwareEnforced(); 1450 AuthorizationList nonValidityPeriodList = attestation.getTeeEnforced(); 1451 1452 // A bug in Android S leads Android S devices with KeyMint1 not to add a creationDateTime. 1453 boolean creationDateTimeBroken = 1454 Build.VERSION.SDK_INT == Build.VERSION_CODES.S && 1455 attestation.getKeymasterVersion() == Attestation.KM_VERSION_KEYMINT_1; 1456 1457 if (!creationDateTimeBroken) { 1458 assertNull(nonValidityPeriodList.getCreationDateTime()); 1459 1460 Date creationDateTime = validityPeriodList.getCreationDateTime(); 1461 1462 boolean requireCreationDateTime = 1463 attestation.getKeymasterVersion() >= Attestation.KM_VERSION_KEYMINT_1; 1464 1465 if (requireCreationDateTime || creationDateTime != null) { 1466 assertNotNull(creationDateTime); 1467 1468 assertTrue("Test start time (" + startTime.getTime() + ") and key creation time (" + 1469 creationDateTime.getTime() + ") should be close", 1470 Math.abs(creationDateTime.getTime() - startTime.getTime()) <= 2000); 1471 1472 // Allow 1 second leeway in case of nearest-second rounding. 1473 Date now = new Date(); 1474 assertTrue("Key creation time (" + creationDateTime.getTime() + ") must be now (" + 1475 now.getTime() + ") or earlier.", 1476 now.getTime() >= (creationDateTime.getTime() - 1000)); 1477 } 1478 } 1479 1480 if (includesValidityDates) { 1481 Date activeDateTime = validityPeriodList.getActiveDateTime(); 1482 Date originationExpirationDateTime = validityPeriodList.getOriginationExpireDateTime(); 1483 Date usageExpirationDateTime = validityPeriodList.getUsageExpireDateTime(); 1484 1485 assertNotNull("Active date time should not be null in SoftwareEnforced" 1486 + " authorization list.", activeDateTime); 1487 assertNotNull("Origination expiration date time should not be null in" 1488 + " SoftwareEnforced authorization list.", 1489 originationExpirationDateTime); 1490 assertNotNull("Usage expiration date time should not be null in SoftwareEnforced" 1491 + " authorization list.", usageExpirationDateTime); 1492 1493 assertNull("Active date time must not be included in TeeEnforced authorization list.", 1494 nonValidityPeriodList.getActiveDateTime()); 1495 assertNull("Origination date time must not be included in TeeEnforced authorization" 1496 + "list.", nonValidityPeriodList.getOriginationExpireDateTime()); 1497 assertNull("Usage expiration date time must not be included in TeeEnforced" 1498 + " authorization list.", 1499 nonValidityPeriodList.getUsageExpireDateTime()); 1500 1501 assertThat("Origination expiration date time must match with provided expiration" 1502 + " date time.", originationExpirationDateTime.getTime(), 1503 is(startTime.getTime() + ORIGINATION_TIME_OFFSET)); 1504 assertThat("Usage (consumption) expiration date time must match with provided" 1505 + " expiration date time.", usageExpirationDateTime.getTime(), 1506 is(startTime.getTime() + CONSUMPTION_TIME_OFFSET)); 1507 } 1508 } 1509 checkDigests(Attestation attestation, Set<Integer> expectedDigests)1510 private void checkDigests(Attestation attestation, Set<Integer> expectedDigests) { 1511 Set<Integer> softwareEnforcedDigests = attestation.getSoftwareEnforced().getDigests(); 1512 Set<Integer> teeEnforcedDigests = attestation.getTeeEnforced().getDigests(); 1513 1514 if (softwareEnforcedDigests == null) { 1515 softwareEnforcedDigests = ImmutableSet.of(); 1516 } 1517 if (teeEnforcedDigests == null) { 1518 teeEnforcedDigests = ImmutableSet.of(); 1519 } 1520 1521 Set<Integer> allDigests = ImmutableSet.<Integer> builder() 1522 .addAll(softwareEnforcedDigests) 1523 .addAll(teeEnforcedDigests) 1524 .build(); 1525 Set<Integer> intersection = new ArraySet<>(); 1526 intersection.addAll(softwareEnforcedDigests); 1527 intersection.retainAll(teeEnforcedDigests); 1528 1529 assertThat("Set of digests from software enforced and Tee enforced must match" 1530 + " with expected digests set.", allDigests, is(expectedDigests)); 1531 assertTrue("Digest sets must be disjoint", intersection.isEmpty()); 1532 1533 if (attestation.getKeymasterSecurityLevel() == KM_SECURITY_LEVEL_SOFTWARE 1534 || attestation.getKeymasterVersion() == 0) { 1535 assertThat("Digests in software-enforced", 1536 softwareEnforcedDigests, is(expectedDigests)); 1537 } else { 1538 if (attestation.getKeymasterVersion() == 1) { 1539 // KM1 implementations may not support SHA512 in the TEE 1540 assertTrue("KeyMaster version 1 may not support SHA256, in which case it must be" 1541 + " software-emulated.", 1542 softwareEnforcedDigests.contains(KM_DIGEST_SHA_2_512) 1543 || teeEnforcedDigests.contains(KM_DIGEST_SHA_2_512)); 1544 1545 assertThat("Tee enforced digests should have digests {none and SHA2-256}", 1546 teeEnforcedDigests, hasItems(KM_DIGEST_NONE, KM_DIGEST_SHA_2_256)); 1547 } else { 1548 assertThat("Tee enforced digests should have all expected digests.", 1549 teeEnforcedDigests, is(expectedDigests)); 1550 } 1551 } 1552 } 1553 checkPurposes(Attestation attestation, int purposes)1554 private Set<Integer> checkPurposes(Attestation attestation, int purposes) { 1555 Set<Integer> expectedPurposes = buildPurposeSet(purposes); 1556 if (attestation.getKeymasterSecurityLevel() == KM_SECURITY_LEVEL_SOFTWARE 1557 || attestation.getKeymasterVersion() == 0) { 1558 assertThat("Purposes in software-enforced should match expected set", 1559 attestation.getSoftwareEnforced().getPurposes(), is(expectedPurposes)); 1560 assertNull("Should be no purposes in TEE-enforced", 1561 attestation.getTeeEnforced().getPurposes()); 1562 } else { 1563 assertThat("Purposes in TEE-enforced should match expected set", 1564 attestation.getTeeEnforced().getPurposes(), is(expectedPurposes)); 1565 assertNull("No purposes in software-enforced", 1566 attestation.getSoftwareEnforced().getPurposes()); 1567 } 1568 return expectedPurposes; 1569 } 1570 checkSystemPatchLevel(int teeOsPatchLevel, int systemPatchLevel)1571 private void checkSystemPatchLevel(int teeOsPatchLevel, int systemPatchLevel) { 1572 if (TestUtils.isGsiImage()) { 1573 // b/168663786: When using a GSI image, the system patch level might be 1574 // greater than or equal to the OS patch level reported from TEE. 1575 assertThat("For GSI image TEE os patch level should be less than or equal to system" 1576 + " patch level.", teeOsPatchLevel, lessThanOrEqualTo(systemPatchLevel)); 1577 } else { 1578 assertThat("TEE os patch level must be equal to system patch level.", 1579 teeOsPatchLevel, is(systemPatchLevel)); 1580 } 1581 } 1582 1583 @SuppressWarnings("unchecked") checkAttestationSecurityLevelDependentParams(Attestation attestation)1584 private void checkAttestationSecurityLevelDependentParams(Attestation attestation) { 1585 assertThat("Attestation version must be one of: {1, 2, 3, 4, 100, 200, 300}", 1586 attestation.getAttestationVersion(), 1587 either(is(1)).or(is(2)).or(is(3)).or(is(4)).or(is(100)).or(is(200)).or(is(300))); 1588 1589 AuthorizationList teeEnforced = attestation.getTeeEnforced(); 1590 AuthorizationList softwareEnforced = attestation.getSoftwareEnforced(); 1591 1592 int systemOsVersion = getSystemOsVersion(); 1593 int systemPatchLevel = getSystemPatchLevel(); 1594 1595 switch (attestation.getAttestationSecurityLevel()) { 1596 case KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT: 1597 assertThat("TEE attestation can only come from TEE keymaster", 1598 attestation.getKeymasterSecurityLevel(), 1599 is(KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT)); 1600 assertThat("KeyMaster version is not valid.", attestation.getKeymasterVersion(), 1601 either(is(2)).or(is(3)).or(is(4)).or(is(41)) 1602 .or(is(100)).or(is(200)).or(is(300))); 1603 1604 checkRootOfTrust(attestation, false /* requireLocked */); 1605 assertThat("TEE enforced OS version and system OS version must be same.", 1606 teeEnforced.getOsVersion(), is(systemOsVersion)); 1607 checkSystemPatchLevel(teeEnforced.getOsPatchLevel(), systemPatchLevel); 1608 break; 1609 1610 case KM_SECURITY_LEVEL_STRONG_BOX: 1611 assertThat("StrongBox attestation can only come from StrongBox keymaster", 1612 attestation.getKeymasterSecurityLevel(), 1613 is(KM_SECURITY_LEVEL_STRONG_BOX)); 1614 assertThat("KeyMaster version is not valid.", attestation.getKeymasterVersion(), 1615 either(is(2)).or(is(3)).or(is(4)).or(is(41)) 1616 .or(is(100)).or(is(200)).or(is(300))); 1617 1618 checkRootOfTrust(attestation, false /* requireLocked */); 1619 assertThat("StrongBox enforced OS version and system OS version must be same.", 1620 teeEnforced.getOsVersion(), is(systemOsVersion)); 1621 checkSystemPatchLevel(teeEnforced.getOsPatchLevel(), systemPatchLevel); 1622 break; 1623 1624 case KM_SECURITY_LEVEL_SOFTWARE: 1625 if (attestation 1626 .getKeymasterSecurityLevel() == KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT) { 1627 assertThat("TEE KM version must be 0 or 1 with software attestation", 1628 attestation.getKeymasterVersion(), either(is(0)).or(is(1))); 1629 } else { 1630 assertThat("Software KM is version 3", attestation.getKeymasterVersion(), 1631 is(3)); 1632 assertThat("Software enforced OS version and System OS version must be same.", 1633 softwareEnforced.getOsVersion(), is(systemOsVersion)); 1634 checkSystemPatchLevel(softwareEnforced.getOsPatchLevel(), systemPatchLevel); 1635 } 1636 1637 assertNull("Software attestation cannot provide root of trust", 1638 teeEnforced.getRootOfTrust()); 1639 1640 break; 1641 1642 default: 1643 fail("Invalid attestation security level: " 1644 + attestation.getAttestationSecurityLevel()); 1645 break; 1646 } 1647 } 1648 checkDeviceLocked(Attestation attestation)1649 private void checkDeviceLocked(Attestation attestation) { 1650 assertThat("Attestation version must be >= 1", 1651 attestation.getAttestationVersion(), greaterThanOrEqualTo(1)); 1652 1653 int attestationSecurityLevel = attestation.getAttestationSecurityLevel(); 1654 switch (attestationSecurityLevel) { 1655 case KM_SECURITY_LEVEL_STRONG_BOX: 1656 case KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT: 1657 assertThat("Attestation security level doesn't match keymaster security level", 1658 attestation.getKeymasterSecurityLevel(), is(attestationSecurityLevel)); 1659 assertThat("Keymaster version should be greater than or equal to 2.", 1660 attestation.getKeymasterVersion(), greaterThanOrEqualTo(2)); 1661 1662 // Devices launched in Android 10.0 (API level 29) and after should run CTS 1663 // in LOCKED state. 1664 boolean requireLocked = PropertyUtil.getFirstApiLevel() >= 29; 1665 checkRootOfTrust(attestation, requireLocked); 1666 break; 1667 1668 case KM_SECURITY_LEVEL_SOFTWARE: 1669 default: 1670 // TEE attestation has been required since Android 7.0. 1671 fail("Unexpected attestation security level: " + 1672 attestation.securityLevelToString(attestationSecurityLevel)); 1673 break; 1674 } 1675 } 1676 checkVerifiedBootHash(byte[] verifiedBootHash)1677 private void checkVerifiedBootHash(byte[] verifiedBootHash) { 1678 assertNotNull(verifiedBootHash); 1679 StringBuilder hexVerifiedBootHash = new StringBuilder(verifiedBootHash.length * 2); 1680 for (byte b : verifiedBootHash) { 1681 hexVerifiedBootHash.append(String.format("%02x", b)); 1682 } 1683 String bootVbMetaDigest = SystemProperties.get("ro.boot.vbmeta.digest", ""); 1684 assertEquals( 1685 "VerifiedBootHash field of RootOfTrust section does not match with" 1686 + "system property ro.boot.vbmeta.digest", 1687 bootVbMetaDigest, hexVerifiedBootHash.toString()); 1688 } 1689 checkRootOfTrust(Attestation attestation, boolean requireLocked)1690 private void checkRootOfTrust(Attestation attestation, boolean requireLocked) { 1691 RootOfTrust rootOfTrust = attestation.getRootOfTrust(); 1692 assertNotNull(rootOfTrust); 1693 assertNotNull(rootOfTrust.getVerifiedBootKey()); 1694 assertTrue("Verified boot key is only " + rootOfTrust.getVerifiedBootKey().length + 1695 " bytes long", rootOfTrust.getVerifiedBootKey().length >= 32); 1696 if (requireLocked) { 1697 final String unlockedDeviceMessage = "The device's bootloader must be locked. This may " 1698 + "not be the default for pre-production devices."; 1699 assertTrue(unlockedDeviceMessage, rootOfTrust.isDeviceLocked()); 1700 checkEntropy(rootOfTrust.getVerifiedBootKey()); 1701 assertEquals(KM_VERIFIED_BOOT_VERIFIED, rootOfTrust.getVerifiedBootState()); 1702 if (PropertyUtil.getFirstApiLevel() < Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { 1703 // Verified boot hash was not previously checked in CTS, so set an api level check 1704 // to avoid running into waiver issues. 1705 return; 1706 } 1707 assertNotNull(rootOfTrust.getVerifiedBootHash()); 1708 assertEquals(32, rootOfTrust.getVerifiedBootHash().length); 1709 checkEntropy(rootOfTrust.getVerifiedBootHash()); 1710 checkVerifiedBootHash(rootOfTrust.getVerifiedBootHash()); 1711 } 1712 } 1713 checkEntropy(byte[] entropyData)1714 private void checkEntropy(byte[] entropyData) { 1715 byte[] entropyDataCopy = Arrays.copyOf(entropyData, entropyData.length); 1716 assertTrue("Failed Shannon entropy check", checkShannonEntropy(entropyDataCopy)); 1717 assertTrue("Failed BiEntropy check", checkTresBiEntropy(entropyDataCopy)); 1718 } 1719 checkShannonEntropy(byte[] verifiedBootKey)1720 private boolean checkShannonEntropy(byte[] verifiedBootKey) { 1721 double probabilityOfSetBit = countSetBits(verifiedBootKey) / (double)(verifiedBootKey.length * 8); 1722 return calculateShannonEntropy(probabilityOfSetBit) > 0.8; 1723 } 1724 calculateShannonEntropy(double probabilityOfSetBit)1725 private double calculateShannonEntropy(double probabilityOfSetBit) { 1726 if (probabilityOfSetBit <= 0.001 || probabilityOfSetBit >= .999) return 0; 1727 double entropy = (-probabilityOfSetBit * logTwo(probabilityOfSetBit)) - 1728 ((1 - probabilityOfSetBit) * logTwo(1 - probabilityOfSetBit)); 1729 Log.i(TAG, "Shannon entropy of VB Key: " + entropy); 1730 return entropy; 1731 } 1732 1733 /** 1734 * Note: This method modifies the input parameter while performing bit entropy check. 1735 */ checkTresBiEntropy(byte[] verifiedBootKey)1736 private boolean checkTresBiEntropy(byte[] verifiedBootKey) { 1737 double weightingFactor = 0; 1738 double weightedEntropy = 0; 1739 double probabilityOfSetBit = 0; 1740 int length = verifiedBootKey.length * 8; 1741 for(int i = 0; i < (verifiedBootKey.length * 8) - 2; i++) { 1742 probabilityOfSetBit = countSetBits(verifiedBootKey) / (double)length; 1743 weightingFactor += logTwo(i+2); 1744 weightedEntropy += calculateShannonEntropy(probabilityOfSetBit) * logTwo(i+2); 1745 deriveBitString(verifiedBootKey, length); 1746 length -= 1; 1747 } 1748 double tresBiEntropy = (1 / weightingFactor) * weightedEntropy; 1749 Log.i(TAG, "BiEntropy of VB Key: " + tresBiEntropy); 1750 return tresBiEntropy > 0.9; 1751 } 1752 1753 /** 1754 * Note: This method modifies the input parameter - bitString. 1755 */ deriveBitString(byte[] bitString, int activeLength)1756 private void deriveBitString(byte[] bitString, int activeLength) { 1757 int length = activeLength / 8; 1758 if (activeLength % 8 != 0) { 1759 length += 1; 1760 } 1761 1762 byte mask = (byte)((byte)0x80 >>> ((activeLength + 6) % 8)); 1763 if (activeLength % 8 == 1) { 1764 mask = (byte)~mask; 1765 } 1766 1767 for(int i = 0; i < length; i++) { 1768 if (i == length - 1) { 1769 bitString[i] ^= ((bitString[i] & 0xFF) << 1); 1770 bitString[i] &= mask; 1771 } else { 1772 bitString[i] ^= ((bitString[i] & 0xFF) << 1) | ((bitString[i+1] & 0xFF) >>> 7); 1773 } 1774 } 1775 } 1776 logTwo(double value)1777 private double logTwo(double value) { 1778 return Math.log(value) / Math.log(2); 1779 } 1780 countSetBits(byte[] toCount)1781 private int countSetBits(byte[] toCount) { 1782 int setBitCount = 0; 1783 for(int i = 0; i < toCount.length; i++) { 1784 setBitCount += countSetBits(toCount[i]); 1785 } 1786 return setBitCount; 1787 } 1788 countSetBits(byte toCount)1789 private int countSetBits(byte toCount) { 1790 int setBitCounter = 0; 1791 while(toCount != 0) { 1792 toCount &= (toCount - 1); 1793 setBitCounter++; 1794 } 1795 return setBitCounter; 1796 } 1797 checkRsaKeyDetails(Attestation attestation, int keySize, int purposes, Set<String> expectedPaddingModes)1798 private void checkRsaKeyDetails(Attestation attestation, int keySize, int purposes, 1799 Set<String> expectedPaddingModes) throws CertificateParsingException { 1800 AuthorizationList keyDetailsList; 1801 AuthorizationList nonKeyDetailsList; 1802 if (attestation.getKeymasterSecurityLevel() == KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT 1803 || attestation.getKeymasterSecurityLevel() == KM_SECURITY_LEVEL_STRONG_BOX) { 1804 keyDetailsList = attestation.getTeeEnforced(); 1805 nonKeyDetailsList = attestation.getSoftwareEnforced(); 1806 } else { 1807 keyDetailsList = attestation.getSoftwareEnforced(); 1808 nonKeyDetailsList = attestation.getTeeEnforced(); 1809 } 1810 assertEquals(keySize, keyDetailsList.getKeySize().intValue()); 1811 assertNull(nonKeyDetailsList.getKeySize()); 1812 1813 assertEquals(KM_ALGORITHM_RSA, keyDetailsList.getAlgorithm().intValue()); 1814 assertNull(nonKeyDetailsList.getAlgorithm()); 1815 1816 assertNull(keyDetailsList.getEcCurve()); 1817 assertNull(nonKeyDetailsList.getEcCurve()); 1818 1819 assertEquals(65537, keyDetailsList.getRsaPublicExponent().longValue()); 1820 assertNull(nonKeyDetailsList.getRsaPublicExponent()); 1821 1822 Set<String> paddingModes; 1823 if (attestation.getKeymasterVersion() == 0) { 1824 // KM0 implementations don't support padding info, so it's always in the 1825 // software-enforced list. 1826 paddingModes = attestation.getSoftwareEnforced().getPaddingModesAsStrings(); 1827 assertNull(attestation.getTeeEnforced().getPaddingModes()); 1828 } else { 1829 paddingModes = keyDetailsList.getPaddingModesAsStrings(); 1830 assertNull(nonKeyDetailsList.getPaddingModes()); 1831 } 1832 1833 // KM1 implementations may add ENCRYPTION_PADDING_NONE to the list of paddings. 1834 Set<String> km1PossiblePaddingModes = expectedPaddingModes; 1835 if (attestation.getKeymasterVersion() == 1 && 1836 attestation.getKeymasterSecurityLevel() == KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT) { 1837 ImmutableSet.Builder<String> builder = ImmutableSet.builder(); 1838 builder.addAll(expectedPaddingModes); 1839 builder.add(ENCRYPTION_PADDING_NONE); 1840 km1PossiblePaddingModes = builder.build(); 1841 } 1842 1843 assertThat("Attested padding mode does not matched with expected modes.", 1844 paddingModes, either(is(expectedPaddingModes)).or(is(km1PossiblePaddingModes))); 1845 } 1846 checkEcKeyDetails(Attestation attestation, String ecCurve, int keySize)1847 private void checkEcKeyDetails(Attestation attestation, String ecCurve, int keySize) { 1848 AuthorizationList keyDetailsList; 1849 AuthorizationList nonKeyDetailsList; 1850 if (attestation.getKeymasterSecurityLevel() == KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT 1851 || attestation.getKeymasterSecurityLevel() == KM_SECURITY_LEVEL_STRONG_BOX) { 1852 keyDetailsList = attestation.getTeeEnforced(); 1853 nonKeyDetailsList = attestation.getSoftwareEnforced(); 1854 } else { 1855 keyDetailsList = attestation.getSoftwareEnforced(); 1856 nonKeyDetailsList = attestation.getTeeEnforced(); 1857 } 1858 assertEquals(keySize, keyDetailsList.getKeySize().intValue()); 1859 assertNull(nonKeyDetailsList.getKeySize()); 1860 assertEquals(KM_ALGORITHM_EC, keyDetailsList.getAlgorithm().intValue()); 1861 assertNull(nonKeyDetailsList.getAlgorithm()); 1862 assertEquals(ecCurve, keyDetailsList.ecCurveAsString()); 1863 assertNull(nonKeyDetailsList.getEcCurve()); 1864 assertNull(keyDetailsList.getRsaPublicExponent()); 1865 assertNull(nonKeyDetailsList.getRsaPublicExponent()); 1866 assertNull(keyDetailsList.getPaddingModes()); 1867 assertNull(nonKeyDetailsList.getPaddingModes()); 1868 } 1869 isEncryptionPurpose(int purposes)1870 private boolean isEncryptionPurpose(int purposes) { 1871 return (purposes & PURPOSE_DECRYPT) != 0 || (purposes & PURPOSE_ENCRYPT) != 0; 1872 } 1873 isSignaturePurpose(int purposes)1874 private boolean isSignaturePurpose(int purposes) { 1875 return (purposes & PURPOSE_SIGN) != 0 || (purposes & PURPOSE_VERIFY) != 0; 1876 } 1877 isAgreeKeyPurpose(int purposes)1878 private boolean isAgreeKeyPurpose(int purposes) { 1879 return (purposes & PURPOSE_AGREE_KEY) != 0; 1880 } 1881 buildPurposeSet(int purposes)1882 private ImmutableSet<Integer> buildPurposeSet(int purposes) { 1883 ImmutableSet.Builder<Integer> builder = ImmutableSet.builder(); 1884 if ((purposes & PURPOSE_SIGN) != 0) 1885 builder.add(KM_PURPOSE_SIGN); 1886 if ((purposes & PURPOSE_VERIFY) != 0) 1887 builder.add(KM_PURPOSE_VERIFY); 1888 if ((purposes & PURPOSE_ENCRYPT) != 0) 1889 builder.add(KM_PURPOSE_ENCRYPT); 1890 if ((purposes & PURPOSE_DECRYPT) != 0) 1891 builder.add(KM_PURPOSE_DECRYPT); 1892 if ((purposes & PURPOSE_AGREE_KEY) != 0) { 1893 builder.add(KM_PURPOSE_AGREE_KEY); 1894 } 1895 return builder.build(); 1896 } 1897 generateKey(KeyGenParameterSpec spec, String algorithm)1898 private void generateKey(KeyGenParameterSpec spec, String algorithm) 1899 throws NoSuchAlgorithmException, NoSuchProviderException, 1900 InvalidAlgorithmParameterException { 1901 KeyGenerator keyGenerator = KeyGenerator.getInstance(algorithm, "AndroidKeyStore"); 1902 keyGenerator.init(spec); 1903 keyGenerator.generateKey(); 1904 } 1905 generateKeyPair(String algorithm, KeyGenParameterSpec spec)1906 private void generateKeyPair(String algorithm, KeyGenParameterSpec spec) 1907 throws NoSuchAlgorithmException, NoSuchProviderException, 1908 InvalidAlgorithmParameterException { 1909 KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(algorithm, 1910 "AndroidKeyStore"); 1911 keyPairGenerator.initialize(spec); 1912 keyPairGenerator.generateKeyPair(); 1913 } 1914 verifyCertificateChain(Certificate[] certChain, boolean expectStrongBox)1915 public static void verifyCertificateChain(Certificate[] certChain, boolean expectStrongBox) 1916 throws GeneralSecurityException { 1917 assertNotNull(certChain); 1918 boolean strongBoxSubjectFound = false; 1919 for (int i = 1; i < certChain.length; ++i) { 1920 try { 1921 PublicKey pubKey = certChain[i].getPublicKey(); 1922 certChain[i - 1].verify(pubKey); 1923 if (i == certChain.length - 1) { 1924 // Last cert should be self-signed. 1925 certChain[i].verify(pubKey); 1926 } 1927 1928 // Check that issuer in the signed cert matches subject in the signing cert. 1929 X509Certificate x509CurrCert = (X509Certificate) certChain[i]; 1930 X509Certificate x509PrevCert = (X509Certificate) certChain[i - 1]; 1931 X500Name signingCertSubject = 1932 new JcaX509CertificateHolder(x509CurrCert).getSubject(); 1933 X500Name signedCertIssuer = 1934 new JcaX509CertificateHolder(x509PrevCert).getIssuer(); 1935 // Use .toASN1Object().equals() rather than .equals() because .equals() is case 1936 // insensitive, and we want to verify an exact match. 1937 assertTrue(String.format("Certificate Issuer (%s) is not matching with parent" 1938 + " certificate's Subject (%s).", 1939 signedCertIssuer.toString(), signingCertSubject.toString()), 1940 signedCertIssuer.toASN1Object().equals(signingCertSubject.toASN1Object())); 1941 1942 X500Name signedCertSubject = 1943 new JcaX509CertificateHolder(x509PrevCert).getSubject(); 1944 if (i == 1) { 1945 // First cert should have subject "CN=Android Keystore Key". 1946 assertEquals(signedCertSubject, new X500Name("CN=Android Keystore Key")); 1947 } else if (signedCertSubject.toString().toLowerCase().contains("strongbox")) { 1948 strongBoxSubjectFound = true; 1949 } 1950 } catch (InvalidKeyException | CertificateException | NoSuchAlgorithmException 1951 | NoSuchProviderException | SignatureException e) { 1952 throw new GeneralSecurityException("Using StrongBox: " + expectStrongBox + "\n" 1953 + "Failed to verify certificate " + certChain[i - 1] 1954 + " with public key " + certChain[i].getPublicKey(), 1955 e); 1956 } 1957 } 1958 // At least one intermediate in a StrongBox chain must have "strongbox" in the subject. 1959 assertEquals(expectStrongBox, strongBoxSubjectFound); 1960 } 1961 testDeviceIdAttestationFailure(int idType, String acceptableDeviceIdAttestationFailureMessage)1962 private void testDeviceIdAttestationFailure(int idType, 1963 String acceptableDeviceIdAttestationFailureMessage) throws Exception { 1964 try { 1965 AttestationUtils.attestDeviceIds(getContext(), new int[] {idType}, "123".getBytes()); 1966 fail("Attestation should have failed."); 1967 } catch (SecurityException e) { 1968 // Attestation is expected to fail. If the device has the device ID type we are trying 1969 // to attest, it should fail with a SecurityException as we do not hold 1970 // READ_PRIVILEGED_PHONE_STATE permission. 1971 } catch (DeviceIdAttestationException e) { 1972 // Attestation is expected to fail. If the device does not have the device ID type we 1973 // are trying to attest (e.g. no IMEI on devices without a radio), it should fail with 1974 // a corresponding DeviceIdAttestationException. 1975 if (acceptableDeviceIdAttestationFailureMessage == null || 1976 !acceptableDeviceIdAttestationFailureMessage.equals(e.getMessage())) { 1977 throw e; 1978 } 1979 } 1980 } 1981 } 1982