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 com.google.common.base.Functions.forMap; 20 import static com.google.common.collect.Collections2.transform; 21 22 import com.google.common.base.Joiner; 23 import com.google.common.collect.ImmutableMap; 24 import com.google.common.collect.ImmutableSet; 25 import com.google.common.collect.Lists; 26 27 import android.security.keystore.KeyProperties; 28 import android.util.Log; 29 30 import com.android.org.bouncycastle.asn1.ASN1Encodable; 31 import com.android.org.bouncycastle.asn1.ASN1Primitive; 32 import com.android.org.bouncycastle.asn1.ASN1Sequence; 33 import com.android.org.bouncycastle.asn1.ASN1SequenceParser; 34 import com.android.org.bouncycastle.asn1.ASN1TaggedObject; 35 import com.android.org.bouncycastle.asn1.ASN1InputStream; 36 37 import java.io.IOException; 38 import java.security.cert.CertificateParsingException; 39 import java.text.DateFormat; 40 import java.util.Collection; 41 import java.util.Date; 42 import java.util.List; 43 import java.util.Set; 44 45 public class AuthorizationList { 46 // Algorithm values. 47 public static final int KM_ALGORITHM_RSA = 1; 48 public static final int KM_ALGORITHM_EC = 3; 49 50 // EC Curves 51 public static final int KM_EC_CURVE_P224 = 0; 52 public static final int KM_EC_CURVE_P256 = 1; 53 public static final int KM_EC_CURVE_P384 = 2; 54 public static final int KM_EC_CURVE_P521 = 3; 55 56 // Padding modes. 57 public static final int KM_PAD_NONE = 1; 58 public static final int KM_PAD_RSA_OAEP = 2; 59 public static final int KM_PAD_RSA_PSS = 3; 60 public static final int KM_PAD_RSA_PKCS1_1_5_ENCRYPT = 4; 61 public static final int KM_PAD_RSA_PKCS1_1_5_SIGN = 5; 62 63 // Digest modes. 64 public static final int KM_DIGEST_NONE = 0; 65 public static final int KM_DIGEST_MD5 = 1; 66 public static final int KM_DIGEST_SHA1 = 2; 67 public static final int KM_DIGEST_SHA_2_224 = 3; 68 public static final int KM_DIGEST_SHA_2_256 = 4; 69 public static final int KM_DIGEST_SHA_2_384 = 5; 70 public static final int KM_DIGEST_SHA_2_512 = 6; 71 72 // Key origins. 73 public static final int KM_ORIGIN_GENERATED = 0; 74 public static final int KM_ORIGIN_IMPORTED = 2; 75 public static final int KM_ORIGIN_UNKNOWN = 3; 76 77 // Operation Purposes. 78 public static final int KM_PURPOSE_ENCRYPT = 0; 79 public static final int KM_PURPOSE_DECRYPT = 1; 80 public static final int KM_PURPOSE_SIGN = 2; 81 public static final int KM_PURPOSE_VERIFY = 3; 82 83 // User authenticators. 84 public static final int HW_AUTH_PASSWORD = 1 << 0; 85 public static final int HW_AUTH_FINGERPRINT = 1 << 1; 86 87 // Keymaster tag classes 88 private static final int KM_ENUM = 1 << 28; 89 private static final int KM_ENUM_REP = 2 << 28; 90 private static final int KM_UINT = 3 << 28; 91 private static final int KM_ULONG = 5 << 28; 92 private static final int KM_DATE = 6 << 28; 93 private static final int KM_BOOL = 7 << 28; 94 private static final int KM_BYTES = 9 << 28; 95 96 // Tag class removal mask 97 private static final int KEYMASTER_TAG_TYPE_MASK = 0x0FFFFFFF; 98 99 // Keymaster tags 100 private static final int KM_TAG_PURPOSE = KM_ENUM_REP | 1; 101 private static final int KM_TAG_ALGORITHM = KM_ENUM | 2; 102 private static final int KM_TAG_KEY_SIZE = KM_UINT | 3; 103 private static final int KM_TAG_DIGEST = KM_ENUM_REP | 5; 104 private static final int KM_TAG_PADDING = KM_ENUM_REP | 6; 105 private static final int KM_TAG_EC_CURVE = KM_ENUM | 10; 106 private static final int KM_TAG_RSA_PUBLIC_EXPONENT = KM_ULONG | 200; 107 private static final int KM_TAG_ACTIVE_DATETIME = KM_DATE | 400; 108 private static final int KM_TAG_ORIGINATION_EXPIRE_DATETIME = KM_DATE | 401; 109 private static final int KM_TAG_USAGE_EXPIRE_DATETIME = KM_DATE | 402; 110 private static final int KM_TAG_NO_AUTH_REQUIRED = KM_BOOL | 503; 111 private static final int KM_TAG_USER_AUTH_TYPE = KM_ENUM | 504; 112 private static final int KM_TAG_ALLOW_WHILE_ON_BODY = KM_BOOL | 506; 113 private static final int KM_TAG_AUTH_TIMEOUT = KM_UINT | 505; 114 private static final int KM_TAG_ALL_APPLICATIONS = KM_BOOL | 600; 115 private static final int KM_TAG_APPLICATION_ID = KM_BYTES | 601; 116 private static final int KM_TAG_CREATION_DATETIME = KM_DATE | 701; 117 private static final int KM_TAG_ORIGIN = KM_ENUM | 702; 118 private static final int KM_TAG_ROLLBACK_RESISTANT = KM_BOOL | 703; 119 private static final int KM_TAG_ROOT_OF_TRUST = KM_BYTES | 704; 120 private static final int KM_TAG_OS_VERSION = KM_UINT | 705; 121 private static final int KM_TAG_OS_PATCHLEVEL = KM_UINT | 706; 122 private static final int KM_TAG_ATTESTATION_APPLICATION_ID = KM_BYTES | 709; 123 124 // Map for converting padding values to strings 125 private static final ImmutableMap<Integer, String> paddingMap = ImmutableMap 126 .<Integer, String> builder() 127 .put(KM_PAD_NONE, "NONE") 128 .put(KM_PAD_RSA_OAEP, "OAEP") 129 .put(KM_PAD_RSA_PSS, "PSS") 130 .put(KM_PAD_RSA_PKCS1_1_5_ENCRYPT, "PKCS1 ENCRYPT") 131 .put(KM_PAD_RSA_PKCS1_1_5_SIGN, "PKCS1 SIGN") 132 .build(); 133 134 // Map for converting digest values to strings 135 private static final ImmutableMap<Integer, String> digestMap = ImmutableMap 136 .<Integer, String> builder() 137 .put(KM_DIGEST_NONE, "NONE") 138 .put(KM_DIGEST_MD5, "MD5") 139 .put(KM_DIGEST_SHA1, "SHA1") 140 .put(KM_DIGEST_SHA_2_224, "SHA224") 141 .put(KM_DIGEST_SHA_2_256, "SHA256") 142 .put(KM_DIGEST_SHA_2_384, "SHA384") 143 .put(KM_DIGEST_SHA_2_512, "SHA512") 144 .build(); 145 146 // Map for converting purpose values to strings 147 private static final ImmutableMap<Integer, String> purposeMap = ImmutableMap 148 .<Integer, String> builder() 149 .put(KM_PURPOSE_DECRYPT, "DECRYPT") 150 .put(KM_PURPOSE_ENCRYPT, "ENCRYPT") 151 .put(KM_PURPOSE_SIGN, "SIGN") 152 .put(KM_PURPOSE_VERIFY, "VERIFY") 153 .build(); 154 155 private Set<Integer> purposes; 156 private Integer algorithm; 157 private Integer keySize; 158 private Set<Integer> digests; 159 private Set<Integer> paddingModes; 160 private Integer ecCurve; 161 private Long rsaPublicExponent; 162 private Date activeDateTime; 163 private Date originationExpireDateTime; 164 private Date usageExpireDateTime; 165 private boolean noAuthRequired; 166 private Integer userAuthType; 167 private Integer authTimeout; 168 private boolean allowWhileOnBody; 169 private boolean allApplications; 170 private byte[] applicationId; 171 private Date creationDateTime; 172 private Integer origin; 173 private boolean rollbackResistant; 174 private RootOfTrust rootOfTrust; 175 private Integer osVersion; 176 private Integer osPatchLevel; 177 private AttestationApplicationId attestationApplicationId; 178 AuthorizationList(ASN1Encodable sequence)179 public AuthorizationList(ASN1Encodable sequence) throws CertificateParsingException { 180 if (!(sequence instanceof ASN1Sequence)) { 181 throw new CertificateParsingException("Expected sequence for authorization list, found " 182 + sequence.getClass().getName()); 183 } 184 185 ASN1SequenceParser parser = ((ASN1Sequence) sequence).parser(); 186 ASN1TaggedObject entry = parseAsn1TaggedObject(parser); 187 for (; entry != null; entry = parseAsn1TaggedObject(parser)) { 188 int tag = entry.getTagNo(); 189 ASN1Primitive value = entry.getObject(); 190 Log.i("Attestation", "Parsing tag: [" + tag + "], value: [" + value + "]"); 191 switch (tag) { 192 default: 193 throw new CertificateParsingException("Unknown tag " + tag + " found"); 194 195 case KM_TAG_PURPOSE & KEYMASTER_TAG_TYPE_MASK: 196 purposes = Asn1Utils.getIntegersFromAsn1Set(value); 197 break; 198 case KM_TAG_ALGORITHM & KEYMASTER_TAG_TYPE_MASK: 199 algorithm = Asn1Utils.getIntegerFromAsn1(value); 200 break; 201 case KM_TAG_KEY_SIZE & KEYMASTER_TAG_TYPE_MASK: 202 keySize = Asn1Utils.getIntegerFromAsn1(value); 203 Log.i("Attestation", "Found KEY SIZE, value: " + keySize); 204 break; 205 case KM_TAG_DIGEST & KEYMASTER_TAG_TYPE_MASK: 206 digests = Asn1Utils.getIntegersFromAsn1Set(value); 207 break; 208 case KM_TAG_PADDING & KEYMASTER_TAG_TYPE_MASK: 209 paddingModes = Asn1Utils.getIntegersFromAsn1Set(value); 210 break; 211 case KM_TAG_RSA_PUBLIC_EXPONENT & KEYMASTER_TAG_TYPE_MASK: 212 rsaPublicExponent = Asn1Utils.getLongFromAsn1(value); 213 break; 214 case KM_TAG_NO_AUTH_REQUIRED & KEYMASTER_TAG_TYPE_MASK: 215 noAuthRequired = true; 216 break; 217 case KM_TAG_CREATION_DATETIME & KEYMASTER_TAG_TYPE_MASK: 218 creationDateTime = Asn1Utils.getDateFromAsn1(value); 219 break; 220 case KM_TAG_ORIGIN & KEYMASTER_TAG_TYPE_MASK: 221 origin = Asn1Utils.getIntegerFromAsn1(value); 222 break; 223 case KM_TAG_OS_VERSION & KEYMASTER_TAG_TYPE_MASK: 224 osVersion = Asn1Utils.getIntegerFromAsn1(value); 225 break; 226 case KM_TAG_OS_PATCHLEVEL & KEYMASTER_TAG_TYPE_MASK: 227 osPatchLevel = Asn1Utils.getIntegerFromAsn1(value); 228 break; 229 case KM_TAG_ACTIVE_DATETIME & KEYMASTER_TAG_TYPE_MASK: 230 activeDateTime = Asn1Utils.getDateFromAsn1(value); 231 break; 232 case KM_TAG_ORIGINATION_EXPIRE_DATETIME & KEYMASTER_TAG_TYPE_MASK: 233 originationExpireDateTime = Asn1Utils.getDateFromAsn1(value); 234 break; 235 case KM_TAG_USAGE_EXPIRE_DATETIME & KEYMASTER_TAG_TYPE_MASK: 236 usageExpireDateTime = Asn1Utils.getDateFromAsn1(value); 237 break; 238 case KM_TAG_APPLICATION_ID & KEYMASTER_TAG_TYPE_MASK: 239 applicationId = Asn1Utils.getByteArrayFromAsn1(value); 240 break; 241 case KM_TAG_ROLLBACK_RESISTANT & KEYMASTER_TAG_TYPE_MASK: 242 rollbackResistant = true; 243 break; 244 case KM_TAG_AUTH_TIMEOUT & KEYMASTER_TAG_TYPE_MASK: 245 authTimeout = Asn1Utils.getIntegerFromAsn1(value); 246 break; 247 case KM_TAG_ALLOW_WHILE_ON_BODY & KEYMASTER_TAG_TYPE_MASK: 248 allowWhileOnBody = true; 249 break; 250 case KM_TAG_EC_CURVE & KEYMASTER_TAG_TYPE_MASK: 251 ecCurve = Asn1Utils.getIntegerFromAsn1(value); 252 break; 253 case KM_TAG_USER_AUTH_TYPE & KEYMASTER_TAG_TYPE_MASK: 254 userAuthType = Asn1Utils.getIntegerFromAsn1(value); 255 break; 256 case KM_TAG_ROOT_OF_TRUST & KEYMASTER_TAG_TYPE_MASK: 257 rootOfTrust = new RootOfTrust(value); 258 break; 259 case KM_TAG_ATTESTATION_APPLICATION_ID & KEYMASTER_TAG_TYPE_MASK: 260 attestationApplicationId = new AttestationApplicationId(Asn1Utils 261 .getAsn1EncodableFromBytes(Asn1Utils.getByteArrayFromAsn1(value))); 262 break; 263 case KM_TAG_ALL_APPLICATIONS & KEYMASTER_TAG_TYPE_MASK: 264 allApplications = true; 265 break; 266 } 267 } 268 269 } 270 algorithmToString(int algorithm)271 public static String algorithmToString(int algorithm) { 272 switch (algorithm) { 273 case KM_ALGORITHM_RSA: 274 return "RSA"; 275 case KM_ALGORITHM_EC: 276 return "ECDSA"; 277 default: 278 return "Unknown"; 279 } 280 } 281 paddingModesToString(final Set<Integer> paddingModes)282 public static String paddingModesToString(final Set<Integer> paddingModes) { 283 return joinStrings(transform(paddingModes, forMap(paddingMap, "Unknown"))); 284 } 285 paddingModeToString(int paddingMode)286 public static String paddingModeToString(int paddingMode) { 287 return forMap(paddingMap, "Unknown").apply(paddingMode); 288 } 289 digestsToString(Set<Integer> digests)290 public static String digestsToString(Set<Integer> digests) { 291 return joinStrings(transform(digests, forMap(digestMap, "Unknown"))); 292 } 293 digestToString(int digest)294 public static String digestToString(int digest) { 295 return forMap(digestMap, "Unknown").apply(digest); 296 } 297 purposesToString(Set<Integer> purposes)298 public static String purposesToString(Set<Integer> purposes) { 299 return joinStrings(transform(purposes, forMap(purposeMap, "Unknown"))); 300 } 301 userAuthTypeToString(int userAuthType)302 public static String userAuthTypeToString(int userAuthType) { 303 List<String> types = Lists.newArrayList(); 304 if ((userAuthType & HW_AUTH_FINGERPRINT) != 0) 305 types.add("Fingerprint"); 306 if ((userAuthType & HW_AUTH_PASSWORD) != 0) 307 types.add("Password"); 308 return joinStrings(types); 309 } 310 originToString(int origin)311 public static String originToString(int origin) { 312 switch (origin) { 313 case KM_ORIGIN_GENERATED: 314 return "Generated"; 315 case KM_ORIGIN_IMPORTED: 316 return "Imported"; 317 case KM_ORIGIN_UNKNOWN: 318 return "Unknown (KM0)"; 319 default: 320 return "Unknown"; 321 } 322 } 323 joinStrings(Collection<String> collection)324 private static String joinStrings(Collection<String> collection) { 325 return new StringBuilder() 326 .append("[") 327 .append(Joiner.on(", ").join(collection)) 328 .append("]") 329 .toString(); 330 } 331 formatDate(Date date)332 private static String formatDate(Date date) { 333 return DateFormat.getDateTimeInstance().format(date); 334 } 335 parseAsn1TaggedObject(ASN1SequenceParser parser)336 private static ASN1TaggedObject parseAsn1TaggedObject(ASN1SequenceParser parser) 337 throws CertificateParsingException { 338 ASN1Encodable asn1Encodable = parseAsn1Encodable(parser); 339 if (asn1Encodable == null || asn1Encodable instanceof ASN1TaggedObject) { 340 return (ASN1TaggedObject) asn1Encodable; 341 } 342 throw new CertificateParsingException( 343 "Expected tagged object, found " + asn1Encodable.getClass().getName()); 344 } 345 parseAsn1Encodable(ASN1SequenceParser parser)346 private static ASN1Encodable parseAsn1Encodable(ASN1SequenceParser parser) 347 throws CertificateParsingException { 348 try { 349 return parser.readObject(); 350 } catch (IOException e) { 351 throw new CertificateParsingException("Failed to parse ASN1 sequence", e); 352 } 353 } 354 getPurposes()355 public Set<Integer> getPurposes() { 356 return purposes; 357 } 358 getAlgorithm()359 public Integer getAlgorithm() { 360 return algorithm; 361 } 362 getKeySize()363 public Integer getKeySize() { 364 return keySize; 365 } 366 getDigests()367 public Set<Integer> getDigests() { 368 return digests; 369 } 370 getPaddingModes()371 public Set<Integer> getPaddingModes() { 372 return paddingModes; 373 } 374 getPaddingModesAsStrings()375 public Set<String> getPaddingModesAsStrings() throws CertificateParsingException { 376 if (paddingModes == null) { 377 return ImmutableSet.of(); 378 } 379 380 ImmutableSet.Builder<String> builder = ImmutableSet.builder(); 381 for (int paddingMode : paddingModes) { 382 switch (paddingMode) { 383 case KM_PAD_NONE: 384 builder.add(KeyProperties.ENCRYPTION_PADDING_NONE); 385 break; 386 case KM_PAD_RSA_OAEP: 387 builder.add(KeyProperties.ENCRYPTION_PADDING_RSA_OAEP); 388 break; 389 case KM_PAD_RSA_PKCS1_1_5_ENCRYPT: 390 builder.add(KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1); 391 break; 392 case KM_PAD_RSA_PKCS1_1_5_SIGN: 393 builder.add(KeyProperties.SIGNATURE_PADDING_RSA_PKCS1); 394 break; 395 case KM_PAD_RSA_PSS: 396 builder.add(KeyProperties.SIGNATURE_PADDING_RSA_PSS); 397 break; 398 default: 399 throw new CertificateParsingException("Invalid padding mode " + paddingMode); 400 } 401 } 402 return builder.build(); 403 } 404 getEcCurve()405 public Integer getEcCurve() { 406 return ecCurve; 407 } 408 ecCurveAsString()409 public String ecCurveAsString() { 410 if (ecCurve == null) 411 return "NULL"; 412 413 switch (ecCurve) { 414 case KM_EC_CURVE_P224: 415 return "secp224r1"; 416 case KM_EC_CURVE_P256: 417 return "secp256r1"; 418 case KM_EC_CURVE_P384: 419 return "secp384r1"; 420 case KM_EC_CURVE_P521: 421 return "secp521r1"; 422 default: 423 return "unknown"; 424 } 425 } 426 getRsaPublicExponent()427 public Long getRsaPublicExponent() { 428 return rsaPublicExponent; 429 } 430 getActiveDateTime()431 public Date getActiveDateTime() { 432 return activeDateTime; 433 } 434 getOriginationExpireDateTime()435 public Date getOriginationExpireDateTime() { 436 return originationExpireDateTime; 437 } 438 getUsageExpireDateTime()439 public Date getUsageExpireDateTime() { 440 return usageExpireDateTime; 441 } 442 isNoAuthRequired()443 public boolean isNoAuthRequired() { 444 return noAuthRequired; 445 } 446 getUserAuthType()447 public Integer getUserAuthType() { 448 return userAuthType; 449 } 450 getAuthTimeout()451 public Integer getAuthTimeout() { 452 return authTimeout; 453 } 454 isAllowWhileOnBody()455 public boolean isAllowWhileOnBody() { 456 return allowWhileOnBody; 457 } 458 isAllApplications()459 public boolean isAllApplications() { 460 return allApplications; 461 } 462 getApplicationId()463 public byte[] getApplicationId() { 464 return applicationId; 465 } 466 getCreationDateTime()467 public Date getCreationDateTime() { 468 return creationDateTime; 469 } 470 getOrigin()471 public Integer getOrigin() { 472 return origin; 473 } 474 isRollbackResistant()475 public boolean isRollbackResistant() { 476 return rollbackResistant; 477 } 478 getRootOfTrust()479 public RootOfTrust getRootOfTrust() { 480 return rootOfTrust; 481 } 482 getOsVersion()483 public Integer getOsVersion() { 484 return osVersion; 485 } 486 getOsPatchLevel()487 public Integer getOsPatchLevel() { 488 return osPatchLevel; 489 } 490 getAttestationApplicationId()491 public AttestationApplicationId getAttestationApplicationId() { 492 return attestationApplicationId; 493 } 494 495 @Override toString()496 public String toString() { 497 StringBuilder s = new StringBuilder(); 498 499 if (algorithm != null) { 500 s.append("\nAlgorithm: ").append(algorithmToString(algorithm)); 501 } 502 503 if (keySize != null) { 504 s.append("\nKeySize: ").append(keySize); 505 } 506 507 if (purposes != null && !purposes.isEmpty()) { 508 s.append("\nPurposes: ").append(purposesToString(purposes)); 509 } 510 511 if (digests != null && !digests.isEmpty()) { 512 s.append("\nDigests: ").append(digestsToString(digests)); 513 } 514 515 if (paddingModes != null && !paddingModes.isEmpty()) { 516 s.append("\nPadding modes: ").append(paddingModesToString(paddingModes)); 517 } 518 519 if (ecCurve != null) { 520 s.append("\nEC Curve: ").append(ecCurveAsString()); 521 } 522 523 String label = "\nRSA exponent: "; 524 if (rsaPublicExponent != null) { 525 s.append(label).append(rsaPublicExponent); 526 } 527 528 if (activeDateTime != null) { 529 s.append("\nActive: ").append(formatDate(activeDateTime)); 530 } 531 532 if (originationExpireDateTime != null) { 533 s.append("\nOrigination expire: ").append(formatDate(originationExpireDateTime)); 534 } 535 536 if (usageExpireDateTime != null) { 537 s.append("\nUsage expire: ").append(formatDate(usageExpireDateTime)); 538 } 539 540 if (!noAuthRequired && userAuthType != null) { 541 s.append("\nAuth types: ").append(userAuthTypeToString(userAuthType)); 542 if (authTimeout != null) { 543 s.append("\nAuth timeout: ").append(authTimeout); 544 } 545 } 546 547 if (applicationId != null) { 548 s.append("\nApplication ID: ").append(new String(applicationId)); 549 } 550 551 if (creationDateTime != null) { 552 s.append("\nCreated: ").append(formatDate(creationDateTime)); 553 } 554 555 if (origin != null) { 556 s.append("\nOrigin: ").append(originToString(origin)); 557 } 558 559 if (rollbackResistant) { 560 s.append("\nRollback resistant: true"); 561 } 562 563 if (rootOfTrust != null) { 564 s.append("\nRoot of Trust:\n"); 565 s.append(rootOfTrust); 566 } 567 568 if (osVersion != null) { 569 s.append("\nOS Version: ").append(osVersion); 570 } 571 572 if (osPatchLevel != null) { 573 s.append("\nOS Patchlevel: ").append(osPatchLevel); 574 } 575 576 if (attestationApplicationId != null) { 577 s.append("\nAttestation Application Id:").append(attestationApplicationId); 578 } 579 return s.toString(); 580 } 581 } 582