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