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