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