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