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