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 56 import android.content.pm.PackageManager.NameNotFoundException; 57 import android.os.Build; 58 import android.os.SystemProperties; 59 import android.platform.test.annotations.RestrictedBuildTest; 60 import android.security.KeyStoreException; 61 import android.security.keystore.AttestationUtils; 62 import android.security.keystore.DeviceIdAttestationException; 63 import android.security.keystore.KeyGenParameterSpec; 64 import android.security.keystore.KeyProperties; 65 import android.test.AndroidTestCase; 66 import android.util.ArraySet; 67 import android.util.Log; 68 69 import com.google.common.collect.ImmutableSet; 70 71 import androidx.test.filters.RequiresDevice; 72 73 import org.bouncycastle.asn1.x500.X500Name; 74 import org.bouncycastle.cert.jcajce.JcaX509CertificateHolder; 75 76 import java.lang.Math; 77 import java.security.GeneralSecurityException; 78 import java.security.InvalidAlgorithmParameterException; 79 import java.security.InvalidKeyException; 80 import java.security.KeyPairGenerator; 81 import java.security.KeyStore; 82 import java.security.NoSuchAlgorithmException; 83 import java.security.NoSuchProviderException; 84 import java.security.ProviderException; 85 import java.security.PublicKey; 86 import java.security.SignatureException; 87 import java.security.cert.Certificate; 88 import java.security.cert.CertificateException; 89 import java.security.cert.CertificateParsingException; 90 import java.security.cert.X509Certificate; 91 import java.security.spec.ECGenParameterSpec; 92 import java.util.Arrays; 93 import java.util.Date; 94 import java.util.Set; 95 import java.util.regex.Matcher; 96 import java.util.regex.Pattern; 97 98 import javax.crypto.KeyGenerator; 99 100 /** 101 * Tests for Android KeysStore attestation. 102 */ 103 public class KeyAttestationTest extends AndroidTestCase { 104 105 private static final String TAG = AndroidKeyStoreTest.class.getSimpleName(); 106 107 private static final int ORIGINATION_TIME_OFFSET = 1000000; 108 private static final int CONSUMPTION_TIME_OFFSET = 2000000; 109 110 private static final int KEY_USAGE_BITSTRING_LENGTH = 9; 111 private static final int KEY_USAGE_DIGITAL_SIGNATURE_BIT_OFFSET = 0; 112 private static final int KEY_USAGE_KEY_ENCIPHERMENT_BIT_OFFSET = 2; 113 private static final int KEY_USAGE_DATA_ENCIPHERMENT_BIT_OFFSET = 3; 114 115 private static final int OS_MAJOR_VERSION_MATCH_GROUP_NAME = 1; 116 private static final int OS_MINOR_VERSION_MATCH_GROUP_NAME = 2; 117 private static final int OS_SUBMINOR_VERSION_MATCH_GROUP_NAME = 3; 118 private static final Pattern OS_VERSION_STRING_PATTERN = Pattern 119 .compile("([0-9]{1,2})(?:\\.([0-9]{1,2}))?(?:\\.([0-9]{1,2}))?(?:[^0-9.]+.*)?"); 120 121 private static final int OS_PATCH_LEVEL_YEAR_GROUP_NAME = 1; 122 private static final int OS_PATCH_LEVEL_MONTH_GROUP_NAME = 2; 123 private static final Pattern OS_PATCH_LEVEL_STRING_PATTERN = Pattern 124 .compile("([0-9]{4})-([0-9]{2})-[0-9]{2}"); 125 126 private static final int KM_ERROR_INVALID_INPUT_LENGTH = -21; 127 private static final int KM_ERROR_PERMISSION_DENIED = 6; 128 testVersionParser()129 public void testVersionParser() throws Exception { 130 // Non-numerics/empty give version 0 131 assertEquals(0, parseSystemOsVersion("")); 132 assertEquals(0, parseSystemOsVersion("N")); 133 134 // Should support one, two or three version number values. 135 assertEquals(10000, parseSystemOsVersion("1")); 136 assertEquals(10200, parseSystemOsVersion("1.2")); 137 assertEquals(10203, parseSystemOsVersion("1.2.3")); 138 139 // It's fine to append other stuff to the dotted numeric version. 140 assertEquals(10000, parseSystemOsVersion("1stuff")); 141 assertEquals(10200, parseSystemOsVersion("1.2garbage.32")); 142 assertEquals(10203, parseSystemOsVersion("1.2.3-stuff")); 143 144 // Two digits per version field are supported 145 assertEquals(152536, parseSystemOsVersion("15.25.36")); 146 assertEquals(999999, parseSystemOsVersion("99.99.99")); 147 assertEquals(0, parseSystemOsVersion("100.99.99")); 148 assertEquals(0, parseSystemOsVersion("99.100.99")); 149 assertEquals(0, parseSystemOsVersion("99.99.100")); 150 } 151 testEcAttestation()152 public void testEcAttestation() throws Exception { 153 // Note: Curve and key sizes arrays must correspond. 154 String[] curves = { 155 "secp224r1", "secp256r1", "secp384r1", "secp521r1" 156 }; 157 int[] keySizes = { 158 224, 256, 384, 521 159 }; 160 byte[][] challenges = { 161 new byte[0], // empty challenge 162 "challenge".getBytes(), // short challenge 163 new byte[128], // long challenge 164 }; 165 int[] purposes = { 166 KM_PURPOSE_SIGN, KM_PURPOSE_VERIFY, KM_PURPOSE_SIGN | KM_PURPOSE_VERIFY 167 }; 168 boolean[] devicePropertiesAttestationValues = {true, false}; 169 boolean[] includeValidityDatesValues = {true, false}; 170 171 for (int curveIndex = 0; curveIndex < curves.length; ++curveIndex) { 172 for (int challengeIndex = 0; challengeIndex < challenges.length; ++challengeIndex) { 173 for (int purposeIndex = 0; purposeIndex < purposes.length; ++purposeIndex) { 174 for (boolean includeValidityDates : includeValidityDatesValues) { 175 for (boolean devicePropertiesAttestation : devicePropertiesAttestationValues) { 176 try { 177 testEcAttestation(challenges[challengeIndex], includeValidityDates, 178 curves[curveIndex], keySizes[curveIndex], 179 purposes[purposeIndex], devicePropertiesAttestation); 180 } catch (Throwable e) { 181 throw new Exception("Failed on curve " + curveIndex + 182 " challenge " + challengeIndex + " purpose " + 183 purposeIndex + " includeValidityDates " + 184 includeValidityDates + " and devicePropertiesAttestation " + 185 devicePropertiesAttestation, e); 186 } 187 } 188 } 189 } 190 } 191 } 192 } 193 testEcAttestation_TooLargeChallenge()194 public void testEcAttestation_TooLargeChallenge() throws Exception { 195 boolean[] devicePropertiesAttestationValues = {true, false}; 196 for (boolean devicePropertiesAttestation : devicePropertiesAttestationValues) { 197 try { 198 testEcAttestation(new byte[129], true /* includeValidityDates */, "secp256r1", 256, 199 KM_PURPOSE_SIGN, devicePropertiesAttestation); 200 fail("Attestation challenges larger than 128 bytes should be rejected"); 201 } catch (ProviderException e) { 202 KeyStoreException cause = (KeyStoreException) e.getCause(); 203 assertEquals(KM_ERROR_INVALID_INPUT_LENGTH, cause.getErrorCode()); 204 } 205 } 206 } 207 testEcAttestation_NoChallenge()208 public void testEcAttestation_NoChallenge() throws Exception { 209 boolean[] devicePropertiesAttestationValues = {true, false}; 210 for (boolean devicePropertiesAttestation : devicePropertiesAttestationValues) { 211 String keystoreAlias = "test_key"; 212 Date now = new Date(); 213 Date originationEnd = new Date(now.getTime() + ORIGINATION_TIME_OFFSET); 214 Date consumptionEnd = new Date(now.getTime() + CONSUMPTION_TIME_OFFSET); 215 KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(keystoreAlias, PURPOSE_SIGN) 216 .setAlgorithmParameterSpec(new ECGenParameterSpec("secp256r1")) 217 .setDigests(DIGEST_NONE, DIGEST_SHA256, DIGEST_SHA512) 218 .setAttestationChallenge(null) 219 .setKeyValidityStart(now) 220 .setKeyValidityForOriginationEnd(originationEnd) 221 .setKeyValidityForConsumptionEnd(consumptionEnd) 222 .setDevicePropertiesAttestationIncluded(devicePropertiesAttestation) 223 .build(); 224 225 generateKeyPair(KEY_ALGORITHM_EC, spec); 226 227 KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); 228 keyStore.load(null); 229 230 try { 231 Certificate certificates[] = keyStore.getCertificateChain(keystoreAlias); 232 assertEquals(1, certificates.length); 233 234 X509Certificate attestationCert = (X509Certificate) certificates[0]; 235 assertNull(attestationCert.getExtensionValue(Attestation.KEY_DESCRIPTION_OID)); 236 } finally { 237 keyStore.deleteEntry(keystoreAlias); 238 } 239 } 240 } 241 242 @RestrictedBuildTest testEcAttestation_DeviceLocked()243 public void testEcAttestation_DeviceLocked() throws Exception { 244 String keystoreAlias = "test_key"; 245 Date now = new Date(); 246 Date originationEnd = new Date(now.getTime() + ORIGINATION_TIME_OFFSET); 247 Date consumptionEnd = new Date(now.getTime() + CONSUMPTION_TIME_OFFSET); 248 KeyGenParameterSpec.Builder builder = 249 new KeyGenParameterSpec.Builder(keystoreAlias, PURPOSE_SIGN) 250 .setAlgorithmParameterSpec(new ECGenParameterSpec("secp256r1")) 251 .setAttestationChallenge(new byte[128]) 252 .setKeyValidityStart(now) 253 .setKeyValidityForOriginationEnd(originationEnd) 254 .setKeyValidityForConsumptionEnd(consumptionEnd); 255 256 if (TestUtils.hasStrongBox(getContext())) { 257 builder.setDigests(DIGEST_NONE, DIGEST_SHA256); 258 builder.setIsStrongBoxBacked(true); 259 } else { 260 builder.setDigests(DIGEST_NONE, DIGEST_SHA256, DIGEST_SHA512); 261 } 262 263 generateKeyPair(KEY_ALGORITHM_EC, builder.build()); 264 265 KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); 266 keyStore.load(null); 267 268 try { 269 Certificate certificates[] = keyStore.getCertificateChain(keystoreAlias); 270 verifyCertificateChain(certificates, TestUtils.hasStrongBox(getContext())); 271 272 X509Certificate attestationCert = (X509Certificate) certificates[0]; 273 checkDeviceLocked(new Attestation(attestationCert)); 274 } finally { 275 keyStore.deleteEntry(keystoreAlias); 276 } 277 } 278 testEcAttestation_KeyStoreExceptionWhenRequestingUniqueId()279 public void testEcAttestation_KeyStoreExceptionWhenRequestingUniqueId() throws Exception { 280 String keystoreAlias = "test_key"; 281 KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(keystoreAlias, PURPOSE_SIGN) 282 .setAlgorithmParameterSpec(new ECGenParameterSpec("secp256r1")) 283 .setDigests(DIGEST_NONE, DIGEST_SHA256, DIGEST_SHA512) 284 .setAttestationChallenge(new byte[128]) 285 .setUniqueIdIncluded(true) 286 .build(); 287 288 try { 289 generateKeyPair(KEY_ALGORITHM_EC, spec); 290 fail("Attestation should have failed."); 291 } catch (ProviderException e) { 292 // Attestation is expected to fail because of lack of permissions. 293 KeyStoreException cause = (KeyStoreException) e.getCause(); 294 assertEquals(KM_ERROR_PERMISSION_DENIED, cause.getErrorCode()); 295 } finally { 296 KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); 297 keyStore.load(null); 298 keyStore.deleteEntry(keystoreAlias); 299 } 300 } 301 testRsaAttestation()302 public void testRsaAttestation() throws Exception { 303 int[] keySizes = { // Smallish sizes to keep test runtimes down. 304 512, 768, 1024 305 }; 306 byte[][] challenges = { 307 new byte[0], // empty challenge 308 "challenge".getBytes(), // short challenge 309 new byte[128] // long challenge 310 }; 311 int[] purposes = { 312 PURPOSE_SIGN | PURPOSE_VERIFY, 313 PURPOSE_ENCRYPT | PURPOSE_DECRYPT, 314 }; 315 String[][] encryptionPaddingModes = { 316 { 317 ENCRYPTION_PADDING_NONE 318 }, 319 { 320 ENCRYPTION_PADDING_RSA_OAEP, 321 }, 322 { 323 ENCRYPTION_PADDING_RSA_PKCS1, 324 }, 325 { 326 ENCRYPTION_PADDING_RSA_OAEP, 327 ENCRYPTION_PADDING_RSA_PKCS1, 328 }, 329 }; 330 String[][] signaturePaddingModes = { 331 { 332 SIGNATURE_PADDING_RSA_PKCS1, 333 }, 334 { 335 SIGNATURE_PADDING_RSA_PSS, 336 }, 337 { 338 SIGNATURE_PADDING_RSA_PKCS1, 339 SIGNATURE_PADDING_RSA_PSS, 340 }, 341 }; 342 boolean[] devicePropertiesAttestationValues = {true, false}; 343 344 for (boolean devicePropertiesAttestation : devicePropertiesAttestationValues) { 345 for (int keySize : keySizes) { 346 for (byte[] challenge : challenges) { 347 for (int purpose : purposes) { 348 if (isEncryptionPurpose(purpose)) { 349 testRsaAttestations(keySize, challenge, purpose, encryptionPaddingModes, 350 devicePropertiesAttestation); 351 } else { 352 testRsaAttestations(keySize, challenge, purpose, signaturePaddingModes, 353 devicePropertiesAttestation); 354 } 355 } 356 } 357 } 358 } 359 } 360 testRsaAttestation_TooLargeChallenge()361 public void testRsaAttestation_TooLargeChallenge() throws Exception { 362 boolean[] devicePropertiesAttestationValues = {true, false}; 363 for (boolean devicePropertiesAttestation : devicePropertiesAttestationValues) { 364 try { 365 testRsaAttestation(new byte[129], true /* includeValidityDates */, 512, 366 PURPOSE_SIGN, 367 null /* paddingModes; may be empty because we'll never test them */, 368 devicePropertiesAttestation); 369 fail("Attestation challenges larger than 128 bytes should be rejected"); 370 } catch(ProviderException e){ 371 KeyStoreException cause = (KeyStoreException) e.getCause(); 372 assertEquals(KM_ERROR_INVALID_INPUT_LENGTH, cause.getErrorCode()); 373 } 374 } 375 } 376 testRsaAttestation_NoChallenge()377 public void testRsaAttestation_NoChallenge() throws Exception { 378 boolean[] devicePropertiesAttestationValues = {true, false}; 379 for (boolean devicePropertiesAttestation : devicePropertiesAttestationValues) { 380 String keystoreAlias = "test_key"; 381 Date now = new Date(); 382 Date originationEnd = new Date(now.getTime() + ORIGINATION_TIME_OFFSET); 383 Date consumptionEnd = new Date(now.getTime() + CONSUMPTION_TIME_OFFSET); 384 KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(keystoreAlias, PURPOSE_SIGN) 385 .setDigests(DIGEST_NONE, DIGEST_SHA256, DIGEST_SHA512) 386 .setAttestationChallenge(null) 387 .setKeyValidityStart(now) 388 .setKeyValidityForOriginationEnd(originationEnd) 389 .setKeyValidityForConsumptionEnd(consumptionEnd) 390 .setDevicePropertiesAttestationIncluded(devicePropertiesAttestation) 391 .build(); 392 393 generateKeyPair(KEY_ALGORITHM_RSA, spec); 394 395 KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); 396 keyStore.load(null); 397 398 try { 399 Certificate certificates[] = keyStore.getCertificateChain(keystoreAlias); 400 assertEquals(1, certificates.length); 401 402 X509Certificate attestationCert = (X509Certificate) certificates[0]; 403 assertNull(attestationCert.getExtensionValue(Attestation.KEY_DESCRIPTION_OID)); 404 } finally { 405 keyStore.deleteEntry(keystoreAlias); 406 } 407 } 408 } 409 410 @RestrictedBuildTest 411 @RequiresDevice // Emulators have no place to store the needed key testRsaAttestation_DeviceLocked()412 public void testRsaAttestation_DeviceLocked() throws Exception { 413 String keystoreAlias = "test_key"; 414 Date now = new Date(); 415 Date originationEnd = new Date(now.getTime() + ORIGINATION_TIME_OFFSET); 416 Date consumptionEnd = new Date(now.getTime() + CONSUMPTION_TIME_OFFSET); 417 KeyGenParameterSpec.Builder builder = 418 new KeyGenParameterSpec.Builder(keystoreAlias, PURPOSE_SIGN) 419 .setDigests(DIGEST_NONE, DIGEST_SHA256, DIGEST_SHA512) 420 .setAttestationChallenge("challenge".getBytes()) 421 .setKeyValidityStart(now) 422 .setKeyValidityForOriginationEnd(originationEnd) 423 .setKeyValidityForConsumptionEnd(consumptionEnd); 424 425 if (TestUtils.hasStrongBox(getContext())) { 426 builder.setDigests(DIGEST_NONE, DIGEST_SHA256); 427 builder.setIsStrongBoxBacked(true); 428 } else { 429 builder.setDigests(DIGEST_NONE, DIGEST_SHA256, DIGEST_SHA512); 430 } 431 432 generateKeyPair(KEY_ALGORITHM_RSA, builder.build()); 433 434 KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); 435 keyStore.load(null); 436 437 try { 438 Certificate certificates[] = keyStore.getCertificateChain(keystoreAlias); 439 verifyCertificateChain(certificates, TestUtils.hasStrongBox(getContext())); 440 441 X509Certificate attestationCert = (X509Certificate) certificates[0]; 442 checkDeviceLocked(new Attestation(attestationCert)); 443 } finally { 444 keyStore.deleteEntry(keystoreAlias); 445 } 446 } 447 testAesAttestation()448 public void testAesAttestation() throws Exception { 449 boolean[] devicePropertiesAttestationValues = {true, false}; 450 for (boolean devicePropertiesAttestation : devicePropertiesAttestationValues) { 451 String keystoreAlias = "test_key"; 452 KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(keystoreAlias, 453 PURPOSE_ENCRYPT) 454 .setBlockModes(KeyProperties.BLOCK_MODE_GCM) 455 .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE) 456 .setAttestationChallenge(new byte[0]) 457 .setDevicePropertiesAttestationIncluded(devicePropertiesAttestation) 458 .build(); 459 generateKey(spec, KeyProperties.KEY_ALGORITHM_AES); 460 461 KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); 462 keyStore.load(null); 463 try { 464 assertNull(keyStore.getCertificateChain(keystoreAlias)); 465 } finally { 466 keyStore.deleteEntry(keystoreAlias); 467 } 468 } 469 } 470 testHmacAttestation()471 public void testHmacAttestation() throws Exception { 472 boolean[] devicePropertiesAttestationValues = {true, false}; 473 for (boolean devicePropertiesAttestation : devicePropertiesAttestationValues) { 474 String keystoreAlias = "test_key"; 475 KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(keystoreAlias, PURPOSE_SIGN) 476 .setDevicePropertiesAttestationIncluded(devicePropertiesAttestation) 477 .build(); 478 479 generateKey(spec, KeyProperties.KEY_ALGORITHM_HMAC_SHA256); 480 481 KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); 482 keyStore.load(null); 483 try { 484 assertNull(keyStore.getCertificateChain(keystoreAlias)); 485 } finally { 486 keyStore.deleteEntry(keystoreAlias); 487 } 488 } 489 } 490 testRsaAttestations(int keySize, byte[] challenge, int purpose, String[][] paddingModes, boolean devicePropertiesAttestation)491 private void testRsaAttestations(int keySize, byte[] challenge, int purpose, 492 String[][] paddingModes, boolean devicePropertiesAttestation) throws Exception { 493 for (String[] paddings : paddingModes) { 494 try { 495 testRsaAttestation(challenge, true /* includeValidityDates */, keySize, purpose, 496 paddings, devicePropertiesAttestation); 497 testRsaAttestation(challenge, false /* includeValidityDates */, keySize, purpose, 498 paddings, devicePropertiesAttestation); 499 } catch (Throwable e) { 500 throw new Exception("Failed on key size " + keySize + " challenge [" + 501 new String(challenge) + "], purposes " + 502 buildPurposeSet(purpose) + " paddings " + 503 ImmutableSet.copyOf(paddings) + " and devicePropertiesAttestation " 504 + devicePropertiesAttestation, 505 e); 506 } 507 } 508 } 509 testDeviceIdAttestation()510 public void testDeviceIdAttestation() throws Exception { 511 testDeviceIdAttestationFailure(AttestationUtils.ID_TYPE_SERIAL, null); 512 testDeviceIdAttestationFailure(AttestationUtils.ID_TYPE_IMEI, "Unable to retrieve IMEI"); 513 testDeviceIdAttestationFailure(AttestationUtils.ID_TYPE_MEID, "Unable to retrieve MEID"); 514 } 515 516 @SuppressWarnings("deprecation") testRsaAttestation(byte[] challenge, boolean includeValidityDates, int keySize, int purposes, String[] paddingModes, boolean devicePropertiesAttestation)517 private void testRsaAttestation(byte[] challenge, boolean includeValidityDates, int keySize, 518 int purposes, String[] paddingModes, boolean devicePropertiesAttestation) 519 throws Exception { 520 Log.i(TAG, "RSA key attestation with: challenge " + Arrays.toString(challenge) + 521 " / includeValidityDates " + includeValidityDates + " / keySize " + keySize + 522 " / purposes " + purposes + " / paddingModes " + Arrays.toString(paddingModes) + 523 " / devicePropertiesAttestation " + devicePropertiesAttestation); 524 525 String keystoreAlias = "test_key"; 526 Date startTime = new Date(); 527 Date originationEnd = new Date(startTime.getTime() + ORIGINATION_TIME_OFFSET); 528 Date consumptionEnd = new Date(startTime.getTime() + CONSUMPTION_TIME_OFFSET); 529 KeyGenParameterSpec.Builder builder = 530 new KeyGenParameterSpec.Builder(keystoreAlias, purposes) 531 .setKeySize(keySize) 532 .setDigests(DIGEST_NONE, DIGEST_SHA256, DIGEST_SHA512) 533 .setAttestationChallenge(challenge) 534 .setDevicePropertiesAttestationIncluded(devicePropertiesAttestation); 535 536 if (includeValidityDates) { 537 builder.setKeyValidityStart(startTime) 538 .setKeyValidityForOriginationEnd(originationEnd) 539 .setKeyValidityForConsumptionEnd(consumptionEnd); 540 } 541 if (isEncryptionPurpose(purposes)) { 542 builder.setEncryptionPaddings(paddingModes); 543 // Because we sometimes set "no padding", allow non-randomized encryption. 544 builder.setRandomizedEncryptionRequired(false); 545 } 546 if (isSignaturePurpose(purposes)) { 547 builder.setSignaturePaddings(paddingModes); 548 } 549 550 generateKeyPair(KEY_ALGORITHM_RSA, builder.build()); 551 552 KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); 553 keyStore.load(null); 554 555 try { 556 Certificate certificates[] = keyStore.getCertificateChain(keystoreAlias); 557 verifyCertificateChain(certificates, false /* expectStrongBox */); 558 559 X509Certificate attestationCert = (X509Certificate) certificates[0]; 560 Attestation attestation = new Attestation(attestationCert); 561 562 checkRsaKeyDetails(attestation, keySize, purposes, ImmutableSet.copyOf(paddingModes)); 563 checkKeyUsage(attestationCert, purposes); 564 checkKeyIndependentAttestationInfo(challenge, purposes, startTime, includeValidityDates, 565 devicePropertiesAttestation, attestation); 566 } finally { 567 keyStore.deleteEntry(keystoreAlias); 568 } 569 } 570 checkKeyUsage(X509Certificate attestationCert, int purposes)571 private void checkKeyUsage(X509Certificate attestationCert, int purposes) { 572 573 boolean[] expectedKeyUsage = new boolean[KEY_USAGE_BITSTRING_LENGTH]; 574 if (isSignaturePurpose(purposes)) { 575 expectedKeyUsage[KEY_USAGE_DIGITAL_SIGNATURE_BIT_OFFSET] = true; 576 } 577 if (isEncryptionPurpose(purposes)) { 578 expectedKeyUsage[KEY_USAGE_KEY_ENCIPHERMENT_BIT_OFFSET] = true; 579 expectedKeyUsage[KEY_USAGE_DATA_ENCIPHERMENT_BIT_OFFSET] = true; 580 } 581 assertThat(attestationCert.getKeyUsage(), is(expectedKeyUsage)); 582 } 583 584 @SuppressWarnings("deprecation") testEcAttestation(byte[] challenge, boolean includeValidityDates, String ecCurve, int keySize, int purposes, boolean devicePropertiesAttestation)585 private void testEcAttestation(byte[] challenge, boolean includeValidityDates, String ecCurve, 586 int keySize, int purposes, boolean devicePropertiesAttestation) throws Exception { 587 Log.i(TAG, "EC key attestation with: challenge " + Arrays.toString(challenge) + 588 " / includeValidityDates " + includeValidityDates + " / ecCurve " + ecCurve + 589 " / keySize " + keySize + " / purposes " + purposes + 590 " / devicePropertiesAttestation " + devicePropertiesAttestation); 591 592 String keystoreAlias = "test_key"; 593 Date startTime = new Date(); 594 Date originationEnd = new Date(startTime.getTime() + ORIGINATION_TIME_OFFSET); 595 Date consumptionEnd = new Date(startTime.getTime() + CONSUMPTION_TIME_OFFSET); 596 KeyGenParameterSpec.Builder builder = new KeyGenParameterSpec.Builder(keystoreAlias, 597 purposes) 598 .setAlgorithmParameterSpec(new ECGenParameterSpec(ecCurve)) 599 .setDigests(DIGEST_NONE, DIGEST_SHA256, DIGEST_SHA512) 600 .setAttestationChallenge(challenge) 601 .setDevicePropertiesAttestationIncluded(devicePropertiesAttestation); 602 603 if (includeValidityDates) { 604 builder.setKeyValidityStart(startTime) 605 .setKeyValidityForOriginationEnd(originationEnd) 606 .setKeyValidityForConsumptionEnd(consumptionEnd); 607 } 608 609 generateKeyPair(KEY_ALGORITHM_EC, builder.build()); 610 611 KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); 612 keyStore.load(null); 613 614 try { 615 Certificate certificates[] = keyStore.getCertificateChain(keystoreAlias); 616 verifyCertificateChain(certificates, false /* expectStrongBox */); 617 618 X509Certificate attestationCert = (X509Certificate) certificates[0]; 619 Attestation attestation = new Attestation(attestationCert); 620 621 checkEcKeyDetails(attestation, ecCurve, keySize); 622 checkKeyUsage(attestationCert, purposes); 623 checkKeyIndependentAttestationInfo(challenge, purposes, startTime, includeValidityDates, 624 devicePropertiesAttestation, attestation); 625 } finally { 626 keyStore.deleteEntry(keystoreAlias); 627 } 628 } 629 checkAttestationApplicationId(Attestation attestation)630 private void checkAttestationApplicationId(Attestation attestation) 631 throws NoSuchAlgorithmException, NameNotFoundException { 632 AttestationApplicationId aaid = null; 633 int kmVersion = attestation.getKeymasterVersion(); 634 assertNull(attestation.getTeeEnforced().getAttestationApplicationId()); 635 aaid = attestation.getSoftwareEnforced().getAttestationApplicationId(); 636 if (kmVersion >= 3) { 637 // must be present and correct 638 assertNotNull(aaid); 639 assertEquals(new AttestationApplicationId(getContext()), aaid); 640 } else { 641 // may be present and 642 // must be correct if present 643 if (aaid != null) { 644 assertEquals(new AttestationApplicationId(getContext()), aaid); 645 } 646 } 647 } 648 checkAttestationDeviceProperties(boolean devicePropertiesAttestation, Attestation attestation)649 private void checkAttestationDeviceProperties(boolean devicePropertiesAttestation, 650 Attestation attestation) { 651 final AuthorizationList keyDetailsList; 652 final AuthorizationList nonKeyDetailsList; 653 if (attestation.getKeymasterSecurityLevel() == KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT) { 654 keyDetailsList = attestation.getTeeEnforced(); 655 nonKeyDetailsList = attestation.getSoftwareEnforced(); 656 } else { 657 keyDetailsList = attestation.getSoftwareEnforced(); 658 nonKeyDetailsList = attestation.getTeeEnforced(); 659 } 660 661 if (devicePropertiesAttestation) { 662 assertEquals(Build.BRAND, keyDetailsList.getBrand()); 663 assertEquals(Build.DEVICE, keyDetailsList.getDevice()); 664 assertEquals(Build.PRODUCT, keyDetailsList.getProduct()); 665 assertEquals(Build.MANUFACTURER, keyDetailsList.getManufacturer()); 666 assertEquals(Build.MODEL, keyDetailsList.getModel()); 667 } else { 668 assertNull(keyDetailsList.getBrand()); 669 assertNull(keyDetailsList.getDevice()); 670 assertNull(keyDetailsList.getProduct()); 671 assertNull(keyDetailsList.getManufacturer()); 672 assertNull(keyDetailsList.getModel()); 673 } 674 assertNull(nonKeyDetailsList.getBrand()); 675 assertNull(nonKeyDetailsList.getDevice()); 676 assertNull(nonKeyDetailsList.getProduct()); 677 assertNull(nonKeyDetailsList.getManufacturer()); 678 assertNull(nonKeyDetailsList.getModel()); 679 } 680 checkAttestationNoUniqueIds(Attestation attestation)681 private void checkAttestationNoUniqueIds(Attestation attestation) { 682 assertNull(attestation.getTeeEnforced().getImei()); 683 assertNull(attestation.getTeeEnforced().getMeid()); 684 assertNull(attestation.getTeeEnforced().getSerialNumber()); 685 assertNull(attestation.getSoftwareEnforced().getImei()); 686 assertNull(attestation.getSoftwareEnforced().getMeid()); 687 assertNull(attestation.getSoftwareEnforced().getSerialNumber()); 688 } 689 checkKeyIndependentAttestationInfo(byte[] challenge, int purposes, Date startTime, boolean includesValidityDates, boolean devicePropertiesAttestation, Attestation attestation)690 private void checkKeyIndependentAttestationInfo(byte[] challenge, int purposes, Date startTime, 691 boolean includesValidityDates, boolean devicePropertiesAttestation, 692 Attestation attestation) throws NoSuchAlgorithmException, NameNotFoundException { 693 checkUnexpectedOids(attestation); 694 checkAttestationSecurityLevelDependentParams(attestation); 695 assertNotNull(attestation.getAttestationChallenge()); 696 assertTrue(Arrays.equals(challenge, attestation.getAttestationChallenge())); 697 assertNotNull(attestation.getUniqueId()); 698 assertEquals(0, attestation.getUniqueId().length); 699 checkPurposes(attestation, purposes); 700 checkDigests(attestation, 701 ImmutableSet.of(KM_DIGEST_NONE, KM_DIGEST_SHA_2_256, KM_DIGEST_SHA_2_512)); 702 checkValidityPeriod(attestation, startTime, includesValidityDates); 703 checkFlags(attestation); 704 checkOrigin(attestation); 705 checkAttestationApplicationId(attestation); 706 checkAttestationDeviceProperties(devicePropertiesAttestation, attestation); 707 checkAttestationNoUniqueIds(attestation); 708 } 709 checkUnexpectedOids(Attestation attestation)710 private void checkUnexpectedOids(Attestation attestation) { 711 assertThat("Attestations must not contain any extra data", 712 attestation.getUnexpectedExtensionOids(), is(empty())); 713 } 714 getSystemPatchLevel()715 private int getSystemPatchLevel() { 716 Matcher matcher = OS_PATCH_LEVEL_STRING_PATTERN.matcher(Build.VERSION.SECURITY_PATCH); 717 assertTrue(matcher.matches()); 718 String year_string = matcher.group(OS_PATCH_LEVEL_YEAR_GROUP_NAME); 719 String month_string = matcher.group(OS_PATCH_LEVEL_MONTH_GROUP_NAME); 720 int patch_level = Integer.parseInt(year_string) * 100 + Integer.parseInt(month_string); 721 return patch_level; 722 } 723 getSystemOsVersion()724 private int getSystemOsVersion() { 725 return parseSystemOsVersion(Build.VERSION.RELEASE); 726 } 727 parseSystemOsVersion(String versionString)728 private int parseSystemOsVersion(String versionString) { 729 Matcher matcher = OS_VERSION_STRING_PATTERN.matcher(versionString); 730 if (!matcher.matches()) { 731 return 0; 732 } 733 734 int version = 0; 735 String major_string = matcher.group(OS_MAJOR_VERSION_MATCH_GROUP_NAME); 736 String minor_string = matcher.group(OS_MINOR_VERSION_MATCH_GROUP_NAME); 737 String subminor_string = matcher.group(OS_SUBMINOR_VERSION_MATCH_GROUP_NAME); 738 if (major_string != null) { 739 version += Integer.parseInt(major_string) * 10000; 740 } 741 if (minor_string != null) { 742 version += Integer.parseInt(minor_string) * 100; 743 } 744 if (subminor_string != null) { 745 version += Integer.parseInt(subminor_string); 746 } 747 return version; 748 } 749 checkOrigin(Attestation attestation)750 private void checkOrigin(Attestation attestation) { 751 assertTrue("Origin must be defined", 752 attestation.getSoftwareEnforced().getOrigin() != null || 753 attestation.getTeeEnforced().getOrigin() != null); 754 if (attestation.getKeymasterVersion() != 0) { 755 assertTrue("Origin may not be defined in both SW and TEE, except on keymaster0", 756 attestation.getSoftwareEnforced().getOrigin() == null || 757 attestation.getTeeEnforced().getOrigin() == null); 758 } 759 760 if (attestation.getKeymasterSecurityLevel() == KM_SECURITY_LEVEL_SOFTWARE) { 761 assertThat(attestation.getSoftwareEnforced().getOrigin(), is(KM_ORIGIN_GENERATED)); 762 } else if (attestation.getKeymasterVersion() == 0) { 763 assertThat(attestation.getTeeEnforced().getOrigin(), is(KM_ORIGIN_UNKNOWN)); 764 } else { 765 assertThat(attestation.getTeeEnforced().getOrigin(), is(KM_ORIGIN_GENERATED)); 766 } 767 } 768 checkFlags(Attestation attestation)769 private void checkFlags(Attestation attestation) { 770 assertFalse("All applications was not requested", 771 attestation.getSoftwareEnforced().isAllApplications()); 772 assertFalse("All applications was not requested", 773 attestation.getTeeEnforced().isAllApplications()); 774 assertFalse("Allow while on body was not requested", 775 attestation.getSoftwareEnforced().isAllowWhileOnBody()); 776 assertFalse("Allow while on body was not requested", 777 attestation.getTeeEnforced().isAllowWhileOnBody()); 778 assertNull("Auth binding was not requiested", 779 attestation.getSoftwareEnforced().getUserAuthType()); 780 assertNull("Auth binding was not requiested", 781 attestation.getTeeEnforced().getUserAuthType()); 782 assertTrue("noAuthRequired must be true", 783 attestation.getSoftwareEnforced().isNoAuthRequired() 784 || attestation.getTeeEnforced().isNoAuthRequired()); 785 assertFalse("auth is either software or TEE", 786 attestation.getSoftwareEnforced().isNoAuthRequired() 787 && attestation.getTeeEnforced().isNoAuthRequired()); 788 assertFalse("Software cannot implement rollback resistance", 789 attestation.getSoftwareEnforced().isRollbackResistant()); 790 } 791 checkValidityPeriod(Attestation attestation, Date startTime, boolean includesValidityDates)792 private void checkValidityPeriod(Attestation attestation, Date startTime, 793 boolean includesValidityDates) { 794 AuthorizationList validityPeriodList; 795 AuthorizationList nonValidityPeriodList; 796 if (attestation.getTeeEnforced().getCreationDateTime() != null) { 797 validityPeriodList = attestation.getTeeEnforced(); 798 nonValidityPeriodList = attestation.getSoftwareEnforced(); 799 } else { 800 validityPeriodList = attestation.getSoftwareEnforced(); 801 nonValidityPeriodList = attestation.getTeeEnforced(); 802 } 803 804 if (attestation.getKeymasterVersion() == 2) { 805 Date creationDateTime = validityPeriodList.getCreationDateTime(); 806 807 assertNotNull(creationDateTime); 808 assertNull(nonValidityPeriodList.getCreationDateTime()); 809 810 // We allow a little slop on creation times because the TEE/HAL may not be quite synced 811 // up with the system. 812 assertTrue("Test start time (" + startTime.getTime() + ") and key creation time (" + 813 creationDateTime.getTime() + ") should be close", 814 Math.abs(creationDateTime.getTime() - startTime.getTime()) <= 2000); 815 } 816 817 if (includesValidityDates) { 818 Date activeDateTime = validityPeriodList.getActiveDateTime(); 819 Date originationExpirationDateTime = validityPeriodList.getOriginationExpireDateTime(); 820 Date usageExpirationDateTime = validityPeriodList.getUsageExpireDateTime(); 821 822 assertNotNull(activeDateTime); 823 assertNotNull(originationExpirationDateTime); 824 assertNotNull(usageExpirationDateTime); 825 826 assertNull(nonValidityPeriodList.getActiveDateTime()); 827 assertNull(nonValidityPeriodList.getOriginationExpireDateTime()); 828 assertNull(nonValidityPeriodList.getUsageExpireDateTime()); 829 830 assertThat(originationExpirationDateTime.getTime(), 831 is(startTime.getTime() + ORIGINATION_TIME_OFFSET)); 832 assertThat(usageExpirationDateTime.getTime(), 833 is(startTime.getTime() + CONSUMPTION_TIME_OFFSET)); 834 } 835 } 836 checkDigests(Attestation attestation, Set<Integer> expectedDigests)837 private void checkDigests(Attestation attestation, Set<Integer> expectedDigests) { 838 Set<Integer> softwareEnforcedDigests = attestation.getSoftwareEnforced().getDigests(); 839 Set<Integer> teeEnforcedDigests = attestation.getTeeEnforced().getDigests(); 840 841 if (softwareEnforcedDigests == null) { 842 softwareEnforcedDigests = ImmutableSet.of(); 843 } 844 if (teeEnforcedDigests == null) { 845 teeEnforcedDigests = ImmutableSet.of(); 846 } 847 848 Set<Integer> allDigests = ImmutableSet.<Integer> builder() 849 .addAll(softwareEnforcedDigests) 850 .addAll(teeEnforcedDigests) 851 .build(); 852 Set<Integer> intersection = new ArraySet<>(); 853 intersection.addAll(softwareEnforcedDigests); 854 intersection.retainAll(teeEnforcedDigests); 855 856 assertThat(allDigests, is(expectedDigests)); 857 assertTrue("Digest sets must be disjoint", intersection.isEmpty()); 858 859 if (attestation.getKeymasterSecurityLevel() == KM_SECURITY_LEVEL_SOFTWARE 860 || attestation.getKeymasterVersion() == 0) { 861 assertThat("Digests in software-enforced", 862 softwareEnforcedDigests, is(expectedDigests)); 863 } else { 864 switch (attestation.getKeymasterVersion()) { 865 case 1: 866 // KM1 implementations may not support SHA512 in the TEE 867 assertTrue(softwareEnforcedDigests.contains(KM_DIGEST_SHA_2_512) 868 || teeEnforcedDigests.contains(KM_DIGEST_SHA_2_512)); 869 870 assertThat(teeEnforcedDigests, hasItems(KM_DIGEST_NONE, KM_DIGEST_SHA_2_256)); 871 break; 872 873 case 2: 874 case 3: 875 case 4: 876 assertThat(teeEnforcedDigests, is(expectedDigests)); 877 break; 878 879 default: 880 fail("Broken CTS test. Should be impossible to get here."); 881 } 882 } 883 } 884 checkPurposes(Attestation attestation, int purposes)885 private Set<Integer> checkPurposes(Attestation attestation, int purposes) { 886 Set<Integer> expectedPurposes = buildPurposeSet(purposes); 887 if (attestation.getKeymasterSecurityLevel() == KM_SECURITY_LEVEL_SOFTWARE 888 || attestation.getKeymasterVersion() == 0) { 889 assertThat("Purposes in software-enforced should match expected set", 890 attestation.getSoftwareEnforced().getPurposes(), is(expectedPurposes)); 891 assertNull("Should be no purposes in TEE-enforced", 892 attestation.getTeeEnforced().getPurposes()); 893 } else { 894 assertThat("Purposes in TEE-enforced should match expected set", 895 attestation.getTeeEnforced().getPurposes(), is(expectedPurposes)); 896 assertNull("No purposes in software-enforced", 897 attestation.getSoftwareEnforced().getPurposes()); 898 } 899 return expectedPurposes; 900 } 901 902 @SuppressWarnings("unchecked") checkAttestationSecurityLevelDependentParams(Attestation attestation)903 private void checkAttestationSecurityLevelDependentParams(Attestation attestation) { 904 assertThat("Attestation version must be 1, 2, 3, or 4", attestation.getAttestationVersion(), 905 either(is(1)).or(is(2)).or(is(3)).or(is(4))); 906 907 AuthorizationList teeEnforced = attestation.getTeeEnforced(); 908 AuthorizationList softwareEnforced = attestation.getSoftwareEnforced(); 909 910 int systemOsVersion = getSystemOsVersion(); 911 int systemPatchLevel = getSystemPatchLevel(); 912 913 switch (attestation.getAttestationSecurityLevel()) { 914 case KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT: 915 assertThat("TEE attestation can only come from TEE keymaster", 916 attestation.getKeymasterSecurityLevel(), 917 is(KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT)); 918 assertThat(attestation.getKeymasterVersion(), 919 either(is(2)).or(is(3)).or(is(4)).or(is(41))); 920 921 checkRootOfTrust(attestation, false /* requireLocked */); 922 assertThat(teeEnforced.getOsVersion(), is(systemOsVersion)); 923 assertThat(teeEnforced.getOsPatchLevel(), is(systemPatchLevel)); 924 break; 925 926 case KM_SECURITY_LEVEL_SOFTWARE: 927 if (attestation 928 .getKeymasterSecurityLevel() == KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT) { 929 assertThat("TEE KM version must be 0 or 1 with software attestation", 930 attestation.getKeymasterVersion(), either(is(0)).or(is(1))); 931 } else { 932 assertThat("Software KM is version 3", attestation.getKeymasterVersion(), 933 is(3)); 934 assertThat(softwareEnforced.getOsVersion(), is(systemOsVersion)); 935 assertThat(softwareEnforced.getOsPatchLevel(), is(systemPatchLevel)); 936 } 937 938 assertNull("Software attestation cannot provide root of trust", 939 teeEnforced.getRootOfTrust()); 940 941 break; 942 943 default: 944 fail("Invalid attestation security level: " 945 + attestation.getAttestationSecurityLevel()); 946 break; 947 } 948 949 assertNull("Software-enforced list must not contain root of trust", 950 softwareEnforced.getRootOfTrust()); 951 } 952 checkDeviceLocked(Attestation attestation)953 private void checkDeviceLocked(Attestation attestation) { 954 assertThat("Attestation version must be >= 1", 955 attestation.getAttestationVersion(), greaterThanOrEqualTo(1)); 956 957 int attestationSecurityLevel = attestation.getAttestationSecurityLevel(); 958 switch (attestationSecurityLevel) { 959 case KM_SECURITY_LEVEL_STRONG_BOX: 960 case KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT: 961 assertThat("Attestation security level doesn't match keymaster security level", 962 attestation.getKeymasterSecurityLevel(), is(attestationSecurityLevel)); 963 assertThat(attestation.getKeymasterVersion(), greaterThanOrEqualTo(2)); 964 965 // Devices launched in Android 10.0 (API level 29) and after should run CTS 966 // in LOCKED state. 967 boolean requireLocked = ( 968 SystemProperties.getInt("ro.product.first_api_level", 0) >= 29); 969 checkRootOfTrust(attestation, requireLocked); 970 break; 971 972 case KM_SECURITY_LEVEL_SOFTWARE: 973 default: 974 // TEE attestation has been required since Android 7.0. 975 fail("Unexpected attestation security level: " + 976 attestation.securityLevelToString(attestationSecurityLevel)); 977 break; 978 } 979 } 980 checkRootOfTrust(Attestation attestation, boolean requireLocked)981 private void checkRootOfTrust(Attestation attestation, boolean requireLocked) { 982 RootOfTrust rootOfTrust = attestation.getTeeEnforced().getRootOfTrust(); 983 assertNotNull(rootOfTrust); 984 assertNotNull(rootOfTrust.getVerifiedBootKey()); 985 assertTrue("Verified boot key is only " + rootOfTrust.getVerifiedBootKey().length + 986 " bytes long", rootOfTrust.getVerifiedBootKey().length >= 32); 987 if (requireLocked) { 988 assertTrue(rootOfTrust.isDeviceLocked()); 989 checkEntropy(rootOfTrust.getVerifiedBootKey()); 990 assertEquals(KM_VERIFIED_BOOT_VERIFIED, rootOfTrust.getVerifiedBootState()); 991 } 992 } 993 checkEntropy(byte[] verifiedBootKey)994 private void checkEntropy(byte[] verifiedBootKey) { 995 assertTrue("Failed Shannon entropy check", checkShannonEntropy(verifiedBootKey)); 996 assertTrue("Failed BiEntropy check", checkTresBiEntropy(verifiedBootKey)); 997 } 998 checkShannonEntropy(byte[] verifiedBootKey)999 private boolean checkShannonEntropy(byte[] verifiedBootKey) { 1000 double probabilityOfSetBit = countSetBits(verifiedBootKey) / (double)(verifiedBootKey.length * 8); 1001 return calculateShannonEntropy(probabilityOfSetBit) > 0.8; 1002 } 1003 calculateShannonEntropy(double probabilityOfSetBit)1004 private double calculateShannonEntropy(double probabilityOfSetBit) { 1005 if (probabilityOfSetBit <= 0.001 || probabilityOfSetBit >= .999) return 0; 1006 double entropy = (-probabilityOfSetBit * logTwo(probabilityOfSetBit)) - 1007 ((1 - probabilityOfSetBit) * logTwo(1 - probabilityOfSetBit)); 1008 Log.i(TAG, "Shannon entropy of VB Key: " + entropy); 1009 return entropy; 1010 } 1011 checkTresBiEntropy(byte[] verifiedBootKey)1012 private boolean checkTresBiEntropy(byte[] verifiedBootKey) { 1013 double weightingFactor = 0; 1014 double weightedEntropy = 0; 1015 double probabilityOfSetBit = 0; 1016 int length = verifiedBootKey.length * 8; 1017 for(int i = 0; i < (verifiedBootKey.length * 8) - 2; i++) { 1018 probabilityOfSetBit = countSetBits(verifiedBootKey) / (double)length; 1019 weightingFactor += logTwo(i+2); 1020 weightedEntropy += calculateShannonEntropy(probabilityOfSetBit) * logTwo(i+2); 1021 deriveBitString(verifiedBootKey, length); 1022 length -= 1; 1023 } 1024 double tresBiEntropy = (1 / weightingFactor) * weightedEntropy; 1025 Log.i(TAG, "BiEntropy of VB Key: " + tresBiEntropy); 1026 return tresBiEntropy > 0.9; 1027 } 1028 deriveBitString(byte[] bitString, int activeLength)1029 private void deriveBitString(byte[] bitString, int activeLength) { 1030 int length = activeLength / 8; 1031 if (activeLength % 8 != 0) { 1032 length += 1; 1033 } 1034 1035 byte mask = (byte)((byte)0x80 >>> ((activeLength + 6) % 8)); 1036 if (activeLength % 8 == 1) { 1037 mask = (byte)~mask; 1038 } 1039 1040 for(int i = 0; i < length; i++) { 1041 if (i == length - 1) { 1042 bitString[i] ^= ((bitString[i] & 0xFF) << 1); 1043 bitString[i] &= mask; 1044 } else { 1045 bitString[i] ^= ((bitString[i] & 0xFF) << 1) | ((bitString[i+1] & 0xFF) >>> 7); 1046 } 1047 } 1048 } 1049 logTwo(double value)1050 private double logTwo(double value) { 1051 return Math.log(value) / Math.log(2); 1052 } 1053 countSetBits(byte[] toCount)1054 private int countSetBits(byte[] toCount) { 1055 int setBitCount = 0; 1056 for(int i = 0; i < toCount.length; i++) { 1057 setBitCount += countSetBits(toCount[i]); 1058 } 1059 return setBitCount; 1060 } 1061 countSetBits(byte toCount)1062 private int countSetBits(byte toCount) { 1063 int setBitCounter = 0; 1064 while(toCount != 0) { 1065 toCount &= (toCount - 1); 1066 setBitCounter++; 1067 } 1068 return setBitCounter; 1069 } 1070 checkRsaKeyDetails(Attestation attestation, int keySize, int purposes, Set<String> expectedPaddingModes)1071 private void checkRsaKeyDetails(Attestation attestation, int keySize, int purposes, 1072 Set<String> expectedPaddingModes) throws CertificateParsingException { 1073 AuthorizationList keyDetailsList; 1074 AuthorizationList nonKeyDetailsList; 1075 if (attestation.getKeymasterSecurityLevel() == KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT) { 1076 keyDetailsList = attestation.getTeeEnforced(); 1077 nonKeyDetailsList = attestation.getSoftwareEnforced(); 1078 } else { 1079 keyDetailsList = attestation.getSoftwareEnforced(); 1080 nonKeyDetailsList = attestation.getTeeEnforced(); 1081 } 1082 assertEquals(keySize, keyDetailsList.getKeySize().intValue()); 1083 assertNull(nonKeyDetailsList.getKeySize()); 1084 1085 assertEquals(KM_ALGORITHM_RSA, keyDetailsList.getAlgorithm().intValue()); 1086 assertNull(nonKeyDetailsList.getAlgorithm()); 1087 1088 assertNull(keyDetailsList.getEcCurve()); 1089 assertNull(nonKeyDetailsList.getEcCurve()); 1090 1091 assertEquals(65537, keyDetailsList.getRsaPublicExponent().longValue()); 1092 assertNull(nonKeyDetailsList.getRsaPublicExponent()); 1093 1094 Set<String> paddingModes; 1095 if (attestation.getKeymasterVersion() == 0) { 1096 // KM0 implementations don't support padding info, so it's always in the 1097 // software-enforced list. 1098 paddingModes = attestation.getSoftwareEnforced().getPaddingModesAsStrings(); 1099 assertNull(attestation.getTeeEnforced().getPaddingModes()); 1100 } else { 1101 paddingModes = keyDetailsList.getPaddingModesAsStrings(); 1102 assertNull(nonKeyDetailsList.getPaddingModes()); 1103 } 1104 1105 // KM1 implementations may add ENCRYPTION_PADDING_NONE to the list of paddings. 1106 Set<String> km1PossiblePaddingModes = expectedPaddingModes; 1107 if (attestation.getKeymasterVersion() == 1 && 1108 attestation.getKeymasterSecurityLevel() == KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT) { 1109 ImmutableSet.Builder<String> builder = ImmutableSet.builder(); 1110 builder.addAll(expectedPaddingModes); 1111 builder.add(ENCRYPTION_PADDING_NONE); 1112 km1PossiblePaddingModes = builder.build(); 1113 } 1114 1115 assertThat(paddingModes, either(is(expectedPaddingModes)).or(is(km1PossiblePaddingModes))); 1116 } 1117 checkEcKeyDetails(Attestation attestation, String ecCurve, int keySize)1118 private void checkEcKeyDetails(Attestation attestation, String ecCurve, int keySize) { 1119 AuthorizationList keyDetailsList; 1120 AuthorizationList nonKeyDetailsList; 1121 if (attestation.getKeymasterSecurityLevel() == KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT) { 1122 keyDetailsList = attestation.getTeeEnforced(); 1123 nonKeyDetailsList = attestation.getSoftwareEnforced(); 1124 } else { 1125 keyDetailsList = attestation.getSoftwareEnforced(); 1126 nonKeyDetailsList = attestation.getTeeEnforced(); 1127 } 1128 assertEquals(keySize, keyDetailsList.getKeySize().intValue()); 1129 assertNull(nonKeyDetailsList.getKeySize()); 1130 assertEquals(KM_ALGORITHM_EC, keyDetailsList.getAlgorithm().intValue()); 1131 assertNull(nonKeyDetailsList.getAlgorithm()); 1132 assertEquals(ecCurve, keyDetailsList.ecCurveAsString()); 1133 assertNull(nonKeyDetailsList.getEcCurve()); 1134 assertNull(keyDetailsList.getRsaPublicExponent()); 1135 assertNull(nonKeyDetailsList.getRsaPublicExponent()); 1136 assertNull(keyDetailsList.getPaddingModes()); 1137 assertNull(nonKeyDetailsList.getPaddingModes()); 1138 } 1139 isEncryptionPurpose(int purposes)1140 private boolean isEncryptionPurpose(int purposes) { 1141 return (purposes & PURPOSE_DECRYPT) != 0 || (purposes & PURPOSE_ENCRYPT) != 0; 1142 } 1143 isSignaturePurpose(int purposes)1144 private boolean isSignaturePurpose(int purposes) { 1145 return (purposes & PURPOSE_SIGN) != 0 || (purposes & PURPOSE_VERIFY) != 0; 1146 } 1147 buildPurposeSet(int purposes)1148 private ImmutableSet<Integer> buildPurposeSet(int purposes) { 1149 ImmutableSet.Builder<Integer> builder = ImmutableSet.builder(); 1150 if ((purposes & PURPOSE_SIGN) != 0) 1151 builder.add(KM_PURPOSE_SIGN); 1152 if ((purposes & PURPOSE_VERIFY) != 0) 1153 builder.add(KM_PURPOSE_VERIFY); 1154 if ((purposes & PURPOSE_ENCRYPT) != 0) 1155 builder.add(KM_PURPOSE_ENCRYPT); 1156 if ((purposes & PURPOSE_DECRYPT) != 0) 1157 builder.add(KM_PURPOSE_DECRYPT); 1158 return builder.build(); 1159 } 1160 generateKey(KeyGenParameterSpec spec, String algorithm)1161 private void generateKey(KeyGenParameterSpec spec, String algorithm) 1162 throws NoSuchAlgorithmException, NoSuchProviderException, 1163 InvalidAlgorithmParameterException { 1164 KeyGenerator keyGenerator = KeyGenerator.getInstance(algorithm, "AndroidKeyStore"); 1165 keyGenerator.init(spec); 1166 keyGenerator.generateKey(); 1167 } 1168 generateKeyPair(String algorithm, KeyGenParameterSpec spec)1169 private void generateKeyPair(String algorithm, KeyGenParameterSpec spec) 1170 throws NoSuchAlgorithmException, NoSuchProviderException, 1171 InvalidAlgorithmParameterException { 1172 KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(algorithm, 1173 "AndroidKeyStore"); 1174 keyPairGenerator.initialize(spec); 1175 keyPairGenerator.generateKeyPair(); 1176 } 1177 verifyCertificateChain(Certificate[] certChain, boolean expectStrongBox)1178 private void verifyCertificateChain(Certificate[] certChain, boolean expectStrongBox) 1179 throws GeneralSecurityException { 1180 assertNotNull(certChain); 1181 for (int i = 1; i < certChain.length; ++i) { 1182 try { 1183 PublicKey pubKey = certChain[i].getPublicKey(); 1184 certChain[i - 1].verify(pubKey); 1185 if (i == certChain.length - 1) { 1186 // Last cert should be self-signed. 1187 certChain[i].verify(pubKey); 1188 } 1189 1190 // Check that issuer in the signed cert matches subject in the signing cert. 1191 X509Certificate x509CurrCert = (X509Certificate) certChain[i]; 1192 X509Certificate x509PrevCert = (X509Certificate) certChain[i - 1]; 1193 X500Name signingCertSubject = 1194 new JcaX509CertificateHolder(x509CurrCert).getSubject(); 1195 X500Name signedCertIssuer = 1196 new JcaX509CertificateHolder(x509PrevCert).getIssuer(); 1197 // Use .toASN1Object().equals() rather than .equals() because .equals() is case 1198 // insensitive, and we want to verify an exact match. 1199 assertTrue( 1200 signedCertIssuer.toASN1Object().equals(signingCertSubject.toASN1Object())); 1201 1202 if (i == 1) { 1203 // First cert should have subject "CN=Android Keystore Key". 1204 X500Name signedCertSubject = 1205 new JcaX509CertificateHolder(x509PrevCert).getSubject(); 1206 assertEquals(signedCertSubject, new X500Name("CN=Android Keystore Key")); 1207 } else { 1208 // Only strongbox implementations should have strongbox in the subject line 1209 assertEquals(expectStrongBox, x509CurrCert.getSubjectDN() 1210 .getName() 1211 .toLowerCase() 1212 .contains("strongbox")); 1213 } 1214 } catch (InvalidKeyException | CertificateException | NoSuchAlgorithmException 1215 | NoSuchProviderException | SignatureException e) { 1216 throw new GeneralSecurityException("Using StrongBox: " + expectStrongBox + "\n" 1217 + "Failed to verify certificate " 1218 + certChain[i - 1] + " with public key " + certChain[i].getPublicKey(), e); 1219 } 1220 } 1221 } 1222 testDeviceIdAttestationFailure(int idType, String acceptableDeviceIdAttestationFailureMessage)1223 private void testDeviceIdAttestationFailure(int idType, 1224 String acceptableDeviceIdAttestationFailureMessage) throws Exception { 1225 try { 1226 AttestationUtils.attestDeviceIds(getContext(), new int[] {idType}, "123".getBytes()); 1227 fail("Attestation should have failed."); 1228 } catch (SecurityException e) { 1229 // Attestation is expected to fail. If the device has the device ID type we are trying 1230 // to attest, it should fail with a SecurityException as we do not hold 1231 // READ_PRIVILEGED_PHONE_STATE permission. 1232 } catch (DeviceIdAttestationException e) { 1233 // Attestation is expected to fail. If the device does not have the device ID type we 1234 // are trying to attest (e.g. no IMEI on devices without a radio), it should fail with 1235 // a corresponding DeviceIdAttestationException. 1236 if (acceptableDeviceIdAttestationFailureMessage == null || 1237 !acceptableDeviceIdAttestationFailureMessage.equals(e.getMessage())) { 1238 throw e; 1239 } 1240 } 1241 } 1242 } 1243