• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.android.compatibility.common.util.PropertyUtil.getVsrApiLevel;
20 
21 import static com.google.common.base.Functions.forMap;
22 import static com.google.common.collect.Collections2.transform;
23 
24 import android.os.Build;
25 import static android.security.keymaster.KeymasterDefs.KM_PURPOSE_AGREE_KEY;
26 import static android.security.keymaster.KeymasterDefs.KM_PURPOSE_ENCRYPT;
27 import static android.security.keymaster.KeymasterDefs.KM_PURPOSE_DECRYPT;
28 import static android.security.keymaster.KeymasterDefs.KM_PURPOSE_SIGN;
29 import static android.security.keymaster.KeymasterDefs.KM_PURPOSE_VERIFY;
30 import android.security.keystore.KeyProperties;
31 import android.util.Log;
32 
33 import com.google.common.base.Joiner;
34 import com.google.common.collect.ImmutableMap;
35 import com.google.common.collect.ImmutableSet;
36 import com.google.common.collect.Lists;
37 
38 import org.bouncycastle.asn1.ASN1Encodable;
39 import org.bouncycastle.asn1.ASN1Primitive;
40 import org.bouncycastle.asn1.ASN1Sequence;
41 import org.bouncycastle.asn1.ASN1SequenceParser;
42 import org.bouncycastle.asn1.ASN1TaggedObject;
43 
44 import java.io.IOException;
45 import java.io.UnsupportedEncodingException;
46 import java.security.cert.CertificateParsingException;
47 import java.text.DateFormat;
48 import java.util.Collection;
49 import java.util.Date;
50 import java.util.HexFormat;
51 import java.util.List;
52 import java.util.Set;
53 
54 import co.nstant.in.cbor.model.DataItem;
55 import co.nstant.in.cbor.model.Number;
56 
57 public class AuthorizationList {
58     // Algorithm values.
59     public static final int KM_ALGORITHM_RSA = 1;
60     public static final int KM_ALGORITHM_EC = 3;
61 
62     // EC Curves
63     public static final int KM_EC_CURVE_P224 = 0;
64     public static final int KM_EC_CURVE_P256 = 1;
65     public static final int KM_EC_CURVE_P384 = 2;
66     public static final int KM_EC_CURVE_P521 = 3;
67     public static final int KM_EC_CURVE_25519 = 4;
68 
69     // Padding modes.
70     public static final int KM_PAD_NONE = 1;
71     public static final int KM_PAD_RSA_OAEP = 2;
72     public static final int KM_PAD_RSA_PSS = 3;
73     public static final int KM_PAD_RSA_PKCS1_1_5_ENCRYPT = 4;
74     public static final int KM_PAD_RSA_PKCS1_1_5_SIGN = 5;
75 
76     // Digest modes.
77     public static final int KM_DIGEST_NONE = 0;
78     public static final int KM_DIGEST_MD5 = 1;
79     public static final int KM_DIGEST_SHA1 = 2;
80     public static final int KM_DIGEST_SHA_2_224 = 3;
81     public static final int KM_DIGEST_SHA_2_256 = 4;
82     public static final int KM_DIGEST_SHA_2_384 = 5;
83     public static final int KM_DIGEST_SHA_2_512 = 6;
84 
85     // Key origins.
86     public static final int KM_ORIGIN_GENERATED = 0;
87     public static final int KM_ORIGIN_IMPORTED = 2;
88     public static final int KM_ORIGIN_UNKNOWN = 3;
89 
90     // User authenticators.
91     public static final int HW_AUTH_PASSWORD = 1 << 0;
92     public static final int HW_AUTH_FINGERPRINT = 1 << 1;
93 
94     // Keymaster tag classes
95     private static final int KM_ENUM = 1 << 28;
96     private static final int KM_ENUM_REP = 2 << 28;
97     private static final int KM_UINT = 3 << 28;
98     private static final int KM_ULONG = 5 << 28;
99     private static final int KM_DATE = 6 << 28;
100     private static final int KM_BOOL = 7 << 28;
101     private static final int KM_BYTES = 9 << 28;
102 
103     // Tag class removal mask
104     private static final int KEYMASTER_TAG_TYPE_MASK = 0x0FFFFFFF;
105 
106     // Keymaster tags
107     private static final int KM_TAG_PURPOSE = KM_ENUM_REP | 1;
108     private static final int KM_TAG_ALGORITHM = KM_ENUM | 2;
109     private static final int KM_TAG_KEY_SIZE = KM_UINT | 3;
110     private static final int KM_TAG_DIGEST = KM_ENUM_REP | 5;
111     private static final int KM_TAG_PADDING = KM_ENUM_REP | 6;
112     private static final int KM_TAG_EC_CURVE = KM_ENUM | 10;
113     private static final int KM_TAG_RSA_PUBLIC_EXPONENT = KM_ULONG | 200;
114     private static final int KM_TAG_RSA_OAEP_MGF_DIGEST = KM_ENUM | 203;
115     private static final int KM_TAG_ROLLBACK_RESISTANCE = KM_BOOL | 303;
116     private static final int KM_TAG_ACTIVE_DATETIME = KM_DATE | 400;
117     private static final int KM_TAG_ORIGINATION_EXPIRE_DATETIME = KM_DATE | 401;
118     private static final int KM_TAG_USAGE_EXPIRE_DATETIME = KM_DATE | 402;
119     private static final int KM_TAG_NO_AUTH_REQUIRED = KM_BOOL | 503;
120     private static final int KM_TAG_USER_AUTH_TYPE = KM_ENUM | 504;
121     private static final int KM_TAG_AUTH_TIMEOUT = KM_UINT | 505;
122     private static final int KM_TAG_ALLOW_WHILE_ON_BODY = KM_BOOL | 506;
123     private static final int KM_TAG_TRUSTED_USER_PRESENCE_REQUIRED = KM_BOOL | 507;
124     private static final int KM_TAG_TRUSTED_CONFIRMATION_REQUIRED = KM_BOOL | 508;
125     private static final int KM_TAG_UNLOCKED_DEVICE_REQUIRED = KM_BOOL | 509;
126     private static final int KM_TAG_ALL_APPLICATIONS = KM_BOOL | 600;
127     private static final int KM_TAG_CREATION_DATETIME = KM_DATE | 701;
128     private static final int KM_TAG_ORIGIN = KM_ENUM | 702;
129     private static final int KM_TAG_ROLLBACK_RESISTANT = KM_BOOL | 703;
130     private static final int KM_TAG_ROOT_OF_TRUST = KM_BYTES | 704;
131     private static final int KM_TAG_OS_VERSION = KM_UINT | 705;
132     private static final int KM_TAG_OS_PATCHLEVEL = KM_UINT | 706;
133     private static final int KM_TAG_ATTESTATION_APPLICATION_ID = KM_BYTES | 709;
134     private static final int KM_TAG_ATTESTATION_ID_BRAND = KM_BYTES | 710;
135     private static final int KM_TAG_ATTESTATION_ID_DEVICE = KM_BYTES | 711;
136     private static final int KM_TAG_ATTESTATION_ID_PRODUCT = KM_BYTES | 712;
137     private static final int KM_TAG_ATTESTATION_ID_SERIAL = KM_BYTES | 713;
138     private static final int KM_TAG_ATTESTATION_ID_IMEI = KM_BYTES | 714;
139     private static final int KM_TAG_ATTESTATION_ID_MEID = KM_BYTES | 715;
140     private static final int KM_TAG_ATTESTATION_ID_MANUFACTURER = KM_BYTES | 716;
141     private static final int KM_TAG_ATTESTATION_ID_MODEL = KM_BYTES | 717;
142     private static final int KM_TAG_VENDOR_PATCHLEVEL = KM_UINT | 718;
143     private static final int KM_TAG_BOOT_PATCHLEVEL = KM_UINT | 719;
144     private static final int KM_TAG_ATTESTATION_ID_SECOND_IMEI = KM_BYTES | 723;
145     private static final int KM_TAG_MODULE_HASH = KM_BYTES | 724;
146 
147     // Map for converting padding values to strings
148     private static final ImmutableMap<Integer, String> paddingMap = ImmutableMap
149             .<Integer, String> builder()
150             .put(KM_PAD_NONE, "NONE")
151             .put(KM_PAD_RSA_OAEP, "OAEP")
152             .put(KM_PAD_RSA_PSS, "PSS")
153             .put(KM_PAD_RSA_PKCS1_1_5_ENCRYPT, "PKCS1 ENCRYPT")
154             .put(KM_PAD_RSA_PKCS1_1_5_SIGN, "PKCS1 SIGN")
155             .build();
156 
157     // Map for converting digest values to strings
158     private static final ImmutableMap<Integer, String> digestMap = ImmutableMap
159             .<Integer, String> builder()
160             .put(KM_DIGEST_NONE, "NONE")
161             .put(KM_DIGEST_MD5, "MD5")
162             .put(KM_DIGEST_SHA1, "SHA1")
163             .put(KM_DIGEST_SHA_2_224, "SHA224")
164             .put(KM_DIGEST_SHA_2_256, "SHA256")
165             .put(KM_DIGEST_SHA_2_384, "SHA384")
166             .put(KM_DIGEST_SHA_2_512, "SHA512")
167             .build();
168 
169     // Map for converting purpose values to strings
170     private static final ImmutableMap<Integer, String> purposeMap = ImmutableMap
171             .<Integer, String> builder()
172             .put(KM_PURPOSE_DECRYPT, "DECRYPT")
173             .put(KM_PURPOSE_ENCRYPT, "ENCRYPT")
174             .put(KM_PURPOSE_SIGN, "SIGN")
175             .put(KM_PURPOSE_VERIFY, "VERIFY")
176             .put(KM_PURPOSE_AGREE_KEY, "AGREE_KEY")
177             .build();
178 
179     private Integer securityLevel;
180     private Set<Integer> purposes;
181     private Integer algorithm;
182     private Integer keySize;
183     private Set<Integer> digests;
184     private Set<Integer> paddingModes;
185     private Integer ecCurve;
186     private Long rsaPublicExponent;
187     private Set<Integer> mRsaOaepMgfDigests;
188     private Date activeDateTime;
189     private Date originationExpireDateTime;
190     private Date usageExpireDateTime;
191     private boolean noAuthRequired;
192     private Integer userAuthType;
193     private Integer authTimeout;
194     private boolean allowWhileOnBody;
195     private boolean allApplications;
196     private byte[] applicationId;
197     private Date creationDateTime;
198     private Integer origin;
199     private boolean rollbackResistant;
200     private boolean rollbackResistance;
201     private RootOfTrust rootOfTrust;
202     private Integer osVersion;
203     private Integer osPatchLevel;
204     private Integer vendorPatchLevel;
205     private Integer bootPatchLevel;
206     private AttestationApplicationId attestationApplicationId;
207     private String brand;
208     private String device;
209     private String serialNumber;
210     private String imei;
211     private String meid;
212     private String product;
213     private String manufacturer;
214     private String model;
215     private boolean userPresenceRequired;
216     private boolean confirmationRequired;
217     private String mSecondImei;
218     private byte[] mModuleHash;
219 
AuthorizationList(ASN1Encodable sequence, int attestationVersion)220     public AuthorizationList(ASN1Encodable sequence, int attestationVersion) throws CertificateParsingException {
221         this(sequence, attestationVersion, true);
222     }
223 
AuthorizationList(ASN1Encodable sequence, int attestationVersion, boolean strictParsing)224     public AuthorizationList(ASN1Encodable sequence, int attestationVersion, boolean strictParsing) throws CertificateParsingException {
225         if (!(sequence instanceof ASN1Sequence)) {
226             throw new CertificateParsingException("Expected sequence for authorization list, found "
227                     + sequence.getClass().getName());
228         }
229 
230         ASN1SequenceParser parser = ((ASN1Sequence) sequence).parser();
231         ASN1TaggedObject entry = parseAsn1TaggedObject(parser);
232         int currentTag = 0, prevTag = 0;
233         for (; entry != null; entry = parseAsn1TaggedObject(parser)) {
234             prevTag = currentTag;
235             currentTag = entry.getTagNo();
236             // The ASN.1 schema for the `AuthorizationList` in the attestation extension requires
237             // that the fields appear in numerical order of their ASN.1 tag value / KeyMint Tag
238             // value.
239             //
240             // However, this was not previously checked for, so we can only be strict about
241             // requiring the correct ordering for later VSR devices.
242             if ((prevTag > currentTag)
243                     && (getVsrApiLevel() >= Build.VERSION_CODES.VANILLA_ICE_CREAM)) {
244                 throw new CertificateParsingException(
245                         "Incorrect order of tags in authorization list: " + currentTag);
246             }
247             ASN1Primitive value = entry.getObject();
248             Log.i("Attestation", "Parsing tag: [" + currentTag + "], value: [" + value + "]");
249             switch (currentTag) {
250                 default:
251                     throw new CertificateParsingException("Unknown tag " + currentTag + " found");
252 
253                 case KM_TAG_PURPOSE & KEYMASTER_TAG_TYPE_MASK:
254                     purposes = Asn1Utils.getIntegersFromAsn1Set(value);
255                     break;
256                 case KM_TAG_ALGORITHM & KEYMASTER_TAG_TYPE_MASK:
257                     algorithm = Asn1Utils.getIntegerFromAsn1(value);
258                     break;
259                 case KM_TAG_KEY_SIZE & KEYMASTER_TAG_TYPE_MASK:
260                     keySize = Asn1Utils.getIntegerFromAsn1(value);
261                     Log.i("Attestation", "Found KEY SIZE, value: " + keySize);
262                     break;
263                 case KM_TAG_DIGEST & KEYMASTER_TAG_TYPE_MASK:
264                     digests = Asn1Utils.getIntegersFromAsn1Set(value);
265                     break;
266                 case KM_TAG_PADDING & KEYMASTER_TAG_TYPE_MASK:
267                     paddingModes = Asn1Utils.getIntegersFromAsn1Set(value);
268                     break;
269                 case KM_TAG_RSA_PUBLIC_EXPONENT & KEYMASTER_TAG_TYPE_MASK:
270                     rsaPublicExponent = Asn1Utils.getLongFromAsn1(value);
271                     break;
272                 case KM_TAG_RSA_OAEP_MGF_DIGEST & KEYMASTER_TAG_TYPE_MASK:
273                     mRsaOaepMgfDigests = Asn1Utils.getIntegersFromAsn1Set(value);
274                     break;
275                 case KM_TAG_NO_AUTH_REQUIRED & KEYMASTER_TAG_TYPE_MASK:
276                     noAuthRequired = true;
277                     break;
278                 case KM_TAG_CREATION_DATETIME & KEYMASTER_TAG_TYPE_MASK:
279                     creationDateTime = Asn1Utils.getDateFromAsn1(value);
280                     break;
281                 case KM_TAG_ORIGIN & KEYMASTER_TAG_TYPE_MASK:
282                     origin = Asn1Utils.getIntegerFromAsn1(value);
283                     break;
284                 case KM_TAG_OS_VERSION & KEYMASTER_TAG_TYPE_MASK:
285                     osVersion = Asn1Utils.getIntegerFromAsn1(value);
286                     break;
287                 case KM_TAG_OS_PATCHLEVEL & KEYMASTER_TAG_TYPE_MASK:
288                     osPatchLevel = Asn1Utils.getIntegerFromAsn1(value);
289                     break;
290                 case KM_TAG_VENDOR_PATCHLEVEL & KEYMASTER_TAG_TYPE_MASK:
291                     vendorPatchLevel = Asn1Utils.getIntegerFromAsn1(value);
292                     break;
293                 case KM_TAG_BOOT_PATCHLEVEL & KEYMASTER_TAG_TYPE_MASK:
294                     bootPatchLevel = Asn1Utils.getIntegerFromAsn1(value);
295                     break;
296                 case KM_TAG_ACTIVE_DATETIME & KEYMASTER_TAG_TYPE_MASK:
297                     activeDateTime = Asn1Utils.getDateFromAsn1(value);
298                     break;
299                 case KM_TAG_ORIGINATION_EXPIRE_DATETIME & KEYMASTER_TAG_TYPE_MASK:
300                     originationExpireDateTime = Asn1Utils.getDateFromAsn1(value);
301                     break;
302                 case KM_TAG_USAGE_EXPIRE_DATETIME & KEYMASTER_TAG_TYPE_MASK:
303                     usageExpireDateTime = Asn1Utils.getDateFromAsn1(value);
304                     break;
305                 case KM_TAG_ROLLBACK_RESISTANT & KEYMASTER_TAG_TYPE_MASK:
306                     rollbackResistant = true;
307                     break;
308                 case KM_TAG_ROLLBACK_RESISTANCE & KEYMASTER_TAG_TYPE_MASK:
309                     rollbackResistance = true;
310                     break;
311                 case KM_TAG_AUTH_TIMEOUT & KEYMASTER_TAG_TYPE_MASK:
312                     authTimeout = Asn1Utils.getIntegerFromAsn1(value);
313                     break;
314                 case KM_TAG_ALLOW_WHILE_ON_BODY & KEYMASTER_TAG_TYPE_MASK:
315                     allowWhileOnBody = true;
316                     break;
317                 case KM_TAG_EC_CURVE & KEYMASTER_TAG_TYPE_MASK:
318                     ecCurve = Asn1Utils.getIntegerFromAsn1(value);
319                     break;
320                 case KM_TAG_USER_AUTH_TYPE & KEYMASTER_TAG_TYPE_MASK:
321                     userAuthType = Asn1Utils.getIntegerFromAsn1(value);
322                     break;
323                 case KM_TAG_ROOT_OF_TRUST & KEYMASTER_TAG_TYPE_MASK:
324                     rootOfTrust = new RootOfTrust(value, attestationVersion, strictParsing);
325                     break;
326                 case KM_TAG_ATTESTATION_APPLICATION_ID & KEYMASTER_TAG_TYPE_MASK:
327                     attestationApplicationId = new AttestationApplicationId(Asn1Utils
328                             .getAsn1EncodableFromBytes(Asn1Utils.getByteArrayFromAsn1(value)));
329                     break;
330                 case KM_TAG_ATTESTATION_ID_BRAND & KEYMASTER_TAG_TYPE_MASK:
331                     brand = getStringFromAsn1Value(value);
332                     break;
333                 case KM_TAG_ATTESTATION_ID_DEVICE & KEYMASTER_TAG_TYPE_MASK:
334                     device = getStringFromAsn1Value(value);
335                     break;
336                 case KM_TAG_ATTESTATION_ID_PRODUCT & KEYMASTER_TAG_TYPE_MASK:
337                     product = getStringFromAsn1Value(value);
338                     break;
339                 case KM_TAG_ATTESTATION_ID_SERIAL & KEYMASTER_TAG_TYPE_MASK:
340                     serialNumber = getStringFromAsn1Value(value);
341                     break;
342                 case KM_TAG_ATTESTATION_ID_IMEI & KEYMASTER_TAG_TYPE_MASK:
343                     imei = getStringFromAsn1Value(value);
344                     break;
345                 case KM_TAG_ATTESTATION_ID_MEID & KEYMASTER_TAG_TYPE_MASK:
346                     meid = getStringFromAsn1Value(value);
347                     break;
348                 case KM_TAG_ATTESTATION_ID_MANUFACTURER & KEYMASTER_TAG_TYPE_MASK:
349                     manufacturer = getStringFromAsn1Value(value);
350                     break;
351                 case KM_TAG_ATTESTATION_ID_MODEL & KEYMASTER_TAG_TYPE_MASK:
352                     model = getStringFromAsn1Value(value);
353                     break;
354                 case KM_TAG_ALL_APPLICATIONS & KEYMASTER_TAG_TYPE_MASK:
355                     allApplications = true;
356                     break;
357                 case KM_TAG_TRUSTED_USER_PRESENCE_REQUIRED & KEYMASTER_TAG_TYPE_MASK:
358                     userPresenceRequired = true;
359                     break;
360                 case KM_TAG_TRUSTED_CONFIRMATION_REQUIRED & KEYMASTER_TAG_TYPE_MASK:
361                     confirmationRequired = true;
362                     break;
363                 case KM_TAG_ATTESTATION_ID_SECOND_IMEI & KEYMASTER_TAG_TYPE_MASK:
364                     mSecondImei = getStringFromAsn1Value(value);
365                     break;
366                 case KM_TAG_MODULE_HASH & KEYMASTER_TAG_TYPE_MASK:
367                     mModuleHash = Asn1Utils.getByteArrayFromAsn1(value);
368                     break;
369             }
370         }
371 
372     }
373 
AuthorizationList(co.nstant.in.cbor.model.Map submodMap)374     public AuthorizationList(co.nstant.in.cbor.model.Map submodMap)
375             throws CertificateParsingException {
376         for (DataItem key : submodMap.getKeys()) {
377             int keyInt = ((Number) key).getValue().intValue();
378             switch (keyInt) {
379                 default:
380                     throw new CertificateParsingException("Unknown EAT tag: " + key);
381 
382                 case EatClaim.SECURITY_LEVEL:
383                     securityLevel = eatSecurityLevelToKeymasterSecurityLevel(
384                             CborUtils.getInt(submodMap, key));
385                     break;
386                 case EatClaim.PURPOSE:
387                     purposes = CborUtils.getIntSet(submodMap, key);
388                     break;
389                 case EatClaim.ALGORITHM:
390                     algorithm = CborUtils.getInt(submodMap, key);
391                     break;
392                 case EatClaim.KEY_SIZE:
393                     keySize = CborUtils.getInt(submodMap, key);
394                     Log.i("Attestation", "Found KEY SIZE, value: " + keySize);
395                     break;
396                 case EatClaim.DIGEST:
397                     digests = CborUtils.getIntSet(submodMap, key);
398                     break;
399                 case EatClaim.PADDING:
400                     paddingModes = CborUtils.getIntSet(submodMap, key);
401                     break;
402                 case EatClaim.RSA_PUBLIC_EXPONENT:
403                     rsaPublicExponent = CborUtils.getLong(submodMap, key);
404                     break;
405                 case EatClaim.RSA_OAEP_MGF_DIGEST:
406                     mRsaOaepMgfDigests = CborUtils.getIntSet(submodMap, key);
407                     break;
408                 case EatClaim.NO_AUTH_REQUIRED:
409                     noAuthRequired = true;
410                     break;
411                 case EatClaim.IAT:
412                     creationDateTime = CborUtils.getDate(submodMap, key);
413                     break;
414                 case EatClaim.ORIGIN:
415                     origin = CborUtils.getInt(submodMap, key);
416                     break;
417                 case EatClaim.OS_VERSION:
418                     osVersion = CborUtils.getInt(submodMap, key);
419                     break;
420                 case EatClaim.OS_PATCHLEVEL:
421                     osPatchLevel = CborUtils.getInt(submodMap, key);
422                     break;
423                 case EatClaim.VENDOR_PATCHLEVEL:
424                     vendorPatchLevel = CborUtils.getInt(submodMap, key);
425                     break;
426                 case EatClaim.BOOT_PATCHLEVEL:
427                     bootPatchLevel = CborUtils.getInt(submodMap, key);
428                     break;
429                 case EatClaim.ACTIVE_DATETIME:
430                     activeDateTime = CborUtils.getDate(submodMap, key);
431                     break;
432                 case EatClaim.ORIGINATION_EXPIRE_DATETIME:
433                     originationExpireDateTime = CborUtils.getDate(submodMap, key);
434                     break;
435                 case EatClaim.USAGE_EXPIRE_DATETIME:
436                     usageExpireDateTime = CborUtils.getDate(submodMap, key);
437                     break;
438                 case EatClaim.ROLLBACK_RESISTANT:
439                     rollbackResistant = true;
440                     break;
441                 case EatClaim.ROLLBACK_RESISTANCE:
442                     rollbackResistance = true;
443                     break;
444                 case EatClaim.AUTH_TIMEOUT:
445                     authTimeout = CborUtils.getInt(submodMap, key);
446                     break;
447                 case EatClaim.ALLOW_WHILE_ON_BODY:
448                     allowWhileOnBody = true;
449                     break;
450                 case EatClaim.EC_CURVE:
451                     ecCurve = CborUtils.getInt(submodMap, key);
452                     break;
453                 case EatClaim.USER_AUTH_TYPE:
454                     userAuthType = CborUtils.getInt(submodMap, key);
455                     break;
456                 case EatClaim.ATTESTATION_APPLICATION_ID:
457                     // TODO: The attestation application ID is currently still encoded as an ASN.1
458                     // structure. Parse a CBOR structure when it's available instead.
459                     attestationApplicationId = new AttestationApplicationId(
460                         Asn1Utils.getAsn1EncodableFromBytes(CborUtils.getBytes(submodMap, key)));
461                     break;
462                 case EatClaim.ATTESTATION_ID_BRAND:
463                     brand = CborUtils.getString(submodMap, key);
464                     break;
465                 case EatClaim.ATTESTATION_ID_DEVICE:
466                     device = CborUtils.getString(submodMap, key);
467                     break;
468                 case EatClaim.ATTESTATION_ID_PRODUCT:
469                     product = CborUtils.getString(submodMap, key);
470                     break;
471                 case EatClaim.ATTESTATION_ID_SERIAL:
472                     serialNumber = CborUtils.getString(submodMap, key);
473                     break;
474                 case EatClaim.UEID:
475                     // TODO: Parse depending on encoding chosen in attestation_record.cpp.
476                     imei = CborUtils.getString(submodMap, key);
477                     break;
478                 case EatClaim.ATTESTATION_ID_MEID:
479                     meid = CborUtils.getString(submodMap, key);
480                     break;
481                 case EatClaim.ATTESTATION_ID_MANUFACTURER:
482                     manufacturer = CborUtils.getString(submodMap, key);
483                     break;
484                 case EatClaim.ATTESTATION_ID_MODEL:
485                     model = CborUtils.getString(submodMap, key);
486                     break;
487                 case EatClaim.USER_PRESENCE_REQUIRED:
488                     userPresenceRequired = CborUtils.getBoolean(submodMap, key);
489                     break;
490                 case EatClaim.TRUSTED_CONFIRMATION_REQUIRED:
491                     confirmationRequired = true;
492                     break;
493             }
494         }
495     }
496 
algorithmToString(int algorithm)497     public static String algorithmToString(int algorithm) {
498         switch (algorithm) {
499             case KM_ALGORITHM_RSA:
500                 return "RSA";
501             case KM_ALGORITHM_EC:
502                 return "ECDSA";
503             default:
504                 return "Unknown";
505         }
506     }
507 
paddingModesToString(final Set<Integer> paddingModes)508     public static String paddingModesToString(final Set<Integer> paddingModes) {
509         return joinStrings(transform(paddingModes, forMap(paddingMap, "Unknown")));
510     }
511 
paddingModeToString(int paddingMode)512     public static String paddingModeToString(int paddingMode) {
513         return forMap(paddingMap, "Unknown").apply(paddingMode);
514     }
515 
digestsToString(Set<Integer> digests)516     public static String digestsToString(Set<Integer> digests) {
517         return joinStrings(transform(digests, forMap(digestMap, "Unknown")));
518     }
519 
digestToString(int digest)520     public static String digestToString(int digest) {
521         return forMap(digestMap, "Unknown").apply(digest);
522     }
523 
purposesToString(Set<Integer> purposes)524     public static String purposesToString(Set<Integer> purposes) {
525         return joinStrings(transform(purposes, forMap(purposeMap, "Unknown")));
526     }
527 
userAuthTypeToString(int userAuthType)528     public static String userAuthTypeToString(int userAuthType) {
529         List<String> types = Lists.newArrayList();
530         if ((userAuthType & HW_AUTH_FINGERPRINT) != 0)
531             types.add("Fingerprint");
532         if ((userAuthType & HW_AUTH_PASSWORD) != 0)
533             types.add("Password");
534         return joinStrings(types);
535     }
536 
originToString(int origin)537     public static String originToString(int origin) {
538         switch (origin) {
539             case KM_ORIGIN_GENERATED:
540                 return "Generated";
541             case KM_ORIGIN_IMPORTED:
542                 return "Imported";
543             case KM_ORIGIN_UNKNOWN:
544                 return "Unknown (KM0)";
545             default:
546                 return "Unknown";
547         }
548     }
549 
joinStrings(Collection<String> collection)550     private static String joinStrings(Collection<String> collection) {
551         return new StringBuilder()
552                 .append("[")
553                 .append(Joiner.on(", ").join(collection))
554                 .append("]")
555                 .toString();
556     }
557 
formatDate(Date date)558     private static String formatDate(Date date) {
559         return DateFormat.getDateTimeInstance().format(date);
560     }
561 
parseAsn1TaggedObject(ASN1SequenceParser parser)562     private static ASN1TaggedObject parseAsn1TaggedObject(ASN1SequenceParser parser)
563             throws CertificateParsingException {
564         ASN1Encodable asn1Encodable = parseAsn1Encodable(parser);
565         if (asn1Encodable == null || asn1Encodable instanceof ASN1TaggedObject) {
566             return (ASN1TaggedObject) asn1Encodable;
567         }
568         throw new CertificateParsingException(
569                 "Expected tagged object, found " + asn1Encodable.getClass().getName());
570     }
571 
parseAsn1Encodable(ASN1SequenceParser parser)572     private static ASN1Encodable parseAsn1Encodable(ASN1SequenceParser parser)
573             throws CertificateParsingException {
574         try {
575             return parser.readObject();
576         } catch (IOException e) {
577             throw new CertificateParsingException("Failed to parse ASN1 sequence", e);
578         }
579     }
580 
getSecurityLevel()581     public Integer getSecurityLevel() {
582         return securityLevel;
583     }
584 
getPurposes()585     public Set<Integer> getPurposes() {
586         return purposes;
587     }
588 
getAlgorithm()589     public Integer getAlgorithm() {
590         return algorithm;
591     }
592 
getKeySize()593     public Integer getKeySize() {
594         return keySize;
595     }
596 
getDigests()597     public Set<Integer> getDigests() {
598         return digests;
599     }
600 
getPaddingModes()601     public Set<Integer> getPaddingModes() {
602         return paddingModes;
603     }
604 
getPaddingModesAsStrings()605     public Set<String> getPaddingModesAsStrings() throws CertificateParsingException {
606         if (paddingModes == null) {
607             return ImmutableSet.of();
608         }
609 
610         ImmutableSet.Builder<String> builder = ImmutableSet.builder();
611         for (int paddingMode : paddingModes) {
612             switch (paddingMode) {
613                 case KM_PAD_NONE:
614                     builder.add(KeyProperties.ENCRYPTION_PADDING_NONE);
615                     break;
616                 case KM_PAD_RSA_OAEP:
617                     builder.add(KeyProperties.ENCRYPTION_PADDING_RSA_OAEP);
618                     break;
619                 case KM_PAD_RSA_PKCS1_1_5_ENCRYPT:
620                     builder.add(KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1);
621                     break;
622                 case KM_PAD_RSA_PKCS1_1_5_SIGN:
623                     builder.add(KeyProperties.SIGNATURE_PADDING_RSA_PKCS1);
624                     break;
625                 case KM_PAD_RSA_PSS:
626                     builder.add(KeyProperties.SIGNATURE_PADDING_RSA_PSS);
627                     break;
628                 default:
629                     throw new CertificateParsingException("Invalid padding mode " + paddingMode);
630             }
631         }
632         return builder.build();
633     }
634 
getEcCurve()635     public Integer getEcCurve() {
636         return ecCurve;
637     }
638 
ecCurveAsString()639     public String ecCurveAsString() {
640         if (ecCurve == null)
641             return "NULL";
642 
643         switch (ecCurve) {
644             case KM_EC_CURVE_P224:
645                 return "secp224r1";
646             case KM_EC_CURVE_P256:
647                 return "secp256r1";
648             case KM_EC_CURVE_P384:
649                 return "secp384r1";
650             case KM_EC_CURVE_P521:
651                 return "secp521r1";
652             case KM_EC_CURVE_25519:
653                 return "CURVE_25519";
654             default:
655                 return "unknown";
656         }
657     }
658 
getRsaPublicExponent()659     public Long getRsaPublicExponent() {
660         return rsaPublicExponent;
661     }
662 
getRsaOaepMgfDigests()663     public Set<Integer> getRsaOaepMgfDigests() {
664         return mRsaOaepMgfDigests;
665     }
666 
getActiveDateTime()667     public Date getActiveDateTime() {
668         return activeDateTime;
669     }
670 
getOriginationExpireDateTime()671     public Date getOriginationExpireDateTime() {
672         return originationExpireDateTime;
673     }
674 
getUsageExpireDateTime()675     public Date getUsageExpireDateTime() {
676         return usageExpireDateTime;
677     }
678 
isNoAuthRequired()679     public boolean isNoAuthRequired() {
680         return noAuthRequired;
681     }
682 
getUserAuthType()683     public Integer getUserAuthType() {
684         return userAuthType;
685     }
686 
getAuthTimeout()687     public Integer getAuthTimeout() {
688         return authTimeout;
689     }
690 
isAllowWhileOnBody()691     public boolean isAllowWhileOnBody() {
692         return allowWhileOnBody;
693     }
694 
isAllApplications()695     public boolean isAllApplications() {
696         return allApplications;
697     }
698 
getApplicationId()699     public byte[] getApplicationId() {
700         return applicationId;
701     }
702 
getCreationDateTime()703     public Date getCreationDateTime() {
704         return creationDateTime;
705     }
706 
getOrigin()707     public Integer getOrigin() {
708         return origin;
709     }
710 
isRollbackResistant()711     public boolean isRollbackResistant() {
712         return rollbackResistant;
713     }
714 
isRollbackResistance()715     public boolean isRollbackResistance() {
716         return rollbackResistance;
717     }
718 
getRootOfTrust()719     public RootOfTrust getRootOfTrust() {
720         return rootOfTrust;
721     }
722 
getOsVersion()723     public Integer getOsVersion() {
724         return osVersion;
725     }
726 
getOsPatchLevel()727     public Integer getOsPatchLevel() {
728         return osPatchLevel;
729     }
730 
getVendorPatchLevel()731     public Integer getVendorPatchLevel() {
732         return vendorPatchLevel;
733     }
734 
getBootPatchLevel()735     public Integer getBootPatchLevel() {
736         return bootPatchLevel;
737     }
738 
getAttestationApplicationId()739     public AttestationApplicationId getAttestationApplicationId() {
740         return attestationApplicationId;
741     }
742 
getBrand()743     public String getBrand() {
744         return brand;
745     }
746 
getDevice()747     public String getDevice() {
748         return device;
749     }
750 
getSerialNumber()751     public String getSerialNumber() {
752         return serialNumber;
753     }
754 
getImei()755     public String getImei() {
756         return imei;
757     }
758 
getMeid()759     public String getMeid() {
760         return meid;
761     }
762 
getProduct()763     public String getProduct() {
764         return product;
765     }
766 
getManufacturer()767     public String getManufacturer() {
768         return manufacturer;
769     }
770 
getModel()771     public String getModel() {
772         return model;
773     }
774 
isUserPresenceRequired()775     public boolean isUserPresenceRequired() {
776         return userPresenceRequired;
777     }
778 
isConfirmationRequired()779     public boolean isConfirmationRequired() {
780         return confirmationRequired;
781     }
782 
getSecondImei()783     public String getSecondImei() {
784         return mSecondImei;
785     }
786 
getModuleHash()787     public byte[] getModuleHash() {
788         return mModuleHash;
789     }
790 
eatSecurityLevelToKeymasterSecurityLevel(int eatSecurityLevel)791     static int eatSecurityLevelToKeymasterSecurityLevel(int eatSecurityLevel) {
792         switch(eatSecurityLevel) {
793             case EatClaim.SECURITY_LEVEL_UNRESTRICTED:
794                 return Attestation.KM_SECURITY_LEVEL_SOFTWARE;
795             case EatClaim.SECURITY_LEVEL_SECURE_RESTRICTED:
796                 return Attestation.KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT;
797             case EatClaim.SECURITY_LEVEL_HARDWARE:
798                 return Attestation.KM_SECURITY_LEVEL_STRONG_BOX;
799             default:
800                 throw new RuntimeException("Invalid EAT security level: " + eatSecurityLevel);
801         }
802     }
803 
getStringFromAsn1Value(ASN1Primitive value)804     private String getStringFromAsn1Value(ASN1Primitive value) throws CertificateParsingException {
805         try {
806             return Asn1Utils.getStringFromAsn1OctetStreamAssumingUTF8(value);
807         } catch (UnsupportedEncodingException e) {
808             throw new CertificateParsingException("Error parsing ASN.1 value", e);
809         }
810     }
811 
812     @Override
toString()813     public String toString() {
814         StringBuilder s = new StringBuilder();
815 
816         if (algorithm != null) {
817             s.append("\nAlgorithm: ").append(algorithmToString(algorithm));
818         }
819 
820         if (keySize != null) {
821             s.append("\nKeySize: ").append(keySize);
822         }
823 
824         if (purposes != null && !purposes.isEmpty()) {
825             s.append("\nPurposes: ").append(purposesToString(purposes));
826         }
827 
828         if (digests != null && !digests.isEmpty()) {
829             s.append("\nDigests: ").append(digestsToString(digests));
830         }
831 
832         if (paddingModes != null && !paddingModes.isEmpty()) {
833             s.append("\nPadding modes: ").append(paddingModesToString(paddingModes));
834         }
835 
836         if (ecCurve != null) {
837             s.append("\nEC Curve: ").append(ecCurveAsString());
838         }
839 
840         String label = "\nRSA exponent: ";
841         if (rsaPublicExponent != null) {
842             s.append(label).append(rsaPublicExponent);
843         }
844 
845         if (mRsaOaepMgfDigests != null && !mRsaOaepMgfDigests.isEmpty()) {
846             s.append("\nRSA OAEP MGF Digests: ").append(digestsToString(mRsaOaepMgfDigests));
847         }
848 
849         if (activeDateTime != null) {
850             s.append("\nActive: ").append(formatDate(activeDateTime));
851         }
852 
853         if (originationExpireDateTime != null) {
854             s.append("\nOrigination expire: ").append(formatDate(originationExpireDateTime));
855         }
856 
857         if (usageExpireDateTime != null) {
858             s.append("\nUsage expire: ").append(formatDate(usageExpireDateTime));
859         }
860 
861         if (!noAuthRequired && userAuthType != null) {
862             s.append("\nAuth types: ").append(userAuthTypeToString(userAuthType));
863             if (authTimeout != null) {
864                 s.append("\nAuth timeout: ").append(authTimeout);
865             }
866         }
867 
868         if (applicationId != null) {
869             s.append("\nApplication ID: ").append(new String(applicationId));
870         }
871 
872         if (creationDateTime != null) {
873             s.append("\nCreated: ").append(formatDate(creationDateTime));
874         }
875 
876         if (origin != null) {
877             s.append("\nOrigin: ").append(originToString(origin));
878         }
879 
880         if (rollbackResistant) {
881             s.append("\nRollback resistant: true");
882         }
883 
884         if (rollbackResistance) {
885             s.append("\nRollback resistance: true");
886         }
887 
888         if (rootOfTrust != null) {
889             s.append("\nRoot of Trust:\n");
890             s.append(rootOfTrust);
891         }
892 
893         if (osVersion != null) {
894             s.append("\nOS Version: ").append(osVersion);
895         }
896 
897         if (osPatchLevel != null) {
898             s.append("\nOS Patchlevel: ").append(osPatchLevel);
899         }
900 
901         if (vendorPatchLevel != null) {
902             s.append("\nVendor Patchlevel: ").append(vendorPatchLevel);
903         }
904 
905         if (bootPatchLevel != null) {
906             s.append("\nBoot Patchlevel: ").append(bootPatchLevel);
907         }
908 
909         if (attestationApplicationId != null) {
910             s.append("\nAttestation Application Id:").append(attestationApplicationId);
911         }
912 
913         if (userPresenceRequired) {
914             s.append("\nUser presence required");
915         }
916 
917         if (confirmationRequired) {
918             s.append("\nConfirmation required");
919         }
920 
921         if (brand != null) {
922             s.append("\nBrand: ").append(brand);
923         }
924         if (device != null) {
925             s.append("\nDevice type: ").append(device);
926         }
927         if (product != null) {
928             s.append("\nProduct: ").append(product);
929         }
930         if (manufacturer != null) {
931             s.append("\nManufacturer: ").append(manufacturer);
932         }
933         if (model != null) {
934             s.append("\nModel: ").append(model);
935         }
936         if (mModuleHash != null) {
937             HexFormat hexFormat = HexFormat.of();
938             s.append("\nModule Hash: ").append(hexFormat.formatHex(mModuleHash));
939         }
940         return s.toString();
941     }
942 }
943