blob: 40570c1083b30e0b36f3a06adea0eaa32de6c861 [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 Inwood4dbdcf42018-08-16 18:49:37 +010019import android.annotation.UnsupportedAppUsage;
Brian Young9272dab2018-02-23 18:04:20 +000020import android.app.ActivityManager;
Svetoslav2dac95d2015-04-30 11:30:33 -070021import android.app.ActivityThread;
22import android.app.Application;
Alex Klyubin54183932015-05-08 15:25:48 -070023import android.app.KeyguardManager;
Alex Klyubin708fc9402015-04-28 18:58:47 -070024import android.content.Context;
Kevin Chyn55966422017-10-23 16:08:47 -070025import android.content.pm.PackageManager;
Alex Klyubin2d7a85c2015-04-30 11:43:53 -070026import android.hardware.fingerprint.FingerprintManager;
Chad Brubakere6a461342015-02-10 21:33:23 -080027import android.os.Binder;
28import android.os.IBinder;
Chad Brubakera91a8502015-05-07 10:02:22 -070029import android.os.Process;
Kenny Root6b776452012-11-02 15:40:32 -070030import android.os.RemoteException;
31import android.os.ServiceManager;
Chad Brubakera91a8502015-05-07 10:02:22 -070032import android.os.UserHandle;
Janis Danisevskis1864c952018-08-09 11:14:49 -070033import android.security.KeyStoreException;
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;
46import android.security.keystore.KeyProtection;
Janis Danisevskisb0358e72018-11-02 10:34:07 -070047import android.security.keystore.KeystoreResponse;
Frank Salimea5e0382018-01-23 22:42:29 -080048import android.security.keystore.StrongBoxUnavailableException;
Alex Klyubin3f8d4d82015-05-13 09:15:00 -070049import android.security.keystore.UserNotAuthenticatedException;
Kenny Root6b776452012-11-02 15:40:32 -070050import android.util.Log;
Janis Danisevskis1864c952018-08-09 11:14:49 -070051import com.android.org.bouncycastle.asn1.ASN1InputStream;
52import com.android.org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
Alex Klyubinae6cb7a2015-06-22 18:09:35 -070053import java.math.BigInteger;
Janis Danisevskis1864c952018-08-09 11:14:49 -070054import java.io.ByteArrayInputStream;
55import java.io.IOException;
Alex Klyubinad9ba102015-04-21 15:17:24 -070056import java.security.InvalidKeyException;
Rob Barnesf1a678e2018-11-13 15:57:22 -070057import java.util.Arrays;
Alex Klyubin708fc9402015-04-28 18:58:47 -070058import java.util.List;
Kenny Rootb91773b2013-09-05 13:03:16 -070059import java.util.Locale;
Janis Danisevskisb0358e72018-11-02 10:34:07 -070060import java.util.concurrent.CompletableFuture;
61import java.util.concurrent.ExecutionException;
Janis Danisevskis1864c952018-08-09 11:14:49 -070062import sun.security.util.ObjectIdentifier;
63import sun.security.x509.AlgorithmId;
Kenny Rootb91773b2013-09-05 13:03:16 -070064
Chia-chi Yeh44039172009-09-21 11:53:59 +080065/**
Brian Carlstrom46703b02011-04-06 15:41:29 -070066 * @hide This should not be made public in its present form because it
67 * assumes that private and secret key bytes are available and would
68 * preclude the use of hardware crypto.
Chia-chi Yeh44039172009-09-21 11:53:59 +080069 */
70public class KeyStore {
Kenny Root6b776452012-11-02 15:40:32 -070071 private static final String TAG = "KeyStore";
Brian Carlstrom5cfee3f2011-05-31 01:00:15 -070072
Dmitry Dementyevefc43112017-10-27 23:10:28 -070073 // ResponseCodes - see system/security/keystore/include/keystore/keystore.h
Mathew Inwood4dbdcf42018-08-16 18:49:37 +010074 @UnsupportedAppUsage
Brian Carlstrom7e4b1a42011-06-01 15:29:29 -070075 public static final int NO_ERROR = 1;
76 public static final int LOCKED = 2;
77 public static final int UNINITIALIZED = 3;
78 public static final int SYSTEM_ERROR = 4;
79 public static final int PROTOCOL_ERROR = 5;
80 public static final int PERMISSION_DENIED = 6;
81 public static final int KEY_NOT_FOUND = 7;
82 public static final int VALUE_CORRUPTED = 8;
83 public static final int UNDEFINED_ACTION = 9;
84 public static final int WRONG_PASSWORD = 10;
Janis Danisevskisd2575382018-10-08 07:56:58 -070085 public static final int KEY_ALREADY_EXISTS = 16;
Eran Messeri61692392018-03-26 16:43:14 +010086 public static final int CANNOT_ATTEST_IDS = -66;
Frank Salimea5e0382018-01-23 22:42:29 -080087 public static final int HARDWARE_TYPE_UNAVAILABLE = -68;
Brian Carlstrom5cfee3f2011-05-31 01:00:15 -070088
Chad Brubaker560d6532015-04-24 10:32:18 -070089 /**
90 * Per operation authentication is needed before this operation is valid.
91 * This is returned from {@link #begin} when begin succeeds but the operation uses
92 * per-operation authentication and must authenticate before calling {@link #update} or
93 * {@link #finish}.
94 */
95 public static final int OP_AUTH_NEEDED = 15;
96
Kenny Root2eeda722013-04-10 11:30:58 -070097 // Used for UID field to indicate the calling UID.
98 public static final int UID_SELF = -1;
99
100 // Flags for "put" "import" and "generate"
101 public static final int FLAG_NONE = 0;
Alex Klyubin54183932015-05-08 15:25:48 -0700102
103 /**
104 * Indicates that this key (or key pair) must be encrypted at rest. This will protect the key
105 * (or key pair) with the secure lock screen credential (e.g., password, PIN, or pattern).
106 *
107 * <p>Note that this requires that the secure lock screen (e.g., password, PIN, pattern) is set
108 * up, otherwise key (or key pair) generation or import will fail. Moreover, this key (or key
109 * pair) will be deleted when the secure lock screen is disabled or reset (e.g., by the user or
110 * a Device Administrator). Finally, this key (or key pair) cannot be used until the user
111 * unlocks the secure lock screen after boot.
112 *
113 * @see KeyguardManager#isDeviceSecure()
114 */
Kenny Roota3788b02013-04-10 10:37:55 -0700115 public static final int FLAG_ENCRYPTED = 1;
116
Rubin Xu12b644d2017-04-21 19:21:42 +0100117 /**
Janis Danisevskis0aadf932017-12-18 17:28:52 -0800118 * Select Software keymaster device, which as of this writing is the lowest security
119 * level available on an android device. If neither FLAG_STRONGBOX nor FLAG_SOFTWARE is provided
120 * A TEE based keymaster implementation is implied.
121 *
122 * Need to be in sync with KeyStoreFlag in system/security/keystore/include/keystore/keystore.h
123 * For historical reasons this corresponds to the KEYSTORE_FLAG_FALLBACK flag.
124 */
125 public static final int FLAG_SOFTWARE = 1 << 1;
126
127 /**
Rubin Xu12b644d2017-04-21 19:21:42 +0100128 * A private flag that's only available to system server to indicate that this key is part of
129 * device encryption flow so it receives special treatment from keystore. For example this key
130 * will not be super encrypted, and it will be stored separately under an unique UID instead
131 * of the caller UID i.e. SYSTEM.
132 *
133 * Need to be in sync with KeyStoreFlag in system/security/keystore/include/keystore/keystore.h
134 */
135 public static final int FLAG_CRITICAL_TO_DEVICE_ENCRYPTION = 1 << 3;
136
Janis Danisevskis0aadf932017-12-18 17:28:52 -0800137 /**
138 * Select Strongbox keymaster device, which as of this writing the the highest security level
139 * available an android devices. If neither FLAG_STRONGBOX nor FLAG_SOFTWARE is provided
140 * A TEE based keymaster implementation is implied.
141 *
142 * Need to be in sync with KeyStoreFlag in system/security/keystore/include/keystore/keystore.h
143 */
144 public static final int FLAG_STRONGBOX = 1 << 4;
145
Brian Carlstrom5cfee3f2011-05-31 01:00:15 -0700146 // States
Mathew Inwoodefb48162018-08-01 10:24:49 +0100147 public enum State {
Mathew Inwood4dbdcf42018-08-16 18:49:37 +0100148 @UnsupportedAppUsage
Mathew Inwoodefb48162018-08-01 10:24:49 +0100149 UNLOCKED,
Mathew Inwood4dbdcf42018-08-16 18:49:37 +0100150 @UnsupportedAppUsage
Mathew Inwoodefb48162018-08-01 10:24:49 +0100151 LOCKED,
152 UNINITIALIZED
153 };
Chia-chi Yeh44039172009-09-21 11:53:59 +0800154
Chia-chi Yeh44039172009-09-21 11:53:59 +0800155 private int mError = NO_ERROR;
156
Kenny Root6b776452012-11-02 15:40:32 -0700157 private final IKeystoreService mBinder;
Alex Klyubin2d7a85c2015-04-30 11:43:53 -0700158 private final Context mContext;
Kenny Root6b776452012-11-02 15:40:32 -0700159
Chad Brubakere6a461342015-02-10 21:33:23 -0800160 private IBinder mToken;
161
Kenny Root6b776452012-11-02 15:40:32 -0700162 private KeyStore(IKeystoreService binder) {
163 mBinder = binder;
Alex Klyubin3f8d4d82015-05-13 09:15:00 -0700164 mContext = getApplicationContext();
Alex Klyubin2d7a85c2015-04-30 11:43:53 -0700165 }
166
Mathew Inwood4dbdcf42018-08-16 18:49:37 +0100167 @UnsupportedAppUsage
Alex Klyubindcdaf872015-05-13 15:57:09 -0700168 public static Context getApplicationContext() {
Alex Klyubina99b8b52015-06-11 13:27:34 -0700169 Application application = ActivityThread.currentApplication();
Alex Klyubin2d7a85c2015-04-30 11:43:53 -0700170 if (application == null) {
171 throw new IllegalStateException(
Alex Klyubina99b8b52015-06-11 13:27:34 -0700172 "Failed to obtain application Context from ActivityThread");
Alex Klyubin2d7a85c2015-04-30 11:43:53 -0700173 }
174 return application;
Kenny Root6b776452012-11-02 15:40:32 -0700175 }
Chia-chi Yeh44039172009-09-21 11:53:59 +0800176
Mathew Inwood4dbdcf42018-08-16 18:49:37 +0100177 @UnsupportedAppUsage
Chia-chi Yeh44039172009-09-21 11:53:59 +0800178 public static KeyStore getInstance() {
Kenny Root6b776452012-11-02 15:40:32 -0700179 IKeystoreService keystore = IKeystoreService.Stub.asInterface(ServiceManager
180 .getService("android.security.keystore"));
181 return new KeyStore(keystore);
Chia-chi Yeh44039172009-09-21 11:53:59 +0800182 }
183
Chad Brubakere6a461342015-02-10 21:33:23 -0800184 private synchronized IBinder getToken() {
185 if (mToken == null) {
186 mToken = new Binder();
187 }
188 return mToken;
189 }
190
Mathew Inwood4dbdcf42018-08-16 18:49:37 +0100191 @UnsupportedAppUsage
Chad Brubakere35d49f2015-05-12 15:19:52 -0700192 public State state(int userId) {
Kenny Root6b776452012-11-02 15:40:32 -0700193 final int ret;
194 try {
Chad Brubakere35d49f2015-05-12 15:19:52 -0700195 ret = mBinder.getState(userId);
Kenny Root6b776452012-11-02 15:40:32 -0700196 } catch (RemoteException e) {
197 Log.w(TAG, "Cannot connect to keystore", e);
198 throw new AssertionError(e);
199 }
200
201 switch (ret) {
Brian Carlstrom5cfee3f2011-05-31 01:00:15 -0700202 case NO_ERROR: return State.UNLOCKED;
203 case LOCKED: return State.LOCKED;
204 case UNINITIALIZED: return State.UNINITIALIZED;
205 default: throw new AssertionError(mError);
206 }
Chia-chi Yeh44039172009-09-21 11:53:59 +0800207 }
208
Mathew Inwood4dbdcf42018-08-16 18:49:37 +0100209 @UnsupportedAppUsage
Chad Brubakere35d49f2015-05-12 15:19:52 -0700210 public State state() {
211 return state(UserHandle.myUserId());
212 }
213
Kenny Rootb9594ce2013-02-14 10:18:38 -0800214 public boolean isUnlocked() {
215 return state() == State.UNLOCKED;
216 }
217
Chad Brubaker5bbf0482015-09-09 14:53:52 -0700218 public byte[] get(String key, int uid) {
Kenny Root6b776452012-11-02 15:40:32 -0700219 try {
Dmitry Dementyevefc43112017-10-27 23:10:28 -0700220 key = key != null ? key : "";
Chad Brubaker5bbf0482015-09-09 14:53:52 -0700221 return mBinder.get(key, uid);
Kenny Root6b776452012-11-02 15:40:32 -0700222 } catch (RemoteException e) {
223 Log.w(TAG, "Cannot connect to keystore", e);
224 return null;
Dmitry Dementyevefc43112017-10-27 23:10:28 -0700225 } catch (android.os.ServiceSpecificException e) {
226 Log.w(TAG, "KeyStore exception", e);
227 return null;
Kenny Root6b776452012-11-02 15:40:32 -0700228 }
Chia-chi Yeh44039172009-09-21 11:53:59 +0800229 }
230
Mathew Inwood4dbdcf42018-08-16 18:49:37 +0100231 @UnsupportedAppUsage
Chad Brubaker5bbf0482015-09-09 14:53:52 -0700232 public byte[] get(String key) {
233 return get(key, UID_SELF);
234 }
235
Kenny Roota3788b02013-04-10 10:37:55 -0700236 public boolean put(String key, byte[] value, int uid, int flags) {
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700237 return insert(key, value, uid, flags) == NO_ERROR;
238 }
239
240 public int insert(String key, byte[] value, int uid, int flags) {
Kenny Root6b776452012-11-02 15:40:32 -0700241 try {
Dmitry Dementyevefc43112017-10-27 23:10:28 -0700242 if (value == null) {
243 value = new byte[0];
244 }
Janis Danisevskisd2575382018-10-08 07:56:58 -0700245 int error = mBinder.insert(key, value, uid, flags);
246 if (error == KEY_ALREADY_EXISTS) {
247 mBinder.del(key, uid);
248 error = mBinder.insert(key, value, uid, flags);
249 }
250 return error;
Kenny Root78ad8492013-02-13 17:02:57 -0800251 } catch (RemoteException e) {
252 Log.w(TAG, "Cannot connect to keystore", e);
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700253 return SYSTEM_ERROR;
Kenny Root78ad8492013-02-13 17:02:57 -0800254 }
255 }
256
Kenny Root78ad8492013-02-13 17:02:57 -0800257 public boolean delete(String key, int uid) {
258 try {
Robin Leee4487ea2016-02-29 17:43:54 +0000259 int ret = mBinder.del(key, uid);
260 return (ret == NO_ERROR || ret == KEY_NOT_FOUND);
Kenny Root6b776452012-11-02 15:40:32 -0700261 } catch (RemoteException e) {
262 Log.w(TAG, "Cannot connect to keystore", e);
263 return false;
264 }
Chia-chi Yeh44039172009-09-21 11:53:59 +0800265 }
266
Mathew Inwood4dbdcf42018-08-16 18:49:37 +0100267 @UnsupportedAppUsage
Chia-chi Yeh44039172009-09-21 11:53:59 +0800268 public boolean delete(String key) {
Kenny Root2eeda722013-04-10 11:30:58 -0700269 return delete(key, UID_SELF);
Kenny Root78ad8492013-02-13 17:02:57 -0800270 }
271
272 public boolean contains(String key, int uid) {
Kenny Root6b776452012-11-02 15:40:32 -0700273 try {
Kenny Root78ad8492013-02-13 17:02:57 -0800274 return mBinder.exist(key, uid) == NO_ERROR;
Kenny Root6b776452012-11-02 15:40:32 -0700275 } catch (RemoteException e) {
276 Log.w(TAG, "Cannot connect to keystore", e);
277 return false;
278 }
Chia-chi Yeh44039172009-09-21 11:53:59 +0800279 }
280
281 public boolean contains(String key) {
Kenny Root2eeda722013-04-10 11:30:58 -0700282 return contains(key, UID_SELF);
Chia-chi Yeh44039172009-09-21 11:53:59 +0800283 }
284
Chad Brubakere35d49f2015-05-12 15:19:52 -0700285 /**
286 * List all entries in the keystore for {@code uid} starting with {@code prefix}.
287 */
288 public String[] list(String prefix, int uid) {
Kenny Root6b776452012-11-02 15:40:32 -0700289 try {
Chad Brubakere35d49f2015-05-12 15:19:52 -0700290 return mBinder.list(prefix, uid);
Kenny Root6b776452012-11-02 15:40:32 -0700291 } catch (RemoteException e) {
292 Log.w(TAG, "Cannot connect to keystore", e);
Chia-chi Yeh44039172009-09-21 11:53:59 +0800293 return null;
Dmitry Dementyevefc43112017-10-27 23:10:28 -0700294 } catch (android.os.ServiceSpecificException e) {
295 Log.w(TAG, "KeyStore exception", e);
296 return null;
Chia-chi Yeh44039172009-09-21 11:53:59 +0800297 }
Chia-chi Yeh44039172009-09-21 11:53:59 +0800298 }
299
Rob Barnesf1a678e2018-11-13 15:57:22 -0700300 /**
301 * List uids of all keys that are auth bound to the current user.
302 * Only system is allowed to call this method.
303 */
304 @UnsupportedAppUsage
305 public int[] listUidsOfAuthBoundKeys() {
306 final int MAX_RESULT_SIZE = 100;
307 int[] uidsOut = new int[MAX_RESULT_SIZE];
308 try {
309 int rc = mBinder.listUidsOfAuthBoundKeys(uidsOut);
310 if (rc != NO_ERROR) {
311 Log.w(TAG, String.format("listUidsOfAuthBoundKeys failed with error code %d", rc));
312 return null;
313 }
314 } catch (RemoteException e) {
315 Log.w(TAG, "Cannot connect to keystore", e);
316 return null;
317 } catch (android.os.ServiceSpecificException e) {
318 Log.w(TAG, "KeyStore exception", e);
319 return null;
320 }
321 // Remove any 0 entries
322 return Arrays.stream(uidsOut).filter(x -> x > 0).toArray();
323 }
324
Chad Brubakere35d49f2015-05-12 15:19:52 -0700325 public String[] list(String prefix) {
326 return list(prefix, UID_SELF);
327 }
328
Mathew Inwood4dbdcf42018-08-16 18:49:37 +0100329 @UnsupportedAppUsage
Chia-chi Yeh44039172009-09-21 11:53:59 +0800330 public boolean reset() {
Kenny Root6b776452012-11-02 15:40:32 -0700331 try {
332 return mBinder.reset() == NO_ERROR;
333 } catch (RemoteException e) {
334 Log.w(TAG, "Cannot connect to keystore", e);
335 return false;
336 }
Chia-chi Yeh44039172009-09-21 11:53:59 +0800337 }
338
Chad Brubakere35d49f2015-05-12 15:19:52 -0700339 /**
340 * Attempt to lock the keystore for {@code user}.
341 *
Brian Young36716eb2018-02-23 18:04:20 +0000342 * @param userId Android user to lock.
Chad Brubakere35d49f2015-05-12 15:19:52 -0700343 * @return whether {@code user}'s keystore was locked.
344 */
345 public boolean lock(int userId) {
Kenny Root6b776452012-11-02 15:40:32 -0700346 try {
Chad Brubakere35d49f2015-05-12 15:19:52 -0700347 return mBinder.lock(userId) == NO_ERROR;
Kenny Root6b776452012-11-02 15:40:32 -0700348 } catch (RemoteException e) {
349 Log.w(TAG, "Cannot connect to keystore", e);
350 return false;
351 }
Chia-chi Yeh44039172009-09-21 11:53:59 +0800352 }
353
Chad Brubakere35d49f2015-05-12 15:19:52 -0700354 public boolean lock() {
355 return lock(UserHandle.myUserId());
356 }
357
Chad Brubakera91a8502015-05-07 10:02:22 -0700358 /**
359 * Attempt to unlock the keystore for {@code user} with the password {@code password}.
360 * This is required before keystore entries created with FLAG_ENCRYPTED can be accessed or
361 * created.
362 *
Brian Young36716eb2018-02-23 18:04:20 +0000363 * @param userId Android user ID to operate on
Chad Brubakera91a8502015-05-07 10:02:22 -0700364 * @param password user's keystore password. Should be the most recent value passed to
365 * {@link #onUserPasswordChanged} for the user.
366 *
367 * @return whether the keystore was unlocked.
368 */
369 public boolean unlock(int userId, String password) {
Kenny Root6b776452012-11-02 15:40:32 -0700370 try {
Dmitry Dementyevefc43112017-10-27 23:10:28 -0700371 password = password != null ? password : "";
Chad Brubakera91a8502015-05-07 10:02:22 -0700372 mError = mBinder.unlock(userId, password);
Kenny Root6b776452012-11-02 15:40:32 -0700373 return mError == NO_ERROR;
374 } catch (RemoteException e) {
375 Log.w(TAG, "Cannot connect to keystore", e);
376 return false;
377 }
Chia-chi Yeh44039172009-09-21 11:53:59 +0800378 }
379
Mathew Inwood4dbdcf42018-08-16 18:49:37 +0100380 @UnsupportedAppUsage
Chad Brubakera91a8502015-05-07 10:02:22 -0700381 public boolean unlock(String password) {
382 return unlock(UserHandle.getUserId(Process.myUid()), password);
383 }
384
Chad Brubakere35d49f2015-05-12 15:19:52 -0700385 /**
386 * Check if the keystore for {@code userId} is empty.
387 */
388 public boolean isEmpty(int userId) {
Kenny Root6b776452012-11-02 15:40:32 -0700389 try {
Chad Brubakere35d49f2015-05-12 15:19:52 -0700390 return mBinder.isEmpty(userId) != 0;
Kenny Root6b776452012-11-02 15:40:32 -0700391 } catch (RemoteException e) {
392 Log.w(TAG, "Cannot connect to keystore", e);
393 return false;
394 }
Kenny Root5423e682011-11-14 08:43:13 -0800395 }
396
Mathew Inwood4dbdcf42018-08-16 18:49:37 +0100397 @UnsupportedAppUsage
Chad Brubakere35d49f2015-05-12 15:19:52 -0700398 public boolean isEmpty() {
399 return isEmpty(UserHandle.myUserId());
400 }
401
Janis Danisevskisb50e9f62017-06-08 17:53:34 -0700402 public String grant(String key, int uid) {
Kenny Root6b776452012-11-02 15:40:32 -0700403 try {
Janis Danisevskisb50e9f62017-06-08 17:53:34 -0700404 String grantAlias = mBinder.grant(key, uid);
405 if (grantAlias == "") return null;
406 return grantAlias;
Kenny Root6b776452012-11-02 15:40:32 -0700407 } catch (RemoteException e) {
408 Log.w(TAG, "Cannot connect to keystore", e);
Janis Danisevskisb50e9f62017-06-08 17:53:34 -0700409 return null;
Kenny Root6b776452012-11-02 15:40:32 -0700410 }
Kenny Root5423e682011-11-14 08:43:13 -0800411 }
412
413 public boolean ungrant(String key, int uid) {
Kenny Root6b776452012-11-02 15:40:32 -0700414 try {
415 return mBinder.ungrant(key, uid) == NO_ERROR;
416 } catch (RemoteException e) {
417 Log.w(TAG, "Cannot connect to keystore", e);
418 return false;
Kenny Root473c7122012-08-17 21:13:48 -0700419 }
Kenny Root473c7122012-08-17 21:13:48 -0700420 }
421
422 /**
423 * Returns the last modification time of the key in milliseconds since the
424 * epoch. Will return -1L if the key could not be found or other error.
425 */
Chad Brubaker5bbf0482015-09-09 14:53:52 -0700426 public long getmtime(String key, int uid) {
Kenny Root6b776452012-11-02 15:40:32 -0700427 try {
Chad Brubaker5bbf0482015-09-09 14:53:52 -0700428 final long millis = mBinder.getmtime(key, uid);
Kenny Roote66769a2013-02-04 15:49:11 -0800429 if (millis == -1L) {
430 return -1L;
431 }
432
433 return millis * 1000L;
Kenny Root6b776452012-11-02 15:40:32 -0700434 } catch (RemoteException e) {
435 Log.w(TAG, "Cannot connect to keystore", e);
436 return -1L;
437 }
Kenny Root473c7122012-08-17 21:13:48 -0700438 }
439
Chad Brubaker5bbf0482015-09-09 14:53:52 -0700440 public long getmtime(String key) {
441 return getmtime(key, UID_SELF);
442 }
443
Alex Klyubin469cbf52015-06-04 12:36:27 -0700444 // TODO: remove this when it's removed from Settings
Kenny Root5cb5cec2013-03-29 11:14:17 -0700445 public boolean isHardwareBacked() {
Kenny Rootb91773b2013-09-05 13:03:16 -0700446 return isHardwareBacked("RSA");
447 }
448
449 public boolean isHardwareBacked(String keyType) {
Kenny Root5cb5cec2013-03-29 11:14:17 -0700450 try {
Kenny Rootb91773b2013-09-05 13:03:16 -0700451 return mBinder.is_hardware_backed(keyType.toUpperCase(Locale.US)) == NO_ERROR;
Kenny Root5cb5cec2013-03-29 11:14:17 -0700452 } catch (RemoteException e) {
453 Log.w(TAG, "Cannot connect to keystore", e);
454 return false;
455 }
456 }
457
Kenny Rootd72317a2013-04-01 15:59:59 -0700458 public boolean clearUid(int uid) {
459 try {
460 return mBinder.clear_uid(uid) == NO_ERROR;
461 } catch (RemoteException e) {
462 Log.w(TAG, "Cannot connect to keystore", e);
463 return false;
464 }
465 }
466
Chia-chi Yeh44039172009-09-21 11:53:59 +0800467 public int getLastError() {
468 return mError;
469 }
Chad Brubakere6a461342015-02-10 21:33:23 -0800470
Janis Danisevskis0aadf932017-12-18 17:28:52 -0800471 public boolean addRngEntropy(byte[] data, int flags) {
Chad Brubakere6a461342015-02-10 21:33:23 -0800472 try {
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700473 KeystoreResultPromise promise = new KeystoreResultPromise();
474 int errorCode = mBinder.addRngEntropy(promise, data, flags);
475 if (errorCode == NO_ERROR) {
476 return promise.getFuture().get().getErrorCode() == NO_ERROR;
477 } else {
478 return false;
479 }
Chad Brubakere6a461342015-02-10 21:33:23 -0800480 } catch (RemoteException e) {
481 Log.w(TAG, "Cannot connect to keystore", e);
482 return false;
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700483 } catch (ExecutionException | InterruptedException e) {
484 Log.e(TAG, "AddRngEntropy completed with exception", e);
485 return false;
Chad Brubakere6a461342015-02-10 21:33:23 -0800486 }
487 }
488
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700489 private class KeyCharacteristicsCallbackResult {
490 private KeystoreResponse keystoreResponse;
491 private KeyCharacteristics keyCharacteristics;
492
493 public KeyCharacteristicsCallbackResult(KeystoreResponse keystoreResponse,
494 KeyCharacteristics keyCharacteristics) {
495 this.keystoreResponse = keystoreResponse;
496 this.keyCharacteristics = keyCharacteristics;
497 }
498
499 public KeystoreResponse getKeystoreResponse() {
500 return keystoreResponse;
501 }
502
503 public void setKeystoreResponse(KeystoreResponse keystoreResponse) {
504 this.keystoreResponse = keystoreResponse;
505 }
506
507 public KeyCharacteristics getKeyCharacteristics() {
508 return keyCharacteristics;
509 }
510
511 public void setKeyCharacteristics(KeyCharacteristics keyCharacteristics) {
512 this.keyCharacteristics = keyCharacteristics;
513 }
514 }
515
516 private class KeyCharacteristicsPromise
517 extends android.security.keystore.IKeystoreKeyCharacteristicsCallback.Stub {
518 final private CompletableFuture<KeyCharacteristicsCallbackResult> future =
519 new CompletableFuture<KeyCharacteristicsCallbackResult>();
520 @Override
521 public void onFinished(KeystoreResponse keystoreResponse,
522 KeyCharacteristics keyCharacteristics)
523 throws android.os.RemoteException {
524 future.complete(
525 new KeyCharacteristicsCallbackResult(keystoreResponse, keyCharacteristics));
526 }
527 public final CompletableFuture<KeyCharacteristicsCallbackResult> getFuture() {
528 return future;
529 }
530 };
531
532 private int generateKeyInternal(String alias, KeymasterArguments args, byte[] entropy, int uid,
533 int flags, KeyCharacteristics outCharacteristics)
534 throws RemoteException, ExecutionException, InterruptedException {
535 KeyCharacteristicsPromise promise = new KeyCharacteristicsPromise();
536 int error = mBinder.generateKey(promise, alias, args, entropy, uid, flags);
537 if (error != NO_ERROR) {
538 Log.e(TAG, "generateKeyInternal failed on request " + error);
539 return error;
540 }
541
542 KeyCharacteristicsCallbackResult result = promise.getFuture().get();
543 error = result.getKeystoreResponse().getErrorCode();
544 if (error != NO_ERROR) {
545 Log.e(TAG, "generateKeyInternal failed on response " + error);
546 return error;
547 }
548 KeyCharacteristics characteristics = result.getKeyCharacteristics();
549 if (characteristics == null) {
550 Log.e(TAG, "generateKeyInternal got empty key cheractariestics " + error);
551 return SYSTEM_ERROR;
552 }
553 outCharacteristics.shallowCopyFrom(characteristics);
554 return NO_ERROR;
555 }
556
Chad Brubakerdae79e52015-03-27 14:28:35 -0700557 public int generateKey(String alias, KeymasterArguments args, byte[] entropy, int uid,
558 int flags, KeyCharacteristics outCharacteristics) {
Chad Brubakere6a461342015-02-10 21:33:23 -0800559 try {
Dmitry Dementyevefc43112017-10-27 23:10:28 -0700560 entropy = entropy != null ? entropy : new byte[0];
561 args = args != null ? args : new KeymasterArguments();
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700562 int error = generateKeyInternal(alias, args, entropy, uid, flags, outCharacteristics);
Janis Danisevskisd2575382018-10-08 07:56:58 -0700563 if (error == KEY_ALREADY_EXISTS) {
564 mBinder.del(alias, uid);
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700565 error = generateKeyInternal(alias, args, entropy, uid, flags, outCharacteristics);
Janis Danisevskisd2575382018-10-08 07:56:58 -0700566 }
567 return error;
Chad Brubakere6a461342015-02-10 21:33:23 -0800568 } catch (RemoteException e) {
569 Log.w(TAG, "Cannot connect to keystore", e);
570 return SYSTEM_ERROR;
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700571 } catch (ExecutionException | InterruptedException e) {
572 Log.e(TAG, "generateKey completed with exception", e);
573 return SYSTEM_ERROR;
Chad Brubakere6a461342015-02-10 21:33:23 -0800574 }
575 }
576
Chad Brubakerdae79e52015-03-27 14:28:35 -0700577 public int generateKey(String alias, KeymasterArguments args, byte[] entropy, int flags,
Chad Brubakere6a461342015-02-10 21:33:23 -0800578 KeyCharacteristics outCharacteristics) {
Chad Brubakerdae79e52015-03-27 14:28:35 -0700579 return generateKey(alias, args, entropy, UID_SELF, flags, outCharacteristics);
Chad Brubakere6a461342015-02-10 21:33:23 -0800580 }
581
Chad Brubaker5e73c0e2015-03-21 22:46:43 -0700582 public int getKeyCharacteristics(String alias, KeymasterBlob clientId, KeymasterBlob appId,
Chad Brubaker5bbf0482015-09-09 14:53:52 -0700583 int uid, KeyCharacteristics outCharacteristics) {
Chad Brubakere6a461342015-02-10 21:33:23 -0800584 try {
Dmitry Dementyevefc43112017-10-27 23:10:28 -0700585 clientId = clientId != null ? clientId : new KeymasterBlob(new byte[0]);
586 appId = appId != null ? appId : new KeymasterBlob(new byte[0]);
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700587 KeyCharacteristicsPromise promise = new KeyCharacteristicsPromise();
588 int error = mBinder.getKeyCharacteristics(promise, alias, clientId, appId, uid);
589 if (error != NO_ERROR) return error;
590
591 KeyCharacteristicsCallbackResult result = promise.getFuture().get();
592 error = result.getKeystoreResponse().getErrorCode();
593 if (error != NO_ERROR) return error;
594
595 KeyCharacteristics characteristics = result.getKeyCharacteristics();
596 if (characteristics == null) return SYSTEM_ERROR;
597 outCharacteristics.shallowCopyFrom(characteristics);
598 return NO_ERROR;
Chad Brubakere6a461342015-02-10 21:33:23 -0800599 } catch (RemoteException e) {
600 Log.w(TAG, "Cannot connect to keystore", e);
601 return SYSTEM_ERROR;
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700602 } catch (ExecutionException | InterruptedException e) {
603 Log.e(TAG, "GetKeyCharacteristics completed with exception", e);
604 return SYSTEM_ERROR;
Chad Brubakere6a461342015-02-10 21:33:23 -0800605 }
606 }
607
Chad Brubaker5bbf0482015-09-09 14:53:52 -0700608 public int getKeyCharacteristics(String alias, KeymasterBlob clientId, KeymasterBlob appId,
609 KeyCharacteristics outCharacteristics) {
610 return getKeyCharacteristics(alias, clientId, appId, UID_SELF, outCharacteristics);
611 }
612
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700613 private int importKeyInternal(String alias, KeymasterArguments args, int format, byte[] keyData,
614 int uid, int flags, KeyCharacteristics outCharacteristics)
615 throws RemoteException, ExecutionException, InterruptedException {
616 KeyCharacteristicsPromise promise = new KeyCharacteristicsPromise();
617 int error = mBinder.importKey(promise, alias, args, format, keyData, uid, flags);
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;
628 }
629
Chad Brubakere6a461342015-02-10 21:33:23 -0800630 public int importKey(String alias, KeymasterArguments args, int format, byte[] keyData,
631 int uid, int flags, KeyCharacteristics outCharacteristics) {
632 try {
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700633 int error = importKeyInternal(alias, args, format, keyData, uid, flags,
Chad Brubakere6a461342015-02-10 21:33:23 -0800634 outCharacteristics);
Janis Danisevskisd2575382018-10-08 07:56:58 -0700635 if (error == KEY_ALREADY_EXISTS) {
636 mBinder.del(alias, uid);
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700637 error = importKeyInternal(alias, args, format, keyData, uid, flags,
Janis Danisevskisd2575382018-10-08 07:56:58 -0700638 outCharacteristics);
639 }
640 return error;
Chad Brubakere6a461342015-02-10 21:33:23 -0800641 } catch (RemoteException e) {
642 Log.w(TAG, "Cannot connect to keystore", e);
643 return SYSTEM_ERROR;
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700644 } catch (ExecutionException | InterruptedException e) {
645 Log.e(TAG, "ImportKey completed with exception", e);
646 return SYSTEM_ERROR;
Chad Brubakere6a461342015-02-10 21:33:23 -0800647 }
648 }
649
650 public int importKey(String alias, KeymasterArguments args, int format, byte[] keyData,
651 int flags, KeyCharacteristics outCharacteristics) {
652 return importKey(alias, args, format, keyData, UID_SELF, flags, outCharacteristics);
653 }
654
Janis Danisevskis1864c952018-08-09 11:14:49 -0700655 private String getAlgorithmFromPKCS8(byte[] keyData) {
656 try {
657 final ASN1InputStream bIn = new ASN1InputStream(new ByteArrayInputStream(keyData));
658 final PrivateKeyInfo pki = PrivateKeyInfo.getInstance(bIn.readObject());
659 final String algOid = pki.getPrivateKeyAlgorithm().getAlgorithm().getId();
660 return new AlgorithmId(new ObjectIdentifier(algOid)).getName();
661 } catch (IOException e) {
662 Log.e(TAG, "getAlgorithmFromPKCS8 Failed to parse key data");
663 Log.e(TAG, Log.getStackTraceString(e));
664 return null;
665 }
666 }
667
668 private KeymasterArguments makeLegacyArguments(String algorithm) {
669 KeymasterArguments args = new KeymasterArguments();
670 args.addEnum(KeymasterDefs.KM_TAG_ALGORITHM,
671 KeyProperties.KeyAlgorithm.toKeymasterAsymmetricKeyAlgorithm(algorithm));
672 args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_SIGN);
673 args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_VERIFY);
674 args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_ENCRYPT);
675 args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_DECRYPT);
676 args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_NONE);
677 if (algorithm.equalsIgnoreCase(KeyProperties.KEY_ALGORITHM_RSA)) {
678 args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_RSA_OAEP);
679 args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_ENCRYPT);
680 args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_SIGN);
681 args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_RSA_PSS);
682 }
683 args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_NONE);
684 args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_MD5);
685 args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA1);
686 args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA_2_224);
687 args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA_2_256);
688 args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA_2_384);
689 args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA_2_512);
690 args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED);
691 args.addUnsignedLong(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME,
692 KeymasterArguments.UINT64_MAX_VALUE);
693 args.addUnsignedLong(KeymasterDefs.KM_TAG_USAGE_EXPIRE_DATETIME,
694 KeymasterArguments.UINT64_MAX_VALUE);
695 args.addUnsignedLong(KeymasterDefs.KM_TAG_ACTIVE_DATETIME, BigInteger.ZERO);
696 return args;
697 }
698
699 public boolean importKey(String alias, byte[] keyData, int uid, int flags) {
700 String algorithm = getAlgorithmFromPKCS8(keyData);
701 if (algorithm == null) return false;
702 KeymasterArguments args = makeLegacyArguments(algorithm);
703 KeyCharacteristics out = new KeyCharacteristics();
704 int result = importKey(alias, args, KeymasterDefs.KM_KEY_FORMAT_PKCS8, keyData, uid,
705 flags, out);
706 if (result != NO_ERROR) {
707 Log.e(TAG, Log.getStackTraceString(
708 new KeyStoreException(result, "legacy key import failed")));
709 return false;
710 }
711 return true;
712 }
713
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700714 private int importWrappedKeyInternal(String wrappedKeyAlias, byte[] wrappedKey,
715 String wrappingKeyAlias,
716 byte[] maskingKey, KeymasterArguments args, long rootSid, long fingerprintSid,
717 KeyCharacteristics outCharacteristics)
718 throws RemoteException, ExecutionException, InterruptedException {
719 KeyCharacteristicsPromise promise = new KeyCharacteristicsPromise();
720 int error = mBinder.importWrappedKey(promise, wrappedKeyAlias, wrappedKey, wrappingKeyAlias,
721 maskingKey, args, rootSid, fingerprintSid);
722 if (error != NO_ERROR) return error;
723
724 KeyCharacteristicsCallbackResult result = promise.getFuture().get();
725 error = result.getKeystoreResponse().getErrorCode();
726 if (error != NO_ERROR) return error;
727
728 KeyCharacteristics characteristics = result.getKeyCharacteristics();
729 if (characteristics == null) return SYSTEM_ERROR;
730 outCharacteristics.shallowCopyFrom(characteristics);
731 return NO_ERROR;
732 }
733
Frank Salim21d9c1d2017-12-19 22:38:09 -0800734 public int importWrappedKey(String wrappedKeyAlias, byte[] wrappedKey,
735 String wrappingKeyAlias,
736 byte[] maskingKey, KeymasterArguments args, long rootSid, long fingerprintSid, int uid,
737 KeyCharacteristics outCharacteristics) {
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700738 // TODO b/119217337 uid parameter gets silently ignored.
Frank Salim21d9c1d2017-12-19 22:38:09 -0800739 try {
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700740 int error = importWrappedKeyInternal(wrappedKeyAlias, wrappedKey, wrappingKeyAlias,
Frank Salim21d9c1d2017-12-19 22:38:09 -0800741 maskingKey, args, rootSid, fingerprintSid, outCharacteristics);
Janis Danisevskisd2575382018-10-08 07:56:58 -0700742 if (error == KEY_ALREADY_EXISTS) {
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700743 mBinder.del(wrappedKeyAlias, UID_SELF);
744 error = importWrappedKeyInternal(wrappedKeyAlias, wrappedKey, wrappingKeyAlias,
Janis Danisevskisd2575382018-10-08 07:56:58 -0700745 maskingKey, args, rootSid, fingerprintSid, outCharacteristics);
746 }
747 return error;
Frank Salim21d9c1d2017-12-19 22:38:09 -0800748 } catch (RemoteException e) {
749 Log.w(TAG, "Cannot connect to keystore", e);
750 return SYSTEM_ERROR;
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700751 } catch (ExecutionException | InterruptedException e) {
752 Log.e(TAG, "ImportWrappedKey completed with exception", e);
753 return SYSTEM_ERROR;
Frank Salim21d9c1d2017-12-19 22:38:09 -0800754 }
755 }
756
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700757 private class ExportKeyPromise
758 extends android.security.keystore.IKeystoreExportKeyCallback.Stub {
759 final private CompletableFuture<ExportResult> future = new CompletableFuture<ExportResult>();
760 @Override
761 public void onFinished(ExportResult exportKeyResult) throws android.os.RemoteException {
762 future.complete(exportKeyResult);
763 }
764 public final CompletableFuture<ExportResult> getFuture() {
765 return future;
766 }
767 };
768
Chad Brubaker5e73c0e2015-03-21 22:46:43 -0700769 public ExportResult exportKey(String alias, int format, KeymasterBlob clientId,
Chad Brubaker5bbf0482015-09-09 14:53:52 -0700770 KeymasterBlob appId, int uid) {
Chad Brubakere6a461342015-02-10 21:33:23 -0800771 try {
Dmitry Dementyevefc43112017-10-27 23:10:28 -0700772 clientId = clientId != null ? clientId : new KeymasterBlob(new byte[0]);
773 appId = appId != null ? appId : new KeymasterBlob(new byte[0]);
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700774 ExportKeyPromise promise = new ExportKeyPromise();
775 int error = mBinder.exportKey(promise, alias, format, clientId, appId, uid);
776 if (error == NO_ERROR) {
777 return promise.getFuture().get();
778 } else {
779 return new ExportResult(error);
780 }
Chad Brubaker5bbf0482015-09-09 14:53:52 -0700781 } catch (RemoteException e) {
782 Log.w(TAG, "Cannot connect to keystore", e);
783 return null;
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700784 } catch (ExecutionException | InterruptedException e) {
785 Log.e(TAG, "ExportKey completed with exception", e);
786 return null;
Chad Brubaker5bbf0482015-09-09 14:53:52 -0700787 }
788 }
789 public ExportResult exportKey(String alias, int format, KeymasterBlob clientId,
790 KeymasterBlob appId) {
791 return exportKey(alias, format, clientId, appId, UID_SELF);
792 }
793
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700794 private class OperationPromise
795 extends android.security.keystore.IKeystoreOperationResultCallback.Stub {
796 final private CompletableFuture<OperationResult> future = new CompletableFuture<OperationResult>();
797 @Override
798 public void onFinished(OperationResult operationResult) throws android.os.RemoteException {
799 future.complete(operationResult);
800 }
801 public final CompletableFuture<OperationResult> getFuture() {
802 return future;
803 }
804 };
805
Chad Brubaker5bbf0482015-09-09 14:53:52 -0700806 public OperationResult begin(String alias, int purpose, boolean pruneable,
807 KeymasterArguments args, byte[] entropy, int uid) {
808 try {
Dmitry Dementyevefc43112017-10-27 23:10:28 -0700809 args = args != null ? args : new KeymasterArguments();
810 entropy = entropy != null ? entropy : new byte[0];
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700811 OperationPromise promise = new OperationPromise();
812 int errorCode = mBinder.begin(promise, getToken(), alias, purpose, pruneable, args,
813 entropy, uid);
814 if (errorCode == NO_ERROR) {
815 return promise.getFuture().get();
816 } else {
817 return new OperationResult(errorCode);
818 }
Chad Brubakere6a461342015-02-10 21:33:23 -0800819 } catch (RemoteException e) {
820 Log.w(TAG, "Cannot connect to keystore", e);
821 return null;
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700822 } catch (ExecutionException | InterruptedException e) {
823 Log.e(TAG, "Begin completed with exception", e);
824 return null;
Chad Brubakere6a461342015-02-10 21:33:23 -0800825 }
826 }
827
828 public OperationResult begin(String alias, int purpose, boolean pruneable,
Chad Brubaker966486e2015-06-01 12:57:06 -0700829 KeymasterArguments args, byte[] entropy) {
Dmitry Dementyevefc43112017-10-27 23:10:28 -0700830 entropy = entropy != null ? entropy : new byte[0];
831 args = args != null ? args : new KeymasterArguments();
Chad Brubaker5bbf0482015-09-09 14:53:52 -0700832 return begin(alias, purpose, pruneable, args, entropy, UID_SELF);
Chad Brubakere6a461342015-02-10 21:33:23 -0800833 }
834
835 public OperationResult update(IBinder token, KeymasterArguments arguments, byte[] input) {
836 try {
Dmitry Dementyevefc43112017-10-27 23:10:28 -0700837 arguments = arguments != null ? arguments : new KeymasterArguments();
838 input = input != null ? input : new byte[0];
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700839 OperationPromise promise = new OperationPromise();
840 int errorCode = mBinder.update(promise, token, arguments, input);
841 if (errorCode == NO_ERROR) {
842 return promise.getFuture().get();
843 } else {
844 return new OperationResult(errorCode);
845 }
Chad Brubakere6a461342015-02-10 21:33:23 -0800846 } catch (RemoteException e) {
847 Log.w(TAG, "Cannot connect to keystore", e);
848 return null;
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700849 } catch (ExecutionException | InterruptedException e) {
850 Log.e(TAG, "Update completed with exception", e);
851 return null;
Chad Brubakere6a461342015-02-10 21:33:23 -0800852 }
853 }
854
Chad Brubaker8a077012015-05-29 12:32:51 -0700855 public OperationResult finish(IBinder token, KeymasterArguments arguments, byte[] signature,
856 byte[] entropy) {
Chad Brubakere6a461342015-02-10 21:33:23 -0800857 try {
Dmitry Dementyevefc43112017-10-27 23:10:28 -0700858 arguments = arguments != null ? arguments : new KeymasterArguments();
859 entropy = entropy != null ? entropy : new byte[0];
860 signature = signature != null ? signature : new byte[0];
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700861 OperationPromise promise = new OperationPromise();
862 int errorCode = mBinder.finish(promise, token, arguments, signature, entropy);
863 if (errorCode == NO_ERROR) {
864 return promise.getFuture().get();
865 } else {
866 return new OperationResult(errorCode);
867 }
Chad Brubakere6a461342015-02-10 21:33:23 -0800868 } catch (RemoteException e) {
869 Log.w(TAG, "Cannot connect to keystore", e);
870 return null;
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700871 } catch (ExecutionException | InterruptedException e) {
872 Log.e(TAG, "Finish completed with exception", e);
873 return null;
Chad Brubakere6a461342015-02-10 21:33:23 -0800874 }
875 }
876
Chad Brubaker8a077012015-05-29 12:32:51 -0700877 public OperationResult finish(IBinder token, KeymasterArguments arguments, byte[] signature) {
878 return finish(token, arguments, signature, null);
879 }
880
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700881 private class KeystoreResultPromise
882 extends android.security.keystore.IKeystoreResponseCallback.Stub {
883 final private CompletableFuture<KeystoreResponse> future = new CompletableFuture<KeystoreResponse>();
884 @Override
885 public void onFinished(KeystoreResponse keystoreResponse) throws android.os.RemoteException {
886 future.complete(keystoreResponse);
887 }
888 public final CompletableFuture<KeystoreResponse> getFuture() {
889 return future;
890 }
891 };
892
Chad Brubakere6a461342015-02-10 21:33:23 -0800893 public int abort(IBinder token) {
894 try {
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700895 KeystoreResultPromise promise = new KeystoreResultPromise();
896 int errorCode = mBinder.abort(promise, token);
897 if (errorCode == NO_ERROR) {
898 return promise.getFuture().get().getErrorCode();
899 } else {
900 return errorCode;
901 }
Chad Brubakere6a461342015-02-10 21:33:23 -0800902 } catch (RemoteException e) {
903 Log.w(TAG, "Cannot connect to keystore", e);
904 return SYSTEM_ERROR;
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700905 } catch (ExecutionException | InterruptedException e) {
906 Log.e(TAG, "Abort completed with exception", e);
907 return SYSTEM_ERROR;
Chad Brubakere6a461342015-02-10 21:33:23 -0800908 }
909 }
Chad Brubaker5654b362015-03-17 16:59:52 -0700910
911 /**
Chad Brubaker5654b362015-03-17 16:59:52 -0700912 * Add an authentication record to the keystore authorization table.
913 *
914 * @param authToken The packed bytes of a hw_auth_token_t to be provided to keymaster.
915 * @return {@code KeyStore.NO_ERROR} on success, otherwise an error value corresponding to
916 * a {@code KeymasterDefs.KM_ERROR_} value or {@code KeyStore} ResponseCode.
917 */
Brian Youngda82e2c2018-02-22 23:36:34 +0000918 public int addAuthToken(byte[] authToken) {
Chad Brubaker5654b362015-03-17 16:59:52 -0700919 try {
Brian Youngda82e2c2018-02-22 23:36:34 +0000920 return mBinder.addAuthToken(authToken);
Chad Brubaker5654b362015-03-17 16:59:52 -0700921 } catch (RemoteException e) {
922 Log.w(TAG, "Cannot connect to keystore", e);
923 return SYSTEM_ERROR;
924 }
925 }
Alex Klyubinb4834ae2015-04-02 15:53:46 -0700926
Alex Klyubinad9ba102015-04-21 15:17:24 -0700927 /**
Chad Brubakera91a8502015-05-07 10:02:22 -0700928 * Notify keystore that a user's password has changed.
929 *
930 * @param userId the user whose password changed.
931 * @param newPassword the new password or "" if the password was removed.
932 */
933 public boolean onUserPasswordChanged(int userId, String newPassword) {
934 // Parcel.cpp doesn't support deserializing null strings and treats them as "". Make that
935 // explicit here.
936 if (newPassword == null) {
937 newPassword = "";
938 }
939 try {
940 return mBinder.onUserPasswordChanged(userId, newPassword) == NO_ERROR;
941 } catch (RemoteException e) {
942 Log.w(TAG, "Cannot connect to keystore", e);
943 return false;
944 }
945 }
946
Chad Brubaker83ce0952015-05-12 13:00:02 -0700947 /**
948 * Notify keystore that a user was added.
949 *
950 * @param userId the new user.
951 * @param parentId the parent of the new user, or -1 if the user has no parent. If parentId is
952 * specified then the new user's keystore will be intialized with the same secure lockscreen
953 * password as the parent.
954 */
955 public void onUserAdded(int userId, int parentId) {
956 try {
957 mBinder.onUserAdded(userId, parentId);
958 } catch (RemoteException e) {
959 Log.w(TAG, "Cannot connect to keystore", e);
960 }
961 }
962
963 /**
964 * Notify keystore that a user was added.
965 *
966 * @param userId the new user.
967 */
968 public void onUserAdded(int userId) {
969 onUserAdded(userId, -1);
970 }
971
972 /**
973 * Notify keystore that a user was removed.
974 *
975 * @param userId the removed user.
976 */
977 public void onUserRemoved(int userId) {
978 try {
979 mBinder.onUserRemoved(userId);
980 } catch (RemoteException e) {
981 Log.w(TAG, "Cannot connect to keystore", e);
982 }
983 }
984
Chad Brubakera91a8502015-05-07 10:02:22 -0700985 public boolean onUserPasswordChanged(String newPassword) {
986 return onUserPasswordChanged(UserHandle.getUserId(Process.myUid()), newPassword);
987 }
988
Janis Danisevskisb0358e72018-11-02 10:34:07 -0700989 private class KeyAttestationCallbackResult {
990 private KeystoreResponse keystoreResponse;
991 private KeymasterCertificateChain certificateChain;
992
993 public KeyAttestationCallbackResult(KeystoreResponse keystoreResponse,
994 KeymasterCertificateChain certificateChain) {
995 this.keystoreResponse = keystoreResponse;
996 this.certificateChain = certificateChain;
997 }
998
999 public KeystoreResponse getKeystoreResponse() {
1000 return keystoreResponse;
1001 }
1002
1003 public void setKeystoreResponse(KeystoreResponse keystoreResponse) {
1004 this.keystoreResponse = keystoreResponse;
1005 }
1006
1007 public KeymasterCertificateChain getCertificateChain() {
1008 return certificateChain;
1009 }
1010
1011 public void setCertificateChain(KeymasterCertificateChain certificateChain) {
1012 this.certificateChain = certificateChain;
1013 }
1014 }
1015
1016 private class CertificateChainPromise
1017 extends android.security.keystore.IKeystoreCertificateChainCallback.Stub {
1018 final private CompletableFuture<KeyAttestationCallbackResult> future = new CompletableFuture<KeyAttestationCallbackResult>();
1019 @Override
1020 public void onFinished(KeystoreResponse keystoreResponse,
1021 KeymasterCertificateChain certificateChain) throws android.os.RemoteException {
1022 future.complete(new KeyAttestationCallbackResult(keystoreResponse, certificateChain));
1023 }
1024 public final CompletableFuture<KeyAttestationCallbackResult> getFuture() {
1025 return future;
1026 }
1027 };
1028
1029
Shawn Willden8d8c7472016-02-02 08:27:39 -07001030 public int attestKey(
1031 String alias, KeymasterArguments params, KeymasterCertificateChain outChain) {
1032 try {
Dmitry Dementyevefc43112017-10-27 23:10:28 -07001033 if (params == null) {
1034 params = new KeymasterArguments();
1035 }
1036 if (outChain == null) {
1037 outChain = new KeymasterCertificateChain();
1038 }
Janis Danisevskisb0358e72018-11-02 10:34:07 -07001039 CertificateChainPromise promise = new CertificateChainPromise();
1040 int error = mBinder.attestKey(promise, alias, params);
1041 if (error != NO_ERROR) return error;
1042 KeyAttestationCallbackResult result = promise.getFuture().get();
1043 error = result.getKeystoreResponse().getErrorCode();
1044 if (error == NO_ERROR) {
1045 outChain.shallowCopyFrom(result.getCertificateChain());
1046 }
1047 return error;
Shawn Willden8d8c7472016-02-02 08:27:39 -07001048 } catch (RemoteException e) {
1049 Log.w(TAG, "Cannot connect to keystore", e);
1050 return SYSTEM_ERROR;
Janis Danisevskisb0358e72018-11-02 10:34:07 -07001051 } catch (ExecutionException | InterruptedException e) {
1052 Log.e(TAG, "AttestKey completed with exception", e);
1053 return SYSTEM_ERROR;
Shawn Willden8d8c7472016-02-02 08:27:39 -07001054 }
1055 }
1056
Bartosz Fabianowski237f4b362017-04-24 13:57:46 +02001057 public int attestDeviceIds(KeymasterArguments params, KeymasterCertificateChain outChain) {
1058 try {
Dmitry Dementyevefc43112017-10-27 23:10:28 -07001059 if (params == null) {
1060 params = new KeymasterArguments();
1061 }
1062 if (outChain == null) {
1063 outChain = new KeymasterCertificateChain();
1064 }
Janis Danisevskisb0358e72018-11-02 10:34:07 -07001065 CertificateChainPromise promise = new CertificateChainPromise();
1066 int error = mBinder.attestDeviceIds(promise, params);
1067 if (error != NO_ERROR) return error;
1068 KeyAttestationCallbackResult result = promise.getFuture().get();
1069 error = result.getKeystoreResponse().getErrorCode();
1070 if (error == NO_ERROR) {
1071 outChain.shallowCopyFrom(result.getCertificateChain());
1072 }
1073 return error;
Bartosz Fabianowski237f4b362017-04-24 13:57:46 +02001074 } catch (RemoteException e) {
1075 Log.w(TAG, "Cannot connect to keystore", e);
1076 return SYSTEM_ERROR;
Janis Danisevskisb0358e72018-11-02 10:34:07 -07001077 } catch (ExecutionException | InterruptedException e) {
1078 Log.e(TAG, "AttestDevicdeIds completed with exception", e);
1079 return SYSTEM_ERROR;
Bartosz Fabianowski237f4b362017-04-24 13:57:46 +02001080 }
1081 }
1082
Tucker Sylvestrob32aae22016-06-23 17:23:33 -04001083 /**
1084 * Notify keystore that the device went off-body.
1085 */
1086 public void onDeviceOffBody() {
1087 try {
1088 mBinder.onDeviceOffBody();
1089 } catch (RemoteException e) {
1090 Log.w(TAG, "Cannot connect to keystore", e);
1091 }
1092 }
Shawn Willden8d8c7472016-02-02 08:27:39 -07001093
Janis Danisevskis7dacad82018-01-24 15:12:11 -08001094 // Keep in sync with confirmationui/1.0/types.hal.
1095 public static final int CONFIRMATIONUI_OK = 0;
1096 public static final int CONFIRMATIONUI_CANCELED = 1;
1097 public static final int CONFIRMATIONUI_ABORTED = 2;
1098 public static final int CONFIRMATIONUI_OPERATION_PENDING = 3;
1099 public static final int CONFIRMATIONUI_IGNORED = 4;
1100 public static final int CONFIRMATIONUI_SYSTEM_ERROR = 5;
1101 public static final int CONFIRMATIONUI_UNIMPLEMENTED = 6;
1102 public static final int CONFIRMATIONUI_UNEXPECTED = 7;
1103 public static final int CONFIRMATIONUI_UIERROR = 0x10000;
1104 public static final int CONFIRMATIONUI_UIERROR_MISSING_GLYPH = 0x10001;
1105 public static final int CONFIRMATIONUI_UIERROR_MESSAGE_TOO_LONG = 0x10002;
1106 public static final int CONFIRMATIONUI_UIERROR_MALFORMED_UTF8_ENCODING = 0x10003;
1107
1108 /**
1109 * Requests keystore call into the confirmationui HAL to display a prompt.
1110 *
1111 * @param listener the binder to use for callbacks.
1112 * @param promptText the prompt to display.
1113 * @param extraData extra data / nonce from application.
1114 * @param locale the locale as a BCP 47 langauge tag.
1115 * @param uiOptionsAsFlags the UI options to use, as flags.
1116 * @return one of the {@code CONFIRMATIONUI_*} constants, for
1117 * example {@code KeyStore.CONFIRMATIONUI_OK}.
1118 */
1119 public int presentConfirmationPrompt(IBinder listener, String promptText, byte[] extraData,
1120 String locale, int uiOptionsAsFlags) {
1121 try {
1122 return mBinder.presentConfirmationPrompt(listener, promptText, extraData, locale,
1123 uiOptionsAsFlags);
1124 } catch (RemoteException e) {
1125 Log.w(TAG, "Cannot connect to keystore", e);
1126 return CONFIRMATIONUI_SYSTEM_ERROR;
1127 }
1128 }
1129
1130 /**
1131 * Requests keystore call into the confirmationui HAL to cancel displaying a prompt.
1132 *
1133 * @param listener the binder passed to the {@link #presentConfirmationPrompt} method.
1134 * @return one of the {@code CONFIRMATIONUI_*} constants, for
1135 * example {@code KeyStore.CONFIRMATIONUI_OK}.
1136 */
1137 public int cancelConfirmationPrompt(IBinder listener) {
1138 try {
1139 return mBinder.cancelConfirmationPrompt(listener);
1140 } catch (RemoteException e) {
1141 Log.w(TAG, "Cannot connect to keystore", e);
1142 return CONFIRMATIONUI_SYSTEM_ERROR;
1143 }
1144 }
1145
Chad Brubakera91a8502015-05-07 10:02:22 -07001146 /**
David Zeuthenbbb7f652018-02-26 11:04:18 -05001147 * Requests keystore to check if the confirmationui HAL is available.
1148 *
1149 * @return whether the confirmationUI HAL is available.
1150 */
1151 public boolean isConfirmationPromptSupported() {
1152 try {
1153 return mBinder.isConfirmationPromptSupported();
1154 } catch (RemoteException e) {
1155 Log.w(TAG, "Cannot connect to keystore", e);
1156 return false;
1157 }
1158 }
1159
1160 /**
Alex Klyubinad9ba102015-04-21 15:17:24 -07001161 * Returns a {@link KeyStoreException} corresponding to the provided keystore/keymaster error
1162 * code.
1163 */
Mathew Inwood4dbdcf42018-08-16 18:49:37 +01001164 @UnsupportedAppUsage
Alex Klyubindcdaf872015-05-13 15:57:09 -07001165 public static KeyStoreException getKeyStoreException(int errorCode) {
Alex Klyubinb4834ae2015-04-02 15:53:46 -07001166 if (errorCode > 0) {
1167 // KeyStore layer error
1168 switch (errorCode) {
1169 case NO_ERROR:
1170 return new KeyStoreException(errorCode, "OK");
1171 case LOCKED:
Alex Klyubin54183932015-05-08 15:25:48 -07001172 return new KeyStoreException(errorCode, "User authentication required");
Alex Klyubinb4834ae2015-04-02 15:53:46 -07001173 case UNINITIALIZED:
1174 return new KeyStoreException(errorCode, "Keystore not initialized");
1175 case SYSTEM_ERROR:
1176 return new KeyStoreException(errorCode, "System error");
1177 case PERMISSION_DENIED:
1178 return new KeyStoreException(errorCode, "Permission denied");
1179 case KEY_NOT_FOUND:
1180 return new KeyStoreException(errorCode, "Key not found");
1181 case VALUE_CORRUPTED:
1182 return new KeyStoreException(errorCode, "Key blob corrupted");
Alex Klyubin058de022015-04-29 17:32:00 -07001183 case OP_AUTH_NEEDED:
1184 return new KeyStoreException(errorCode, "Operation requires authorization");
Alex Klyubinb4834ae2015-04-02 15:53:46 -07001185 default:
1186 return new KeyStoreException(errorCode, String.valueOf(errorCode));
1187 }
1188 } else {
1189 // Keymaster layer error
1190 switch (errorCode) {
1191 case KeymasterDefs.KM_ERROR_INVALID_AUTHORIZATION_TIMEOUT:
1192 // The name of this parameter significantly differs between Keymaster and
1193 // framework APIs. Use the framework wording to make life easier for developers.
1194 return new KeyStoreException(errorCode,
1195 "Invalid user authentication validity duration");
1196 default:
1197 return new KeyStoreException(errorCode,
1198 KeymasterDefs.getErrorMessage(errorCode));
1199 }
1200 }
1201 }
1202
Alex Klyubinad9ba102015-04-21 15:17:24 -07001203 /**
1204 * Returns an {@link InvalidKeyException} corresponding to the provided
1205 * {@link KeyStoreException}.
1206 */
Alex Klyubindcdaf872015-05-13 15:57:09 -07001207 public InvalidKeyException getInvalidKeyException(
Alex Klyubin3876b1b2015-09-09 14:55:03 -07001208 String keystoreKeyAlias, int uid, KeyStoreException e) {
Alex Klyubinb4834ae2015-04-02 15:53:46 -07001209 switch (e.getErrorCode()) {
Brian Youngda82e2c2018-02-22 23:36:34 +00001210 case LOCKED:
Alex Klyubin54183932015-05-08 15:25:48 -07001211 return new UserNotAuthenticatedException();
Brian Youngda82e2c2018-02-22 23:36:34 +00001212 case KeymasterDefs.KM_ERROR_KEY_EXPIRED:
Alex Klyubinb4834ae2015-04-02 15:53:46 -07001213 return new KeyExpiredException();
Brian Youngda82e2c2018-02-22 23:36:34 +00001214 case KeymasterDefs.KM_ERROR_KEY_NOT_YET_VALID:
Alex Klyubinb4834ae2015-04-02 15:53:46 -07001215 return new KeyNotYetValidException();
Brian Youngda82e2c2018-02-22 23:36:34 +00001216 case KeymasterDefs.KM_ERROR_KEY_USER_NOT_AUTHENTICATED:
1217 case OP_AUTH_NEEDED:
Alex Klyubin708fc9402015-04-28 18:58:47 -07001218 {
1219 // We now need to determine whether the key/operation can become usable if user
1220 // authentication is performed, or whether it can never become usable again.
1221 // User authentication requirements are contained in the key's characteristics. We
1222 // need to check whether these requirements can be be satisfied by asking the user
1223 // to authenticate.
1224 KeyCharacteristics keyCharacteristics = new KeyCharacteristics();
1225 int getKeyCharacteristicsErrorCode =
Alex Klyubin3876b1b2015-09-09 14:55:03 -07001226 getKeyCharacteristics(keystoreKeyAlias, null, null, uid,
1227 keyCharacteristics);
Alex Klyubin708fc9402015-04-28 18:58:47 -07001228 if (getKeyCharacteristicsErrorCode != NO_ERROR) {
1229 return new InvalidKeyException(
1230 "Failed to obtained key characteristics",
1231 getKeyStoreException(getKeyCharacteristicsErrorCode));
1232 }
Alex Klyubinae6cb7a2015-06-22 18:09:35 -07001233 List<BigInteger> keySids =
1234 keyCharacteristics.getUnsignedLongs(KeymasterDefs.KM_TAG_USER_SECURE_ID);
Alex Klyubin708fc9402015-04-28 18:58:47 -07001235 if (keySids.isEmpty()) {
1236 // Key is not bound to any SIDs -- no amount of authentication will help here.
1237 return new KeyPermanentlyInvalidatedException();
1238 }
1239 long rootSid = GateKeeper.getSecureUserId();
Alex Klyubinae6cb7a2015-06-22 18:09:35 -07001240 if ((rootSid != 0) && (keySids.contains(KeymasterArguments.toUint64(rootSid)))) {
Alex Klyubin708fc9402015-04-28 18:58:47 -07001241 // One of the key's SIDs is the current root SID -- user can be authenticated
1242 // against that SID.
1243 return new UserNotAuthenticatedException();
1244 }
1245
1246 long fingerprintOnlySid = getFingerprintOnlySid();
1247 if ((fingerprintOnlySid != 0)
Alex Klyubinae6cb7a2015-06-22 18:09:35 -07001248 && (keySids.contains(KeymasterArguments.toUint64(fingerprintOnlySid)))) {
Alex Klyubin708fc9402015-04-28 18:58:47 -07001249 // One of the key's SIDs is the current fingerprint SID -- user can be
1250 // authenticated against that SID.
1251 return new UserNotAuthenticatedException();
1252 }
1253
1254 // None of the key's SIDs can ever be authenticated
1255 return new KeyPermanentlyInvalidatedException();
1256 }
Brian Youngda82e2c2018-02-22 23:36:34 +00001257 case UNINITIALIZED:
Janis Danisevskisd07d3382017-09-01 14:45:16 -07001258 return new KeyPermanentlyInvalidatedException();
Alex Klyubinb4834ae2015-04-02 15:53:46 -07001259 default:
Alex Klyubinad9ba102015-04-21 15:17:24 -07001260 return new InvalidKeyException("Keystore operation failed", e);
Alex Klyubinb4834ae2015-04-02 15:53:46 -07001261 }
1262 }
1263
Alex Klyubin2d7a85c2015-04-30 11:43:53 -07001264 private long getFingerprintOnlySid() {
Kevin Chyn55966422017-10-23 16:08:47 -07001265 final PackageManager packageManager = mContext.getPackageManager();
1266 if (!packageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) {
1267 return 0;
1268 }
Alex Klyubina99b8b52015-06-11 13:27:34 -07001269 FingerprintManager fingerprintManager = mContext.getSystemService(FingerprintManager.class);
Alex Klyubin2d7a85c2015-04-30 11:43:53 -07001270 if (fingerprintManager == null) {
Alex Klyubin708fc9402015-04-28 18:58:47 -07001271 return 0;
1272 }
1273
Alex Klyubina99b8b52015-06-11 13:27:34 -07001274 // TODO: Restore USE_FINGERPRINT permission check in
1275 // FingerprintManager.getAuthenticatorId once the ID is no longer needed here.
Alex Klyubin2d7a85c2015-04-30 11:43:53 -07001276 return fingerprintManager.getAuthenticatorId();
Svetoslav2dac95d2015-04-30 11:30:33 -07001277 }
1278
Alex Klyubinad9ba102015-04-21 15:17:24 -07001279 /**
1280 * Returns an {@link InvalidKeyException} corresponding to the provided keystore/keymaster error
1281 * code.
1282 */
Alex Klyubin3876b1b2015-09-09 14:55:03 -07001283 public InvalidKeyException getInvalidKeyException(String keystoreKeyAlias, int uid,
1284 int errorCode) {
1285 return getInvalidKeyException(keystoreKeyAlias, uid, getKeyStoreException(errorCode));
Alex Klyubinb4834ae2015-04-02 15:53:46 -07001286 }
Chia-chi Yeh44039172009-09-21 11:53:59 +08001287}