1 /*
2  * Copyright (C) 2022 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 com.android.server.security;
18 
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 
22 import com.android.framework.protobuf.ByteString;
23 import com.android.internal.org.bouncycastle.asn1.ASN1Boolean;
24 import com.android.internal.org.bouncycastle.asn1.ASN1Encodable;
25 import com.android.internal.org.bouncycastle.asn1.ASN1Enumerated;
26 import com.android.internal.org.bouncycastle.asn1.ASN1InputStream;
27 import com.android.internal.org.bouncycastle.asn1.ASN1Integer;
28 import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
29 import com.android.internal.org.bouncycastle.asn1.ASN1OctetString;
30 import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
31 import com.android.internal.org.bouncycastle.asn1.ASN1Set;
32 import com.android.internal.org.bouncycastle.asn1.ASN1TaggedObject;
33 import com.android.internal.org.bouncycastle.asn1.x509.Certificate;
34 
35 import java.io.IOException;
36 import java.nio.charset.StandardCharsets;
37 import java.security.cert.CertificateEncodingException;
38 import java.security.cert.X509Certificate;
39 import java.util.ArrayList;
40 import java.util.Collections;
41 import java.util.HashMap;
42 import java.util.List;
43 import java.util.Map;
44 
45 /**
46  * Parsed {@link X509Certificate} attestation extension values for Android Keystore attestations.
47  *
48  * Pull fields out of the top-level sequence. A full description of this structure is at
49  * https://source.android.com/security/keystore/attestation.
50  *
51  * If a value is null or empty, then it was not set/found in the extension values.
52  *
53  */
54 class AndroidKeystoreAttestationVerificationAttributes {
55     // The OID for the extension Android Keymaster puts into device-generated certificates.
56     private static final String ANDROID_KEYMASTER_KEY_DESCRIPTION_EXTENSION_OID =
57             "1.3.6.1.4.1.11129.2.1.17";
58 
59     // ASN.1 sequence index values for the Android Keymaster extension.
60     private static final int ATTESTATION_VERSION_INDEX = 0;
61     private static final int ATTESTATION_SECURITY_LEVEL_INDEX = 1;
62     private static final int KEYMASTER_VERSION_INDEX = 2;
63     private static final int KEYMASTER_SECURITY_LEVEL_INDEX = 3;
64     private static final int ATTESTATION_CHALLENGE_INDEX = 4;
65     private static final int KEYMASTER_UNIQUE_ID_INDEX = 5;
66     private static final int SW_ENFORCED_INDEX = 6;
67     private static final int HW_ENFORCED_INDEX = 7;
68     private static final int VERIFIED_BOOT_KEY_INDEX = 0;
69     private static final int VERIFIED_BOOT_LOCKED_INDEX = 1;
70     private static final int VERIFIED_BOOT_STATE_INDEX = 2;
71     private static final int VERIFIED_BOOT_HASH_INDEX = 3;
72 
73     // ASN.1 sequence index values for the Android Keystore application id.
74     private static final int PACKAGE_INFO_SET_INDEX = 0;
75     private static final int PACKAGE_SIGNATURE_SET_INDEX = 1;
76     private static final int PACKAGE_INFO_NAME_INDEX = 0;
77     private static final int PACKAGE_INFO_VERSION_INDEX = 1;
78 
79     // See these AOSP files: hardware/libhardware/include/hardware/hw_auth_token.h
80     private static final int HW_AUTH_NONE = 0;
81 
82     // Some keymaster constants. See this AOSP file:
83     // hardware/libhardware/include/hardware/keymaster_defs.h
84     private static final int KM_TAG_NO_AUTH_REQUIRED = 503;
85     private static final int KM_TAG_UNLOCKED_DEVICE_REQUIRED = 509;
86     private static final int KM_TAG_ALL_APPLICATIONS = 600;
87     private static final int KM_TAG_ROOT_OF_TRUST = 704;
88     private static final int KM_TAG_OS_VERSION = 705;
89     private static final int KM_TAG_OS_PATCHLEVEL = 706;
90     private static final int KM_TAG_ATTESTATION_APPLICATION_ID = 709;
91     private static final int KM_TAG_ATTESTATION_ID_BRAND = 710;
92     private static final int KM_TAG_ATTESTATION_ID_DEVICE = 711;
93     private static final int KM_TAG_ATTESTATION_ID_PRODUCT = 712;
94     private static final int KM_TAG_VENDOR_PATCHLEVEL = 718;
95     private static final int KM_TAG_BOOT_PATCHLEVEL = 719;
96 
97     private static final int KM_SECURITY_LEVEL_SOFTWARE = 0;
98     private static final int KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT = 1;
99     private static final int KM_SECURITY_LEVEL_STRONG_BOX = 2;
100     private static final int KM_VERIFIED_BOOT_STATE_VERIFIED = 0;
101     private static final int KM_VERIFIED_BOOT_STATE_SELF_SIGNED = 1;
102     private static final int KM_VERIFIED_BOOT_STATE_UNVERIFIED = 2;
103     private static final int KM_VERIFIED_BOOT_STATE_FAILED = 3;
104 
105     private Integer mAttestationVersion = null;
106     private SecurityLevel mAttestationSecurityLevel = null;
107     private boolean mAttestationHardwareBacked = false;
108     private Integer mKeymasterVersion = null;
109     private SecurityLevel mKeymasterSecurityLevel = null;
110     private boolean mKeymasterHardwareBacked = false;
111     private ByteString mAttestationChallenge = null;
112     private ByteString mKeymasterUniqueId = null;
113     private String mDeviceBrand = null;
114     private String mDeviceName = null;
115     private String mDeviceProductName = null;
116     private boolean mKeyAllowedForAllApplications = false;
117     private Integer mKeyAuthenticatorType = null;
118     private Integer mKeyBootPatchLevel = null;
119     private Integer mKeyOsPatchLevel = null;
120     private Integer mKeyOsVersion = null;
121     private Integer mKeyVendorPatchLevel = null;
122     private Boolean mKeyRequiresUnlockedDevice = null;
123     private ByteString mVerifiedBootHash = null;
124     private ByteString mVerifiedBootKey = null;
125     private Boolean mVerifiedBootLocked = null;
126     private VerifiedBootState mVerifiedBootState = null;
127     private Map<String, Long> mApplicationPackageNameVersion = null;
128     private List<ByteString> mApplicationCertificateDigests = null;
129 
130     enum VerifiedBootState {
131         VERIFIED,
132         SELF_SIGNED,
133         UNVERIFIED,
134         FAILED
135     }
136 
137     enum SecurityLevel {
138         SOFTWARE,
139         TRUSTED_ENVIRONMENT,
140         STRONG_BOX
141     }
142 
143     /**
144      * Extracts attestation extension properties from {@link X509Certificate}
145      * and returns a {@link AndroidKeystoreAttestationVerificationAttributes} that encapsulates the
146      * properties.
147      */
148     @NonNull
fromCertificate( @onNull X509Certificate x509Certificate)149     static AndroidKeystoreAttestationVerificationAttributes fromCertificate(
150             @NonNull X509Certificate x509Certificate)
151             throws CertificateEncodingException, IOException {
152         return new AndroidKeystoreAttestationVerificationAttributes(x509Certificate);
153     }
154 
getAttestationVersion()155     int getAttestationVersion() {
156         return mAttestationVersion;
157     }
158 
159     @Nullable
getAttestationSecurityLevel()160     SecurityLevel getAttestationSecurityLevel() {
161         return mAttestationSecurityLevel;
162     }
163 
isAttestationHardwareBacked()164     boolean isAttestationHardwareBacked() {
165         return mAttestationHardwareBacked;
166     }
167 
getKeymasterVersion()168     int getKeymasterVersion() {
169         return mKeymasterVersion;
170     }
171 
172     @Nullable
getKeymasterSecurityLevel()173     SecurityLevel getKeymasterSecurityLevel() {
174         return mKeymasterSecurityLevel;
175     }
176 
isKeymasterHardwareBacked()177     boolean isKeymasterHardwareBacked() {
178         return mKeymasterHardwareBacked;
179     }
180 
181     @Nullable
getAttestationChallenge()182     ByteString getAttestationChallenge() {
183         return mAttestationChallenge;
184     }
185 
186     @Nullable
getKeymasterUniqueId()187     ByteString getKeymasterUniqueId() {
188         return mKeymasterUniqueId;
189     }
190 
191     @Nullable
getDeviceBrand()192     String getDeviceBrand() {
193         return mDeviceBrand;
194     }
195 
196     @Nullable
getDeviceName()197     String getDeviceName() {
198         return mDeviceName;
199     }
200 
201     @Nullable
getDeviceProductName()202     String getDeviceProductName() {
203         return mDeviceProductName;
204     }
205 
isKeyAllowedForAllApplications()206     boolean isKeyAllowedForAllApplications() {
207         return mKeyAllowedForAllApplications;
208     }
209 
getKeyAuthenticatorType()210     int getKeyAuthenticatorType() {
211         if (mKeyAuthenticatorType == null) {
212             throw new IllegalStateException("KeyAuthenticatorType is not set.");
213         }
214         return mKeyAuthenticatorType;
215     }
216 
getKeyBootPatchLevel()217     int getKeyBootPatchLevel() {
218         if (mKeyBootPatchLevel == null) {
219             throw new IllegalStateException("KeyBootPatchLevel is not set.");
220         }
221         return mKeyBootPatchLevel;
222     }
223 
getKeyOsPatchLevel()224     int getKeyOsPatchLevel() {
225         if (mKeyOsPatchLevel == null) {
226             throw new IllegalStateException("KeyOsPatchLevel is not set.");
227         }
228         return mKeyOsPatchLevel;
229     }
230 
getKeyVendorPatchLevel()231     int getKeyVendorPatchLevel() {
232         if (mKeyVendorPatchLevel == null) {
233             throw new IllegalStateException("KeyVendorPatchLevel is not set.");
234         }
235         return mKeyVendorPatchLevel;
236     }
237 
getKeyOsVersion()238     int getKeyOsVersion() {
239         if (mKeyOsVersion == null) {
240             throw new IllegalStateException("KeyOsVersion is not set.");
241         }
242         return mKeyOsVersion;
243     }
244 
isKeyRequiresUnlockedDevice()245     boolean isKeyRequiresUnlockedDevice() {
246         if (mKeyRequiresUnlockedDevice == null) {
247             throw new IllegalStateException("KeyRequiresUnlockedDevice is not set.");
248         }
249         return mKeyRequiresUnlockedDevice;
250     }
251 
252     @Nullable
getVerifiedBootHash()253     ByteString getVerifiedBootHash() {
254         return mVerifiedBootHash;
255     }
256 
257     @Nullable
getVerifiedBootKey()258     ByteString getVerifiedBootKey() {
259         return mVerifiedBootKey;
260     }
261 
isVerifiedBootLocked()262     boolean isVerifiedBootLocked() {
263         if (mVerifiedBootLocked == null) {
264             throw new IllegalStateException("VerifiedBootLocked is not set.");
265         }
266         return mVerifiedBootLocked;
267     }
268 
269     @Nullable
getVerifiedBootState()270     VerifiedBootState getVerifiedBootState() {
271         return mVerifiedBootState;
272     }
273 
274     @Nullable
getApplicationPackageNameVersion()275     Map<String, Long> getApplicationPackageNameVersion() {
276         return Collections.unmodifiableMap(mApplicationPackageNameVersion);
277     }
278 
279     @Nullable
getApplicationCertificateDigests()280     List<ByteString> getApplicationCertificateDigests() {
281         return Collections.unmodifiableList(mApplicationCertificateDigests);
282     }
283 
AndroidKeystoreAttestationVerificationAttributes(X509Certificate x509Certificate)284     private AndroidKeystoreAttestationVerificationAttributes(X509Certificate x509Certificate)
285             throws CertificateEncodingException, IOException {
286         Certificate certificate = Certificate.getInstance(
287                 new ASN1InputStream(x509Certificate.getEncoded()).readObject());
288         ASN1Sequence keyAttributes = (ASN1Sequence) certificate.getTBSCertificate().getExtensions()
289                 .getExtensionParsedValue(
290                         new ASN1ObjectIdentifier(ANDROID_KEYMASTER_KEY_DESCRIPTION_EXTENSION_OID));
291         if (keyAttributes == null) {
292             throw new CertificateEncodingException(
293                     "No attestation extension found in certificate.");
294         }
295         this.mAttestationVersion = getIntegerFromAsn1(
296                 keyAttributes.getObjectAt(ATTESTATION_VERSION_INDEX));
297         this.mAttestationSecurityLevel = getSecurityLevelEnum(
298                 keyAttributes.getObjectAt(ATTESTATION_SECURITY_LEVEL_INDEX));
299         this.mAttestationHardwareBacked =
300                 this.mAttestationSecurityLevel == SecurityLevel.TRUSTED_ENVIRONMENT;
301         this.mAttestationChallenge = getOctetsFromAsn1(
302                 keyAttributes.getObjectAt(ATTESTATION_CHALLENGE_INDEX));
303         this.mKeymasterVersion = getIntegerFromAsn1(
304                 keyAttributes.getObjectAt(KEYMASTER_VERSION_INDEX));
305         this.mKeymasterUniqueId = getOctetsFromAsn1(
306                 keyAttributes.getObjectAt(KEYMASTER_UNIQUE_ID_INDEX));
307         this.mKeymasterSecurityLevel = getSecurityLevelEnum(
308                 keyAttributes.getObjectAt(KEYMASTER_SECURITY_LEVEL_INDEX));
309         this.mKeymasterHardwareBacked =
310                 this.mKeymasterSecurityLevel == SecurityLevel.TRUSTED_ENVIRONMENT;
311 
312         ASN1Encodable[] softwareEnforced = ((ASN1Sequence)
313                 keyAttributes.getObjectAt(SW_ENFORCED_INDEX)).toArray();
314         for (ASN1Encodable entry : softwareEnforced) {
315             ASN1TaggedObject taggedEntry = (ASN1TaggedObject) entry;
316             switch (taggedEntry.getTagNo()) {
317                 case KM_TAG_ATTESTATION_APPLICATION_ID:
318                     parseAttestationApplicationId(
319                             getOctetsFromAsn1(taggedEntry.getObject()).toByteArray());
320                     break;
321                 case KM_TAG_UNLOCKED_DEVICE_REQUIRED:
322                     this.mKeyRequiresUnlockedDevice = getBoolFromAsn1(taggedEntry.getObject());
323                     break;
324                 default:
325                     break;
326             }
327         }
328 
329         ASN1Encodable[] hardwareEnforced = ((ASN1Sequence)
330                 keyAttributes.getObjectAt(HW_ENFORCED_INDEX)).toArray();
331         for (ASN1Encodable entry : hardwareEnforced) {
332             ASN1TaggedObject taggedEntry = (ASN1TaggedObject) entry;
333             switch (taggedEntry.getTagNo()) {
334                 case KM_TAG_NO_AUTH_REQUIRED:
335                     this.mKeyAuthenticatorType = HW_AUTH_NONE;
336                     break;
337                 case KM_TAG_ALL_APPLICATIONS:
338                     this.mKeyAllowedForAllApplications = true;
339                     break;
340                 case KM_TAG_ROOT_OF_TRUST:
341                     ASN1Sequence rootOfTrust = (ASN1Sequence) taggedEntry.getObject();
342                     this.mVerifiedBootKey =
343                             getOctetsFromAsn1(rootOfTrust.getObjectAt(VERIFIED_BOOT_KEY_INDEX));
344                     this.mVerifiedBootLocked =
345                             getBoolFromAsn1(rootOfTrust.getObjectAt(VERIFIED_BOOT_LOCKED_INDEX));
346                     this.mVerifiedBootState =
347                             getVerifiedBootStateEnum(
348                                     rootOfTrust.getObjectAt(VERIFIED_BOOT_STATE_INDEX));
349                     // The verified boot hash was added in structure version 3 (Keymaster 4.0).
350                     if (mAttestationVersion >= 3) {
351                         this.mVerifiedBootHash =
352                                 getOctetsFromAsn1(
353                                         rootOfTrust.getObjectAt(VERIFIED_BOOT_HASH_INDEX));
354                     }
355                     break;
356                 case KM_TAG_OS_VERSION:
357                     this.mKeyOsVersion = getIntegerFromAsn1(taggedEntry.getObject());
358                     break;
359                 case KM_TAG_OS_PATCHLEVEL:
360                     this.mKeyOsPatchLevel = getIntegerFromAsn1(taggedEntry.getObject());
361                     break;
362                 case KM_TAG_ATTESTATION_ID_BRAND:
363                     this.mDeviceBrand = getUtf8FromOctetsFromAsn1(taggedEntry.getObject());
364                     break;
365                 case KM_TAG_ATTESTATION_ID_DEVICE:
366                     this.mDeviceName = getUtf8FromOctetsFromAsn1(taggedEntry.getObject());
367                     break;
368                 case KM_TAG_ATTESTATION_ID_PRODUCT:
369                     this.mDeviceProductName = getUtf8FromOctetsFromAsn1(taggedEntry.getObject());
370                     break;
371                 case KM_TAG_VENDOR_PATCHLEVEL:
372                     this.mKeyVendorPatchLevel = getIntegerFromAsn1(taggedEntry.getObject());
373                     break;
374                 case KM_TAG_BOOT_PATCHLEVEL:
375                     this.mKeyBootPatchLevel = getIntegerFromAsn1(taggedEntry.getObject());
376                     break;
377                 default:
378                     break;
379             }
380         }
381     }
382 
parseAttestationApplicationId(byte [] attestationApplicationId)383     private void parseAttestationApplicationId(byte [] attestationApplicationId)
384             throws IOException {
385         ASN1Sequence outerSequence = ASN1Sequence.getInstance(
386                 new ASN1InputStream(attestationApplicationId).readObject());
387         Map<String, Long> packageNameVersion = new HashMap<>();
388         ASN1Set packageInfoSet = (ASN1Set) outerSequence.getObjectAt(PACKAGE_INFO_SET_INDEX);
389         for (ASN1Encodable packageInfoEntry : packageInfoSet.toArray()) {
390             ASN1Sequence packageInfoSequence = (ASN1Sequence) packageInfoEntry;
391             packageNameVersion.put(
392                     getUtf8FromOctetsFromAsn1(
393                             packageInfoSequence.getObjectAt(PACKAGE_INFO_NAME_INDEX)),
394                     getLongFromAsn1(packageInfoSequence.getObjectAt(PACKAGE_INFO_VERSION_INDEX)));
395         }
396         List<ByteString> certificateDigests = new ArrayList<>();
397         ASN1Set certificateDigestSet =
398                 (ASN1Set) outerSequence.getObjectAt(PACKAGE_SIGNATURE_SET_INDEX);
399         for (ASN1Encodable certificateDigestEntry : certificateDigestSet.toArray()) {
400             certificateDigests.add(getOctetsFromAsn1(certificateDigestEntry));
401         }
402         this.mApplicationPackageNameVersion = Collections.unmodifiableMap(packageNameVersion);
403         this.mApplicationCertificateDigests = Collections.unmodifiableList(certificateDigests);
404 
405     }
406 
getVerifiedBootStateEnum(ASN1Encodable asn1)407     private VerifiedBootState getVerifiedBootStateEnum(ASN1Encodable asn1) {
408         int verifiedBoot = getEnumFromAsn1(asn1);
409         switch (verifiedBoot) {
410             case KM_VERIFIED_BOOT_STATE_VERIFIED:
411                 return VerifiedBootState.VERIFIED;
412             case KM_VERIFIED_BOOT_STATE_SELF_SIGNED:
413                 return VerifiedBootState.SELF_SIGNED;
414             case KM_VERIFIED_BOOT_STATE_UNVERIFIED:
415                 return VerifiedBootState.UNVERIFIED;
416             case KM_VERIFIED_BOOT_STATE_FAILED:
417                 return VerifiedBootState.FAILED;
418             default:
419                 throw new IllegalArgumentException("Invalid verified boot state.");
420         }
421     }
422 
getSecurityLevelEnum(ASN1Encodable asn1)423     private SecurityLevel getSecurityLevelEnum(ASN1Encodable asn1) {
424         int securityLevel = getEnumFromAsn1(asn1);
425         switch (securityLevel) {
426             case KM_SECURITY_LEVEL_SOFTWARE:
427                 return SecurityLevel.SOFTWARE;
428             case KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT:
429                 return SecurityLevel.TRUSTED_ENVIRONMENT;
430             case KM_SECURITY_LEVEL_STRONG_BOX:
431                 return SecurityLevel.STRONG_BOX;
432             default:
433                 throw new IllegalArgumentException("Invalid security level.");
434         }
435     }
436 
437     @NonNull
getOctetsFromAsn1(ASN1Encodable asn1)438     private ByteString getOctetsFromAsn1(ASN1Encodable asn1) {
439         return ByteString.copyFrom(((ASN1OctetString) asn1).getOctets());
440     }
441 
442     @NonNull
getUtf8FromOctetsFromAsn1(ASN1Encodable asn1)443     private String getUtf8FromOctetsFromAsn1(ASN1Encodable asn1) {
444         return new String(((ASN1OctetString) asn1).getOctets(), StandardCharsets.UTF_8);
445     }
446 
447     @NonNull
getIntegerFromAsn1(ASN1Encodable asn1)448     private int getIntegerFromAsn1(ASN1Encodable asn1) {
449         return ((ASN1Integer) asn1).getValue().intValueExact();
450     }
451 
452     @NonNull
getLongFromAsn1(ASN1Encodable asn1)453     private long getLongFromAsn1(ASN1Encodable asn1) {
454         return ((ASN1Integer) asn1).getValue().longValueExact();
455     }
456 
457     @NonNull
getEnumFromAsn1(ASN1Encodable asn1)458     private int getEnumFromAsn1(ASN1Encodable asn1) {
459         return ((ASN1Enumerated) asn1).getValue().intValueExact();
460     }
461 
462     @Nullable
getBoolFromAsn1(ASN1Encodable asn1)463     private Boolean getBoolFromAsn1(ASN1Encodable asn1) {
464         if (asn1 instanceof ASN1Boolean) {
465             return ((ASN1Boolean) asn1).isTrue();
466         }
467         return null;
468     }
469 }
470