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 android.os.SystemProperties; 20 import android.platform.test.annotations.RestrictedBuildTest; 21 22 import static android.keystore.cts.Attestation.KM_SECURITY_LEVEL_SOFTWARE; 23 import static android.keystore.cts.Attestation.KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT; 24 import static android.keystore.cts.AuthorizationList.KM_ALGORITHM_EC; 25 import static android.keystore.cts.AuthorizationList.KM_ALGORITHM_RSA; 26 import static android.keystore.cts.AuthorizationList.KM_DIGEST_NONE; 27 import static android.keystore.cts.AuthorizationList.KM_DIGEST_SHA_2_256; 28 import static android.keystore.cts.AuthorizationList.KM_DIGEST_SHA_2_512; 29 import static android.keystore.cts.AuthorizationList.KM_ORIGIN_GENERATED; 30 import static android.keystore.cts.AuthorizationList.KM_ORIGIN_UNKNOWN; 31 import static android.keystore.cts.AuthorizationList.KM_PURPOSE_DECRYPT; 32 import static android.keystore.cts.AuthorizationList.KM_PURPOSE_ENCRYPT; 33 import static android.keystore.cts.AuthorizationList.KM_PURPOSE_SIGN; 34 import static android.keystore.cts.AuthorizationList.KM_PURPOSE_VERIFY; 35 import static android.keystore.cts.RootOfTrust.KM_VERIFIED_BOOT_VERIFIED; 36 import static android.security.keystore.KeyProperties.DIGEST_NONE; 37 import static android.security.keystore.KeyProperties.DIGEST_SHA256; 38 import static android.security.keystore.KeyProperties.DIGEST_SHA512; 39 import static android.security.keystore.KeyProperties.ENCRYPTION_PADDING_NONE; 40 import static android.security.keystore.KeyProperties.ENCRYPTION_PADDING_RSA_OAEP; 41 import static android.security.keystore.KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1; 42 import static android.security.keystore.KeyProperties.KEY_ALGORITHM_EC; 43 import static android.security.keystore.KeyProperties.KEY_ALGORITHM_RSA; 44 import static android.security.keystore.KeyProperties.PURPOSE_DECRYPT; 45 import static android.security.keystore.KeyProperties.PURPOSE_ENCRYPT; 46 import static android.security.keystore.KeyProperties.PURPOSE_SIGN; 47 import static android.security.keystore.KeyProperties.PURPOSE_VERIFY; 48 import static android.security.keystore.KeyProperties.SIGNATURE_PADDING_RSA_PKCS1; 49 import static android.security.keystore.KeyProperties.SIGNATURE_PADDING_RSA_PSS; 50 import static org.hamcrest.CoreMatchers.is; 51 import static org.junit.Assert.assertThat; 52 import static org.junit.matchers.JUnitMatchers.either; 53 import static org.junit.matchers.JUnitMatchers.hasItems; 54 55 import com.google.common.collect.ImmutableSet; 56 import android.content.pm.PackageManager.NameNotFoundException; 57 import android.content.Context; 58 import android.os.Build; 59 import android.os.SystemProperties; 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 68 import org.bouncycastle.asn1.x500.X500Name; 69 import org.bouncycastle.cert.jcajce.JcaX509CertificateHolder; 70 71 import java.security.GeneralSecurityException; 72 import java.security.InvalidAlgorithmParameterException; 73 import java.security.InvalidKeyException; 74 import java.security.KeyPairGenerator; 75 import java.security.KeyStore; 76 import java.security.NoSuchAlgorithmException; 77 import java.security.NoSuchProviderException; 78 import java.security.ProviderException; 79 import java.security.PublicKey; 80 import java.security.SignatureException; 81 import java.security.cert.Certificate; 82 import java.security.cert.CertificateException; 83 import java.security.cert.CertificateParsingException; 84 import java.security.cert.X509Certificate; 85 import java.security.spec.ECGenParameterSpec; 86 import java.util.Arrays; 87 import java.util.Date; 88 import java.util.Set; 89 import java.util.regex.Matcher; 90 import java.util.regex.Pattern; 91 92 import javax.crypto.KeyGenerator; 93 94 /** 95 * Tests for Android KeysStore attestation. 96 */ 97 public class KeyAttestationTest extends AndroidTestCase { 98 99 private static final int ORIGINATION_TIME_OFFSET = 1000000; 100 private static final int CONSUMPTION_TIME_OFFSET = 2000000; 101 102 private static final int KEY_USAGE_BITSTRING_LENGTH = 9; 103 private static final int KEY_USAGE_DIGITAL_SIGNATURE_BIT_OFFSET = 0; 104 private static final int KEY_USAGE_KEY_ENCIPHERMENT_BIT_OFFSET = 2; 105 private static final int KEY_USAGE_DATA_ENCIPHERMENT_BIT_OFFSET = 3; 106 107 private static final int OS_MAJOR_VERSION_MATCH_GROUP_NAME = 1; 108 private static final int OS_MINOR_VERSION_MATCH_GROUP_NAME = 2; 109 private static final int OS_SUBMINOR_VERSION_MATCH_GROUP_NAME = 3; 110 private static final Pattern OS_VERSION_STRING_PATTERN = Pattern 111 .compile("([0-9]{1,2})(?:\\.([0-9]{1,2}))?(?:\\.([0-9]{1,2}))?(?:[^0-9.]+.*)?"); 112 113 private static final int OS_PATCH_LEVEL_YEAR_GROUP_NAME = 1; 114 private static final int OS_PATCH_LEVEL_MONTH_GROUP_NAME = 2; 115 private static final Pattern OS_PATCH_LEVEL_STRING_PATTERN = Pattern 116 .compile("([0-9]{4})-([0-9]{2})-[0-9]{2}"); 117 118 private static final int KM_ERROR_INVALID_INPUT_LENGTH = -21; 119 private static final int KM_ERROR_PERMISSION_DENIED = 6; 120 testVersionParser()121 public void testVersionParser() throws Exception { 122 // Non-numerics/empty give version 0 123 assertEquals(0, parseSystemOsVersion("")); 124 assertEquals(0, parseSystemOsVersion("N")); 125 126 // Should support one, two or three version number values. 127 assertEquals(10000, parseSystemOsVersion("1")); 128 assertEquals(10200, parseSystemOsVersion("1.2")); 129 assertEquals(10203, parseSystemOsVersion("1.2.3")); 130 131 // It's fine to append other stuff to the dotted numeric version. 132 assertEquals(10000, parseSystemOsVersion("1stuff")); 133 assertEquals(10200, parseSystemOsVersion("1.2garbage.32")); 134 assertEquals(10203, parseSystemOsVersion("1.2.3-stuff")); 135 136 // Two digits per version field are supported 137 assertEquals(152536, parseSystemOsVersion("15.25.36")); 138 assertEquals(999999, parseSystemOsVersion("99.99.99")); 139 assertEquals(0, parseSystemOsVersion("100.99.99")); 140 assertEquals(0, parseSystemOsVersion("99.100.99")); 141 assertEquals(0, parseSystemOsVersion("99.99.100")); 142 } 143 144 @RestrictedBuildTest testEcAttestation()145 public void testEcAttestation() throws Exception { 146 // Note: Curve and key sizes arrays must correspond. 147 String[] curves = { 148 "secp224r1", "secp256r1", "secp384r1", "secp521r1" 149 }; 150 int[] keySizes = { 151 224, 256, 384, 521 152 }; 153 byte[][] challenges = { 154 new byte[0], // empty challenge 155 "challenge".getBytes(), // short challenge 156 new byte[128], // long challenge 157 }; 158 int[] purposes = { 159 KM_PURPOSE_SIGN, KM_PURPOSE_VERIFY, KM_PURPOSE_SIGN | KM_PURPOSE_VERIFY 160 }; 161 162 for (int curveIndex = 0; curveIndex < curves.length; ++curveIndex) { 163 for (int challengeIndex = 0; challengeIndex < challenges.length; ++challengeIndex) { 164 for (int purposeIndex = 0; purposeIndex < purposes.length; ++purposeIndex) { 165 try { 166 testEcAttestation(challenges[challengeIndex], 167 true /* includeValidityDates */, 168 curves[curveIndex], keySizes[curveIndex], purposes[purposeIndex]); 169 testEcAttestation(challenges[challengeIndex], 170 false /* includeValidityDates */, 171 curves[curveIndex], keySizes[curveIndex], purposes[purposeIndex]); 172 } catch (Throwable e) { 173 throw new Exception( 174 "Failed on curve " + curveIndex + " and challege " + challengeIndex, 175 e); 176 } 177 } 178 } 179 } 180 } 181 testEcAttestation_TooLargeChallenge()182 public void testEcAttestation_TooLargeChallenge() throws Exception { 183 try { 184 testEcAttestation(new byte[129], true /* includeValidityDates */, "secp256r1", 256, 185 KM_PURPOSE_SIGN); 186 fail("Attestation challenges larger than 128 bytes should be rejected"); 187 } catch (ProviderException e) { 188 KeyStoreException cause = (KeyStoreException) e.getCause(); 189 assertEquals(KM_ERROR_INVALID_INPUT_LENGTH, cause.getErrorCode()); 190 } 191 } 192 testEcAttestation_NoChallenge()193 public void testEcAttestation_NoChallenge() throws Exception { 194 String keystoreAlias = "test_key"; 195 Date now = new Date(); 196 Date originationEnd = new Date(now.getTime() + ORIGINATION_TIME_OFFSET); 197 Date consumptionEnd = new Date(now.getTime() + CONSUMPTION_TIME_OFFSET); 198 KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(keystoreAlias, PURPOSE_SIGN) 199 .setAlgorithmParameterSpec(new ECGenParameterSpec("secp256r1")) 200 .setDigests(DIGEST_NONE, DIGEST_SHA256, DIGEST_SHA512) 201 .setAttestationChallenge(null) 202 .setKeyValidityStart(now) 203 .setKeyValidityForOriginationEnd(originationEnd) 204 .setKeyValidityForConsumptionEnd(consumptionEnd) 205 .build(); 206 207 generateKeyPair(KEY_ALGORITHM_EC, spec); 208 209 KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); 210 keyStore.load(null); 211 212 try { 213 Certificate certificates[] = keyStore.getCertificateChain(keystoreAlias); 214 assertEquals(1, certificates.length); 215 216 X509Certificate attestationCert = (X509Certificate) certificates[0]; 217 assertNull(attestationCert.getExtensionValue(Attestation.KEY_DESCRIPTION_OID)); 218 } finally { 219 keyStore.deleteEntry(keystoreAlias); 220 } 221 } 222 testEcAttestation_KeyStoreExceptionWhenRequestingUniqueId()223 public void testEcAttestation_KeyStoreExceptionWhenRequestingUniqueId() throws Exception { 224 String keystoreAlias = "test_key"; 225 KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(keystoreAlias, PURPOSE_SIGN) 226 .setAlgorithmParameterSpec(new ECGenParameterSpec("secp256r1")) 227 .setDigests(DIGEST_NONE, DIGEST_SHA256, DIGEST_SHA512) 228 .setAttestationChallenge(new byte[128]) 229 .setUniqueIdIncluded(true) 230 .build(); 231 232 try { 233 generateKeyPair(KEY_ALGORITHM_EC, spec); 234 fail("Attestation should have failed."); 235 } catch (ProviderException e) { 236 // Attestation is expected to fail because of lack of permissions. 237 KeyStoreException cause = (KeyStoreException) e.getCause(); 238 assertEquals(KM_ERROR_PERMISSION_DENIED, cause.getErrorCode()); 239 } finally { 240 KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); 241 keyStore.load(null); 242 keyStore.deleteEntry(keystoreAlias); 243 } 244 } 245 246 @RestrictedBuildTest testRsaAttestation()247 public void testRsaAttestation() throws Exception { 248 int[] keySizes = { // Smallish sizes to keep test runtimes down. 249 512, 768, 1024 250 }; 251 byte[][] challenges = { 252 new byte[0], // empty challenge 253 "challenge".getBytes(), // short challenge 254 new byte[128] // long challenge 255 }; 256 int[] purposes = { 257 PURPOSE_SIGN | PURPOSE_VERIFY, 258 PURPOSE_ENCRYPT | PURPOSE_DECRYPT, 259 }; 260 String[][] encryptionPaddingModes = { 261 { 262 ENCRYPTION_PADDING_NONE 263 }, 264 { 265 ENCRYPTION_PADDING_RSA_OAEP, 266 }, 267 { 268 ENCRYPTION_PADDING_RSA_PKCS1, 269 }, 270 { 271 ENCRYPTION_PADDING_RSA_OAEP, 272 ENCRYPTION_PADDING_RSA_PKCS1, 273 }, 274 }; 275 String[][] signaturePaddingModes = { 276 { 277 SIGNATURE_PADDING_RSA_PKCS1, 278 }, 279 { 280 SIGNATURE_PADDING_RSA_PSS, 281 }, 282 { 283 SIGNATURE_PADDING_RSA_PKCS1, 284 SIGNATURE_PADDING_RSA_PSS, 285 }, 286 }; 287 288 for (int keySize : keySizes) { 289 for (byte[] challenge : challenges) { 290 for (int purpose : purposes) { 291 if (isEncryptionPurpose(purpose)) { 292 testRsaAttestations(keySize, challenge, purpose, encryptionPaddingModes); 293 } else { 294 testRsaAttestations(keySize, challenge, purpose, signaturePaddingModes); 295 } 296 } 297 } 298 } 299 } 300 testRsaAttestation_TooLargeChallenge()301 public void testRsaAttestation_TooLargeChallenge() throws Exception { 302 try { 303 testRsaAttestation(new byte[129], true /* includeValidityDates */, 512, PURPOSE_SIGN, 304 null /* paddingModes; may be empty because we'll never test them */); 305 fail("Attestation challenges larger than 128 bytes should be rejected"); 306 } catch (ProviderException e) { 307 KeyStoreException cause = (KeyStoreException) e.getCause(); 308 assertEquals(KM_ERROR_INVALID_INPUT_LENGTH, cause.getErrorCode()); 309 } 310 } 311 testRsaAttestation_NoChallenge()312 public void testRsaAttestation_NoChallenge() throws Exception { 313 String keystoreAlias = "test_key"; 314 Date now = new Date(); 315 Date originationEnd = new Date(now.getTime() + ORIGINATION_TIME_OFFSET); 316 Date consumptionEnd = new Date(now.getTime() + CONSUMPTION_TIME_OFFSET); 317 KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(keystoreAlias, PURPOSE_SIGN) 318 .setDigests(DIGEST_NONE, DIGEST_SHA256, DIGEST_SHA512) 319 .setAttestationChallenge(null) 320 .setKeyValidityStart(now) 321 .setKeyValidityForOriginationEnd(originationEnd) 322 .setKeyValidityForConsumptionEnd(consumptionEnd) 323 .build(); 324 325 generateKeyPair(KEY_ALGORITHM_RSA, spec); 326 327 KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); 328 keyStore.load(null); 329 330 try { 331 Certificate certificates[] = keyStore.getCertificateChain(keystoreAlias); 332 assertEquals(1, certificates.length); 333 334 X509Certificate attestationCert = (X509Certificate) certificates[0]; 335 assertNull(attestationCert.getExtensionValue(Attestation.KEY_DESCRIPTION_OID)); 336 } finally { 337 keyStore.deleteEntry(keystoreAlias); 338 } 339 } 340 testAesAttestation()341 public void testAesAttestation() throws Exception { 342 String keystoreAlias = "test_key"; 343 KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(keystoreAlias, PURPOSE_ENCRYPT) 344 .setBlockModes(KeyProperties.BLOCK_MODE_GCM) 345 .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE) 346 .setAttestationChallenge(new byte[0]) 347 .build(); 348 generateKey(spec, KeyProperties.KEY_ALGORITHM_AES); 349 350 KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); 351 keyStore.load(null); 352 try { 353 assertNull(keyStore.getCertificateChain(keystoreAlias)); 354 } finally { 355 keyStore.deleteEntry(keystoreAlias); 356 } 357 } 358 testHmacAttestation()359 public void testHmacAttestation() throws Exception { 360 String keystoreAlias = "test_key"; 361 KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(keystoreAlias, PURPOSE_SIGN) 362 .build(); 363 364 generateKey(spec, KeyProperties.KEY_ALGORITHM_HMAC_SHA256); 365 366 KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); 367 keyStore.load(null); 368 try { 369 assertNull(keyStore.getCertificateChain(keystoreAlias)); 370 } finally { 371 keyStore.deleteEntry(keystoreAlias); 372 } 373 } 374 testRsaAttestations(int keySize, byte[] challenge, int purpose, String[][] paddingModes)375 private void testRsaAttestations(int keySize, byte[] challenge, int purpose, 376 String[][] paddingModes) throws Exception { 377 for (String[] paddings : paddingModes) { 378 try { 379 testRsaAttestation(challenge, true /* includeValidityDates */, keySize, purpose, 380 paddings); 381 testRsaAttestation(challenge, false /* includeValidityDates */, keySize, purpose, 382 paddings); 383 } catch (Throwable e) { 384 throw new Exception("Failed on key size " + keySize + " challenge [" + 385 new String(challenge) + "], purposes " + 386 buildPurposeSet(purpose) + " and paddings " + 387 ImmutableSet.copyOf(paddings), 388 e); 389 } 390 } 391 } 392 testDeviceIdAttestation()393 public void testDeviceIdAttestation() throws Exception { 394 testDeviceIdAttestationFailure(AttestationUtils.ID_TYPE_SERIAL, null); 395 testDeviceIdAttestationFailure(AttestationUtils.ID_TYPE_IMEI, "Unable to retrieve IMEI"); 396 testDeviceIdAttestationFailure(AttestationUtils.ID_TYPE_MEID, "Unable to retrieve MEID"); 397 } 398 399 @SuppressWarnings("deprecation") testRsaAttestation(byte[] challenge, boolean includeValidityDates, int keySize, int purposes, String[] paddingModes)400 private void testRsaAttestation(byte[] challenge, boolean includeValidityDates, int keySize, 401 int purposes, String[] paddingModes) throws Exception { 402 String keystoreAlias = "test_key"; 403 404 Date startTime = new Date(); 405 Date originationEnd = new Date(startTime.getTime() + ORIGINATION_TIME_OFFSET); 406 Date consumptionEnd = new Date(startTime.getTime() + CONSUMPTION_TIME_OFFSET); 407 KeyGenParameterSpec.Builder builder = 408 new KeyGenParameterSpec.Builder(keystoreAlias, purposes) 409 .setKeySize(keySize) 410 .setDigests(DIGEST_NONE, DIGEST_SHA256, DIGEST_SHA512) 411 .setAttestationChallenge(challenge); 412 413 if (includeValidityDates) { 414 builder.setKeyValidityStart(startTime) 415 .setKeyValidityForOriginationEnd(originationEnd) 416 .setKeyValidityForConsumptionEnd(consumptionEnd); 417 } 418 if (isEncryptionPurpose(purposes)) { 419 builder.setEncryptionPaddings(paddingModes); 420 // Because we sometimes set "no padding", allow non-randomized encryption. 421 builder.setRandomizedEncryptionRequired(false); 422 } 423 if (isSignaturePurpose(purposes)) { 424 builder.setSignaturePaddings(paddingModes); 425 } 426 427 generateKeyPair(KEY_ALGORITHM_RSA, builder.build()); 428 429 KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); 430 keyStore.load(null); 431 432 try { 433 Certificate certificates[] = keyStore.getCertificateChain(keystoreAlias); 434 verifyCertificateChain(certificates); 435 436 X509Certificate attestationCert = (X509Certificate) certificates[0]; 437 Attestation attestation = new Attestation(attestationCert); 438 439 checkRsaKeyDetails(attestation, keySize, purposes, ImmutableSet.copyOf(paddingModes)); 440 checkKeyUsage(attestationCert, purposes); 441 checkKeyIndependentAttestationInfo(challenge, purposes, startTime, includeValidityDates, 442 attestation); 443 } finally { 444 keyStore.deleteEntry(keystoreAlias); 445 } 446 } 447 checkKeyUsage(X509Certificate attestationCert, int purposes)448 private void checkKeyUsage(X509Certificate attestationCert, int purposes) { 449 450 boolean[] expectedKeyUsage = new boolean[KEY_USAGE_BITSTRING_LENGTH]; 451 if (isSignaturePurpose(purposes)) { 452 expectedKeyUsage[KEY_USAGE_DIGITAL_SIGNATURE_BIT_OFFSET] = true; 453 } 454 if (isEncryptionPurpose(purposes)) { 455 expectedKeyUsage[KEY_USAGE_KEY_ENCIPHERMENT_BIT_OFFSET] = true; 456 expectedKeyUsage[KEY_USAGE_DATA_ENCIPHERMENT_BIT_OFFSET] = true; 457 } 458 assertThat(attestationCert.getKeyUsage(), is(expectedKeyUsage)); 459 } 460 461 @SuppressWarnings("deprecation") testEcAttestation(byte[] challenge, boolean includeValidityDates, String ecCurve, int keySize, int purposes)462 private void testEcAttestation(byte[] challenge, boolean includeValidityDates, String ecCurve, 463 int keySize, int purposes) throws Exception { 464 String keystoreAlias = "test_key"; 465 466 Date startTime = new Date(); 467 Date originationEnd = new Date(startTime.getTime() + ORIGINATION_TIME_OFFSET); 468 Date consumptionEnd = new Date(startTime.getTime() + CONSUMPTION_TIME_OFFSET); 469 KeyGenParameterSpec.Builder builder = new KeyGenParameterSpec.Builder(keystoreAlias, 470 purposes) 471 .setAlgorithmParameterSpec(new ECGenParameterSpec(ecCurve)) 472 .setDigests(DIGEST_NONE, DIGEST_SHA256, DIGEST_SHA512) 473 .setAttestationChallenge(challenge); 474 475 if (includeValidityDates) { 476 builder.setKeyValidityStart(startTime) 477 .setKeyValidityForOriginationEnd(originationEnd) 478 .setKeyValidityForConsumptionEnd(consumptionEnd); 479 } 480 481 generateKeyPair(KEY_ALGORITHM_EC, builder.build()); 482 483 KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); 484 keyStore.load(null); 485 486 try { 487 Certificate certificates[] = keyStore.getCertificateChain(keystoreAlias); 488 verifyCertificateChain(certificates); 489 490 X509Certificate attestationCert = (X509Certificate) certificates[0]; 491 Attestation attestation = new Attestation(attestationCert); 492 493 checkEcKeyDetails(attestation, ecCurve, keySize); 494 checkKeyUsage(attestationCert, purposes); 495 checkKeyIndependentAttestationInfo(challenge, purposes, startTime, includeValidityDates, 496 attestation); 497 } finally { 498 keyStore.deleteEntry(keystoreAlias); 499 } 500 } 501 checkAttestationApplicationId(Attestation attestation)502 private void checkAttestationApplicationId(Attestation attestation) 503 throws NoSuchAlgorithmException, NameNotFoundException { 504 AttestationApplicationId aaid = null; 505 int kmVersion = attestation.getKeymasterVersion(); 506 assertNull(attestation.getTeeEnforced().getAttestationApplicationId()); 507 aaid = attestation.getSoftwareEnforced().getAttestationApplicationId(); 508 if (kmVersion >= 3) { 509 // must be present and correct 510 assertNotNull(aaid); 511 assertEquals(new AttestationApplicationId(getContext()), aaid); 512 } else { 513 // may be present and 514 // must be correct if present 515 if (aaid != null) { 516 assertEquals(new AttestationApplicationId(getContext()), aaid); 517 } 518 } 519 } 520 checkKeyIndependentAttestationInfo(byte[] challenge, int purposes, Date startTime, boolean includesValidityDates, Attestation attestation)521 private void checkKeyIndependentAttestationInfo(byte[] challenge, int purposes, Date startTime, 522 boolean includesValidityDates, Attestation attestation) 523 throws NoSuchAlgorithmException, NameNotFoundException { 524 checkAttestationSecurityLevelDependentParams(attestation); 525 assertNotNull(attestation.getAttestationChallenge()); 526 assertTrue(Arrays.equals(challenge, attestation.getAttestationChallenge())); 527 assertNotNull(attestation.getUniqueId()); 528 assertEquals(0, attestation.getUniqueId().length); 529 checkPurposes(attestation, purposes); 530 checkDigests(attestation, 531 ImmutableSet.of(KM_DIGEST_NONE, KM_DIGEST_SHA_2_256, KM_DIGEST_SHA_2_512)); 532 checkValidityPeriod(attestation, startTime, includesValidityDates); 533 checkFlags(attestation); 534 checkOrigin(attestation); 535 checkAttestationApplicationId(attestation); 536 } 537 getSystemPatchLevel()538 private int getSystemPatchLevel() { 539 Matcher matcher = OS_PATCH_LEVEL_STRING_PATTERN.matcher(Build.VERSION.SECURITY_PATCH); 540 assertTrue(matcher.matches()); 541 String year_string = matcher.group(OS_PATCH_LEVEL_YEAR_GROUP_NAME); 542 String month_string = matcher.group(OS_PATCH_LEVEL_MONTH_GROUP_NAME); 543 int patch_level = Integer.parseInt(year_string) * 100 + Integer.parseInt(month_string); 544 return patch_level; 545 } 546 getSystemOsVersion()547 private int getSystemOsVersion() { 548 return parseSystemOsVersion(Build.VERSION.RELEASE); 549 } 550 parseSystemOsVersion(String versionString)551 private int parseSystemOsVersion(String versionString) { 552 Matcher matcher = OS_VERSION_STRING_PATTERN.matcher(versionString); 553 if (!matcher.matches()) { 554 return 0; 555 } 556 557 int version = 0; 558 String major_string = matcher.group(OS_MAJOR_VERSION_MATCH_GROUP_NAME); 559 String minor_string = matcher.group(OS_MINOR_VERSION_MATCH_GROUP_NAME); 560 String subminor_string = matcher.group(OS_SUBMINOR_VERSION_MATCH_GROUP_NAME); 561 if (major_string != null) { 562 version += Integer.parseInt(major_string) * 10000; 563 } 564 if (minor_string != null) { 565 version += Integer.parseInt(minor_string) * 100; 566 } 567 if (subminor_string != null) { 568 version += Integer.parseInt(subminor_string); 569 } 570 return version; 571 } 572 checkOrigin(Attestation attestation)573 private void checkOrigin(Attestation attestation) { 574 assertTrue("Origin must be defined", 575 attestation.getSoftwareEnforced().getOrigin() != null || 576 attestation.getTeeEnforced().getOrigin() != null); 577 if (attestation.getKeymasterVersion() != 0) { 578 assertTrue("Origin may not be defined in both SW and TEE, except on keymaster0", 579 attestation.getSoftwareEnforced().getOrigin() == null || 580 attestation.getTeeEnforced().getOrigin() == null); 581 } 582 583 if (attestation.getKeymasterSecurityLevel() == KM_SECURITY_LEVEL_SOFTWARE) { 584 assertThat(attestation.getSoftwareEnforced().getOrigin(), is(KM_ORIGIN_GENERATED)); 585 } else if (attestation.getKeymasterVersion() == 0) { 586 assertThat(attestation.getTeeEnforced().getOrigin(), is(KM_ORIGIN_UNKNOWN)); 587 } else { 588 assertThat(attestation.getTeeEnforced().getOrigin(), is(KM_ORIGIN_GENERATED)); 589 } 590 } 591 checkFlags(Attestation attestation)592 private void checkFlags(Attestation attestation) { 593 assertFalse("All applications was not requested", 594 attestation.getSoftwareEnforced().isAllApplications()); 595 assertFalse("All applications was not requested", 596 attestation.getTeeEnforced().isAllApplications()); 597 assertFalse("Allow while on body was not requested", 598 attestation.getSoftwareEnforced().isAllowWhileOnBody()); 599 assertFalse("Allow while on body was not requested", 600 attestation.getTeeEnforced().isAllowWhileOnBody()); 601 assertNull("Auth binding was not requiested", 602 attestation.getSoftwareEnforced().getUserAuthType()); 603 assertNull("Auth binding was not requiested", 604 attestation.getTeeEnforced().getUserAuthType()); 605 assertTrue("noAuthRequired must be true", 606 attestation.getSoftwareEnforced().isNoAuthRequired() 607 || attestation.getTeeEnforced().isNoAuthRequired()); 608 assertFalse("auth is either software or TEE", 609 attestation.getSoftwareEnforced().isNoAuthRequired() 610 && attestation.getTeeEnforced().isNoAuthRequired()); 611 assertFalse("Software cannot implement rollback resistance", 612 attestation.getSoftwareEnforced().isRollbackResistant()); 613 } 614 checkValidityPeriod(Attestation attestation, Date startTime, boolean includesValidityDates)615 private void checkValidityPeriod(Attestation attestation, Date startTime, 616 boolean includesValidityDates) { 617 AuthorizationList validityPeriodList; 618 AuthorizationList nonValidityPeriodList; 619 if (attestation.getTeeEnforced().getCreationDateTime() != null) { 620 validityPeriodList = attestation.getTeeEnforced(); 621 nonValidityPeriodList = attestation.getSoftwareEnforced(); 622 } else { 623 validityPeriodList = attestation.getSoftwareEnforced(); 624 nonValidityPeriodList = attestation.getTeeEnforced(); 625 } 626 627 if (attestation.getKeymasterVersion() == 2) { 628 Date creationDateTime = validityPeriodList.getCreationDateTime(); 629 630 assertNotNull(creationDateTime); 631 assertNull(nonValidityPeriodList.getCreationDateTime()); 632 633 // We allow a little slop on creation times because the TEE/HAL may not be quite synced 634 // up with the system. 635 assertTrue("Test start time (" + startTime.getTime() + ") and key creation time (" + 636 creationDateTime.getTime() + ") should be close", 637 Math.abs(creationDateTime.getTime() - startTime.getTime()) <= 2000); 638 } 639 640 if (includesValidityDates) { 641 Date activeDateTime = validityPeriodList.getActiveDateTime(); 642 Date originationExpirationDateTime = validityPeriodList.getOriginationExpireDateTime(); 643 Date usageExpirationDateTime = validityPeriodList.getUsageExpireDateTime(); 644 645 assertNotNull(activeDateTime); 646 assertNotNull(originationExpirationDateTime); 647 assertNotNull(usageExpirationDateTime); 648 649 assertNull(nonValidityPeriodList.getActiveDateTime()); 650 assertNull(nonValidityPeriodList.getOriginationExpireDateTime()); 651 assertNull(nonValidityPeriodList.getUsageExpireDateTime()); 652 653 assertThat(originationExpirationDateTime.getTime(), 654 is(startTime.getTime() + ORIGINATION_TIME_OFFSET)); 655 assertThat(usageExpirationDateTime.getTime(), 656 is(startTime.getTime() + CONSUMPTION_TIME_OFFSET)); 657 } 658 } 659 checkDigests(Attestation attestation, Set<Integer> expectedDigests)660 private void checkDigests(Attestation attestation, Set<Integer> expectedDigests) { 661 Set<Integer> softwareEnforcedDigests = attestation.getSoftwareEnforced().getDigests(); 662 Set<Integer> teeEnforcedDigests = attestation.getTeeEnforced().getDigests(); 663 664 if (softwareEnforcedDigests == null) { 665 softwareEnforcedDigests = ImmutableSet.of(); 666 } 667 if (teeEnforcedDigests == null) { 668 teeEnforcedDigests = ImmutableSet.of(); 669 } 670 671 Set<Integer> allDigests = ImmutableSet.<Integer> builder() 672 .addAll(softwareEnforcedDigests) 673 .addAll(teeEnforcedDigests) 674 .build(); 675 Set<Integer> intersection = new ArraySet<>(); 676 intersection.addAll(softwareEnforcedDigests); 677 intersection.retainAll(teeEnforcedDigests); 678 679 assertThat(allDigests, is(expectedDigests)); 680 assertTrue("Digest sets must be disjoint", intersection.isEmpty()); 681 682 if (attestation.getKeymasterSecurityLevel() == KM_SECURITY_LEVEL_SOFTWARE 683 || attestation.getKeymasterVersion() == 0) { 684 assertThat("Digests in software-enforced", 685 softwareEnforcedDigests, is(expectedDigests)); 686 } else { 687 switch (attestation.getKeymasterVersion()) { 688 case 1: 689 // KM1 implementations may not support SHA512 in the TEE 690 assertTrue(softwareEnforcedDigests.contains(KM_DIGEST_SHA_2_512) 691 || teeEnforcedDigests.contains(KM_DIGEST_SHA_2_512)); 692 693 assertThat(teeEnforcedDigests, hasItems(KM_DIGEST_NONE, KM_DIGEST_SHA_2_256)); 694 break; 695 696 case 2: 697 case 3: 698 case 4: 699 assertThat(teeEnforcedDigests, is(expectedDigests)); 700 break; 701 702 default: 703 fail("Broken CTS test. Should be impossible to get here."); 704 } 705 } 706 } 707 checkPurposes(Attestation attestation, int purposes)708 private Set<Integer> checkPurposes(Attestation attestation, int purposes) { 709 Set<Integer> expectedPurposes = buildPurposeSet(purposes); 710 if (attestation.getKeymasterSecurityLevel() == KM_SECURITY_LEVEL_SOFTWARE 711 || attestation.getKeymasterVersion() == 0) { 712 assertThat("Purposes in software-enforced should match expected set", 713 attestation.getSoftwareEnforced().getPurposes(), is(expectedPurposes)); 714 assertNull("Should be no purposes in TEE-enforced", 715 attestation.getTeeEnforced().getPurposes()); 716 } else { 717 assertThat("Purposes in TEE-enforced should match expected set", 718 attestation.getTeeEnforced().getPurposes(), is(expectedPurposes)); 719 assertNull("No purposes in software-enforced", 720 attestation.getSoftwareEnforced().getPurposes()); 721 } 722 return expectedPurposes; 723 } 724 725 @SuppressWarnings("unchecked") checkAttestationSecurityLevelDependentParams(Attestation attestation)726 private void checkAttestationSecurityLevelDependentParams(Attestation attestation) { 727 assertThat("Attestation version must be 1, 2, or 3", attestation.getAttestationVersion(), 728 either(is(1)).or(is(2)).or(is(3))); 729 730 AuthorizationList teeEnforced = attestation.getTeeEnforced(); 731 AuthorizationList softwareEnforced = attestation.getSoftwareEnforced(); 732 733 int systemOsVersion = getSystemOsVersion(); 734 int systemPatchLevel = getSystemPatchLevel(); 735 736 switch (attestation.getAttestationSecurityLevel()) { 737 case KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT: 738 assertThat("TEE attestation can only come from TEE keymaster", 739 attestation.getKeymasterSecurityLevel(), 740 is(KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT)); 741 assertThat(attestation.getKeymasterVersion(), either(is(2)).or(is(3)).or(is(4))); 742 743 checkRootOfTrust(attestation); 744 assertThat(teeEnforced.getOsVersion(), is(systemOsVersion)); 745 assertThat(teeEnforced.getOsPatchLevel(), is(systemPatchLevel)); 746 break; 747 748 case KM_SECURITY_LEVEL_SOFTWARE: 749 if (attestation 750 .getKeymasterSecurityLevel() == KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT) { 751 assertThat("TEE KM version must be 0 or 1 with software attestation", 752 attestation.getKeymasterVersion(), either(is(0)).or(is(1))); 753 } else { 754 assertThat("Software KM is version 3", attestation.getKeymasterVersion(), 755 is(3)); 756 assertThat(softwareEnforced.getOsVersion(), is(systemOsVersion)); 757 assertThat(softwareEnforced.getOsPatchLevel(), is(systemPatchLevel)); 758 } 759 760 assertNull("Software attestation cannot provide root of trust", 761 teeEnforced.getRootOfTrust()); 762 763 break; 764 765 default: 766 fail("Invalid attestation security level: " 767 + attestation.getAttestationSecurityLevel()); 768 break; 769 } 770 771 assertNull("Software-enforced list must not contain root of trust", 772 softwareEnforced.getRootOfTrust()); 773 } 774 checkRootOfTrust(Attestation attestation)775 private void checkRootOfTrust(Attestation attestation) { 776 RootOfTrust rootOfTrust = attestation.getTeeEnforced().getRootOfTrust(); 777 assertNotNull(rootOfTrust); 778 assertNotNull(rootOfTrust.getVerifiedBootKey()); 779 assertTrue(rootOfTrust.getVerifiedBootKey().length >= 32); 780 if (SystemProperties.getInt("ro.product.first_api_level", 0) >= 29) { 781 // Devices launched in Q and after should run CTS in LOCKED state. 782 assertTrue(rootOfTrust.isDeviceLocked()); 783 assertEquals(KM_VERIFIED_BOOT_VERIFIED, rootOfTrust.getVerifiedBootState()); 784 } 785 } 786 checkRsaKeyDetails(Attestation attestation, int keySize, int purposes, Set<String> expectedPaddingModes)787 private void checkRsaKeyDetails(Attestation attestation, int keySize, int purposes, 788 Set<String> expectedPaddingModes) throws CertificateParsingException { 789 AuthorizationList keyDetailsList; 790 AuthorizationList nonKeyDetailsList; 791 if (attestation.getKeymasterSecurityLevel() == KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT) { 792 keyDetailsList = attestation.getTeeEnforced(); 793 nonKeyDetailsList = attestation.getSoftwareEnforced(); 794 } else { 795 keyDetailsList = attestation.getSoftwareEnforced(); 796 nonKeyDetailsList = attestation.getTeeEnforced(); 797 } 798 assertEquals(keySize, keyDetailsList.getKeySize().intValue()); 799 assertNull(nonKeyDetailsList.getKeySize()); 800 801 assertEquals(KM_ALGORITHM_RSA, keyDetailsList.getAlgorithm().intValue()); 802 assertNull(nonKeyDetailsList.getAlgorithm()); 803 804 assertNull(keyDetailsList.getEcCurve()); 805 assertNull(nonKeyDetailsList.getEcCurve()); 806 807 assertEquals(65537, keyDetailsList.getRsaPublicExponent().longValue()); 808 assertNull(nonKeyDetailsList.getRsaPublicExponent()); 809 810 Set<String> paddingModes; 811 if (attestation.getKeymasterVersion() == 0) { 812 // KM0 implementations don't support padding info, so it's always in the 813 // software-enforced list. 814 paddingModes = attestation.getSoftwareEnforced().getPaddingModesAsStrings(); 815 assertNull(attestation.getTeeEnforced().getPaddingModes()); 816 } else { 817 paddingModes = keyDetailsList.getPaddingModesAsStrings(); 818 assertNull(nonKeyDetailsList.getPaddingModes()); 819 } 820 821 // KM1 implementations may add ENCRYPTION_PADDING_NONE to the list of paddings. 822 Set<String> km1PossiblePaddingModes = expectedPaddingModes; 823 if (attestation.getKeymasterVersion() == 1 && 824 attestation.getKeymasterSecurityLevel() == KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT) { 825 ImmutableSet.Builder<String> builder = ImmutableSet.builder(); 826 builder.addAll(expectedPaddingModes); 827 builder.add(ENCRYPTION_PADDING_NONE); 828 km1PossiblePaddingModes = builder.build(); 829 } 830 831 assertThat(paddingModes, either(is(expectedPaddingModes)).or(is(km1PossiblePaddingModes))); 832 } 833 checkEcKeyDetails(Attestation attestation, String ecCurve, int keySize)834 private void checkEcKeyDetails(Attestation attestation, String ecCurve, int keySize) { 835 AuthorizationList keyDetailsList; 836 AuthorizationList nonKeyDetailsList; 837 if (attestation.getKeymasterSecurityLevel() == KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT) { 838 keyDetailsList = attestation.getTeeEnforced(); 839 nonKeyDetailsList = attestation.getSoftwareEnforced(); 840 } else { 841 keyDetailsList = attestation.getSoftwareEnforced(); 842 nonKeyDetailsList = attestation.getTeeEnforced(); 843 } 844 assertEquals(keySize, keyDetailsList.getKeySize().intValue()); 845 assertNull(nonKeyDetailsList.getKeySize()); 846 assertEquals(KM_ALGORITHM_EC, keyDetailsList.getAlgorithm().intValue()); 847 assertNull(nonKeyDetailsList.getAlgorithm()); 848 assertEquals(ecCurve, keyDetailsList.ecCurveAsString()); 849 assertNull(nonKeyDetailsList.getEcCurve()); 850 assertNull(keyDetailsList.getRsaPublicExponent()); 851 assertNull(nonKeyDetailsList.getRsaPublicExponent()); 852 assertNull(keyDetailsList.getPaddingModes()); 853 assertNull(nonKeyDetailsList.getPaddingModes()); 854 } 855 isEncryptionPurpose(int purposes)856 private boolean isEncryptionPurpose(int purposes) { 857 return (purposes & PURPOSE_DECRYPT) != 0 || (purposes & PURPOSE_ENCRYPT) != 0; 858 } 859 isSignaturePurpose(int purposes)860 private boolean isSignaturePurpose(int purposes) { 861 return (purposes & PURPOSE_SIGN) != 0 || (purposes & PURPOSE_VERIFY) != 0; 862 } 863 buildPurposeSet(int purposes)864 private ImmutableSet<Integer> buildPurposeSet(int purposes) { 865 ImmutableSet.Builder<Integer> builder = ImmutableSet.builder(); 866 if ((purposes & PURPOSE_SIGN) != 0) 867 builder.add(KM_PURPOSE_SIGN); 868 if ((purposes & PURPOSE_VERIFY) != 0) 869 builder.add(KM_PURPOSE_VERIFY); 870 if ((purposes & PURPOSE_ENCRYPT) != 0) 871 builder.add(KM_PURPOSE_ENCRYPT); 872 if ((purposes & PURPOSE_DECRYPT) != 0) 873 builder.add(KM_PURPOSE_DECRYPT); 874 return builder.build(); 875 } 876 generateKey(KeyGenParameterSpec spec, String algorithm)877 private void generateKey(KeyGenParameterSpec spec, String algorithm) 878 throws NoSuchAlgorithmException, NoSuchProviderException, 879 InvalidAlgorithmParameterException { 880 KeyGenerator keyGenerator = KeyGenerator.getInstance(algorithm, "AndroidKeyStore"); 881 keyGenerator.init(spec); 882 keyGenerator.generateKey(); 883 } 884 generateKeyPair(String algorithm, KeyGenParameterSpec spec)885 private void generateKeyPair(String algorithm, KeyGenParameterSpec spec) 886 throws NoSuchAlgorithmException, NoSuchProviderException, 887 InvalidAlgorithmParameterException { 888 KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(algorithm, 889 "AndroidKeyStore"); 890 keyPairGenerator.initialize(spec); 891 keyPairGenerator.generateKeyPair(); 892 } 893 verifyCertificateChain(Certificate[] certChain)894 private void verifyCertificateChain(Certificate[] certChain) 895 throws GeneralSecurityException { 896 assertNotNull(certChain); 897 for (int i = 1; i < certChain.length; ++i) { 898 try { 899 PublicKey pubKey = certChain[i].getPublicKey(); 900 certChain[i - 1].verify(pubKey); 901 if (i == certChain.length - 1) { 902 // Last cert should be self-signed. 903 certChain[i].verify(pubKey); 904 } 905 906 // Check that issuer in the signed cert matches subject in the signing cert. 907 X509Certificate x509CurrCert = (X509Certificate) certChain[i]; 908 X509Certificate x509PrevCert = (X509Certificate) certChain[i - 1]; 909 X500Name signingCertSubject = 910 new JcaX509CertificateHolder(x509CurrCert).getSubject(); 911 X500Name signedCertIssuer = 912 new JcaX509CertificateHolder(x509PrevCert).getIssuer(); 913 // Use .toASN1Object().equals() rather than .equals() because .equals() is case 914 // insensitive, and we want to verify an exact match. 915 assertTrue( 916 signedCertIssuer.toASN1Object().equals(signingCertSubject.toASN1Object())); 917 918 if (i == 1) { 919 // First cert should have subject "CN=Android Keystore Key". 920 X500Name signedCertSubject = 921 new JcaX509CertificateHolder(x509PrevCert).getSubject(); 922 assertEquals(signedCertSubject, new X500Name("CN=Android Keystore Key")); 923 } 924 } catch (InvalidKeyException | CertificateException | NoSuchAlgorithmException 925 | NoSuchProviderException | SignatureException e) { 926 throw new GeneralSecurityException("Failed to verify certificate " 927 + certChain[i - 1] + " with public key " + certChain[i].getPublicKey(), e); 928 } 929 } 930 } 931 testDeviceIdAttestationFailure(int idType, String acceptableDeviceIdAttestationFailureMessage)932 private void testDeviceIdAttestationFailure(int idType, 933 String acceptableDeviceIdAttestationFailureMessage) throws Exception { 934 try { 935 AttestationUtils.attestDeviceIds(getContext(), new int[] {idType}, "123".getBytes()); 936 fail("Attestation should have failed."); 937 } catch (SecurityException e) { 938 // Attestation is expected to fail. If the device has the device ID type we are trying 939 // to attest, it should fail with a SecurityException as we do not hold 940 // READ_PRIVILEGED_PHONE_STATE permission. 941 } catch (DeviceIdAttestationException e) { 942 // Attestation is expected to fail. If the device does not have the device ID type we 943 // are trying to attest (e.g. no IMEI on devices without a radio), it should fail with 944 // a corresponding DeviceIdAttestationException. 945 if (acceptableDeviceIdAttestationFailureMessage == null || 946 !acceptableDeviceIdAttestationFailureMessage.equals(e.getMessage())) { 947 throw e; 948 } 949 } 950 } 951 } 952