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_STRONG_BOX;
21 import static android.keystore.cts.Attestation.KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT;
22 import static android.keystore.cts.AuthorizationList.KM_ALGORITHM_EC;
23 import static android.keystore.cts.AuthorizationList.KM_ALGORITHM_RSA;
24 import static android.keystore.cts.AuthorizationList.KM_DIGEST_NONE;
25 import static android.keystore.cts.AuthorizationList.KM_DIGEST_SHA_2_256;
26 import static android.keystore.cts.AuthorizationList.KM_DIGEST_SHA_2_512;
27 import static android.keystore.cts.AuthorizationList.KM_ORIGIN_GENERATED;
28 import static android.keystore.cts.AuthorizationList.KM_ORIGIN_UNKNOWN;
29 import static android.keystore.cts.AuthorizationList.KM_PURPOSE_DECRYPT;
30 import static android.keystore.cts.AuthorizationList.KM_PURPOSE_ENCRYPT;
31 import static android.keystore.cts.AuthorizationList.KM_PURPOSE_SIGN;
32 import static android.keystore.cts.AuthorizationList.KM_PURPOSE_VERIFY;
33 import static android.keystore.cts.RootOfTrust.KM_VERIFIED_BOOT_VERIFIED;
34 import static android.security.keystore.KeyProperties.DIGEST_NONE;
35 import static android.security.keystore.KeyProperties.DIGEST_SHA256;
36 import static android.security.keystore.KeyProperties.DIGEST_SHA512;
37 import static android.security.keystore.KeyProperties.ENCRYPTION_PADDING_NONE;
38 import static android.security.keystore.KeyProperties.ENCRYPTION_PADDING_RSA_OAEP;
39 import static android.security.keystore.KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1;
40 import static android.security.keystore.KeyProperties.KEY_ALGORITHM_EC;
41 import static android.security.keystore.KeyProperties.KEY_ALGORITHM_RSA;
42 import static android.security.keystore.KeyProperties.PURPOSE_DECRYPT;
43 import static android.security.keystore.KeyProperties.PURPOSE_ENCRYPT;
44 import static android.security.keystore.KeyProperties.PURPOSE_SIGN;
45 import static android.security.keystore.KeyProperties.PURPOSE_VERIFY;
46 import static android.security.keystore.KeyProperties.SIGNATURE_PADDING_RSA_PKCS1;
47 import static android.security.keystore.KeyProperties.SIGNATURE_PADDING_RSA_PSS;
48 
49 import static org.hamcrest.CoreMatchers.is;
50 import static org.hamcrest.MatcherAssert.assertThat;
51 import static org.hamcrest.Matchers.either;
52 import static org.hamcrest.Matchers.empty;
53 import static org.hamcrest.Matchers.greaterThanOrEqualTo;
54 import static org.hamcrest.Matchers.hasItems;
55 
56 import android.content.pm.PackageManager.NameNotFoundException;
57 import android.os.Build;
58 import android.os.SystemProperties;
59 import android.platform.test.annotations.RestrictedBuildTest;
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 import android.util.Log;
68 
69 import com.google.common.collect.ImmutableSet;
70 
71 import androidx.test.filters.RequiresDevice;
72 
73 import org.bouncycastle.asn1.x500.X500Name;
74 import org.bouncycastle.cert.jcajce.JcaX509CertificateHolder;
75 
76 import java.lang.Math;
77 import java.security.GeneralSecurityException;
78 import java.security.InvalidAlgorithmParameterException;
79 import java.security.InvalidKeyException;
80 import java.security.KeyPairGenerator;
81 import java.security.KeyStore;
82 import java.security.NoSuchAlgorithmException;
83 import java.security.NoSuchProviderException;
84 import java.security.ProviderException;
85 import java.security.PublicKey;
86 import java.security.SignatureException;
87 import java.security.cert.Certificate;
88 import java.security.cert.CertificateException;
89 import java.security.cert.CertificateParsingException;
90 import java.security.cert.X509Certificate;
91 import java.security.spec.ECGenParameterSpec;
92 import java.util.Arrays;
93 import java.util.Date;
94 import java.util.Set;
95 import java.util.regex.Matcher;
96 import java.util.regex.Pattern;
97 
98 import javax.crypto.KeyGenerator;
99 
100 /**
101  * Tests for Android KeysStore attestation.
102  */
103 public class KeyAttestationTest extends AndroidTestCase {
104 
105     private static final String TAG = AndroidKeyStoreTest.class.getSimpleName();
106 
107     private static final int ORIGINATION_TIME_OFFSET = 1000000;
108     private static final int CONSUMPTION_TIME_OFFSET = 2000000;
109 
110     private static final int KEY_USAGE_BITSTRING_LENGTH = 9;
111     private static final int KEY_USAGE_DIGITAL_SIGNATURE_BIT_OFFSET = 0;
112     private static final int KEY_USAGE_KEY_ENCIPHERMENT_BIT_OFFSET = 2;
113     private static final int KEY_USAGE_DATA_ENCIPHERMENT_BIT_OFFSET = 3;
114 
115     private static final int OS_MAJOR_VERSION_MATCH_GROUP_NAME = 1;
116     private static final int OS_MINOR_VERSION_MATCH_GROUP_NAME = 2;
117     private static final int OS_SUBMINOR_VERSION_MATCH_GROUP_NAME = 3;
118     private static final Pattern OS_VERSION_STRING_PATTERN = Pattern
119             .compile("([0-9]{1,2})(?:\\.([0-9]{1,2}))?(?:\\.([0-9]{1,2}))?(?:[^0-9.]+.*)?");
120 
121     private static final int OS_PATCH_LEVEL_YEAR_GROUP_NAME = 1;
122     private static final int OS_PATCH_LEVEL_MONTH_GROUP_NAME = 2;
123     private static final Pattern OS_PATCH_LEVEL_STRING_PATTERN = Pattern
124             .compile("([0-9]{4})-([0-9]{2})-[0-9]{2}");
125 
126     private static final int KM_ERROR_INVALID_INPUT_LENGTH = -21;
127     private static final int KM_ERROR_PERMISSION_DENIED = 6;
128 
testVersionParser()129     public void testVersionParser() throws Exception {
130         // Non-numerics/empty give version 0
131         assertEquals(0, parseSystemOsVersion(""));
132         assertEquals(0, parseSystemOsVersion("N"));
133 
134         // Should support one, two or three version number values.
135         assertEquals(10000, parseSystemOsVersion("1"));
136         assertEquals(10200, parseSystemOsVersion("1.2"));
137         assertEquals(10203, parseSystemOsVersion("1.2.3"));
138 
139         // It's fine to append other stuff to the dotted numeric version.
140         assertEquals(10000, parseSystemOsVersion("1stuff"));
141         assertEquals(10200, parseSystemOsVersion("1.2garbage.32"));
142         assertEquals(10203, parseSystemOsVersion("1.2.3-stuff"));
143 
144         // Two digits per version field are supported
145         assertEquals(152536, parseSystemOsVersion("15.25.36"));
146         assertEquals(999999, parseSystemOsVersion("99.99.99"));
147         assertEquals(0, parseSystemOsVersion("100.99.99"));
148         assertEquals(0, parseSystemOsVersion("99.100.99"));
149         assertEquals(0, parseSystemOsVersion("99.99.100"));
150     }
151 
testEcAttestation()152     public void testEcAttestation() throws Exception {
153         // Note: Curve and key sizes arrays must correspond.
154         String[] curves = {
155                 "secp224r1", "secp256r1", "secp384r1", "secp521r1"
156         };
157         int[] keySizes = {
158                 224, 256, 384, 521
159         };
160         byte[][] challenges = {
161                 new byte[0], // empty challenge
162                 "challenge".getBytes(), // short challenge
163                 new byte[128], // long challenge
164         };
165         int[] purposes = {
166                 KM_PURPOSE_SIGN, KM_PURPOSE_VERIFY, KM_PURPOSE_SIGN | KM_PURPOSE_VERIFY
167         };
168         boolean[] devicePropertiesAttestationValues = {true, false};
169         boolean[] includeValidityDatesValues = {true, false};
170 
171         for (int curveIndex = 0; curveIndex < curves.length; ++curveIndex) {
172             for (int challengeIndex = 0; challengeIndex < challenges.length; ++challengeIndex) {
173                 for (int purposeIndex = 0; purposeIndex < purposes.length; ++purposeIndex) {
174                     for (boolean includeValidityDates : includeValidityDatesValues) {
175                         for (boolean devicePropertiesAttestation : devicePropertiesAttestationValues) {
176                             try {
177                                 testEcAttestation(challenges[challengeIndex], includeValidityDates,
178                                         curves[curveIndex], keySizes[curveIndex],
179                                         purposes[purposeIndex], devicePropertiesAttestation);
180                             } catch (Throwable e) {
181                                 throw new Exception("Failed on curve " + curveIndex +
182                                         " challenge " + challengeIndex + " purpose " +
183                                         purposeIndex + " includeValidityDates " +
184                                         includeValidityDates + " and devicePropertiesAttestation " +
185                                         devicePropertiesAttestation, e);
186                             }
187                         }
188                     }
189                 }
190             }
191         }
192     }
193 
testEcAttestation_TooLargeChallenge()194     public void testEcAttestation_TooLargeChallenge() throws Exception {
195         boolean[] devicePropertiesAttestationValues = {true, false};
196         for (boolean devicePropertiesAttestation : devicePropertiesAttestationValues) {
197             try {
198                 testEcAttestation(new byte[129], true /* includeValidityDates */, "secp256r1", 256,
199                         KM_PURPOSE_SIGN, devicePropertiesAttestation);
200                 fail("Attestation challenges larger than 128 bytes should be rejected");
201             } catch (ProviderException e) {
202                 KeyStoreException cause = (KeyStoreException) e.getCause();
203                 assertEquals(KM_ERROR_INVALID_INPUT_LENGTH, cause.getErrorCode());
204             }
205         }
206     }
207 
testEcAttestation_NoChallenge()208     public void testEcAttestation_NoChallenge() throws Exception {
209         boolean[] devicePropertiesAttestationValues = {true, false};
210         for (boolean devicePropertiesAttestation : devicePropertiesAttestationValues) {
211             String keystoreAlias = "test_key";
212             Date now = new Date();
213             Date originationEnd = new Date(now.getTime() + ORIGINATION_TIME_OFFSET);
214             Date consumptionEnd = new Date(now.getTime() + CONSUMPTION_TIME_OFFSET);
215             KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(keystoreAlias, PURPOSE_SIGN)
216                     .setAlgorithmParameterSpec(new ECGenParameterSpec("secp256r1"))
217                     .setDigests(DIGEST_NONE, DIGEST_SHA256, DIGEST_SHA512)
218                     .setAttestationChallenge(null)
219                     .setKeyValidityStart(now)
220                     .setKeyValidityForOriginationEnd(originationEnd)
221                     .setKeyValidityForConsumptionEnd(consumptionEnd)
222                     .setDevicePropertiesAttestationIncluded(devicePropertiesAttestation)
223                     .build();
224 
225             generateKeyPair(KEY_ALGORITHM_EC, spec);
226 
227             KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
228             keyStore.load(null);
229 
230             try {
231                 Certificate certificates[] = keyStore.getCertificateChain(keystoreAlias);
232                 assertEquals(1, certificates.length);
233 
234                 X509Certificate attestationCert = (X509Certificate) certificates[0];
235                 assertNull(attestationCert.getExtensionValue(Attestation.KEY_DESCRIPTION_OID));
236             } finally {
237                 keyStore.deleteEntry(keystoreAlias);
238             }
239         }
240     }
241 
242     @RestrictedBuildTest
testEcAttestation_DeviceLocked()243     public void testEcAttestation_DeviceLocked() throws Exception {
244         String keystoreAlias = "test_key";
245         Date now = new Date();
246         Date originationEnd = new Date(now.getTime() + ORIGINATION_TIME_OFFSET);
247         Date consumptionEnd = new Date(now.getTime() + CONSUMPTION_TIME_OFFSET);
248         KeyGenParameterSpec.Builder builder =
249             new KeyGenParameterSpec.Builder(keystoreAlias, PURPOSE_SIGN)
250                     .setAlgorithmParameterSpec(new ECGenParameterSpec("secp256r1"))
251                     .setAttestationChallenge(new byte[128])
252                     .setKeyValidityStart(now)
253                     .setKeyValidityForOriginationEnd(originationEnd)
254                     .setKeyValidityForConsumptionEnd(consumptionEnd);
255 
256         if (TestUtils.hasStrongBox(getContext())) {
257             builder.setDigests(DIGEST_NONE, DIGEST_SHA256);
258             builder.setIsStrongBoxBacked(true);
259         } else {
260             builder.setDigests(DIGEST_NONE, DIGEST_SHA256, DIGEST_SHA512);
261         }
262 
263         generateKeyPair(KEY_ALGORITHM_EC, builder.build());
264 
265         KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
266         keyStore.load(null);
267 
268         try {
269             Certificate certificates[] = keyStore.getCertificateChain(keystoreAlias);
270             verifyCertificateChain(certificates, TestUtils.hasStrongBox(getContext()));
271 
272             X509Certificate attestationCert = (X509Certificate) certificates[0];
273             checkDeviceLocked(new Attestation(attestationCert));
274         } finally {
275             keyStore.deleteEntry(keystoreAlias);
276         }
277     }
278 
testEcAttestation_KeyStoreExceptionWhenRequestingUniqueId()279     public void testEcAttestation_KeyStoreExceptionWhenRequestingUniqueId() throws Exception {
280         String keystoreAlias = "test_key";
281         KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(keystoreAlias, PURPOSE_SIGN)
282                 .setAlgorithmParameterSpec(new ECGenParameterSpec("secp256r1"))
283                 .setDigests(DIGEST_NONE, DIGEST_SHA256, DIGEST_SHA512)
284                 .setAttestationChallenge(new byte[128])
285                 .setUniqueIdIncluded(true)
286                 .build();
287 
288         try {
289             generateKeyPair(KEY_ALGORITHM_EC, spec);
290             fail("Attestation should have failed.");
291         } catch (ProviderException e) {
292             // Attestation is expected to fail because of lack of permissions.
293             KeyStoreException cause = (KeyStoreException) e.getCause();
294             assertEquals(KM_ERROR_PERMISSION_DENIED, cause.getErrorCode());
295         } finally {
296             KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
297             keyStore.load(null);
298             keyStore.deleteEntry(keystoreAlias);
299         }
300     }
301 
testRsaAttestation()302     public void testRsaAttestation() throws Exception {
303         int[] keySizes = { // Smallish sizes to keep test runtimes down.
304                 512, 768, 1024
305         };
306         byte[][] challenges = {
307                 new byte[0], // empty challenge
308                 "challenge".getBytes(), // short challenge
309                 new byte[128] // long challenge
310         };
311         int[] purposes = {
312                 PURPOSE_SIGN | PURPOSE_VERIFY,
313                 PURPOSE_ENCRYPT | PURPOSE_DECRYPT,
314         };
315         String[][] encryptionPaddingModes = {
316                 {
317                         ENCRYPTION_PADDING_NONE
318                 },
319                 {
320                         ENCRYPTION_PADDING_RSA_OAEP,
321                 },
322                 {
323                         ENCRYPTION_PADDING_RSA_PKCS1,
324                 },
325                 {
326                         ENCRYPTION_PADDING_RSA_OAEP,
327                         ENCRYPTION_PADDING_RSA_PKCS1,
328                 },
329         };
330         String[][] signaturePaddingModes = {
331                 {
332                         SIGNATURE_PADDING_RSA_PKCS1,
333                 },
334                 {
335                         SIGNATURE_PADDING_RSA_PSS,
336                 },
337                 {
338                         SIGNATURE_PADDING_RSA_PKCS1,
339                         SIGNATURE_PADDING_RSA_PSS,
340                 },
341         };
342         boolean[] devicePropertiesAttestationValues = {true, false};
343 
344         for (boolean devicePropertiesAttestation : devicePropertiesAttestationValues) {
345             for (int keySize : keySizes) {
346                 for (byte[] challenge : challenges) {
347                     for (int purpose : purposes) {
348                         if (isEncryptionPurpose(purpose)) {
349                             testRsaAttestations(keySize, challenge, purpose, encryptionPaddingModes,
350                                     devicePropertiesAttestation);
351                         } else {
352                             testRsaAttestations(keySize, challenge, purpose, signaturePaddingModes,
353                                     devicePropertiesAttestation);
354                         }
355                     }
356                 }
357             }
358         }
359     }
360 
testRsaAttestation_TooLargeChallenge()361     public void testRsaAttestation_TooLargeChallenge() throws Exception {
362         boolean[] devicePropertiesAttestationValues = {true, false};
363         for (boolean devicePropertiesAttestation : devicePropertiesAttestationValues) {
364             try {
365                 testRsaAttestation(new byte[129], true /* includeValidityDates */, 512,
366                         PURPOSE_SIGN,
367                         null /* paddingModes; may be empty because we'll never test them */,
368                         devicePropertiesAttestation);
369                 fail("Attestation challenges larger than 128 bytes should be rejected");
370             } catch(ProviderException e){
371                 KeyStoreException cause = (KeyStoreException) e.getCause();
372                 assertEquals(KM_ERROR_INVALID_INPUT_LENGTH, cause.getErrorCode());
373             }
374         }
375     }
376 
testRsaAttestation_NoChallenge()377     public void testRsaAttestation_NoChallenge() throws Exception {
378         boolean[] devicePropertiesAttestationValues = {true, false};
379         for (boolean devicePropertiesAttestation : devicePropertiesAttestationValues) {
380             String keystoreAlias = "test_key";
381             Date now = new Date();
382             Date originationEnd = new Date(now.getTime() + ORIGINATION_TIME_OFFSET);
383             Date consumptionEnd = new Date(now.getTime() + CONSUMPTION_TIME_OFFSET);
384             KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(keystoreAlias, PURPOSE_SIGN)
385                     .setDigests(DIGEST_NONE, DIGEST_SHA256, DIGEST_SHA512)
386                     .setAttestationChallenge(null)
387                     .setKeyValidityStart(now)
388                     .setKeyValidityForOriginationEnd(originationEnd)
389                     .setKeyValidityForConsumptionEnd(consumptionEnd)
390                     .setDevicePropertiesAttestationIncluded(devicePropertiesAttestation)
391                     .build();
392 
393             generateKeyPair(KEY_ALGORITHM_RSA, spec);
394 
395             KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
396             keyStore.load(null);
397 
398             try {
399                 Certificate certificates[] = keyStore.getCertificateChain(keystoreAlias);
400                 assertEquals(1, certificates.length);
401 
402                 X509Certificate attestationCert = (X509Certificate) certificates[0];
403                 assertNull(attestationCert.getExtensionValue(Attestation.KEY_DESCRIPTION_OID));
404             } finally {
405                 keyStore.deleteEntry(keystoreAlias);
406             }
407         }
408     }
409 
410     @RestrictedBuildTest
411     @RequiresDevice  // Emulators have no place to store the needed key
testRsaAttestation_DeviceLocked()412     public void testRsaAttestation_DeviceLocked() throws Exception {
413         String keystoreAlias = "test_key";
414         Date now = new Date();
415         Date originationEnd = new Date(now.getTime() + ORIGINATION_TIME_OFFSET);
416         Date consumptionEnd = new Date(now.getTime() + CONSUMPTION_TIME_OFFSET);
417         KeyGenParameterSpec.Builder builder =
418             new KeyGenParameterSpec.Builder(keystoreAlias, PURPOSE_SIGN)
419                     .setDigests(DIGEST_NONE, DIGEST_SHA256, DIGEST_SHA512)
420                     .setAttestationChallenge("challenge".getBytes())
421                     .setKeyValidityStart(now)
422                     .setKeyValidityForOriginationEnd(originationEnd)
423                     .setKeyValidityForConsumptionEnd(consumptionEnd);
424 
425         if (TestUtils.hasStrongBox(getContext())) {
426             builder.setDigests(DIGEST_NONE, DIGEST_SHA256);
427             builder.setIsStrongBoxBacked(true);
428         } else {
429             builder.setDigests(DIGEST_NONE, DIGEST_SHA256, DIGEST_SHA512);
430         }
431 
432         generateKeyPair(KEY_ALGORITHM_RSA, builder.build());
433 
434         KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
435         keyStore.load(null);
436 
437         try {
438             Certificate certificates[] = keyStore.getCertificateChain(keystoreAlias);
439             verifyCertificateChain(certificates, TestUtils.hasStrongBox(getContext()));
440 
441             X509Certificate attestationCert = (X509Certificate) certificates[0];
442             checkDeviceLocked(new Attestation(attestationCert));
443         } finally {
444             keyStore.deleteEntry(keystoreAlias);
445         }
446     }
447 
testAesAttestation()448     public void testAesAttestation() throws Exception {
449         boolean[] devicePropertiesAttestationValues = {true, false};
450         for (boolean devicePropertiesAttestation : devicePropertiesAttestationValues) {
451             String keystoreAlias = "test_key";
452             KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(keystoreAlias,
453                     PURPOSE_ENCRYPT)
454                     .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
455                     .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
456                     .setAttestationChallenge(new byte[0])
457                     .setDevicePropertiesAttestationIncluded(devicePropertiesAttestation)
458                     .build();
459             generateKey(spec, KeyProperties.KEY_ALGORITHM_AES);
460 
461             KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
462             keyStore.load(null);
463             try {
464                 assertNull(keyStore.getCertificateChain(keystoreAlias));
465             } finally {
466                 keyStore.deleteEntry(keystoreAlias);
467             }
468         }
469     }
470 
testHmacAttestation()471     public void testHmacAttestation() throws Exception {
472         boolean[] devicePropertiesAttestationValues = {true, false};
473         for (boolean devicePropertiesAttestation : devicePropertiesAttestationValues) {
474             String keystoreAlias = "test_key";
475             KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(keystoreAlias, PURPOSE_SIGN)
476                     .setDevicePropertiesAttestationIncluded(devicePropertiesAttestation)
477                     .build();
478 
479             generateKey(spec, KeyProperties.KEY_ALGORITHM_HMAC_SHA256);
480 
481             KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
482             keyStore.load(null);
483             try {
484                 assertNull(keyStore.getCertificateChain(keystoreAlias));
485             } finally {
486                 keyStore.deleteEntry(keystoreAlias);
487             }
488         }
489     }
490 
testRsaAttestations(int keySize, byte[] challenge, int purpose, String[][] paddingModes, boolean devicePropertiesAttestation)491     private void testRsaAttestations(int keySize, byte[] challenge, int purpose,
492             String[][] paddingModes, boolean devicePropertiesAttestation) throws Exception {
493         for (String[] paddings : paddingModes) {
494             try {
495                 testRsaAttestation(challenge, true /* includeValidityDates */, keySize, purpose,
496                         paddings, devicePropertiesAttestation);
497                 testRsaAttestation(challenge, false /* includeValidityDates */, keySize, purpose,
498                         paddings, devicePropertiesAttestation);
499             } catch (Throwable e) {
500                 throw new Exception("Failed on key size " + keySize + " challenge [" +
501                         new String(challenge) + "], purposes " +
502                         buildPurposeSet(purpose) + " paddings " +
503                         ImmutableSet.copyOf(paddings) + " and devicePropertiesAttestation "
504                         + devicePropertiesAttestation,
505                         e);
506             }
507         }
508     }
509 
testDeviceIdAttestation()510     public void testDeviceIdAttestation() throws Exception {
511         testDeviceIdAttestationFailure(AttestationUtils.ID_TYPE_SERIAL, null);
512         testDeviceIdAttestationFailure(AttestationUtils.ID_TYPE_IMEI, "Unable to retrieve IMEI");
513         testDeviceIdAttestationFailure(AttestationUtils.ID_TYPE_MEID, "Unable to retrieve MEID");
514     }
515 
516     @SuppressWarnings("deprecation")
testRsaAttestation(byte[] challenge, boolean includeValidityDates, int keySize, int purposes, String[] paddingModes, boolean devicePropertiesAttestation)517     private void testRsaAttestation(byte[] challenge, boolean includeValidityDates, int keySize,
518             int purposes, String[] paddingModes, boolean devicePropertiesAttestation)
519             throws Exception {
520         Log.i(TAG, "RSA key attestation with: challenge " + Arrays.toString(challenge) +
521                 " / includeValidityDates " + includeValidityDates + " / keySize " + keySize +
522                 " / purposes " + purposes + " / paddingModes " + Arrays.toString(paddingModes) +
523                 " / devicePropertiesAttestation " + devicePropertiesAttestation);
524 
525         String keystoreAlias = "test_key";
526         Date startTime = new Date();
527         Date originationEnd = new Date(startTime.getTime() + ORIGINATION_TIME_OFFSET);
528         Date consumptionEnd = new Date(startTime.getTime() + CONSUMPTION_TIME_OFFSET);
529         KeyGenParameterSpec.Builder builder =
530             new KeyGenParameterSpec.Builder(keystoreAlias, purposes)
531                         .setKeySize(keySize)
532                         .setDigests(DIGEST_NONE, DIGEST_SHA256, DIGEST_SHA512)
533                         .setAttestationChallenge(challenge)
534                         .setDevicePropertiesAttestationIncluded(devicePropertiesAttestation);
535 
536         if (includeValidityDates) {
537             builder.setKeyValidityStart(startTime)
538                     .setKeyValidityForOriginationEnd(originationEnd)
539                     .setKeyValidityForConsumptionEnd(consumptionEnd);
540         }
541         if (isEncryptionPurpose(purposes)) {
542             builder.setEncryptionPaddings(paddingModes);
543             // Because we sometimes set "no padding", allow non-randomized encryption.
544             builder.setRandomizedEncryptionRequired(false);
545         }
546         if (isSignaturePurpose(purposes)) {
547             builder.setSignaturePaddings(paddingModes);
548         }
549 
550         generateKeyPair(KEY_ALGORITHM_RSA, builder.build());
551 
552         KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
553         keyStore.load(null);
554 
555         try {
556             Certificate certificates[] = keyStore.getCertificateChain(keystoreAlias);
557             verifyCertificateChain(certificates, false /* expectStrongBox */);
558 
559             X509Certificate attestationCert = (X509Certificate) certificates[0];
560             Attestation attestation = new Attestation(attestationCert);
561 
562             checkRsaKeyDetails(attestation, keySize, purposes, ImmutableSet.copyOf(paddingModes));
563             checkKeyUsage(attestationCert, purposes);
564             checkKeyIndependentAttestationInfo(challenge, purposes, startTime, includeValidityDates,
565                     devicePropertiesAttestation, attestation);
566         } finally {
567             keyStore.deleteEntry(keystoreAlias);
568         }
569     }
570 
checkKeyUsage(X509Certificate attestationCert, int purposes)571     private void checkKeyUsage(X509Certificate attestationCert, int purposes) {
572 
573         boolean[] expectedKeyUsage = new boolean[KEY_USAGE_BITSTRING_LENGTH];
574         if (isSignaturePurpose(purposes)) {
575             expectedKeyUsage[KEY_USAGE_DIGITAL_SIGNATURE_BIT_OFFSET] = true;
576         }
577         if (isEncryptionPurpose(purposes)) {
578             expectedKeyUsage[KEY_USAGE_KEY_ENCIPHERMENT_BIT_OFFSET] = true;
579             expectedKeyUsage[KEY_USAGE_DATA_ENCIPHERMENT_BIT_OFFSET] = true;
580         }
581         assertThat(attestationCert.getKeyUsage(), is(expectedKeyUsage));
582     }
583 
584     @SuppressWarnings("deprecation")
testEcAttestation(byte[] challenge, boolean includeValidityDates, String ecCurve, int keySize, int purposes, boolean devicePropertiesAttestation)585     private void testEcAttestation(byte[] challenge, boolean includeValidityDates, String ecCurve,
586             int keySize, int purposes, boolean devicePropertiesAttestation) throws Exception {
587         Log.i(TAG, "EC key attestation with: challenge " + Arrays.toString(challenge) +
588                 " / includeValidityDates " + includeValidityDates + " / ecCurve " + ecCurve +
589                 " / keySize " + keySize + " / purposes " + purposes +
590                 " / devicePropertiesAttestation " + devicePropertiesAttestation);
591 
592         String keystoreAlias = "test_key";
593         Date startTime = new Date();
594         Date originationEnd = new Date(startTime.getTime() + ORIGINATION_TIME_OFFSET);
595         Date consumptionEnd = new Date(startTime.getTime() + CONSUMPTION_TIME_OFFSET);
596         KeyGenParameterSpec.Builder builder = new KeyGenParameterSpec.Builder(keystoreAlias,
597                 purposes)
598                         .setAlgorithmParameterSpec(new ECGenParameterSpec(ecCurve))
599                         .setDigests(DIGEST_NONE, DIGEST_SHA256, DIGEST_SHA512)
600                         .setAttestationChallenge(challenge)
601                         .setDevicePropertiesAttestationIncluded(devicePropertiesAttestation);
602 
603         if (includeValidityDates) {
604             builder.setKeyValidityStart(startTime)
605                     .setKeyValidityForOriginationEnd(originationEnd)
606                     .setKeyValidityForConsumptionEnd(consumptionEnd);
607         }
608 
609         generateKeyPair(KEY_ALGORITHM_EC, builder.build());
610 
611         KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
612         keyStore.load(null);
613 
614         try {
615             Certificate certificates[] = keyStore.getCertificateChain(keystoreAlias);
616             verifyCertificateChain(certificates, false /* expectStrongBox */);
617 
618             X509Certificate attestationCert = (X509Certificate) certificates[0];
619             Attestation attestation = new Attestation(attestationCert);
620 
621             checkEcKeyDetails(attestation, ecCurve, keySize);
622             checkKeyUsage(attestationCert, purposes);
623             checkKeyIndependentAttestationInfo(challenge, purposes, startTime, includeValidityDates,
624                     devicePropertiesAttestation, attestation);
625         } finally {
626             keyStore.deleteEntry(keystoreAlias);
627         }
628     }
629 
checkAttestationApplicationId(Attestation attestation)630     private void checkAttestationApplicationId(Attestation attestation)
631             throws NoSuchAlgorithmException, NameNotFoundException {
632         AttestationApplicationId aaid = null;
633         int kmVersion = attestation.getKeymasterVersion();
634         assertNull(attestation.getTeeEnforced().getAttestationApplicationId());
635         aaid = attestation.getSoftwareEnforced().getAttestationApplicationId();
636         if (kmVersion >= 3) {
637             // must be present and correct
638             assertNotNull(aaid);
639             assertEquals(new AttestationApplicationId(getContext()), aaid);
640         } else {
641             // may be present and
642             // must be correct if present
643             if (aaid != null) {
644                 assertEquals(new AttestationApplicationId(getContext()), aaid);
645             }
646         }
647     }
648 
checkAttestationDeviceProperties(boolean devicePropertiesAttestation, Attestation attestation)649     private void checkAttestationDeviceProperties(boolean devicePropertiesAttestation,
650             Attestation attestation) {
651         final AuthorizationList keyDetailsList;
652         final AuthorizationList nonKeyDetailsList;
653         if (attestation.getKeymasterSecurityLevel() == KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT) {
654             keyDetailsList = attestation.getTeeEnforced();
655             nonKeyDetailsList = attestation.getSoftwareEnforced();
656         } else {
657             keyDetailsList = attestation.getSoftwareEnforced();
658             nonKeyDetailsList = attestation.getTeeEnforced();
659         }
660 
661         if (devicePropertiesAttestation) {
662             assertEquals(Build.BRAND, keyDetailsList.getBrand());
663             assertEquals(Build.DEVICE, keyDetailsList.getDevice());
664             assertEquals(Build.PRODUCT, keyDetailsList.getProduct());
665             assertEquals(Build.MANUFACTURER, keyDetailsList.getManufacturer());
666             assertEquals(Build.MODEL, keyDetailsList.getModel());
667         } else {
668             assertNull(keyDetailsList.getBrand());
669             assertNull(keyDetailsList.getDevice());
670             assertNull(keyDetailsList.getProduct());
671             assertNull(keyDetailsList.getManufacturer());
672             assertNull(keyDetailsList.getModel());
673         }
674         assertNull(nonKeyDetailsList.getBrand());
675         assertNull(nonKeyDetailsList.getDevice());
676         assertNull(nonKeyDetailsList.getProduct());
677         assertNull(nonKeyDetailsList.getManufacturer());
678         assertNull(nonKeyDetailsList.getModel());
679     }
680 
checkAttestationNoUniqueIds(Attestation attestation)681     private void checkAttestationNoUniqueIds(Attestation attestation) {
682         assertNull(attestation.getTeeEnforced().getImei());
683         assertNull(attestation.getTeeEnforced().getMeid());
684         assertNull(attestation.getTeeEnforced().getSerialNumber());
685         assertNull(attestation.getSoftwareEnforced().getImei());
686         assertNull(attestation.getSoftwareEnforced().getMeid());
687         assertNull(attestation.getSoftwareEnforced().getSerialNumber());
688     }
689 
checkKeyIndependentAttestationInfo(byte[] challenge, int purposes, Date startTime, boolean includesValidityDates, boolean devicePropertiesAttestation, Attestation attestation)690     private void checkKeyIndependentAttestationInfo(byte[] challenge, int purposes, Date startTime,
691             boolean includesValidityDates, boolean devicePropertiesAttestation,
692             Attestation attestation) throws NoSuchAlgorithmException, NameNotFoundException {
693         checkUnexpectedOids(attestation);
694         checkAttestationSecurityLevelDependentParams(attestation);
695         assertNotNull(attestation.getAttestationChallenge());
696         assertTrue(Arrays.equals(challenge, attestation.getAttestationChallenge()));
697         assertNotNull(attestation.getUniqueId());
698         assertEquals(0, attestation.getUniqueId().length);
699         checkPurposes(attestation, purposes);
700         checkDigests(attestation,
701                 ImmutableSet.of(KM_DIGEST_NONE, KM_DIGEST_SHA_2_256, KM_DIGEST_SHA_2_512));
702         checkValidityPeriod(attestation, startTime, includesValidityDates);
703         checkFlags(attestation);
704         checkOrigin(attestation);
705         checkAttestationApplicationId(attestation);
706         checkAttestationDeviceProperties(devicePropertiesAttestation, attestation);
707         checkAttestationNoUniqueIds(attestation);
708     }
709 
checkUnexpectedOids(Attestation attestation)710     private void checkUnexpectedOids(Attestation attestation) {
711         assertThat("Attestations must not contain any extra data",
712                 attestation.getUnexpectedExtensionOids(), is(empty()));
713     }
714 
getSystemPatchLevel()715     private int getSystemPatchLevel() {
716         Matcher matcher = OS_PATCH_LEVEL_STRING_PATTERN.matcher(Build.VERSION.SECURITY_PATCH);
717         assertTrue(matcher.matches());
718         String year_string = matcher.group(OS_PATCH_LEVEL_YEAR_GROUP_NAME);
719         String month_string = matcher.group(OS_PATCH_LEVEL_MONTH_GROUP_NAME);
720         int patch_level = Integer.parseInt(year_string) * 100 + Integer.parseInt(month_string);
721         return patch_level;
722     }
723 
getSystemOsVersion()724     private int getSystemOsVersion() {
725         return parseSystemOsVersion(Build.VERSION.RELEASE);
726     }
727 
parseSystemOsVersion(String versionString)728     private int parseSystemOsVersion(String versionString) {
729         Matcher matcher = OS_VERSION_STRING_PATTERN.matcher(versionString);
730         if (!matcher.matches()) {
731             return 0;
732         }
733 
734         int version = 0;
735         String major_string = matcher.group(OS_MAJOR_VERSION_MATCH_GROUP_NAME);
736         String minor_string = matcher.group(OS_MINOR_VERSION_MATCH_GROUP_NAME);
737         String subminor_string = matcher.group(OS_SUBMINOR_VERSION_MATCH_GROUP_NAME);
738         if (major_string != null) {
739             version += Integer.parseInt(major_string) * 10000;
740         }
741         if (minor_string != null) {
742             version += Integer.parseInt(minor_string) * 100;
743         }
744         if (subminor_string != null) {
745             version += Integer.parseInt(subminor_string);
746         }
747         return version;
748     }
749 
checkOrigin(Attestation attestation)750     private void checkOrigin(Attestation attestation) {
751         assertTrue("Origin must be defined",
752                 attestation.getSoftwareEnforced().getOrigin() != null ||
753                         attestation.getTeeEnforced().getOrigin() != null);
754         if (attestation.getKeymasterVersion() != 0) {
755             assertTrue("Origin may not be defined in both SW and TEE, except on keymaster0",
756                     attestation.getSoftwareEnforced().getOrigin() == null ||
757                             attestation.getTeeEnforced().getOrigin() == null);
758         }
759 
760         if (attestation.getKeymasterSecurityLevel() == KM_SECURITY_LEVEL_SOFTWARE) {
761             assertThat(attestation.getSoftwareEnforced().getOrigin(), is(KM_ORIGIN_GENERATED));
762         } else if (attestation.getKeymasterVersion() == 0) {
763             assertThat(attestation.getTeeEnforced().getOrigin(), is(KM_ORIGIN_UNKNOWN));
764         } else {
765             assertThat(attestation.getTeeEnforced().getOrigin(), is(KM_ORIGIN_GENERATED));
766         }
767     }
768 
checkFlags(Attestation attestation)769     private void checkFlags(Attestation attestation) {
770         assertFalse("All applications was not requested",
771                 attestation.getSoftwareEnforced().isAllApplications());
772         assertFalse("All applications was not requested",
773                 attestation.getTeeEnforced().isAllApplications());
774         assertFalse("Allow while on body was not requested",
775                 attestation.getSoftwareEnforced().isAllowWhileOnBody());
776         assertFalse("Allow while on body was not requested",
777                 attestation.getTeeEnforced().isAllowWhileOnBody());
778         assertNull("Auth binding was not requiested",
779                 attestation.getSoftwareEnforced().getUserAuthType());
780         assertNull("Auth binding was not requiested",
781                 attestation.getTeeEnforced().getUserAuthType());
782         assertTrue("noAuthRequired must be true",
783                 attestation.getSoftwareEnforced().isNoAuthRequired()
784                         || attestation.getTeeEnforced().isNoAuthRequired());
785         assertFalse("auth is either software or TEE",
786                 attestation.getSoftwareEnforced().isNoAuthRequired()
787                         && attestation.getTeeEnforced().isNoAuthRequired());
788         assertFalse("Software cannot implement rollback resistance",
789                 attestation.getSoftwareEnforced().isRollbackResistant());
790     }
791 
checkValidityPeriod(Attestation attestation, Date startTime, boolean includesValidityDates)792     private void checkValidityPeriod(Attestation attestation, Date startTime,
793             boolean includesValidityDates) {
794         AuthorizationList validityPeriodList;
795         AuthorizationList nonValidityPeriodList;
796         if (attestation.getTeeEnforced().getCreationDateTime() != null) {
797             validityPeriodList = attestation.getTeeEnforced();
798             nonValidityPeriodList = attestation.getSoftwareEnforced();
799         } else {
800             validityPeriodList = attestation.getSoftwareEnforced();
801             nonValidityPeriodList = attestation.getTeeEnforced();
802         }
803 
804         if (attestation.getKeymasterVersion() == 2) {
805             Date creationDateTime = validityPeriodList.getCreationDateTime();
806 
807             assertNotNull(creationDateTime);
808             assertNull(nonValidityPeriodList.getCreationDateTime());
809 
810             // We allow a little slop on creation times because the TEE/HAL may not be quite synced
811             // up with the system.
812             assertTrue("Test start time (" + startTime.getTime() + ") and key creation time (" +
813                     creationDateTime.getTime() + ") should be close",
814                     Math.abs(creationDateTime.getTime() - startTime.getTime()) <= 2000);
815         }
816 
817         if (includesValidityDates) {
818             Date activeDateTime = validityPeriodList.getActiveDateTime();
819             Date originationExpirationDateTime = validityPeriodList.getOriginationExpireDateTime();
820             Date usageExpirationDateTime = validityPeriodList.getUsageExpireDateTime();
821 
822             assertNotNull(activeDateTime);
823             assertNotNull(originationExpirationDateTime);
824             assertNotNull(usageExpirationDateTime);
825 
826             assertNull(nonValidityPeriodList.getActiveDateTime());
827             assertNull(nonValidityPeriodList.getOriginationExpireDateTime());
828             assertNull(nonValidityPeriodList.getUsageExpireDateTime());
829 
830             assertThat(originationExpirationDateTime.getTime(),
831                     is(startTime.getTime() + ORIGINATION_TIME_OFFSET));
832             assertThat(usageExpirationDateTime.getTime(),
833                     is(startTime.getTime() + CONSUMPTION_TIME_OFFSET));
834         }
835     }
836 
checkDigests(Attestation attestation, Set<Integer> expectedDigests)837     private void checkDigests(Attestation attestation, Set<Integer> expectedDigests) {
838         Set<Integer> softwareEnforcedDigests = attestation.getSoftwareEnforced().getDigests();
839         Set<Integer> teeEnforcedDigests = attestation.getTeeEnforced().getDigests();
840 
841         if (softwareEnforcedDigests == null) {
842             softwareEnforcedDigests = ImmutableSet.of();
843         }
844         if (teeEnforcedDigests == null) {
845             teeEnforcedDigests = ImmutableSet.of();
846         }
847 
848         Set<Integer> allDigests = ImmutableSet.<Integer> builder()
849                 .addAll(softwareEnforcedDigests)
850                 .addAll(teeEnforcedDigests)
851                 .build();
852         Set<Integer> intersection = new ArraySet<>();
853         intersection.addAll(softwareEnforcedDigests);
854         intersection.retainAll(teeEnforcedDigests);
855 
856         assertThat(allDigests, is(expectedDigests));
857         assertTrue("Digest sets must be disjoint", intersection.isEmpty());
858 
859         if (attestation.getKeymasterSecurityLevel() == KM_SECURITY_LEVEL_SOFTWARE
860                 || attestation.getKeymasterVersion() == 0) {
861             assertThat("Digests in software-enforced",
862                     softwareEnforcedDigests, is(expectedDigests));
863         } else {
864             switch (attestation.getKeymasterVersion()) {
865                 case 1:
866                     // KM1 implementations may not support SHA512 in the TEE
867                     assertTrue(softwareEnforcedDigests.contains(KM_DIGEST_SHA_2_512)
868                             || teeEnforcedDigests.contains(KM_DIGEST_SHA_2_512));
869 
870                     assertThat(teeEnforcedDigests, hasItems(KM_DIGEST_NONE, KM_DIGEST_SHA_2_256));
871                     break;
872 
873                 case 2:
874                 case 3:
875                 case 4:
876                     assertThat(teeEnforcedDigests, is(expectedDigests));
877                     break;
878 
879                 default:
880                     fail("Broken CTS test. Should be impossible to get here.");
881             }
882         }
883     }
884 
checkPurposes(Attestation attestation, int purposes)885     private Set<Integer> checkPurposes(Attestation attestation, int purposes) {
886         Set<Integer> expectedPurposes = buildPurposeSet(purposes);
887         if (attestation.getKeymasterSecurityLevel() == KM_SECURITY_LEVEL_SOFTWARE
888                 || attestation.getKeymasterVersion() == 0) {
889             assertThat("Purposes in software-enforced should match expected set",
890                     attestation.getSoftwareEnforced().getPurposes(), is(expectedPurposes));
891             assertNull("Should be no purposes in TEE-enforced",
892                     attestation.getTeeEnforced().getPurposes());
893         } else {
894             assertThat("Purposes in TEE-enforced should match expected set",
895                     attestation.getTeeEnforced().getPurposes(), is(expectedPurposes));
896             assertNull("No purposes in software-enforced",
897                     attestation.getSoftwareEnforced().getPurposes());
898         }
899         return expectedPurposes;
900     }
901 
902     @SuppressWarnings("unchecked")
checkAttestationSecurityLevelDependentParams(Attestation attestation)903     private void checkAttestationSecurityLevelDependentParams(Attestation attestation) {
904         assertThat("Attestation version must be 1, 2, 3, or 4", attestation.getAttestationVersion(),
905                either(is(1)).or(is(2)).or(is(3)).or(is(4)));
906 
907         AuthorizationList teeEnforced = attestation.getTeeEnforced();
908         AuthorizationList softwareEnforced = attestation.getSoftwareEnforced();
909 
910         int systemOsVersion = getSystemOsVersion();
911         int systemPatchLevel = getSystemPatchLevel();
912 
913         switch (attestation.getAttestationSecurityLevel()) {
914             case KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT:
915                 assertThat("TEE attestation can only come from TEE keymaster",
916                         attestation.getKeymasterSecurityLevel(),
917                         is(KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT));
918                 assertThat(attestation.getKeymasterVersion(),
919                            either(is(2)).or(is(3)).or(is(4)).or(is(41)));
920 
921                 checkRootOfTrust(attestation, false /* requireLocked */);
922                 assertThat(teeEnforced.getOsVersion(), is(systemOsVersion));
923                 assertThat(teeEnforced.getOsPatchLevel(), is(systemPatchLevel));
924                 break;
925 
926             case KM_SECURITY_LEVEL_SOFTWARE:
927                 if (attestation
928                         .getKeymasterSecurityLevel() == KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT) {
929                     assertThat("TEE KM version must be 0 or 1 with software attestation",
930                             attestation.getKeymasterVersion(), either(is(0)).or(is(1)));
931                 } else {
932                     assertThat("Software KM is version 3", attestation.getKeymasterVersion(),
933                             is(3));
934                     assertThat(softwareEnforced.getOsVersion(), is(systemOsVersion));
935                     assertThat(softwareEnforced.getOsPatchLevel(), is(systemPatchLevel));
936                 }
937 
938                 assertNull("Software attestation cannot provide root of trust",
939                         teeEnforced.getRootOfTrust());
940 
941                 break;
942 
943             default:
944                 fail("Invalid attestation security level: "
945                         + attestation.getAttestationSecurityLevel());
946                 break;
947         }
948 
949         assertNull("Software-enforced list must not contain root of trust",
950                 softwareEnforced.getRootOfTrust());
951     }
952 
checkDeviceLocked(Attestation attestation)953     private void checkDeviceLocked(Attestation attestation) {
954         assertThat("Attestation version must be >= 1",
955                 attestation.getAttestationVersion(), greaterThanOrEqualTo(1));
956 
957         int attestationSecurityLevel = attestation.getAttestationSecurityLevel();
958         switch (attestationSecurityLevel) {
959             case KM_SECURITY_LEVEL_STRONG_BOX:
960             case KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT:
961                 assertThat("Attestation security level doesn't match keymaster security level",
962                         attestation.getKeymasterSecurityLevel(), is(attestationSecurityLevel));
963                 assertThat(attestation.getKeymasterVersion(), greaterThanOrEqualTo(2));
964 
965                 // Devices launched in Android 10.0 (API level 29) and after should run CTS
966                 // in LOCKED state.
967                 boolean requireLocked = (
968                         SystemProperties.getInt("ro.product.first_api_level", 0) >= 29);
969                 checkRootOfTrust(attestation, requireLocked);
970                 break;
971 
972             case KM_SECURITY_LEVEL_SOFTWARE:
973             default:
974                 // TEE attestation has been required since Android 7.0.
975                 fail("Unexpected attestation security level: " +
976                      attestation.securityLevelToString(attestationSecurityLevel));
977                 break;
978         }
979     }
980 
checkRootOfTrust(Attestation attestation, boolean requireLocked)981     private void checkRootOfTrust(Attestation attestation, boolean requireLocked) {
982         RootOfTrust rootOfTrust = attestation.getTeeEnforced().getRootOfTrust();
983         assertNotNull(rootOfTrust);
984         assertNotNull(rootOfTrust.getVerifiedBootKey());
985         assertTrue("Verified boot key is only " + rootOfTrust.getVerifiedBootKey().length +
986                    " bytes long", rootOfTrust.getVerifiedBootKey().length >= 32);
987         if (requireLocked) {
988             assertTrue(rootOfTrust.isDeviceLocked());
989             checkEntropy(rootOfTrust.getVerifiedBootKey());
990             assertEquals(KM_VERIFIED_BOOT_VERIFIED, rootOfTrust.getVerifiedBootState());
991         }
992     }
993 
checkEntropy(byte[] verifiedBootKey)994     private void checkEntropy(byte[] verifiedBootKey) {
995         assertTrue("Failed Shannon entropy check", checkShannonEntropy(verifiedBootKey));
996         assertTrue("Failed BiEntropy check", checkTresBiEntropy(verifiedBootKey));
997     }
998 
checkShannonEntropy(byte[] verifiedBootKey)999     private boolean checkShannonEntropy(byte[] verifiedBootKey) {
1000         double probabilityOfSetBit = countSetBits(verifiedBootKey) / (double)(verifiedBootKey.length * 8);
1001         return calculateShannonEntropy(probabilityOfSetBit) > 0.8;
1002     }
1003 
calculateShannonEntropy(double probabilityOfSetBit)1004     private double calculateShannonEntropy(double probabilityOfSetBit) {
1005         if (probabilityOfSetBit <= 0.001 || probabilityOfSetBit >= .999) return 0;
1006         double entropy = (-probabilityOfSetBit * logTwo(probabilityOfSetBit)) -
1007                             ((1 - probabilityOfSetBit) * logTwo(1 - probabilityOfSetBit));
1008         Log.i(TAG, "Shannon entropy of VB Key: " + entropy);
1009         return entropy;
1010     }
1011 
checkTresBiEntropy(byte[] verifiedBootKey)1012     private boolean checkTresBiEntropy(byte[] verifiedBootKey) {
1013         double weightingFactor = 0;
1014         double weightedEntropy = 0;
1015         double probabilityOfSetBit = 0;
1016         int length = verifiedBootKey.length * 8;
1017         for(int i = 0; i < (verifiedBootKey.length * 8) - 2; i++) {
1018             probabilityOfSetBit = countSetBits(verifiedBootKey) / (double)length;
1019             weightingFactor += logTwo(i+2);
1020             weightedEntropy += calculateShannonEntropy(probabilityOfSetBit) * logTwo(i+2);
1021             deriveBitString(verifiedBootKey, length);
1022             length -= 1;
1023         }
1024         double tresBiEntropy = (1 / weightingFactor) * weightedEntropy;
1025         Log.i(TAG, "BiEntropy of VB Key: " + tresBiEntropy);
1026         return tresBiEntropy > 0.9;
1027     }
1028 
deriveBitString(byte[] bitString, int activeLength)1029     private void deriveBitString(byte[] bitString, int activeLength) {
1030         int length = activeLength / 8;
1031         if (activeLength % 8 != 0) {
1032             length += 1;
1033         }
1034 
1035         byte mask = (byte)((byte)0x80 >>> ((activeLength + 6) % 8));
1036         if (activeLength % 8 == 1) {
1037             mask = (byte)~mask;
1038         }
1039 
1040         for(int i = 0; i < length; i++) {
1041             if (i == length - 1) {
1042                 bitString[i] ^= ((bitString[i] & 0xFF) << 1);
1043                 bitString[i] &= mask;
1044             } else {
1045                 bitString[i] ^= ((bitString[i] & 0xFF) << 1) | ((bitString[i+1] & 0xFF) >>> 7);
1046             }
1047         }
1048     }
1049 
logTwo(double value)1050     private double logTwo(double value) {
1051         return Math.log(value) / Math.log(2);
1052     }
1053 
countSetBits(byte[] toCount)1054     private int countSetBits(byte[] toCount) {
1055         int setBitCount = 0;
1056         for(int i = 0; i < toCount.length; i++) {
1057             setBitCount += countSetBits(toCount[i]);
1058         }
1059         return setBitCount;
1060     }
1061 
countSetBits(byte toCount)1062     private int countSetBits(byte toCount) {
1063         int setBitCounter = 0;
1064         while(toCount != 0) {
1065             toCount &= (toCount - 1);
1066             setBitCounter++;
1067         }
1068         return setBitCounter;
1069     }
1070 
checkRsaKeyDetails(Attestation attestation, int keySize, int purposes, Set<String> expectedPaddingModes)1071     private void checkRsaKeyDetails(Attestation attestation, int keySize, int purposes,
1072             Set<String> expectedPaddingModes) throws CertificateParsingException {
1073         AuthorizationList keyDetailsList;
1074         AuthorizationList nonKeyDetailsList;
1075         if (attestation.getKeymasterSecurityLevel() == KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT) {
1076             keyDetailsList = attestation.getTeeEnforced();
1077             nonKeyDetailsList = attestation.getSoftwareEnforced();
1078         } else {
1079             keyDetailsList = attestation.getSoftwareEnforced();
1080             nonKeyDetailsList = attestation.getTeeEnforced();
1081         }
1082         assertEquals(keySize, keyDetailsList.getKeySize().intValue());
1083         assertNull(nonKeyDetailsList.getKeySize());
1084 
1085         assertEquals(KM_ALGORITHM_RSA, keyDetailsList.getAlgorithm().intValue());
1086         assertNull(nonKeyDetailsList.getAlgorithm());
1087 
1088         assertNull(keyDetailsList.getEcCurve());
1089         assertNull(nonKeyDetailsList.getEcCurve());
1090 
1091         assertEquals(65537, keyDetailsList.getRsaPublicExponent().longValue());
1092         assertNull(nonKeyDetailsList.getRsaPublicExponent());
1093 
1094         Set<String> paddingModes;
1095         if (attestation.getKeymasterVersion() == 0) {
1096             // KM0 implementations don't support padding info, so it's always in the
1097             // software-enforced list.
1098             paddingModes = attestation.getSoftwareEnforced().getPaddingModesAsStrings();
1099             assertNull(attestation.getTeeEnforced().getPaddingModes());
1100         } else {
1101             paddingModes = keyDetailsList.getPaddingModesAsStrings();
1102             assertNull(nonKeyDetailsList.getPaddingModes());
1103         }
1104 
1105         // KM1 implementations may add ENCRYPTION_PADDING_NONE to the list of paddings.
1106         Set<String> km1PossiblePaddingModes = expectedPaddingModes;
1107         if (attestation.getKeymasterVersion() == 1 &&
1108                 attestation.getKeymasterSecurityLevel() == KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT) {
1109             ImmutableSet.Builder<String> builder = ImmutableSet.builder();
1110             builder.addAll(expectedPaddingModes);
1111             builder.add(ENCRYPTION_PADDING_NONE);
1112             km1PossiblePaddingModes = builder.build();
1113         }
1114 
1115         assertThat(paddingModes, either(is(expectedPaddingModes)).or(is(km1PossiblePaddingModes)));
1116     }
1117 
checkEcKeyDetails(Attestation attestation, String ecCurve, int keySize)1118     private void checkEcKeyDetails(Attestation attestation, String ecCurve, int keySize) {
1119         AuthorizationList keyDetailsList;
1120         AuthorizationList nonKeyDetailsList;
1121         if (attestation.getKeymasterSecurityLevel() == KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT) {
1122             keyDetailsList = attestation.getTeeEnforced();
1123             nonKeyDetailsList = attestation.getSoftwareEnforced();
1124         } else {
1125             keyDetailsList = attestation.getSoftwareEnforced();
1126             nonKeyDetailsList = attestation.getTeeEnforced();
1127         }
1128         assertEquals(keySize, keyDetailsList.getKeySize().intValue());
1129         assertNull(nonKeyDetailsList.getKeySize());
1130         assertEquals(KM_ALGORITHM_EC, keyDetailsList.getAlgorithm().intValue());
1131         assertNull(nonKeyDetailsList.getAlgorithm());
1132         assertEquals(ecCurve, keyDetailsList.ecCurveAsString());
1133         assertNull(nonKeyDetailsList.getEcCurve());
1134         assertNull(keyDetailsList.getRsaPublicExponent());
1135         assertNull(nonKeyDetailsList.getRsaPublicExponent());
1136         assertNull(keyDetailsList.getPaddingModes());
1137         assertNull(nonKeyDetailsList.getPaddingModes());
1138     }
1139 
isEncryptionPurpose(int purposes)1140     private boolean isEncryptionPurpose(int purposes) {
1141         return (purposes & PURPOSE_DECRYPT) != 0 || (purposes & PURPOSE_ENCRYPT) != 0;
1142     }
1143 
isSignaturePurpose(int purposes)1144     private boolean isSignaturePurpose(int purposes) {
1145         return (purposes & PURPOSE_SIGN) != 0 || (purposes & PURPOSE_VERIFY) != 0;
1146     }
1147 
buildPurposeSet(int purposes)1148     private ImmutableSet<Integer> buildPurposeSet(int purposes) {
1149         ImmutableSet.Builder<Integer> builder = ImmutableSet.builder();
1150         if ((purposes & PURPOSE_SIGN) != 0)
1151             builder.add(KM_PURPOSE_SIGN);
1152         if ((purposes & PURPOSE_VERIFY) != 0)
1153             builder.add(KM_PURPOSE_VERIFY);
1154         if ((purposes & PURPOSE_ENCRYPT) != 0)
1155             builder.add(KM_PURPOSE_ENCRYPT);
1156         if ((purposes & PURPOSE_DECRYPT) != 0)
1157             builder.add(KM_PURPOSE_DECRYPT);
1158         return builder.build();
1159     }
1160 
generateKey(KeyGenParameterSpec spec, String algorithm)1161     private void generateKey(KeyGenParameterSpec spec, String algorithm)
1162             throws NoSuchAlgorithmException, NoSuchProviderException,
1163             InvalidAlgorithmParameterException {
1164         KeyGenerator keyGenerator = KeyGenerator.getInstance(algorithm, "AndroidKeyStore");
1165         keyGenerator.init(spec);
1166         keyGenerator.generateKey();
1167     }
1168 
generateKeyPair(String algorithm, KeyGenParameterSpec spec)1169     private void generateKeyPair(String algorithm, KeyGenParameterSpec spec)
1170             throws NoSuchAlgorithmException, NoSuchProviderException,
1171             InvalidAlgorithmParameterException {
1172         KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(algorithm,
1173                 "AndroidKeyStore");
1174         keyPairGenerator.initialize(spec);
1175         keyPairGenerator.generateKeyPair();
1176     }
1177 
verifyCertificateChain(Certificate[] certChain, boolean expectStrongBox)1178     private void verifyCertificateChain(Certificate[] certChain, boolean expectStrongBox)
1179             throws GeneralSecurityException {
1180         assertNotNull(certChain);
1181         for (int i = 1; i < certChain.length; ++i) {
1182             try {
1183                 PublicKey pubKey = certChain[i].getPublicKey();
1184                 certChain[i - 1].verify(pubKey);
1185                 if (i == certChain.length - 1) {
1186                     // Last cert should be self-signed.
1187                     certChain[i].verify(pubKey);
1188                 }
1189 
1190                 // Check that issuer in the signed cert matches subject in the signing cert.
1191                 X509Certificate x509CurrCert = (X509Certificate) certChain[i];
1192                 X509Certificate x509PrevCert = (X509Certificate) certChain[i - 1];
1193                 X500Name signingCertSubject =
1194                         new JcaX509CertificateHolder(x509CurrCert).getSubject();
1195                 X500Name signedCertIssuer =
1196                         new JcaX509CertificateHolder(x509PrevCert).getIssuer();
1197                 // Use .toASN1Object().equals() rather than .equals() because .equals() is case
1198                 // insensitive, and we want to verify an exact match.
1199                 assertTrue(
1200                         signedCertIssuer.toASN1Object().equals(signingCertSubject.toASN1Object()));
1201 
1202                 if (i == 1) {
1203                     // First cert should have subject "CN=Android Keystore Key".
1204                     X500Name signedCertSubject =
1205                             new JcaX509CertificateHolder(x509PrevCert).getSubject();
1206                     assertEquals(signedCertSubject, new X500Name("CN=Android Keystore Key"));
1207                 } else {
1208                     // Only strongbox implementations should have strongbox in the subject line
1209                     assertEquals(expectStrongBox, x509CurrCert.getSubjectDN()
1210                                                               .getName()
1211                                                               .toLowerCase()
1212                                                               .contains("strongbox"));
1213                 }
1214             } catch (InvalidKeyException | CertificateException | NoSuchAlgorithmException
1215                     | NoSuchProviderException | SignatureException e) {
1216                 throw new GeneralSecurityException("Using StrongBox: " + expectStrongBox + "\n"
1217                         + "Failed to verify certificate "
1218                         + certChain[i - 1] + " with public key " + certChain[i].getPublicKey(), e);
1219             }
1220         }
1221     }
1222 
testDeviceIdAttestationFailure(int idType, String acceptableDeviceIdAttestationFailureMessage)1223     private void testDeviceIdAttestationFailure(int idType,
1224             String acceptableDeviceIdAttestationFailureMessage) throws Exception {
1225         try {
1226             AttestationUtils.attestDeviceIds(getContext(), new int[] {idType}, "123".getBytes());
1227             fail("Attestation should have failed.");
1228         } catch (SecurityException e) {
1229             // Attestation is expected to fail. If the device has the device ID type we are trying
1230             // to attest, it should fail with a SecurityException as we do not hold
1231             // READ_PRIVILEGED_PHONE_STATE permission.
1232         } catch (DeviceIdAttestationException e) {
1233             // Attestation is expected to fail. If the device does not have the device ID type we
1234             // are trying to attest (e.g. no IMEI on devices without a radio), it should fail with
1235             // a corresponding DeviceIdAttestationException.
1236             if (acceptableDeviceIdAttestationFailureMessage == null ||
1237                     !acceptableDeviceIdAttestationFailureMessage.equals(e.getMessage())) {
1238                 throw e;
1239             }
1240         }
1241     }
1242 }
1243