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