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.keystore.KeyProperties.DIGEST_NONE; 35 import static android.security.keystore.KeyProperties.DIGEST_SHA256; 36 import static android.security.keystore.KeyProperties.DIGEST_SHA512; 37 import static android.security.keystore.KeyProperties.ENCRYPTION_PADDING_NONE; 38 import static android.security.keystore.KeyProperties.ENCRYPTION_PADDING_RSA_OAEP; 39 import static android.security.keystore.KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1; 40 import static android.security.keystore.KeyProperties.KEY_ALGORITHM_EC; 41 import static android.security.keystore.KeyProperties.KEY_ALGORITHM_RSA; 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 org.hamcrest.CoreMatchers.is; 50 import static org.hamcrest.MatcherAssert.assertThat; 51 import static org.hamcrest.Matchers.either; 52 import static org.hamcrest.Matchers.empty; 53 import static org.hamcrest.Matchers.greaterThanOrEqualTo; 54 import static org.hamcrest.Matchers.hasItems; 55 import static org.hamcrest.Matchers.lessThanOrEqualTo; 56 import static org.junit.Assert.assertEquals; 57 import static org.junit.Assert.assertFalse; 58 import static org.junit.Assert.assertNotEquals; 59 import static org.junit.Assert.assertNotNull; 60 import static org.junit.Assert.assertNull; 61 import static org.junit.Assert.assertTrue; 62 import static org.junit.Assert.fail; 63 import static org.junit.Assume.assumeTrue; 64 65 import android.content.Context; 66 import android.content.pm.PackageManager; 67 import android.content.pm.PackageManager.NameNotFoundException; 68 import android.keystore.cts.Attestation; 69 import android.keystore.cts.util.TestUtils; 70 import android.os.Build; 71 import android.os.SystemProperties; 72 import android.platform.test.annotations.RestrictedBuildTest; 73 import android.security.KeyStoreException; 74 import android.security.keystore.AttestationUtils; 75 import android.security.keystore.DeviceIdAttestationException; 76 import android.security.keystore.KeyGenParameterSpec; 77 import android.security.keystore.KeyProperties; 78 import android.util.ArraySet; 79 import android.util.Log; 80 81 import androidx.test.InstrumentationRegistry; 82 import androidx.test.filters.RequiresDevice; 83 import androidx.test.runner.AndroidJUnit4; 84 85 import com.android.bedstead.nene.TestApis; 86 import com.android.bedstead.nene.permissions.PermissionContext; 87 88 import com.google.common.collect.ImmutableSet; 89 90 import org.bouncycastle.asn1.x500.X500Name; 91 import org.bouncycastle.cert.jcajce.JcaX509CertificateHolder; 92 import org.junit.Test; 93 import org.junit.runner.RunWith; 94 95 import java.io.File; 96 import java.security.GeneralSecurityException; 97 import java.security.InvalidAlgorithmParameterException; 98 import java.security.InvalidKeyException; 99 import java.security.KeyPairGenerator; 100 import java.security.KeyStore; 101 import java.security.NoSuchAlgorithmException; 102 import java.security.NoSuchProviderException; 103 import java.security.ProviderException; 104 import java.security.PublicKey; 105 import java.security.SignatureException; 106 import java.security.cert.Certificate; 107 import java.security.cert.CertificateException; 108 import java.security.cert.CertificateParsingException; 109 import java.security.cert.X509Certificate; 110 import java.security.spec.ECGenParameterSpec; 111 import java.util.Arrays; 112 import java.util.Date; 113 import java.util.Set; 114 import java.util.regex.Matcher; 115 import java.util.regex.Pattern; 116 117 import javax.crypto.KeyGenerator; 118 119 /** 120 * Tests for Android Keystore attestation. 121 */ 122 @RunWith(AndroidJUnit4.class) 123 public class KeyAttestationTest { 124 125 private static final String TAG = AndroidKeyStoreTest.class.getSimpleName(); 126 127 private static final int ORIGINATION_TIME_OFFSET = 1000000; 128 private static final int CONSUMPTION_TIME_OFFSET = 2000000; 129 130 private static final int KEY_USAGE_BITSTRING_LENGTH = 9; 131 private static final int KEY_USAGE_DIGITAL_SIGNATURE_BIT_OFFSET = 0; 132 private static final int KEY_USAGE_KEY_ENCIPHERMENT_BIT_OFFSET = 2; 133 private static final int KEY_USAGE_DATA_ENCIPHERMENT_BIT_OFFSET = 3; 134 135 private static final int OS_MAJOR_VERSION_MATCH_GROUP_NAME = 1; 136 private static final int OS_MINOR_VERSION_MATCH_GROUP_NAME = 2; 137 private static final int OS_SUBMINOR_VERSION_MATCH_GROUP_NAME = 3; 138 private static final Pattern OS_VERSION_STRING_PATTERN = Pattern 139 .compile("([0-9]{1,2})(?:\\.([0-9]{1,2}))?(?:\\.([0-9]{1,2}))?(?:[^0-9.]+.*)?"); 140 141 private static final int OS_PATCH_LEVEL_YEAR_GROUP_NAME = 1; 142 private static final int OS_PATCH_LEVEL_MONTH_GROUP_NAME = 2; 143 private static final Pattern OS_PATCH_LEVEL_STRING_PATTERN = Pattern 144 .compile("([0-9]{4})-([0-9]{2})-[0-9]{2}"); 145 146 private static final int KM_ERROR_CANNOT_ATTEST_IDS = -66; 147 private static final int KM_ERROR_INVALID_INPUT_LENGTH = -21; 148 private static final int KM_ERROR_PERMISSION_DENIED = 6; 149 getContext()150 private Context getContext() { 151 return InstrumentationRegistry.getInstrumentation().getTargetContext(); 152 } 153 154 @Test testVersionParser()155 public void testVersionParser() throws Exception { 156 // Non-numerics/empty give version 0 157 assertEquals(0, parseSystemOsVersion("")); 158 assertEquals(0, parseSystemOsVersion("N")); 159 160 // Should support one, two or three version number values. 161 assertEquals(10000, parseSystemOsVersion("1")); 162 assertEquals(10200, parseSystemOsVersion("1.2")); 163 assertEquals(10203, parseSystemOsVersion("1.2.3")); 164 165 // It's fine to append other stuff to the dotted numeric version. 166 assertEquals(10000, parseSystemOsVersion("1stuff")); 167 assertEquals(10200, parseSystemOsVersion("1.2garbage.32")); 168 assertEquals(10203, parseSystemOsVersion("1.2.3-stuff")); 169 170 // Two digits per version field are supported 171 assertEquals(152536, parseSystemOsVersion("15.25.36")); 172 assertEquals(999999, parseSystemOsVersion("99.99.99")); 173 assertEquals(0, parseSystemOsVersion("100.99.99")); 174 assertEquals(0, parseSystemOsVersion("99.100.99")); 175 assertEquals(0, parseSystemOsVersion("99.99.100")); 176 } 177 178 @RequiresDevice 179 @Test testEcAttestation()180 public void testEcAttestation() throws Exception { 181 if (!TestUtils.isAttestationSupported()) { 182 return; 183 } 184 185 if (getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_PC)) 186 return; 187 188 // Note: Curve and key sizes arrays must correspond. 189 String[] curves = { 190 "secp224r1", "secp256r1", "secp384r1", "secp521r1" 191 }; 192 int[] keySizes = { 193 224, 256, 384, 521 194 }; 195 byte[][] challenges = { 196 new byte[0], // empty challenge 197 "challenge".getBytes(), // short challenge 198 new byte[128], // long challenge 199 }; 200 int[] purposes = { 201 KM_PURPOSE_SIGN, KM_PURPOSE_VERIFY, KM_PURPOSE_SIGN | KM_PURPOSE_VERIFY 202 }; 203 boolean[] devicePropertiesAttestationValues = {true, false}; 204 boolean[] includeValidityDatesValues = {true, false}; 205 206 for (int curveIndex = 0; curveIndex < curves.length; ++curveIndex) { 207 for (int challengeIndex = 0; challengeIndex < challenges.length; ++challengeIndex) { 208 for (int purposeIndex = 0; purposeIndex < purposes.length; ++purposeIndex) { 209 for (boolean includeValidityDates : includeValidityDatesValues) { 210 for (boolean devicePropertiesAttestation : devicePropertiesAttestationValues) { 211 try { 212 testEcAttestation(challenges[challengeIndex], includeValidityDates, 213 curves[curveIndex], keySizes[curveIndex], 214 purposes[purposeIndex], devicePropertiesAttestation); 215 } catch (Throwable e) { 216 boolean isIdAttestationFailure = 217 (e.getCause() instanceof KeyStoreException) 218 && KeyStoreException.ERROR_ID_ATTESTATION_FAILURE 219 == ((KeyStoreException) e.getCause()).getNumericErrorCode(); 220 if (devicePropertiesAttestation && isIdAttestationFailure) { 221 Log.i(TAG, "key attestation with device IDs not supported; " 222 + "test skipped"); 223 continue; 224 } 225 throw new Exception("Failed on curve " + curveIndex + 226 " challenge " + challengeIndex + " purpose " + 227 purposeIndex + " includeValidityDates " + 228 includeValidityDates + " and devicePropertiesAttestation " + 229 devicePropertiesAttestation, e); 230 } 231 } 232 } 233 } 234 } 235 } 236 } 237 assertPublicAttestationError(KeyStoreException keyStoreException, boolean devicePropertiesAttestation)238 private void assertPublicAttestationError(KeyStoreException keyStoreException, 239 boolean devicePropertiesAttestation) { 240 // Assert public failure information. 241 int errorCode = keyStoreException.getNumericErrorCode(); 242 String assertMessage = String.format( 243 "Error code was %d, device properties attestation? %b", 244 errorCode, devicePropertiesAttestation); 245 assertTrue(assertMessage, KeyStoreException.ERROR_INCORRECT_USAGE == errorCode 246 || (devicePropertiesAttestation 247 && KeyStoreException.ERROR_ID_ATTESTATION_FAILURE == errorCode)); 248 assertFalse(keyStoreException.isTransientFailure()); 249 } 250 251 @Test testEcAttestation_TooLargeChallenge()252 public void testEcAttestation_TooLargeChallenge() throws Exception { 253 if (!TestUtils.isAttestationSupported()) { 254 return; 255 } 256 257 boolean[] devicePropertiesAttestationValues = {true, false}; 258 for (boolean devicePropertiesAttestation : devicePropertiesAttestationValues) { 259 try { 260 testEcAttestation(new byte[129], true /* includeValidityDates */, "secp256r1", 256, 261 KM_PURPOSE_SIGN, devicePropertiesAttestation); 262 fail("Attestation challenges larger than 128 bytes should be rejected"); 263 } catch (ProviderException e) { 264 KeyStoreException cause = (KeyStoreException) e.getCause(); 265 assertTrue(KM_ERROR_INVALID_INPUT_LENGTH == cause.getErrorCode() || 266 (devicePropertiesAttestation 267 && KM_ERROR_CANNOT_ATTEST_IDS == cause.getErrorCode()) 268 ); 269 assertPublicAttestationError(cause, devicePropertiesAttestation); 270 } 271 } 272 } 273 274 @Test testEcAttestation_NoChallenge()275 public void testEcAttestation_NoChallenge() throws Exception { 276 boolean[] devicePropertiesAttestationValues = {true, false}; 277 for (boolean devicePropertiesAttestation : devicePropertiesAttestationValues) { 278 String keystoreAlias = "test_key"; 279 Date now = new Date(); 280 Date originationEnd = new Date(now.getTime() + ORIGINATION_TIME_OFFSET); 281 Date consumptionEnd = new Date(now.getTime() + CONSUMPTION_TIME_OFFSET); 282 KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(keystoreAlias, PURPOSE_SIGN) 283 .setAlgorithmParameterSpec(new ECGenParameterSpec("secp256r1")) 284 .setDigests(DIGEST_NONE, DIGEST_SHA256, DIGEST_SHA512) 285 .setAttestationChallenge(null) 286 .setKeyValidityStart(now) 287 .setKeyValidityForOriginationEnd(originationEnd) 288 .setKeyValidityForConsumptionEnd(consumptionEnd) 289 .setDevicePropertiesAttestationIncluded(devicePropertiesAttestation) 290 .build(); 291 292 generateKeyPair(KEY_ALGORITHM_EC, spec); 293 294 KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); 295 keyStore.load(null); 296 297 try { 298 Certificate certificates[] = keyStore.getCertificateChain(keystoreAlias); 299 assertEquals(1, certificates.length); 300 301 X509Certificate attestationCert = (X509Certificate) certificates[0]; 302 assertNull(attestationCert.getExtensionValue(Attestation.ASN1_OID)); 303 assertNull(attestationCert.getExtensionValue(Attestation.EAT_OID)); 304 } finally { 305 keyStore.deleteEntry(keystoreAlias); 306 } 307 } 308 } 309 testEcAttestation_DeviceLocked(Boolean expectStrongBox)310 private void testEcAttestation_DeviceLocked(Boolean expectStrongBox) throws Exception { 311 if (!TestUtils.isAttestationSupported()) { 312 return; 313 } 314 315 if (getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_PC)) 316 return; 317 318 String keystoreAlias = "test_key"; 319 Date now = new Date(); 320 Date originationEnd = new Date(now.getTime() + ORIGINATION_TIME_OFFSET); 321 Date consumptionEnd = new Date(now.getTime() + CONSUMPTION_TIME_OFFSET); 322 KeyGenParameterSpec.Builder builder = 323 new KeyGenParameterSpec.Builder(keystoreAlias, PURPOSE_SIGN) 324 .setAlgorithmParameterSpec(new ECGenParameterSpec("secp256r1")) 325 .setAttestationChallenge(new byte[128]) 326 .setKeyValidityStart(now) 327 .setKeyValidityForOriginationEnd(originationEnd) 328 .setKeyValidityForConsumptionEnd(consumptionEnd) 329 .setIsStrongBoxBacked(expectStrongBox); 330 331 if (expectStrongBox) { 332 builder.setDigests(DIGEST_NONE, DIGEST_SHA256); 333 } else { 334 builder.setDigests(DIGEST_NONE, DIGEST_SHA256, DIGEST_SHA512); 335 } 336 337 generateKeyPair(KEY_ALGORITHM_EC, builder.build()); 338 339 KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); 340 keyStore.load(null); 341 342 try { 343 Certificate certificates[] = keyStore.getCertificateChain(keystoreAlias); 344 verifyCertificateChain(certificates, expectStrongBox); 345 346 X509Certificate attestationCert = (X509Certificate) certificates[0]; 347 checkDeviceLocked(Attestation.loadFromCertificate(attestationCert)); 348 } finally { 349 keyStore.deleteEntry(keystoreAlias); 350 } 351 } 352 353 @RestrictedBuildTest 354 @RequiresDevice 355 @Test testEcAttestation_DeviceLocked()356 public void testEcAttestation_DeviceLocked() throws Exception { 357 testEcAttestation_DeviceLocked(false /* expectStrongBox */); 358 } 359 360 @RestrictedBuildTest 361 @RequiresDevice 362 @Test testEcAttestation_DeviceLockedStrongbox()363 public void testEcAttestation_DeviceLockedStrongbox() throws Exception { 364 if (!TestUtils.hasStrongBox(getContext())) 365 return; 366 367 testEcAttestation_DeviceLocked(true /* expectStrongBox */); 368 } 369 370 @Test testAttestationKmVersionMatchesFeatureVersion()371 public void testAttestationKmVersionMatchesFeatureVersion() throws Exception { 372 if (getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_PC)) 373 return; 374 375 String keystoreAlias = "test_key"; 376 Date now = new Date(); 377 Date originationEnd = new Date(now.getTime() + ORIGINATION_TIME_OFFSET); 378 Date consumptionEnd = new Date(now.getTime() + CONSUMPTION_TIME_OFFSET); 379 KeyGenParameterSpec.Builder builder = 380 new KeyGenParameterSpec.Builder(keystoreAlias, PURPOSE_SIGN) 381 .setAlgorithmParameterSpec(new ECGenParameterSpec("secp256r1")) 382 .setAttestationChallenge(new byte[128]) 383 .setKeyValidityStart(now) 384 .setKeyValidityForOriginationEnd(originationEnd) 385 .setKeyValidityForConsumptionEnd(consumptionEnd); 386 387 generateKeyPair(KEY_ALGORITHM_EC, builder.build()); 388 389 KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); 390 keyStore.load(null); 391 392 try { 393 Certificate certificates[] = keyStore.getCertificateChain(keystoreAlias); 394 verifyCertificateChain(certificates, false /* expectStrongBox */); 395 X509Certificate attestationCert = (X509Certificate) certificates[0]; 396 Attestation attestation = Attestation.loadFromCertificate(attestationCert); 397 int kmVersionFromAttestation = attestation.keymasterVersion; 398 int keyStoreFeatureVersion = TestUtils.getFeatureVersionKeystore(getContext()); 399 400 // Feature Version is required on devices launching with Android 12 (API Level 401 // 31) but may be reported on devices launching with an earlier version. If it's 402 // present, it must match what is reported in attestation. 403 int firstApiLevel = SystemProperties.getInt("ro.product.first_api_level", 0); 404 if (firstApiLevel >= 31) { 405 assertNotEquals(0, keyStoreFeatureVersion); 406 } 407 if (keyStoreFeatureVersion != 0) { 408 assertEquals(kmVersionFromAttestation, keyStoreFeatureVersion); 409 } 410 } finally { 411 keyStore.deleteEntry(keystoreAlias); 412 } 413 } 414 415 @Test testAttestationKmVersionMatchesFeatureVersionStrongBox()416 public void testAttestationKmVersionMatchesFeatureVersionStrongBox() throws Exception { 417 if (getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_PC)) 418 return; 419 420 int keyStoreFeatureVersionStrongBox = 421 TestUtils.getFeatureVersionKeystoreStrongBox(getContext()); 422 423 if (!TestUtils.hasStrongBox(getContext())) { 424 // If there's no StrongBox, ensure there's no feature version for it. 425 assertEquals(0, keyStoreFeatureVersionStrongBox); 426 return; 427 } 428 429 String keystoreAlias = "test_key"; 430 Date now = new Date(); 431 Date originationEnd = new Date(now.getTime() + ORIGINATION_TIME_OFFSET); 432 Date consumptionEnd = new Date(now.getTime() + CONSUMPTION_TIME_OFFSET); 433 KeyGenParameterSpec.Builder builder = 434 new KeyGenParameterSpec.Builder(keystoreAlias, PURPOSE_SIGN) 435 .setAlgorithmParameterSpec(new ECGenParameterSpec("secp256r1")) 436 .setAttestationChallenge(new byte[128]) 437 .setKeyValidityStart(now) 438 .setKeyValidityForOriginationEnd(originationEnd) 439 .setKeyValidityForConsumptionEnd(consumptionEnd) 440 .setIsStrongBoxBacked(true); 441 442 generateKeyPair(KEY_ALGORITHM_EC, builder.build()); 443 444 KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); 445 keyStore.load(null); 446 447 try { 448 Certificate certificates[] = keyStore.getCertificateChain(keystoreAlias); 449 verifyCertificateChain(certificates, true /* expectStrongBox */); 450 X509Certificate attestationCert = (X509Certificate) certificates[0]; 451 Attestation attestation = Attestation.loadFromCertificate(attestationCert); 452 int kmVersionFromAttestation = attestation.keymasterVersion; 453 454 // Feature Version is required on devices launching with Android 12 (API Level 455 // 31) but may be reported on devices launching with an earlier version. If it's 456 // present, it must match what is reported in attestation. 457 int firstApiLevel = SystemProperties.getInt("ro.product.first_api_level", 0); 458 if (firstApiLevel >= 31) { 459 assertNotEquals(0, keyStoreFeatureVersionStrongBox); 460 } 461 if (keyStoreFeatureVersionStrongBox != 0) { 462 assertEquals(kmVersionFromAttestation, keyStoreFeatureVersionStrongBox); 463 } 464 } finally { 465 keyStore.deleteEntry(keystoreAlias); 466 } 467 } 468 469 @Test testEcAttestation_KeyStoreExceptionWhenRequestingUniqueId()470 public void testEcAttestation_KeyStoreExceptionWhenRequestingUniqueId() throws Exception { 471 String keystoreAlias = "test_key"; 472 KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(keystoreAlias, PURPOSE_SIGN) 473 .setAlgorithmParameterSpec(new ECGenParameterSpec("secp256r1")) 474 .setDigests(DIGEST_NONE, DIGEST_SHA256, DIGEST_SHA512) 475 .setAttestationChallenge(new byte[128]) 476 .setUniqueIdIncluded(true) 477 .build(); 478 479 try { 480 generateKeyPair(KEY_ALGORITHM_EC, spec); 481 fail("Attestation should have failed."); 482 } catch (ProviderException e) { 483 // Attestation is expected to fail because of lack of permissions. 484 KeyStoreException cause = (KeyStoreException) e.getCause(); 485 assertEquals(KM_ERROR_PERMISSION_DENIED, cause.getErrorCode()); 486 // Assert public failure information. 487 assertEquals(KeyStoreException.ERROR_PERMISSION_DENIED, cause.getNumericErrorCode()); 488 assertFalse(cause.isTransientFailure()); 489 } finally { 490 KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); 491 keyStore.load(null); 492 keyStore.deleteEntry(keystoreAlias); 493 } 494 } 495 496 @Test testEcAttestation_UniqueIdWorksWithCorrectPermission()497 public void testEcAttestation_UniqueIdWorksWithCorrectPermission() throws Exception { 498 assumeTrue("Device doesn't have secure lock screen", 499 TestUtils.hasSecureLockScreen(getContext())); 500 501 String keystoreAlias = "test_key"; 502 KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(keystoreAlias, PURPOSE_SIGN) 503 .setAlgorithmParameterSpec(new ECGenParameterSpec("secp256r1")) 504 .setDigests(DIGEST_NONE, DIGEST_SHA256, DIGEST_SHA512) 505 .setAttestationChallenge(new byte[128]) 506 .setUniqueIdIncluded(true) 507 .build(); 508 509 KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); 510 keyStore.load(null); 511 512 try (PermissionContext c = TestApis.permissions().withPermission( 513 "android.permission.REQUEST_UNIQUE_ID_ATTESTATION")) { 514 generateKeyPair(KEY_ALGORITHM_EC, spec); 515 Certificate certificates[] = keyStore.getCertificateChain(keystoreAlias); 516 Attestation attestation = Attestation.loadFromCertificate((X509Certificate) certificates[0]); 517 byte[] firstUniqueId = attestation.getUniqueId(); 518 assertTrue("UniqueId must not be empty", firstUniqueId.length > 0); 519 520 // The unique id rotates (30 days in the default implementation), and it's possible to 521 // get a spurious failure if the test runs exactly when the rotation occurs. Allow a 522 // single retry, just in case. 523 byte[] secondUniqueId = null; 524 for (int i = 0; i < 2; ++i) { 525 keyStore.deleteEntry(keystoreAlias); 526 527 generateKeyPair(KEY_ALGORITHM_EC, spec); 528 certificates = keyStore.getCertificateChain(keystoreAlias); 529 attestation = Attestation.loadFromCertificate((X509Certificate) certificates[0]); 530 secondUniqueId = attestation.getUniqueId(); 531 532 if (Arrays.equals(firstUniqueId, secondUniqueId)) { 533 break; 534 } else { 535 firstUniqueId = secondUniqueId; 536 secondUniqueId = null; 537 } 538 } 539 assertTrue("UniqueIds must be consistent", 540 Arrays.equals(firstUniqueId, secondUniqueId)); 541 542 } finally { 543 keyStore.deleteEntry(keystoreAlias); 544 } 545 } 546 547 @RequiresDevice 548 @Test testRsaAttestation()549 public void testRsaAttestation() throws Exception { 550 if (!TestUtils.isAttestationSupported()) { 551 return; 552 } 553 554 if (getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_PC)) 555 return; 556 557 int[] keySizes = { // Smallish sizes to keep test runtimes down. 558 512, 768, 1024 559 }; 560 byte[][] challenges = { 561 new byte[0], // empty challenge 562 "challenge".getBytes(), // short challenge 563 new byte[128] // long challenge 564 }; 565 int[] purposes = { 566 PURPOSE_SIGN | PURPOSE_VERIFY, 567 PURPOSE_ENCRYPT | PURPOSE_DECRYPT, 568 }; 569 String[][] encryptionPaddingModes = { 570 { 571 ENCRYPTION_PADDING_NONE 572 }, 573 { 574 ENCRYPTION_PADDING_RSA_OAEP, 575 }, 576 { 577 ENCRYPTION_PADDING_RSA_PKCS1, 578 }, 579 { 580 ENCRYPTION_PADDING_RSA_OAEP, 581 ENCRYPTION_PADDING_RSA_PKCS1, 582 }, 583 }; 584 String[][] signaturePaddingModes = { 585 { 586 SIGNATURE_PADDING_RSA_PKCS1, 587 }, 588 { 589 SIGNATURE_PADDING_RSA_PSS, 590 }, 591 { 592 SIGNATURE_PADDING_RSA_PKCS1, 593 SIGNATURE_PADDING_RSA_PSS, 594 }, 595 }; 596 boolean[] devicePropertiesAttestationValues = {true, false}; 597 598 for (boolean devicePropertiesAttestation : devicePropertiesAttestationValues) { 599 for (int keySize : keySizes) { 600 for (byte[] challenge : challenges) { 601 for (int purpose : purposes) { 602 if (isEncryptionPurpose(purpose)) { 603 testRsaAttestations(keySize, challenge, purpose, encryptionPaddingModes, 604 devicePropertiesAttestation); 605 } else { 606 testRsaAttestations(keySize, challenge, purpose, signaturePaddingModes, 607 devicePropertiesAttestation); 608 } 609 } 610 } 611 } 612 } 613 } 614 615 @Test testRsaAttestation_TooLargeChallenge()616 public void testRsaAttestation_TooLargeChallenge() throws Exception { 617 if (!TestUtils.isAttestationSupported()) { 618 return; 619 } 620 621 boolean[] devicePropertiesAttestationValues = {true, false}; 622 for (boolean devicePropertiesAttestation : devicePropertiesAttestationValues) { 623 try { 624 testRsaAttestation(new byte[129], true /* includeValidityDates */, 512, 625 PURPOSE_SIGN, 626 null /* paddingModes; may be empty because we'll never test them */, 627 devicePropertiesAttestation); 628 fail("Attestation challenges larger than 128 bytes should be rejected"); 629 } catch(ProviderException e){ 630 KeyStoreException cause = (KeyStoreException) e.getCause(); 631 assertTrue(KM_ERROR_INVALID_INPUT_LENGTH == cause.getErrorCode() || 632 (devicePropertiesAttestation 633 && KM_ERROR_CANNOT_ATTEST_IDS == cause.getErrorCode()) 634 ); 635 assertPublicAttestationError(cause, devicePropertiesAttestation); 636 } 637 } 638 } 639 640 @Test testRsaAttestation_NoChallenge()641 public void testRsaAttestation_NoChallenge() throws Exception { 642 boolean[] devicePropertiesAttestationValues = {true, false}; 643 for (boolean devicePropertiesAttestation : devicePropertiesAttestationValues) { 644 String keystoreAlias = "test_key"; 645 Date now = new Date(); 646 Date originationEnd = new Date(now.getTime() + ORIGINATION_TIME_OFFSET); 647 Date consumptionEnd = new Date(now.getTime() + CONSUMPTION_TIME_OFFSET); 648 KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(keystoreAlias, PURPOSE_SIGN) 649 .setDigests(DIGEST_NONE, DIGEST_SHA256, DIGEST_SHA512) 650 .setAttestationChallenge(null) 651 .setKeyValidityStart(now) 652 .setKeyValidityForOriginationEnd(originationEnd) 653 .setKeyValidityForConsumptionEnd(consumptionEnd) 654 .setDevicePropertiesAttestationIncluded(devicePropertiesAttestation) 655 .build(); 656 657 generateKeyPair(KEY_ALGORITHM_RSA, spec); 658 659 KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); 660 keyStore.load(null); 661 662 try { 663 Certificate certificates[] = keyStore.getCertificateChain(keystoreAlias); 664 assertEquals(1, certificates.length); 665 666 X509Certificate attestationCert = (X509Certificate) certificates[0]; 667 assertNull(attestationCert.getExtensionValue(Attestation.ASN1_OID)); 668 } finally { 669 keyStore.deleteEntry(keystoreAlias); 670 } 671 } 672 } 673 testRsaAttestation_DeviceLocked(Boolean expectStrongBox)674 private void testRsaAttestation_DeviceLocked(Boolean expectStrongBox) throws Exception { 675 if (!TestUtils.isAttestationSupported()) { 676 return; 677 } 678 679 if (getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_PC)) 680 return; 681 682 String keystoreAlias = "test_key"; 683 Date now = new Date(); 684 Date originationEnd = new Date(now.getTime() + ORIGINATION_TIME_OFFSET); 685 Date consumptionEnd = new Date(now.getTime() + CONSUMPTION_TIME_OFFSET); 686 KeyGenParameterSpec.Builder builder = 687 new KeyGenParameterSpec.Builder(keystoreAlias, PURPOSE_SIGN) 688 .setDigests(DIGEST_NONE, DIGEST_SHA256, DIGEST_SHA512) 689 .setAttestationChallenge("challenge".getBytes()) 690 .setKeyValidityStart(now) 691 .setKeyValidityForOriginationEnd(originationEnd) 692 .setKeyValidityForConsumptionEnd(consumptionEnd) 693 .setIsStrongBoxBacked(expectStrongBox); 694 695 if (expectStrongBox) { 696 builder.setDigests(DIGEST_NONE, DIGEST_SHA256); 697 } else { 698 builder.setDigests(DIGEST_NONE, DIGEST_SHA256, DIGEST_SHA512); 699 } 700 701 generateKeyPair(KEY_ALGORITHM_RSA, builder.build()); 702 703 KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); 704 keyStore.load(null); 705 706 try { 707 Certificate certificates[] = keyStore.getCertificateChain(keystoreAlias); 708 verifyCertificateChain(certificates, expectStrongBox); 709 710 X509Certificate attestationCert = (X509Certificate) certificates[0]; 711 checkDeviceLocked(Attestation.loadFromCertificate(attestationCert)); 712 } finally { 713 keyStore.deleteEntry(keystoreAlias); 714 } 715 } 716 717 @RestrictedBuildTest 718 @RequiresDevice // Emulators have no place to store the needed key 719 @Test testRsaAttestation_DeviceLocked()720 public void testRsaAttestation_DeviceLocked() throws Exception { 721 testRsaAttestation_DeviceLocked(false /* expectStrongbox */); 722 } 723 724 @RestrictedBuildTest 725 @RequiresDevice // Emulators have no place to store the needed key 726 @Test testRsaAttestation_DeviceLockedStrongbox()727 public void testRsaAttestation_DeviceLockedStrongbox() throws Exception { 728 if (!TestUtils.hasStrongBox(getContext())) 729 return; 730 731 testRsaAttestation_DeviceLocked(true /* expectStrongbox */); 732 } 733 734 @Test testAesAttestation()735 public void testAesAttestation() throws Exception { 736 boolean[] devicePropertiesAttestationValues = {true, false}; 737 for (boolean devicePropertiesAttestation : devicePropertiesAttestationValues) { 738 String keystoreAlias = "test_key"; 739 KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(keystoreAlias, 740 PURPOSE_ENCRYPT) 741 .setBlockModes(KeyProperties.BLOCK_MODE_GCM) 742 .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE) 743 .setAttestationChallenge(new byte[0]) 744 .setDevicePropertiesAttestationIncluded(devicePropertiesAttestation) 745 .build(); 746 generateKey(spec, KeyProperties.KEY_ALGORITHM_AES); 747 748 KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); 749 keyStore.load(null); 750 try { 751 assertNull(keyStore.getCertificateChain(keystoreAlias)); 752 } finally { 753 keyStore.deleteEntry(keystoreAlias); 754 } 755 } 756 } 757 758 @Test testHmacAttestation()759 public void testHmacAttestation() throws Exception { 760 boolean[] devicePropertiesAttestationValues = {true, false}; 761 for (boolean devicePropertiesAttestation : devicePropertiesAttestationValues) { 762 String keystoreAlias = "test_key"; 763 KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(keystoreAlias, PURPOSE_SIGN) 764 .setDevicePropertiesAttestationIncluded(devicePropertiesAttestation) 765 .build(); 766 767 generateKey(spec, KeyProperties.KEY_ALGORITHM_HMAC_SHA256); 768 769 KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); 770 keyStore.load(null); 771 try { 772 assertNull(keyStore.getCertificateChain(keystoreAlias)); 773 } finally { 774 keyStore.deleteEntry(keystoreAlias); 775 } 776 } 777 } 778 testRsaAttestations(int keySize, byte[] challenge, int purpose, String[][] paddingModes, boolean devicePropertiesAttestation)779 private void testRsaAttestations(int keySize, byte[] challenge, int purpose, 780 String[][] paddingModes, boolean devicePropertiesAttestation) throws Exception { 781 for (String[] paddings : paddingModes) { 782 try { 783 testRsaAttestation(challenge, true /* includeValidityDates */, keySize, purpose, 784 paddings, devicePropertiesAttestation); 785 testRsaAttestation(challenge, false /* includeValidityDates */, keySize, purpose, 786 paddings, devicePropertiesAttestation); 787 } catch (Throwable e) { 788 boolean isIdAttestationFailure = 789 (e.getCause() instanceof KeyStoreException) 790 && KeyStoreException.ERROR_ID_ATTESTATION_FAILURE 791 == ((KeyStoreException) e.getCause()).getNumericErrorCode(); 792 if (devicePropertiesAttestation && isIdAttestationFailure) { 793 Log.i(TAG, "key attestation with device IDs not supported; test skipped"); 794 continue; 795 } 796 throw new Exception("Failed on key size " + keySize + " challenge [" + 797 new String(challenge) + "], purposes " + 798 buildPurposeSet(purpose) + " paddings " + 799 ImmutableSet.copyOf(paddings) + " and devicePropertiesAttestation " 800 + devicePropertiesAttestation, 801 e); 802 } 803 } 804 } 805 806 @Test testDeviceIdAttestation()807 public void testDeviceIdAttestation() throws Exception { 808 testDeviceIdAttestationFailure(AttestationUtils.ID_TYPE_SERIAL, null); 809 testDeviceIdAttestationFailure(AttestationUtils.ID_TYPE_IMEI, "Unable to retrieve IMEI"); 810 testDeviceIdAttestationFailure(AttestationUtils.ID_TYPE_MEID, "Unable to retrieve MEID"); 811 } 812 813 @SuppressWarnings("deprecation") testRsaAttestation(byte[] challenge, boolean includeValidityDates, int keySize, int purposes, String[] paddingModes, boolean devicePropertiesAttestation)814 private void testRsaAttestation(byte[] challenge, boolean includeValidityDates, int keySize, 815 int purposes, String[] paddingModes, boolean devicePropertiesAttestation) 816 throws Exception { 817 Log.i(TAG, "RSA key attestation with: challenge " + Arrays.toString(challenge) + 818 " / includeValidityDates " + includeValidityDates + " / keySize " + keySize + 819 " / purposes " + purposes + " / paddingModes " + Arrays.toString(paddingModes) + 820 " / devicePropertiesAttestation " + devicePropertiesAttestation); 821 822 String keystoreAlias = "test_key"; 823 Date startTime = new Date(); 824 Date originationEnd = new Date(startTime.getTime() + ORIGINATION_TIME_OFFSET); 825 Date consumptionEnd = new Date(startTime.getTime() + CONSUMPTION_TIME_OFFSET); 826 KeyGenParameterSpec.Builder builder = 827 new KeyGenParameterSpec.Builder(keystoreAlias, purposes) 828 .setKeySize(keySize) 829 .setDigests(DIGEST_NONE, DIGEST_SHA256, DIGEST_SHA512) 830 .setAttestationChallenge(challenge) 831 .setDevicePropertiesAttestationIncluded(devicePropertiesAttestation); 832 833 if (includeValidityDates) { 834 builder.setKeyValidityStart(startTime) 835 .setKeyValidityForOriginationEnd(originationEnd) 836 .setKeyValidityForConsumptionEnd(consumptionEnd); 837 } 838 if (isEncryptionPurpose(purposes)) { 839 builder.setEncryptionPaddings(paddingModes); 840 // Because we sometimes set "no padding", allow non-randomized encryption. 841 builder.setRandomizedEncryptionRequired(false); 842 } 843 if (isSignaturePurpose(purposes)) { 844 builder.setSignaturePaddings(paddingModes); 845 } 846 847 generateKeyPair(KEY_ALGORITHM_RSA, builder.build()); 848 849 KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); 850 keyStore.load(null); 851 852 try { 853 Certificate certificates[] = keyStore.getCertificateChain(keystoreAlias); 854 verifyCertificateChain(certificates, false /* expectStrongBox */); 855 856 X509Certificate attestationCert = (X509Certificate) certificates[0]; 857 Attestation attestation = Attestation.loadFromCertificate(attestationCert); 858 859 checkRsaKeyDetails(attestation, keySize, purposes, 860 ImmutableSet.copyOf(paddingModes)); 861 checkKeyUsage(attestationCert, purposes); 862 checkKeyIndependentAttestationInfo(challenge, purposes, startTime, 863 includeValidityDates, devicePropertiesAttestation, attestation); 864 } finally { 865 keyStore.deleteEntry(keystoreAlias); 866 } 867 } 868 checkKeyUsage(X509Certificate attestationCert, int purposes)869 private void checkKeyUsage(X509Certificate attestationCert, int purposes) { 870 871 boolean[] expectedKeyUsage = new boolean[KEY_USAGE_BITSTRING_LENGTH]; 872 if (isSignaturePurpose(purposes)) { 873 expectedKeyUsage[KEY_USAGE_DIGITAL_SIGNATURE_BIT_OFFSET] = true; 874 } 875 if (isEncryptionPurpose(purposes)) { 876 expectedKeyUsage[KEY_USAGE_KEY_ENCIPHERMENT_BIT_OFFSET] = true; 877 expectedKeyUsage[KEY_USAGE_DATA_ENCIPHERMENT_BIT_OFFSET] = true; 878 } 879 assertThat(attestationCert.getKeyUsage(), is(expectedKeyUsage)); 880 } 881 882 @SuppressWarnings("deprecation") testEcAttestation(byte[] challenge, boolean includeValidityDates, String ecCurve, int keySize, int purposes, boolean devicePropertiesAttestation)883 private void testEcAttestation(byte[] challenge, boolean includeValidityDates, String ecCurve, 884 int keySize, int purposes, boolean devicePropertiesAttestation) throws Exception { 885 Log.i(TAG, "EC key attestation with: challenge " + Arrays.toString(challenge) + 886 " / includeValidityDates " + includeValidityDates + " / ecCurve " + ecCurve + 887 " / keySize " + keySize + " / purposes " + purposes + 888 " / devicePropertiesAttestation " + devicePropertiesAttestation); 889 890 String keystoreAlias = "test_key"; 891 Date startTime = new Date(); 892 Date originationEnd = new Date(startTime.getTime() + ORIGINATION_TIME_OFFSET); 893 Date consumptionEnd = new Date(startTime.getTime() + CONSUMPTION_TIME_OFFSET); 894 KeyGenParameterSpec.Builder builder = new KeyGenParameterSpec.Builder(keystoreAlias, 895 purposes) 896 .setAlgorithmParameterSpec(new ECGenParameterSpec(ecCurve)) 897 .setDigests(DIGEST_NONE, DIGEST_SHA256, DIGEST_SHA512) 898 .setAttestationChallenge(challenge) 899 .setDevicePropertiesAttestationIncluded(devicePropertiesAttestation); 900 901 if (includeValidityDates) { 902 builder.setKeyValidityStart(startTime) 903 .setKeyValidityForOriginationEnd(originationEnd) 904 .setKeyValidityForConsumptionEnd(consumptionEnd); 905 } 906 907 generateKeyPair(KEY_ALGORITHM_EC, builder.build()); 908 909 KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); 910 keyStore.load(null); 911 912 try { 913 Certificate certificates[] = keyStore.getCertificateChain(keystoreAlias); 914 verifyCertificateChain(certificates, false /* expectStrongBox */); 915 916 X509Certificate attestationCert = (X509Certificate) certificates[0]; 917 Attestation attestation = Attestation.loadFromCertificate(attestationCert); 918 919 checkEcKeyDetails(attestation, ecCurve, keySize); 920 checkKeyUsage(attestationCert, purposes); 921 checkKeyIndependentAttestationInfo(challenge, purposes, startTime, 922 includeValidityDates, devicePropertiesAttestation, attestation); 923 } finally { 924 keyStore.deleteEntry(keystoreAlias); 925 } 926 } 927 checkAttestationApplicationId(Attestation attestation)928 private void checkAttestationApplicationId(Attestation attestation) 929 throws NoSuchAlgorithmException, NameNotFoundException { 930 AttestationApplicationId aaid = null; 931 int kmVersion = attestation.getKeymasterVersion(); 932 assertNull(attestation.getTeeEnforced().getAttestationApplicationId()); 933 aaid = attestation.getSoftwareEnforced().getAttestationApplicationId(); 934 935 if (kmVersion >= 3) { 936 // must be present and correct 937 assertNotNull(aaid); 938 assertEquals(new AttestationApplicationId(getContext()), aaid); 939 } else { 940 // may be present and 941 // must be correct if present 942 if (aaid != null) { 943 assertEquals(new AttestationApplicationId(getContext()), aaid); 944 } 945 } 946 } 947 checkAttestationDeviceProperties(boolean devicePropertiesAttestation, Attestation attestation)948 private void checkAttestationDeviceProperties(boolean devicePropertiesAttestation, 949 Attestation attestation) { 950 final AuthorizationList keyDetailsList; 951 final AuthorizationList nonKeyDetailsList; 952 if (attestation.getKeymasterSecurityLevel() == KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT) { 953 keyDetailsList = attestation.getTeeEnforced(); 954 nonKeyDetailsList = attestation.getSoftwareEnforced(); 955 } else { 956 keyDetailsList = attestation.getSoftwareEnforced(); 957 nonKeyDetailsList = attestation.getTeeEnforced(); 958 } 959 960 if (devicePropertiesAttestation) { 961 assertEquals(Build.BRAND, keyDetailsList.getBrand()); 962 assertEquals(Build.DEVICE, keyDetailsList.getDevice()); 963 assertEquals(Build.PRODUCT, keyDetailsList.getProduct()); 964 assertEquals(Build.MANUFACTURER, keyDetailsList.getManufacturer()); 965 assertEquals(Build.MODEL, keyDetailsList.getModel()); 966 } else { 967 assertNull(keyDetailsList.getBrand()); 968 assertNull(keyDetailsList.getDevice()); 969 assertNull(keyDetailsList.getProduct()); 970 assertNull(keyDetailsList.getManufacturer()); 971 assertNull(keyDetailsList.getModel()); 972 } 973 assertNull(nonKeyDetailsList.getBrand()); 974 assertNull(nonKeyDetailsList.getDevice()); 975 assertNull(nonKeyDetailsList.getProduct()); 976 assertNull(nonKeyDetailsList.getManufacturer()); 977 assertNull(nonKeyDetailsList.getModel()); 978 } 979 checkAttestationNoUniqueIds(Attestation attestation)980 private void checkAttestationNoUniqueIds(Attestation attestation) { 981 assertNull(attestation.getTeeEnforced().getImei()); 982 assertNull(attestation.getTeeEnforced().getMeid()); 983 assertNull(attestation.getTeeEnforced().getSerialNumber()); 984 assertNull(attestation.getSoftwareEnforced().getImei()); 985 assertNull(attestation.getSoftwareEnforced().getMeid()); 986 assertNull(attestation.getSoftwareEnforced().getSerialNumber()); 987 } 988 checkKeyIndependentAttestationInfo(byte[] challenge, int purposes, Date startTime, boolean includesValidityDates, boolean devicePropertiesAttestation, Attestation attestation)989 private void checkKeyIndependentAttestationInfo(byte[] challenge, int purposes, Date startTime, 990 boolean includesValidityDates, boolean devicePropertiesAttestation, 991 Attestation attestation) throws NoSuchAlgorithmException, NameNotFoundException { 992 checkUnexpectedOids(attestation); 993 checkAttestationSecurityLevelDependentParams(attestation); 994 assertNotNull(attestation.getAttestationChallenge()); 995 assertThat(attestation.getAttestationChallenge(), is(challenge)); 996 // In EAT, this is null if not filled in. In ASN.1, this is an array with length 0. 997 if (attestation.getUniqueId() != null) { 998 assertEquals(0, attestation.getUniqueId().length); 999 } 1000 checkPurposes(attestation, purposes); 1001 checkDigests(attestation, 1002 ImmutableSet.of(KM_DIGEST_NONE, KM_DIGEST_SHA_2_256, KM_DIGEST_SHA_2_512)); 1003 checkValidityPeriod(attestation, startTime, includesValidityDates); 1004 checkFlags(attestation); 1005 checkOrigin(attestation); 1006 checkAttestationApplicationId(attestation); 1007 checkAttestationDeviceProperties(devicePropertiesAttestation, attestation); 1008 checkAttestationNoUniqueIds(attestation); 1009 } 1010 checkUnexpectedOids(Attestation attestation)1011 private void checkUnexpectedOids(Attestation attestation) { 1012 assertThat("Attestations must not contain any extra data", 1013 attestation.getUnexpectedExtensionOids(), is(empty())); 1014 } 1015 getSystemPatchLevel()1016 private int getSystemPatchLevel() { 1017 Matcher matcher = OS_PATCH_LEVEL_STRING_PATTERN.matcher(Build.VERSION.SECURITY_PATCH); 1018 assertTrue(matcher.matches()); 1019 String year_string = matcher.group(OS_PATCH_LEVEL_YEAR_GROUP_NAME); 1020 String month_string = matcher.group(OS_PATCH_LEVEL_MONTH_GROUP_NAME); 1021 int patch_level = Integer.parseInt(year_string) * 100 + Integer.parseInt(month_string); 1022 return patch_level; 1023 } 1024 getSystemOsVersion()1025 private int getSystemOsVersion() { 1026 return parseSystemOsVersion(Build.VERSION.RELEASE); 1027 } 1028 parseSystemOsVersion(String versionString)1029 private int parseSystemOsVersion(String versionString) { 1030 Matcher matcher = OS_VERSION_STRING_PATTERN.matcher(versionString); 1031 if (!matcher.matches()) { 1032 return 0; 1033 } 1034 1035 int version = 0; 1036 String major_string = matcher.group(OS_MAJOR_VERSION_MATCH_GROUP_NAME); 1037 String minor_string = matcher.group(OS_MINOR_VERSION_MATCH_GROUP_NAME); 1038 String subminor_string = matcher.group(OS_SUBMINOR_VERSION_MATCH_GROUP_NAME); 1039 if (major_string != null) { 1040 version += Integer.parseInt(major_string) * 10000; 1041 } 1042 if (minor_string != null) { 1043 version += Integer.parseInt(minor_string) * 100; 1044 } 1045 if (subminor_string != null) { 1046 version += Integer.parseInt(subminor_string); 1047 } 1048 return version; 1049 } 1050 checkOrigin(Attestation attestation)1051 private void checkOrigin(Attestation attestation) { 1052 assertTrue("Origin must be defined", 1053 attestation.getSoftwareEnforced().getOrigin() != null || 1054 attestation.getTeeEnforced().getOrigin() != null); 1055 if (attestation.getKeymasterVersion() != 0) { 1056 assertTrue("Origin may not be defined in both SW and TEE, except on keymaster0", 1057 attestation.getSoftwareEnforced().getOrigin() == null || 1058 attestation.getTeeEnforced().getOrigin() == null); 1059 } 1060 1061 if (attestation.getKeymasterSecurityLevel() == KM_SECURITY_LEVEL_SOFTWARE) { 1062 assertThat(attestation.getSoftwareEnforced().getOrigin(), is(KM_ORIGIN_GENERATED)); 1063 } else if (attestation.getKeymasterVersion() == 0) { 1064 assertThat(attestation.getTeeEnforced().getOrigin(), is(KM_ORIGIN_UNKNOWN)); 1065 } else { 1066 assertThat(attestation.getTeeEnforced().getOrigin(), is(KM_ORIGIN_GENERATED)); 1067 } 1068 } 1069 checkFlags(Attestation attestation)1070 private void checkFlags(Attestation attestation) { 1071 assertFalse("All applications was not requested", 1072 attestation.getSoftwareEnforced().isAllApplications()); 1073 assertFalse("All applications was not requested", 1074 attestation.getTeeEnforced().isAllApplications()); 1075 assertFalse("Allow while on body was not requested", 1076 attestation.getSoftwareEnforced().isAllowWhileOnBody()); 1077 assertFalse("Allow while on body was not requested", 1078 attestation.getTeeEnforced().isAllowWhileOnBody()); 1079 assertNull("Auth binding was not requiested", 1080 attestation.getSoftwareEnforced().getUserAuthType()); 1081 assertNull("Auth binding was not requiested", 1082 attestation.getTeeEnforced().getUserAuthType()); 1083 assertTrue("noAuthRequired must be true", 1084 attestation.getSoftwareEnforced().isNoAuthRequired() 1085 || attestation.getTeeEnforced().isNoAuthRequired()); 1086 assertFalse("auth is either software or TEE", 1087 attestation.getSoftwareEnforced().isNoAuthRequired() 1088 && attestation.getTeeEnforced().isNoAuthRequired()); 1089 assertFalse("Software cannot implement rollback resistance", 1090 attestation.getSoftwareEnforced().isRollbackResistant()); 1091 } 1092 checkValidityPeriod(Attestation attestation, Date startTime, boolean includesValidityDates)1093 private void checkValidityPeriod(Attestation attestation, Date startTime, 1094 boolean includesValidityDates) { 1095 AuthorizationList validityPeriodList = attestation.getSoftwareEnforced(); 1096 AuthorizationList nonValidityPeriodList = attestation.getTeeEnforced(); 1097 1098 // A bug in Android S leads Android S devices with KeyMint1 not to add a creationDateTime. 1099 boolean creationDateTimeBroken = 1100 Build.VERSION.SDK_INT == Build.VERSION_CODES.S && 1101 attestation.getKeymasterVersion() == Attestation.KM_VERSION_KEYMINT_1; 1102 1103 if (!creationDateTimeBroken) { 1104 assertNull(nonValidityPeriodList.getCreationDateTime()); 1105 1106 Date creationDateTime = validityPeriodList.getCreationDateTime(); 1107 1108 boolean requireCreationDateTime = 1109 attestation.getKeymasterVersion() >= Attestation.KM_VERSION_KEYMINT_1; 1110 1111 // b/232078430: skip time checks in Android T due to unfixed bug. 1112 boolean doTimeChecks = false; 1113 1114 if (doTimeChecks && (requireCreationDateTime || creationDateTime != null)) { 1115 assertNotNull(creationDateTime); 1116 1117 assertTrue("Test start time (" + startTime.getTime() + ") and key creation time (" + 1118 creationDateTime.getTime() + ") should be close", 1119 Math.abs(creationDateTime.getTime() - startTime.getTime()) <= 2000); 1120 1121 // Allow 1 second leeway in case of nearest-second rounding. 1122 Date now = new Date(); 1123 assertTrue("Key creation time (" + creationDateTime.getTime() + ") must be now (" + 1124 now.getTime() + ") or earlier.", 1125 now.getTime() >= (creationDateTime.getTime() - 1000)); 1126 } 1127 } 1128 1129 if (includesValidityDates) { 1130 Date activeDateTime = validityPeriodList.getActiveDateTime(); 1131 Date originationExpirationDateTime = validityPeriodList.getOriginationExpireDateTime(); 1132 Date usageExpirationDateTime = validityPeriodList.getUsageExpireDateTime(); 1133 1134 assertNotNull(activeDateTime); 1135 assertNotNull(originationExpirationDateTime); 1136 assertNotNull(usageExpirationDateTime); 1137 1138 assertNull(nonValidityPeriodList.getActiveDateTime()); 1139 assertNull(nonValidityPeriodList.getOriginationExpireDateTime()); 1140 assertNull(nonValidityPeriodList.getUsageExpireDateTime()); 1141 1142 assertThat(originationExpirationDateTime.getTime(), 1143 is(startTime.getTime() + ORIGINATION_TIME_OFFSET)); 1144 assertThat(usageExpirationDateTime.getTime(), 1145 is(startTime.getTime() + CONSUMPTION_TIME_OFFSET)); 1146 } 1147 } 1148 checkDigests(Attestation attestation, Set<Integer> expectedDigests)1149 private void checkDigests(Attestation attestation, Set<Integer> expectedDigests) { 1150 Set<Integer> softwareEnforcedDigests = attestation.getSoftwareEnforced().getDigests(); 1151 Set<Integer> teeEnforcedDigests = attestation.getTeeEnforced().getDigests(); 1152 1153 if (softwareEnforcedDigests == null) { 1154 softwareEnforcedDigests = ImmutableSet.of(); 1155 } 1156 if (teeEnforcedDigests == null) { 1157 teeEnforcedDigests = ImmutableSet.of(); 1158 } 1159 1160 Set<Integer> allDigests = ImmutableSet.<Integer> builder() 1161 .addAll(softwareEnforcedDigests) 1162 .addAll(teeEnforcedDigests) 1163 .build(); 1164 Set<Integer> intersection = new ArraySet<>(); 1165 intersection.addAll(softwareEnforcedDigests); 1166 intersection.retainAll(teeEnforcedDigests); 1167 1168 assertThat(allDigests, is(expectedDigests)); 1169 assertTrue("Digest sets must be disjoint", intersection.isEmpty()); 1170 1171 if (attestation.getKeymasterSecurityLevel() == KM_SECURITY_LEVEL_SOFTWARE 1172 || attestation.getKeymasterVersion() == 0) { 1173 assertThat("Digests in software-enforced", 1174 softwareEnforcedDigests, is(expectedDigests)); 1175 } else { 1176 if (attestation.getKeymasterVersion() == 1) { 1177 // KM1 implementations may not support SHA512 in the TEE 1178 assertTrue(softwareEnforcedDigests.contains(KM_DIGEST_SHA_2_512) 1179 || teeEnforcedDigests.contains(KM_DIGEST_SHA_2_512)); 1180 1181 assertThat(teeEnforcedDigests, hasItems(KM_DIGEST_NONE, KM_DIGEST_SHA_2_256)); 1182 } else { 1183 assertThat(teeEnforcedDigests, is(expectedDigests)); 1184 } 1185 } 1186 } 1187 checkPurposes(Attestation attestation, int purposes)1188 private Set<Integer> checkPurposes(Attestation attestation, int purposes) { 1189 Set<Integer> expectedPurposes = buildPurposeSet(purposes); 1190 if (attestation.getKeymasterSecurityLevel() == KM_SECURITY_LEVEL_SOFTWARE 1191 || attestation.getKeymasterVersion() == 0) { 1192 assertThat("Purposes in software-enforced should match expected set", 1193 attestation.getSoftwareEnforced().getPurposes(), is(expectedPurposes)); 1194 assertNull("Should be no purposes in TEE-enforced", 1195 attestation.getTeeEnforced().getPurposes()); 1196 } else { 1197 assertThat("Purposes in TEE-enforced should match expected set", 1198 attestation.getTeeEnforced().getPurposes(), is(expectedPurposes)); 1199 assertNull("No purposes in software-enforced", 1200 attestation.getSoftwareEnforced().getPurposes()); 1201 } 1202 return expectedPurposes; 1203 } 1204 isGsiImage()1205 private boolean isGsiImage() { 1206 final File initGsiRc= new File("/system/system_ext/etc/init/init.gsi.rc"); 1207 return initGsiRc.exists(); 1208 } 1209 checkSystemPatchLevel(int teeOsPatchLevel, int systemPatchLevel)1210 private void checkSystemPatchLevel(int teeOsPatchLevel, int systemPatchLevel) { 1211 if (isGsiImage()) { 1212 // b/168663786: When using a GSI image, the system patch level might be 1213 // greater than or equal to the OS patch level reported from TEE. 1214 assertThat(teeOsPatchLevel, lessThanOrEqualTo(systemPatchLevel)); 1215 } else { 1216 assertThat(teeOsPatchLevel, is(systemPatchLevel)); 1217 } 1218 } 1219 1220 @SuppressWarnings("unchecked") checkAttestationSecurityLevelDependentParams(Attestation attestation)1221 private void checkAttestationSecurityLevelDependentParams(Attestation attestation) { 1222 assertThat("Attestation version must be one of: {1, 2, 3, 4, 100, 200}", 1223 attestation.getAttestationVersion(), 1224 either(is(1)).or(is(2)).or(is(3)).or(is(4)).or(is(100)).or(is(200))); 1225 1226 AuthorizationList teeEnforced = attestation.getTeeEnforced(); 1227 AuthorizationList softwareEnforced = attestation.getSoftwareEnforced(); 1228 1229 int systemOsVersion = getSystemOsVersion(); 1230 int systemPatchLevel = getSystemPatchLevel(); 1231 1232 switch (attestation.getAttestationSecurityLevel()) { 1233 case KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT: 1234 assertThat("TEE attestation can only come from TEE keymaster", 1235 attestation.getKeymasterSecurityLevel(), 1236 is(KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT)); 1237 assertThat(attestation.getKeymasterVersion(), 1238 either(is(2)).or(is(3)).or(is(4)).or(is(41)).or(is(100)).or(is(200))); 1239 1240 checkRootOfTrust(attestation, false /* requireLocked */); 1241 assertThat(teeEnforced.getOsVersion(), is(systemOsVersion)); 1242 checkSystemPatchLevel(teeEnforced.getOsPatchLevel(), systemPatchLevel); 1243 break; 1244 1245 case KM_SECURITY_LEVEL_SOFTWARE: 1246 if (attestation 1247 .getKeymasterSecurityLevel() == KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT) { 1248 assertThat("TEE KM version must be 0 or 1 with software attestation", 1249 attestation.getKeymasterVersion(), either(is(0)).or(is(1))); 1250 } else { 1251 assertThat("Software KM is version 3", attestation.getKeymasterVersion(), 1252 is(3)); 1253 assertThat(softwareEnforced.getOsVersion(), is(systemOsVersion)); 1254 checkSystemPatchLevel(softwareEnforced.getOsPatchLevel(), systemPatchLevel); 1255 } 1256 1257 assertNull("Software attestation cannot provide root of trust", 1258 teeEnforced.getRootOfTrust()); 1259 1260 break; 1261 1262 default: 1263 fail("Invalid attestation security level: " 1264 + attestation.getAttestationSecurityLevel()); 1265 break; 1266 } 1267 } 1268 checkDeviceLocked(Attestation attestation)1269 private void checkDeviceLocked(Attestation attestation) { 1270 assertThat("Attestation version must be >= 1", 1271 attestation.getAttestationVersion(), greaterThanOrEqualTo(1)); 1272 1273 int attestationSecurityLevel = attestation.getAttestationSecurityLevel(); 1274 switch (attestationSecurityLevel) { 1275 case KM_SECURITY_LEVEL_STRONG_BOX: 1276 case KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT: 1277 assertThat("Attestation security level doesn't match keymaster security level", 1278 attestation.getKeymasterSecurityLevel(), is(attestationSecurityLevel)); 1279 assertThat(attestation.getKeymasterVersion(), greaterThanOrEqualTo(2)); 1280 1281 // Devices launched in Android 10.0 (API level 29) and after should run CTS 1282 // in LOCKED state. 1283 boolean requireLocked = ( 1284 SystemProperties.getInt("ro.product.first_api_level", 0) >= 29); 1285 checkRootOfTrust(attestation, requireLocked); 1286 break; 1287 1288 case KM_SECURITY_LEVEL_SOFTWARE: 1289 default: 1290 // TEE attestation has been required since Android 7.0. 1291 fail("Unexpected attestation security level: " + 1292 attestation.securityLevelToString(attestationSecurityLevel)); 1293 break; 1294 } 1295 } 1296 checkRootOfTrust(Attestation attestation, boolean requireLocked)1297 private void checkRootOfTrust(Attestation attestation, boolean requireLocked) { 1298 RootOfTrust rootOfTrust = attestation.getRootOfTrust(); 1299 assertNotNull(rootOfTrust); 1300 assertNotNull(rootOfTrust.getVerifiedBootKey()); 1301 assertTrue("Verified boot key is only " + rootOfTrust.getVerifiedBootKey().length + 1302 " bytes long", rootOfTrust.getVerifiedBootKey().length >= 32); 1303 if (requireLocked) { 1304 final String unlockedDeviceMessage = "The device's bootloader must be locked. This may " 1305 + "not be the default for pre-production devices."; 1306 assertTrue(unlockedDeviceMessage, rootOfTrust.isDeviceLocked()); 1307 checkEntropy(rootOfTrust.getVerifiedBootKey()); 1308 assertEquals(KM_VERIFIED_BOOT_VERIFIED, rootOfTrust.getVerifiedBootState()); 1309 } 1310 } 1311 checkEntropy(byte[] verifiedBootKey)1312 private void checkEntropy(byte[] verifiedBootKey) { 1313 assertTrue("Failed Shannon entropy check", checkShannonEntropy(verifiedBootKey)); 1314 assertTrue("Failed BiEntropy check", checkTresBiEntropy(verifiedBootKey)); 1315 } 1316 checkShannonEntropy(byte[] verifiedBootKey)1317 private boolean checkShannonEntropy(byte[] verifiedBootKey) { 1318 double probabilityOfSetBit = countSetBits(verifiedBootKey) / (double)(verifiedBootKey.length * 8); 1319 return calculateShannonEntropy(probabilityOfSetBit) > 0.8; 1320 } 1321 calculateShannonEntropy(double probabilityOfSetBit)1322 private double calculateShannonEntropy(double probabilityOfSetBit) { 1323 if (probabilityOfSetBit <= 0.001 || probabilityOfSetBit >= .999) return 0; 1324 double entropy = (-probabilityOfSetBit * logTwo(probabilityOfSetBit)) - 1325 ((1 - probabilityOfSetBit) * logTwo(1 - probabilityOfSetBit)); 1326 Log.i(TAG, "Shannon entropy of VB Key: " + entropy); 1327 return entropy; 1328 } 1329 checkTresBiEntropy(byte[] verifiedBootKey)1330 private boolean checkTresBiEntropy(byte[] verifiedBootKey) { 1331 double weightingFactor = 0; 1332 double weightedEntropy = 0; 1333 double probabilityOfSetBit = 0; 1334 int length = verifiedBootKey.length * 8; 1335 for(int i = 0; i < (verifiedBootKey.length * 8) - 2; i++) { 1336 probabilityOfSetBit = countSetBits(verifiedBootKey) / (double)length; 1337 weightingFactor += logTwo(i+2); 1338 weightedEntropy += calculateShannonEntropy(probabilityOfSetBit) * logTwo(i+2); 1339 deriveBitString(verifiedBootKey, length); 1340 length -= 1; 1341 } 1342 double tresBiEntropy = (1 / weightingFactor) * weightedEntropy; 1343 Log.i(TAG, "BiEntropy of VB Key: " + tresBiEntropy); 1344 return tresBiEntropy > 0.9; 1345 } 1346 deriveBitString(byte[] bitString, int activeLength)1347 private void deriveBitString(byte[] bitString, int activeLength) { 1348 int length = activeLength / 8; 1349 if (activeLength % 8 != 0) { 1350 length += 1; 1351 } 1352 1353 byte mask = (byte)((byte)0x80 >>> ((activeLength + 6) % 8)); 1354 if (activeLength % 8 == 1) { 1355 mask = (byte)~mask; 1356 } 1357 1358 for(int i = 0; i < length; i++) { 1359 if (i == length - 1) { 1360 bitString[i] ^= ((bitString[i] & 0xFF) << 1); 1361 bitString[i] &= mask; 1362 } else { 1363 bitString[i] ^= ((bitString[i] & 0xFF) << 1) | ((bitString[i+1] & 0xFF) >>> 7); 1364 } 1365 } 1366 } 1367 logTwo(double value)1368 private double logTwo(double value) { 1369 return Math.log(value) / Math.log(2); 1370 } 1371 countSetBits(byte[] toCount)1372 private int countSetBits(byte[] toCount) { 1373 int setBitCount = 0; 1374 for(int i = 0; i < toCount.length; i++) { 1375 setBitCount += countSetBits(toCount[i]); 1376 } 1377 return setBitCount; 1378 } 1379 countSetBits(byte toCount)1380 private int countSetBits(byte toCount) { 1381 int setBitCounter = 0; 1382 while(toCount != 0) { 1383 toCount &= (toCount - 1); 1384 setBitCounter++; 1385 } 1386 return setBitCounter; 1387 } 1388 checkRsaKeyDetails(Attestation attestation, int keySize, int purposes, Set<String> expectedPaddingModes)1389 private void checkRsaKeyDetails(Attestation attestation, int keySize, int purposes, 1390 Set<String> expectedPaddingModes) throws CertificateParsingException { 1391 AuthorizationList keyDetailsList; 1392 AuthorizationList nonKeyDetailsList; 1393 if (attestation.getKeymasterSecurityLevel() == KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT) { 1394 keyDetailsList = attestation.getTeeEnforced(); 1395 nonKeyDetailsList = attestation.getSoftwareEnforced(); 1396 } else { 1397 keyDetailsList = attestation.getSoftwareEnforced(); 1398 nonKeyDetailsList = attestation.getTeeEnforced(); 1399 } 1400 assertEquals(keySize, keyDetailsList.getKeySize().intValue()); 1401 assertNull(nonKeyDetailsList.getKeySize()); 1402 1403 assertEquals(KM_ALGORITHM_RSA, keyDetailsList.getAlgorithm().intValue()); 1404 assertNull(nonKeyDetailsList.getAlgorithm()); 1405 1406 assertNull(keyDetailsList.getEcCurve()); 1407 assertNull(nonKeyDetailsList.getEcCurve()); 1408 1409 assertEquals(65537, keyDetailsList.getRsaPublicExponent().longValue()); 1410 assertNull(nonKeyDetailsList.getRsaPublicExponent()); 1411 1412 Set<String> paddingModes; 1413 if (attestation.getKeymasterVersion() == 0) { 1414 // KM0 implementations don't support padding info, so it's always in the 1415 // software-enforced list. 1416 paddingModes = attestation.getSoftwareEnforced().getPaddingModesAsStrings(); 1417 assertNull(attestation.getTeeEnforced().getPaddingModes()); 1418 } else { 1419 paddingModes = keyDetailsList.getPaddingModesAsStrings(); 1420 assertNull(nonKeyDetailsList.getPaddingModes()); 1421 } 1422 1423 // KM1 implementations may add ENCRYPTION_PADDING_NONE to the list of paddings. 1424 Set<String> km1PossiblePaddingModes = expectedPaddingModes; 1425 if (attestation.getKeymasterVersion() == 1 && 1426 attestation.getKeymasterSecurityLevel() == KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT) { 1427 ImmutableSet.Builder<String> builder = ImmutableSet.builder(); 1428 builder.addAll(expectedPaddingModes); 1429 builder.add(ENCRYPTION_PADDING_NONE); 1430 km1PossiblePaddingModes = builder.build(); 1431 } 1432 1433 assertThat(paddingModes, either(is(expectedPaddingModes)).or(is(km1PossiblePaddingModes))); 1434 } 1435 checkEcKeyDetails(Attestation attestation, String ecCurve, int keySize)1436 private void checkEcKeyDetails(Attestation attestation, String ecCurve, int keySize) { 1437 AuthorizationList keyDetailsList; 1438 AuthorizationList nonKeyDetailsList; 1439 if (attestation.getKeymasterSecurityLevel() == KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT) { 1440 keyDetailsList = attestation.getTeeEnforced(); 1441 nonKeyDetailsList = attestation.getSoftwareEnforced(); 1442 } else { 1443 keyDetailsList = attestation.getSoftwareEnforced(); 1444 nonKeyDetailsList = attestation.getTeeEnforced(); 1445 } 1446 assertEquals(keySize, keyDetailsList.getKeySize().intValue()); 1447 assertNull(nonKeyDetailsList.getKeySize()); 1448 assertEquals(KM_ALGORITHM_EC, keyDetailsList.getAlgorithm().intValue()); 1449 assertNull(nonKeyDetailsList.getAlgorithm()); 1450 assertEquals(ecCurve, keyDetailsList.ecCurveAsString()); 1451 assertNull(nonKeyDetailsList.getEcCurve()); 1452 assertNull(keyDetailsList.getRsaPublicExponent()); 1453 assertNull(nonKeyDetailsList.getRsaPublicExponent()); 1454 assertNull(keyDetailsList.getPaddingModes()); 1455 assertNull(nonKeyDetailsList.getPaddingModes()); 1456 } 1457 isEncryptionPurpose(int purposes)1458 private boolean isEncryptionPurpose(int purposes) { 1459 return (purposes & PURPOSE_DECRYPT) != 0 || (purposes & PURPOSE_ENCRYPT) != 0; 1460 } 1461 isSignaturePurpose(int purposes)1462 private boolean isSignaturePurpose(int purposes) { 1463 return (purposes & PURPOSE_SIGN) != 0 || (purposes & PURPOSE_VERIFY) != 0; 1464 } 1465 buildPurposeSet(int purposes)1466 private ImmutableSet<Integer> buildPurposeSet(int purposes) { 1467 ImmutableSet.Builder<Integer> builder = ImmutableSet.builder(); 1468 if ((purposes & PURPOSE_SIGN) != 0) 1469 builder.add(KM_PURPOSE_SIGN); 1470 if ((purposes & PURPOSE_VERIFY) != 0) 1471 builder.add(KM_PURPOSE_VERIFY); 1472 if ((purposes & PURPOSE_ENCRYPT) != 0) 1473 builder.add(KM_PURPOSE_ENCRYPT); 1474 if ((purposes & PURPOSE_DECRYPT) != 0) 1475 builder.add(KM_PURPOSE_DECRYPT); 1476 return builder.build(); 1477 } 1478 generateKey(KeyGenParameterSpec spec, String algorithm)1479 private void generateKey(KeyGenParameterSpec spec, String algorithm) 1480 throws NoSuchAlgorithmException, NoSuchProviderException, 1481 InvalidAlgorithmParameterException { 1482 KeyGenerator keyGenerator = KeyGenerator.getInstance(algorithm, "AndroidKeyStore"); 1483 keyGenerator.init(spec); 1484 keyGenerator.generateKey(); 1485 } 1486 generateKeyPair(String algorithm, KeyGenParameterSpec spec)1487 private void generateKeyPair(String algorithm, KeyGenParameterSpec spec) 1488 throws NoSuchAlgorithmException, NoSuchProviderException, 1489 InvalidAlgorithmParameterException { 1490 KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(algorithm, 1491 "AndroidKeyStore"); 1492 keyPairGenerator.initialize(spec); 1493 keyPairGenerator.generateKeyPair(); 1494 } 1495 verifyCertificateChain(Certificate[] certChain, boolean expectStrongBox)1496 public static void verifyCertificateChain(Certificate[] certChain, boolean expectStrongBox) 1497 throws GeneralSecurityException { 1498 assertNotNull(certChain); 1499 boolean strongBoxSubjectFound = false; 1500 for (int i = 1; i < certChain.length; ++i) { 1501 try { 1502 PublicKey pubKey = certChain[i].getPublicKey(); 1503 certChain[i - 1].verify(pubKey); 1504 if (i == certChain.length - 1) { 1505 // Last cert should be self-signed. 1506 certChain[i].verify(pubKey); 1507 } 1508 1509 // Check that issuer in the signed cert matches subject in the signing cert. 1510 X509Certificate x509CurrCert = (X509Certificate) certChain[i]; 1511 X509Certificate x509PrevCert = (X509Certificate) certChain[i - 1]; 1512 X500Name signingCertSubject = 1513 new JcaX509CertificateHolder(x509CurrCert).getSubject(); 1514 X500Name signedCertIssuer = 1515 new JcaX509CertificateHolder(x509PrevCert).getIssuer(); 1516 // Use .toASN1Object().equals() rather than .equals() because .equals() is case 1517 // insensitive, and we want to verify an exact match. 1518 assertTrue( 1519 signedCertIssuer.toASN1Object().equals(signingCertSubject.toASN1Object())); 1520 1521 X500Name signedCertSubject = 1522 new JcaX509CertificateHolder(x509PrevCert).getSubject(); 1523 if (i == 1) { 1524 // First cert should have subject "CN=Android Keystore Key". 1525 assertEquals(signedCertSubject, new X500Name("CN=Android Keystore Key")); 1526 } else if (signedCertSubject.toString().toLowerCase().contains("strongbox")) { 1527 strongBoxSubjectFound = true; 1528 } 1529 } catch (InvalidKeyException | CertificateException | NoSuchAlgorithmException 1530 | NoSuchProviderException | SignatureException e) { 1531 throw new GeneralSecurityException("Using StrongBox: " + expectStrongBox + "\n" 1532 + "Failed to verify certificate " + certChain[i - 1] 1533 + " with public key " + certChain[i].getPublicKey(), 1534 e); 1535 } 1536 } 1537 // At least one intermediate in a StrongBox chain must have "strongbox" in the subject. 1538 assertEquals(expectStrongBox, strongBoxSubjectFound); 1539 } 1540 testDeviceIdAttestationFailure(int idType, String acceptableDeviceIdAttestationFailureMessage)1541 private void testDeviceIdAttestationFailure(int idType, 1542 String acceptableDeviceIdAttestationFailureMessage) throws Exception { 1543 try { 1544 AttestationUtils.attestDeviceIds(getContext(), new int[] {idType}, "123".getBytes()); 1545 fail("Attestation should have failed."); 1546 } catch (SecurityException e) { 1547 // Attestation is expected to fail. If the device has the device ID type we are trying 1548 // to attest, it should fail with a SecurityException as we do not hold 1549 // READ_PRIVILEGED_PHONE_STATE permission. 1550 } catch (DeviceIdAttestationException e) { 1551 // Attestation is expected to fail. If the device does not have the device ID type we 1552 // are trying to attest (e.g. no IMEI on devices without a radio), it should fail with 1553 // a corresponding DeviceIdAttestationException. 1554 if (acceptableDeviceIdAttestationFailureMessage == null || 1555 !acceptableDeviceIdAttestationFailureMessage.equals(e.getMessage())) { 1556 throw e; 1557 } 1558 } 1559 } 1560 } 1561