blob: 670ef5e32f0c9bd3aa99521a603656b15834b406 [file] [log] [blame]
Alex Klyubincc21bb32015-03-31 16:50:37 -07001/*
2 * Copyright (C) 2015 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
Alex Klyubindcdaf872015-05-13 15:57:09 -070017package android.security.keystore;
Alex Klyubind23a1f72015-03-27 14:39:28 -070018
Kevin Chyn7d07c892020-02-18 18:18:17 -080019import android.hardware.biometrics.BiometricManager;
Alex Klyubindcdaf872015-05-13 15:57:09 -070020import android.security.GateKeeper;
21import android.security.KeyStore;
Alex Klyubin1eda77a2015-04-28 14:21:01 -070022import android.security.keymaster.KeymasterArguments;
Alex Klyubin5927c9f2015-04-10 13:28:03 -070023import android.security.keymaster.KeymasterDefs;
Alex Klyubind23a1f72015-03-27 14:39:28 -070024
Alex Klyubina95550f2015-07-16 16:32:23 -070025import java.security.ProviderException;
Kevin Chyn057b7432018-09-24 14:36:39 -070026import java.util.ArrayList;
27import java.util.List;
Alex Klyubina95550f2015-07-16 16:32:23 -070028
Alex Klyubind23a1f72015-03-27 14:39:28 -070029/**
30 * @hide
31 */
32public abstract class KeymasterUtils {
Alex Klyubin5927c9f2015-04-10 13:28:03 -070033
Alex Klyubind23a1f72015-03-27 14:39:28 -070034 private KeymasterUtils() {}
35
Alex Klyubin7ea50902015-04-30 10:50:45 -070036 public static int getDigestOutputSizeBits(int keymasterDigest) {
Alex Klyubin5927c9f2015-04-10 13:28:03 -070037 switch (keymasterDigest) {
38 case KeymasterDefs.KM_DIGEST_NONE:
39 return -1;
40 case KeymasterDefs.KM_DIGEST_MD5:
Alex Klyubin7ea50902015-04-30 10:50:45 -070041 return 128;
Alex Klyubin5927c9f2015-04-10 13:28:03 -070042 case KeymasterDefs.KM_DIGEST_SHA1:
Alex Klyubin7ea50902015-04-30 10:50:45 -070043 return 160;
Alex Klyubin5927c9f2015-04-10 13:28:03 -070044 case KeymasterDefs.KM_DIGEST_SHA_2_224:
Alex Klyubin7ea50902015-04-30 10:50:45 -070045 return 224;
Alex Klyubin5927c9f2015-04-10 13:28:03 -070046 case KeymasterDefs.KM_DIGEST_SHA_2_256:
Alex Klyubin7ea50902015-04-30 10:50:45 -070047 return 256;
Alex Klyubin5927c9f2015-04-10 13:28:03 -070048 case KeymasterDefs.KM_DIGEST_SHA_2_384:
Alex Klyubin7ea50902015-04-30 10:50:45 -070049 return 384;
Alex Klyubin5927c9f2015-04-10 13:28:03 -070050 case KeymasterDefs.KM_DIGEST_SHA_2_512:
Alex Klyubin7ea50902015-04-30 10:50:45 -070051 return 512;
Alex Klyubin5927c9f2015-04-10 13:28:03 -070052 default:
53 throw new IllegalArgumentException("Unknown digest: " + keymasterDigest);
54 }
55 }
56
Alex Klyubin3ceb1a02015-06-05 15:51:06 -070057 public static boolean isKeymasterBlockModeIndCpaCompatibleWithSymmetricCrypto(
58 int keymasterBlockMode) {
Alex Klyubin5927c9f2015-04-10 13:28:03 -070059 switch (keymasterBlockMode) {
60 case KeymasterDefs.KM_MODE_ECB:
61 return false;
62 case KeymasterDefs.KM_MODE_CBC:
63 case KeymasterDefs.KM_MODE_CTR:
64 case KeymasterDefs.KM_MODE_GCM:
65 return true;
66 default:
67 throw new IllegalArgumentException("Unsupported block mode: " + keymasterBlockMode);
68 }
69 }
70
Alex Klyubin3ceb1a02015-06-05 15:51:06 -070071 public static boolean isKeymasterPaddingSchemeIndCpaCompatibleWithAsymmetricCrypto(
72 int keymasterPadding) {
73 switch (keymasterPadding) {
74 case KeymasterDefs.KM_PAD_NONE:
75 return false;
76 case KeymasterDefs.KM_PAD_RSA_OAEP:
77 case KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_ENCRYPT:
78 return true;
79 default:
80 throw new IllegalArgumentException(
Alex Klyubinfdbc02a2015-06-29 14:39:29 -070081 "Unsupported asymmetric encryption padding scheme: " + keymasterPadding);
Alex Klyubin3ceb1a02015-06-05 15:51:06 -070082 }
83 }
84
Max Bires1cfd95e2020-03-12 16:26:07 -070085 private static void addSids(KeymasterArguments args, UserAuthArgs spec) {
86 // If both biometric and credential are accepted, then just use the root sid from gatekeeper
87 if (spec.getUserAuthenticationType() == (KeyProperties.AUTH_BIOMETRIC_STRONG
88 | KeyProperties.AUTH_DEVICE_CREDENTIAL)) {
89 if (spec.getBoundToSpecificSecureUserId() != GateKeeper.INVALID_SECURE_USER_ID) {
90 args.addUnsignedLong(KeymasterDefs.KM_TAG_USER_SECURE_ID,
91 KeymasterArguments.toUint64(spec.getBoundToSpecificSecureUserId()));
92 } else {
93 // The key is authorized for use for the specified amount of time after the user has
94 // authenticated. Whatever unlocks the secure lock screen should authorize this key.
95 args.addUnsignedLong(KeymasterDefs.KM_TAG_USER_SECURE_ID,
96 KeymasterArguments.toUint64(getRootSid()));
97 }
98 } else {
99 List<Long> sids = new ArrayList<>();
100 if ((spec.getUserAuthenticationType() & KeyProperties.AUTH_BIOMETRIC_STRONG) != 0) {
101 final BiometricManager bm = KeyStore.getApplicationContext()
102 .getSystemService(BiometricManager.class);
103
104 // TODO: Restore permission check in getAuthenticatorIds once the ID is no longer
105 // needed here.
106
107 final long[] biometricSids = bm.getAuthenticatorIds();
108
109 if (biometricSids.length == 0) {
110 throw new IllegalStateException(
111 "At least one biometric must be enrolled to create keys requiring user"
112 + " authentication for every use");
113 }
114
115 if (spec.getBoundToSpecificSecureUserId() != GateKeeper.INVALID_SECURE_USER_ID) {
116 sids.add(spec.getBoundToSpecificSecureUserId());
117 } else if (spec.isInvalidatedByBiometricEnrollment()) {
118 // The biometric-only SIDs will change on biometric enrollment or removal of all
119 // enrolled templates, invalidating the key.
120 for (long sid : biometricSids) {
121 sids.add(sid);
122 }
123 } else {
124 // The root SID will *not* change on fingerprint enrollment, or removal of all
125 // enrolled fingerprints, allowing the key to remain valid.
126 sids.add(getRootSid());
127 }
128 } else if ((spec.getUserAuthenticationType() & KeyProperties.AUTH_DEVICE_CREDENTIAL)
129 != 0) {
130 sids.add(getRootSid());
131 } else {
132 throw new IllegalStateException("Invalid or no authentication type specified.");
133 }
134
135 for (int i = 0; i < sids.size(); i++) {
136 args.addUnsignedLong(KeymasterDefs.KM_TAG_USER_SECURE_ID,
137 KeymasterArguments.toUint64(sids.get(i)));
138 }
139 }
140 }
141
Alex Klyubin1eda77a2015-04-28 14:21:01 -0700142 /**
143 * Adds keymaster arguments to express the key's authorization policy supported by user
144 * authentication.
145 *
Max Bires04b682d2020-01-14 16:10:36 -0800146 * @param args The arguments sent to keymaster that need to be populated from the spec
147 * @param spec The user authentication relevant portions of the spec passed in from the caller.
148 * This spec will be translated into the relevant keymaster tags to be loaded into args.
Alex Klyubinb6e62862015-07-06 10:31:07 -0700149 * @throws IllegalStateException if user authentication is required but the system is in a wrong
150 * state (e.g., secure lock screen not set up) for generating or importing keys that
151 * require user authentication.
Alex Klyubin1eda77a2015-04-28 14:21:01 -0700152 */
Brian Young36716eb2018-02-23 18:04:20 +0000153 public static void addUserAuthArgs(KeymasterArguments args, UserAuthArgs spec) {
Brian Young36716eb2018-02-23 18:04:20 +0000154
Brian Young5437b812018-02-23 18:04:20 +0000155 if (spec.isUserConfirmationRequired()) {
David Zeuthena8e8b652017-10-25 14:25:55 -0400156 args.addBoolean(KeymasterDefs.KM_TAG_TRUSTED_CONFIRMATION_REQUIRED);
157 }
158
Shawn Willden3c1830b2018-03-27 16:10:37 -0600159 if (spec.isUserPresenceRequired()) {
Brian Young5437b812018-02-23 18:04:20 +0000160 args.addBoolean(KeymasterDefs.KM_TAG_TRUSTED_USER_PRESENCE_REQUIRED);
161 }
162
Brian Young9272dab2018-02-23 18:04:20 +0000163 if (spec.isUnlockedDeviceRequired()) {
164 args.addBoolean(KeymasterDefs.KM_TAG_UNLOCKED_DEVICE_REQUIRED);
165 }
166
Brian Young5437b812018-02-23 18:04:20 +0000167 if (!spec.isUserAuthenticationRequired()) {
Alex Klyubin1eda77a2015-04-28 14:21:01 -0700168 args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED);
169 return;
170 }
171
Max Bires04b682d2020-01-14 16:10:36 -0800172 if (spec.getUserAuthenticationValidityDurationSeconds() == 0) {
Kevin Chyn7d07c892020-02-18 18:18:17 -0800173 // Every use of this key needs to be authorized by the user.
Max Bires1cfd95e2020-03-12 16:26:07 -0700174 addSids(args, spec);
Max Bires04b682d2020-01-14 16:10:36 -0800175 args.addEnum(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, spec.getUserAuthenticationType());
Kevin Chyn057b7432018-09-24 14:36:39 -0700176
Brian Young5437b812018-02-23 18:04:20 +0000177 if (spec.isUserAuthenticationValidWhileOnBody()) {
Shawn Willdenadef4962016-01-29 07:07:16 -0700178 throw new ProviderException("Key validity extension while device is on-body is not "
179 + "supported for keys requiring fingerprint authentication");
180 }
Alex Klyubin1eda77a2015-04-28 14:21:01 -0700181 } else {
Max Bires1cfd95e2020-03-12 16:26:07 -0700182 addSids(args, spec);
Max Biresa8117872020-03-11 01:53:59 -0700183 args.addEnum(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, spec.getUserAuthenticationType());
Alex Klyubinae6cb7a2015-06-22 18:09:35 -0700184 args.addUnsignedInt(KeymasterDefs.KM_TAG_AUTH_TIMEOUT,
Brian Young5437b812018-02-23 18:04:20 +0000185 spec.getUserAuthenticationValidityDurationSeconds());
186 if (spec.isUserAuthenticationValidWhileOnBody()) {
Shawn Willdenadef4962016-01-29 07:07:16 -0700187 args.addBoolean(KeymasterDefs.KM_TAG_ALLOW_WHILE_ON_BODY);
188 }
Alex Klyubin1eda77a2015-04-28 14:21:01 -0700189 }
190 }
Alex Klyubina95550f2015-07-16 16:32:23 -0700191
192 /**
193 * Adds {@code KM_TAG_MIN_MAC_LENGTH} tag, if necessary, to the keymaster arguments for
194 * generating or importing a key. This tag may only be needed for symmetric keys (e.g., HMAC,
195 * AES-GCM).
196 */
197 public static void addMinMacLengthAuthorizationIfNecessary(KeymasterArguments args,
198 int keymasterAlgorithm,
199 int[] keymasterBlockModes,
200 int[] keymasterDigests) {
201 switch (keymasterAlgorithm) {
202 case KeymasterDefs.KM_ALGORITHM_AES:
203 if (com.android.internal.util.ArrayUtils.contains(
204 keymasterBlockModes, KeymasterDefs.KM_MODE_GCM)) {
205 // AES GCM key needs the minimum length of AEAD tag specified.
206 args.addUnsignedInt(KeymasterDefs.KM_TAG_MIN_MAC_LENGTH,
207 AndroidKeyStoreAuthenticatedAESCipherSpi.GCM
208 .MIN_SUPPORTED_TAG_LENGTH_BITS);
209 }
210 break;
211 case KeymasterDefs.KM_ALGORITHM_HMAC:
212 // HMAC key needs the minimum length of MAC set to the output size of the associated
213 // digest. This is because we do not offer a way to generate shorter MACs and
214 // don't offer a way to verify MACs (other than by generating them).
215 if (keymasterDigests.length != 1) {
216 throw new ProviderException(
217 "Unsupported number of authorized digests for HMAC key: "
218 + keymasterDigests.length
219 + ". Exactly one digest must be authorized");
220 }
221 int keymasterDigest = keymasterDigests[0];
222 int digestOutputSizeBits = getDigestOutputSizeBits(keymasterDigest);
223 if (digestOutputSizeBits == -1) {
224 throw new ProviderException(
225 "HMAC key authorized for unsupported digest: "
226 + KeyProperties.Digest.fromKeymaster(keymasterDigest));
227 }
228 args.addUnsignedInt(KeymasterDefs.KM_TAG_MIN_MAC_LENGTH, digestOutputSizeBits);
229 break;
230 }
231 }
Shawn Willdenc38eae52016-02-22 23:28:34 +0000232
233 private static long getRootSid() {
234 long rootSid = GateKeeper.getSecureUserId();
235 if (rootSid == 0) {
236 throw new IllegalStateException("Secure lock screen must be enabled"
237 + " to create keys requiring user authentication");
238 }
239 return rootSid;
240 }
Alex Klyubind23a1f72015-03-27 14:39:28 -0700241}