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