blob: e9bc8026d25eb3e94bb935ec54aaf4174bac2fd7 [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 Satayev7651f0a2019-12-10 17:47:55 +000022import android.compat.annotation.UnsupportedAppUsage;
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;
Chad Brubakere6a461342015-02-10 21:33:23 -080034import android.security.keymaster.ExportResult;
35import android.security.keymaster.KeyCharacteristics;
36import android.security.keymaster.KeymasterArguments;
Chad Brubaker5e73c0e2015-03-21 22:46:43 -070037import android.security.keymaster.KeymasterBlob;
Shawn Willden8d8c7472016-02-02 08:27:39 -070038import android.security.keymaster.KeymasterCertificateChain;
Alex Klyubinb4834ae2015-04-02 15:53:46 -070039import android.security.keymaster.KeymasterDefs;
Chad Brubakere6a461342015-02-10 21:33:23 -080040import android.security.keymaster.OperationResult;
Janis Danisevskisb0358e72018-11-02 10:34:07 -070041import android.security.keystore.IKeystoreService;
Alex Klyubin3f8d4d82015-05-13 09:15:00 -070042import android.security.keystore.KeyExpiredException;
43import android.security.keystore.KeyNotYetValidException;
44import android.security.keystore.KeyPermanentlyInvalidatedException;
Janis Danisevskis1864c952018-08-09 11:14:49 -070045import android.security.keystore.KeyProperties;
Janis Danisevskisb0358e72018-11-02 10:34:07 -070046import android.security.keystore.KeystoreResponse;
Alex Klyubin3f8d4d82015-05-13 09:15:00 -070047import android.security.keystore.UserNotAuthenticatedException;
Kenny Root6b776452012-11-02 15:40:32 -070048import android.util.Log;
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -070049
Janis Danisevskis1864c952018-08-09 11:14:49 -070050import com.android.org.bouncycastle.asn1.ASN1InputStream;
51import com.android.org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -070052
Janis Danisevskis1864c952018-08-09 11:14:49 -070053import java.io.ByteArrayInputStream;
54import java.io.IOException;
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -070055import java.math.BigInteger;
Alex Klyubinad9ba102015-04-21 15:17:24 -070056import java.security.InvalidKeyException;
Rob Barnesebe26742018-11-13 15:57:22 -070057import java.util.ArrayList;
Janis Danisevskis2b106ad2018-11-15 09:27:16 -080058import java.util.Date;
Alex Klyubin708fc9402015-04-28 18:58:47 -070059import java.util.List;
Kenny Rootb91773b2013-09-05 13:03:16 -070060import java.util.Locale;
Janis Danisevskisb0358e72018-11-02 10:34:07 -070061import java.util.concurrent.CompletableFuture;
62import java.util.concurrent.ExecutionException;
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -070063
Janis Danisevskis1864c952018-08-09 11:14:49 -070064import sun.security.util.ObjectIdentifier;
65import sun.security.x509.AlgorithmId;
Kenny Rootb91773b2013-09-05 13:03:16 -070066
Chia-chi Yeh44039172009-09-21 11:53:59 +080067/**
Brian Carlstrom46703b02011-04-06 15:41:29 -070068 * @hide This should not be made public in its present form because it
69 * assumes that private and secret key bytes are available and would
70 * preclude the use of hardware crypto.
Chia-chi Yeh44039172009-09-21 11:53:59 +080071 */
72public class KeyStore {
Kenny Root6b776452012-11-02 15:40:32 -070073 private static final String TAG = "KeyStore";
Brian Carlstrom5cfee3f2011-05-31 01:00:15 -070074
Dmitry Dementyevefc43112017-10-27 23:10:28 -070075 // ResponseCodes - see system/security/keystore/include/keystore/keystore.h
Mathew Inwoode420f8b2018-08-16 18:40:47 +010076 @UnsupportedAppUsage
Brian Carlstrom7e4b1a42011-06-01 15:29:29 -070077 public static final int NO_ERROR = 1;
78 public static final int LOCKED = 2;
79 public static final int UNINITIALIZED = 3;
80 public static final int SYSTEM_ERROR = 4;
81 public static final int PROTOCOL_ERROR = 5;
82 public static final int PERMISSION_DENIED = 6;
83 public static final int KEY_NOT_FOUND = 7;
84 public static final int VALUE_CORRUPTED = 8;
85 public static final int UNDEFINED_ACTION = 9;
86 public static final int WRONG_PASSWORD = 10;
Janis Danisevskisd2575382018-10-08 07:56:58 -070087 public static final int KEY_ALREADY_EXISTS = 16;
Eran Messeri61692392018-03-26 16:43:14 +010088 public static final int CANNOT_ATTEST_IDS = -66;
Frank Salimea5e0382018-01-23 22:42:29 -080089 public static final int HARDWARE_TYPE_UNAVAILABLE = -68;
Brian Carlstrom5cfee3f2011-05-31 01:00:15 -070090
Chad Brubaker560d6532015-04-24 10:32:18 -070091 /**
92 * Per operation authentication is needed before this operation is valid.
93 * This is returned from {@link #begin} when begin succeeds but the operation uses
94 * per-operation authentication and must authenticate before calling {@link #update} or
95 * {@link #finish}.
96 */
97 public static final int OP_AUTH_NEEDED = 15;
98
Max Bires13f98ce2018-11-02 10:50:40 -070099 // Used when a user changes their pin, invalidating old auth bound keys.
100 public static final int KEY_PERMANENTLY_INVALIDATED = 17;
101
Kenny Root2eeda722013-04-10 11:30:58 -0700102 // Used for UID field to indicate the calling UID.
103 public static final int UID_SELF = -1;
104
105 // Flags for "put" "import" and "generate"
106 public static final int FLAG_NONE = 0;
Alex Klyubin54183932015-05-08 15:25:48 -0700107
108 /**
109 * Indicates that this key (or key pair) must be encrypted at rest. This will protect the key
110 * (or key pair) with the secure lock screen credential (e.g., password, PIN, or pattern).
111 *
112 * <p>Note that this requires that the secure lock screen (e.g., password, PIN, pattern) is set
113 * up, otherwise key (or key pair) generation or import will fail. Moreover, this key (or key
114 * pair) will be deleted when the secure lock screen is disabled or reset (e.g., by the user or
115 * a Device Administrator). Finally, this key (or key pair) cannot be used until the user
116 * unlocks the secure lock screen after boot.
117 *
118 * @see KeyguardManager#isDeviceSecure()
119 */
Kenny Roota3788b02013-04-10 10:37:55 -0700120 public static final int FLAG_ENCRYPTED = 1;
121
Rubin Xu12b644d2017-04-21 19:21:42 +0100122 /**
Janis Danisevskis0aadf932017-12-18 17:28:52 -0800123 * Select Software keymaster device, which as of this writing is the lowest security
124 * level available on an android device. If neither FLAG_STRONGBOX nor FLAG_SOFTWARE is provided
125 * A TEE based keymaster implementation is implied.
126 *
127 * Need to be in sync with KeyStoreFlag in system/security/keystore/include/keystore/keystore.h
128 * For historical reasons this corresponds to the KEYSTORE_FLAG_FALLBACK flag.
129 */
130 public static final int FLAG_SOFTWARE = 1 << 1;
131
132 /**
Rubin Xu12b644d2017-04-21 19:21:42 +0100133 * A private flag that's only available to system server to indicate that this key is part of
134 * device encryption flow so it receives special treatment from keystore. For example this key
135 * will not be super encrypted, and it will be stored separately under an unique UID instead
136 * of the caller UID i.e. SYSTEM.
137 *
138 * Need to be in sync with KeyStoreFlag in system/security/keystore/include/keystore/keystore.h
139 */
140 public static final int FLAG_CRITICAL_TO_DEVICE_ENCRYPTION = 1 << 3;
141
Janis Danisevskis0aadf932017-12-18 17:28:52 -0800142 /**
143 * Select Strongbox keymaster device, which as of this writing the the highest security level
144 * available an android devices. If neither FLAG_STRONGBOX nor FLAG_SOFTWARE is provided
145 * A TEE based keymaster implementation is implied.
146 *
147 * Need to be in sync with KeyStoreFlag in system/security/keystore/include/keystore/keystore.h
148 */
149 public static final int FLAG_STRONGBOX = 1 << 4;
150
Brian Carlstrom5cfee3f2011-05-31 01:00:15 -0700151 // States
Mathew Inwoodefb48162018-08-01 10:24:49 +0100152 public enum State {
Mathew Inwoode420f8b2018-08-16 18:40:47 +0100153 @UnsupportedAppUsage
Mathew Inwoodefb48162018-08-01 10:24:49 +0100154 UNLOCKED,
Mathew Inwoode420f8b2018-08-16 18:40:47 +0100155 @UnsupportedAppUsage
Mathew Inwoodefb48162018-08-01 10:24:49 +0100156 LOCKED,
157 UNINITIALIZED
158 };
Chia-chi Yeh44039172009-09-21 11:53:59 +0800159
Chia-chi Yeh44039172009-09-21 11:53:59 +0800160 private int mError = NO_ERROR;
161
Kenny Root6b776452012-11-02 15:40:32 -0700162 private final IKeystoreService mBinder;
Alex Klyubin2d7a85c2015-04-30 11:43:53 -0700163 private final Context mContext;
Kenny Root6b776452012-11-02 15:40:32 -0700164
Chad Brubakere6a461342015-02-10 21:33:23 -0800165 private IBinder mToken;
166
Kenny Root6b776452012-11-02 15:40:32 -0700167 private KeyStore(IKeystoreService binder) {
168 mBinder = binder;
Alex Klyubin3f8d4d82015-05-13 09:15:00 -0700169 mContext = getApplicationContext();
Alex Klyubin2d7a85c2015-04-30 11:43:53 -0700170 }
171
Mathew Inwoode420f8b2018-08-16 18:40:47 +0100172 @UnsupportedAppUsage
Alex Klyubindcdaf872015-05-13 15:57:09 -0700173 public static Context getApplicationContext() {
Alex Klyubina99b8b52015-06-11 13:27:34 -0700174 Application application = ActivityThread.currentApplication();
Alex Klyubin2d7a85c2015-04-30 11:43:53 -0700175 if (application == null) {
176 throw new IllegalStateException(
Alex Klyubina99b8b52015-06-11 13:27:34 -0700177 "Failed to obtain application Context from ActivityThread");
Alex Klyubin2d7a85c2015-04-30 11:43:53 -0700178 }
179 return application;
Kenny Root6b776452012-11-02 15:40:32 -0700180 }
Chia-chi Yeh44039172009-09-21 11:53:59 +0800181
Mathew Inwoode420f8b2018-08-16 18:40:47 +0100182 @UnsupportedAppUsage
Chia-chi Yeh44039172009-09-21 11:53:59 +0800183 public static KeyStore getInstance() {
Kenny Root6b776452012-11-02 15:40:32 -0700184 IKeystoreService keystore = IKeystoreService.Stub.asInterface(ServiceManager
185 .getService("android.security.keystore"));
186 return new KeyStore(keystore);
Chia-chi Yeh44039172009-09-21 11:53:59 +0800187 }
188
Chad Brubakere6a461342015-02-10 21:33:23 -0800189 private synchronized IBinder getToken() {
190 if (mToken == null) {
191 mToken = new Binder();
192 }
193 return mToken;
194 }
195
Mathew Inwoode420f8b2018-08-16 18:40:47 +0100196 @UnsupportedAppUsage
Chad Brubakere35d49f2015-05-12 15:19:52 -0700197 public State state(int userId) {
Kenny Root6b776452012-11-02 15:40:32 -0700198 final int ret;
199 try {
Chad Brubakere35d49f2015-05-12 15:19:52 -0700200 ret = mBinder.getState(userId);
Kenny Root6b776452012-11-02 15:40:32 -0700201 } catch (RemoteException e) {
202 Log.w(TAG, "Cannot connect to keystore", e);
203 throw new AssertionError(e);
204 }
205
206 switch (ret) {
Brian Carlstrom5cfee3f2011-05-31 01:00:15 -0700207 case NO_ERROR: return State.UNLOCKED;
208 case LOCKED: return State.LOCKED;
209 case UNINITIALIZED: return State.UNINITIALIZED;
210 default: throw new AssertionError(mError);
211 }
Chia-chi Yeh44039172009-09-21 11:53:59 +0800212 }
213
Mathew Inwoode420f8b2018-08-16 18:40:47 +0100214 @UnsupportedAppUsage
Chad Brubakere35d49f2015-05-12 15:19:52 -0700215 public State state() {
216 return state(UserHandle.myUserId());
217 }
218
Kenny Rootb9594ce2013-02-14 10:18:38 -0800219 public boolean isUnlocked() {
220 return state() == State.UNLOCKED;
221 }
222
Chad Brubaker5bbf0482015-09-09 14:53:52 -0700223 public byte[] get(String key, int uid) {
Irina Dumitrescu4a1cccc2018-06-08 19:36:34 +0100224 return get(key, uid, false);
Chia-chi Yeh44039172009-09-21 11:53:59 +0800225 }
226
Mathew Inwoode420f8b2018-08-16 18:40:47 +0100227 @UnsupportedAppUsage
Chad Brubaker5bbf0482015-09-09 14:53:52 -0700228 public byte[] get(String key) {
229 return get(key, UID_SELF);
230 }
231
Irina Dumitrescu4a1cccc2018-06-08 19:36:34 +0100232 public byte[] get(String key, int uid, boolean suppressKeyNotFoundWarning) {
233 try {
234 key = key != null ? key : "";
235 return mBinder.get(key, uid);
236 } catch (RemoteException e) {
237 Log.w(TAG, "Cannot connect to keystore", e);
238 return null;
239 } catch (android.os.ServiceSpecificException e) {
240 if (!suppressKeyNotFoundWarning || e.errorCode != KEY_NOT_FOUND) {
241 Log.w(TAG, "KeyStore exception", e);
242 }
243 return null;
244 }
245 }
246
247 public byte[] get(String key, boolean suppressKeyNotFoundWarning) {
248 return get(key, UID_SELF, suppressKeyNotFoundWarning);
249 }
250
251
Kenny Roota3788b02013-04-10 10:37:55 -0700252 public boolean put(String key, byte[] value, int uid, int flags) {
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700253 return insert(key, value, uid, flags) == NO_ERROR;
254 }
255
256 public int insert(String key, byte[] value, int uid, int flags) {
Kenny Root6b776452012-11-02 15:40:32 -0700257 try {
Dmitry Dementyevefc43112017-10-27 23:10:28 -0700258 if (value == null) {
259 value = new byte[0];
260 }
Janis Danisevskisd2575382018-10-08 07:56:58 -0700261 int error = mBinder.insert(key, value, uid, flags);
262 if (error == KEY_ALREADY_EXISTS) {
263 mBinder.del(key, uid);
264 error = mBinder.insert(key, value, uid, flags);
265 }
266 return error;
Kenny Root78ad8492013-02-13 17:02:57 -0800267 } catch (RemoteException e) {
268 Log.w(TAG, "Cannot connect to keystore", e);
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700269 return SYSTEM_ERROR;
Kenny Root78ad8492013-02-13 17:02:57 -0800270 }
271 }
272
Janis Danisevskis906147c2018-11-06 14:14:05 -0800273 int delete2(String key, int uid) {
Kenny Root78ad8492013-02-13 17:02:57 -0800274 try {
Janis Danisevskis906147c2018-11-06 14:14:05 -0800275 return mBinder.del(key, uid);
Kenny Root6b776452012-11-02 15:40:32 -0700276 } catch (RemoteException e) {
277 Log.w(TAG, "Cannot connect to keystore", e);
Janis Danisevskis906147c2018-11-06 14:14:05 -0800278 return SYSTEM_ERROR;
Kenny Root6b776452012-11-02 15:40:32 -0700279 }
Chia-chi Yeh44039172009-09-21 11:53:59 +0800280 }
281
Janis Danisevskis906147c2018-11-06 14:14:05 -0800282 public boolean delete(String key, int uid) {
283 int ret = delete2(key, uid);
284 return ret == NO_ERROR || ret == KEY_NOT_FOUND;
285 }
286
Mathew Inwoode420f8b2018-08-16 18:40:47 +0100287 @UnsupportedAppUsage
Chia-chi Yeh44039172009-09-21 11:53:59 +0800288 public boolean delete(String key) {
Kenny Root2eeda722013-04-10 11:30:58 -0700289 return delete(key, UID_SELF);
Kenny Root78ad8492013-02-13 17:02:57 -0800290 }
291
292 public boolean contains(String key, int uid) {
Kenny Root6b776452012-11-02 15:40:32 -0700293 try {
Kenny Root78ad8492013-02-13 17:02:57 -0800294 return mBinder.exist(key, uid) == NO_ERROR;
Kenny Root6b776452012-11-02 15:40:32 -0700295 } catch (RemoteException e) {
296 Log.w(TAG, "Cannot connect to keystore", e);
297 return false;
298 }
Chia-chi Yeh44039172009-09-21 11:53:59 +0800299 }
300
301 public boolean contains(String key) {
Kenny Root2eeda722013-04-10 11:30:58 -0700302 return contains(key, UID_SELF);
Chia-chi Yeh44039172009-09-21 11:53:59 +0800303 }
304
Chad Brubakere35d49f2015-05-12 15:19:52 -0700305 /**
306 * List all entries in the keystore for {@code uid} starting with {@code prefix}.
307 */
308 public String[] list(String prefix, int uid) {
Kenny Root6b776452012-11-02 15:40:32 -0700309 try {
Chad Brubakere35d49f2015-05-12 15:19:52 -0700310 return mBinder.list(prefix, uid);
Kenny Root6b776452012-11-02 15:40:32 -0700311 } catch (RemoteException e) {
312 Log.w(TAG, "Cannot connect to keystore", e);
Chia-chi Yeh44039172009-09-21 11:53:59 +0800313 return null;
Dmitry Dementyevefc43112017-10-27 23:10:28 -0700314 } catch (android.os.ServiceSpecificException e) {
315 Log.w(TAG, "KeyStore exception", e);
316 return null;
Chia-chi Yeh44039172009-09-21 11:53:59 +0800317 }
Chia-chi Yeh44039172009-09-21 11:53:59 +0800318 }
319
Rob Barnesf1a678e2018-11-13 15:57:22 -0700320 /**
Rob Barnesebe26742018-11-13 15:57:22 -0700321 * List uids of all keys that are auth bound to the current user.
Rob Barnesf1a678e2018-11-13 15:57:22 -0700322 * Only system is allowed to call this method.
323 */
324 @UnsupportedAppUsage
325 public int[] listUidsOfAuthBoundKeys() {
Rob Barnesebe26742018-11-13 15:57:22 -0700326 // uids are returned as a list of strings because list of integers
327 // as an output parameter is not supported by aidl-cpp.
328 List<String> uidsOut = new ArrayList<>();
Rob Barnesf1a678e2018-11-13 15:57:22 -0700329 try {
330 int rc = mBinder.listUidsOfAuthBoundKeys(uidsOut);
331 if (rc != NO_ERROR) {
332 Log.w(TAG, String.format("listUidsOfAuthBoundKeys failed with error code %d", rc));
333 return null;
334 }
335 } catch (RemoteException e) {
336 Log.w(TAG, "Cannot connect to keystore", e);
337 return null;
338 } catch (android.os.ServiceSpecificException e) {
339 Log.w(TAG, "KeyStore exception", e);
340 return null;
341 }
Rob Barnesebe26742018-11-13 15:57:22 -0700342 // Turn list of strings into an array of uid integers.
343 return uidsOut.stream().mapToInt(Integer::parseInt).toArray();
Rob Barnesf1a678e2018-11-13 15:57:22 -0700344 }
345
Chad Brubakere35d49f2015-05-12 15:19:52 -0700346 public String[] list(String prefix) {
347 return list(prefix, UID_SELF);
348 }
349
Chad Brubakere35d49f2015-05-12 15:19:52 -0700350 /**
351 * Attempt to lock the keystore for {@code user}.
352 *
Brian Youngfd75c722018-02-23 18:04:20 +0000353 * @param userId Android user to lock.
Chad Brubakere35d49f2015-05-12 15:19:52 -0700354 * @return whether {@code user}'s keystore was locked.
355 */
356 public boolean lock(int userId) {
Kenny Root6b776452012-11-02 15:40:32 -0700357 try {
Chad Brubakere35d49f2015-05-12 15:19:52 -0700358 return mBinder.lock(userId) == NO_ERROR;
Kenny Root6b776452012-11-02 15:40:32 -0700359 } catch (RemoteException e) {
360 Log.w(TAG, "Cannot connect to keystore", e);
361 return false;
362 }
Chia-chi Yeh44039172009-09-21 11:53:59 +0800363 }
364
Chad Brubakere35d49f2015-05-12 15:19:52 -0700365 public boolean lock() {
366 return lock(UserHandle.myUserId());
367 }
368
Chad Brubakera91a8502015-05-07 10:02:22 -0700369 /**
370 * Attempt to unlock the keystore for {@code user} with the password {@code password}.
371 * This is required before keystore entries created with FLAG_ENCRYPTED can be accessed or
372 * created.
373 *
Brian Youngfd75c722018-02-23 18:04:20 +0000374 * @param userId Android user ID to operate on
Chad Brubakera91a8502015-05-07 10:02:22 -0700375 * @param password user's keystore password. Should be the most recent value passed to
376 * {@link #onUserPasswordChanged} for the user.
377 *
378 * @return whether the keystore was unlocked.
379 */
380 public boolean unlock(int userId, String password) {
Kenny Root6b776452012-11-02 15:40:32 -0700381 try {
Dmitry Dementyevefc43112017-10-27 23:10:28 -0700382 password = password != null ? password : "";
Chad Brubakera91a8502015-05-07 10:02:22 -0700383 mError = mBinder.unlock(userId, password);
Kenny Root6b776452012-11-02 15:40:32 -0700384 return mError == NO_ERROR;
385 } catch (RemoteException e) {
386 Log.w(TAG, "Cannot connect to keystore", e);
387 return false;
388 }
Chia-chi Yeh44039172009-09-21 11:53:59 +0800389 }
390
Mathew Inwoode420f8b2018-08-16 18:40:47 +0100391 @UnsupportedAppUsage
Chad Brubakera91a8502015-05-07 10:02:22 -0700392 public boolean unlock(String password) {
393 return unlock(UserHandle.getUserId(Process.myUid()), password);
394 }
395
Chad Brubakere35d49f2015-05-12 15:19:52 -0700396 /**
397 * Check if the keystore for {@code userId} is empty.
398 */
399 public boolean isEmpty(int userId) {
Kenny Root6b776452012-11-02 15:40:32 -0700400 try {
Chad Brubakere35d49f2015-05-12 15:19:52 -0700401 return mBinder.isEmpty(userId) != 0;
Kenny Root6b776452012-11-02 15:40:32 -0700402 } catch (RemoteException e) {
403 Log.w(TAG, "Cannot connect to keystore", e);
404 return false;
405 }
Kenny Root5423e682011-11-14 08:43:13 -0800406 }
407
Mathew Inwood31755f92018-12-20 13:53:36 +0000408 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
Chad Brubakere35d49f2015-05-12 15:19:52 -0700409 public boolean isEmpty() {
410 return isEmpty(UserHandle.myUserId());
411 }
412
Janis Danisevskisb50e9f62017-06-08 17:53:34 -0700413 public String grant(String key, int uid) {
Kenny Root6b776452012-11-02 15:40:32 -0700414 try {
Janis Danisevskisb50e9f62017-06-08 17:53:34 -0700415 String grantAlias = mBinder.grant(key, uid);
416 if (grantAlias == "") return null;
417 return grantAlias;
Kenny Root6b776452012-11-02 15:40:32 -0700418 } catch (RemoteException e) {
419 Log.w(TAG, "Cannot connect to keystore", e);
Janis Danisevskisb50e9f62017-06-08 17:53:34 -0700420 return null;
Kenny Root6b776452012-11-02 15:40:32 -0700421 }
Kenny Root5423e682011-11-14 08:43:13 -0800422 }
423
424 public boolean ungrant(String key, int uid) {
Kenny Root6b776452012-11-02 15:40:32 -0700425 try {
426 return mBinder.ungrant(key, uid) == NO_ERROR;
427 } catch (RemoteException e) {
428 Log.w(TAG, "Cannot connect to keystore", e);
429 return false;
Kenny Root473c7122012-08-17 21:13:48 -0700430 }
Kenny Root473c7122012-08-17 21:13:48 -0700431 }
432
433 /**
434 * Returns the last modification time of the key in milliseconds since the
435 * epoch. Will return -1L if the key could not be found or other error.
436 */
Chad Brubaker5bbf0482015-09-09 14:53:52 -0700437 public long getmtime(String key, int uid) {
Kenny Root6b776452012-11-02 15:40:32 -0700438 try {
Chad Brubaker5bbf0482015-09-09 14:53:52 -0700439 final long millis = mBinder.getmtime(key, uid);
Kenny Roote66769a2013-02-04 15:49:11 -0800440 if (millis == -1L) {
441 return -1L;
442 }
443
444 return millis * 1000L;
Kenny Root6b776452012-11-02 15:40:32 -0700445 } catch (RemoteException e) {
446 Log.w(TAG, "Cannot connect to keystore", e);
447 return -1L;
448 }
Kenny Root473c7122012-08-17 21:13:48 -0700449 }
450
Chad Brubaker5bbf0482015-09-09 14:53:52 -0700451 public long getmtime(String key) {
452 return getmtime(key, UID_SELF);
453 }
454
Alex Klyubin469cbf52015-06-04 12:36:27 -0700455 // TODO: remove this when it's removed from Settings
Kenny Root5cb5cec2013-03-29 11:14:17 -0700456 public boolean isHardwareBacked() {
Kenny Rootb91773b2013-09-05 13:03:16 -0700457 return isHardwareBacked("RSA");
458 }
459
460 public boolean isHardwareBacked(String keyType) {
Kenny Root5cb5cec2013-03-29 11:14:17 -0700461 try {
Kenny Rootb91773b2013-09-05 13:03:16 -0700462 return mBinder.is_hardware_backed(keyType.toUpperCase(Locale.US)) == NO_ERROR;
Kenny Root5cb5cec2013-03-29 11:14:17 -0700463 } catch (RemoteException e) {
464 Log.w(TAG, "Cannot connect to keystore", e);
465 return false;
466 }
467 }
468
Kenny Rootd72317a2013-04-01 15:59:59 -0700469 public boolean clearUid(int uid) {
470 try {
471 return mBinder.clear_uid(uid) == NO_ERROR;
472 } catch (RemoteException e) {
473 Log.w(TAG, "Cannot connect to keystore", e);
474 return false;
475 }
476 }
477
Chia-chi Yeh44039172009-09-21 11:53:59 +0800478 public int getLastError() {
479 return mError;
480 }
Chad Brubakere6a461342015-02-10 21:33:23 -0800481
Janis Danisevskis0aadf932017-12-18 17:28:52 -0800482 public boolean addRngEntropy(byte[] data, int flags) {
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700483 KeystoreResultPromise promise = new KeystoreResultPromise();
Chad Brubakere6a461342015-02-10 21:33:23 -0800484 try {
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700485 mBinder.asBinder().linkToDeath(promise, 0);
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700486 int errorCode = mBinder.addRngEntropy(promise, data, flags);
487 if (errorCode == NO_ERROR) {
488 return promise.getFuture().get().getErrorCode() == NO_ERROR;
489 } else {
490 return false;
491 }
Chad Brubakere6a461342015-02-10 21:33:23 -0800492 } catch (RemoteException e) {
493 Log.w(TAG, "Cannot connect to keystore", e);
494 return false;
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700495 } catch (ExecutionException | InterruptedException e) {
496 Log.e(TAG, "AddRngEntropy completed with exception", e);
497 return false;
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700498 } finally {
499 mBinder.asBinder().unlinkToDeath(promise, 0);
Chad Brubakere6a461342015-02-10 21:33:23 -0800500 }
501 }
502
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700503 private class KeyCharacteristicsCallbackResult {
504 private KeystoreResponse keystoreResponse;
505 private KeyCharacteristics keyCharacteristics;
506
507 public KeyCharacteristicsCallbackResult(KeystoreResponse keystoreResponse,
508 KeyCharacteristics keyCharacteristics) {
509 this.keystoreResponse = keystoreResponse;
510 this.keyCharacteristics = keyCharacteristics;
511 }
512
513 public KeystoreResponse getKeystoreResponse() {
514 return keystoreResponse;
515 }
516
517 public void setKeystoreResponse(KeystoreResponse keystoreResponse) {
518 this.keystoreResponse = keystoreResponse;
519 }
520
521 public KeyCharacteristics getKeyCharacteristics() {
522 return keyCharacteristics;
523 }
524
525 public void setKeyCharacteristics(KeyCharacteristics keyCharacteristics) {
526 this.keyCharacteristics = keyCharacteristics;
527 }
528 }
529
530 private class KeyCharacteristicsPromise
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700531 extends android.security.keystore.IKeystoreKeyCharacteristicsCallback.Stub
532 implements IBinder.DeathRecipient {
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700533 final private CompletableFuture<KeyCharacteristicsCallbackResult> future =
534 new CompletableFuture<KeyCharacteristicsCallbackResult>();
535 @Override
536 public void onFinished(KeystoreResponse keystoreResponse,
537 KeyCharacteristics keyCharacteristics)
538 throws android.os.RemoteException {
539 future.complete(
540 new KeyCharacteristicsCallbackResult(keystoreResponse, keyCharacteristics));
541 }
542 public final CompletableFuture<KeyCharacteristicsCallbackResult> getFuture() {
543 return future;
544 }
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700545 @Override
546 public void binderDied() {
547 future.completeExceptionally(new RemoteException("Keystore died"));
548 }
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700549 };
550
551 private int generateKeyInternal(String alias, KeymasterArguments args, byte[] entropy, int uid,
552 int flags, KeyCharacteristics outCharacteristics)
553 throws RemoteException, ExecutionException, InterruptedException {
554 KeyCharacteristicsPromise promise = new KeyCharacteristicsPromise();
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700555 int error = NO_ERROR;
556 KeyCharacteristicsCallbackResult result = null;
557 try {
558 mBinder.asBinder().linkToDeath(promise, 0);
559 error = mBinder.generateKey(promise, alias, args, entropy, uid, flags);
560 if (error != NO_ERROR) {
561 Log.e(TAG, "generateKeyInternal failed on request " + error);
562 return error;
563 }
564 result = promise.getFuture().get();
565 } finally {
566 mBinder.asBinder().unlinkToDeath(promise, 0);
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700567 }
568
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700569 error = result.getKeystoreResponse().getErrorCode();
570 if (error != NO_ERROR) {
571 Log.e(TAG, "generateKeyInternal failed on response " + error);
572 return error;
573 }
574 KeyCharacteristics characteristics = result.getKeyCharacteristics();
575 if (characteristics == null) {
576 Log.e(TAG, "generateKeyInternal got empty key cheractariestics " + error);
577 return SYSTEM_ERROR;
578 }
579 outCharacteristics.shallowCopyFrom(characteristics);
580 return NO_ERROR;
581 }
582
Chad Brubakerdae79e52015-03-27 14:28:35 -0700583 public int generateKey(String alias, KeymasterArguments args, byte[] entropy, int uid,
584 int flags, KeyCharacteristics outCharacteristics) {
Chad Brubakere6a461342015-02-10 21:33:23 -0800585 try {
Dmitry Dementyevefc43112017-10-27 23:10:28 -0700586 entropy = entropy != null ? entropy : new byte[0];
587 args = args != null ? args : new KeymasterArguments();
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700588 int error = generateKeyInternal(alias, args, entropy, uid, flags, outCharacteristics);
Janis Danisevskisd2575382018-10-08 07:56:58 -0700589 if (error == KEY_ALREADY_EXISTS) {
590 mBinder.del(alias, uid);
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700591 error = generateKeyInternal(alias, args, entropy, uid, flags, outCharacteristics);
Janis Danisevskisd2575382018-10-08 07:56:58 -0700592 }
593 return error;
Chad Brubakere6a461342015-02-10 21:33:23 -0800594 } catch (RemoteException e) {
595 Log.w(TAG, "Cannot connect to keystore", e);
596 return SYSTEM_ERROR;
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700597 } catch (ExecutionException | InterruptedException e) {
598 Log.e(TAG, "generateKey completed with exception", e);
599 return SYSTEM_ERROR;
Chad Brubakere6a461342015-02-10 21:33:23 -0800600 }
601 }
602
Chad Brubakerdae79e52015-03-27 14:28:35 -0700603 public int generateKey(String alias, KeymasterArguments args, byte[] entropy, int flags,
Chad Brubakere6a461342015-02-10 21:33:23 -0800604 KeyCharacteristics outCharacteristics) {
Chad Brubakerdae79e52015-03-27 14:28:35 -0700605 return generateKey(alias, args, entropy, UID_SELF, flags, outCharacteristics);
Chad Brubakere6a461342015-02-10 21:33:23 -0800606 }
607
Chad Brubaker5e73c0e2015-03-21 22:46:43 -0700608 public int getKeyCharacteristics(String alias, KeymasterBlob clientId, KeymasterBlob appId,
Chad Brubaker5bbf0482015-09-09 14:53:52 -0700609 int uid, KeyCharacteristics outCharacteristics) {
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700610 KeyCharacteristicsPromise promise = new KeyCharacteristicsPromise();
Chad Brubakere6a461342015-02-10 21:33:23 -0800611 try {
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700612 mBinder.asBinder().linkToDeath(promise, 0);
Dmitry Dementyevefc43112017-10-27 23:10:28 -0700613 clientId = clientId != null ? clientId : new KeymasterBlob(new byte[0]);
614 appId = appId != null ? appId : new KeymasterBlob(new byte[0]);
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700615
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700616 int error = mBinder.getKeyCharacteristics(promise, alias, clientId, appId, uid);
617 if (error != NO_ERROR) return error;
618
619 KeyCharacteristicsCallbackResult result = promise.getFuture().get();
620 error = result.getKeystoreResponse().getErrorCode();
621 if (error != NO_ERROR) return error;
622
623 KeyCharacteristics characteristics = result.getKeyCharacteristics();
624 if (characteristics == null) return SYSTEM_ERROR;
625 outCharacteristics.shallowCopyFrom(characteristics);
626 return NO_ERROR;
Chad Brubakere6a461342015-02-10 21:33:23 -0800627 } catch (RemoteException e) {
628 Log.w(TAG, "Cannot connect to keystore", e);
629 return SYSTEM_ERROR;
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700630 } catch (ExecutionException | InterruptedException e) {
631 Log.e(TAG, "GetKeyCharacteristics completed with exception", e);
632 return SYSTEM_ERROR;
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700633 } finally {
634 mBinder.asBinder().unlinkToDeath(promise, 0);
Chad Brubakere6a461342015-02-10 21:33:23 -0800635 }
636 }
637
Chad Brubaker5bbf0482015-09-09 14:53:52 -0700638 public int getKeyCharacteristics(String alias, KeymasterBlob clientId, KeymasterBlob appId,
639 KeyCharacteristics outCharacteristics) {
640 return getKeyCharacteristics(alias, clientId, appId, UID_SELF, outCharacteristics);
641 }
642
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700643 private int importKeyInternal(String alias, KeymasterArguments args, int format, byte[] keyData,
644 int uid, int flags, KeyCharacteristics outCharacteristics)
645 throws RemoteException, ExecutionException, InterruptedException {
646 KeyCharacteristicsPromise promise = new KeyCharacteristicsPromise();
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700647 mBinder.asBinder().linkToDeath(promise, 0);
648 try {
649 int error = mBinder.importKey(promise, alias, args, format, keyData, uid, flags);
650 if (error != NO_ERROR) return error;
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700651
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700652 KeyCharacteristicsCallbackResult result = promise.getFuture().get();
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700653
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700654 error = result.getKeystoreResponse().getErrorCode();
655 if (error != NO_ERROR) return error;
656
657 KeyCharacteristics characteristics = result.getKeyCharacteristics();
658 if (characteristics == null) return SYSTEM_ERROR;
659 outCharacteristics.shallowCopyFrom(characteristics);
660 return NO_ERROR;
661 } finally {
662 mBinder.asBinder().unlinkToDeath(promise, 0);
663 }
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700664 }
665
Chad Brubakere6a461342015-02-10 21:33:23 -0800666 public int importKey(String alias, KeymasterArguments args, int format, byte[] keyData,
667 int uid, int flags, KeyCharacteristics outCharacteristics) {
668 try {
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700669 int error = importKeyInternal(alias, args, format, keyData, uid, flags,
Chad Brubakere6a461342015-02-10 21:33:23 -0800670 outCharacteristics);
Janis Danisevskisd2575382018-10-08 07:56:58 -0700671 if (error == KEY_ALREADY_EXISTS) {
672 mBinder.del(alias, uid);
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700673 error = importKeyInternal(alias, args, format, keyData, uid, flags,
Janis Danisevskisd2575382018-10-08 07:56:58 -0700674 outCharacteristics);
675 }
676 return error;
Chad Brubakere6a461342015-02-10 21:33:23 -0800677 } catch (RemoteException e) {
678 Log.w(TAG, "Cannot connect to keystore", e);
679 return SYSTEM_ERROR;
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700680 } catch (ExecutionException | InterruptedException e) {
681 Log.e(TAG, "ImportKey completed with exception", e);
682 return SYSTEM_ERROR;
Chad Brubakere6a461342015-02-10 21:33:23 -0800683 }
684 }
685
686 public int importKey(String alias, KeymasterArguments args, int format, byte[] keyData,
687 int flags, KeyCharacteristics outCharacteristics) {
688 return importKey(alias, args, format, keyData, UID_SELF, flags, outCharacteristics);
689 }
690
Janis Danisevskis1864c952018-08-09 11:14:49 -0700691 private String getAlgorithmFromPKCS8(byte[] keyData) {
692 try {
693 final ASN1InputStream bIn = new ASN1InputStream(new ByteArrayInputStream(keyData));
694 final PrivateKeyInfo pki = PrivateKeyInfo.getInstance(bIn.readObject());
695 final String algOid = pki.getPrivateKeyAlgorithm().getAlgorithm().getId();
696 return new AlgorithmId(new ObjectIdentifier(algOid)).getName();
697 } catch (IOException e) {
698 Log.e(TAG, "getAlgorithmFromPKCS8 Failed to parse key data");
699 Log.e(TAG, Log.getStackTraceString(e));
700 return null;
701 }
702 }
703
704 private KeymasterArguments makeLegacyArguments(String algorithm) {
705 KeymasterArguments args = new KeymasterArguments();
706 args.addEnum(KeymasterDefs.KM_TAG_ALGORITHM,
707 KeyProperties.KeyAlgorithm.toKeymasterAsymmetricKeyAlgorithm(algorithm));
708 args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_SIGN);
709 args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_VERIFY);
710 args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_ENCRYPT);
711 args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_DECRYPT);
712 args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_NONE);
713 if (algorithm.equalsIgnoreCase(KeyProperties.KEY_ALGORITHM_RSA)) {
714 args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_RSA_OAEP);
715 args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_ENCRYPT);
716 args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_SIGN);
717 args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_RSA_PSS);
718 }
719 args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_NONE);
720 args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_MD5);
721 args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA1);
722 args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA_2_224);
723 args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA_2_256);
724 args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA_2_384);
725 args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA_2_512);
726 args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED);
Janis Danisevskis2b106ad2018-11-15 09:27:16 -0800727 args.addDate(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME, new Date(Long.MAX_VALUE));
728 args.addDate(KeymasterDefs.KM_TAG_USAGE_EXPIRE_DATETIME, new Date(Long.MAX_VALUE));
729 args.addDate(KeymasterDefs.KM_TAG_ACTIVE_DATETIME, new Date(0));
Janis Danisevskis1864c952018-08-09 11:14:49 -0700730 return args;
731 }
732
733 public boolean importKey(String alias, byte[] keyData, int uid, int flags) {
734 String algorithm = getAlgorithmFromPKCS8(keyData);
735 if (algorithm == null) return false;
736 KeymasterArguments args = makeLegacyArguments(algorithm);
737 KeyCharacteristics out = new KeyCharacteristics();
738 int result = importKey(alias, args, KeymasterDefs.KM_KEY_FORMAT_PKCS8, keyData, uid,
739 flags, out);
740 if (result != NO_ERROR) {
741 Log.e(TAG, Log.getStackTraceString(
742 new KeyStoreException(result, "legacy key import failed")));
743 return false;
744 }
745 return true;
746 }
747
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700748 private int importWrappedKeyInternal(String wrappedKeyAlias, byte[] wrappedKey,
749 String wrappingKeyAlias,
750 byte[] maskingKey, KeymasterArguments args, long rootSid, long fingerprintSid,
751 KeyCharacteristics outCharacteristics)
752 throws RemoteException, ExecutionException, InterruptedException {
753 KeyCharacteristicsPromise promise = new KeyCharacteristicsPromise();
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700754 mBinder.asBinder().linkToDeath(promise, 0);
755 try {
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700756 int error = mBinder.importWrappedKey(promise, wrappedKeyAlias, wrappedKey,
757 wrappingKeyAlias, maskingKey, args, rootSid, fingerprintSid);
758 if (error != NO_ERROR) return error;
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700759
Janis Danisevskisf924b7e2019-04-17 14:06:09 -0700760 KeyCharacteristicsCallbackResult result = promise.getFuture().get();
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700761
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700762 error = result.getKeystoreResponse().getErrorCode();
763 if (error != NO_ERROR) return error;
764
765 KeyCharacteristics characteristics = result.getKeyCharacteristics();
766 if (characteristics == null) return SYSTEM_ERROR;
767 outCharacteristics.shallowCopyFrom(characteristics);
768 return NO_ERROR;
769 } finally {
770 mBinder.asBinder().unlinkToDeath(promise, 0);
771 }
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700772 }
773
Frank Salim21d9c1d2017-12-19 22:38:09 -0800774 public int importWrappedKey(String wrappedKeyAlias, byte[] wrappedKey,
775 String wrappingKeyAlias,
776 byte[] maskingKey, KeymasterArguments args, long rootSid, long fingerprintSid, int uid,
777 KeyCharacteristics outCharacteristics) {
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700778 // TODO b/119217337 uid parameter gets silently ignored.
Frank Salim21d9c1d2017-12-19 22:38:09 -0800779 try {
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700780 int error = importWrappedKeyInternal(wrappedKeyAlias, wrappedKey, wrappingKeyAlias,
Frank Salim21d9c1d2017-12-19 22:38:09 -0800781 maskingKey, args, rootSid, fingerprintSid, outCharacteristics);
Janis Danisevskisd2575382018-10-08 07:56:58 -0700782 if (error == KEY_ALREADY_EXISTS) {
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700783 mBinder.del(wrappedKeyAlias, UID_SELF);
784 error = importWrappedKeyInternal(wrappedKeyAlias, wrappedKey, wrappingKeyAlias,
Janis Danisevskisd2575382018-10-08 07:56:58 -0700785 maskingKey, args, rootSid, fingerprintSid, outCharacteristics);
786 }
787 return error;
Frank Salim21d9c1d2017-12-19 22:38:09 -0800788 } catch (RemoteException e) {
789 Log.w(TAG, "Cannot connect to keystore", e);
790 return SYSTEM_ERROR;
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700791 } catch (ExecutionException | InterruptedException e) {
792 Log.e(TAG, "ImportWrappedKey completed with exception", e);
793 return SYSTEM_ERROR;
Frank Salim21d9c1d2017-12-19 22:38:09 -0800794 }
795 }
796
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700797 private class ExportKeyPromise
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700798 extends android.security.keystore.IKeystoreExportKeyCallback.Stub
799 implements IBinder.DeathRecipient {
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700800 final private CompletableFuture<ExportResult> future = new CompletableFuture<ExportResult>();
801 @Override
802 public void onFinished(ExportResult exportKeyResult) throws android.os.RemoteException {
803 future.complete(exportKeyResult);
804 }
805 public final CompletableFuture<ExportResult> getFuture() {
806 return future;
807 }
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700808 @Override
809 public void binderDied() {
810 future.completeExceptionally(new RemoteException("Keystore died"));
811 }
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700812 };
813
Chad Brubaker5e73c0e2015-03-21 22:46:43 -0700814 public ExportResult exportKey(String alias, int format, KeymasterBlob clientId,
Chad Brubaker5bbf0482015-09-09 14:53:52 -0700815 KeymasterBlob appId, int uid) {
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700816 ExportKeyPromise promise = new ExportKeyPromise();
Chad Brubakere6a461342015-02-10 21:33:23 -0800817 try {
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700818 mBinder.asBinder().linkToDeath(promise, 0);
Dmitry Dementyevefc43112017-10-27 23:10:28 -0700819 clientId = clientId != null ? clientId : new KeymasterBlob(new byte[0]);
820 appId = appId != null ? appId : new KeymasterBlob(new byte[0]);
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700821 int error = mBinder.exportKey(promise, alias, format, clientId, appId, uid);
822 if (error == NO_ERROR) {
823 return promise.getFuture().get();
824 } else {
825 return new ExportResult(error);
826 }
Chad Brubaker5bbf0482015-09-09 14:53:52 -0700827 } catch (RemoteException e) {
828 Log.w(TAG, "Cannot connect to keystore", e);
829 return null;
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700830 } catch (ExecutionException | InterruptedException e) {
831 Log.e(TAG, "ExportKey completed with exception", e);
832 return null;
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700833 } finally {
834 mBinder.asBinder().unlinkToDeath(promise, 0);
Chad Brubaker5bbf0482015-09-09 14:53:52 -0700835 }
836 }
837 public ExportResult exportKey(String alias, int format, KeymasterBlob clientId,
838 KeymasterBlob appId) {
839 return exportKey(alias, format, clientId, appId, UID_SELF);
840 }
841
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700842 private class OperationPromise
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700843 extends android.security.keystore.IKeystoreOperationResultCallback.Stub
844 implements IBinder.DeathRecipient {
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700845 final private CompletableFuture<OperationResult> future = new CompletableFuture<OperationResult>();
846 @Override
847 public void onFinished(OperationResult operationResult) throws android.os.RemoteException {
848 future.complete(operationResult);
849 }
850 public final CompletableFuture<OperationResult> getFuture() {
851 return future;
852 }
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700853 @Override
854 public void binderDied() {
855 future.completeExceptionally(new RemoteException("Keystore died"));
856 }
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700857 };
858
Chad Brubaker5bbf0482015-09-09 14:53:52 -0700859 public OperationResult begin(String alias, int purpose, boolean pruneable,
860 KeymasterArguments args, byte[] entropy, int uid) {
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700861 OperationPromise promise = new OperationPromise();
Chad Brubaker5bbf0482015-09-09 14:53:52 -0700862 try {
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700863 mBinder.asBinder().linkToDeath(promise, 0);
Dmitry Dementyevefc43112017-10-27 23:10:28 -0700864 args = args != null ? args : new KeymasterArguments();
865 entropy = entropy != null ? entropy : new byte[0];
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700866 int errorCode = mBinder.begin(promise, getToken(), alias, purpose, pruneable, args,
867 entropy, uid);
868 if (errorCode == NO_ERROR) {
869 return promise.getFuture().get();
870 } else {
871 return new OperationResult(errorCode);
872 }
Chad Brubakere6a461342015-02-10 21:33:23 -0800873 } catch (RemoteException e) {
874 Log.w(TAG, "Cannot connect to keystore", e);
875 return null;
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700876 } catch (ExecutionException | InterruptedException e) {
877 Log.e(TAG, "Begin completed with exception", e);
878 return null;
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700879 } finally {
880 mBinder.asBinder().unlinkToDeath(promise, 0);
Chad Brubakere6a461342015-02-10 21:33:23 -0800881 }
882 }
883
884 public OperationResult begin(String alias, int purpose, boolean pruneable,
Chad Brubaker966486e2015-06-01 12:57:06 -0700885 KeymasterArguments args, byte[] entropy) {
Dmitry Dementyevefc43112017-10-27 23:10:28 -0700886 entropy = entropy != null ? entropy : new byte[0];
887 args = args != null ? args : new KeymasterArguments();
Chad Brubaker5bbf0482015-09-09 14:53:52 -0700888 return begin(alias, purpose, pruneable, args, entropy, UID_SELF);
Chad Brubakere6a461342015-02-10 21:33:23 -0800889 }
890
891 public OperationResult update(IBinder token, KeymasterArguments arguments, byte[] input) {
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700892 OperationPromise promise = new OperationPromise();
Chad Brubakere6a461342015-02-10 21:33:23 -0800893 try {
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700894 mBinder.asBinder().linkToDeath(promise, 0);
Dmitry Dementyevefc43112017-10-27 23:10:28 -0700895 arguments = arguments != null ? arguments : new KeymasterArguments();
896 input = input != null ? input : new byte[0];
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700897 int errorCode = mBinder.update(promise, token, arguments, input);
898 if (errorCode == NO_ERROR) {
899 return promise.getFuture().get();
900 } else {
901 return new OperationResult(errorCode);
902 }
Chad Brubakere6a461342015-02-10 21:33:23 -0800903 } catch (RemoteException e) {
904 Log.w(TAG, "Cannot connect to keystore", e);
905 return null;
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700906 } catch (ExecutionException | InterruptedException e) {
907 Log.e(TAG, "Update completed with exception", e);
908 return null;
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700909 } finally {
910 mBinder.asBinder().unlinkToDeath(promise, 0);
Chad Brubakere6a461342015-02-10 21:33:23 -0800911 }
912 }
913
Rob Barnes92743aeb2019-11-14 15:13:52 -0700914 /**
915 * Android KeyStore finish operation.
916 *
917 * @param token Authentication token.
918 * @param arguments Keymaster arguments
919 * @param input Optional additional input data.
920 * @param signature Optional signature to be verified.
921 * @param entropy Optional additional entropy
922 * @return OperationResult that will indicate success or error of the operation.
923 */
924 public OperationResult finish(IBinder token, KeymasterArguments arguments, byte[] input,
925 byte[] signature, byte[] entropy) {
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700926 OperationPromise promise = new OperationPromise();
Chad Brubakere6a461342015-02-10 21:33:23 -0800927 try {
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700928 mBinder.asBinder().linkToDeath(promise, 0);
Dmitry Dementyevefc43112017-10-27 23:10:28 -0700929 arguments = arguments != null ? arguments : new KeymasterArguments();
930 entropy = entropy != null ? entropy : new byte[0];
Rob Barnes92743aeb2019-11-14 15:13:52 -0700931 input = input != null ? input : new byte[0];
Dmitry Dementyevefc43112017-10-27 23:10:28 -0700932 signature = signature != null ? signature : new byte[0];
Rob Barnes92743aeb2019-11-14 15:13:52 -0700933 int errorCode = mBinder.finish(promise, token, arguments, input, signature, entropy);
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700934 if (errorCode == NO_ERROR) {
935 return promise.getFuture().get();
936 } else {
937 return new OperationResult(errorCode);
938 }
Chad Brubakere6a461342015-02-10 21:33:23 -0800939 } catch (RemoteException e) {
940 Log.w(TAG, "Cannot connect to keystore", e);
941 return null;
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700942 } catch (ExecutionException | InterruptedException e) {
943 Log.e(TAG, "Finish completed with exception", e);
944 return null;
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700945 } finally {
946 mBinder.asBinder().unlinkToDeath(promise, 0);
Chad Brubakere6a461342015-02-10 21:33:23 -0800947 }
948 }
949
Chad Brubaker8a077012015-05-29 12:32:51 -0700950 public OperationResult finish(IBinder token, KeymasterArguments arguments, byte[] signature) {
Rob Barnes92743aeb2019-11-14 15:13:52 -0700951 return finish(token, arguments, null, signature, null);
Chad Brubaker8a077012015-05-29 12:32:51 -0700952 }
953
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700954 private class KeystoreResultPromise
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700955 extends android.security.keystore.IKeystoreResponseCallback.Stub
956 implements IBinder.DeathRecipient {
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700957 final private CompletableFuture<KeystoreResponse> future = new CompletableFuture<KeystoreResponse>();
958 @Override
959 public void onFinished(KeystoreResponse keystoreResponse) throws android.os.RemoteException {
960 future.complete(keystoreResponse);
961 }
962 public final CompletableFuture<KeystoreResponse> getFuture() {
963 return future;
964 }
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700965 @Override
966 public void binderDied() {
967 future.completeExceptionally(new RemoteException("Keystore died"));
968 }
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700969 };
970
Chad Brubakere6a461342015-02-10 21:33:23 -0800971 public int abort(IBinder token) {
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700972 KeystoreResultPromise promise = new KeystoreResultPromise();
Chad Brubakere6a461342015-02-10 21:33:23 -0800973 try {
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700974 mBinder.asBinder().linkToDeath(promise, 0);
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700975 int errorCode = mBinder.abort(promise, token);
976 if (errorCode == NO_ERROR) {
977 return promise.getFuture().get().getErrorCode();
978 } else {
979 return errorCode;
980 }
Chad Brubakere6a461342015-02-10 21:33:23 -0800981 } catch (RemoteException e) {
982 Log.w(TAG, "Cannot connect to keystore", e);
983 return SYSTEM_ERROR;
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700984 } catch (ExecutionException | InterruptedException e) {
985 Log.e(TAG, "Abort completed with exception", e);
986 return SYSTEM_ERROR;
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -0700987 } finally {
988 mBinder.asBinder().unlinkToDeath(promise, 0);
Chad Brubakere6a461342015-02-10 21:33:23 -0800989 }
990 }
Chad Brubaker5654b362015-03-17 16:59:52 -0700991
992 /**
Chad Brubaker5654b362015-03-17 16:59:52 -0700993 * Add an authentication record to the keystore authorization table.
994 *
995 * @param authToken The packed bytes of a hw_auth_token_t to be provided to keymaster.
996 * @return {@code KeyStore.NO_ERROR} on success, otherwise an error value corresponding to
997 * a {@code KeymasterDefs.KM_ERROR_} value or {@code KeyStore} ResponseCode.
998 */
Brian Youngda82e2c2018-02-22 23:36:34 +0000999 public int addAuthToken(byte[] authToken) {
Chad Brubaker5654b362015-03-17 16:59:52 -07001000 try {
Brian Youngda82e2c2018-02-22 23:36:34 +00001001 return mBinder.addAuthToken(authToken);
Chad Brubaker5654b362015-03-17 16:59:52 -07001002 } catch (RemoteException e) {
1003 Log.w(TAG, "Cannot connect to keystore", e);
1004 return SYSTEM_ERROR;
1005 }
1006 }
Alex Klyubinb4834ae2015-04-02 15:53:46 -07001007
Alex Klyubinad9ba102015-04-21 15:17:24 -07001008 /**
Chad Brubakera91a8502015-05-07 10:02:22 -07001009 * Notify keystore that a user's password has changed.
1010 *
1011 * @param userId the user whose password changed.
1012 * @param newPassword the new password or "" if the password was removed.
1013 */
1014 public boolean onUserPasswordChanged(int userId, String newPassword) {
1015 // Parcel.cpp doesn't support deserializing null strings and treats them as "". Make that
1016 // explicit here.
1017 if (newPassword == null) {
1018 newPassword = "";
1019 }
1020 try {
1021 return mBinder.onUserPasswordChanged(userId, newPassword) == NO_ERROR;
1022 } catch (RemoteException e) {
1023 Log.w(TAG, "Cannot connect to keystore", e);
1024 return false;
1025 }
1026 }
1027
Chad Brubaker83ce0952015-05-12 13:00:02 -07001028 /**
1029 * Notify keystore that a user was added.
1030 *
1031 * @param userId the new user.
1032 * @param parentId the parent of the new user, or -1 if the user has no parent. If parentId is
1033 * specified then the new user's keystore will be intialized with the same secure lockscreen
1034 * password as the parent.
1035 */
1036 public void onUserAdded(int userId, int parentId) {
1037 try {
1038 mBinder.onUserAdded(userId, parentId);
1039 } catch (RemoteException e) {
1040 Log.w(TAG, "Cannot connect to keystore", e);
1041 }
1042 }
1043
1044 /**
1045 * Notify keystore that a user was added.
1046 *
1047 * @param userId the new user.
1048 */
1049 public void onUserAdded(int userId) {
1050 onUserAdded(userId, -1);
1051 }
1052
1053 /**
1054 * Notify keystore that a user was removed.
1055 *
1056 * @param userId the removed user.
1057 */
1058 public void onUserRemoved(int userId) {
1059 try {
1060 mBinder.onUserRemoved(userId);
1061 } catch (RemoteException e) {
1062 Log.w(TAG, "Cannot connect to keystore", e);
1063 }
1064 }
1065
Chad Brubakera91a8502015-05-07 10:02:22 -07001066 public boolean onUserPasswordChanged(String newPassword) {
1067 return onUserPasswordChanged(UserHandle.getUserId(Process.myUid()), newPassword);
1068 }
1069
Janis Danisevskisb0358e72018-11-02 10:34:07 -07001070 private class KeyAttestationCallbackResult {
1071 private KeystoreResponse keystoreResponse;
1072 private KeymasterCertificateChain certificateChain;
1073
1074 public KeyAttestationCallbackResult(KeystoreResponse keystoreResponse,
1075 KeymasterCertificateChain certificateChain) {
1076 this.keystoreResponse = keystoreResponse;
1077 this.certificateChain = certificateChain;
1078 }
1079
1080 public KeystoreResponse getKeystoreResponse() {
1081 return keystoreResponse;
1082 }
1083
1084 public void setKeystoreResponse(KeystoreResponse keystoreResponse) {
1085 this.keystoreResponse = keystoreResponse;
1086 }
1087
1088 public KeymasterCertificateChain getCertificateChain() {
1089 return certificateChain;
1090 }
1091
1092 public void setCertificateChain(KeymasterCertificateChain certificateChain) {
1093 this.certificateChain = certificateChain;
1094 }
1095 }
1096
1097 private class CertificateChainPromise
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -07001098 extends android.security.keystore.IKeystoreCertificateChainCallback.Stub
1099 implements IBinder.DeathRecipient {
Janis Danisevskisb0358e72018-11-02 10:34:07 -07001100 final private CompletableFuture<KeyAttestationCallbackResult> future = new CompletableFuture<KeyAttestationCallbackResult>();
1101 @Override
1102 public void onFinished(KeystoreResponse keystoreResponse,
1103 KeymasterCertificateChain certificateChain) throws android.os.RemoteException {
1104 future.complete(new KeyAttestationCallbackResult(keystoreResponse, certificateChain));
1105 }
1106 public final CompletableFuture<KeyAttestationCallbackResult> getFuture() {
1107 return future;
1108 }
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -07001109 @Override
1110 public void binderDied() {
1111 future.completeExceptionally(new RemoteException("Keystore died"));
1112 }
Janis Danisevskisb0358e72018-11-02 10:34:07 -07001113 };
1114
1115
Shawn Willden8d8c7472016-02-02 08:27:39 -07001116 public int attestKey(
1117 String alias, KeymasterArguments params, KeymasterCertificateChain outChain) {
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -07001118 CertificateChainPromise promise = new CertificateChainPromise();
Shawn Willden8d8c7472016-02-02 08:27:39 -07001119 try {
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -07001120 mBinder.asBinder().linkToDeath(promise, 0);
Dmitry Dementyevefc43112017-10-27 23:10:28 -07001121 if (params == null) {
1122 params = new KeymasterArguments();
1123 }
1124 if (outChain == null) {
1125 outChain = new KeymasterCertificateChain();
1126 }
Janis Danisevskisb0358e72018-11-02 10:34:07 -07001127 int error = mBinder.attestKey(promise, alias, params);
1128 if (error != NO_ERROR) return error;
1129 KeyAttestationCallbackResult result = promise.getFuture().get();
1130 error = result.getKeystoreResponse().getErrorCode();
1131 if (error == NO_ERROR) {
1132 outChain.shallowCopyFrom(result.getCertificateChain());
1133 }
1134 return error;
Shawn Willden8d8c7472016-02-02 08:27:39 -07001135 } catch (RemoteException e) {
1136 Log.w(TAG, "Cannot connect to keystore", e);
1137 return SYSTEM_ERROR;
Janis Danisevskisb0358e72018-11-02 10:34:07 -07001138 } catch (ExecutionException | InterruptedException e) {
1139 Log.e(TAG, "AttestKey completed with exception", e);
1140 return SYSTEM_ERROR;
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -07001141 } finally {
1142 mBinder.asBinder().unlinkToDeath(promise, 0);
Shawn Willden8d8c7472016-02-02 08:27:39 -07001143 }
1144 }
1145
Bartosz Fabianowski237f4b362017-04-24 13:57:46 +02001146 public int attestDeviceIds(KeymasterArguments params, KeymasterCertificateChain outChain) {
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -07001147 CertificateChainPromise promise = new CertificateChainPromise();
Bartosz Fabianowski237f4b362017-04-24 13:57:46 +02001148 try {
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -07001149 mBinder.asBinder().linkToDeath(promise, 0);
Dmitry Dementyevefc43112017-10-27 23:10:28 -07001150 if (params == null) {
1151 params = new KeymasterArguments();
1152 }
1153 if (outChain == null) {
1154 outChain = new KeymasterCertificateChain();
1155 }
Janis Danisevskisb0358e72018-11-02 10:34:07 -07001156 int error = mBinder.attestDeviceIds(promise, params);
1157 if (error != NO_ERROR) return error;
1158 KeyAttestationCallbackResult result = promise.getFuture().get();
1159 error = result.getKeystoreResponse().getErrorCode();
1160 if (error == NO_ERROR) {
1161 outChain.shallowCopyFrom(result.getCertificateChain());
1162 }
1163 return error;
Bartosz Fabianowski237f4b362017-04-24 13:57:46 +02001164 } catch (RemoteException e) {
1165 Log.w(TAG, "Cannot connect to keystore", e);
1166 return SYSTEM_ERROR;
Janis Danisevskisb0358e72018-11-02 10:34:07 -07001167 } catch (ExecutionException | InterruptedException e) {
1168 Log.e(TAG, "AttestDevicdeIds completed with exception", e);
1169 return SYSTEM_ERROR;
Janis Danisevskisc9277ffd2019-03-27 15:50:28 -07001170 } finally {
1171 mBinder.asBinder().unlinkToDeath(promise, 0);
Bartosz Fabianowski237f4b362017-04-24 13:57:46 +02001172 }
1173 }
1174
Tucker Sylvestrob32aae22016-06-23 17:23:33 -04001175 /**
1176 * Notify keystore that the device went off-body.
1177 */
1178 public void onDeviceOffBody() {
1179 try {
1180 mBinder.onDeviceOffBody();
1181 } catch (RemoteException e) {
1182 Log.w(TAG, "Cannot connect to keystore", e);
1183 }
1184 }
Shawn Willden8d8c7472016-02-02 08:27:39 -07001185
Janis Danisevskis7dacad82018-01-24 15:12:11 -08001186 // Keep in sync with confirmationui/1.0/types.hal.
1187 public static final int CONFIRMATIONUI_OK = 0;
1188 public static final int CONFIRMATIONUI_CANCELED = 1;
1189 public static final int CONFIRMATIONUI_ABORTED = 2;
1190 public static final int CONFIRMATIONUI_OPERATION_PENDING = 3;
1191 public static final int CONFIRMATIONUI_IGNORED = 4;
1192 public static final int CONFIRMATIONUI_SYSTEM_ERROR = 5;
1193 public static final int CONFIRMATIONUI_UNIMPLEMENTED = 6;
1194 public static final int CONFIRMATIONUI_UNEXPECTED = 7;
1195 public static final int CONFIRMATIONUI_UIERROR = 0x10000;
1196 public static final int CONFIRMATIONUI_UIERROR_MISSING_GLYPH = 0x10001;
1197 public static final int CONFIRMATIONUI_UIERROR_MESSAGE_TOO_LONG = 0x10002;
1198 public static final int CONFIRMATIONUI_UIERROR_MALFORMED_UTF8_ENCODING = 0x10003;
1199
1200 /**
1201 * Requests keystore call into the confirmationui HAL to display a prompt.
1202 *
1203 * @param listener the binder to use for callbacks.
1204 * @param promptText the prompt to display.
1205 * @param extraData extra data / nonce from application.
1206 * @param locale the locale as a BCP 47 langauge tag.
1207 * @param uiOptionsAsFlags the UI options to use, as flags.
1208 * @return one of the {@code CONFIRMATIONUI_*} constants, for
1209 * example {@code KeyStore.CONFIRMATIONUI_OK}.
1210 */
1211 public int presentConfirmationPrompt(IBinder listener, String promptText, byte[] extraData,
1212 String locale, int uiOptionsAsFlags) {
1213 try {
1214 return mBinder.presentConfirmationPrompt(listener, promptText, extraData, locale,
1215 uiOptionsAsFlags);
1216 } catch (RemoteException e) {
1217 Log.w(TAG, "Cannot connect to keystore", e);
1218 return CONFIRMATIONUI_SYSTEM_ERROR;
1219 }
1220 }
1221
1222 /**
1223 * Requests keystore call into the confirmationui HAL to cancel displaying a prompt.
1224 *
1225 * @param listener the binder passed to the {@link #presentConfirmationPrompt} method.
1226 * @return one of the {@code CONFIRMATIONUI_*} constants, for
1227 * example {@code KeyStore.CONFIRMATIONUI_OK}.
1228 */
1229 public int cancelConfirmationPrompt(IBinder listener) {
1230 try {
1231 return mBinder.cancelConfirmationPrompt(listener);
1232 } catch (RemoteException e) {
1233 Log.w(TAG, "Cannot connect to keystore", e);
1234 return CONFIRMATIONUI_SYSTEM_ERROR;
1235 }
1236 }
1237
Chad Brubakera91a8502015-05-07 10:02:22 -07001238 /**
David Zeuthenbbb7f652018-02-26 11:04:18 -05001239 * Requests keystore to check if the confirmationui HAL is available.
1240 *
1241 * @return whether the confirmationUI HAL is available.
1242 */
1243 public boolean isConfirmationPromptSupported() {
1244 try {
1245 return mBinder.isConfirmationPromptSupported();
1246 } catch (RemoteException e) {
1247 Log.w(TAG, "Cannot connect to keystore", e);
1248 return false;
1249 }
1250 }
1251
1252 /**
Alex Klyubinad9ba102015-04-21 15:17:24 -07001253 * Returns a {@link KeyStoreException} corresponding to the provided keystore/keymaster error
1254 * code.
1255 */
Mathew Inwoode420f8b2018-08-16 18:40:47 +01001256 @UnsupportedAppUsage
Alex Klyubindcdaf872015-05-13 15:57:09 -07001257 public static KeyStoreException getKeyStoreException(int errorCode) {
Alex Klyubinb4834ae2015-04-02 15:53:46 -07001258 if (errorCode > 0) {
1259 // KeyStore layer error
1260 switch (errorCode) {
1261 case NO_ERROR:
1262 return new KeyStoreException(errorCode, "OK");
1263 case LOCKED:
Alex Klyubin54183932015-05-08 15:25:48 -07001264 return new KeyStoreException(errorCode, "User authentication required");
Alex Klyubinb4834ae2015-04-02 15:53:46 -07001265 case UNINITIALIZED:
1266 return new KeyStoreException(errorCode, "Keystore not initialized");
1267 case SYSTEM_ERROR:
1268 return new KeyStoreException(errorCode, "System error");
1269 case PERMISSION_DENIED:
1270 return new KeyStoreException(errorCode, "Permission denied");
1271 case KEY_NOT_FOUND:
1272 return new KeyStoreException(errorCode, "Key not found");
1273 case VALUE_CORRUPTED:
1274 return new KeyStoreException(errorCode, "Key blob corrupted");
Alex Klyubin058de022015-04-29 17:32:00 -07001275 case OP_AUTH_NEEDED:
1276 return new KeyStoreException(errorCode, "Operation requires authorization");
Max Bires13f98ce2018-11-02 10:50:40 -07001277 case KEY_PERMANENTLY_INVALIDATED:
1278 return new KeyStoreException(errorCode, "Key permanently invalidated");
Alex Klyubinb4834ae2015-04-02 15:53:46 -07001279 default:
1280 return new KeyStoreException(errorCode, String.valueOf(errorCode));
1281 }
1282 } else {
1283 // Keymaster layer error
1284 switch (errorCode) {
1285 case KeymasterDefs.KM_ERROR_INVALID_AUTHORIZATION_TIMEOUT:
1286 // The name of this parameter significantly differs between Keymaster and
1287 // framework APIs. Use the framework wording to make life easier for developers.
1288 return new KeyStoreException(errorCode,
1289 "Invalid user authentication validity duration");
1290 default:
1291 return new KeyStoreException(errorCode,
1292 KeymasterDefs.getErrorMessage(errorCode));
1293 }
1294 }
1295 }
1296
Alex Klyubinad9ba102015-04-21 15:17:24 -07001297 /**
1298 * Returns an {@link InvalidKeyException} corresponding to the provided
1299 * {@link KeyStoreException}.
1300 */
Alex Klyubindcdaf872015-05-13 15:57:09 -07001301 public InvalidKeyException getInvalidKeyException(
Alex Klyubin3876b1b2015-09-09 14:55:03 -07001302 String keystoreKeyAlias, int uid, KeyStoreException e) {
Alex Klyubinb4834ae2015-04-02 15:53:46 -07001303 switch (e.getErrorCode()) {
Brian Youngda82e2c2018-02-22 23:36:34 +00001304 case LOCKED:
Alex Klyubin54183932015-05-08 15:25:48 -07001305 return new UserNotAuthenticatedException();
Brian Youngda82e2c2018-02-22 23:36:34 +00001306 case KeymasterDefs.KM_ERROR_KEY_EXPIRED:
Alex Klyubinb4834ae2015-04-02 15:53:46 -07001307 return new KeyExpiredException();
Brian Youngda82e2c2018-02-22 23:36:34 +00001308 case KeymasterDefs.KM_ERROR_KEY_NOT_YET_VALID:
Alex Klyubinb4834ae2015-04-02 15:53:46 -07001309 return new KeyNotYetValidException();
Brian Youngda82e2c2018-02-22 23:36:34 +00001310 case KeymasterDefs.KM_ERROR_KEY_USER_NOT_AUTHENTICATED:
1311 case OP_AUTH_NEEDED:
Alex Klyubin708fc9402015-04-28 18:58:47 -07001312 {
1313 // We now need to determine whether the key/operation can become usable if user
1314 // authentication is performed, or whether it can never become usable again.
1315 // User authentication requirements are contained in the key's characteristics. We
1316 // need to check whether these requirements can be be satisfied by asking the user
1317 // to authenticate.
1318 KeyCharacteristics keyCharacteristics = new KeyCharacteristics();
1319 int getKeyCharacteristicsErrorCode =
Alex Klyubin3876b1b2015-09-09 14:55:03 -07001320 getKeyCharacteristics(keystoreKeyAlias, null, null, uid,
1321 keyCharacteristics);
Alex Klyubin708fc9402015-04-28 18:58:47 -07001322 if (getKeyCharacteristicsErrorCode != NO_ERROR) {
1323 return new InvalidKeyException(
1324 "Failed to obtained key characteristics",
1325 getKeyStoreException(getKeyCharacteristicsErrorCode));
1326 }
Alex Klyubinae6cb7a2015-06-22 18:09:35 -07001327 List<BigInteger> keySids =
1328 keyCharacteristics.getUnsignedLongs(KeymasterDefs.KM_TAG_USER_SECURE_ID);
Alex Klyubin708fc9402015-04-28 18:58:47 -07001329 if (keySids.isEmpty()) {
1330 // Key is not bound to any SIDs -- no amount of authentication will help here.
1331 return new KeyPermanentlyInvalidatedException();
1332 }
1333 long rootSid = GateKeeper.getSecureUserId();
Alex Klyubinae6cb7a2015-06-22 18:09:35 -07001334 if ((rootSid != 0) && (keySids.contains(KeymasterArguments.toUint64(rootSid)))) {
Alex Klyubin708fc9402015-04-28 18:58:47 -07001335 // One of the key's SIDs is the current root SID -- user can be authenticated
1336 // against that SID.
1337 return new UserNotAuthenticatedException();
1338 }
1339
Kevin Chyn057b7432018-09-24 14:36:39 -07001340 final long fingerprintOnlySid = getFingerprintOnlySid();
Alex Klyubin708fc9402015-04-28 18:58:47 -07001341 if ((fingerprintOnlySid != 0)
Alex Klyubinae6cb7a2015-06-22 18:09:35 -07001342 && (keySids.contains(KeymasterArguments.toUint64(fingerprintOnlySid)))) {
Alex Klyubin708fc9402015-04-28 18:58:47 -07001343 // One of the key's SIDs is the current fingerprint SID -- user can be
1344 // authenticated against that SID.
1345 return new UserNotAuthenticatedException();
1346 }
1347
Kevin Chyn057b7432018-09-24 14:36:39 -07001348 final long faceOnlySid = getFaceOnlySid();
1349 if ((faceOnlySid != 0)
1350 && (keySids.contains(KeymasterArguments.toUint64(faceOnlySid)))) {
1351 // One of the key's SIDs is the current face SID -- user can be
1352 // authenticated against that SID.
1353 return new UserNotAuthenticatedException();
1354 }
1355
Alex Klyubin708fc9402015-04-28 18:58:47 -07001356 // None of the key's SIDs can ever be authenticated
1357 return new KeyPermanentlyInvalidatedException();
1358 }
Brian Youngda82e2c2018-02-22 23:36:34 +00001359 case UNINITIALIZED:
Janis Danisevskisd07d3382017-09-01 14:45:16 -07001360 return new KeyPermanentlyInvalidatedException();
Alex Klyubinb4834ae2015-04-02 15:53:46 -07001361 default:
Alex Klyubinad9ba102015-04-21 15:17:24 -07001362 return new InvalidKeyException("Keystore operation failed", e);
Alex Klyubinb4834ae2015-04-02 15:53:46 -07001363 }
1364 }
1365
Kevin Chyn057b7432018-09-24 14:36:39 -07001366 private long getFaceOnlySid() {
1367 final PackageManager packageManager = mContext.getPackageManager();
1368 if (!packageManager.hasSystemFeature(PackageManager.FEATURE_FACE)) {
1369 return 0;
1370 }
1371 FaceManager faceManager = mContext.getSystemService(FaceManager.class);
1372 if (faceManager == null) {
1373 return 0;
1374 }
1375
1376 // TODO: Restore USE_BIOMETRIC or USE_BIOMETRIC_INTERNAL permission check in
1377 // FaceManager.getAuthenticatorId once the ID is no longer needed here.
1378 return faceManager.getAuthenticatorId();
1379 }
1380
Alex Klyubin2d7a85c2015-04-30 11:43:53 -07001381 private long getFingerprintOnlySid() {
Kevin Chyn55966422017-10-23 16:08:47 -07001382 final PackageManager packageManager = mContext.getPackageManager();
1383 if (!packageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) {
1384 return 0;
1385 }
Alex Klyubina99b8b52015-06-11 13:27:34 -07001386 FingerprintManager fingerprintManager = mContext.getSystemService(FingerprintManager.class);
Alex Klyubin2d7a85c2015-04-30 11:43:53 -07001387 if (fingerprintManager == null) {
Alex Klyubin708fc9402015-04-28 18:58:47 -07001388 return 0;
1389 }
1390
Alex Klyubina99b8b52015-06-11 13:27:34 -07001391 // TODO: Restore USE_FINGERPRINT permission check in
1392 // FingerprintManager.getAuthenticatorId once the ID is no longer needed here.
Alex Klyubin2d7a85c2015-04-30 11:43:53 -07001393 return fingerprintManager.getAuthenticatorId();
Svetoslav2dac95d2015-04-30 11:30:33 -07001394 }
1395
Alex Klyubinad9ba102015-04-21 15:17:24 -07001396 /**
1397 * Returns an {@link InvalidKeyException} corresponding to the provided keystore/keymaster error
1398 * code.
1399 */
Alex Klyubin3876b1b2015-09-09 14:55:03 -07001400 public InvalidKeyException getInvalidKeyException(String keystoreKeyAlias, int uid,
1401 int errorCode) {
1402 return getInvalidKeyException(keystoreKeyAlias, uid, getKeyStoreException(errorCode));
Alex Klyubinb4834ae2015-04-02 15:53:46 -07001403 }
Chia-chi Yeh44039172009-09-21 11:53:59 +08001404}