• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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.security.keystore2;
18 
19 import android.annotation.NonNull;
20 import android.hardware.biometrics.BiometricManager;
21 import android.hardware.security.keymint.KeyParameter;
22 import android.hardware.security.keymint.KeyParameterValue;
23 import android.hardware.security.keymint.SecurityLevel;
24 import android.hardware.security.keymint.Tag;
25 import android.security.GateKeeper;
26 import android.security.keymaster.KeymasterDefs;
27 import android.security.keystore.KeyProperties;
28 import android.security.keystore.UserAuthArgs;
29 import android.system.keystore2.Authorization;
30 
31 import java.math.BigInteger;
32 import java.security.ProviderException;
33 import java.util.ArrayList;
34 import java.util.Date;
35 import java.util.List;
36 import java.util.function.Consumer;
37 
38 /**
39  * @hide
40  */
41 public final class KeyStore2ParameterUtils {
42 
KeyStore2ParameterUtils()43     private KeyStore2ParameterUtils() {}
44 
45     /**
46      * This function constructs a {@link KeyParameter} expressing a boolean value.
47      * @param tag Must be KeyMint tag with the associated type BOOL.
48      * @return An instance of {@link KeyParameter}.
49      * @hide
50      */
makeBool(int tag)51     static @NonNull KeyParameter makeBool(int tag) {
52         int type = KeymasterDefs.getTagType(tag);
53         if (type != KeymasterDefs.KM_BOOL) {
54             throw new IllegalArgumentException("Not a boolean tag: " + tag);
55         }
56         KeyParameter p = new KeyParameter();
57         p.tag = tag;
58         p.value = KeyParameterValue.boolValue(true);
59         return p;
60     }
61 
62     /**
63      * This function constructs a {@link KeyParameter} expressing an enum value.
64      * @param tag Must be KeyMint tag with the associated type ENUM or ENUM_REP.
65      * @param v A 32bit integer.
66      * @return An instance of {@link KeyParameter}.
67      * @hide
68      */
makeEnum(int tag, int v)69     static @NonNull KeyParameter makeEnum(int tag, int v) {
70         KeyParameter kp = new KeyParameter();
71         kp.tag = tag;
72         switch (tag) {
73             case Tag.PURPOSE:
74                 kp.value = KeyParameterValue.keyPurpose(v);
75                 break;
76             case Tag.ALGORITHM:
77                 kp.value = KeyParameterValue.algorithm(v);
78                 break;
79             case Tag.BLOCK_MODE:
80                 kp.value = KeyParameterValue.blockMode(v);
81                 break;
82             case Tag.DIGEST:
83             case Tag.RSA_OAEP_MGF_DIGEST:
84                 kp.value = KeyParameterValue.digest(v);
85                 break;
86             case Tag.EC_CURVE:
87                 kp.value = KeyParameterValue.ecCurve(v);
88                 break;
89             case Tag.ORIGIN:
90                 kp.value = KeyParameterValue.origin(v);
91                 break;
92             case Tag.PADDING:
93                 kp.value = KeyParameterValue.paddingMode(v);
94                 break;
95             case Tag.USER_AUTH_TYPE:
96                 kp.value = KeyParameterValue.hardwareAuthenticatorType(v);
97                 break;
98             case Tag.HARDWARE_TYPE:
99                 kp.value = KeyParameterValue.securityLevel(v);
100                 break;
101             default:
102                 throw new IllegalArgumentException("Not an enum or repeatable enum tag: " + tag);
103         }
104         return kp;
105     }
106 
107     /**
108      * This function constructs a {@link KeyParameter} expressing an integer value.
109      * @param tag Must be KeyMint tag with the associated type UINT or UINT_REP.
110      * @param v A 32bit integer.
111      * @return An instance of {@link KeyParameter}.
112      * @hide
113      */
makeInt(int tag, int v)114     static @NonNull KeyParameter makeInt(int tag, int v) {
115         int type = KeymasterDefs.getTagType(tag);
116         if (type != KeymasterDefs.KM_UINT && type != KeymasterDefs.KM_UINT_REP) {
117             throw new IllegalArgumentException("Not an int or repeatable int tag: " + tag);
118         }
119         KeyParameter p = new KeyParameter();
120         p.tag = tag;
121         p.value = KeyParameterValue.integer(v);
122         return p;
123     }
124 
125     /**
126      * This function constructs a {@link KeyParameter} expressing a long integer value.
127      * @param tag Must be KeyMint tag with the associated type ULONG or ULONG_REP.
128      * @param v A 64bit integer.
129      * @return An instance of {@link KeyParameter}.
130      * @hide
131      */
makeLong(int tag, long v)132     static @NonNull KeyParameter makeLong(int tag, long v) {
133         int type = KeymasterDefs.getTagType(tag);
134         if (type != KeymasterDefs.KM_ULONG && type != KeymasterDefs.KM_ULONG_REP) {
135             throw new IllegalArgumentException("Not a long or repeatable long tag: " + tag);
136         }
137         KeyParameter p = new KeyParameter();
138         p.tag = tag;
139         p.value = KeyParameterValue.longInteger(v);
140         return p;
141     }
142 
143     /**
144      * This function constructs a {@link KeyParameter} expressing a blob.
145      * @param tag Must be KeyMint tag with the associated type BYTES.
146      * @param b A byte array to be stored in the new key parameter.
147      * @return An instance of {@link KeyParameter}.
148      * @hide
149      */
makeBytes(int tag, @NonNull byte[] b)150     static @NonNull KeyParameter makeBytes(int tag, @NonNull byte[] b) {
151         if (KeymasterDefs.getTagType(tag) != KeymasterDefs.KM_BYTES) {
152             throw new IllegalArgumentException("Not a bytes tag: " + tag);
153         }
154         KeyParameter p = new KeyParameter();
155         p.tag = tag;
156         p.value = KeyParameterValue.blob(b);
157         return p;
158     }
159 
160     /**
161      * This function constructs a {@link KeyParameter} expressing a Bignum.
162      * @param tag Must be KeyMint tag with the associated type BIGNUM.
163      * @param b A BitInteger to be stored in the new key parameter.
164      * @return An instance of {@link KeyParameter}.
165      * @hide
166      */
makeBignum(int tag, @NonNull BigInteger b)167     static @NonNull KeyParameter makeBignum(int tag, @NonNull BigInteger b) {
168         if (KeymasterDefs.getTagType(tag) != KeymasterDefs.KM_BIGNUM) {
169             throw new IllegalArgumentException("Not a bignum tag: " + tag);
170         }
171         KeyParameter p = new KeyParameter();
172         p.tag = tag;
173         p.value = KeyParameterValue.blob(b.toByteArray());
174         return p;
175     }
176 
177     /**
178      * This function constructs a {@link KeyParameter} expressing date.
179      * @param tag Must be KeyMint tag with the associated type DATE.
180      * @param date A date
181      * @return An instance of {@link KeyParameter}.
182      * @hide
183      */
makeDate(int tag, @NonNull Date date)184     static @NonNull KeyParameter makeDate(int tag, @NonNull Date date) {
185         if (KeymasterDefs.getTagType(tag) != KeymasterDefs.KM_DATE) {
186             throw new IllegalArgumentException("Not a date tag: " + tag);
187         }
188         KeyParameter p = new KeyParameter();
189         p.tag = tag;
190         p.value = KeyParameterValue.dateTime(date.getTime());
191         return p;
192     }
193     /**
194      * Returns true if the given security level is TEE or Strongbox.
195      *
196      * @param securityLevel the security level to query
197      * @return truw if the given security level is TEE or Strongbox.
198      */
isSecureHardware(@ecurityLevel int securityLevel)199     static boolean isSecureHardware(@SecurityLevel int securityLevel) {
200         return securityLevel == SecurityLevel.TRUSTED_ENVIRONMENT
201                 || securityLevel == SecurityLevel.STRONGBOX;
202     }
203 
getUnsignedInt(@onNull Authorization param)204     static long getUnsignedInt(@NonNull Authorization param) {
205         if (KeymasterDefs.getTagType(param.keyParameter.tag) != KeymasterDefs.KM_UINT) {
206             throw new IllegalArgumentException("Not an int tag: " + param.keyParameter.tag);
207         }
208         // KM_UINT is 32 bits wide so we must suppress sign extension.
209         return ((long) param.keyParameter.value.getInteger()) & 0xffffffffL;
210     }
211 
getDate(@onNull Authorization param)212     static @NonNull Date getDate(@NonNull Authorization param) {
213         if (KeymasterDefs.getTagType(param.keyParameter.tag) != KeymasterDefs.KM_DATE) {
214             throw new IllegalArgumentException("Not a date tag: " + param.keyParameter.tag);
215         }
216         if (param.keyParameter.value.getDateTime() < 0) {
217             throw new IllegalArgumentException("Date Value too large: "
218                     + param.keyParameter.value.getDateTime());
219         }
220         return new Date(param.keyParameter.value.getDateTime());
221     }
222 
forEachSetFlag(int flags, Consumer<Integer> consumer)223     static void forEachSetFlag(int flags, Consumer<Integer> consumer) {
224         int offset = 0;
225         while (flags != 0) {
226             if ((flags & 1) == 1) {
227                 consumer.accept(1 << offset);
228             }
229             offset += 1;
230             flags >>>= 1;
231         }
232     }
233 
getRootSid()234     private static long getRootSid() {
235         long rootSid = GateKeeper.getSecureUserId();
236         if (rootSid == 0) {
237             throw new IllegalStateException("Secure lock screen must be enabled"
238                     + " to create keys requiring user authentication");
239         }
240         return rootSid;
241     }
242 
addSids(@onNull List<KeyParameter> params, @NonNull UserAuthArgs spec)243     private static void addSids(@NonNull List<KeyParameter> params, @NonNull UserAuthArgs spec) {
244         // If both biometric and credential are accepted, then just use the root sid from gatekeeper
245         if (spec.getUserAuthenticationType() == (KeyProperties.AUTH_BIOMETRIC_STRONG
246                 | KeyProperties.AUTH_DEVICE_CREDENTIAL)) {
247             if (spec.getBoundToSpecificSecureUserId() != GateKeeper.INVALID_SECURE_USER_ID) {
248                 params.add(makeLong(
249                         KeymasterDefs.KM_TAG_USER_SECURE_ID,
250                         spec.getBoundToSpecificSecureUserId()
251                 ));
252             } else {
253                 // The key is authorized for use for the specified amount of time after the user has
254                 // authenticated. Whatever unlocks the secure lock screen should authorize this key.
255                 params.add(makeLong(KeymasterDefs.KM_TAG_USER_SECURE_ID, getRootSid()));
256             }
257         } else {
258             List<Long> sids = new ArrayList<>();
259             if ((spec.getUserAuthenticationType() & KeyProperties.AUTH_BIOMETRIC_STRONG) != 0) {
260                 final BiometricManager bm = android.app.AppGlobals.getInitialApplication()
261                         .getSystemService(BiometricManager.class);
262 
263                 // TODO: Restore permission check in getAuthenticatorIds once the ID is no longer
264                 //       needed here.
265 
266                 final long[] biometricSids = bm.getAuthenticatorIds();
267 
268                 if (biometricSids.length == 0) {
269                     throw new IllegalStateException(
270                             "At least one biometric must be enrolled to create keys requiring user"
271                                     + " authentication for every use");
272                 }
273 
274                 if (spec.getBoundToSpecificSecureUserId() != GateKeeper.INVALID_SECURE_USER_ID) {
275                     sids.add(spec.getBoundToSpecificSecureUserId());
276                 } else if (spec.isInvalidatedByBiometricEnrollment()) {
277                     // The biometric-only SIDs will change on biometric enrollment or removal of all
278                     // enrolled templates, invalidating the key.
279                     for (long sid : biometricSids) {
280                         sids.add(sid);
281                     }
282                 } else {
283                     // The root SID will *not* change on fingerprint enrollment, or removal of all
284                     // enrolled fingerprints, allowing the key to remain valid.
285                     sids.add(getRootSid());
286                 }
287             } else if ((spec.getUserAuthenticationType() & KeyProperties.AUTH_DEVICE_CREDENTIAL)
288                     != 0) {
289                 sids.add(getRootSid());
290             } else {
291                 throw new IllegalStateException("Invalid or no authentication type specified.");
292             }
293 
294             for (int i = 0; i < sids.size(); i++) {
295                 params.add(makeLong(KeymasterDefs.KM_TAG_USER_SECURE_ID, sids.get(i)));
296             }
297         }
298     }
299 
300     /**
301      * Adds keymaster arguments to express the key's authorization policy supported by user
302      * authentication.
303      *
304      * @param args The arguments sent to keymaster that need to be populated from the spec
305      * @param spec The user authentication relevant portions of the spec passed in from the caller.
306      *        This spec will be translated into the relevant keymaster tags to be loaded into args.
307      * @throws IllegalStateException if user authentication is required but the system is in a wrong
308      *         state (e.g., secure lock screen not set up) for generating or importing keys that
309      *         require user authentication.
310      */
addUserAuthArgs(@onNull List<KeyParameter> args, @NonNull UserAuthArgs spec)311     static void addUserAuthArgs(@NonNull List<KeyParameter> args,
312             @NonNull UserAuthArgs spec) {
313 
314         if (spec.isUserConfirmationRequired()) {
315             args.add(KeyStore2ParameterUtils.makeBool(
316                     KeymasterDefs.KM_TAG_TRUSTED_CONFIRMATION_REQUIRED));
317         }
318         if (spec.isUserPresenceRequired()) {
319             args.add(KeyStore2ParameterUtils.makeBool(
320                     KeymasterDefs.KM_TAG_TRUSTED_USER_PRESENCE_REQUIRED));
321         }
322         if (spec.isUnlockedDeviceRequired()) {
323             args.add(KeyStore2ParameterUtils.makeBool(
324                     KeymasterDefs.KM_TAG_UNLOCKED_DEVICE_REQUIRED));
325         }
326         if (!spec.isUserAuthenticationRequired()) {
327             args.add(KeyStore2ParameterUtils.makeBool(
328                     KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED));
329         } else {
330             addSids(args, spec);
331             args.add(KeyStore2ParameterUtils.makeEnum(
332                     KeymasterDefs.KM_TAG_USER_AUTH_TYPE, spec.getUserAuthenticationType()
333             ));
334             if (spec.getUserAuthenticationValidityDurationSeconds() != 0) {
335                 args.add(KeyStore2ParameterUtils.makeInt(
336                         KeymasterDefs.KM_TAG_AUTH_TIMEOUT,
337                         spec.getUserAuthenticationValidityDurationSeconds()
338                 ));
339             }
340             if (spec.isUserAuthenticationValidWhileOnBody()) {
341                 if (spec.getUserAuthenticationValidityDurationSeconds() == 0) {
342                     throw new ProviderException(
343                             "Key validity extension while device is on-body is not "
344                                     + "supported for keys requiring fingerprint authentication");
345                 }
346                 args.add(KeyStore2ParameterUtils.makeBool(
347                         KeymasterDefs.KM_TAG_ALLOW_WHILE_ON_BODY
348                 ));
349             }
350         }
351     }
352 }
353