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 com.google.common.io.BaseEncoding; 20 21 import org.bouncycastle.asn1.ASN1Encodable; 22 import org.bouncycastle.asn1.ASN1Sequence; 23 24 import java.security.cert.CertificateParsingException; 25 26 public class RootOfTrust { 27 private static final int VERIFIED_BOOT_KEY_INDEX = 0; 28 private static final int DEVICE_LOCKED_INDEX = 1; 29 private static final int VERIFIED_BOOT_STATE_INDEX = 2; 30 private static final int VERIFIED_BOOT_HASH_INDEX = 3; 31 32 public static final int KM_VERIFIED_BOOT_VERIFIED = 0; 33 public static final int KM_VERIFIED_BOOT_SELF_SIGNED = 1; 34 public static final int KM_VERIFIED_BOOT_UNVERIFIED = 2; 35 public static final int KM_VERIFIED_BOOT_FAILED = 3; 36 37 private final byte[] mVerifiedBootKey; 38 private final boolean mDeviceLocked; 39 private final int mVerifiedBootState; 40 private final byte[] mVerifiedBootHash; 41 RootOfTrust(ASN1Encodable asn1Encodable, int attestationVersion)42 public RootOfTrust(ASN1Encodable asn1Encodable, int attestationVersion) throws CertificateParsingException { 43 this(asn1Encodable, attestationVersion, true); 44 } 45 RootOfTrust(ASN1Encodable asn1Encodable, int attestationVersion, boolean strictParsing)46 public RootOfTrust(ASN1Encodable asn1Encodable, int attestationVersion, boolean strictParsing) 47 throws CertificateParsingException { 48 if (!(asn1Encodable instanceof ASN1Sequence)) { 49 throw new CertificateParsingException("Expected sequence for root of trust, found " 50 + asn1Encodable.getClass().getName()); 51 } 52 53 ASN1Sequence sequence = (ASN1Sequence) asn1Encodable; 54 mVerifiedBootKey = 55 Asn1Utils.getByteArrayFromAsn1(sequence.getObjectAt(VERIFIED_BOOT_KEY_INDEX)); 56 mDeviceLocked = Asn1Utils.getBooleanFromAsn1( 57 sequence.getObjectAt(DEVICE_LOCKED_INDEX), strictParsing); 58 mVerifiedBootState = 59 Asn1Utils.getIntegerFromAsn1(sequence.getObjectAt(VERIFIED_BOOT_STATE_INDEX)); 60 // Verified boot hash was presented after attestation version v3.0 61 if (attestationVersion >= 3) { 62 mVerifiedBootHash = 63 Asn1Utils.getByteArrayFromAsn1(sequence.getObjectAt(VERIFIED_BOOT_HASH_INDEX)); 64 } else { 65 mVerifiedBootHash = null; 66 } 67 } 68 RootOfTrust(byte[] verifiedBootKey, boolean deviceLocked, int verifiedBootState, byte[] verifiedBootHash)69 RootOfTrust(byte[] verifiedBootKey, boolean deviceLocked, int verifiedBootState, 70 byte[] verifiedBootHash) { 71 this.mVerifiedBootKey = verifiedBootKey; 72 this.mDeviceLocked = deviceLocked; 73 this.mVerifiedBootState = verifiedBootState; 74 this.mVerifiedBootHash = verifiedBootHash; 75 } 76 verifiedBootStateToString(int verifiedBootState)77 public static String verifiedBootStateToString(int verifiedBootState) { 78 switch (verifiedBootState) { 79 case KM_VERIFIED_BOOT_VERIFIED: 80 return "Verified"; 81 case KM_VERIFIED_BOOT_SELF_SIGNED: 82 return "Self-signed"; 83 case KM_VERIFIED_BOOT_UNVERIFIED: 84 return "Unverified"; 85 case KM_VERIFIED_BOOT_FAILED: 86 return "Failed"; 87 default: 88 return "Unknown"; 89 } 90 } 91 getVerifiedBootKey()92 public byte[] getVerifiedBootKey() { 93 return mVerifiedBootKey; 94 } 95 isDeviceLocked()96 public boolean isDeviceLocked() { 97 return mDeviceLocked; 98 } 99 getVerifiedBootState()100 public int getVerifiedBootState() { 101 return mVerifiedBootState; 102 } 103 getVerifiedBootHash()104 public byte[] getVerifiedBootHash() { 105 return mVerifiedBootHash; 106 } 107 108 @Override toString()109 public String toString() { 110 return new StringBuilder() 111 .append("\nVerified boot Key: ") 112 .append(mVerifiedBootKey != null 113 ? BaseEncoding.base64().encode(mVerifiedBootKey) 114 : "null") 115 .append("\nDevice locked: ") 116 .append(mDeviceLocked) 117 .append("\nVerified boot state: ") 118 .append(verifiedBootStateToString(mVerifiedBootState)) 119 .append("\nVerified boot hash: ") 120 .append(mVerifiedBootHash != null 121 ? BaseEncoding.base64().encode(mVerifiedBootHash) 122 : "null") 123 .toString(); 124 } 125 126 public static class Builder { 127 private byte[] mVerifiedBootKey; 128 private boolean mDeviceLocked = false; 129 private int mVerifiedBootState = -1; 130 private byte[] mVerifiedBootHash; 131 setVerifiedBootKey(byte[] verifiedBootKey)132 public Builder setVerifiedBootKey(byte[] verifiedBootKey) { 133 this.mVerifiedBootKey = verifiedBootKey; 134 return this; 135 } setDeviceLocked(boolean deviceLocked)136 public Builder setDeviceLocked(boolean deviceLocked) { 137 this.mDeviceLocked = deviceLocked; 138 return this; 139 } setVerifiedBootState(int verifiedBootState)140 public Builder setVerifiedBootState(int verifiedBootState) { 141 this.mVerifiedBootState = verifiedBootState; 142 return this; 143 } setVerifiedBootHash(byte[] verifiedBootHash)144 public Builder setVerifiedBootHash(byte[] verifiedBootHash) { 145 this.mVerifiedBootHash = verifiedBootHash; 146 return this; 147 } build()148 public RootOfTrust build() { 149 return new RootOfTrust(mVerifiedBootKey, mDeviceLocked, 150 mVerifiedBootState, mVerifiedBootHash); 151 } 152 } 153 } 154