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