• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.keystore.cts;
18 
19 import 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 import static org.hamcrest.Matchers.lessThanOrEqualTo;
56 import static org.junit.Assert.assertEquals;
57 import static org.junit.Assert.assertFalse;
58 import static org.junit.Assert.assertNotEquals;
59 import static org.junit.Assert.assertNotNull;
60 import static org.junit.Assert.assertNull;
61 import static org.junit.Assert.assertTrue;
62 import static org.junit.Assert.fail;
63 import static org.junit.Assume.assumeTrue;
64 
65 import android.content.Context;
66 import android.content.pm.PackageManager;
67 import android.content.pm.PackageManager.NameNotFoundException;
68 import android.keystore.cts.Attestation;
69 import android.keystore.cts.util.TestUtils;
70 import android.os.Build;
71 import android.os.SystemProperties;
72 import android.platform.test.annotations.RestrictedBuildTest;
73 import android.security.KeyStoreException;
74 import android.security.keystore.AttestationUtils;
75 import android.security.keystore.DeviceIdAttestationException;
76 import android.security.keystore.KeyGenParameterSpec;
77 import android.security.keystore.KeyProperties;
78 import android.util.ArraySet;
79 import android.util.Log;
80 
81 import androidx.test.InstrumentationRegistry;
82 import androidx.test.filters.RequiresDevice;
83 import androidx.test.runner.AndroidJUnit4;
84 
85 import com.android.bedstead.nene.TestApis;
86 import com.android.bedstead.nene.permissions.PermissionContext;
87 
88 import com.google.common.collect.ImmutableSet;
89 
90 import org.bouncycastle.asn1.x500.X500Name;
91 import org.bouncycastle.cert.jcajce.JcaX509CertificateHolder;
92 import org.junit.Test;
93 import org.junit.runner.RunWith;
94 
95 import java.io.File;
96 import java.security.GeneralSecurityException;
97 import java.security.InvalidAlgorithmParameterException;
98 import java.security.InvalidKeyException;
99 import java.security.KeyPairGenerator;
100 import java.security.KeyStore;
101 import java.security.NoSuchAlgorithmException;
102 import java.security.NoSuchProviderException;
103 import java.security.ProviderException;
104 import java.security.PublicKey;
105 import java.security.SignatureException;
106 import java.security.cert.Certificate;
107 import java.security.cert.CertificateException;
108 import java.security.cert.CertificateParsingException;
109 import java.security.cert.X509Certificate;
110 import java.security.spec.ECGenParameterSpec;
111 import java.util.Arrays;
112 import java.util.Date;
113 import java.util.Set;
114 import java.util.regex.Matcher;
115 import java.util.regex.Pattern;
116 
117 import javax.crypto.KeyGenerator;
118 
119 /**
120  * Tests for Android Keystore attestation.
121  */
122 @RunWith(AndroidJUnit4.class)
123 public class KeyAttestationTest {
124 
125     private static final String TAG = AndroidKeyStoreTest.class.getSimpleName();
126 
127     private static final int ORIGINATION_TIME_OFFSET = 1000000;
128     private static final int CONSUMPTION_TIME_OFFSET = 2000000;
129 
130     private static final int KEY_USAGE_BITSTRING_LENGTH = 9;
131     private static final int KEY_USAGE_DIGITAL_SIGNATURE_BIT_OFFSET = 0;
132     private static final int KEY_USAGE_KEY_ENCIPHERMENT_BIT_OFFSET = 2;
133     private static final int KEY_USAGE_DATA_ENCIPHERMENT_BIT_OFFSET = 3;
134 
135     private static final int OS_MAJOR_VERSION_MATCH_GROUP_NAME = 1;
136     private static final int OS_MINOR_VERSION_MATCH_GROUP_NAME = 2;
137     private static final int OS_SUBMINOR_VERSION_MATCH_GROUP_NAME = 3;
138     private static final Pattern OS_VERSION_STRING_PATTERN = Pattern
139             .compile("([0-9]{1,2})(?:\\.([0-9]{1,2}))?(?:\\.([0-9]{1,2}))?(?:[^0-9.]+.*)?");
140 
141     private static final int OS_PATCH_LEVEL_YEAR_GROUP_NAME = 1;
142     private static final int OS_PATCH_LEVEL_MONTH_GROUP_NAME = 2;
143     private static final Pattern OS_PATCH_LEVEL_STRING_PATTERN = Pattern
144             .compile("([0-9]{4})-([0-9]{2})-[0-9]{2}");
145 
146     private static final int KM_ERROR_CANNOT_ATTEST_IDS = -66;
147     private static final int KM_ERROR_INVALID_INPUT_LENGTH = -21;
148     private static final int KM_ERROR_PERMISSION_DENIED = 6;
149 
getContext()150     private Context getContext() {
151         return InstrumentationRegistry.getInstrumentation().getTargetContext();
152     }
153 
154     @Test
testVersionParser()155     public void testVersionParser() throws Exception {
156         // Non-numerics/empty give version 0
157         assertEquals(0, parseSystemOsVersion(""));
158         assertEquals(0, parseSystemOsVersion("N"));
159 
160         // Should support one, two or three version number values.
161         assertEquals(10000, parseSystemOsVersion("1"));
162         assertEquals(10200, parseSystemOsVersion("1.2"));
163         assertEquals(10203, parseSystemOsVersion("1.2.3"));
164 
165         // It's fine to append other stuff to the dotted numeric version.
166         assertEquals(10000, parseSystemOsVersion("1stuff"));
167         assertEquals(10200, parseSystemOsVersion("1.2garbage.32"));
168         assertEquals(10203, parseSystemOsVersion("1.2.3-stuff"));
169 
170         // Two digits per version field are supported
171         assertEquals(152536, parseSystemOsVersion("15.25.36"));
172         assertEquals(999999, parseSystemOsVersion("99.99.99"));
173         assertEquals(0, parseSystemOsVersion("100.99.99"));
174         assertEquals(0, parseSystemOsVersion("99.100.99"));
175         assertEquals(0, parseSystemOsVersion("99.99.100"));
176     }
177 
178     @RequiresDevice
179     @Test
testEcAttestation()180     public void testEcAttestation() throws Exception {
181         if (!TestUtils.isAttestationSupported()) {
182             return;
183         }
184 
185         if (getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_PC))
186             return;
187 
188         // Note: Curve and key sizes arrays must correspond.
189         String[] curves = {
190                 "secp224r1", "secp256r1", "secp384r1", "secp521r1"
191         };
192         int[] keySizes = {
193                 224, 256, 384, 521
194         };
195         byte[][] challenges = {
196                 new byte[0], // empty challenge
197                 "challenge".getBytes(), // short challenge
198                 new byte[128], // long challenge
199         };
200         int[] purposes = {
201                 KM_PURPOSE_SIGN, KM_PURPOSE_VERIFY, KM_PURPOSE_SIGN | KM_PURPOSE_VERIFY
202         };
203         boolean[] devicePropertiesAttestationValues = {true, false};
204         boolean[] includeValidityDatesValues = {true, false};
205 
206         for (int curveIndex = 0; curveIndex < curves.length; ++curveIndex) {
207             for (int challengeIndex = 0; challengeIndex < challenges.length; ++challengeIndex) {
208                 for (int purposeIndex = 0; purposeIndex < purposes.length; ++purposeIndex) {
209                     for (boolean includeValidityDates : includeValidityDatesValues) {
210                         for (boolean devicePropertiesAttestation : devicePropertiesAttestationValues) {
211                             try {
212                                 testEcAttestation(challenges[challengeIndex], includeValidityDates,
213                                         curves[curveIndex], keySizes[curveIndex],
214                                         purposes[purposeIndex], devicePropertiesAttestation);
215                             } catch (Throwable e) {
216                                 boolean isIdAttestationFailure =
217                                         (e.getCause() instanceof KeyStoreException)
218                                         && KeyStoreException.ERROR_ID_ATTESTATION_FAILURE
219                                         == ((KeyStoreException) e.getCause()).getNumericErrorCode();
220                                 if (devicePropertiesAttestation && isIdAttestationFailure) {
221                                     Log.i(TAG, "key attestation with device IDs not supported; "
222                                             + "test skipped");
223                                     continue;
224                                 }
225                                 throw new Exception("Failed on curve " + curveIndex +
226                                         " challenge " + challengeIndex + " purpose " +
227                                         purposeIndex + " includeValidityDates " +
228                                         includeValidityDates + " and devicePropertiesAttestation " +
229                                         devicePropertiesAttestation, e);
230                             }
231                         }
232                     }
233                 }
234             }
235         }
236     }
237 
assertPublicAttestationError(KeyStoreException keyStoreException, boolean devicePropertiesAttestation)238     private void assertPublicAttestationError(KeyStoreException keyStoreException,
239             boolean devicePropertiesAttestation) {
240         // Assert public failure information.
241         int errorCode = keyStoreException.getNumericErrorCode();
242         String assertMessage = String.format(
243                 "Error code was %d, device properties attestation? %b",
244                 errorCode, devicePropertiesAttestation);
245         assertTrue(assertMessage, KeyStoreException.ERROR_INCORRECT_USAGE == errorCode
246                 || (devicePropertiesAttestation
247                 && KeyStoreException.ERROR_ID_ATTESTATION_FAILURE == errorCode));
248         assertFalse(keyStoreException.isTransientFailure());
249     }
250 
251     @Test
testEcAttestation_TooLargeChallenge()252     public void testEcAttestation_TooLargeChallenge() throws Exception {
253         if (!TestUtils.isAttestationSupported()) {
254             return;
255         }
256 
257         boolean[] devicePropertiesAttestationValues = {true, false};
258         for (boolean devicePropertiesAttestation : devicePropertiesAttestationValues) {
259             try {
260                 testEcAttestation(new byte[129], true /* includeValidityDates */, "secp256r1", 256,
261                         KM_PURPOSE_SIGN, devicePropertiesAttestation);
262                 fail("Attestation challenges larger than 128 bytes should be rejected");
263             } catch (ProviderException e) {
264                 KeyStoreException cause = (KeyStoreException) e.getCause();
265                 assertTrue(KM_ERROR_INVALID_INPUT_LENGTH == cause.getErrorCode() ||
266                         (devicePropertiesAttestation
267                                 && KM_ERROR_CANNOT_ATTEST_IDS == cause.getErrorCode())
268                 );
269                 assertPublicAttestationError(cause, devicePropertiesAttestation);
270             }
271         }
272     }
273 
274     @Test
testEcAttestation_NoChallenge()275     public void testEcAttestation_NoChallenge() throws Exception {
276         boolean[] devicePropertiesAttestationValues = {true, false};
277         for (boolean devicePropertiesAttestation : devicePropertiesAttestationValues) {
278             String keystoreAlias = "test_key";
279             Date now = new Date();
280             Date originationEnd = new Date(now.getTime() + ORIGINATION_TIME_OFFSET);
281             Date consumptionEnd = new Date(now.getTime() + CONSUMPTION_TIME_OFFSET);
282             KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(keystoreAlias, PURPOSE_SIGN)
283                     .setAlgorithmParameterSpec(new ECGenParameterSpec("secp256r1"))
284                     .setDigests(DIGEST_NONE, DIGEST_SHA256, DIGEST_SHA512)
285                     .setAttestationChallenge(null)
286                     .setKeyValidityStart(now)
287                     .setKeyValidityForOriginationEnd(originationEnd)
288                     .setKeyValidityForConsumptionEnd(consumptionEnd)
289                     .setDevicePropertiesAttestationIncluded(devicePropertiesAttestation)
290                     .build();
291 
292             generateKeyPair(KEY_ALGORITHM_EC, spec);
293 
294             KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
295             keyStore.load(null);
296 
297             try {
298                 Certificate certificates[] = keyStore.getCertificateChain(keystoreAlias);
299                 assertEquals(1, certificates.length);
300 
301                 X509Certificate attestationCert = (X509Certificate) certificates[0];
302                 assertNull(attestationCert.getExtensionValue(Attestation.ASN1_OID));
303                 assertNull(attestationCert.getExtensionValue(Attestation.EAT_OID));
304             } finally {
305                 keyStore.deleteEntry(keystoreAlias);
306             }
307         }
308     }
309 
testEcAttestation_DeviceLocked(Boolean expectStrongBox)310     private void testEcAttestation_DeviceLocked(Boolean expectStrongBox) throws Exception {
311         if (!TestUtils.isAttestationSupported()) {
312             return;
313         }
314 
315         if (getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_PC))
316             return;
317 
318         String keystoreAlias = "test_key";
319         Date now = new Date();
320         Date originationEnd = new Date(now.getTime() + ORIGINATION_TIME_OFFSET);
321         Date consumptionEnd = new Date(now.getTime() + CONSUMPTION_TIME_OFFSET);
322         KeyGenParameterSpec.Builder builder =
323             new KeyGenParameterSpec.Builder(keystoreAlias, PURPOSE_SIGN)
324                     .setAlgorithmParameterSpec(new ECGenParameterSpec("secp256r1"))
325                     .setAttestationChallenge(new byte[128])
326                     .setKeyValidityStart(now)
327                     .setKeyValidityForOriginationEnd(originationEnd)
328                     .setKeyValidityForConsumptionEnd(consumptionEnd)
329                     .setIsStrongBoxBacked(expectStrongBox);
330 
331         if (expectStrongBox) {
332             builder.setDigests(DIGEST_NONE, DIGEST_SHA256);
333         } else {
334             builder.setDigests(DIGEST_NONE, DIGEST_SHA256, DIGEST_SHA512);
335         }
336 
337         generateKeyPair(KEY_ALGORITHM_EC, builder.build());
338 
339         KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
340         keyStore.load(null);
341 
342         try {
343             Certificate certificates[] = keyStore.getCertificateChain(keystoreAlias);
344             verifyCertificateChain(certificates, expectStrongBox);
345 
346             X509Certificate attestationCert = (X509Certificate) certificates[0];
347             checkDeviceLocked(Attestation.loadFromCertificate(attestationCert));
348         } finally {
349             keyStore.deleteEntry(keystoreAlias);
350         }
351     }
352 
353     @RestrictedBuildTest
354     @RequiresDevice
355     @Test
testEcAttestation_DeviceLocked()356     public void testEcAttestation_DeviceLocked() throws Exception {
357         testEcAttestation_DeviceLocked(false /* expectStrongBox */);
358     }
359 
360     @RestrictedBuildTest
361     @RequiresDevice
362     @Test
testEcAttestation_DeviceLockedStrongbox()363     public void testEcAttestation_DeviceLockedStrongbox() throws Exception {
364         if (!TestUtils.hasStrongBox(getContext()))
365             return;
366 
367         testEcAttestation_DeviceLocked(true /* expectStrongBox */);
368     }
369 
370     @Test
testAttestationKmVersionMatchesFeatureVersion()371     public void testAttestationKmVersionMatchesFeatureVersion() throws Exception {
372         if (getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_PC))
373             return;
374 
375         String keystoreAlias = "test_key";
376         Date now = new Date();
377         Date originationEnd = new Date(now.getTime() + ORIGINATION_TIME_OFFSET);
378         Date consumptionEnd = new Date(now.getTime() + CONSUMPTION_TIME_OFFSET);
379         KeyGenParameterSpec.Builder builder =
380             new KeyGenParameterSpec.Builder(keystoreAlias, PURPOSE_SIGN)
381                     .setAlgorithmParameterSpec(new ECGenParameterSpec("secp256r1"))
382                     .setAttestationChallenge(new byte[128])
383                     .setKeyValidityStart(now)
384                     .setKeyValidityForOriginationEnd(originationEnd)
385                     .setKeyValidityForConsumptionEnd(consumptionEnd);
386 
387         generateKeyPair(KEY_ALGORITHM_EC, builder.build());
388 
389         KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
390         keyStore.load(null);
391 
392         try {
393             Certificate certificates[] = keyStore.getCertificateChain(keystoreAlias);
394             verifyCertificateChain(certificates, false /* expectStrongBox */);
395             X509Certificate attestationCert = (X509Certificate) certificates[0];
396             Attestation attestation = Attestation.loadFromCertificate(attestationCert);
397             int kmVersionFromAttestation = attestation.keymasterVersion;
398             int keyStoreFeatureVersion = TestUtils.getFeatureVersionKeystore(getContext());
399 
400             // Feature Version is required on devices launching with Android 12 (API Level
401             // 31) but may be reported on devices launching with an earlier version. If it's
402             // present, it must match what is reported in attestation.
403             int firstApiLevel = SystemProperties.getInt("ro.product.first_api_level", 0);
404             if (firstApiLevel >= 31) {
405                 assertNotEquals(0, keyStoreFeatureVersion);
406             }
407             if (keyStoreFeatureVersion != 0) {
408                 assertEquals(kmVersionFromAttestation, keyStoreFeatureVersion);
409             }
410         } finally {
411             keyStore.deleteEntry(keystoreAlias);
412         }
413     }
414 
415     @Test
testAttestationKmVersionMatchesFeatureVersionStrongBox()416     public void testAttestationKmVersionMatchesFeatureVersionStrongBox() throws Exception {
417         if (getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_PC))
418             return;
419 
420         int keyStoreFeatureVersionStrongBox =
421                 TestUtils.getFeatureVersionKeystoreStrongBox(getContext());
422 
423         if (!TestUtils.hasStrongBox(getContext())) {
424             // If there's no StrongBox, ensure there's no feature version for it.
425             assertEquals(0, keyStoreFeatureVersionStrongBox);
426             return;
427         }
428 
429         String keystoreAlias = "test_key";
430         Date now = new Date();
431         Date originationEnd = new Date(now.getTime() + ORIGINATION_TIME_OFFSET);
432         Date consumptionEnd = new Date(now.getTime() + CONSUMPTION_TIME_OFFSET);
433         KeyGenParameterSpec.Builder builder =
434             new KeyGenParameterSpec.Builder(keystoreAlias, PURPOSE_SIGN)
435                     .setAlgorithmParameterSpec(new ECGenParameterSpec("secp256r1"))
436                     .setAttestationChallenge(new byte[128])
437                     .setKeyValidityStart(now)
438                     .setKeyValidityForOriginationEnd(originationEnd)
439                     .setKeyValidityForConsumptionEnd(consumptionEnd)
440                     .setIsStrongBoxBacked(true);
441 
442         generateKeyPair(KEY_ALGORITHM_EC, builder.build());
443 
444         KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
445         keyStore.load(null);
446 
447         try {
448             Certificate certificates[] = keyStore.getCertificateChain(keystoreAlias);
449             verifyCertificateChain(certificates, true /* expectStrongBox */);
450             X509Certificate attestationCert = (X509Certificate) certificates[0];
451             Attestation attestation = Attestation.loadFromCertificate(attestationCert);
452             int kmVersionFromAttestation = attestation.keymasterVersion;
453 
454             // Feature Version is required on devices launching with Android 12 (API Level
455             // 31) but may be reported on devices launching with an earlier version. If it's
456             // present, it must match what is reported in attestation.
457             int firstApiLevel = SystemProperties.getInt("ro.product.first_api_level", 0);
458             if (firstApiLevel >= 31) {
459                 assertNotEquals(0, keyStoreFeatureVersionStrongBox);
460             }
461             if (keyStoreFeatureVersionStrongBox != 0) {
462                 assertEquals(kmVersionFromAttestation, keyStoreFeatureVersionStrongBox);
463             }
464         } finally {
465             keyStore.deleteEntry(keystoreAlias);
466         }
467     }
468 
469     @Test
testEcAttestation_KeyStoreExceptionWhenRequestingUniqueId()470     public void testEcAttestation_KeyStoreExceptionWhenRequestingUniqueId() throws Exception {
471         String keystoreAlias = "test_key";
472         KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(keystoreAlias, PURPOSE_SIGN)
473                 .setAlgorithmParameterSpec(new ECGenParameterSpec("secp256r1"))
474                 .setDigests(DIGEST_NONE, DIGEST_SHA256, DIGEST_SHA512)
475                 .setAttestationChallenge(new byte[128])
476                 .setUniqueIdIncluded(true)
477                 .build();
478 
479         try {
480             generateKeyPair(KEY_ALGORITHM_EC, spec);
481             fail("Attestation should have failed.");
482         } catch (ProviderException e) {
483             // Attestation is expected to fail because of lack of permissions.
484             KeyStoreException cause = (KeyStoreException) e.getCause();
485             assertEquals(KM_ERROR_PERMISSION_DENIED, cause.getErrorCode());
486             // Assert public failure information.
487             assertEquals(KeyStoreException.ERROR_PERMISSION_DENIED, cause.getNumericErrorCode());
488             assertFalse(cause.isTransientFailure());
489         } finally {
490             KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
491             keyStore.load(null);
492             keyStore.deleteEntry(keystoreAlias);
493         }
494     }
495 
496     @Test
testEcAttestation_UniqueIdWorksWithCorrectPermission()497     public void testEcAttestation_UniqueIdWorksWithCorrectPermission() throws Exception {
498         assumeTrue("Device doesn't have secure lock screen",
499                 TestUtils.hasSecureLockScreen(getContext()));
500 
501         String keystoreAlias = "test_key";
502         KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(keystoreAlias, PURPOSE_SIGN)
503                 .setAlgorithmParameterSpec(new ECGenParameterSpec("secp256r1"))
504                 .setDigests(DIGEST_NONE, DIGEST_SHA256, DIGEST_SHA512)
505                 .setAttestationChallenge(new byte[128])
506                 .setUniqueIdIncluded(true)
507                 .build();
508 
509         KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
510         keyStore.load(null);
511 
512         try (PermissionContext c = TestApis.permissions().withPermission(
513                   "android.permission.REQUEST_UNIQUE_ID_ATTESTATION")) {
514             generateKeyPair(KEY_ALGORITHM_EC, spec);
515             Certificate certificates[] = keyStore.getCertificateChain(keystoreAlias);
516             Attestation attestation = Attestation.loadFromCertificate((X509Certificate) certificates[0]);
517             byte[] firstUniqueId = attestation.getUniqueId();
518             assertTrue("UniqueId must not be empty", firstUniqueId.length > 0);
519 
520             // The unique id rotates (30 days in the default implementation), and it's possible to
521             // get a spurious failure if the test runs exactly when the rotation occurs. Allow a
522             // single retry, just in case.
523             byte[] secondUniqueId = null;
524             for (int i = 0; i < 2; ++i) {
525                 keyStore.deleteEntry(keystoreAlias);
526 
527                 generateKeyPair(KEY_ALGORITHM_EC, spec);
528                 certificates = keyStore.getCertificateChain(keystoreAlias);
529                 attestation = Attestation.loadFromCertificate((X509Certificate) certificates[0]);
530                 secondUniqueId = attestation.getUniqueId();
531 
532                 if (Arrays.equals(firstUniqueId, secondUniqueId)) {
533                     break;
534                 } else {
535                     firstUniqueId = secondUniqueId;
536                     secondUniqueId = null;
537                 }
538             }
539             assertTrue("UniqueIds must be consistent",
540                     Arrays.equals(firstUniqueId, secondUniqueId));
541 
542         } finally {
543             keyStore.deleteEntry(keystoreAlias);
544         }
545     }
546 
547     @RequiresDevice
548     @Test
testRsaAttestation()549     public void testRsaAttestation() throws Exception {
550         if (!TestUtils.isAttestationSupported()) {
551             return;
552         }
553 
554         if (getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_PC))
555             return;
556 
557         int[] keySizes = { // Smallish sizes to keep test runtimes down.
558                 512, 768, 1024
559         };
560         byte[][] challenges = {
561                 new byte[0], // empty challenge
562                 "challenge".getBytes(), // short challenge
563                 new byte[128] // long challenge
564         };
565         int[] purposes = {
566                 PURPOSE_SIGN | PURPOSE_VERIFY,
567                 PURPOSE_ENCRYPT | PURPOSE_DECRYPT,
568         };
569         String[][] encryptionPaddingModes = {
570                 {
571                         ENCRYPTION_PADDING_NONE
572                 },
573                 {
574                         ENCRYPTION_PADDING_RSA_OAEP,
575                 },
576                 {
577                         ENCRYPTION_PADDING_RSA_PKCS1,
578                 },
579                 {
580                         ENCRYPTION_PADDING_RSA_OAEP,
581                         ENCRYPTION_PADDING_RSA_PKCS1,
582                 },
583         };
584         String[][] signaturePaddingModes = {
585                 {
586                         SIGNATURE_PADDING_RSA_PKCS1,
587                 },
588                 {
589                         SIGNATURE_PADDING_RSA_PSS,
590                 },
591                 {
592                         SIGNATURE_PADDING_RSA_PKCS1,
593                         SIGNATURE_PADDING_RSA_PSS,
594                 },
595         };
596         boolean[] devicePropertiesAttestationValues = {true, false};
597 
598         for (boolean devicePropertiesAttestation : devicePropertiesAttestationValues) {
599             for (int keySize : keySizes) {
600                 for (byte[] challenge : challenges) {
601                     for (int purpose : purposes) {
602                         if (isEncryptionPurpose(purpose)) {
603                             testRsaAttestations(keySize, challenge, purpose, encryptionPaddingModes,
604                                     devicePropertiesAttestation);
605                         } else {
606                             testRsaAttestations(keySize, challenge, purpose, signaturePaddingModes,
607                                     devicePropertiesAttestation);
608                         }
609                     }
610                 }
611             }
612         }
613     }
614 
615     @Test
testRsaAttestation_TooLargeChallenge()616     public void testRsaAttestation_TooLargeChallenge() throws Exception {
617         if (!TestUtils.isAttestationSupported()) {
618             return;
619         }
620 
621         boolean[] devicePropertiesAttestationValues = {true, false};
622         for (boolean devicePropertiesAttestation : devicePropertiesAttestationValues) {
623             try {
624                 testRsaAttestation(new byte[129], true /* includeValidityDates */, 512,
625                         PURPOSE_SIGN,
626                         null /* paddingModes; may be empty because we'll never test them */,
627                         devicePropertiesAttestation);
628                 fail("Attestation challenges larger than 128 bytes should be rejected");
629             } catch(ProviderException e){
630                 KeyStoreException cause = (KeyStoreException) e.getCause();
631                 assertTrue(KM_ERROR_INVALID_INPUT_LENGTH == cause.getErrorCode() ||
632                         (devicePropertiesAttestation
633                                 && KM_ERROR_CANNOT_ATTEST_IDS == cause.getErrorCode())
634                 );
635                 assertPublicAttestationError(cause, devicePropertiesAttestation);
636             }
637         }
638     }
639 
640     @Test
testRsaAttestation_NoChallenge()641     public void testRsaAttestation_NoChallenge() throws Exception {
642         boolean[] devicePropertiesAttestationValues = {true, false};
643         for (boolean devicePropertiesAttestation : devicePropertiesAttestationValues) {
644             String keystoreAlias = "test_key";
645             Date now = new Date();
646             Date originationEnd = new Date(now.getTime() + ORIGINATION_TIME_OFFSET);
647             Date consumptionEnd = new Date(now.getTime() + CONSUMPTION_TIME_OFFSET);
648             KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(keystoreAlias, PURPOSE_SIGN)
649                     .setDigests(DIGEST_NONE, DIGEST_SHA256, DIGEST_SHA512)
650                     .setAttestationChallenge(null)
651                     .setKeyValidityStart(now)
652                     .setKeyValidityForOriginationEnd(originationEnd)
653                     .setKeyValidityForConsumptionEnd(consumptionEnd)
654                     .setDevicePropertiesAttestationIncluded(devicePropertiesAttestation)
655                     .build();
656 
657             generateKeyPair(KEY_ALGORITHM_RSA, spec);
658 
659             KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
660             keyStore.load(null);
661 
662             try {
663                 Certificate certificates[] = keyStore.getCertificateChain(keystoreAlias);
664                 assertEquals(1, certificates.length);
665 
666                 X509Certificate attestationCert = (X509Certificate) certificates[0];
667                 assertNull(attestationCert.getExtensionValue(Attestation.ASN1_OID));
668             } finally {
669                 keyStore.deleteEntry(keystoreAlias);
670             }
671         }
672     }
673 
testRsaAttestation_DeviceLocked(Boolean expectStrongBox)674     private void testRsaAttestation_DeviceLocked(Boolean expectStrongBox) throws Exception {
675         if (!TestUtils.isAttestationSupported()) {
676             return;
677         }
678 
679         if (getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_PC))
680             return;
681 
682         String keystoreAlias = "test_key";
683         Date now = new Date();
684         Date originationEnd = new Date(now.getTime() + ORIGINATION_TIME_OFFSET);
685         Date consumptionEnd = new Date(now.getTime() + CONSUMPTION_TIME_OFFSET);
686         KeyGenParameterSpec.Builder builder =
687             new KeyGenParameterSpec.Builder(keystoreAlias, PURPOSE_SIGN)
688                     .setDigests(DIGEST_NONE, DIGEST_SHA256, DIGEST_SHA512)
689                     .setAttestationChallenge("challenge".getBytes())
690                     .setKeyValidityStart(now)
691                     .setKeyValidityForOriginationEnd(originationEnd)
692                     .setKeyValidityForConsumptionEnd(consumptionEnd)
693                     .setIsStrongBoxBacked(expectStrongBox);
694 
695         if (expectStrongBox) {
696             builder.setDigests(DIGEST_NONE, DIGEST_SHA256);
697         } else {
698             builder.setDigests(DIGEST_NONE, DIGEST_SHA256, DIGEST_SHA512);
699         }
700 
701         generateKeyPair(KEY_ALGORITHM_RSA, builder.build());
702 
703         KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
704         keyStore.load(null);
705 
706         try {
707             Certificate certificates[] = keyStore.getCertificateChain(keystoreAlias);
708             verifyCertificateChain(certificates, expectStrongBox);
709 
710             X509Certificate attestationCert = (X509Certificate) certificates[0];
711             checkDeviceLocked(Attestation.loadFromCertificate(attestationCert));
712         } finally {
713             keyStore.deleteEntry(keystoreAlias);
714         }
715     }
716 
717     @RestrictedBuildTest
718     @RequiresDevice  // Emulators have no place to store the needed key
719     @Test
testRsaAttestation_DeviceLocked()720     public void testRsaAttestation_DeviceLocked() throws Exception {
721         testRsaAttestation_DeviceLocked(false /* expectStrongbox */);
722     }
723 
724     @RestrictedBuildTest
725     @RequiresDevice  // Emulators have no place to store the needed key
726     @Test
testRsaAttestation_DeviceLockedStrongbox()727     public void testRsaAttestation_DeviceLockedStrongbox() throws Exception {
728         if (!TestUtils.hasStrongBox(getContext()))
729             return;
730 
731         testRsaAttestation_DeviceLocked(true /* expectStrongbox */);
732     }
733 
734     @Test
testAesAttestation()735     public void testAesAttestation() throws Exception {
736         boolean[] devicePropertiesAttestationValues = {true, false};
737         for (boolean devicePropertiesAttestation : devicePropertiesAttestationValues) {
738             String keystoreAlias = "test_key";
739             KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(keystoreAlias,
740                     PURPOSE_ENCRYPT)
741                     .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
742                     .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
743                     .setAttestationChallenge(new byte[0])
744                     .setDevicePropertiesAttestationIncluded(devicePropertiesAttestation)
745                     .build();
746             generateKey(spec, KeyProperties.KEY_ALGORITHM_AES);
747 
748             KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
749             keyStore.load(null);
750             try {
751                 assertNull(keyStore.getCertificateChain(keystoreAlias));
752             } finally {
753                 keyStore.deleteEntry(keystoreAlias);
754             }
755         }
756     }
757 
758     @Test
testHmacAttestation()759     public void testHmacAttestation() throws Exception {
760         boolean[] devicePropertiesAttestationValues = {true, false};
761         for (boolean devicePropertiesAttestation : devicePropertiesAttestationValues) {
762             String keystoreAlias = "test_key";
763             KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(keystoreAlias, PURPOSE_SIGN)
764                     .setDevicePropertiesAttestationIncluded(devicePropertiesAttestation)
765                     .build();
766 
767             generateKey(spec, KeyProperties.KEY_ALGORITHM_HMAC_SHA256);
768 
769             KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
770             keyStore.load(null);
771             try {
772                 assertNull(keyStore.getCertificateChain(keystoreAlias));
773             } finally {
774                 keyStore.deleteEntry(keystoreAlias);
775             }
776         }
777     }
778 
testRsaAttestations(int keySize, byte[] challenge, int purpose, String[][] paddingModes, boolean devicePropertiesAttestation)779     private void testRsaAttestations(int keySize, byte[] challenge, int purpose,
780             String[][] paddingModes, boolean devicePropertiesAttestation) throws Exception {
781         for (String[] paddings : paddingModes) {
782             try {
783                 testRsaAttestation(challenge, true /* includeValidityDates */, keySize, purpose,
784                         paddings, devicePropertiesAttestation);
785                 testRsaAttestation(challenge, false /* includeValidityDates */, keySize, purpose,
786                         paddings, devicePropertiesAttestation);
787             } catch (Throwable e) {
788                 boolean isIdAttestationFailure =
789                         (e.getCause() instanceof KeyStoreException)
790                                 && KeyStoreException.ERROR_ID_ATTESTATION_FAILURE
791                                 == ((KeyStoreException) e.getCause()).getNumericErrorCode();
792                 if (devicePropertiesAttestation && isIdAttestationFailure) {
793                     Log.i(TAG, "key attestation with device IDs not supported; test skipped");
794                     continue;
795                 }
796                 throw new Exception("Failed on key size " + keySize + " challenge [" +
797                         new String(challenge) + "], purposes " +
798                         buildPurposeSet(purpose) + " paddings " +
799                         ImmutableSet.copyOf(paddings) + " and devicePropertiesAttestation "
800                         + devicePropertiesAttestation,
801                         e);
802             }
803         }
804     }
805 
806     @Test
testDeviceIdAttestation()807     public void testDeviceIdAttestation() throws Exception {
808         testDeviceIdAttestationFailure(AttestationUtils.ID_TYPE_SERIAL, null);
809         testDeviceIdAttestationFailure(AttestationUtils.ID_TYPE_IMEI, "Unable to retrieve IMEI");
810         testDeviceIdAttestationFailure(AttestationUtils.ID_TYPE_MEID, "Unable to retrieve MEID");
811     }
812 
813     @SuppressWarnings("deprecation")
testRsaAttestation(byte[] challenge, boolean includeValidityDates, int keySize, int purposes, String[] paddingModes, boolean devicePropertiesAttestation)814     private void testRsaAttestation(byte[] challenge, boolean includeValidityDates, int keySize,
815             int purposes, String[] paddingModes, boolean devicePropertiesAttestation)
816             throws Exception {
817         Log.i(TAG, "RSA key attestation with: challenge " + Arrays.toString(challenge) +
818                 " / includeValidityDates " + includeValidityDates + " / keySize " + keySize +
819                 " / purposes " + purposes + " / paddingModes " + Arrays.toString(paddingModes) +
820                 " / devicePropertiesAttestation " + devicePropertiesAttestation);
821 
822         String keystoreAlias = "test_key";
823         Date startTime = new Date();
824         Date originationEnd = new Date(startTime.getTime() + ORIGINATION_TIME_OFFSET);
825         Date consumptionEnd = new Date(startTime.getTime() + CONSUMPTION_TIME_OFFSET);
826         KeyGenParameterSpec.Builder builder =
827             new KeyGenParameterSpec.Builder(keystoreAlias, purposes)
828                         .setKeySize(keySize)
829                         .setDigests(DIGEST_NONE, DIGEST_SHA256, DIGEST_SHA512)
830                         .setAttestationChallenge(challenge)
831                         .setDevicePropertiesAttestationIncluded(devicePropertiesAttestation);
832 
833         if (includeValidityDates) {
834             builder.setKeyValidityStart(startTime)
835                     .setKeyValidityForOriginationEnd(originationEnd)
836                     .setKeyValidityForConsumptionEnd(consumptionEnd);
837         }
838         if (isEncryptionPurpose(purposes)) {
839             builder.setEncryptionPaddings(paddingModes);
840             // Because we sometimes set "no padding", allow non-randomized encryption.
841             builder.setRandomizedEncryptionRequired(false);
842         }
843         if (isSignaturePurpose(purposes)) {
844             builder.setSignaturePaddings(paddingModes);
845         }
846 
847         generateKeyPair(KEY_ALGORITHM_RSA, builder.build());
848 
849         KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
850         keyStore.load(null);
851 
852         try {
853             Certificate certificates[] = keyStore.getCertificateChain(keystoreAlias);
854             verifyCertificateChain(certificates, false /* expectStrongBox */);
855 
856             X509Certificate attestationCert = (X509Certificate) certificates[0];
857             Attestation attestation = Attestation.loadFromCertificate(attestationCert);
858 
859             checkRsaKeyDetails(attestation, keySize, purposes,
860                 ImmutableSet.copyOf(paddingModes));
861             checkKeyUsage(attestationCert, purposes);
862             checkKeyIndependentAttestationInfo(challenge, purposes, startTime,
863                 includeValidityDates, devicePropertiesAttestation, attestation);
864         } finally {
865             keyStore.deleteEntry(keystoreAlias);
866         }
867     }
868 
checkKeyUsage(X509Certificate attestationCert, int purposes)869     private void checkKeyUsage(X509Certificate attestationCert, int purposes) {
870 
871         boolean[] expectedKeyUsage = new boolean[KEY_USAGE_BITSTRING_LENGTH];
872         if (isSignaturePurpose(purposes)) {
873             expectedKeyUsage[KEY_USAGE_DIGITAL_SIGNATURE_BIT_OFFSET] = true;
874         }
875         if (isEncryptionPurpose(purposes)) {
876             expectedKeyUsage[KEY_USAGE_KEY_ENCIPHERMENT_BIT_OFFSET] = true;
877             expectedKeyUsage[KEY_USAGE_DATA_ENCIPHERMENT_BIT_OFFSET] = true;
878         }
879         assertThat(attestationCert.getKeyUsage(), is(expectedKeyUsage));
880     }
881 
882     @SuppressWarnings("deprecation")
testEcAttestation(byte[] challenge, boolean includeValidityDates, String ecCurve, int keySize, int purposes, boolean devicePropertiesAttestation)883     private void testEcAttestation(byte[] challenge, boolean includeValidityDates, String ecCurve,
884             int keySize, int purposes, boolean devicePropertiesAttestation) throws Exception {
885         Log.i(TAG, "EC key attestation with: challenge " + Arrays.toString(challenge) +
886                 " / includeValidityDates " + includeValidityDates + " / ecCurve " + ecCurve +
887                 " / keySize " + keySize + " / purposes " + purposes +
888                 " / devicePropertiesAttestation " + devicePropertiesAttestation);
889 
890         String keystoreAlias = "test_key";
891         Date startTime = new Date();
892         Date originationEnd = new Date(startTime.getTime() + ORIGINATION_TIME_OFFSET);
893         Date consumptionEnd = new Date(startTime.getTime() + CONSUMPTION_TIME_OFFSET);
894         KeyGenParameterSpec.Builder builder = new KeyGenParameterSpec.Builder(keystoreAlias,
895                 purposes)
896                         .setAlgorithmParameterSpec(new ECGenParameterSpec(ecCurve))
897                         .setDigests(DIGEST_NONE, DIGEST_SHA256, DIGEST_SHA512)
898                         .setAttestationChallenge(challenge)
899                         .setDevicePropertiesAttestationIncluded(devicePropertiesAttestation);
900 
901         if (includeValidityDates) {
902             builder.setKeyValidityStart(startTime)
903                     .setKeyValidityForOriginationEnd(originationEnd)
904                     .setKeyValidityForConsumptionEnd(consumptionEnd);
905         }
906 
907         generateKeyPair(KEY_ALGORITHM_EC, builder.build());
908 
909         KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
910         keyStore.load(null);
911 
912         try {
913             Certificate certificates[] = keyStore.getCertificateChain(keystoreAlias);
914             verifyCertificateChain(certificates, false /* expectStrongBox */);
915 
916             X509Certificate attestationCert = (X509Certificate) certificates[0];
917             Attestation attestation = Attestation.loadFromCertificate(attestationCert);
918 
919             checkEcKeyDetails(attestation, ecCurve, keySize);
920             checkKeyUsage(attestationCert, purposes);
921             checkKeyIndependentAttestationInfo(challenge, purposes, startTime,
922                 includeValidityDates, devicePropertiesAttestation, attestation);
923         } finally {
924             keyStore.deleteEntry(keystoreAlias);
925         }
926     }
927 
checkAttestationApplicationId(Attestation attestation)928     private void checkAttestationApplicationId(Attestation attestation)
929             throws NoSuchAlgorithmException, NameNotFoundException {
930         AttestationApplicationId aaid = null;
931         int kmVersion = attestation.getKeymasterVersion();
932         assertNull(attestation.getTeeEnforced().getAttestationApplicationId());
933         aaid = attestation.getSoftwareEnforced().getAttestationApplicationId();
934 
935         if (kmVersion >= 3) {
936             // must be present and correct
937             assertNotNull(aaid);
938             assertEquals(new AttestationApplicationId(getContext()), aaid);
939         } else {
940             // may be present and
941             // must be correct if present
942             if (aaid != null) {
943                 assertEquals(new AttestationApplicationId(getContext()), aaid);
944             }
945         }
946     }
947 
checkAttestationDeviceProperties(boolean devicePropertiesAttestation, Attestation attestation)948     private void checkAttestationDeviceProperties(boolean devicePropertiesAttestation,
949             Attestation attestation) {
950         final AuthorizationList keyDetailsList;
951         final AuthorizationList nonKeyDetailsList;
952         if (attestation.getKeymasterSecurityLevel() == KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT) {
953             keyDetailsList = attestation.getTeeEnforced();
954             nonKeyDetailsList = attestation.getSoftwareEnforced();
955         } else {
956             keyDetailsList = attestation.getSoftwareEnforced();
957             nonKeyDetailsList = attestation.getTeeEnforced();
958         }
959 
960         if (devicePropertiesAttestation) {
961             assertEquals(Build.BRAND, keyDetailsList.getBrand());
962             assertEquals(Build.DEVICE, keyDetailsList.getDevice());
963             assertEquals(Build.PRODUCT, keyDetailsList.getProduct());
964             assertEquals(Build.MANUFACTURER, keyDetailsList.getManufacturer());
965             assertEquals(Build.MODEL, keyDetailsList.getModel());
966         } else {
967             assertNull(keyDetailsList.getBrand());
968             assertNull(keyDetailsList.getDevice());
969             assertNull(keyDetailsList.getProduct());
970             assertNull(keyDetailsList.getManufacturer());
971             assertNull(keyDetailsList.getModel());
972         }
973         assertNull(nonKeyDetailsList.getBrand());
974         assertNull(nonKeyDetailsList.getDevice());
975         assertNull(nonKeyDetailsList.getProduct());
976         assertNull(nonKeyDetailsList.getManufacturer());
977         assertNull(nonKeyDetailsList.getModel());
978     }
979 
checkAttestationNoUniqueIds(Attestation attestation)980     private void checkAttestationNoUniqueIds(Attestation attestation) {
981         assertNull(attestation.getTeeEnforced().getImei());
982         assertNull(attestation.getTeeEnforced().getMeid());
983         assertNull(attestation.getTeeEnforced().getSerialNumber());
984         assertNull(attestation.getSoftwareEnforced().getImei());
985         assertNull(attestation.getSoftwareEnforced().getMeid());
986         assertNull(attestation.getSoftwareEnforced().getSerialNumber());
987     }
988 
checkKeyIndependentAttestationInfo(byte[] challenge, int purposes, Date startTime, boolean includesValidityDates, boolean devicePropertiesAttestation, Attestation attestation)989     private void checkKeyIndependentAttestationInfo(byte[] challenge, int purposes, Date startTime,
990             boolean includesValidityDates, boolean devicePropertiesAttestation,
991             Attestation attestation) throws NoSuchAlgorithmException, NameNotFoundException {
992         checkUnexpectedOids(attestation);
993         checkAttestationSecurityLevelDependentParams(attestation);
994         assertNotNull(attestation.getAttestationChallenge());
995         assertThat(attestation.getAttestationChallenge(), is(challenge));
996         // In EAT, this is null if not filled in. In ASN.1, this is an array with length 0.
997         if (attestation.getUniqueId() != null) {
998             assertEquals(0, attestation.getUniqueId().length);
999         }
1000         checkPurposes(attestation, purposes);
1001         checkDigests(attestation,
1002                 ImmutableSet.of(KM_DIGEST_NONE, KM_DIGEST_SHA_2_256, KM_DIGEST_SHA_2_512));
1003         checkValidityPeriod(attestation, startTime, includesValidityDates);
1004         checkFlags(attestation);
1005         checkOrigin(attestation);
1006         checkAttestationApplicationId(attestation);
1007         checkAttestationDeviceProperties(devicePropertiesAttestation, attestation);
1008         checkAttestationNoUniqueIds(attestation);
1009     }
1010 
checkUnexpectedOids(Attestation attestation)1011     private void checkUnexpectedOids(Attestation attestation) {
1012         assertThat("Attestations must not contain any extra data",
1013                 attestation.getUnexpectedExtensionOids(), is(empty()));
1014     }
1015 
getSystemPatchLevel()1016     private int getSystemPatchLevel() {
1017         Matcher matcher = OS_PATCH_LEVEL_STRING_PATTERN.matcher(Build.VERSION.SECURITY_PATCH);
1018         assertTrue(matcher.matches());
1019         String year_string = matcher.group(OS_PATCH_LEVEL_YEAR_GROUP_NAME);
1020         String month_string = matcher.group(OS_PATCH_LEVEL_MONTH_GROUP_NAME);
1021         int patch_level = Integer.parseInt(year_string) * 100 + Integer.parseInt(month_string);
1022         return patch_level;
1023     }
1024 
getSystemOsVersion()1025     private int getSystemOsVersion() {
1026         return parseSystemOsVersion(Build.VERSION.RELEASE);
1027     }
1028 
parseSystemOsVersion(String versionString)1029     private int parseSystemOsVersion(String versionString) {
1030         Matcher matcher = OS_VERSION_STRING_PATTERN.matcher(versionString);
1031         if (!matcher.matches()) {
1032             return 0;
1033         }
1034 
1035         int version = 0;
1036         String major_string = matcher.group(OS_MAJOR_VERSION_MATCH_GROUP_NAME);
1037         String minor_string = matcher.group(OS_MINOR_VERSION_MATCH_GROUP_NAME);
1038         String subminor_string = matcher.group(OS_SUBMINOR_VERSION_MATCH_GROUP_NAME);
1039         if (major_string != null) {
1040             version += Integer.parseInt(major_string) * 10000;
1041         }
1042         if (minor_string != null) {
1043             version += Integer.parseInt(minor_string) * 100;
1044         }
1045         if (subminor_string != null) {
1046             version += Integer.parseInt(subminor_string);
1047         }
1048         return version;
1049     }
1050 
checkOrigin(Attestation attestation)1051     private void checkOrigin(Attestation attestation) {
1052         assertTrue("Origin must be defined",
1053                 attestation.getSoftwareEnforced().getOrigin() != null ||
1054                         attestation.getTeeEnforced().getOrigin() != null);
1055         if (attestation.getKeymasterVersion() != 0) {
1056             assertTrue("Origin may not be defined in both SW and TEE, except on keymaster0",
1057                     attestation.getSoftwareEnforced().getOrigin() == null ||
1058                             attestation.getTeeEnforced().getOrigin() == null);
1059         }
1060 
1061         if (attestation.getKeymasterSecurityLevel() == KM_SECURITY_LEVEL_SOFTWARE) {
1062             assertThat(attestation.getSoftwareEnforced().getOrigin(), is(KM_ORIGIN_GENERATED));
1063         } else if (attestation.getKeymasterVersion() == 0) {
1064             assertThat(attestation.getTeeEnforced().getOrigin(), is(KM_ORIGIN_UNKNOWN));
1065         } else {
1066             assertThat(attestation.getTeeEnforced().getOrigin(), is(KM_ORIGIN_GENERATED));
1067         }
1068     }
1069 
checkFlags(Attestation attestation)1070     private void checkFlags(Attestation attestation) {
1071         assertFalse("All applications was not requested",
1072                 attestation.getSoftwareEnforced().isAllApplications());
1073         assertFalse("All applications was not requested",
1074                 attestation.getTeeEnforced().isAllApplications());
1075         assertFalse("Allow while on body was not requested",
1076                 attestation.getSoftwareEnforced().isAllowWhileOnBody());
1077         assertFalse("Allow while on body was not requested",
1078                 attestation.getTeeEnforced().isAllowWhileOnBody());
1079         assertNull("Auth binding was not requiested",
1080                 attestation.getSoftwareEnforced().getUserAuthType());
1081         assertNull("Auth binding was not requiested",
1082                 attestation.getTeeEnforced().getUserAuthType());
1083         assertTrue("noAuthRequired must be true",
1084                 attestation.getSoftwareEnforced().isNoAuthRequired()
1085                         || attestation.getTeeEnforced().isNoAuthRequired());
1086         assertFalse("auth is either software or TEE",
1087                 attestation.getSoftwareEnforced().isNoAuthRequired()
1088                         && attestation.getTeeEnforced().isNoAuthRequired());
1089         assertFalse("Software cannot implement rollback resistance",
1090                 attestation.getSoftwareEnforced().isRollbackResistant());
1091     }
1092 
checkValidityPeriod(Attestation attestation, Date startTime, boolean includesValidityDates)1093     private void checkValidityPeriod(Attestation attestation, Date startTime,
1094             boolean includesValidityDates) {
1095         AuthorizationList validityPeriodList = attestation.getSoftwareEnforced();
1096         AuthorizationList nonValidityPeriodList = attestation.getTeeEnforced();
1097 
1098         // A bug in Android S leads Android S devices with KeyMint1 not to add a creationDateTime.
1099         boolean creationDateTimeBroken =
1100             Build.VERSION.SDK_INT == Build.VERSION_CODES.S &&
1101             attestation.getKeymasterVersion() == Attestation.KM_VERSION_KEYMINT_1;
1102 
1103         if (!creationDateTimeBroken) {
1104             assertNull(nonValidityPeriodList.getCreationDateTime());
1105 
1106             Date creationDateTime = validityPeriodList.getCreationDateTime();
1107 
1108             boolean requireCreationDateTime =
1109                 attestation.getKeymasterVersion() >= Attestation.KM_VERSION_KEYMINT_1;
1110 
1111             // b/232078430: skip time checks in Android T due to unfixed bug.
1112             boolean doTimeChecks = false;
1113 
1114             if (doTimeChecks && (requireCreationDateTime || creationDateTime != null)) {
1115                 assertNotNull(creationDateTime);
1116 
1117                 assertTrue("Test start time (" + startTime.getTime() + ") and key creation time (" +
1118                         creationDateTime.getTime() + ") should be close",
1119                         Math.abs(creationDateTime.getTime() - startTime.getTime()) <= 2000);
1120 
1121                 // Allow 1 second leeway in case of nearest-second rounding.
1122                 Date now = new Date();
1123                 assertTrue("Key creation time (" + creationDateTime.getTime() + ") must be now (" +
1124                         now.getTime() + ") or earlier.",
1125                         now.getTime() >= (creationDateTime.getTime() - 1000));
1126             }
1127         }
1128 
1129         if (includesValidityDates) {
1130             Date activeDateTime = validityPeriodList.getActiveDateTime();
1131             Date originationExpirationDateTime = validityPeriodList.getOriginationExpireDateTime();
1132             Date usageExpirationDateTime = validityPeriodList.getUsageExpireDateTime();
1133 
1134             assertNotNull(activeDateTime);
1135             assertNotNull(originationExpirationDateTime);
1136             assertNotNull(usageExpirationDateTime);
1137 
1138             assertNull(nonValidityPeriodList.getActiveDateTime());
1139             assertNull(nonValidityPeriodList.getOriginationExpireDateTime());
1140             assertNull(nonValidityPeriodList.getUsageExpireDateTime());
1141 
1142             assertThat(originationExpirationDateTime.getTime(),
1143                     is(startTime.getTime() + ORIGINATION_TIME_OFFSET));
1144             assertThat(usageExpirationDateTime.getTime(),
1145                     is(startTime.getTime() + CONSUMPTION_TIME_OFFSET));
1146         }
1147     }
1148 
checkDigests(Attestation attestation, Set<Integer> expectedDigests)1149     private void checkDigests(Attestation attestation, Set<Integer> expectedDigests) {
1150         Set<Integer> softwareEnforcedDigests = attestation.getSoftwareEnforced().getDigests();
1151         Set<Integer> teeEnforcedDigests = attestation.getTeeEnforced().getDigests();
1152 
1153         if (softwareEnforcedDigests == null) {
1154             softwareEnforcedDigests = ImmutableSet.of();
1155         }
1156         if (teeEnforcedDigests == null) {
1157             teeEnforcedDigests = ImmutableSet.of();
1158         }
1159 
1160         Set<Integer> allDigests = ImmutableSet.<Integer> builder()
1161                 .addAll(softwareEnforcedDigests)
1162                 .addAll(teeEnforcedDigests)
1163                 .build();
1164         Set<Integer> intersection = new ArraySet<>();
1165         intersection.addAll(softwareEnforcedDigests);
1166         intersection.retainAll(teeEnforcedDigests);
1167 
1168         assertThat(allDigests, is(expectedDigests));
1169         assertTrue("Digest sets must be disjoint", intersection.isEmpty());
1170 
1171         if (attestation.getKeymasterSecurityLevel() == KM_SECURITY_LEVEL_SOFTWARE
1172                 || attestation.getKeymasterVersion() == 0) {
1173             assertThat("Digests in software-enforced",
1174                     softwareEnforcedDigests, is(expectedDigests));
1175         } else {
1176             if (attestation.getKeymasterVersion() == 1) {
1177                 // KM1 implementations may not support SHA512 in the TEE
1178                 assertTrue(softwareEnforcedDigests.contains(KM_DIGEST_SHA_2_512)
1179                         || teeEnforcedDigests.contains(KM_DIGEST_SHA_2_512));
1180 
1181                 assertThat(teeEnforcedDigests, hasItems(KM_DIGEST_NONE, KM_DIGEST_SHA_2_256));
1182             } else {
1183                 assertThat(teeEnforcedDigests, is(expectedDigests));
1184             }
1185         }
1186     }
1187 
checkPurposes(Attestation attestation, int purposes)1188     private Set<Integer> checkPurposes(Attestation attestation, int purposes) {
1189         Set<Integer> expectedPurposes = buildPurposeSet(purposes);
1190         if (attestation.getKeymasterSecurityLevel() == KM_SECURITY_LEVEL_SOFTWARE
1191                 || attestation.getKeymasterVersion() == 0) {
1192             assertThat("Purposes in software-enforced should match expected set",
1193                     attestation.getSoftwareEnforced().getPurposes(), is(expectedPurposes));
1194             assertNull("Should be no purposes in TEE-enforced",
1195                     attestation.getTeeEnforced().getPurposes());
1196         } else {
1197             assertThat("Purposes in TEE-enforced should match expected set",
1198                     attestation.getTeeEnforced().getPurposes(), is(expectedPurposes));
1199             assertNull("No purposes in software-enforced",
1200                     attestation.getSoftwareEnforced().getPurposes());
1201         }
1202         return expectedPurposes;
1203     }
1204 
isGsiImage()1205     private boolean isGsiImage() {
1206         final File initGsiRc= new File("/system/system_ext/etc/init/init.gsi.rc");
1207         return initGsiRc.exists();
1208     }
1209 
checkSystemPatchLevel(int teeOsPatchLevel, int systemPatchLevel)1210     private void checkSystemPatchLevel(int teeOsPatchLevel, int systemPatchLevel) {
1211         if (isGsiImage()) {
1212             // b/168663786: When using a GSI image, the system patch level might be
1213             // greater than or equal to the OS patch level reported from TEE.
1214             assertThat(teeOsPatchLevel, lessThanOrEqualTo(systemPatchLevel));
1215         } else {
1216             assertThat(teeOsPatchLevel, is(systemPatchLevel));
1217         }
1218     }
1219 
1220     @SuppressWarnings("unchecked")
checkAttestationSecurityLevelDependentParams(Attestation attestation)1221     private void checkAttestationSecurityLevelDependentParams(Attestation attestation) {
1222         assertThat("Attestation version must be one of: {1, 2, 3, 4, 100, 200}",
1223                 attestation.getAttestationVersion(),
1224                 either(is(1)).or(is(2)).or(is(3)).or(is(4)).or(is(100)).or(is(200)));
1225 
1226         AuthorizationList teeEnforced = attestation.getTeeEnforced();
1227         AuthorizationList softwareEnforced = attestation.getSoftwareEnforced();
1228 
1229         int systemOsVersion = getSystemOsVersion();
1230         int systemPatchLevel = getSystemPatchLevel();
1231 
1232         switch (attestation.getAttestationSecurityLevel()) {
1233             case KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT:
1234                 assertThat("TEE attestation can only come from TEE keymaster",
1235                         attestation.getKeymasterSecurityLevel(),
1236                         is(KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT));
1237                 assertThat(attestation.getKeymasterVersion(),
1238                         either(is(2)).or(is(3)).or(is(4)).or(is(41)).or(is(100)).or(is(200)));
1239 
1240                 checkRootOfTrust(attestation, false /* requireLocked */);
1241                 assertThat(teeEnforced.getOsVersion(), is(systemOsVersion));
1242                 checkSystemPatchLevel(teeEnforced.getOsPatchLevel(), systemPatchLevel);
1243                 break;
1244 
1245             case KM_SECURITY_LEVEL_SOFTWARE:
1246                 if (attestation
1247                         .getKeymasterSecurityLevel() == KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT) {
1248                     assertThat("TEE KM version must be 0 or 1 with software attestation",
1249                             attestation.getKeymasterVersion(), either(is(0)).or(is(1)));
1250                 } else {
1251                     assertThat("Software KM is version 3", attestation.getKeymasterVersion(),
1252                             is(3));
1253                     assertThat(softwareEnforced.getOsVersion(), is(systemOsVersion));
1254                     checkSystemPatchLevel(softwareEnforced.getOsPatchLevel(), systemPatchLevel);
1255                 }
1256 
1257                 assertNull("Software attestation cannot provide root of trust",
1258                         teeEnforced.getRootOfTrust());
1259 
1260                 break;
1261 
1262             default:
1263                 fail("Invalid attestation security level: "
1264                         + attestation.getAttestationSecurityLevel());
1265                 break;
1266         }
1267     }
1268 
checkDeviceLocked(Attestation attestation)1269     private void checkDeviceLocked(Attestation attestation) {
1270         assertThat("Attestation version must be >= 1",
1271                 attestation.getAttestationVersion(), greaterThanOrEqualTo(1));
1272 
1273         int attestationSecurityLevel = attestation.getAttestationSecurityLevel();
1274         switch (attestationSecurityLevel) {
1275             case KM_SECURITY_LEVEL_STRONG_BOX:
1276             case KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT:
1277                 assertThat("Attestation security level doesn't match keymaster security level",
1278                         attestation.getKeymasterSecurityLevel(), is(attestationSecurityLevel));
1279                 assertThat(attestation.getKeymasterVersion(), greaterThanOrEqualTo(2));
1280 
1281                 // Devices launched in Android 10.0 (API level 29) and after should run CTS
1282                 // in LOCKED state.
1283                 boolean requireLocked = (
1284                         SystemProperties.getInt("ro.product.first_api_level", 0) >= 29);
1285                 checkRootOfTrust(attestation, requireLocked);
1286                 break;
1287 
1288             case KM_SECURITY_LEVEL_SOFTWARE:
1289             default:
1290                 // TEE attestation has been required since Android 7.0.
1291                 fail("Unexpected attestation security level: " +
1292                      attestation.securityLevelToString(attestationSecurityLevel));
1293                 break;
1294         }
1295     }
1296 
checkRootOfTrust(Attestation attestation, boolean requireLocked)1297     private void checkRootOfTrust(Attestation attestation, boolean requireLocked) {
1298         RootOfTrust rootOfTrust = attestation.getRootOfTrust();
1299         assertNotNull(rootOfTrust);
1300         assertNotNull(rootOfTrust.getVerifiedBootKey());
1301         assertTrue("Verified boot key is only " + rootOfTrust.getVerifiedBootKey().length +
1302                    " bytes long", rootOfTrust.getVerifiedBootKey().length >= 32);
1303         if (requireLocked) {
1304             final String unlockedDeviceMessage = "The device's bootloader must be locked. This may "
1305                     + "not be the default for pre-production devices.";
1306             assertTrue(unlockedDeviceMessage, rootOfTrust.isDeviceLocked());
1307             checkEntropy(rootOfTrust.getVerifiedBootKey());
1308             assertEquals(KM_VERIFIED_BOOT_VERIFIED, rootOfTrust.getVerifiedBootState());
1309         }
1310     }
1311 
checkEntropy(byte[] verifiedBootKey)1312     private void checkEntropy(byte[] verifiedBootKey) {
1313         assertTrue("Failed Shannon entropy check", checkShannonEntropy(verifiedBootKey));
1314         assertTrue("Failed BiEntropy check", checkTresBiEntropy(verifiedBootKey));
1315     }
1316 
checkShannonEntropy(byte[] verifiedBootKey)1317     private boolean checkShannonEntropy(byte[] verifiedBootKey) {
1318         double probabilityOfSetBit = countSetBits(verifiedBootKey) / (double)(verifiedBootKey.length * 8);
1319         return calculateShannonEntropy(probabilityOfSetBit) > 0.8;
1320     }
1321 
calculateShannonEntropy(double probabilityOfSetBit)1322     private double calculateShannonEntropy(double probabilityOfSetBit) {
1323         if (probabilityOfSetBit <= 0.001 || probabilityOfSetBit >= .999) return 0;
1324         double entropy = (-probabilityOfSetBit * logTwo(probabilityOfSetBit)) -
1325                             ((1 - probabilityOfSetBit) * logTwo(1 - probabilityOfSetBit));
1326         Log.i(TAG, "Shannon entropy of VB Key: " + entropy);
1327         return entropy;
1328     }
1329 
checkTresBiEntropy(byte[] verifiedBootKey)1330     private boolean checkTresBiEntropy(byte[] verifiedBootKey) {
1331         double weightingFactor = 0;
1332         double weightedEntropy = 0;
1333         double probabilityOfSetBit = 0;
1334         int length = verifiedBootKey.length * 8;
1335         for(int i = 0; i < (verifiedBootKey.length * 8) - 2; i++) {
1336             probabilityOfSetBit = countSetBits(verifiedBootKey) / (double)length;
1337             weightingFactor += logTwo(i+2);
1338             weightedEntropy += calculateShannonEntropy(probabilityOfSetBit) * logTwo(i+2);
1339             deriveBitString(verifiedBootKey, length);
1340             length -= 1;
1341         }
1342         double tresBiEntropy = (1 / weightingFactor) * weightedEntropy;
1343         Log.i(TAG, "BiEntropy of VB Key: " + tresBiEntropy);
1344         return tresBiEntropy > 0.9;
1345     }
1346 
deriveBitString(byte[] bitString, int activeLength)1347     private void deriveBitString(byte[] bitString, int activeLength) {
1348         int length = activeLength / 8;
1349         if (activeLength % 8 != 0) {
1350             length += 1;
1351         }
1352 
1353         byte mask = (byte)((byte)0x80 >>> ((activeLength + 6) % 8));
1354         if (activeLength % 8 == 1) {
1355             mask = (byte)~mask;
1356         }
1357 
1358         for(int i = 0; i < length; i++) {
1359             if (i == length - 1) {
1360                 bitString[i] ^= ((bitString[i] & 0xFF) << 1);
1361                 bitString[i] &= mask;
1362             } else {
1363                 bitString[i] ^= ((bitString[i] & 0xFF) << 1) | ((bitString[i+1] & 0xFF) >>> 7);
1364             }
1365         }
1366     }
1367 
logTwo(double value)1368     private double logTwo(double value) {
1369         return Math.log(value) / Math.log(2);
1370     }
1371 
countSetBits(byte[] toCount)1372     private int countSetBits(byte[] toCount) {
1373         int setBitCount = 0;
1374         for(int i = 0; i < toCount.length; i++) {
1375             setBitCount += countSetBits(toCount[i]);
1376         }
1377         return setBitCount;
1378     }
1379 
countSetBits(byte toCount)1380     private int countSetBits(byte toCount) {
1381         int setBitCounter = 0;
1382         while(toCount != 0) {
1383             toCount &= (toCount - 1);
1384             setBitCounter++;
1385         }
1386         return setBitCounter;
1387     }
1388 
checkRsaKeyDetails(Attestation attestation, int keySize, int purposes, Set<String> expectedPaddingModes)1389     private void checkRsaKeyDetails(Attestation attestation, int keySize, int purposes,
1390             Set<String> expectedPaddingModes) throws CertificateParsingException {
1391         AuthorizationList keyDetailsList;
1392         AuthorizationList nonKeyDetailsList;
1393         if (attestation.getKeymasterSecurityLevel() == KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT) {
1394             keyDetailsList = attestation.getTeeEnforced();
1395             nonKeyDetailsList = attestation.getSoftwareEnforced();
1396         } else {
1397             keyDetailsList = attestation.getSoftwareEnforced();
1398             nonKeyDetailsList = attestation.getTeeEnforced();
1399         }
1400         assertEquals(keySize, keyDetailsList.getKeySize().intValue());
1401         assertNull(nonKeyDetailsList.getKeySize());
1402 
1403         assertEquals(KM_ALGORITHM_RSA, keyDetailsList.getAlgorithm().intValue());
1404         assertNull(nonKeyDetailsList.getAlgorithm());
1405 
1406         assertNull(keyDetailsList.getEcCurve());
1407         assertNull(nonKeyDetailsList.getEcCurve());
1408 
1409         assertEquals(65537, keyDetailsList.getRsaPublicExponent().longValue());
1410         assertNull(nonKeyDetailsList.getRsaPublicExponent());
1411 
1412         Set<String> paddingModes;
1413         if (attestation.getKeymasterVersion() == 0) {
1414             // KM0 implementations don't support padding info, so it's always in the
1415             // software-enforced list.
1416             paddingModes = attestation.getSoftwareEnforced().getPaddingModesAsStrings();
1417             assertNull(attestation.getTeeEnforced().getPaddingModes());
1418         } else {
1419             paddingModes = keyDetailsList.getPaddingModesAsStrings();
1420             assertNull(nonKeyDetailsList.getPaddingModes());
1421         }
1422 
1423         // KM1 implementations may add ENCRYPTION_PADDING_NONE to the list of paddings.
1424         Set<String> km1PossiblePaddingModes = expectedPaddingModes;
1425         if (attestation.getKeymasterVersion() == 1 &&
1426                 attestation.getKeymasterSecurityLevel() == KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT) {
1427             ImmutableSet.Builder<String> builder = ImmutableSet.builder();
1428             builder.addAll(expectedPaddingModes);
1429             builder.add(ENCRYPTION_PADDING_NONE);
1430             km1PossiblePaddingModes = builder.build();
1431         }
1432 
1433         assertThat(paddingModes, either(is(expectedPaddingModes)).or(is(km1PossiblePaddingModes)));
1434     }
1435 
checkEcKeyDetails(Attestation attestation, String ecCurve, int keySize)1436     private void checkEcKeyDetails(Attestation attestation, String ecCurve, int keySize) {
1437         AuthorizationList keyDetailsList;
1438         AuthorizationList nonKeyDetailsList;
1439         if (attestation.getKeymasterSecurityLevel() == KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT) {
1440             keyDetailsList = attestation.getTeeEnforced();
1441             nonKeyDetailsList = attestation.getSoftwareEnforced();
1442         } else {
1443             keyDetailsList = attestation.getSoftwareEnforced();
1444             nonKeyDetailsList = attestation.getTeeEnforced();
1445         }
1446         assertEquals(keySize, keyDetailsList.getKeySize().intValue());
1447         assertNull(nonKeyDetailsList.getKeySize());
1448         assertEquals(KM_ALGORITHM_EC, keyDetailsList.getAlgorithm().intValue());
1449         assertNull(nonKeyDetailsList.getAlgorithm());
1450         assertEquals(ecCurve, keyDetailsList.ecCurveAsString());
1451         assertNull(nonKeyDetailsList.getEcCurve());
1452         assertNull(keyDetailsList.getRsaPublicExponent());
1453         assertNull(nonKeyDetailsList.getRsaPublicExponent());
1454         assertNull(keyDetailsList.getPaddingModes());
1455         assertNull(nonKeyDetailsList.getPaddingModes());
1456     }
1457 
isEncryptionPurpose(int purposes)1458     private boolean isEncryptionPurpose(int purposes) {
1459         return (purposes & PURPOSE_DECRYPT) != 0 || (purposes & PURPOSE_ENCRYPT) != 0;
1460     }
1461 
isSignaturePurpose(int purposes)1462     private boolean isSignaturePurpose(int purposes) {
1463         return (purposes & PURPOSE_SIGN) != 0 || (purposes & PURPOSE_VERIFY) != 0;
1464     }
1465 
buildPurposeSet(int purposes)1466     private ImmutableSet<Integer> buildPurposeSet(int purposes) {
1467         ImmutableSet.Builder<Integer> builder = ImmutableSet.builder();
1468         if ((purposes & PURPOSE_SIGN) != 0)
1469             builder.add(KM_PURPOSE_SIGN);
1470         if ((purposes & PURPOSE_VERIFY) != 0)
1471             builder.add(KM_PURPOSE_VERIFY);
1472         if ((purposes & PURPOSE_ENCRYPT) != 0)
1473             builder.add(KM_PURPOSE_ENCRYPT);
1474         if ((purposes & PURPOSE_DECRYPT) != 0)
1475             builder.add(KM_PURPOSE_DECRYPT);
1476         return builder.build();
1477     }
1478 
generateKey(KeyGenParameterSpec spec, String algorithm)1479     private void generateKey(KeyGenParameterSpec spec, String algorithm)
1480             throws NoSuchAlgorithmException, NoSuchProviderException,
1481             InvalidAlgorithmParameterException {
1482         KeyGenerator keyGenerator = KeyGenerator.getInstance(algorithm, "AndroidKeyStore");
1483         keyGenerator.init(spec);
1484         keyGenerator.generateKey();
1485     }
1486 
generateKeyPair(String algorithm, KeyGenParameterSpec spec)1487     private void generateKeyPair(String algorithm, KeyGenParameterSpec spec)
1488             throws NoSuchAlgorithmException, NoSuchProviderException,
1489             InvalidAlgorithmParameterException {
1490         KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(algorithm,
1491                 "AndroidKeyStore");
1492         keyPairGenerator.initialize(spec);
1493         keyPairGenerator.generateKeyPair();
1494     }
1495 
verifyCertificateChain(Certificate[] certChain, boolean expectStrongBox)1496     public static void verifyCertificateChain(Certificate[] certChain, boolean expectStrongBox)
1497             throws GeneralSecurityException {
1498         assertNotNull(certChain);
1499         boolean strongBoxSubjectFound = false;
1500         for (int i = 1; i < certChain.length; ++i) {
1501             try {
1502                 PublicKey pubKey = certChain[i].getPublicKey();
1503                 certChain[i - 1].verify(pubKey);
1504                 if (i == certChain.length - 1) {
1505                     // Last cert should be self-signed.
1506                     certChain[i].verify(pubKey);
1507                 }
1508 
1509                 // Check that issuer in the signed cert matches subject in the signing cert.
1510                 X509Certificate x509CurrCert = (X509Certificate) certChain[i];
1511                 X509Certificate x509PrevCert = (X509Certificate) certChain[i - 1];
1512                 X500Name signingCertSubject =
1513                         new JcaX509CertificateHolder(x509CurrCert).getSubject();
1514                 X500Name signedCertIssuer =
1515                         new JcaX509CertificateHolder(x509PrevCert).getIssuer();
1516                 // Use .toASN1Object().equals() rather than .equals() because .equals() is case
1517                 // insensitive, and we want to verify an exact match.
1518                 assertTrue(
1519                         signedCertIssuer.toASN1Object().equals(signingCertSubject.toASN1Object()));
1520 
1521                 X500Name signedCertSubject =
1522                         new JcaX509CertificateHolder(x509PrevCert).getSubject();
1523                 if (i == 1) {
1524                     // First cert should have subject "CN=Android Keystore Key".
1525                     assertEquals(signedCertSubject, new X500Name("CN=Android Keystore Key"));
1526                 } else if (signedCertSubject.toString().toLowerCase().contains("strongbox")) {
1527                     strongBoxSubjectFound = true;
1528                 }
1529             } catch (InvalidKeyException | CertificateException | NoSuchAlgorithmException
1530                     | NoSuchProviderException | SignatureException e) {
1531                 throw new GeneralSecurityException("Using StrongBox: " + expectStrongBox + "\n"
1532                                 + "Failed to verify certificate " + certChain[i - 1]
1533                                 + " with public key " + certChain[i].getPublicKey(),
1534                         e);
1535             }
1536         }
1537         // At least one intermediate in a StrongBox chain must have "strongbox" in the subject.
1538         assertEquals(expectStrongBox, strongBoxSubjectFound);
1539     }
1540 
testDeviceIdAttestationFailure(int idType, String acceptableDeviceIdAttestationFailureMessage)1541     private void testDeviceIdAttestationFailure(int idType,
1542             String acceptableDeviceIdAttestationFailureMessage) throws Exception {
1543         try {
1544             AttestationUtils.attestDeviceIds(getContext(), new int[] {idType}, "123".getBytes());
1545             fail("Attestation should have failed.");
1546         } catch (SecurityException e) {
1547             // Attestation is expected to fail. If the device has the device ID type we are trying
1548             // to attest, it should fail with a SecurityException as we do not hold
1549             // READ_PRIVILEGED_PHONE_STATE permission.
1550         } catch (DeviceIdAttestationException e) {
1551             // Attestation is expected to fail. If the device does not have the device ID type we
1552             // are trying to attest (e.g. no IMEI on devices without a radio), it should fail with
1553             // a corresponding DeviceIdAttestationException.
1554             if (acceptableDeviceIdAttestationFailureMessage == null ||
1555                     !acceptableDeviceIdAttestationFailureMessage.equals(e.getMessage())) {
1556                 throw e;
1557             }
1558         }
1559     }
1560 }
1561