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