blob: a85547a72eed124ae6a5ee75c7b1253b02853097 [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
Mathew Inwoode420f8b2018-08-16 18:40:47 +010019import android.annotation.UnsupportedAppUsage;
Svetoslav2dac95d2015-04-30 11:30:33 -070020import android.app.ActivityThread;
21import android.app.Application;
Alex Klyubin54183932015-05-08 15:25:48 -070022import android.app.KeyguardManager;
Alex Klyubin708fc9402015-04-28 18:58:47 -070023import android.content.Context;
Kevin Chyn55966422017-10-23 16:08:47 -070024import android.content.pm.PackageManager;
Kevin Chyn057b7432018-09-24 14:36:39 -070025import android.hardware.face.FaceManager;
Alex Klyubin2d7a85c2015-04-30 11:43:53 -070026import android.hardware.fingerprint.FingerprintManager;
Chad Brubakere6a461342015-02-10 21:33:23 -080027import android.os.Binder;
Mathew Inwood31755f92018-12-20 13:53:36 +000028import android.os.Build;
Chad Brubakere6a461342015-02-10 21:33:23 -080029import android.os.IBinder;
Chad Brubakera91a8502015-05-07 10:02:22 -070030import android.os.Process;
Kenny Root6b776452012-11-02 15:40:32 -070031import android.os.RemoteException;
32import android.os.ServiceManager;
Chad Brubakera91a8502015-05-07 10:02:22 -070033import android.os.UserHandle;
Janis Danisevskis1864c952018-08-09 11:14:49 -070034import android.security.KeyStoreException;
Chad Brubakere6a461342015-02-10 21:33:23 -080035import android.security.keymaster.ExportResult;
36import android.security.keymaster.KeyCharacteristics;
37import android.security.keymaster.KeymasterArguments;
Chad Brubaker5e73c0e2015-03-21 22:46:43 -070038import android.security.keymaster.KeymasterBlob;
Shawn Willden8d8c7472016-02-02 08:27:39 -070039import android.security.keymaster.KeymasterCertificateChain;
Alex Klyubinb4834ae2015-04-02 15:53:46 -070040import android.security.keymaster.KeymasterDefs;
Chad Brubakere6a461342015-02-10 21:33:23 -080041import android.security.keymaster.OperationResult;
Janis Danisevskisb0358e72018-11-02 10:34:07 -070042import android.security.keystore.IKeystoreService;
Alex Klyubin3f8d4d82015-05-13 09:15:00 -070043import android.security.keystore.KeyExpiredException;
44import android.security.keystore.KeyNotYetValidException;
45import android.security.keystore.KeyPermanentlyInvalidatedException;
Janis Danisevskis1864c952018-08-09 11:14:49 -070046import android.security.keystore.KeyProperties;
Janis Danisevskisb0358e72018-11-02 10:34:07 -070047import android.security.keystore.KeystoreResponse;
Alex Klyubin3f8d4d82015-05-13 09:15:00 -070048import android.security.keystore.UserNotAuthenticatedException;
Kenny Root6b776452012-11-02 15:40:32 -070049import android.util.Log;
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -070050
Janis Danisevskis1864c952018-08-09 11:14:49 -070051import com.android.org.bouncycastle.asn1.ASN1InputStream;
52import com.android.org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -070053
Janis Danisevskis1864c952018-08-09 11:14:49 -070054import java.io.ByteArrayInputStream;
55import java.io.IOException;
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -070056import java.math.BigInteger;
Alex Klyubinad9ba102015-04-21 15:17:24 -070057import java.security.InvalidKeyException;
Rob Barnesebe26742018-11-13 15:57:22 -070058import java.util.ArrayList;
Janis Danisevskis2b106ad2018-11-15 09:27:16 -080059import java.util.Date;
Alex Klyubin708fc9402015-04-28 18:58:47 -070060import java.util.List;
Kenny Rootb91773b2013-09-05 13:03:16 -070061import java.util.Locale;
Janis Danisevskisb0358e72018-11-02 10:34:07 -070062import java.util.concurrent.CompletableFuture;
63import java.util.concurrent.ExecutionException;
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -070064
Janis Danisevskis1864c952018-08-09 11:14:49 -070065import sun.security.util.ObjectIdentifier;
66import sun.security.x509.AlgorithmId;
Kenny Rootb91773b2013-09-05 13:03:16 -070067
Chia-chi Yeh44039172009-09-21 11:53:59 +080068/**
Brian Carlstrom46703b02011-04-06 15:41:29 -070069 * @hide This should not be made public in its present form because it
70 * assumes that private and secret key bytes are available and would
71 * preclude the use of hardware crypto.
Chia-chi Yeh44039172009-09-21 11:53:59 +080072 */
73public class KeyStore {
Kenny Root6b776452012-11-02 15:40:32 -070074 private static final String TAG = "KeyStore";
Brian Carlstrom5cfee3f2011-05-31 01:00:15 -070075
Dmitry Dementyevefc43112017-10-27 23:10:28 -070076 // ResponseCodes - see system/security/keystore/include/keystore/keystore.h
Mathew Inwoode420f8b2018-08-16 18:40:47 +010077 @UnsupportedAppUsage
Brian Carlstrom7e4b1a42011-06-01 15:29:29 -070078 public static final int NO_ERROR = 1;
79 public static final int LOCKED = 2;
80 public static final int UNINITIALIZED = 3;
81 public static final int SYSTEM_ERROR = 4;
82 public static final int PROTOCOL_ERROR = 5;
83 public static final int PERMISSION_DENIED = 6;
84 public static final int KEY_NOT_FOUND = 7;
85 public static final int VALUE_CORRUPTED = 8;
86 public static final int UNDEFINED_ACTION = 9;
87 public static final int WRONG_PASSWORD = 10;
Janis Danisevskisd2575382018-10-08 07:56:58 -070088 public static final int KEY_ALREADY_EXISTS = 16;
Eran Messeri61692392018-03-26 16:43:14 +010089 public static final int CANNOT_ATTEST_IDS = -66;
Frank Salimea5e0382018-01-23 22:42:29 -080090 public static final int HARDWARE_TYPE_UNAVAILABLE = -68;
Brian Carlstrom5cfee3f2011-05-31 01:00:15 -070091
Chad Brubaker560d6532015-04-24 10:32:18 -070092 /**
93 * Per operation authentication is needed before this operation is valid.
94 * This is returned from {@link #begin} when begin succeeds but the operation uses
95 * per-operation authentication and must authenticate before calling {@link #update} or
96 * {@link #finish}.
97 */
98 public static final int OP_AUTH_NEEDED = 15;
99
Max Bires13f98ce2018-11-02 10:50:40 -0700100 // Used when a user changes their pin, invalidating old auth bound keys.
101 public static final int KEY_PERMANENTLY_INVALIDATED = 17;
102
Kenny Root2eeda722013-04-10 11:30:58 -0700103 // Used for UID field to indicate the calling UID.
104 public static final int UID_SELF = -1;
105
106 // Flags for "put" "import" and "generate"
107 public static final int FLAG_NONE = 0;
Alex Klyubin54183932015-05-08 15:25:48 -0700108
109 /**
110 * Indicates that this key (or key pair) must be encrypted at rest. This will protect the key
111 * (or key pair) with the secure lock screen credential (e.g., password, PIN, or pattern).
112 *
113 * <p>Note that this requires that the secure lock screen (e.g., password, PIN, pattern) is set
114 * up, otherwise key (or key pair) generation or import will fail. Moreover, this key (or key
115 * pair) will be deleted when the secure lock screen is disabled or reset (e.g., by the user or
116 * a Device Administrator). Finally, this key (or key pair) cannot be used until the user
117 * unlocks the secure lock screen after boot.
118 *
119 * @see KeyguardManager#isDeviceSecure()
120 */
Kenny Roota3788b02013-04-10 10:37:55 -0700121 public static final int FLAG_ENCRYPTED = 1;
122
Rubin Xu12b644d2017-04-21 19:21:42 +0100123 /**
Janis Danisevskis0aadf932017-12-18 17:28:52 -0800124 * Select Software keymaster device, which as of this writing is the lowest security
125 * level available on an android device. If neither FLAG_STRONGBOX nor FLAG_SOFTWARE is provided
126 * A TEE based keymaster implementation is implied.
127 *
128 * Need to be in sync with KeyStoreFlag in system/security/keystore/include/keystore/keystore.h
129 * For historical reasons this corresponds to the KEYSTORE_FLAG_FALLBACK flag.
130 */
131 public static final int FLAG_SOFTWARE = 1 << 1;
132
133 /**
Rubin Xu12b644d2017-04-21 19:21:42 +0100134 * A private flag that's only available to system server to indicate that this key is part of
135 * device encryption flow so it receives special treatment from keystore. For example this key
136 * will not be super encrypted, and it will be stored separately under an unique UID instead
137 * of the caller UID i.e. SYSTEM.
138 *
139 * Need to be in sync with KeyStoreFlag in system/security/keystore/include/keystore/keystore.h
140 */
141 public static final int FLAG_CRITICAL_TO_DEVICE_ENCRYPTION = 1 << 3;
142
Janis Danisevskis0aadf932017-12-18 17:28:52 -0800143 /**
144 * Select Strongbox keymaster device, which as of this writing the the highest security level
145 * available an android devices. If neither FLAG_STRONGBOX nor FLAG_SOFTWARE is provided
146 * A TEE based keymaster implementation is implied.
147 *
148 * Need to be in sync with KeyStoreFlag in system/security/keystore/include/keystore/keystore.h
149 */
150 public static final int FLAG_STRONGBOX = 1 << 4;
151
Brian Carlstrom5cfee3f2011-05-31 01:00:15 -0700152 // States
Mathew Inwoodefb48162018-08-01 10:24:49 +0100153 public enum State {
Mathew Inwoode420f8b2018-08-16 18:40:47 +0100154 @UnsupportedAppUsage
Mathew Inwoodefb48162018-08-01 10:24:49 +0100155 UNLOCKED,
Mathew Inwoode420f8b2018-08-16 18:40:47 +0100156 @UnsupportedAppUsage
Mathew Inwoodefb48162018-08-01 10:24:49 +0100157 LOCKED,
158 UNINITIALIZED
159 };
Chia-chi Yeh44039172009-09-21 11:53:59 +0800160
Chia-chi Yeh44039172009-09-21 11:53:59 +0800161 private int mError = NO_ERROR;
162
Kenny Root6b776452012-11-02 15:40:32 -0700163 private final IKeystoreService mBinder;
Alex Klyubin2d7a85c2015-04-30 11:43:53 -0700164 private final Context mContext;
Kenny Root6b776452012-11-02 15:40:32 -0700165
Chad Brubakere6a461342015-02-10 21:33:23 -0800166 private IBinder mToken;
167
Kenny Root6b776452012-11-02 15:40:32 -0700168 private KeyStore(IKeystoreService binder) {
169 mBinder = binder;
Alex Klyubin3f8d4d82015-05-13 09:15:00 -0700170 mContext = getApplicationContext();
Alex Klyubin2d7a85c2015-04-30 11:43:53 -0700171 }
172
Mathew Inwoode420f8b2018-08-16 18:40:47 +0100173 @UnsupportedAppUsage
Alex Klyubindcdaf872015-05-13 15:57:09 -0700174 public static Context getApplicationContext() {
Alex Klyubina99b8b52015-06-11 13:27:34 -0700175 Application application = ActivityThread.currentApplication();
Alex Klyubin2d7a85c2015-04-30 11:43:53 -0700176 if (application == null) {
177 throw new IllegalStateException(
Alex Klyubina99b8b52015-06-11 13:27:34 -0700178 "Failed to obtain application Context from ActivityThread");
Alex Klyubin2d7a85c2015-04-30 11:43:53 -0700179 }
180 return application;
Kenny Root6b776452012-11-02 15:40:32 -0700181 }
Chia-chi Yeh44039172009-09-21 11:53:59 +0800182
Mathew Inwoode420f8b2018-08-16 18:40:47 +0100183 @UnsupportedAppUsage
Chia-chi Yeh44039172009-09-21 11:53:59 +0800184 public static KeyStore getInstance() {
Kenny Root6b776452012-11-02 15:40:32 -0700185 IKeystoreService keystore = IKeystoreService.Stub.asInterface(ServiceManager
186 .getService("android.security.keystore"));
187 return new KeyStore(keystore);
Chia-chi Yeh44039172009-09-21 11:53:59 +0800188 }
189
Chad Brubakere6a461342015-02-10 21:33:23 -0800190 private synchronized IBinder getToken() {
191 if (mToken == null) {
192 mToken = new Binder();
193 }
194 return mToken;
195 }
196
Mathew Inwoode420f8b2018-08-16 18:40:47 +0100197 @UnsupportedAppUsage
Chad Brubakere35d49f2015-05-12 15:19:52 -0700198 public State state(int userId) {
Kenny Root6b776452012-11-02 15:40:32 -0700199 final int ret;
200 try {
Chad Brubakere35d49f2015-05-12 15:19:52 -0700201 ret = mBinder.getState(userId);
Kenny Root6b776452012-11-02 15:40:32 -0700202 } catch (RemoteException e) {
203 Log.w(TAG, "Cannot connect to keystore", e);
204 throw new AssertionError(e);
205 }
206
207 switch (ret) {
Brian Carlstrom5cfee3f2011-05-31 01:00:15 -0700208 case NO_ERROR: return State.UNLOCKED;
209 case LOCKED: return State.LOCKED;
210 case UNINITIALIZED: return State.UNINITIALIZED;
211 default: throw new AssertionError(mError);
212 }
Chia-chi Yeh44039172009-09-21 11:53:59 +0800213 }
214
Mathew Inwoode420f8b2018-08-16 18:40:47 +0100215 @UnsupportedAppUsage
Chad Brubakere35d49f2015-05-12 15:19:52 -0700216 public State state() {
217 return state(UserHandle.myUserId());
218 }
219
Kenny Rootb9594ce2013-02-14 10:18:38 -0800220 public boolean isUnlocked() {
221 return state() == State.UNLOCKED;
222 }
223
Chad Brubaker5bbf0482015-09-09 14:53:52 -0700224 public byte[] get(String key, int uid) {
Irina Dumitrescu4a1cccc2018-06-08 19:36:34 +0100225 return get(key, uid, false);
Chia-chi Yeh44039172009-09-21 11:53:59 +0800226 }
227
Mathew Inwoode420f8b2018-08-16 18:40:47 +0100228 @UnsupportedAppUsage
Chad Brubaker5bbf0482015-09-09 14:53:52 -0700229 public byte[] get(String key) {
230 return get(key, UID_SELF);
231 }
232
Irina Dumitrescu4a1cccc2018-06-08 19:36:34 +0100233 public byte[] get(String key, int uid, boolean suppressKeyNotFoundWarning) {
234 try {
235 key = key != null ? key : "";
236 return mBinder.get(key, uid);
237 } catch (RemoteException e) {
238 Log.w(TAG, "Cannot connect to keystore", e);
239 return null;
240 } catch (android.os.ServiceSpecificException e) {
241 if (!suppressKeyNotFoundWarning || e.errorCode != KEY_NOT_FOUND) {
242 Log.w(TAG, "KeyStore exception", e);
243 }
244 return null;
245 }
246 }
247
248 public byte[] get(String key, boolean suppressKeyNotFoundWarning) {
249 return get(key, UID_SELF, suppressKeyNotFoundWarning);
250 }
251
252
Kenny Roota3788b02013-04-10 10:37:55 -0700253 public boolean put(String key, byte[] value, int uid, int flags) {
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700254 return insert(key, value, uid, flags) == NO_ERROR;
255 }
256
257 public int insert(String key, byte[] value, int uid, int flags) {
Kenny Root6b776452012-11-02 15:40:32 -0700258 try {
Dmitry Dementyevefc43112017-10-27 23:10:28 -0700259 if (value == null) {
260 value = new byte[0];
261 }
Janis Danisevskisd2575382018-10-08 07:56:58 -0700262 int error = mBinder.insert(key, value, uid, flags);
263 if (error == KEY_ALREADY_EXISTS) {
264 mBinder.del(key, uid);
265 error = mBinder.insert(key, value, uid, flags);
266 }
267 return error;
Kenny Root78ad8492013-02-13 17:02:57 -0800268 } catch (RemoteException e) {
269 Log.w(TAG, "Cannot connect to keystore", e);
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700270 return SYSTEM_ERROR;
Kenny Root78ad8492013-02-13 17:02:57 -0800271 }
272 }
273
Janis Danisevskis906147c2018-11-06 14:14:05 -0800274 int delete2(String key, int uid) {
Kenny Root78ad8492013-02-13 17:02:57 -0800275 try {
Janis Danisevskis906147c2018-11-06 14:14:05 -0800276 return mBinder.del(key, uid);
Kenny Root6b776452012-11-02 15:40:32 -0700277 } catch (RemoteException e) {
278 Log.w(TAG, "Cannot connect to keystore", e);
Janis Danisevskis906147c2018-11-06 14:14:05 -0800279 return SYSTEM_ERROR;
Kenny Root6b776452012-11-02 15:40:32 -0700280 }
Chia-chi Yeh44039172009-09-21 11:53:59 +0800281 }
282
Janis Danisevskis906147c2018-11-06 14:14:05 -0800283 public boolean delete(String key, int uid) {
284 int ret = delete2(key, uid);
285 return ret == NO_ERROR || ret == KEY_NOT_FOUND;
286 }
287
Mathew Inwoode420f8b2018-08-16 18:40:47 +0100288 @UnsupportedAppUsage
Chia-chi Yeh44039172009-09-21 11:53:59 +0800289 public boolean delete(String key) {
Kenny Root2eeda722013-04-10 11:30:58 -0700290 return delete(key, UID_SELF);
Kenny Root78ad8492013-02-13 17:02:57 -0800291 }
292
293 public boolean contains(String key, int uid) {
Kenny Root6b776452012-11-02 15:40:32 -0700294 try {
Kenny Root78ad8492013-02-13 17:02:57 -0800295 return mBinder.exist(key, uid) == NO_ERROR;
Kenny Root6b776452012-11-02 15:40:32 -0700296 } catch (RemoteException e) {
297 Log.w(TAG, "Cannot connect to keystore", e);
298 return false;
299 }
Chia-chi Yeh44039172009-09-21 11:53:59 +0800300 }
301
302 public boolean contains(String key) {
Kenny Root2eeda722013-04-10 11:30:58 -0700303 return contains(key, UID_SELF);
Chia-chi Yeh44039172009-09-21 11:53:59 +0800304 }
305
Chad Brubakere35d49f2015-05-12 15:19:52 -0700306 /**
307 * List all entries in the keystore for {@code uid} starting with {@code prefix}.
308 */
309 public String[] list(String prefix, int uid) {
Kenny Root6b776452012-11-02 15:40:32 -0700310 try {
Chad Brubakere35d49f2015-05-12 15:19:52 -0700311 return mBinder.list(prefix, uid);
Kenny Root6b776452012-11-02 15:40:32 -0700312 } catch (RemoteException e) {
313 Log.w(TAG, "Cannot connect to keystore", e);
Chia-chi Yeh44039172009-09-21 11:53:59 +0800314 return null;
Dmitry Dementyevefc43112017-10-27 23:10:28 -0700315 } catch (android.os.ServiceSpecificException e) {
316 Log.w(TAG, "KeyStore exception", e);
317 return null;
Chia-chi Yeh44039172009-09-21 11:53:59 +0800318 }
Chia-chi Yeh44039172009-09-21 11:53:59 +0800319 }
320
Rob Barnesf1a678e2018-11-13 15:57:22 -0700321 /**
Rob Barnesebe26742018-11-13 15:57:22 -0700322 * List uids of all keys that are auth bound to the current user.
Rob Barnesf1a678e2018-11-13 15:57:22 -0700323 * Only system is allowed to call this method.
324 */
325 @UnsupportedAppUsage
326 public int[] listUidsOfAuthBoundKeys() {
Rob Barnesebe26742018-11-13 15:57:22 -0700327 // uids are returned as a list of strings because list of integers
328 // as an output parameter is not supported by aidl-cpp.
329 List<String> uidsOut = new ArrayList<>();
Rob Barnesf1a678e2018-11-13 15:57:22 -0700330 try {
331 int rc = mBinder.listUidsOfAuthBoundKeys(uidsOut);
332 if (rc != NO_ERROR) {
333 Log.w(TAG, String.format("listUidsOfAuthBoundKeys failed with error code %d", rc));
334 return null;
335 }
336 } catch (RemoteException e) {
337 Log.w(TAG, "Cannot connect to keystore", e);
338 return null;
339 } catch (android.os.ServiceSpecificException e) {
340 Log.w(TAG, "KeyStore exception", e);
341 return null;
342 }
Rob Barnesebe26742018-11-13 15:57:22 -0700343 // Turn list of strings into an array of uid integers.
344 return uidsOut.stream().mapToInt(Integer::parseInt).toArray();
Rob Barnesf1a678e2018-11-13 15:57:22 -0700345 }
346
Chad Brubakere35d49f2015-05-12 15:19:52 -0700347 public String[] list(String prefix) {
348 return list(prefix, UID_SELF);
349 }
350
Chad Brubakere35d49f2015-05-12 15:19:52 -0700351 /**
352 * Attempt to lock the keystore for {@code user}.
353 *
Brian Youngfd75c722018-02-23 18:04:20 +0000354 * @param userId Android user to lock.
Chad Brubakere35d49f2015-05-12 15:19:52 -0700355 * @return whether {@code user}'s keystore was locked.
356 */
357 public boolean lock(int userId) {
Kenny Root6b776452012-11-02 15:40:32 -0700358 try {
Chad Brubakere35d49f2015-05-12 15:19:52 -0700359 return mBinder.lock(userId) == NO_ERROR;
Kenny Root6b776452012-11-02 15:40:32 -0700360 } catch (RemoteException e) {
361 Log.w(TAG, "Cannot connect to keystore", e);
362 return false;
363 }
Chia-chi Yeh44039172009-09-21 11:53:59 +0800364 }
365
Chad Brubakere35d49f2015-05-12 15:19:52 -0700366 public boolean lock() {
367 return lock(UserHandle.myUserId());
368 }
369
Chad Brubakera91a8502015-05-07 10:02:22 -0700370 /**
371 * Attempt to unlock the keystore for {@code user} with the password {@code password}.
372 * This is required before keystore entries created with FLAG_ENCRYPTED can be accessed or
373 * created.
374 *
Brian Youngfd75c722018-02-23 18:04:20 +0000375 * @param userId Android user ID to operate on
Chad Brubakera91a8502015-05-07 10:02:22 -0700376 * @param password user's keystore password. Should be the most recent value passed to
377 * {@link #onUserPasswordChanged} for the user.
378 *
379 * @return whether the keystore was unlocked.
380 */
381 public boolean unlock(int userId, String password) {
Kenny Root6b776452012-11-02 15:40:32 -0700382 try {
Dmitry Dementyevefc43112017-10-27 23:10:28 -0700383 password = password != null ? password : "";
Chad Brubakera91a8502015-05-07 10:02:22 -0700384 mError = mBinder.unlock(userId, password);
Kenny Root6b776452012-11-02 15:40:32 -0700385 return mError == NO_ERROR;
386 } catch (RemoteException e) {
387 Log.w(TAG, "Cannot connect to keystore", e);
388 return false;
389 }
Chia-chi Yeh44039172009-09-21 11:53:59 +0800390 }
391
Mathew Inwoode420f8b2018-08-16 18:40:47 +0100392 @UnsupportedAppUsage
Chad Brubakera91a8502015-05-07 10:02:22 -0700393 public boolean unlock(String password) {
394 return unlock(UserHandle.getUserId(Process.myUid()), password);
395 }
396
Chad Brubakere35d49f2015-05-12 15:19:52 -0700397 /**
398 * Check if the keystore for {@code userId} is empty.
399 */
400 public boolean isEmpty(int userId) {
Kenny Root6b776452012-11-02 15:40:32 -0700401 try {
Chad Brubakere35d49f2015-05-12 15:19:52 -0700402 return mBinder.isEmpty(userId) != 0;
Kenny Root6b776452012-11-02 15:40:32 -0700403 } catch (RemoteException e) {
404 Log.w(TAG, "Cannot connect to keystore", e);
405 return false;
406 }
Kenny Root5423e682011-11-14 08:43:13 -0800407 }
408
Mathew Inwood31755f92018-12-20 13:53:36 +0000409 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
Chad Brubakere35d49f2015-05-12 15:19:52 -0700410 public boolean isEmpty() {
411 return isEmpty(UserHandle.myUserId());
412 }
413
Janis Danisevskisb50e9f62017-06-08 17:53:34 -0700414 public String grant(String key, int uid) {
Kenny Root6b776452012-11-02 15:40:32 -0700415 try {
Janis Danisevskisb50e9f62017-06-08 17:53:34 -0700416 String grantAlias = mBinder.grant(key, uid);
417 if (grantAlias == "") return null;
418 return grantAlias;
Kenny Root6b776452012-11-02 15:40:32 -0700419 } catch (RemoteException e) {
420 Log.w(TAG, "Cannot connect to keystore", e);
Janis Danisevskisb50e9f62017-06-08 17:53:34 -0700421 return null;
Kenny Root6b776452012-11-02 15:40:32 -0700422 }
Kenny Root5423e682011-11-14 08:43:13 -0800423 }
424
425 public boolean ungrant(String key, int uid) {
Kenny Root6b776452012-11-02 15:40:32 -0700426 try {
427 return mBinder.ungrant(key, uid) == NO_ERROR;
428 } catch (RemoteException e) {
429 Log.w(TAG, "Cannot connect to keystore", e);
430 return false;
Kenny Root473c7122012-08-17 21:13:48 -0700431 }
Kenny Root473c7122012-08-17 21:13:48 -0700432 }
433
434 /**
435 * Returns the last modification time of the key in milliseconds since the
436 * epoch. Will return -1L if the key could not be found or other error.
437 */
Chad Brubaker5bbf0482015-09-09 14:53:52 -0700438 public long getmtime(String key, int uid) {
Kenny Root6b776452012-11-02 15:40:32 -0700439 try {
Chad Brubaker5bbf0482015-09-09 14:53:52 -0700440 final long millis = mBinder.getmtime(key, uid);
Kenny Roote66769a2013-02-04 15:49:11 -0800441 if (millis == -1L) {
442 return -1L;
443 }
444
445 return millis * 1000L;
Kenny Root6b776452012-11-02 15:40:32 -0700446 } catch (RemoteException e) {
447 Log.w(TAG, "Cannot connect to keystore", e);
448 return -1L;
449 }
Kenny Root473c7122012-08-17 21:13:48 -0700450 }
451
Chad Brubaker5bbf0482015-09-09 14:53:52 -0700452 public long getmtime(String key) {
453 return getmtime(key, UID_SELF);
454 }
455
Alex Klyubin469cbf52015-06-04 12:36:27 -0700456 // TODO: remove this when it's removed from Settings
Kenny Root5cb5cec2013-03-29 11:14:17 -0700457 public boolean isHardwareBacked() {
Kenny Rootb91773b2013-09-05 13:03:16 -0700458 return isHardwareBacked("RSA");
459 }
460
461 public boolean isHardwareBacked(String keyType) {
Kenny Root5cb5cec2013-03-29 11:14:17 -0700462 try {
Kenny Rootb91773b2013-09-05 13:03:16 -0700463 return mBinder.is_hardware_backed(keyType.toUpperCase(Locale.US)) == NO_ERROR;
Kenny Root5cb5cec2013-03-29 11:14:17 -0700464 } catch (RemoteException e) {
465 Log.w(TAG, "Cannot connect to keystore", e);
466 return false;
467 }
468 }
469
Kenny Rootd72317a2013-04-01 15:59:59 -0700470 public boolean clearUid(int uid) {
471 try {
472 return mBinder.clear_uid(uid) == NO_ERROR;
473 } catch (RemoteException e) {
474 Log.w(TAG, "Cannot connect to keystore", e);
475 return false;
476 }
477 }
478
Chia-chi Yeh44039172009-09-21 11:53:59 +0800479 public int getLastError() {
480 return mError;
481 }
Chad Brubakere6a461342015-02-10 21:33:23 -0800482
Janis Danisevskis0aadf932017-12-18 17:28:52 -0800483 public boolean addRngEntropy(byte[] data, int flags) {
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700484 KeystoreResultPromise promise = new KeystoreResultPromise();
Chad Brubakere6a461342015-02-10 21:33:23 -0800485 try {
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700486 mBinder.asBinder().linkToDeath(promise, 0);
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700487 int errorCode = mBinder.addRngEntropy(promise, data, flags);
488 if (errorCode == NO_ERROR) {
489 return promise.getFuture().get().getErrorCode() == NO_ERROR;
490 } else {
491 return false;
492 }
Chad Brubakere6a461342015-02-10 21:33:23 -0800493 } catch (RemoteException e) {
494 Log.w(TAG, "Cannot connect to keystore", e);
495 return false;
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700496 } catch (ExecutionException | InterruptedException e) {
497 Log.e(TAG, "AddRngEntropy completed with exception", e);
498 return false;
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700499 } finally {
500 mBinder.asBinder().unlinkToDeath(promise, 0);
Chad Brubakere6a461342015-02-10 21:33:23 -0800501 }
502 }
503
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700504 private class KeyCharacteristicsCallbackResult {
505 private KeystoreResponse keystoreResponse;
506 private KeyCharacteristics keyCharacteristics;
507
508 public KeyCharacteristicsCallbackResult(KeystoreResponse keystoreResponse,
509 KeyCharacteristics keyCharacteristics) {
510 this.keystoreResponse = keystoreResponse;
511 this.keyCharacteristics = keyCharacteristics;
512 }
513
514 public KeystoreResponse getKeystoreResponse() {
515 return keystoreResponse;
516 }
517
518 public void setKeystoreResponse(KeystoreResponse keystoreResponse) {
519 this.keystoreResponse = keystoreResponse;
520 }
521
522 public KeyCharacteristics getKeyCharacteristics() {
523 return keyCharacteristics;
524 }
525
526 public void setKeyCharacteristics(KeyCharacteristics keyCharacteristics) {
527 this.keyCharacteristics = keyCharacteristics;
528 }
529 }
530
531 private class KeyCharacteristicsPromise
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700532 extends android.security.keystore.IKeystoreKeyCharacteristicsCallback.Stub
533 implements IBinder.DeathRecipient {
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700534 final private CompletableFuture<KeyCharacteristicsCallbackResult> future =
535 new CompletableFuture<KeyCharacteristicsCallbackResult>();
536 @Override
537 public void onFinished(KeystoreResponse keystoreResponse,
538 KeyCharacteristics keyCharacteristics)
539 throws android.os.RemoteException {
540 future.complete(
541 new KeyCharacteristicsCallbackResult(keystoreResponse, keyCharacteristics));
542 }
543 public final CompletableFuture<KeyCharacteristicsCallbackResult> getFuture() {
544 return future;
545 }
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700546 @Override
547 public void binderDied() {
548 future.completeExceptionally(new RemoteException("Keystore died"));
549 }
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700550 };
551
552 private int generateKeyInternal(String alias, KeymasterArguments args, byte[] entropy, int uid,
553 int flags, KeyCharacteristics outCharacteristics)
554 throws RemoteException, ExecutionException, InterruptedException {
555 KeyCharacteristicsPromise promise = new KeyCharacteristicsPromise();
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700556 int error = NO_ERROR;
557 KeyCharacteristicsCallbackResult result = null;
558 try {
559 mBinder.asBinder().linkToDeath(promise, 0);
560 error = mBinder.generateKey(promise, alias, args, entropy, uid, flags);
561 if (error != NO_ERROR) {
562 Log.e(TAG, "generateKeyInternal failed on request " + error);
563 return error;
564 }
565 result = promise.getFuture().get();
566 } finally {
567 mBinder.asBinder().unlinkToDeath(promise, 0);
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700568 }
569
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700570 error = result.getKeystoreResponse().getErrorCode();
571 if (error != NO_ERROR) {
572 Log.e(TAG, "generateKeyInternal failed on response " + error);
573 return error;
574 }
575 KeyCharacteristics characteristics = result.getKeyCharacteristics();
576 if (characteristics == null) {
577 Log.e(TAG, "generateKeyInternal got empty key cheractariestics " + error);
578 return SYSTEM_ERROR;
579 }
580 outCharacteristics.shallowCopyFrom(characteristics);
581 return NO_ERROR;
582 }
583
Chad Brubakerdae79e52015-03-27 14:28:35 -0700584 public int generateKey(String alias, KeymasterArguments args, byte[] entropy, int uid,
585 int flags, KeyCharacteristics outCharacteristics) {
Chad Brubakere6a461342015-02-10 21:33:23 -0800586 try {
Dmitry Dementyevefc43112017-10-27 23:10:28 -0700587 entropy = entropy != null ? entropy : new byte[0];
588 args = args != null ? args : new KeymasterArguments();
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700589 int error = generateKeyInternal(alias, args, entropy, uid, flags, outCharacteristics);
Janis Danisevskisd2575382018-10-08 07:56:58 -0700590 if (error == KEY_ALREADY_EXISTS) {
591 mBinder.del(alias, uid);
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700592 error = generateKeyInternal(alias, args, entropy, uid, flags, outCharacteristics);
Janis Danisevskisd2575382018-10-08 07:56:58 -0700593 }
594 return error;
Chad Brubakere6a461342015-02-10 21:33:23 -0800595 } catch (RemoteException e) {
596 Log.w(TAG, "Cannot connect to keystore", e);
597 return SYSTEM_ERROR;
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700598 } catch (ExecutionException | InterruptedException e) {
599 Log.e(TAG, "generateKey completed with exception", e);
600 return SYSTEM_ERROR;
Chad Brubakere6a461342015-02-10 21:33:23 -0800601 }
602 }
603
Chad Brubakerdae79e52015-03-27 14:28:35 -0700604 public int generateKey(String alias, KeymasterArguments args, byte[] entropy, int flags,
Chad Brubakere6a461342015-02-10 21:33:23 -0800605 KeyCharacteristics outCharacteristics) {
Chad Brubakerdae79e52015-03-27 14:28:35 -0700606 return generateKey(alias, args, entropy, UID_SELF, flags, outCharacteristics);
Chad Brubakere6a461342015-02-10 21:33:23 -0800607 }
608
Chad Brubaker5e73c0e2015-03-21 22:46:43 -0700609 public int getKeyCharacteristics(String alias, KeymasterBlob clientId, KeymasterBlob appId,
Chad Brubaker5bbf0482015-09-09 14:53:52 -0700610 int uid, KeyCharacteristics outCharacteristics) {
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700611 KeyCharacteristicsPromise promise = new KeyCharacteristicsPromise();
Chad Brubakere6a461342015-02-10 21:33:23 -0800612 try {
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700613 mBinder.asBinder().linkToDeath(promise, 0);
Dmitry Dementyevefc43112017-10-27 23:10:28 -0700614 clientId = clientId != null ? clientId : new KeymasterBlob(new byte[0]);
615 appId = appId != null ? appId : new KeymasterBlob(new byte[0]);
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700616
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700617 int error = mBinder.getKeyCharacteristics(promise, alias, clientId, appId, uid);
618 if (error != NO_ERROR) return error;
619
620 KeyCharacteristicsCallbackResult result = promise.getFuture().get();
621 error = result.getKeystoreResponse().getErrorCode();
622 if (error != NO_ERROR) return error;
623
624 KeyCharacteristics characteristics = result.getKeyCharacteristics();
625 if (characteristics == null) return SYSTEM_ERROR;
626 outCharacteristics.shallowCopyFrom(characteristics);
627 return NO_ERROR;
Chad Brubakere6a461342015-02-10 21:33:23 -0800628 } catch (RemoteException e) {
629 Log.w(TAG, "Cannot connect to keystore", e);
630 return SYSTEM_ERROR;
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700631 } catch (ExecutionException | InterruptedException e) {
632 Log.e(TAG, "GetKeyCharacteristics completed with exception", e);
633 return SYSTEM_ERROR;
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700634 } finally {
635 mBinder.asBinder().unlinkToDeath(promise, 0);
Chad Brubakere6a461342015-02-10 21:33:23 -0800636 }
637 }
638
Chad Brubaker5bbf0482015-09-09 14:53:52 -0700639 public int getKeyCharacteristics(String alias, KeymasterBlob clientId, KeymasterBlob appId,
640 KeyCharacteristics outCharacteristics) {
641 return getKeyCharacteristics(alias, clientId, appId, UID_SELF, outCharacteristics);
642 }
643
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700644 private int importKeyInternal(String alias, KeymasterArguments args, int format, byte[] keyData,
645 int uid, int flags, KeyCharacteristics outCharacteristics)
646 throws RemoteException, ExecutionException, InterruptedException {
647 KeyCharacteristicsPromise promise = new KeyCharacteristicsPromise();
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700648 mBinder.asBinder().linkToDeath(promise, 0);
649 try {
650 int error = mBinder.importKey(promise, alias, args, format, keyData, uid, flags);
651 if (error != NO_ERROR) return error;
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700652
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700653 KeyCharacteristicsCallbackResult result = promise.getFuture().get();
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700654
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700655 error = result.getKeystoreResponse().getErrorCode();
656 if (error != NO_ERROR) return error;
657
658 KeyCharacteristics characteristics = result.getKeyCharacteristics();
659 if (characteristics == null) return SYSTEM_ERROR;
660 outCharacteristics.shallowCopyFrom(characteristics);
661 return NO_ERROR;
662 } finally {
663 mBinder.asBinder().unlinkToDeath(promise, 0);
664 }
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700665 }
666
Chad Brubakere6a461342015-02-10 21:33:23 -0800667 public int importKey(String alias, KeymasterArguments args, int format, byte[] keyData,
668 int uid, int flags, KeyCharacteristics outCharacteristics) {
669 try {
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700670 int error = importKeyInternal(alias, args, format, keyData, uid, flags,
Chad Brubakere6a461342015-02-10 21:33:23 -0800671 outCharacteristics);
Janis Danisevskisd2575382018-10-08 07:56:58 -0700672 if (error == KEY_ALREADY_EXISTS) {
673 mBinder.del(alias, uid);
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700674 error = importKeyInternal(alias, args, format, keyData, uid, flags,
Janis Danisevskisd2575382018-10-08 07:56:58 -0700675 outCharacteristics);
676 }
677 return error;
Chad Brubakere6a461342015-02-10 21:33:23 -0800678 } catch (RemoteException e) {
679 Log.w(TAG, "Cannot connect to keystore", e);
680 return SYSTEM_ERROR;
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700681 } catch (ExecutionException | InterruptedException e) {
682 Log.e(TAG, "ImportKey completed with exception", e);
683 return SYSTEM_ERROR;
Chad Brubakere6a461342015-02-10 21:33:23 -0800684 }
685 }
686
687 public int importKey(String alias, KeymasterArguments args, int format, byte[] keyData,
688 int flags, KeyCharacteristics outCharacteristics) {
689 return importKey(alias, args, format, keyData, UID_SELF, flags, outCharacteristics);
690 }
691
Janis Danisevskis1864c952018-08-09 11:14:49 -0700692 private String getAlgorithmFromPKCS8(byte[] keyData) {
693 try {
694 final ASN1InputStream bIn = new ASN1InputStream(new ByteArrayInputStream(keyData));
695 final PrivateKeyInfo pki = PrivateKeyInfo.getInstance(bIn.readObject());
696 final String algOid = pki.getPrivateKeyAlgorithm().getAlgorithm().getId();
697 return new AlgorithmId(new ObjectIdentifier(algOid)).getName();
698 } catch (IOException e) {
699 Log.e(TAG, "getAlgorithmFromPKCS8 Failed to parse key data");
700 Log.e(TAG, Log.getStackTraceString(e));
701 return null;
702 }
703 }
704
705 private KeymasterArguments makeLegacyArguments(String algorithm) {
706 KeymasterArguments args = new KeymasterArguments();
707 args.addEnum(KeymasterDefs.KM_TAG_ALGORITHM,
708 KeyProperties.KeyAlgorithm.toKeymasterAsymmetricKeyAlgorithm(algorithm));
709 args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_SIGN);
710 args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_VERIFY);
711 args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_ENCRYPT);
712 args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_DECRYPT);
713 args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_NONE);
714 if (algorithm.equalsIgnoreCase(KeyProperties.KEY_ALGORITHM_RSA)) {
715 args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_RSA_OAEP);
716 args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_ENCRYPT);
717 args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_SIGN);
718 args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_RSA_PSS);
719 }
720 args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_NONE);
721 args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_MD5);
722 args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA1);
723 args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA_2_224);
724 args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA_2_256);
725 args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA_2_384);
726 args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA_2_512);
727 args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED);
Janis Danisevskis2b106ad2018-11-15 09:27:16 -0800728 args.addDate(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME, new Date(Long.MAX_VALUE));
729 args.addDate(KeymasterDefs.KM_TAG_USAGE_EXPIRE_DATETIME, new Date(Long.MAX_VALUE));
730 args.addDate(KeymasterDefs.KM_TAG_ACTIVE_DATETIME, new Date(0));
Janis Danisevskis1864c952018-08-09 11:14:49 -0700731 return args;
732 }
733
734 public boolean importKey(String alias, byte[] keyData, int uid, int flags) {
735 String algorithm = getAlgorithmFromPKCS8(keyData);
736 if (algorithm == null) return false;
737 KeymasterArguments args = makeLegacyArguments(algorithm);
738 KeyCharacteristics out = new KeyCharacteristics();
739 int result = importKey(alias, args, KeymasterDefs.KM_KEY_FORMAT_PKCS8, keyData, uid,
740 flags, out);
741 if (result != NO_ERROR) {
742 Log.e(TAG, Log.getStackTraceString(
743 new KeyStoreException(result, "legacy key import failed")));
744 return false;
745 }
746 return true;
747 }
748
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700749 private int importWrappedKeyInternal(String wrappedKeyAlias, byte[] wrappedKey,
750 String wrappingKeyAlias,
751 byte[] maskingKey, KeymasterArguments args, long rootSid, long fingerprintSid,
752 KeyCharacteristics outCharacteristics)
753 throws RemoteException, ExecutionException, InterruptedException {
754 KeyCharacteristicsPromise promise = new KeyCharacteristicsPromise();
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700755 mBinder.asBinder().linkToDeath(promise, 0);
756 try {
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700757 int error = mBinder.importWrappedKey(promise, wrappedKeyAlias, wrappedKey,
758 wrappingKeyAlias, maskingKey, args, rootSid, fingerprintSid);
759 if (error != NO_ERROR) return error;
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700760
Janis Danisevskisf924b7e2019-04-17 14:06:09 -0700761 KeyCharacteristicsCallbackResult result = promise.getFuture().get();
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700762
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700763 error = result.getKeystoreResponse().getErrorCode();
764 if (error != NO_ERROR) return error;
765
766 KeyCharacteristics characteristics = result.getKeyCharacteristics();
767 if (characteristics == null) return SYSTEM_ERROR;
768 outCharacteristics.shallowCopyFrom(characteristics);
769 return NO_ERROR;
770 } finally {
771 mBinder.asBinder().unlinkToDeath(promise, 0);
772 }
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700773 }
774
Frank Salim21d9c1d2017-12-19 22:38:09 -0800775 public int importWrappedKey(String wrappedKeyAlias, byte[] wrappedKey,
776 String wrappingKeyAlias,
777 byte[] maskingKey, KeymasterArguments args, long rootSid, long fingerprintSid, int uid,
778 KeyCharacteristics outCharacteristics) {
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700779 // TODO b/119217337 uid parameter gets silently ignored.
Frank Salim21d9c1d2017-12-19 22:38:09 -0800780 try {
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700781 int error = importWrappedKeyInternal(wrappedKeyAlias, wrappedKey, wrappingKeyAlias,
Frank Salim21d9c1d2017-12-19 22:38:09 -0800782 maskingKey, args, rootSid, fingerprintSid, outCharacteristics);
Janis Danisevskisd2575382018-10-08 07:56:58 -0700783 if (error == KEY_ALREADY_EXISTS) {
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700784 mBinder.del(wrappedKeyAlias, UID_SELF);
785 error = importWrappedKeyInternal(wrappedKeyAlias, wrappedKey, wrappingKeyAlias,
Janis Danisevskisd2575382018-10-08 07:56:58 -0700786 maskingKey, args, rootSid, fingerprintSid, outCharacteristics);
787 }
788 return error;
Frank Salim21d9c1d2017-12-19 22:38:09 -0800789 } catch (RemoteException e) {
790 Log.w(TAG, "Cannot connect to keystore", e);
791 return SYSTEM_ERROR;
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700792 } catch (ExecutionException | InterruptedException e) {
793 Log.e(TAG, "ImportWrappedKey completed with exception", e);
794 return SYSTEM_ERROR;
Frank Salim21d9c1d2017-12-19 22:38:09 -0800795 }
796 }
797
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700798 private class ExportKeyPromise
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700799 extends android.security.keystore.IKeystoreExportKeyCallback.Stub
800 implements IBinder.DeathRecipient {
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700801 final private CompletableFuture<ExportResult> future = new CompletableFuture<ExportResult>();
802 @Override
803 public void onFinished(ExportResult exportKeyResult) throws android.os.RemoteException {
804 future.complete(exportKeyResult);
805 }
806 public final CompletableFuture<ExportResult> getFuture() {
807 return future;
808 }
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700809 @Override
810 public void binderDied() {
811 future.completeExceptionally(new RemoteException("Keystore died"));
812 }
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700813 };
814
Chad Brubaker5e73c0e2015-03-21 22:46:43 -0700815 public ExportResult exportKey(String alias, int format, KeymasterBlob clientId,
Chad Brubaker5bbf0482015-09-09 14:53:52 -0700816 KeymasterBlob appId, int uid) {
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700817 ExportKeyPromise promise = new ExportKeyPromise();
Chad Brubakere6a461342015-02-10 21:33:23 -0800818 try {
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700819 mBinder.asBinder().linkToDeath(promise, 0);
Dmitry Dementyevefc43112017-10-27 23:10:28 -0700820 clientId = clientId != null ? clientId : new KeymasterBlob(new byte[0]);
821 appId = appId != null ? appId : new KeymasterBlob(new byte[0]);
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700822 int error = mBinder.exportKey(promise, alias, format, clientId, appId, uid);
823 if (error == NO_ERROR) {
824 return promise.getFuture().get();
825 } else {
826 return new ExportResult(error);
827 }
Chad Brubaker5bbf0482015-09-09 14:53:52 -0700828 } catch (RemoteException e) {
829 Log.w(TAG, "Cannot connect to keystore", e);
830 return null;
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700831 } catch (ExecutionException | InterruptedException e) {
832 Log.e(TAG, "ExportKey completed with exception", e);
833 return null;
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700834 } finally {
835 mBinder.asBinder().unlinkToDeath(promise, 0);
Chad Brubaker5bbf0482015-09-09 14:53:52 -0700836 }
837 }
838 public ExportResult exportKey(String alias, int format, KeymasterBlob clientId,
839 KeymasterBlob appId) {
840 return exportKey(alias, format, clientId, appId, UID_SELF);
841 }
842
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700843 private class OperationPromise
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700844 extends android.security.keystore.IKeystoreOperationResultCallback.Stub
845 implements IBinder.DeathRecipient {
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700846 final private CompletableFuture<OperationResult> future = new CompletableFuture<OperationResult>();
847 @Override
848 public void onFinished(OperationResult operationResult) throws android.os.RemoteException {
849 future.complete(operationResult);
850 }
851 public final CompletableFuture<OperationResult> getFuture() {
852 return future;
853 }
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700854 @Override
855 public void binderDied() {
856 future.completeExceptionally(new RemoteException("Keystore died"));
857 }
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700858 };
859
Chad Brubaker5bbf0482015-09-09 14:53:52 -0700860 public OperationResult begin(String alias, int purpose, boolean pruneable,
861 KeymasterArguments args, byte[] entropy, int uid) {
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700862 OperationPromise promise = new OperationPromise();
Chad Brubaker5bbf0482015-09-09 14:53:52 -0700863 try {
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700864 mBinder.asBinder().linkToDeath(promise, 0);
Dmitry Dementyevefc43112017-10-27 23:10:28 -0700865 args = args != null ? args : new KeymasterArguments();
866 entropy = entropy != null ? entropy : new byte[0];
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700867 int errorCode = mBinder.begin(promise, getToken(), alias, purpose, pruneable, args,
868 entropy, uid);
869 if (errorCode == NO_ERROR) {
870 return promise.getFuture().get();
871 } else {
872 return new OperationResult(errorCode);
873 }
Chad Brubakere6a461342015-02-10 21:33:23 -0800874 } catch (RemoteException e) {
875 Log.w(TAG, "Cannot connect to keystore", e);
876 return null;
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700877 } catch (ExecutionException | InterruptedException e) {
878 Log.e(TAG, "Begin completed with exception", e);
879 return null;
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700880 } finally {
881 mBinder.asBinder().unlinkToDeath(promise, 0);
Chad Brubakere6a461342015-02-10 21:33:23 -0800882 }
883 }
884
885 public OperationResult begin(String alias, int purpose, boolean pruneable,
Chad Brubaker966486e2015-06-01 12:57:06 -0700886 KeymasterArguments args, byte[] entropy) {
Dmitry Dementyevefc43112017-10-27 23:10:28 -0700887 entropy = entropy != null ? entropy : new byte[0];
888 args = args != null ? args : new KeymasterArguments();
Chad Brubaker5bbf0482015-09-09 14:53:52 -0700889 return begin(alias, purpose, pruneable, args, entropy, UID_SELF);
Chad Brubakere6a461342015-02-10 21:33:23 -0800890 }
891
892 public OperationResult update(IBinder token, KeymasterArguments arguments, byte[] input) {
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700893 OperationPromise promise = new OperationPromise();
Chad Brubakere6a461342015-02-10 21:33:23 -0800894 try {
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700895 mBinder.asBinder().linkToDeath(promise, 0);
Dmitry Dementyevefc43112017-10-27 23:10:28 -0700896 arguments = arguments != null ? arguments : new KeymasterArguments();
897 input = input != null ? input : new byte[0];
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700898 int errorCode = mBinder.update(promise, token, arguments, input);
899 if (errorCode == NO_ERROR) {
900 return promise.getFuture().get();
901 } else {
902 return new OperationResult(errorCode);
903 }
Chad Brubakere6a461342015-02-10 21:33:23 -0800904 } catch (RemoteException e) {
905 Log.w(TAG, "Cannot connect to keystore", e);
906 return null;
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700907 } catch (ExecutionException | InterruptedException e) {
908 Log.e(TAG, "Update completed with exception", e);
909 return null;
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700910 } finally {
911 mBinder.asBinder().unlinkToDeath(promise, 0);
Chad Brubakere6a461342015-02-10 21:33:23 -0800912 }
913 }
914
Chad Brubaker8a077012015-05-29 12:32:51 -0700915 public OperationResult finish(IBinder token, KeymasterArguments arguments, byte[] signature,
916 byte[] entropy) {
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700917 OperationPromise promise = new OperationPromise();
Chad Brubakere6a461342015-02-10 21:33:23 -0800918 try {
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700919 mBinder.asBinder().linkToDeath(promise, 0);
Dmitry Dementyevefc43112017-10-27 23:10:28 -0700920 arguments = arguments != null ? arguments : new KeymasterArguments();
921 entropy = entropy != null ? entropy : new byte[0];
922 signature = signature != null ? signature : new byte[0];
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700923 int errorCode = mBinder.finish(promise, token, arguments, signature, entropy);
924 if (errorCode == NO_ERROR) {
925 return promise.getFuture().get();
926 } else {
927 return new OperationResult(errorCode);
928 }
Chad Brubakere6a461342015-02-10 21:33:23 -0800929 } catch (RemoteException e) {
930 Log.w(TAG, "Cannot connect to keystore", e);
931 return null;
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700932 } catch (ExecutionException | InterruptedException e) {
933 Log.e(TAG, "Finish completed with exception", e);
934 return null;
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700935 } finally {
936 mBinder.asBinder().unlinkToDeath(promise, 0);
Chad Brubakere6a461342015-02-10 21:33:23 -0800937 }
938 }
939
Chad Brubaker8a077012015-05-29 12:32:51 -0700940 public OperationResult finish(IBinder token, KeymasterArguments arguments, byte[] signature) {
941 return finish(token, arguments, signature, null);
942 }
943
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700944 private class KeystoreResultPromise
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700945 extends android.security.keystore.IKeystoreResponseCallback.Stub
946 implements IBinder.DeathRecipient {
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700947 final private CompletableFuture<KeystoreResponse> future = new CompletableFuture<KeystoreResponse>();
948 @Override
949 public void onFinished(KeystoreResponse keystoreResponse) throws android.os.RemoteException {
950 future.complete(keystoreResponse);
951 }
952 public final CompletableFuture<KeystoreResponse> getFuture() {
953 return future;
954 }
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700955 @Override
956 public void binderDied() {
957 future.completeExceptionally(new RemoteException("Keystore died"));
958 }
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700959 };
960
Chad Brubakere6a461342015-02-10 21:33:23 -0800961 public int abort(IBinder token) {
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700962 KeystoreResultPromise promise = new KeystoreResultPromise();
Chad Brubakere6a461342015-02-10 21:33:23 -0800963 try {
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700964 mBinder.asBinder().linkToDeath(promise, 0);
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700965 int errorCode = mBinder.abort(promise, token);
966 if (errorCode == NO_ERROR) {
967 return promise.getFuture().get().getErrorCode();
968 } else {
969 return errorCode;
970 }
Chad Brubakere6a461342015-02-10 21:33:23 -0800971 } catch (RemoteException e) {
972 Log.w(TAG, "Cannot connect to keystore", e);
973 return SYSTEM_ERROR;
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700974 } catch (ExecutionException | InterruptedException e) {
975 Log.e(TAG, "Abort completed with exception", e);
976 return SYSTEM_ERROR;
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700977 } finally {
978 mBinder.asBinder().unlinkToDeath(promise, 0);
Chad Brubakere6a461342015-02-10 21:33:23 -0800979 }
980 }
Chad Brubaker5654b362015-03-17 16:59:52 -0700981
982 /**
Chad Brubaker5654b362015-03-17 16:59:52 -0700983 * Add an authentication record to the keystore authorization table.
984 *
985 * @param authToken The packed bytes of a hw_auth_token_t to be provided to keymaster.
986 * @return {@code KeyStore.NO_ERROR} on success, otherwise an error value corresponding to
987 * a {@code KeymasterDefs.KM_ERROR_} value or {@code KeyStore} ResponseCode.
988 */
Brian Youngda82e2c2018-02-22 23:36:34 +0000989 public int addAuthToken(byte[] authToken) {
Chad Brubaker5654b362015-03-17 16:59:52 -0700990 try {
Brian Youngda82e2c2018-02-22 23:36:34 +0000991 return mBinder.addAuthToken(authToken);
Chad Brubaker5654b362015-03-17 16:59:52 -0700992 } catch (RemoteException e) {
993 Log.w(TAG, "Cannot connect to keystore", e);
994 return SYSTEM_ERROR;
995 }
996 }
Alex Klyubinb4834ae2015-04-02 15:53:46 -0700997
Alex Klyubinad9ba102015-04-21 15:17:24 -0700998 /**
Chad Brubakera91a8502015-05-07 10:02:22 -0700999 * Notify keystore that a user's password has changed.
1000 *
1001 * @param userId the user whose password changed.
1002 * @param newPassword the new password or "" if the password was removed.
1003 */
1004 public boolean onUserPasswordChanged(int userId, String newPassword) {
1005 // Parcel.cpp doesn't support deserializing null strings and treats them as "". Make that
1006 // explicit here.
1007 if (newPassword == null) {
1008 newPassword = "";
1009 }
1010 try {
1011 return mBinder.onUserPasswordChanged(userId, newPassword) == NO_ERROR;
1012 } catch (RemoteException e) {
1013 Log.w(TAG, "Cannot connect to keystore", e);
1014 return false;
1015 }
1016 }
1017
Chad Brubaker83ce0952015-05-12 13:00:02 -07001018 /**
1019 * Notify keystore that a user was added.
1020 *
1021 * @param userId the new user.
1022 * @param parentId the parent of the new user, or -1 if the user has no parent. If parentId is
1023 * specified then the new user's keystore will be intialized with the same secure lockscreen
1024 * password as the parent.
1025 */
1026 public void onUserAdded(int userId, int parentId) {
1027 try {
1028 mBinder.onUserAdded(userId, parentId);
1029 } catch (RemoteException e) {
1030 Log.w(TAG, "Cannot connect to keystore", e);
1031 }
1032 }
1033
1034 /**
1035 * Notify keystore that a user was added.
1036 *
1037 * @param userId the new user.
1038 */
1039 public void onUserAdded(int userId) {
1040 onUserAdded(userId, -1);
1041 }
1042
1043 /**
1044 * Notify keystore that a user was removed.
1045 *
1046 * @param userId the removed user.
1047 */
1048 public void onUserRemoved(int userId) {
1049 try {
1050 mBinder.onUserRemoved(userId);
1051 } catch (RemoteException e) {
1052 Log.w(TAG, "Cannot connect to keystore", e);
1053 }
1054 }
1055
Chad Brubakera91a8502015-05-07 10:02:22 -07001056 public boolean onUserPasswordChanged(String newPassword) {
1057 return onUserPasswordChanged(UserHandle.getUserId(Process.myUid()), newPassword);
1058 }
1059
Janis Danisevskisb0358e72018-11-02 10:34:07 -07001060 private class KeyAttestationCallbackResult {
1061 private KeystoreResponse keystoreResponse;
1062 private KeymasterCertificateChain certificateChain;
1063
1064 public KeyAttestationCallbackResult(KeystoreResponse keystoreResponse,
1065 KeymasterCertificateChain certificateChain) {
1066 this.keystoreResponse = keystoreResponse;
1067 this.certificateChain = certificateChain;
1068 }
1069
1070 public KeystoreResponse getKeystoreResponse() {
1071 return keystoreResponse;
1072 }
1073
1074 public void setKeystoreResponse(KeystoreResponse keystoreResponse) {
1075 this.keystoreResponse = keystoreResponse;
1076 }
1077
1078 public KeymasterCertificateChain getCertificateChain() {
1079 return certificateChain;
1080 }
1081
1082 public void setCertificateChain(KeymasterCertificateChain certificateChain) {
1083 this.certificateChain = certificateChain;
1084 }
1085 }
1086
1087 private class CertificateChainPromise
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -07001088 extends android.security.keystore.IKeystoreCertificateChainCallback.Stub
1089 implements IBinder.DeathRecipient {
Janis Danisevskisb0358e72018-11-02 10:34:07 -07001090 final private CompletableFuture<KeyAttestationCallbackResult> future = new CompletableFuture<KeyAttestationCallbackResult>();
1091 @Override
1092 public void onFinished(KeystoreResponse keystoreResponse,
1093 KeymasterCertificateChain certificateChain) throws android.os.RemoteException {
1094 future.complete(new KeyAttestationCallbackResult(keystoreResponse, certificateChain));
1095 }
1096 public final CompletableFuture<KeyAttestationCallbackResult> getFuture() {
1097 return future;
1098 }
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -07001099 @Override
1100 public void binderDied() {
1101 future.completeExceptionally(new RemoteException("Keystore died"));
1102 }
Janis Danisevskisb0358e72018-11-02 10:34:07 -07001103 };
1104
1105
Shawn Willden8d8c7472016-02-02 08:27:39 -07001106 public int attestKey(
1107 String alias, KeymasterArguments params, KeymasterCertificateChain outChain) {
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -07001108 CertificateChainPromise promise = new CertificateChainPromise();
Shawn Willden8d8c7472016-02-02 08:27:39 -07001109 try {
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -07001110 mBinder.asBinder().linkToDeath(promise, 0);
Dmitry Dementyevefc43112017-10-27 23:10:28 -07001111 if (params == null) {
1112 params = new KeymasterArguments();
1113 }
1114 if (outChain == null) {
1115 outChain = new KeymasterCertificateChain();
1116 }
Janis Danisevskisb0358e72018-11-02 10:34:07 -07001117 int error = mBinder.attestKey(promise, alias, params);
1118 if (error != NO_ERROR) return error;
1119 KeyAttestationCallbackResult result = promise.getFuture().get();
1120 error = result.getKeystoreResponse().getErrorCode();
1121 if (error == NO_ERROR) {
1122 outChain.shallowCopyFrom(result.getCertificateChain());
1123 }
1124 return error;
Shawn Willden8d8c7472016-02-02 08:27:39 -07001125 } catch (RemoteException e) {
1126 Log.w(TAG, "Cannot connect to keystore", e);
1127 return SYSTEM_ERROR;
Janis Danisevskisb0358e72018-11-02 10:34:07 -07001128 } catch (ExecutionException | InterruptedException e) {
1129 Log.e(TAG, "AttestKey completed with exception", e);
1130 return SYSTEM_ERROR;
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -07001131 } finally {
1132 mBinder.asBinder().unlinkToDeath(promise, 0);
Shawn Willden8d8c7472016-02-02 08:27:39 -07001133 }
1134 }
1135
Bartosz Fabianowski237f4b362017-04-24 13:57:46 +02001136 public int attestDeviceIds(KeymasterArguments params, KeymasterCertificateChain outChain) {
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -07001137 CertificateChainPromise promise = new CertificateChainPromise();
Bartosz Fabianowski237f4b362017-04-24 13:57:46 +02001138 try {
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -07001139 mBinder.asBinder().linkToDeath(promise, 0);
Dmitry Dementyevefc43112017-10-27 23:10:28 -07001140 if (params == null) {
1141 params = new KeymasterArguments();
1142 }
1143 if (outChain == null) {
1144 outChain = new KeymasterCertificateChain();
1145 }
Janis Danisevskisb0358e72018-11-02 10:34:07 -07001146 int error = mBinder.attestDeviceIds(promise, params);
1147 if (error != NO_ERROR) return error;
1148 KeyAttestationCallbackResult result = promise.getFuture().get();
1149 error = result.getKeystoreResponse().getErrorCode();
1150 if (error == NO_ERROR) {
1151 outChain.shallowCopyFrom(result.getCertificateChain());
1152 }
1153 return error;
Bartosz Fabianowski237f4b362017-04-24 13:57:46 +02001154 } catch (RemoteException e) {
1155 Log.w(TAG, "Cannot connect to keystore", e);
1156 return SYSTEM_ERROR;
Janis Danisevskisb0358e72018-11-02 10:34:07 -07001157 } catch (ExecutionException | InterruptedException e) {
1158 Log.e(TAG, "AttestDevicdeIds completed with exception", e);
1159 return SYSTEM_ERROR;
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -07001160 } finally {
1161 mBinder.asBinder().unlinkToDeath(promise, 0);
Bartosz Fabianowski237f4b362017-04-24 13:57:46 +02001162 }
1163 }
1164
Tucker Sylvestrob32aae22016-06-23 17:23:33 -04001165 /**
1166 * Notify keystore that the device went off-body.
1167 */
1168 public void onDeviceOffBody() {
1169 try {
1170 mBinder.onDeviceOffBody();
1171 } catch (RemoteException e) {
1172 Log.w(TAG, "Cannot connect to keystore", e);
1173 }
1174 }
Shawn Willden8d8c7472016-02-02 08:27:39 -07001175
Janis Danisevskis7dacad82018-01-24 15:12:11 -08001176 // Keep in sync with confirmationui/1.0/types.hal.
1177 public static final int CONFIRMATIONUI_OK = 0;
1178 public static final int CONFIRMATIONUI_CANCELED = 1;
1179 public static final int CONFIRMATIONUI_ABORTED = 2;
1180 public static final int CONFIRMATIONUI_OPERATION_PENDING = 3;
1181 public static final int CONFIRMATIONUI_IGNORED = 4;
1182 public static final int CONFIRMATIONUI_SYSTEM_ERROR = 5;
1183 public static final int CONFIRMATIONUI_UNIMPLEMENTED = 6;
1184 public static final int CONFIRMATIONUI_UNEXPECTED = 7;
1185 public static final int CONFIRMATIONUI_UIERROR = 0x10000;
1186 public static final int CONFIRMATIONUI_UIERROR_MISSING_GLYPH = 0x10001;
1187 public static final int CONFIRMATIONUI_UIERROR_MESSAGE_TOO_LONG = 0x10002;
1188 public static final int CONFIRMATIONUI_UIERROR_MALFORMED_UTF8_ENCODING = 0x10003;
1189
1190 /**
1191 * Requests keystore call into the confirmationui HAL to display a prompt.
1192 *
1193 * @param listener the binder to use for callbacks.
1194 * @param promptText the prompt to display.
1195 * @param extraData extra data / nonce from application.
1196 * @param locale the locale as a BCP 47 langauge tag.
1197 * @param uiOptionsAsFlags the UI options to use, as flags.
1198 * @return one of the {@code CONFIRMATIONUI_*} constants, for
1199 * example {@code KeyStore.CONFIRMATIONUI_OK}.
1200 */
1201 public int presentConfirmationPrompt(IBinder listener, String promptText, byte[] extraData,
1202 String locale, int uiOptionsAsFlags) {
1203 try {
1204 return mBinder.presentConfirmationPrompt(listener, promptText, extraData, locale,
1205 uiOptionsAsFlags);
1206 } catch (RemoteException e) {
1207 Log.w(TAG, "Cannot connect to keystore", e);
1208 return CONFIRMATIONUI_SYSTEM_ERROR;
1209 }
1210 }
1211
1212 /**
1213 * Requests keystore call into the confirmationui HAL to cancel displaying a prompt.
1214 *
1215 * @param listener the binder passed to the {@link #presentConfirmationPrompt} method.
1216 * @return one of the {@code CONFIRMATIONUI_*} constants, for
1217 * example {@code KeyStore.CONFIRMATIONUI_OK}.
1218 */
1219 public int cancelConfirmationPrompt(IBinder listener) {
1220 try {
1221 return mBinder.cancelConfirmationPrompt(listener);
1222 } catch (RemoteException e) {
1223 Log.w(TAG, "Cannot connect to keystore", e);
1224 return CONFIRMATIONUI_SYSTEM_ERROR;
1225 }
1226 }
1227
Chad Brubakera91a8502015-05-07 10:02:22 -07001228 /**
David Zeuthenbbb7f652018-02-26 11:04:18 -05001229 * Requests keystore to check if the confirmationui HAL is available.
1230 *
1231 * @return whether the confirmationUI HAL is available.
1232 */
1233 public boolean isConfirmationPromptSupported() {
1234 try {
1235 return mBinder.isConfirmationPromptSupported();
1236 } catch (RemoteException e) {
1237 Log.w(TAG, "Cannot connect to keystore", e);
1238 return false;
1239 }
1240 }
1241
1242 /**
Alex Klyubinad9ba102015-04-21 15:17:24 -07001243 * Returns a {@link KeyStoreException} corresponding to the provided keystore/keymaster error
1244 * code.
1245 */
Mathew Inwoode420f8b2018-08-16 18:40:47 +01001246 @UnsupportedAppUsage
Alex Klyubindcdaf872015-05-13 15:57:09 -07001247 public static KeyStoreException getKeyStoreException(int errorCode) {
Alex Klyubinb4834ae2015-04-02 15:53:46 -07001248 if (errorCode > 0) {
1249 // KeyStore layer error
1250 switch (errorCode) {
1251 case NO_ERROR:
1252 return new KeyStoreException(errorCode, "OK");
1253 case LOCKED:
Alex Klyubin54183932015-05-08 15:25:48 -07001254 return new KeyStoreException(errorCode, "User authentication required");
Alex Klyubinb4834ae2015-04-02 15:53:46 -07001255 case UNINITIALIZED:
1256 return new KeyStoreException(errorCode, "Keystore not initialized");
1257 case SYSTEM_ERROR:
1258 return new KeyStoreException(errorCode, "System error");
1259 case PERMISSION_DENIED:
1260 return new KeyStoreException(errorCode, "Permission denied");
1261 case KEY_NOT_FOUND:
1262 return new KeyStoreException(errorCode, "Key not found");
1263 case VALUE_CORRUPTED:
1264 return new KeyStoreException(errorCode, "Key blob corrupted");
Alex Klyubin058de022015-04-29 17:32:00 -07001265 case OP_AUTH_NEEDED:
1266 return new KeyStoreException(errorCode, "Operation requires authorization");
Max Bires13f98ce2018-11-02 10:50:40 -07001267 case KEY_PERMANENTLY_INVALIDATED:
1268 return new KeyStoreException(errorCode, "Key permanently invalidated");
Alex Klyubinb4834ae2015-04-02 15:53:46 -07001269 default:
1270 return new KeyStoreException(errorCode, String.valueOf(errorCode));
1271 }
1272 } else {
1273 // Keymaster layer error
1274 switch (errorCode) {
1275 case KeymasterDefs.KM_ERROR_INVALID_AUTHORIZATION_TIMEOUT:
1276 // The name of this parameter significantly differs between Keymaster and
1277 // framework APIs. Use the framework wording to make life easier for developers.
1278 return new KeyStoreException(errorCode,
1279 "Invalid user authentication validity duration");
1280 default:
1281 return new KeyStoreException(errorCode,
1282 KeymasterDefs.getErrorMessage(errorCode));
1283 }
1284 }
1285 }
1286
Alex Klyubinad9ba102015-04-21 15:17:24 -07001287 /**
1288 * Returns an {@link InvalidKeyException} corresponding to the provided
1289 * {@link KeyStoreException}.
1290 */
Alex Klyubindcdaf872015-05-13 15:57:09 -07001291 public InvalidKeyException getInvalidKeyException(
Alex Klyubin3876b1b2015-09-09 14:55:03 -07001292 String keystoreKeyAlias, int uid, KeyStoreException e) {
Alex Klyubinb4834ae2015-04-02 15:53:46 -07001293 switch (e.getErrorCode()) {
Brian Youngda82e2c2018-02-22 23:36:34 +00001294 case LOCKED:
Alex Klyubin54183932015-05-08 15:25:48 -07001295 return new UserNotAuthenticatedException();
Brian Youngda82e2c2018-02-22 23:36:34 +00001296 case KeymasterDefs.KM_ERROR_KEY_EXPIRED:
Alex Klyubinb4834ae2015-04-02 15:53:46 -07001297 return new KeyExpiredException();
Brian Youngda82e2c2018-02-22 23:36:34 +00001298 case KeymasterDefs.KM_ERROR_KEY_NOT_YET_VALID:
Alex Klyubinb4834ae2015-04-02 15:53:46 -07001299 return new KeyNotYetValidException();
Brian Youngda82e2c2018-02-22 23:36:34 +00001300 case KeymasterDefs.KM_ERROR_KEY_USER_NOT_AUTHENTICATED:
1301 case OP_AUTH_NEEDED:
Alex Klyubin708fc9402015-04-28 18:58:47 -07001302 {
1303 // We now need to determine whether the key/operation can become usable if user
1304 // authentication is performed, or whether it can never become usable again.
1305 // User authentication requirements are contained in the key's characteristics. We
1306 // need to check whether these requirements can be be satisfied by asking the user
1307 // to authenticate.
1308 KeyCharacteristics keyCharacteristics = new KeyCharacteristics();
1309 int getKeyCharacteristicsErrorCode =
Alex Klyubin3876b1b2015-09-09 14:55:03 -07001310 getKeyCharacteristics(keystoreKeyAlias, null, null, uid,
1311 keyCharacteristics);
Alex Klyubin708fc9402015-04-28 18:58:47 -07001312 if (getKeyCharacteristicsErrorCode != NO_ERROR) {
1313 return new InvalidKeyException(
1314 "Failed to obtained key characteristics",
1315 getKeyStoreException(getKeyCharacteristicsErrorCode));
1316 }
Alex Klyubinae6cb7a2015-06-22 18:09:35 -07001317 List<BigInteger> keySids =
1318 keyCharacteristics.getUnsignedLongs(KeymasterDefs.KM_TAG_USER_SECURE_ID);
Alex Klyubin708fc9402015-04-28 18:58:47 -07001319 if (keySids.isEmpty()) {
1320 // Key is not bound to any SIDs -- no amount of authentication will help here.
1321 return new KeyPermanentlyInvalidatedException();
1322 }
1323 long rootSid = GateKeeper.getSecureUserId();
Alex Klyubinae6cb7a2015-06-22 18:09:35 -07001324 if ((rootSid != 0) && (keySids.contains(KeymasterArguments.toUint64(rootSid)))) {
Alex Klyubin708fc9402015-04-28 18:58:47 -07001325 // One of the key's SIDs is the current root SID -- user can be authenticated
1326 // against that SID.
1327 return new UserNotAuthenticatedException();
1328 }
1329
Kevin Chyn057b7432018-09-24 14:36:39 -07001330 final long fingerprintOnlySid = getFingerprintOnlySid();
Alex Klyubin708fc9402015-04-28 18:58:47 -07001331 if ((fingerprintOnlySid != 0)
Alex Klyubinae6cb7a2015-06-22 18:09:35 -07001332 && (keySids.contains(KeymasterArguments.toUint64(fingerprintOnlySid)))) {
Alex Klyubin708fc9402015-04-28 18:58:47 -07001333 // One of the key's SIDs is the current fingerprint SID -- user can be
1334 // authenticated against that SID.
1335 return new UserNotAuthenticatedException();
1336 }
1337
Kevin Chyn057b7432018-09-24 14:36:39 -07001338 final long faceOnlySid = getFaceOnlySid();
1339 if ((faceOnlySid != 0)
1340 && (keySids.contains(KeymasterArguments.toUint64(faceOnlySid)))) {
1341 // One of the key's SIDs is the current face SID -- user can be
1342 // authenticated against that SID.
1343 return new UserNotAuthenticatedException();
1344 }
1345
Alex Klyubin708fc9402015-04-28 18:58:47 -07001346 // None of the key's SIDs can ever be authenticated
1347 return new KeyPermanentlyInvalidatedException();
1348 }
Brian Youngda82e2c2018-02-22 23:36:34 +00001349 case UNINITIALIZED:
Janis Danisevskisd07d3382017-09-01 14:45:16 -07001350 return new KeyPermanentlyInvalidatedException();
Alex Klyubinb4834ae2015-04-02 15:53:46 -07001351 default:
Alex Klyubinad9ba102015-04-21 15:17:24 -07001352 return new InvalidKeyException("Keystore operation failed", e);
Alex Klyubinb4834ae2015-04-02 15:53:46 -07001353 }
1354 }
1355
Kevin Chyn057b7432018-09-24 14:36:39 -07001356 private long getFaceOnlySid() {
1357 final PackageManager packageManager = mContext.getPackageManager();
1358 if (!packageManager.hasSystemFeature(PackageManager.FEATURE_FACE)) {
1359 return 0;
1360 }
1361 FaceManager faceManager = mContext.getSystemService(FaceManager.class);
1362 if (faceManager == null) {
1363 return 0;
1364 }
1365
1366 // TODO: Restore USE_BIOMETRIC or USE_BIOMETRIC_INTERNAL permission check in
1367 // FaceManager.getAuthenticatorId once the ID is no longer needed here.
1368 return faceManager.getAuthenticatorId();
1369 }
1370
Alex Klyubin2d7a85c2015-04-30 11:43:53 -07001371 private long getFingerprintOnlySid() {
Kevin Chyn55966422017-10-23 16:08:47 -07001372 final PackageManager packageManager = mContext.getPackageManager();
1373 if (!packageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) {
1374 return 0;
1375 }
Alex Klyubina99b8b52015-06-11 13:27:34 -07001376 FingerprintManager fingerprintManager = mContext.getSystemService(FingerprintManager.class);
Alex Klyubin2d7a85c2015-04-30 11:43:53 -07001377 if (fingerprintManager == null) {
Alex Klyubin708fc9402015-04-28 18:58:47 -07001378 return 0;
1379 }
1380
Alex Klyubina99b8b52015-06-11 13:27:34 -07001381 // TODO: Restore USE_FINGERPRINT permission check in
1382 // FingerprintManager.getAuthenticatorId once the ID is no longer needed here.
Alex Klyubin2d7a85c2015-04-30 11:43:53 -07001383 return fingerprintManager.getAuthenticatorId();
Svetoslav2dac95d2015-04-30 11:30:33 -07001384 }
1385
Alex Klyubinad9ba102015-04-21 15:17:24 -07001386 /**
1387 * Returns an {@link InvalidKeyException} corresponding to the provided keystore/keymaster error
1388 * code.
1389 */
Alex Klyubin3876b1b2015-09-09 14:55:03 -07001390 public InvalidKeyException getInvalidKeyException(String keystoreKeyAlias, int uid,
1391 int errorCode) {
1392 return getInvalidKeyException(keystoreKeyAlias, uid, getKeyStoreException(errorCode));
Alex Klyubinb4834ae2015-04-02 15:53:46 -07001393 }
Chia-chi Yeh44039172009-09-21 11:53:59 +08001394}