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