blob: 9d0fe11be46b6e80fbd88fd4bec227e4078dbf8f [file] [log] [blame]
Chia-chi Yeh44039172009-09-21 11:53:59 +08001/*
2 * Copyright (C) 2009 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
17package android.security;
18
Svetoslav2dac95d2015-04-30 11:30:33 -070019import android.app.ActivityThread;
20import android.app.Application;
Alex Klyubin54183932015-05-08 15:25:48 -070021import android.app.KeyguardManager;
Artur Satayev53fe9662019-12-10 17:47:55 +000022import android.compat.annotation.UnsupportedAppUsage;
Alex Klyubin708fc9402015-04-28 18:58:47 -070023import android.content.Context;
Kevin Chyn7d07c892020-02-18 18:18:17 -080024import android.hardware.biometrics.BiometricManager;
Chad Brubakere6a461342015-02-10 21:33:23 -080025import android.os.Binder;
Mathew Inwood31755f92018-12-20 13:53:36 +000026import android.os.Build;
Chad Brubakere6a461342015-02-10 21:33:23 -080027import android.os.IBinder;
Chad Brubakera91a8502015-05-07 10:02:22 -070028import android.os.Process;
Kenny Root6b776452012-11-02 15:40:32 -070029import android.os.RemoteException;
30import android.os.ServiceManager;
Chad Brubakera91a8502015-05-07 10:02:22 -070031import android.os.UserHandle;
Chad Brubakere6a461342015-02-10 21:33:23 -080032import android.security.keymaster.ExportResult;
33import android.security.keymaster.KeyCharacteristics;
34import android.security.keymaster.KeymasterArguments;
Chad Brubaker5e73c0e2015-03-21 22:46:43 -070035import android.security.keymaster.KeymasterBlob;
Shawn Willden8d8c7472016-02-02 08:27:39 -070036import android.security.keymaster.KeymasterCertificateChain;
Alex Klyubinb4834ae2015-04-02 15:53:46 -070037import android.security.keymaster.KeymasterDefs;
Chad Brubakere6a461342015-02-10 21:33:23 -080038import android.security.keymaster.OperationResult;
Janis Danisevskisb0358e72018-11-02 10:34:07 -070039import android.security.keystore.IKeystoreService;
Alex Klyubin3f8d4d82015-05-13 09:15:00 -070040import android.security.keystore.KeyExpiredException;
41import android.security.keystore.KeyNotYetValidException;
42import android.security.keystore.KeyPermanentlyInvalidatedException;
Janis Danisevskis1864c952018-08-09 11:14:49 -070043import android.security.keystore.KeyProperties;
Janis Danisevskisb0358e72018-11-02 10:34:07 -070044import android.security.keystore.KeystoreResponse;
Alex Klyubin3f8d4d82015-05-13 09:15:00 -070045import android.security.keystore.UserNotAuthenticatedException;
Kenny Root6b776452012-11-02 15:40:32 -070046import android.util.Log;
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -070047
Janis Danisevskis1864c952018-08-09 11:14:49 -070048import com.android.org.bouncycastle.asn1.ASN1InputStream;
49import com.android.org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -070050
Janis Danisevskis1864c952018-08-09 11:14:49 -070051import java.io.ByteArrayInputStream;
52import java.io.IOException;
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -070053import java.math.BigInteger;
Alex Klyubinad9ba102015-04-21 15:17:24 -070054import java.security.InvalidKeyException;
Rob Barnesebe26742018-11-13 15:57:22 -070055import java.util.ArrayList;
Janis Danisevskis2b106ad2018-11-15 09:27:16 -080056import java.util.Date;
Alex Klyubin708fc9402015-04-28 18:58:47 -070057import java.util.List;
Kenny Rootb91773b2013-09-05 13:03:16 -070058import java.util.Locale;
Janis Danisevskisb0358e72018-11-02 10:34:07 -070059import java.util.concurrent.CompletableFuture;
60import java.util.concurrent.ExecutionException;
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -070061
Janis Danisevskis1864c952018-08-09 11:14:49 -070062import sun.security.util.ObjectIdentifier;
63import sun.security.x509.AlgorithmId;
Kenny Rootb91773b2013-09-05 13:03:16 -070064
Chia-chi Yeh44039172009-09-21 11:53:59 +080065/**
Brian Carlstrom46703b02011-04-06 15:41:29 -070066 * @hide This should not be made public in its present form because it
67 * assumes that private and secret key bytes are available and would
68 * preclude the use of hardware crypto.
Chia-chi Yeh44039172009-09-21 11:53:59 +080069 */
70public class KeyStore {
Kenny Root6b776452012-11-02 15:40:32 -070071 private static final String TAG = "KeyStore";
Brian Carlstrom5cfee3f2011-05-31 01:00:15 -070072
Dmitry Dementyevefc43112017-10-27 23:10:28 -070073 // ResponseCodes - see system/security/keystore/include/keystore/keystore.h
Mathew Inwoode420f8b2018-08-16 18:40:47 +010074 @UnsupportedAppUsage
Brian Carlstrom7e4b1a42011-06-01 15:29:29 -070075 public static final int NO_ERROR = 1;
76 public static final int LOCKED = 2;
77 public static final int UNINITIALIZED = 3;
78 public static final int SYSTEM_ERROR = 4;
79 public static final int PROTOCOL_ERROR = 5;
80 public static final int PERMISSION_DENIED = 6;
81 public static final int KEY_NOT_FOUND = 7;
82 public static final int VALUE_CORRUPTED = 8;
83 public static final int UNDEFINED_ACTION = 9;
84 public static final int WRONG_PASSWORD = 10;
Janis Danisevskisd2575382018-10-08 07:56:58 -070085 public static final int KEY_ALREADY_EXISTS = 16;
Eran Messeri61692392018-03-26 16:43:14 +010086 public static final int CANNOT_ATTEST_IDS = -66;
Frank Salimea5e0382018-01-23 22:42:29 -080087 public static final int HARDWARE_TYPE_UNAVAILABLE = -68;
Brian Carlstrom5cfee3f2011-05-31 01:00:15 -070088
Chad Brubaker560d6532015-04-24 10:32:18 -070089 /**
90 * Per operation authentication is needed before this operation is valid.
91 * This is returned from {@link #begin} when begin succeeds but the operation uses
92 * per-operation authentication and must authenticate before calling {@link #update} or
93 * {@link #finish}.
94 */
95 public static final int OP_AUTH_NEEDED = 15;
96
Max Bires13f98ce2018-11-02 10:50:40 -070097 // Used when a user changes their pin, invalidating old auth bound keys.
98 public static final int KEY_PERMANENTLY_INVALIDATED = 17;
99
Kenny Root2eeda722013-04-10 11:30:58 -0700100 // Used for UID field to indicate the calling UID.
101 public static final int UID_SELF = -1;
102
103 // Flags for "put" "import" and "generate"
104 public static final int FLAG_NONE = 0;
Alex Klyubin54183932015-05-08 15:25:48 -0700105
106 /**
107 * Indicates that this key (or key pair) must be encrypted at rest. This will protect the key
108 * (or key pair) with the secure lock screen credential (e.g., password, PIN, or pattern).
109 *
110 * <p>Note that this requires that the secure lock screen (e.g., password, PIN, pattern) is set
111 * up, otherwise key (or key pair) generation or import will fail. Moreover, this key (or key
112 * pair) will be deleted when the secure lock screen is disabled or reset (e.g., by the user or
113 * a Device Administrator). Finally, this key (or key pair) cannot be used until the user
114 * unlocks the secure lock screen after boot.
115 *
116 * @see KeyguardManager#isDeviceSecure()
117 */
Kenny Roota3788b02013-04-10 10:37:55 -0700118 public static final int FLAG_ENCRYPTED = 1;
119
Rubin Xu12b644d2017-04-21 19:21:42 +0100120 /**
Janis Danisevskis0aadf932017-12-18 17:28:52 -0800121 * Select Software keymaster device, which as of this writing is the lowest security
122 * level available on an android device. If neither FLAG_STRONGBOX nor FLAG_SOFTWARE is provided
123 * A TEE based keymaster implementation is implied.
124 *
125 * Need to be in sync with KeyStoreFlag in system/security/keystore/include/keystore/keystore.h
126 * For historical reasons this corresponds to the KEYSTORE_FLAG_FALLBACK flag.
127 */
128 public static final int FLAG_SOFTWARE = 1 << 1;
129
130 /**
Rubin Xu12b644d2017-04-21 19:21:42 +0100131 * A private flag that's only available to system server to indicate that this key is part of
132 * device encryption flow so it receives special treatment from keystore. For example this key
133 * will not be super encrypted, and it will be stored separately under an unique UID instead
134 * of the caller UID i.e. SYSTEM.
135 *
136 * Need to be in sync with KeyStoreFlag in system/security/keystore/include/keystore/keystore.h
137 */
138 public static final int FLAG_CRITICAL_TO_DEVICE_ENCRYPTION = 1 << 3;
139
Janis Danisevskis0aadf932017-12-18 17:28:52 -0800140 /**
141 * Select Strongbox keymaster device, which as of this writing the the highest security level
142 * available an android devices. If neither FLAG_STRONGBOX nor FLAG_SOFTWARE is provided
143 * A TEE based keymaster implementation is implied.
144 *
145 * Need to be in sync with KeyStoreFlag in system/security/keystore/include/keystore/keystore.h
146 */
147 public static final int FLAG_STRONGBOX = 1 << 4;
148
Brian Carlstrom5cfee3f2011-05-31 01:00:15 -0700149 // States
Mathew Inwoodefb48162018-08-01 10:24:49 +0100150 public enum State {
Mathew Inwoode420f8b2018-08-16 18:40:47 +0100151 @UnsupportedAppUsage
Mathew Inwoodefb48162018-08-01 10:24:49 +0100152 UNLOCKED,
Mathew Inwoode420f8b2018-08-16 18:40:47 +0100153 @UnsupportedAppUsage
Mathew Inwoodefb48162018-08-01 10:24:49 +0100154 LOCKED,
155 UNINITIALIZED
156 };
Chia-chi Yeh44039172009-09-21 11:53:59 +0800157
Chia-chi Yeh44039172009-09-21 11:53:59 +0800158 private int mError = NO_ERROR;
159
Kenny Root6b776452012-11-02 15:40:32 -0700160 private final IKeystoreService mBinder;
Alex Klyubin2d7a85c2015-04-30 11:43:53 -0700161 private final Context mContext;
Kenny Root6b776452012-11-02 15:40:32 -0700162
Chad Brubakere6a461342015-02-10 21:33:23 -0800163 private IBinder mToken;
164
Kenny Root6b776452012-11-02 15:40:32 -0700165 private KeyStore(IKeystoreService binder) {
166 mBinder = binder;
Alex Klyubin3f8d4d82015-05-13 09:15:00 -0700167 mContext = getApplicationContext();
Alex Klyubin2d7a85c2015-04-30 11:43:53 -0700168 }
169
Mathew Inwoode420f8b2018-08-16 18:40:47 +0100170 @UnsupportedAppUsage
Alex Klyubindcdaf872015-05-13 15:57:09 -0700171 public static Context getApplicationContext() {
Alex Klyubina99b8b52015-06-11 13:27:34 -0700172 Application application = ActivityThread.currentApplication();
Alex Klyubin2d7a85c2015-04-30 11:43:53 -0700173 if (application == null) {
174 throw new IllegalStateException(
Alex Klyubina99b8b52015-06-11 13:27:34 -0700175 "Failed to obtain application Context from ActivityThread");
Alex Klyubin2d7a85c2015-04-30 11:43:53 -0700176 }
177 return application;
Kenny Root6b776452012-11-02 15:40:32 -0700178 }
Chia-chi Yeh44039172009-09-21 11:53:59 +0800179
Mathew Inwoode420f8b2018-08-16 18:40:47 +0100180 @UnsupportedAppUsage
Chia-chi Yeh44039172009-09-21 11:53:59 +0800181 public static KeyStore getInstance() {
Kenny Root6b776452012-11-02 15:40:32 -0700182 IKeystoreService keystore = IKeystoreService.Stub.asInterface(ServiceManager
183 .getService("android.security.keystore"));
184 return new KeyStore(keystore);
Chia-chi Yeh44039172009-09-21 11:53:59 +0800185 }
186
Chad Brubakere6a461342015-02-10 21:33:23 -0800187 private synchronized IBinder getToken() {
188 if (mToken == null) {
189 mToken = new Binder();
190 }
191 return mToken;
192 }
193
Mathew Inwoode420f8b2018-08-16 18:40:47 +0100194 @UnsupportedAppUsage
Chad Brubakere35d49f2015-05-12 15:19:52 -0700195 public State state(int userId) {
Kenny Root6b776452012-11-02 15:40:32 -0700196 final int ret;
197 try {
Chad Brubakere35d49f2015-05-12 15:19:52 -0700198 ret = mBinder.getState(userId);
Kenny Root6b776452012-11-02 15:40:32 -0700199 } catch (RemoteException e) {
200 Log.w(TAG, "Cannot connect to keystore", e);
201 throw new AssertionError(e);
202 }
203
204 switch (ret) {
Brian Carlstrom5cfee3f2011-05-31 01:00:15 -0700205 case NO_ERROR: return State.UNLOCKED;
206 case LOCKED: return State.LOCKED;
207 case UNINITIALIZED: return State.UNINITIALIZED;
208 default: throw new AssertionError(mError);
209 }
Chia-chi Yeh44039172009-09-21 11:53:59 +0800210 }
211
Mathew Inwoode420f8b2018-08-16 18:40:47 +0100212 @UnsupportedAppUsage
Chad Brubakere35d49f2015-05-12 15:19:52 -0700213 public State state() {
214 return state(UserHandle.myUserId());
215 }
216
Kenny Rootb9594ce2013-02-14 10:18:38 -0800217 public boolean isUnlocked() {
218 return state() == State.UNLOCKED;
219 }
220
Chad Brubaker5bbf0482015-09-09 14:53:52 -0700221 public byte[] get(String key, int uid) {
Irina Dumitrescu4a1cccc2018-06-08 19:36:34 +0100222 return get(key, uid, false);
Chia-chi Yeh44039172009-09-21 11:53:59 +0800223 }
224
Mathew Inwoode420f8b2018-08-16 18:40:47 +0100225 @UnsupportedAppUsage
Chad Brubaker5bbf0482015-09-09 14:53:52 -0700226 public byte[] get(String key) {
227 return get(key, UID_SELF);
228 }
229
Irina Dumitrescu4a1cccc2018-06-08 19:36:34 +0100230 public byte[] get(String key, int uid, boolean suppressKeyNotFoundWarning) {
231 try {
232 key = key != null ? key : "";
233 return mBinder.get(key, uid);
234 } catch (RemoteException e) {
235 Log.w(TAG, "Cannot connect to keystore", e);
236 return null;
237 } catch (android.os.ServiceSpecificException e) {
238 if (!suppressKeyNotFoundWarning || e.errorCode != KEY_NOT_FOUND) {
239 Log.w(TAG, "KeyStore exception", e);
240 }
241 return null;
242 }
243 }
244
245 public byte[] get(String key, boolean suppressKeyNotFoundWarning) {
246 return get(key, UID_SELF, suppressKeyNotFoundWarning);
247 }
248
249
Kenny Roota3788b02013-04-10 10:37:55 -0700250 public boolean put(String key, byte[] value, int uid, int flags) {
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700251 return insert(key, value, uid, flags) == NO_ERROR;
252 }
253
254 public int insert(String key, byte[] value, int uid, int flags) {
Kenny Root6b776452012-11-02 15:40:32 -0700255 try {
Dmitry Dementyevefc43112017-10-27 23:10:28 -0700256 if (value == null) {
257 value = new byte[0];
258 }
Janis Danisevskisd2575382018-10-08 07:56:58 -0700259 int error = mBinder.insert(key, value, uid, flags);
260 if (error == KEY_ALREADY_EXISTS) {
261 mBinder.del(key, uid);
262 error = mBinder.insert(key, value, uid, flags);
263 }
264 return error;
Kenny Root78ad8492013-02-13 17:02:57 -0800265 } catch (RemoteException e) {
266 Log.w(TAG, "Cannot connect to keystore", e);
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700267 return SYSTEM_ERROR;
Kenny Root78ad8492013-02-13 17:02:57 -0800268 }
269 }
270
Janis Danisevskis906147c2018-11-06 14:14:05 -0800271 int delete2(String key, int uid) {
Kenny Root78ad8492013-02-13 17:02:57 -0800272 try {
Janis Danisevskis906147c2018-11-06 14:14:05 -0800273 return mBinder.del(key, uid);
Kenny Root6b776452012-11-02 15:40:32 -0700274 } catch (RemoteException e) {
275 Log.w(TAG, "Cannot connect to keystore", e);
Janis Danisevskis906147c2018-11-06 14:14:05 -0800276 return SYSTEM_ERROR;
Kenny Root6b776452012-11-02 15:40:32 -0700277 }
Chia-chi Yeh44039172009-09-21 11:53:59 +0800278 }
279
Janis Danisevskis906147c2018-11-06 14:14:05 -0800280 public boolean delete(String key, int uid) {
281 int ret = delete2(key, uid);
282 return ret == NO_ERROR || ret == KEY_NOT_FOUND;
283 }
284
Mathew Inwoode420f8b2018-08-16 18:40:47 +0100285 @UnsupportedAppUsage
Chia-chi Yeh44039172009-09-21 11:53:59 +0800286 public boolean delete(String key) {
Kenny Root2eeda722013-04-10 11:30:58 -0700287 return delete(key, UID_SELF);
Kenny Root78ad8492013-02-13 17:02:57 -0800288 }
289
290 public boolean contains(String key, int uid) {
Kenny Root6b776452012-11-02 15:40:32 -0700291 try {
Kenny Root78ad8492013-02-13 17:02:57 -0800292 return mBinder.exist(key, uid) == NO_ERROR;
Kenny Root6b776452012-11-02 15:40:32 -0700293 } catch (RemoteException e) {
294 Log.w(TAG, "Cannot connect to keystore", e);
295 return false;
296 }
Chia-chi Yeh44039172009-09-21 11:53:59 +0800297 }
298
299 public boolean contains(String key) {
Kenny Root2eeda722013-04-10 11:30:58 -0700300 return contains(key, UID_SELF);
Chia-chi Yeh44039172009-09-21 11:53:59 +0800301 }
302
Chad Brubakere35d49f2015-05-12 15:19:52 -0700303 /**
304 * List all entries in the keystore for {@code uid} starting with {@code prefix}.
305 */
306 public String[] list(String prefix, int uid) {
Kenny Root6b776452012-11-02 15:40:32 -0700307 try {
Chad Brubakere35d49f2015-05-12 15:19:52 -0700308 return mBinder.list(prefix, uid);
Kenny Root6b776452012-11-02 15:40:32 -0700309 } catch (RemoteException e) {
310 Log.w(TAG, "Cannot connect to keystore", e);
Chia-chi Yeh44039172009-09-21 11:53:59 +0800311 return null;
Dmitry Dementyevefc43112017-10-27 23:10:28 -0700312 } catch (android.os.ServiceSpecificException e) {
313 Log.w(TAG, "KeyStore exception", e);
314 return null;
Chia-chi Yeh44039172009-09-21 11:53:59 +0800315 }
Chia-chi Yeh44039172009-09-21 11:53:59 +0800316 }
317
Rob Barnesf1a678e2018-11-13 15:57:22 -0700318 /**
Rob Barnesebe26742018-11-13 15:57:22 -0700319 * List uids of all keys that are auth bound to the current user.
Rob Barnesf1a678e2018-11-13 15:57:22 -0700320 * Only system is allowed to call this method.
321 */
322 @UnsupportedAppUsage
323 public int[] listUidsOfAuthBoundKeys() {
Rob Barnesebe26742018-11-13 15:57:22 -0700324 // uids are returned as a list of strings because list of integers
325 // as an output parameter is not supported by aidl-cpp.
326 List<String> uidsOut = new ArrayList<>();
Rob Barnesf1a678e2018-11-13 15:57:22 -0700327 try {
328 int rc = mBinder.listUidsOfAuthBoundKeys(uidsOut);
329 if (rc != NO_ERROR) {
330 Log.w(TAG, String.format("listUidsOfAuthBoundKeys failed with error code %d", rc));
331 return null;
332 }
333 } catch (RemoteException e) {
334 Log.w(TAG, "Cannot connect to keystore", e);
335 return null;
336 } catch (android.os.ServiceSpecificException e) {
337 Log.w(TAG, "KeyStore exception", e);
338 return null;
339 }
Rob Barnesebe26742018-11-13 15:57:22 -0700340 // Turn list of strings into an array of uid integers.
341 return uidsOut.stream().mapToInt(Integer::parseInt).toArray();
Rob Barnesf1a678e2018-11-13 15:57:22 -0700342 }
343
Chad Brubakere35d49f2015-05-12 15:19:52 -0700344 public String[] list(String prefix) {
345 return list(prefix, UID_SELF);
346 }
347
Chad Brubakere35d49f2015-05-12 15:19:52 -0700348 /**
349 * Attempt to lock the keystore for {@code user}.
350 *
Brian Youngfd75c722018-02-23 18:04:20 +0000351 * @param userId Android user to lock.
Chad Brubakere35d49f2015-05-12 15:19:52 -0700352 * @return whether {@code user}'s keystore was locked.
353 */
354 public boolean lock(int userId) {
Kenny Root6b776452012-11-02 15:40:32 -0700355 try {
Chad Brubakere35d49f2015-05-12 15:19:52 -0700356 return mBinder.lock(userId) == NO_ERROR;
Kenny Root6b776452012-11-02 15:40:32 -0700357 } catch (RemoteException e) {
358 Log.w(TAG, "Cannot connect to keystore", e);
359 return false;
360 }
Chia-chi Yeh44039172009-09-21 11:53:59 +0800361 }
362
Chad Brubakere35d49f2015-05-12 15:19:52 -0700363 public boolean lock() {
364 return lock(UserHandle.myUserId());
365 }
366
Chad Brubakera91a8502015-05-07 10:02:22 -0700367 /**
368 * Attempt to unlock the keystore for {@code user} with the password {@code password}.
369 * This is required before keystore entries created with FLAG_ENCRYPTED can be accessed or
370 * created.
371 *
Brian Youngfd75c722018-02-23 18:04:20 +0000372 * @param userId Android user ID to operate on
Chad Brubakera91a8502015-05-07 10:02:22 -0700373 * @param password user's keystore password. Should be the most recent value passed to
374 * {@link #onUserPasswordChanged} for the user.
375 *
376 * @return whether the keystore was unlocked.
377 */
378 public boolean unlock(int userId, String password) {
Kenny Root6b776452012-11-02 15:40:32 -0700379 try {
Dmitry Dementyevefc43112017-10-27 23:10:28 -0700380 password = password != null ? password : "";
Chad Brubakera91a8502015-05-07 10:02:22 -0700381 mError = mBinder.unlock(userId, password);
Kenny Root6b776452012-11-02 15:40:32 -0700382 return mError == NO_ERROR;
383 } catch (RemoteException e) {
384 Log.w(TAG, "Cannot connect to keystore", e);
385 return false;
386 }
Chia-chi Yeh44039172009-09-21 11:53:59 +0800387 }
388
Mathew Inwoode420f8b2018-08-16 18:40:47 +0100389 @UnsupportedAppUsage
Chad Brubakera91a8502015-05-07 10:02:22 -0700390 public boolean unlock(String password) {
391 return unlock(UserHandle.getUserId(Process.myUid()), password);
392 }
393
Chad Brubakere35d49f2015-05-12 15:19:52 -0700394 /**
395 * Check if the keystore for {@code userId} is empty.
396 */
397 public boolean isEmpty(int userId) {
Kenny Root6b776452012-11-02 15:40:32 -0700398 try {
Chad Brubakere35d49f2015-05-12 15:19:52 -0700399 return mBinder.isEmpty(userId) != 0;
Kenny Root6b776452012-11-02 15:40:32 -0700400 } catch (RemoteException e) {
401 Log.w(TAG, "Cannot connect to keystore", e);
402 return false;
403 }
Kenny Root5423e682011-11-14 08:43:13 -0800404 }
405
Mathew Inwood31755f92018-12-20 13:53:36 +0000406 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
Chad Brubakere35d49f2015-05-12 15:19:52 -0700407 public boolean isEmpty() {
408 return isEmpty(UserHandle.myUserId());
409 }
410
Janis Danisevskisb50e9f62017-06-08 17:53:34 -0700411 public String grant(String key, int uid) {
Kenny Root6b776452012-11-02 15:40:32 -0700412 try {
Janis Danisevskisb50e9f62017-06-08 17:53:34 -0700413 String grantAlias = mBinder.grant(key, uid);
414 if (grantAlias == "") return null;
415 return grantAlias;
Kenny Root6b776452012-11-02 15:40:32 -0700416 } catch (RemoteException e) {
417 Log.w(TAG, "Cannot connect to keystore", e);
Janis Danisevskisb50e9f62017-06-08 17:53:34 -0700418 return null;
Kenny Root6b776452012-11-02 15:40:32 -0700419 }
Kenny Root5423e682011-11-14 08:43:13 -0800420 }
421
422 public boolean ungrant(String key, int uid) {
Kenny Root6b776452012-11-02 15:40:32 -0700423 try {
424 return mBinder.ungrant(key, uid) == NO_ERROR;
425 } catch (RemoteException e) {
426 Log.w(TAG, "Cannot connect to keystore", e);
427 return false;
Kenny Root473c7122012-08-17 21:13:48 -0700428 }
Kenny Root473c7122012-08-17 21:13:48 -0700429 }
430
431 /**
432 * Returns the last modification time of the key in milliseconds since the
433 * epoch. Will return -1L if the key could not be found or other error.
434 */
Chad Brubaker5bbf0482015-09-09 14:53:52 -0700435 public long getmtime(String key, int uid) {
Kenny Root6b776452012-11-02 15:40:32 -0700436 try {
Chad Brubaker5bbf0482015-09-09 14:53:52 -0700437 final long millis = mBinder.getmtime(key, uid);
Kenny Roote66769a2013-02-04 15:49:11 -0800438 if (millis == -1L) {
439 return -1L;
440 }
441
442 return millis * 1000L;
Kenny Root6b776452012-11-02 15:40:32 -0700443 } catch (RemoteException e) {
444 Log.w(TAG, "Cannot connect to keystore", e);
445 return -1L;
446 }
Kenny Root473c7122012-08-17 21:13:48 -0700447 }
448
Chad Brubaker5bbf0482015-09-09 14:53:52 -0700449 public long getmtime(String key) {
450 return getmtime(key, UID_SELF);
451 }
452
Alex Klyubin469cbf52015-06-04 12:36:27 -0700453 // TODO: remove this when it's removed from Settings
Kenny Root5cb5cec2013-03-29 11:14:17 -0700454 public boolean isHardwareBacked() {
Kenny Rootb91773b2013-09-05 13:03:16 -0700455 return isHardwareBacked("RSA");
456 }
457
458 public boolean isHardwareBacked(String keyType) {
Kenny Root5cb5cec2013-03-29 11:14:17 -0700459 try {
Kenny Rootb91773b2013-09-05 13:03:16 -0700460 return mBinder.is_hardware_backed(keyType.toUpperCase(Locale.US)) == NO_ERROR;
Kenny Root5cb5cec2013-03-29 11:14:17 -0700461 } catch (RemoteException e) {
462 Log.w(TAG, "Cannot connect to keystore", e);
463 return false;
464 }
465 }
466
Kenny Rootd72317a2013-04-01 15:59:59 -0700467 public boolean clearUid(int uid) {
468 try {
469 return mBinder.clear_uid(uid) == NO_ERROR;
470 } catch (RemoteException e) {
471 Log.w(TAG, "Cannot connect to keystore", e);
472 return false;
473 }
474 }
475
Chia-chi Yeh44039172009-09-21 11:53:59 +0800476 public int getLastError() {
477 return mError;
478 }
Chad Brubakere6a461342015-02-10 21:33:23 -0800479
Janis Danisevskis0aadf932017-12-18 17:28:52 -0800480 public boolean addRngEntropy(byte[] data, int flags) {
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700481 KeystoreResultPromise promise = new KeystoreResultPromise();
Chad Brubakere6a461342015-02-10 21:33:23 -0800482 try {
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700483 mBinder.asBinder().linkToDeath(promise, 0);
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700484 int errorCode = mBinder.addRngEntropy(promise, data, flags);
485 if (errorCode == NO_ERROR) {
486 return promise.getFuture().get().getErrorCode() == NO_ERROR;
487 } else {
488 return false;
489 }
Chad Brubakere6a461342015-02-10 21:33:23 -0800490 } catch (RemoteException e) {
491 Log.w(TAG, "Cannot connect to keystore", e);
492 return false;
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700493 } catch (ExecutionException | InterruptedException e) {
494 Log.e(TAG, "AddRngEntropy completed with exception", e);
495 return false;
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700496 } finally {
497 mBinder.asBinder().unlinkToDeath(promise, 0);
Chad Brubakere6a461342015-02-10 21:33:23 -0800498 }
499 }
500
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700501 private class KeyCharacteristicsCallbackResult {
502 private KeystoreResponse keystoreResponse;
503 private KeyCharacteristics keyCharacteristics;
504
505 public KeyCharacteristicsCallbackResult(KeystoreResponse keystoreResponse,
506 KeyCharacteristics keyCharacteristics) {
507 this.keystoreResponse = keystoreResponse;
508 this.keyCharacteristics = keyCharacteristics;
509 }
510
511 public KeystoreResponse getKeystoreResponse() {
512 return keystoreResponse;
513 }
514
515 public void setKeystoreResponse(KeystoreResponse keystoreResponse) {
516 this.keystoreResponse = keystoreResponse;
517 }
518
519 public KeyCharacteristics getKeyCharacteristics() {
520 return keyCharacteristics;
521 }
522
523 public void setKeyCharacteristics(KeyCharacteristics keyCharacteristics) {
524 this.keyCharacteristics = keyCharacteristics;
525 }
526 }
527
528 private class KeyCharacteristicsPromise
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700529 extends android.security.keystore.IKeystoreKeyCharacteristicsCallback.Stub
530 implements IBinder.DeathRecipient {
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700531 final private CompletableFuture<KeyCharacteristicsCallbackResult> future =
532 new CompletableFuture<KeyCharacteristicsCallbackResult>();
533 @Override
534 public void onFinished(KeystoreResponse keystoreResponse,
535 KeyCharacteristics keyCharacteristics)
536 throws android.os.RemoteException {
537 future.complete(
538 new KeyCharacteristicsCallbackResult(keystoreResponse, keyCharacteristics));
539 }
540 public final CompletableFuture<KeyCharacteristicsCallbackResult> getFuture() {
541 return future;
542 }
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700543 @Override
544 public void binderDied() {
545 future.completeExceptionally(new RemoteException("Keystore died"));
546 }
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700547 };
548
549 private int generateKeyInternal(String alias, KeymasterArguments args, byte[] entropy, int uid,
550 int flags, KeyCharacteristics outCharacteristics)
551 throws RemoteException, ExecutionException, InterruptedException {
552 KeyCharacteristicsPromise promise = new KeyCharacteristicsPromise();
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700553 int error = NO_ERROR;
554 KeyCharacteristicsCallbackResult result = null;
555 try {
556 mBinder.asBinder().linkToDeath(promise, 0);
557 error = mBinder.generateKey(promise, alias, args, entropy, uid, flags);
558 if (error != NO_ERROR) {
559 Log.e(TAG, "generateKeyInternal failed on request " + error);
560 return error;
561 }
562 result = promise.getFuture().get();
563 } finally {
564 mBinder.asBinder().unlinkToDeath(promise, 0);
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700565 }
566
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700567 error = result.getKeystoreResponse().getErrorCode();
568 if (error != NO_ERROR) {
569 Log.e(TAG, "generateKeyInternal failed on response " + error);
570 return error;
571 }
572 KeyCharacteristics characteristics = result.getKeyCharacteristics();
573 if (characteristics == null) {
Solomon Kinard2bd792f32019-07-03 11:22:34 -0700574 Log.e(TAG, "generateKeyInternal got empty key characteristics " + error);
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700575 return SYSTEM_ERROR;
576 }
577 outCharacteristics.shallowCopyFrom(characteristics);
578 return NO_ERROR;
579 }
580
Chad Brubakerdae79e52015-03-27 14:28:35 -0700581 public int generateKey(String alias, KeymasterArguments args, byte[] entropy, int uid,
582 int flags, KeyCharacteristics outCharacteristics) {
Chad Brubakere6a461342015-02-10 21:33:23 -0800583 try {
Dmitry Dementyevefc43112017-10-27 23:10:28 -0700584 entropy = entropy != null ? entropy : new byte[0];
585 args = args != null ? args : new KeymasterArguments();
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700586 int error = generateKeyInternal(alias, args, entropy, uid, flags, outCharacteristics);
Janis Danisevskisd2575382018-10-08 07:56:58 -0700587 if (error == KEY_ALREADY_EXISTS) {
588 mBinder.del(alias, uid);
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700589 error = generateKeyInternal(alias, args, entropy, uid, flags, outCharacteristics);
Janis Danisevskisd2575382018-10-08 07:56:58 -0700590 }
591 return error;
Chad Brubakere6a461342015-02-10 21:33:23 -0800592 } catch (RemoteException e) {
593 Log.w(TAG, "Cannot connect to keystore", e);
594 return SYSTEM_ERROR;
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700595 } catch (ExecutionException | InterruptedException e) {
596 Log.e(TAG, "generateKey completed with exception", e);
597 return SYSTEM_ERROR;
Chad Brubakere6a461342015-02-10 21:33:23 -0800598 }
599 }
600
Chad Brubakerdae79e52015-03-27 14:28:35 -0700601 public int generateKey(String alias, KeymasterArguments args, byte[] entropy, int flags,
Chad Brubakere6a461342015-02-10 21:33:23 -0800602 KeyCharacteristics outCharacteristics) {
Chad Brubakerdae79e52015-03-27 14:28:35 -0700603 return generateKey(alias, args, entropy, UID_SELF, flags, outCharacteristics);
Chad Brubakere6a461342015-02-10 21:33:23 -0800604 }
605
Chad Brubaker5e73c0e2015-03-21 22:46:43 -0700606 public int getKeyCharacteristics(String alias, KeymasterBlob clientId, KeymasterBlob appId,
Chad Brubaker5bbf0482015-09-09 14:53:52 -0700607 int uid, KeyCharacteristics outCharacteristics) {
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700608 KeyCharacteristicsPromise promise = new KeyCharacteristicsPromise();
Chad Brubakere6a461342015-02-10 21:33:23 -0800609 try {
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700610 mBinder.asBinder().linkToDeath(promise, 0);
Dmitry Dementyevefc43112017-10-27 23:10:28 -0700611 clientId = clientId != null ? clientId : new KeymasterBlob(new byte[0]);
612 appId = appId != null ? appId : new KeymasterBlob(new byte[0]);
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700613
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700614 int error = mBinder.getKeyCharacteristics(promise, alias, clientId, appId, uid);
615 if (error != NO_ERROR) return error;
616
617 KeyCharacteristicsCallbackResult result = promise.getFuture().get();
618 error = result.getKeystoreResponse().getErrorCode();
619 if (error != NO_ERROR) return error;
620
621 KeyCharacteristics characteristics = result.getKeyCharacteristics();
622 if (characteristics == null) return SYSTEM_ERROR;
623 outCharacteristics.shallowCopyFrom(characteristics);
624 return NO_ERROR;
Chad Brubakere6a461342015-02-10 21:33:23 -0800625 } catch (RemoteException e) {
626 Log.w(TAG, "Cannot connect to keystore", e);
627 return SYSTEM_ERROR;
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700628 } catch (ExecutionException | InterruptedException e) {
629 Log.e(TAG, "GetKeyCharacteristics completed with exception", e);
630 return SYSTEM_ERROR;
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700631 } finally {
632 mBinder.asBinder().unlinkToDeath(promise, 0);
Chad Brubakere6a461342015-02-10 21:33:23 -0800633 }
634 }
635
Chad Brubaker5bbf0482015-09-09 14:53:52 -0700636 public int getKeyCharacteristics(String alias, KeymasterBlob clientId, KeymasterBlob appId,
637 KeyCharacteristics outCharacteristics) {
638 return getKeyCharacteristics(alias, clientId, appId, UID_SELF, outCharacteristics);
639 }
640
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700641 private int importKeyInternal(String alias, KeymasterArguments args, int format, byte[] keyData,
642 int uid, int flags, KeyCharacteristics outCharacteristics)
643 throws RemoteException, ExecutionException, InterruptedException {
644 KeyCharacteristicsPromise promise = new KeyCharacteristicsPromise();
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700645 mBinder.asBinder().linkToDeath(promise, 0);
646 try {
647 int error = mBinder.importKey(promise, alias, args, format, keyData, uid, flags);
648 if (error != NO_ERROR) return error;
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700649
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700650 KeyCharacteristicsCallbackResult result = promise.getFuture().get();
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700651
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700652 error = result.getKeystoreResponse().getErrorCode();
653 if (error != NO_ERROR) return error;
654
655 KeyCharacteristics characteristics = result.getKeyCharacteristics();
656 if (characteristics == null) return SYSTEM_ERROR;
657 outCharacteristics.shallowCopyFrom(characteristics);
658 return NO_ERROR;
659 } finally {
660 mBinder.asBinder().unlinkToDeath(promise, 0);
661 }
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700662 }
663
Chad Brubakere6a461342015-02-10 21:33:23 -0800664 public int importKey(String alias, KeymasterArguments args, int format, byte[] keyData,
665 int uid, int flags, KeyCharacteristics outCharacteristics) {
666 try {
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700667 int error = importKeyInternal(alias, args, format, keyData, uid, flags,
Chad Brubakere6a461342015-02-10 21:33:23 -0800668 outCharacteristics);
Janis Danisevskisd2575382018-10-08 07:56:58 -0700669 if (error == KEY_ALREADY_EXISTS) {
670 mBinder.del(alias, uid);
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700671 error = importKeyInternal(alias, args, format, keyData, uid, flags,
Janis Danisevskisd2575382018-10-08 07:56:58 -0700672 outCharacteristics);
673 }
674 return error;
Chad Brubakere6a461342015-02-10 21:33:23 -0800675 } catch (RemoteException e) {
676 Log.w(TAG, "Cannot connect to keystore", e);
677 return SYSTEM_ERROR;
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700678 } catch (ExecutionException | InterruptedException e) {
679 Log.e(TAG, "ImportKey completed with exception", e);
680 return SYSTEM_ERROR;
Chad Brubakere6a461342015-02-10 21:33:23 -0800681 }
682 }
683
684 public int importKey(String alias, KeymasterArguments args, int format, byte[] keyData,
685 int flags, KeyCharacteristics outCharacteristics) {
686 return importKey(alias, args, format, keyData, UID_SELF, flags, outCharacteristics);
687 }
688
Janis Danisevskis1864c952018-08-09 11:14:49 -0700689 private String getAlgorithmFromPKCS8(byte[] keyData) {
690 try {
691 final ASN1InputStream bIn = new ASN1InputStream(new ByteArrayInputStream(keyData));
692 final PrivateKeyInfo pki = PrivateKeyInfo.getInstance(bIn.readObject());
693 final String algOid = pki.getPrivateKeyAlgorithm().getAlgorithm().getId();
694 return new AlgorithmId(new ObjectIdentifier(algOid)).getName();
695 } catch (IOException e) {
696 Log.e(TAG, "getAlgorithmFromPKCS8 Failed to parse key data");
697 Log.e(TAG, Log.getStackTraceString(e));
698 return null;
699 }
700 }
701
702 private KeymasterArguments makeLegacyArguments(String algorithm) {
703 KeymasterArguments args = new KeymasterArguments();
704 args.addEnum(KeymasterDefs.KM_TAG_ALGORITHM,
705 KeyProperties.KeyAlgorithm.toKeymasterAsymmetricKeyAlgorithm(algorithm));
706 args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_SIGN);
707 args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_VERIFY);
708 args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_ENCRYPT);
709 args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_DECRYPT);
710 args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_NONE);
711 if (algorithm.equalsIgnoreCase(KeyProperties.KEY_ALGORITHM_RSA)) {
712 args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_RSA_OAEP);
713 args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_ENCRYPT);
714 args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_SIGN);
715 args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_RSA_PSS);
716 }
717 args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_NONE);
718 args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_MD5);
719 args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA1);
720 args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA_2_224);
721 args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA_2_256);
722 args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA_2_384);
723 args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA_2_512);
724 args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED);
Janis Danisevskis2b106ad2018-11-15 09:27:16 -0800725 args.addDate(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME, new Date(Long.MAX_VALUE));
726 args.addDate(KeymasterDefs.KM_TAG_USAGE_EXPIRE_DATETIME, new Date(Long.MAX_VALUE));
727 args.addDate(KeymasterDefs.KM_TAG_ACTIVE_DATETIME, new Date(0));
Janis Danisevskis1864c952018-08-09 11:14:49 -0700728 return args;
729 }
730
731 public boolean importKey(String alias, byte[] keyData, int uid, int flags) {
732 String algorithm = getAlgorithmFromPKCS8(keyData);
733 if (algorithm == null) return false;
734 KeymasterArguments args = makeLegacyArguments(algorithm);
735 KeyCharacteristics out = new KeyCharacteristics();
736 int result = importKey(alias, args, KeymasterDefs.KM_KEY_FORMAT_PKCS8, keyData, uid,
737 flags, out);
738 if (result != NO_ERROR) {
739 Log.e(TAG, Log.getStackTraceString(
740 new KeyStoreException(result, "legacy key import failed")));
741 return false;
742 }
743 return true;
744 }
745
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700746 private int importWrappedKeyInternal(String wrappedKeyAlias, byte[] wrappedKey,
747 String wrappingKeyAlias,
748 byte[] maskingKey, KeymasterArguments args, long rootSid, long fingerprintSid,
749 KeyCharacteristics outCharacteristics)
750 throws RemoteException, ExecutionException, InterruptedException {
751 KeyCharacteristicsPromise promise = new KeyCharacteristicsPromise();
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700752 mBinder.asBinder().linkToDeath(promise, 0);
753 try {
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700754 int error = mBinder.importWrappedKey(promise, wrappedKeyAlias, wrappedKey,
755 wrappingKeyAlias, maskingKey, args, rootSid, fingerprintSid);
756 if (error != NO_ERROR) return error;
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700757
Janis Danisevskisf924b7e2019-04-17 14:06:09 -0700758 KeyCharacteristicsCallbackResult result = promise.getFuture().get();
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700759
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700760 error = result.getKeystoreResponse().getErrorCode();
761 if (error != NO_ERROR) return error;
762
763 KeyCharacteristics characteristics = result.getKeyCharacteristics();
764 if (characteristics == null) return SYSTEM_ERROR;
765 outCharacteristics.shallowCopyFrom(characteristics);
766 return NO_ERROR;
767 } finally {
768 mBinder.asBinder().unlinkToDeath(promise, 0);
769 }
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700770 }
771
Frank Salim21d9c1d2017-12-19 22:38:09 -0800772 public int importWrappedKey(String wrappedKeyAlias, byte[] wrappedKey,
773 String wrappingKeyAlias,
774 byte[] maskingKey, KeymasterArguments args, long rootSid, long fingerprintSid, int uid,
775 KeyCharacteristics outCharacteristics) {
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700776 // TODO b/119217337 uid parameter gets silently ignored.
Frank Salim21d9c1d2017-12-19 22:38:09 -0800777 try {
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700778 int error = importWrappedKeyInternal(wrappedKeyAlias, wrappedKey, wrappingKeyAlias,
Frank Salim21d9c1d2017-12-19 22:38:09 -0800779 maskingKey, args, rootSid, fingerprintSid, outCharacteristics);
Janis Danisevskisd2575382018-10-08 07:56:58 -0700780 if (error == KEY_ALREADY_EXISTS) {
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700781 mBinder.del(wrappedKeyAlias, UID_SELF);
782 error = importWrappedKeyInternal(wrappedKeyAlias, wrappedKey, wrappingKeyAlias,
Janis Danisevskisd2575382018-10-08 07:56:58 -0700783 maskingKey, args, rootSid, fingerprintSid, outCharacteristics);
784 }
785 return error;
Frank Salim21d9c1d2017-12-19 22:38:09 -0800786 } catch (RemoteException e) {
787 Log.w(TAG, "Cannot connect to keystore", e);
788 return SYSTEM_ERROR;
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700789 } catch (ExecutionException | InterruptedException e) {
790 Log.e(TAG, "ImportWrappedKey completed with exception", e);
791 return SYSTEM_ERROR;
Frank Salim21d9c1d2017-12-19 22:38:09 -0800792 }
793 }
794
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700795 private class ExportKeyPromise
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700796 extends android.security.keystore.IKeystoreExportKeyCallback.Stub
797 implements IBinder.DeathRecipient {
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700798 final private CompletableFuture<ExportResult> future = new CompletableFuture<ExportResult>();
799 @Override
800 public void onFinished(ExportResult exportKeyResult) throws android.os.RemoteException {
801 future.complete(exportKeyResult);
802 }
803 public final CompletableFuture<ExportResult> getFuture() {
804 return future;
805 }
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700806 @Override
807 public void binderDied() {
808 future.completeExceptionally(new RemoteException("Keystore died"));
809 }
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700810 };
811
Chad Brubaker5e73c0e2015-03-21 22:46:43 -0700812 public ExportResult exportKey(String alias, int format, KeymasterBlob clientId,
Chad Brubaker5bbf0482015-09-09 14:53:52 -0700813 KeymasterBlob appId, int uid) {
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700814 ExportKeyPromise promise = new ExportKeyPromise();
Chad Brubakere6a461342015-02-10 21:33:23 -0800815 try {
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700816 mBinder.asBinder().linkToDeath(promise, 0);
Dmitry Dementyevefc43112017-10-27 23:10:28 -0700817 clientId = clientId != null ? clientId : new KeymasterBlob(new byte[0]);
818 appId = appId != null ? appId : new KeymasterBlob(new byte[0]);
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700819 int error = mBinder.exportKey(promise, alias, format, clientId, appId, uid);
820 if (error == NO_ERROR) {
821 return promise.getFuture().get();
822 } else {
823 return new ExportResult(error);
824 }
Chad Brubaker5bbf0482015-09-09 14:53:52 -0700825 } catch (RemoteException e) {
826 Log.w(TAG, "Cannot connect to keystore", e);
827 return null;
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700828 } catch (ExecutionException | InterruptedException e) {
829 Log.e(TAG, "ExportKey completed with exception", e);
830 return null;
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700831 } finally {
832 mBinder.asBinder().unlinkToDeath(promise, 0);
Chad Brubaker5bbf0482015-09-09 14:53:52 -0700833 }
834 }
835 public ExportResult exportKey(String alias, int format, KeymasterBlob clientId,
836 KeymasterBlob appId) {
837 return exportKey(alias, format, clientId, appId, UID_SELF);
838 }
839
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700840 private class OperationPromise
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700841 extends android.security.keystore.IKeystoreOperationResultCallback.Stub
842 implements IBinder.DeathRecipient {
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700843 final private CompletableFuture<OperationResult> future = new CompletableFuture<OperationResult>();
844 @Override
845 public void onFinished(OperationResult operationResult) throws android.os.RemoteException {
846 future.complete(operationResult);
847 }
848 public final CompletableFuture<OperationResult> getFuture() {
849 return future;
850 }
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700851 @Override
852 public void binderDied() {
853 future.completeExceptionally(new RemoteException("Keystore died"));
854 }
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700855 };
856
Chad Brubaker5bbf0482015-09-09 14:53:52 -0700857 public OperationResult begin(String alias, int purpose, boolean pruneable,
858 KeymasterArguments args, byte[] entropy, int uid) {
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700859 OperationPromise promise = new OperationPromise();
Chad Brubaker5bbf0482015-09-09 14:53:52 -0700860 try {
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700861 mBinder.asBinder().linkToDeath(promise, 0);
Dmitry Dementyevefc43112017-10-27 23:10:28 -0700862 args = args != null ? args : new KeymasterArguments();
863 entropy = entropy != null ? entropy : new byte[0];
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700864 int errorCode = mBinder.begin(promise, getToken(), alias, purpose, pruneable, args,
865 entropy, uid);
866 if (errorCode == NO_ERROR) {
867 return promise.getFuture().get();
868 } else {
869 return new OperationResult(errorCode);
870 }
Chad Brubakere6a461342015-02-10 21:33:23 -0800871 } catch (RemoteException e) {
872 Log.w(TAG, "Cannot connect to keystore", e);
873 return null;
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700874 } catch (ExecutionException | InterruptedException e) {
875 Log.e(TAG, "Begin completed with exception", e);
876 return null;
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700877 } finally {
878 mBinder.asBinder().unlinkToDeath(promise, 0);
Chad Brubakere6a461342015-02-10 21:33:23 -0800879 }
880 }
881
882 public OperationResult begin(String alias, int purpose, boolean pruneable,
Chad Brubaker966486e2015-06-01 12:57:06 -0700883 KeymasterArguments args, byte[] entropy) {
Dmitry Dementyevefc43112017-10-27 23:10:28 -0700884 entropy = entropy != null ? entropy : new byte[0];
885 args = args != null ? args : new KeymasterArguments();
Chad Brubaker5bbf0482015-09-09 14:53:52 -0700886 return begin(alias, purpose, pruneable, args, entropy, UID_SELF);
Chad Brubakere6a461342015-02-10 21:33:23 -0800887 }
888
889 public OperationResult update(IBinder token, KeymasterArguments arguments, byte[] input) {
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700890 OperationPromise promise = new OperationPromise();
Chad Brubakere6a461342015-02-10 21:33:23 -0800891 try {
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700892 mBinder.asBinder().linkToDeath(promise, 0);
Dmitry Dementyevefc43112017-10-27 23:10:28 -0700893 arguments = arguments != null ? arguments : new KeymasterArguments();
894 input = input != null ? input : new byte[0];
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700895 int errorCode = mBinder.update(promise, token, arguments, input);
896 if (errorCode == NO_ERROR) {
897 return promise.getFuture().get();
898 } else {
899 return new OperationResult(errorCode);
900 }
Chad Brubakere6a461342015-02-10 21:33:23 -0800901 } catch (RemoteException e) {
902 Log.w(TAG, "Cannot connect to keystore", e);
903 return null;
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700904 } catch (ExecutionException | InterruptedException e) {
905 Log.e(TAG, "Update completed with exception", e);
906 return null;
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700907 } finally {
908 mBinder.asBinder().unlinkToDeath(promise, 0);
Chad Brubakere6a461342015-02-10 21:33:23 -0800909 }
910 }
911
Rob Barnes92743aeb2019-11-14 15:13:52 -0700912 /**
913 * Android KeyStore finish operation.
914 *
915 * @param token Authentication token.
916 * @param arguments Keymaster arguments
917 * @param input Optional additional input data.
918 * @param signature Optional signature to be verified.
919 * @param entropy Optional additional entropy
920 * @return OperationResult that will indicate success or error of the operation.
921 */
922 public OperationResult finish(IBinder token, KeymasterArguments arguments, byte[] input,
923 byte[] signature, byte[] entropy) {
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700924 OperationPromise promise = new OperationPromise();
Chad Brubakere6a461342015-02-10 21:33:23 -0800925 try {
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700926 mBinder.asBinder().linkToDeath(promise, 0);
Dmitry Dementyevefc43112017-10-27 23:10:28 -0700927 arguments = arguments != null ? arguments : new KeymasterArguments();
928 entropy = entropy != null ? entropy : new byte[0];
Rob Barnes92743aeb2019-11-14 15:13:52 -0700929 input = input != null ? input : new byte[0];
Dmitry Dementyevefc43112017-10-27 23:10:28 -0700930 signature = signature != null ? signature : new byte[0];
Rob Barnes92743aeb2019-11-14 15:13:52 -0700931 int errorCode = mBinder.finish(promise, token, arguments, input, signature, entropy);
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700932 if (errorCode == NO_ERROR) {
933 return promise.getFuture().get();
934 } else {
935 return new OperationResult(errorCode);
936 }
Chad Brubakere6a461342015-02-10 21:33:23 -0800937 } catch (RemoteException e) {
938 Log.w(TAG, "Cannot connect to keystore", e);
939 return null;
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700940 } catch (ExecutionException | InterruptedException e) {
941 Log.e(TAG, "Finish completed with exception", e);
942 return null;
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700943 } finally {
944 mBinder.asBinder().unlinkToDeath(promise, 0);
Chad Brubakere6a461342015-02-10 21:33:23 -0800945 }
946 }
947
Chad Brubaker8a077012015-05-29 12:32:51 -0700948 public OperationResult finish(IBinder token, KeymasterArguments arguments, byte[] signature) {
Rob Barnes92743aeb2019-11-14 15:13:52 -0700949 return finish(token, arguments, null, signature, null);
Chad Brubaker8a077012015-05-29 12:32:51 -0700950 }
951
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700952 private class KeystoreResultPromise
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700953 extends android.security.keystore.IKeystoreResponseCallback.Stub
954 implements IBinder.DeathRecipient {
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700955 final private CompletableFuture<KeystoreResponse> future = new CompletableFuture<KeystoreResponse>();
956 @Override
957 public void onFinished(KeystoreResponse keystoreResponse) throws android.os.RemoteException {
958 future.complete(keystoreResponse);
959 }
960 public final CompletableFuture<KeystoreResponse> getFuture() {
961 return future;
962 }
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700963 @Override
964 public void binderDied() {
965 future.completeExceptionally(new RemoteException("Keystore died"));
966 }
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700967 };
968
Chad Brubakere6a461342015-02-10 21:33:23 -0800969 public int abort(IBinder token) {
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700970 KeystoreResultPromise promise = new KeystoreResultPromise();
Chad Brubakere6a461342015-02-10 21:33:23 -0800971 try {
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700972 mBinder.asBinder().linkToDeath(promise, 0);
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700973 int errorCode = mBinder.abort(promise, token);
974 if (errorCode == NO_ERROR) {
975 return promise.getFuture().get().getErrorCode();
976 } else {
977 return errorCode;
978 }
Chad Brubakere6a461342015-02-10 21:33:23 -0800979 } catch (RemoteException e) {
980 Log.w(TAG, "Cannot connect to keystore", e);
981 return SYSTEM_ERROR;
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700982 } catch (ExecutionException | InterruptedException e) {
983 Log.e(TAG, "Abort completed with exception", e);
984 return SYSTEM_ERROR;
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700985 } finally {
986 mBinder.asBinder().unlinkToDeath(promise, 0);
Chad Brubakere6a461342015-02-10 21:33:23 -0800987 }
988 }
Chad Brubaker5654b362015-03-17 16:59:52 -0700989
990 /**
Chad Brubaker5654b362015-03-17 16:59:52 -0700991 * Add an authentication record to the keystore authorization table.
992 *
993 * @param authToken The packed bytes of a hw_auth_token_t to be provided to keymaster.
994 * @return {@code KeyStore.NO_ERROR} on success, otherwise an error value corresponding to
995 * a {@code KeymasterDefs.KM_ERROR_} value or {@code KeyStore} ResponseCode.
996 */
Brian Youngda82e2c2018-02-22 23:36:34 +0000997 public int addAuthToken(byte[] authToken) {
Chad Brubaker5654b362015-03-17 16:59:52 -0700998 try {
Brian Youngda82e2c2018-02-22 23:36:34 +0000999 return mBinder.addAuthToken(authToken);
Chad Brubaker5654b362015-03-17 16:59:52 -07001000 } catch (RemoteException e) {
1001 Log.w(TAG, "Cannot connect to keystore", e);
1002 return SYSTEM_ERROR;
1003 }
1004 }
Alex Klyubinb4834ae2015-04-02 15:53:46 -07001005
Alex Klyubinad9ba102015-04-21 15:17:24 -07001006 /**
Chad Brubakera91a8502015-05-07 10:02:22 -07001007 * Notify keystore that a user's password has changed.
1008 *
1009 * @param userId the user whose password changed.
1010 * @param newPassword the new password or "" if the password was removed.
1011 */
1012 public boolean onUserPasswordChanged(int userId, String newPassword) {
1013 // Parcel.cpp doesn't support deserializing null strings and treats them as "". Make that
1014 // explicit here.
1015 if (newPassword == null) {
1016 newPassword = "";
1017 }
1018 try {
1019 return mBinder.onUserPasswordChanged(userId, newPassword) == NO_ERROR;
1020 } catch (RemoteException e) {
1021 Log.w(TAG, "Cannot connect to keystore", e);
1022 return false;
1023 }
1024 }
1025
Chad Brubaker83ce0952015-05-12 13:00:02 -07001026 /**
1027 * Notify keystore that a user was added.
1028 *
1029 * @param userId the new user.
1030 * @param parentId the parent of the new user, or -1 if the user has no parent. If parentId is
1031 * specified then the new user's keystore will be intialized with the same secure lockscreen
1032 * password as the parent.
1033 */
1034 public void onUserAdded(int userId, int parentId) {
1035 try {
1036 mBinder.onUserAdded(userId, parentId);
1037 } catch (RemoteException e) {
1038 Log.w(TAG, "Cannot connect to keystore", e);
1039 }
1040 }
1041
1042 /**
1043 * Notify keystore that a user was added.
1044 *
1045 * @param userId the new user.
1046 */
1047 public void onUserAdded(int userId) {
1048 onUserAdded(userId, -1);
1049 }
1050
1051 /**
1052 * Notify keystore that a user was removed.
1053 *
1054 * @param userId the removed user.
1055 */
1056 public void onUserRemoved(int userId) {
1057 try {
1058 mBinder.onUserRemoved(userId);
1059 } catch (RemoteException e) {
1060 Log.w(TAG, "Cannot connect to keystore", e);
1061 }
1062 }
1063
Chad Brubakera91a8502015-05-07 10:02:22 -07001064 public boolean onUserPasswordChanged(String newPassword) {
1065 return onUserPasswordChanged(UserHandle.getUserId(Process.myUid()), newPassword);
1066 }
1067
Rubin Xuc3986272019-11-05 10:15:36 +00001068 /**
1069 * Notify keystore about the latest user locked state. This is to support keyguard-bound key.
1070 */
1071 public void onUserLockedStateChanged(int userHandle, boolean locked) {
1072 try {
1073 mBinder.onKeyguardVisibilityChanged(locked, userHandle);
1074 } catch (RemoteException e) {
1075 Log.w(TAG, "Failed to update user locked state " + userHandle, e);
1076 }
1077 }
1078
Janis Danisevskisb0358e72018-11-02 10:34:07 -07001079 private class KeyAttestationCallbackResult {
1080 private KeystoreResponse keystoreResponse;
1081 private KeymasterCertificateChain certificateChain;
1082
1083 public KeyAttestationCallbackResult(KeystoreResponse keystoreResponse,
1084 KeymasterCertificateChain certificateChain) {
1085 this.keystoreResponse = keystoreResponse;
1086 this.certificateChain = certificateChain;
1087 }
1088
1089 public KeystoreResponse getKeystoreResponse() {
1090 return keystoreResponse;
1091 }
1092
1093 public void setKeystoreResponse(KeystoreResponse keystoreResponse) {
1094 this.keystoreResponse = keystoreResponse;
1095 }
1096
1097 public KeymasterCertificateChain getCertificateChain() {
1098 return certificateChain;
1099 }
1100
1101 public void setCertificateChain(KeymasterCertificateChain certificateChain) {
1102 this.certificateChain = certificateChain;
1103 }
1104 }
1105
1106 private class CertificateChainPromise
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -07001107 extends android.security.keystore.IKeystoreCertificateChainCallback.Stub
1108 implements IBinder.DeathRecipient {
Janis Danisevskisb0358e72018-11-02 10:34:07 -07001109 final private CompletableFuture<KeyAttestationCallbackResult> future = new CompletableFuture<KeyAttestationCallbackResult>();
1110 @Override
1111 public void onFinished(KeystoreResponse keystoreResponse,
1112 KeymasterCertificateChain certificateChain) throws android.os.RemoteException {
1113 future.complete(new KeyAttestationCallbackResult(keystoreResponse, certificateChain));
1114 }
1115 public final CompletableFuture<KeyAttestationCallbackResult> getFuture() {
1116 return future;
1117 }
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -07001118 @Override
1119 public void binderDied() {
1120 future.completeExceptionally(new RemoteException("Keystore died"));
1121 }
Janis Danisevskisb0358e72018-11-02 10:34:07 -07001122 };
1123
1124
Shawn Willden8d8c7472016-02-02 08:27:39 -07001125 public int attestKey(
1126 String alias, KeymasterArguments params, KeymasterCertificateChain outChain) {
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -07001127 CertificateChainPromise promise = new CertificateChainPromise();
Shawn Willden8d8c7472016-02-02 08:27:39 -07001128 try {
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -07001129 mBinder.asBinder().linkToDeath(promise, 0);
Dmitry Dementyevefc43112017-10-27 23:10:28 -07001130 if (params == null) {
1131 params = new KeymasterArguments();
1132 }
1133 if (outChain == null) {
1134 outChain = new KeymasterCertificateChain();
1135 }
Janis Danisevskisb0358e72018-11-02 10:34:07 -07001136 int error = mBinder.attestKey(promise, alias, params);
1137 if (error != NO_ERROR) return error;
1138 KeyAttestationCallbackResult result = promise.getFuture().get();
1139 error = result.getKeystoreResponse().getErrorCode();
1140 if (error == NO_ERROR) {
1141 outChain.shallowCopyFrom(result.getCertificateChain());
1142 }
1143 return error;
Shawn Willden8d8c7472016-02-02 08:27:39 -07001144 } catch (RemoteException e) {
1145 Log.w(TAG, "Cannot connect to keystore", e);
1146 return SYSTEM_ERROR;
Janis Danisevskisb0358e72018-11-02 10:34:07 -07001147 } catch (ExecutionException | InterruptedException e) {
1148 Log.e(TAG, "AttestKey completed with exception", e);
1149 return SYSTEM_ERROR;
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -07001150 } finally {
1151 mBinder.asBinder().unlinkToDeath(promise, 0);
Shawn Willden8d8c7472016-02-02 08:27:39 -07001152 }
1153 }
1154
Bartosz Fabianowski237f4b362017-04-24 13:57:46 +02001155 public int attestDeviceIds(KeymasterArguments params, KeymasterCertificateChain outChain) {
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -07001156 CertificateChainPromise promise = new CertificateChainPromise();
Bartosz Fabianowski237f4b362017-04-24 13:57:46 +02001157 try {
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -07001158 mBinder.asBinder().linkToDeath(promise, 0);
Dmitry Dementyevefc43112017-10-27 23:10:28 -07001159 if (params == null) {
1160 params = new KeymasterArguments();
1161 }
1162 if (outChain == null) {
1163 outChain = new KeymasterCertificateChain();
1164 }
Janis Danisevskisb0358e72018-11-02 10:34:07 -07001165 int error = mBinder.attestDeviceIds(promise, params);
1166 if (error != NO_ERROR) return error;
1167 KeyAttestationCallbackResult result = promise.getFuture().get();
1168 error = result.getKeystoreResponse().getErrorCode();
1169 if (error == NO_ERROR) {
1170 outChain.shallowCopyFrom(result.getCertificateChain());
1171 }
1172 return error;
Bartosz Fabianowski237f4b362017-04-24 13:57:46 +02001173 } catch (RemoteException e) {
1174 Log.w(TAG, "Cannot connect to keystore", e);
1175 return SYSTEM_ERROR;
Janis Danisevskisb0358e72018-11-02 10:34:07 -07001176 } catch (ExecutionException | InterruptedException e) {
1177 Log.e(TAG, "AttestDevicdeIds completed with exception", e);
1178 return SYSTEM_ERROR;
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -07001179 } finally {
1180 mBinder.asBinder().unlinkToDeath(promise, 0);
Bartosz Fabianowski237f4b362017-04-24 13:57:46 +02001181 }
1182 }
1183
Tucker Sylvestrob32aae22016-06-23 17:23:33 -04001184 /**
1185 * Notify keystore that the device went off-body.
1186 */
1187 public void onDeviceOffBody() {
1188 try {
1189 mBinder.onDeviceOffBody();
1190 } catch (RemoteException e) {
1191 Log.w(TAG, "Cannot connect to keystore", e);
1192 }
1193 }
Shawn Willden8d8c7472016-02-02 08:27:39 -07001194
Janis Danisevskis7dacad82018-01-24 15:12:11 -08001195 // Keep in sync with confirmationui/1.0/types.hal.
1196 public static final int CONFIRMATIONUI_OK = 0;
1197 public static final int CONFIRMATIONUI_CANCELED = 1;
1198 public static final int CONFIRMATIONUI_ABORTED = 2;
1199 public static final int CONFIRMATIONUI_OPERATION_PENDING = 3;
1200 public static final int CONFIRMATIONUI_IGNORED = 4;
1201 public static final int CONFIRMATIONUI_SYSTEM_ERROR = 5;
1202 public static final int CONFIRMATIONUI_UNIMPLEMENTED = 6;
1203 public static final int CONFIRMATIONUI_UNEXPECTED = 7;
1204 public static final int CONFIRMATIONUI_UIERROR = 0x10000;
1205 public static final int CONFIRMATIONUI_UIERROR_MISSING_GLYPH = 0x10001;
1206 public static final int CONFIRMATIONUI_UIERROR_MESSAGE_TOO_LONG = 0x10002;
1207 public static final int CONFIRMATIONUI_UIERROR_MALFORMED_UTF8_ENCODING = 0x10003;
1208
1209 /**
1210 * Requests keystore call into the confirmationui HAL to display a prompt.
1211 *
1212 * @param listener the binder to use for callbacks.
1213 * @param promptText the prompt to display.
1214 * @param extraData extra data / nonce from application.
1215 * @param locale the locale as a BCP 47 langauge tag.
1216 * @param uiOptionsAsFlags the UI options to use, as flags.
1217 * @return one of the {@code CONFIRMATIONUI_*} constants, for
1218 * example {@code KeyStore.CONFIRMATIONUI_OK}.
1219 */
1220 public int presentConfirmationPrompt(IBinder listener, String promptText, byte[] extraData,
1221 String locale, int uiOptionsAsFlags) {
1222 try {
1223 return mBinder.presentConfirmationPrompt(listener, promptText, extraData, locale,
1224 uiOptionsAsFlags);
1225 } catch (RemoteException e) {
1226 Log.w(TAG, "Cannot connect to keystore", e);
1227 return CONFIRMATIONUI_SYSTEM_ERROR;
1228 }
1229 }
1230
1231 /**
1232 * Requests keystore call into the confirmationui HAL to cancel displaying a prompt.
1233 *
1234 * @param listener the binder passed to the {@link #presentConfirmationPrompt} method.
1235 * @return one of the {@code CONFIRMATIONUI_*} constants, for
1236 * example {@code KeyStore.CONFIRMATIONUI_OK}.
1237 */
1238 public int cancelConfirmationPrompt(IBinder listener) {
1239 try {
1240 return mBinder.cancelConfirmationPrompt(listener);
1241 } catch (RemoteException e) {
1242 Log.w(TAG, "Cannot connect to keystore", e);
1243 return CONFIRMATIONUI_SYSTEM_ERROR;
1244 }
1245 }
1246
Chad Brubakera91a8502015-05-07 10:02:22 -07001247 /**
David Zeuthenbbb7f652018-02-26 11:04:18 -05001248 * Requests keystore to check if the confirmationui HAL is available.
1249 *
1250 * @return whether the confirmationUI HAL is available.
1251 */
1252 public boolean isConfirmationPromptSupported() {
1253 try {
1254 return mBinder.isConfirmationPromptSupported();
1255 } catch (RemoteException e) {
1256 Log.w(TAG, "Cannot connect to keystore", e);
1257 return false;
1258 }
1259 }
1260
1261 /**
Alex Klyubinad9ba102015-04-21 15:17:24 -07001262 * Returns a {@link KeyStoreException} corresponding to the provided keystore/keymaster error
1263 * code.
1264 */
Mathew Inwoode420f8b2018-08-16 18:40:47 +01001265 @UnsupportedAppUsage
Alex Klyubindcdaf872015-05-13 15:57:09 -07001266 public static KeyStoreException getKeyStoreException(int errorCode) {
Alex Klyubinb4834ae2015-04-02 15:53:46 -07001267 if (errorCode > 0) {
1268 // KeyStore layer error
1269 switch (errorCode) {
1270 case NO_ERROR:
1271 return new KeyStoreException(errorCode, "OK");
1272 case LOCKED:
Alex Klyubin54183932015-05-08 15:25:48 -07001273 return new KeyStoreException(errorCode, "User authentication required");
Alex Klyubinb4834ae2015-04-02 15:53:46 -07001274 case UNINITIALIZED:
1275 return new KeyStoreException(errorCode, "Keystore not initialized");
1276 case SYSTEM_ERROR:
1277 return new KeyStoreException(errorCode, "System error");
1278 case PERMISSION_DENIED:
1279 return new KeyStoreException(errorCode, "Permission denied");
1280 case KEY_NOT_FOUND:
1281 return new KeyStoreException(errorCode, "Key not found");
1282 case VALUE_CORRUPTED:
1283 return new KeyStoreException(errorCode, "Key blob corrupted");
Alex Klyubin058de022015-04-29 17:32:00 -07001284 case OP_AUTH_NEEDED:
1285 return new KeyStoreException(errorCode, "Operation requires authorization");
Max Bires13f98ce2018-11-02 10:50:40 -07001286 case KEY_PERMANENTLY_INVALIDATED:
1287 return new KeyStoreException(errorCode, "Key permanently invalidated");
Alex Klyubinb4834ae2015-04-02 15:53:46 -07001288 default:
1289 return new KeyStoreException(errorCode, String.valueOf(errorCode));
1290 }
1291 } else {
1292 // Keymaster layer error
1293 switch (errorCode) {
1294 case KeymasterDefs.KM_ERROR_INVALID_AUTHORIZATION_TIMEOUT:
1295 // The name of this parameter significantly differs between Keymaster and
1296 // framework APIs. Use the framework wording to make life easier for developers.
1297 return new KeyStoreException(errorCode,
1298 "Invalid user authentication validity duration");
1299 default:
1300 return new KeyStoreException(errorCode,
1301 KeymasterDefs.getErrorMessage(errorCode));
1302 }
1303 }
1304 }
1305
Alex Klyubinad9ba102015-04-21 15:17:24 -07001306 /**
1307 * Returns an {@link InvalidKeyException} corresponding to the provided
1308 * {@link KeyStoreException}.
1309 */
Alex Klyubindcdaf872015-05-13 15:57:09 -07001310 public InvalidKeyException getInvalidKeyException(
Alex Klyubin3876b1b2015-09-09 14:55:03 -07001311 String keystoreKeyAlias, int uid, KeyStoreException e) {
Alex Klyubinb4834ae2015-04-02 15:53:46 -07001312 switch (e.getErrorCode()) {
Brian Youngda82e2c2018-02-22 23:36:34 +00001313 case LOCKED:
Alex Klyubin54183932015-05-08 15:25:48 -07001314 return new UserNotAuthenticatedException();
Brian Youngda82e2c2018-02-22 23:36:34 +00001315 case KeymasterDefs.KM_ERROR_KEY_EXPIRED:
Alex Klyubinb4834ae2015-04-02 15:53:46 -07001316 return new KeyExpiredException();
Brian Youngda82e2c2018-02-22 23:36:34 +00001317 case KeymasterDefs.KM_ERROR_KEY_NOT_YET_VALID:
Alex Klyubinb4834ae2015-04-02 15:53:46 -07001318 return new KeyNotYetValidException();
Brian Youngda82e2c2018-02-22 23:36:34 +00001319 case KeymasterDefs.KM_ERROR_KEY_USER_NOT_AUTHENTICATED:
1320 case OP_AUTH_NEEDED:
Alex Klyubin708fc9402015-04-28 18:58:47 -07001321 {
1322 // We now need to determine whether the key/operation can become usable if user
1323 // authentication is performed, or whether it can never become usable again.
1324 // User authentication requirements are contained in the key's characteristics. We
1325 // need to check whether these requirements can be be satisfied by asking the user
1326 // to authenticate.
1327 KeyCharacteristics keyCharacteristics = new KeyCharacteristics();
1328 int getKeyCharacteristicsErrorCode =
Alex Klyubin3876b1b2015-09-09 14:55:03 -07001329 getKeyCharacteristics(keystoreKeyAlias, null, null, uid,
1330 keyCharacteristics);
Alex Klyubin708fc9402015-04-28 18:58:47 -07001331 if (getKeyCharacteristicsErrorCode != NO_ERROR) {
1332 return new InvalidKeyException(
1333 "Failed to obtained key characteristics",
1334 getKeyStoreException(getKeyCharacteristicsErrorCode));
1335 }
Alex Klyubinae6cb7a2015-06-22 18:09:35 -07001336 List<BigInteger> keySids =
1337 keyCharacteristics.getUnsignedLongs(KeymasterDefs.KM_TAG_USER_SECURE_ID);
Alex Klyubin708fc9402015-04-28 18:58:47 -07001338 if (keySids.isEmpty()) {
1339 // Key is not bound to any SIDs -- no amount of authentication will help here.
1340 return new KeyPermanentlyInvalidatedException();
1341 }
1342 long rootSid = GateKeeper.getSecureUserId();
Alex Klyubinae6cb7a2015-06-22 18:09:35 -07001343 if ((rootSid != 0) && (keySids.contains(KeymasterArguments.toUint64(rootSid)))) {
Alex Klyubin708fc9402015-04-28 18:58:47 -07001344 // One of the key's SIDs is the current root SID -- user can be authenticated
1345 // against that SID.
1346 return new UserNotAuthenticatedException();
1347 }
1348
Kevin Chyn7d07c892020-02-18 18:18:17 -08001349 final BiometricManager bm = mContext.getSystemService(BiometricManager.class);
1350 long[] biometricSids = bm.getAuthenticatorIds();
1351
1352 // The key must contain every biometric SID. This is because the current API surface
1353 // treats all biometrics (capable of keystore integration) equally. e.g. if the
1354 // device has multiple keystore-capable sensors, and one of the sensor's SIDs
1355 // changed, 1) there is no way for a developer to specify authentication with a
1356 // specific sensor (the one that hasn't changed), and 2) currently the only
1357 // signal to developers is the UserNotAuthenticatedException, which doesn't
1358 // indicate a specific sensor.
1359 boolean canUnlockViaBiometrics = true;
1360 for (long sid : biometricSids) {
1361 if (!keySids.contains(KeymasterArguments.toUint64(sid))) {
1362 canUnlockViaBiometrics = false;
1363 break;
1364 }
Alex Klyubin708fc9402015-04-28 18:58:47 -07001365 }
1366
Kevin Chyn7d07c892020-02-18 18:18:17 -08001367 if (canUnlockViaBiometrics) {
1368 // All of the biometric SIDs are contained in the key's SIDs.
Kevin Chyn057b7432018-09-24 14:36:39 -07001369 return new UserNotAuthenticatedException();
1370 }
1371
Alex Klyubin708fc9402015-04-28 18:58:47 -07001372 // None of the key's SIDs can ever be authenticated
1373 return new KeyPermanentlyInvalidatedException();
1374 }
Brian Youngda82e2c2018-02-22 23:36:34 +00001375 case UNINITIALIZED:
Janis Danisevskisd07d3382017-09-01 14:45:16 -07001376 return new KeyPermanentlyInvalidatedException();
Alex Klyubinb4834ae2015-04-02 15:53:46 -07001377 default:
Alex Klyubinad9ba102015-04-21 15:17:24 -07001378 return new InvalidKeyException("Keystore operation failed", e);
Alex Klyubinb4834ae2015-04-02 15:53:46 -07001379 }
1380 }
1381
Alex Klyubinad9ba102015-04-21 15:17:24 -07001382 /**
1383 * Returns an {@link InvalidKeyException} corresponding to the provided keystore/keymaster error
1384 * code.
1385 */
Alex Klyubin3876b1b2015-09-09 14:55:03 -07001386 public InvalidKeyException getInvalidKeyException(String keystoreKeyAlias, int uid,
1387 int errorCode) {
1388 return getInvalidKeyException(keystoreKeyAlias, uid, getKeyStoreException(errorCode));
Alex Klyubinb4834ae2015-04-02 15:53:46 -07001389 }
Chia-chi Yeh44039172009-09-21 11:53:59 +08001390}