• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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