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