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