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