1 /*
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 
17 package android.security;
18 
19 import android.app.ActivityThread;
20 import android.app.Application;
21 import android.app.KeyguardManager;
22 import android.compat.annotation.UnsupportedAppUsage;
23 import android.content.Context;
24 import android.hardware.biometrics.BiometricManager;
25 import android.os.Binder;
26 import android.os.Build;
27 import android.os.IBinder;
28 import android.os.Process;
29 import android.os.RemoteException;
30 import android.os.ServiceManager;
31 import android.os.UserHandle;
32 import android.security.keymaster.ExportResult;
33 import android.security.keymaster.KeyCharacteristics;
34 import android.security.keymaster.KeymasterArguments;
35 import android.security.keymaster.KeymasterBlob;
36 import android.security.keymaster.KeymasterCertificateChain;
37 import android.security.keymaster.KeymasterDefs;
38 import android.security.keymaster.OperationResult;
39 import android.security.keystore.IKeystoreService;
40 import android.security.keystore.KeyExpiredException;
41 import android.security.keystore.KeyNotYetValidException;
42 import android.security.keystore.KeyPermanentlyInvalidatedException;
43 import android.security.keystore.KeyProperties;
44 import android.security.keystore.KeystoreResponse;
45 import android.security.keystore.UserNotAuthenticatedException;
46 import android.util.Log;
47 
48 import com.android.org.bouncycastle.asn1.ASN1InputStream;
49 import com.android.org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
50 
51 import java.io.ByteArrayInputStream;
52 import java.io.IOException;
53 import java.math.BigInteger;
54 import java.security.InvalidKeyException;
55 import java.util.ArrayList;
56 import java.util.Date;
57 import java.util.List;
58 import java.util.Locale;
59 import java.util.concurrent.CompletableFuture;
60 import java.util.concurrent.ExecutionException;
61 
62 import sun.security.util.ObjectIdentifier;
63 import sun.security.x509.AlgorithmId;
64 
65 /**
66  * @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.
69  */
70 public class KeyStore {
71     private static final String TAG = "KeyStore";
72 
73     // ResponseCodes - see system/security/keystore/include/keystore/keystore.h
74     @UnsupportedAppUsage
75     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;
85     public static final int KEY_ALREADY_EXISTS = 16;
86     public static final int CANNOT_ATTEST_IDS = -66;
87     public static final int HARDWARE_TYPE_UNAVAILABLE = -68;
88 
89     /**
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 
97     // Used when a user changes their pin, invalidating old auth bound keys.
98     public static final int KEY_PERMANENTLY_INVALIDATED = 17;
99 
100     // Used for UID field to indicate the calling UID.
101     public static final int UID_SELF = -1;
102 
103     // Flags for "put" "import" and "generate"
104     public static final int FLAG_NONE = 0;
105 
106     /**
107      * Indicates that this key (or key pair) must be encrypted at rest. This will protect the key
108      * (or key pair) with the secure lock screen credential (e.g., password, PIN, or pattern).
109      *
110      * <p>Note that this requires that the secure lock screen (e.g., password, PIN, pattern) is set
111      * up, otherwise key (or key pair) generation or import will fail. Moreover, this key (or key
112      * pair) will be deleted when the secure lock screen is disabled or reset (e.g., by the user or
113      * a Device Administrator). Finally, this key (or key pair) cannot be used until the user
114      * unlocks the secure lock screen after boot.
115      *
116      * @see KeyguardManager#isDeviceSecure()
117      */
118     public static final int FLAG_ENCRYPTED = 1;
119 
120     /**
121      * Select Software keymaster device, which as of this writing is the lowest security
122      * level available on an android device. If neither FLAG_STRONGBOX nor FLAG_SOFTWARE is provided
123      * A TEE based keymaster implementation is implied.
124      *
125      * Need to be in sync with KeyStoreFlag in system/security/keystore/include/keystore/keystore.h
126      * For historical reasons this corresponds to the KEYSTORE_FLAG_FALLBACK flag.
127      */
128     public static final int FLAG_SOFTWARE = 1 << 1;
129 
130     /**
131      * A private flag that's only available to system server to indicate that this key is part of
132      * device encryption flow so it receives special treatment from keystore. For example this key
133      * will not be super encrypted, and it will be stored separately under an unique UID instead
134      * of the caller UID i.e. SYSTEM.
135      *
136      * Need to be in sync with KeyStoreFlag in system/security/keystore/include/keystore/keystore.h
137      */
138     public static final int FLAG_CRITICAL_TO_DEVICE_ENCRYPTION = 1 << 3;
139 
140     /**
141      * Select Strongbox keymaster device, which as of this writing the the highest security level
142      * available an android devices. If neither FLAG_STRONGBOX nor FLAG_SOFTWARE is provided
143      * A TEE based keymaster implementation is implied.
144      *
145      * Need to be in sync with KeyStoreFlag in system/security/keystore/include/keystore/keystore.h
146      */
147     public static final int FLAG_STRONGBOX = 1 << 4;
148 
149     // States
150     public enum State {
151         @UnsupportedAppUsage
152         UNLOCKED,
153         @UnsupportedAppUsage
154         LOCKED,
155         UNINITIALIZED
156     };
157 
158     private int mError = NO_ERROR;
159 
160     private final IKeystoreService mBinder;
161     private final Context mContext;
162 
163     private IBinder mToken;
164 
KeyStore(IKeystoreService binder)165     private KeyStore(IKeystoreService binder) {
166         mBinder = binder;
167         mContext = getApplicationContext();
168     }
169 
170     @UnsupportedAppUsage
getApplicationContext()171     public static Context getApplicationContext() {
172         Application application = ActivityThread.currentApplication();
173         if (application == null) {
174             throw new IllegalStateException(
175                     "Failed to obtain application Context from ActivityThread");
176         }
177         return application;
178     }
179 
180     @UnsupportedAppUsage
getInstance()181     public static KeyStore getInstance() {
182         IKeystoreService keystore = IKeystoreService.Stub.asInterface(ServiceManager
183                 .getService("android.security.keystore"));
184         return new KeyStore(keystore);
185     }
186 
getToken()187     private synchronized IBinder getToken() {
188         if (mToken == null) {
189             mToken = new Binder();
190         }
191         return mToken;
192     }
193 
194     @UnsupportedAppUsage
state(int userId)195     public State state(int userId) {
196         final int ret;
197         try {
198             ret = mBinder.getState(userId);
199         } catch (RemoteException e) {
200             Log.w(TAG, "Cannot connect to keystore", e);
201             throw new AssertionError(e);
202         }
203 
204         switch (ret) {
205             case NO_ERROR: return State.UNLOCKED;
206             case LOCKED: return State.LOCKED;
207             case UNINITIALIZED: return State.UNINITIALIZED;
208             default: throw new AssertionError(mError);
209         }
210     }
211 
212     @UnsupportedAppUsage
state()213     public State state() {
214         return state(UserHandle.myUserId());
215     }
216 
isUnlocked()217     public boolean isUnlocked() {
218         return state() == State.UNLOCKED;
219     }
220 
get(String key, int uid)221     public byte[] get(String key, int uid) {
222         return get(key, uid, false);
223     }
224 
225     @UnsupportedAppUsage
get(String key)226     public byte[] get(String key) {
227         return get(key, UID_SELF);
228     }
229 
get(String key, int uid, boolean suppressKeyNotFoundWarning)230     public byte[] get(String key, int uid, boolean suppressKeyNotFoundWarning) {
231         try {
232             key = key != null ? key : "";
233             return mBinder.get(key, uid);
234         } catch (RemoteException e) {
235              Log.w(TAG, "Cannot connect to keystore", e);
236             return null;
237         } catch (android.os.ServiceSpecificException e) {
238             if (!suppressKeyNotFoundWarning || e.errorCode != KEY_NOT_FOUND) {
239                 Log.w(TAG, "KeyStore exception", e);
240             }
241             return null;
242         }
243     }
244 
get(String key, boolean suppressKeyNotFoundWarning)245     public byte[] get(String key, boolean suppressKeyNotFoundWarning) {
246         return get(key, UID_SELF, suppressKeyNotFoundWarning);
247     }
248 
249 
put(String key, byte[] value, int uid, int flags)250     public boolean put(String key, byte[] value, int uid, int flags) {
251         return insert(key, value, uid, flags) == NO_ERROR;
252     }
253 
insert(String key, byte[] value, int uid, int flags)254     public int insert(String key, byte[] value, int uid, int flags) {
255         try {
256             if (value == null) {
257                 value = new byte[0];
258             }
259             int error = mBinder.insert(key, value, uid, flags);
260             if (error == KEY_ALREADY_EXISTS) {
261                 mBinder.del(key, uid);
262                 error = mBinder.insert(key, value, uid, flags);
263             }
264             return error;
265         } catch (RemoteException e) {
266             Log.w(TAG, "Cannot connect to keystore", e);
267             return SYSTEM_ERROR;
268         }
269     }
270 
delete2(String key, int uid)271     int delete2(String key, int uid) {
272         try {
273             return mBinder.del(key, uid);
274         } catch (RemoteException e) {
275             Log.w(TAG, "Cannot connect to keystore", e);
276             return SYSTEM_ERROR;
277         }
278     }
279 
delete(String key, int uid)280     public boolean delete(String key, int uid) {
281         int ret = delete2(key, uid);
282         return ret == NO_ERROR || ret == KEY_NOT_FOUND;
283     }
284 
285     @UnsupportedAppUsage
delete(String key)286     public boolean delete(String key) {
287         return delete(key, UID_SELF);
288     }
289 
contains(String key, int uid)290     public boolean contains(String key, int uid) {
291         try {
292             return mBinder.exist(key, uid) == NO_ERROR;
293         } catch (RemoteException e) {
294             Log.w(TAG, "Cannot connect to keystore", e);
295             return false;
296         }
297     }
298 
contains(String key)299     public boolean contains(String key) {
300         return contains(key, UID_SELF);
301     }
302 
303     /**
304      * List all entries in the keystore for {@code uid} starting with {@code prefix}.
305      */
list(String prefix, int uid)306     public String[] list(String prefix, int uid) {
307         try {
308             return mBinder.list(prefix, uid);
309         } catch (RemoteException e) {
310             Log.w(TAG, "Cannot connect to keystore", e);
311             return null;
312         } catch (android.os.ServiceSpecificException e) {
313             Log.w(TAG, "KeyStore exception", e);
314             return null;
315         }
316     }
317 
318     /**
319      * List uids of all keys that are auth bound to the current user.
320      * Only system is allowed to call this method.
321      */
322     @UnsupportedAppUsage
listUidsOfAuthBoundKeys()323     public int[] listUidsOfAuthBoundKeys() {
324         // uids are returned as a list of strings because list of integers
325         // as an output parameter is not supported by aidl-cpp.
326         List<String> uidsOut = new ArrayList<>();
327         try {
328             int rc = mBinder.listUidsOfAuthBoundKeys(uidsOut);
329             if (rc != NO_ERROR) {
330                 Log.w(TAG, String.format("listUidsOfAuthBoundKeys failed with error code %d", rc));
331                 return null;
332             }
333         } catch (RemoteException e) {
334             Log.w(TAG, "Cannot connect to keystore", e);
335             return null;
336         } catch (android.os.ServiceSpecificException e) {
337             Log.w(TAG, "KeyStore exception", e);
338             return null;
339         }
340         // Turn list of strings into an array of uid integers.
341         return uidsOut.stream().mapToInt(Integer::parseInt).toArray();
342    }
343 
list(String prefix)344     public String[] list(String prefix) {
345         return list(prefix, UID_SELF);
346     }
347 
348     /**
349      * Attempt to lock the keystore for {@code user}.
350      *
351      * @param userId Android user to lock.
352      * @return whether {@code user}'s keystore was locked.
353      */
lock(int userId)354     public boolean lock(int userId) {
355         try {
356             return mBinder.lock(userId) == NO_ERROR;
357         } catch (RemoteException e) {
358             Log.w(TAG, "Cannot connect to keystore", e);
359             return false;
360         }
361     }
362 
lock()363     public boolean lock() {
364         return lock(UserHandle.myUserId());
365     }
366 
367     /**
368      * Attempt to unlock the keystore for {@code user} with the password {@code password}.
369      * This is required before keystore entries created with FLAG_ENCRYPTED can be accessed or
370      * created.
371      *
372      * @param userId Android user ID to operate on
373      * @param password user's keystore password. Should be the most recent value passed to
374      * {@link #onUserPasswordChanged} for the user.
375      *
376      * @return whether the keystore was unlocked.
377      */
unlock(int userId, String password)378     public boolean unlock(int userId, String password) {
379         try {
380             password = password != null ? password : "";
381             mError = mBinder.unlock(userId, password);
382             return mError == NO_ERROR;
383         } catch (RemoteException e) {
384             Log.w(TAG, "Cannot connect to keystore", e);
385             return false;
386         }
387     }
388 
389     @UnsupportedAppUsage
unlock(String password)390     public boolean unlock(String password) {
391         return unlock(UserHandle.getUserId(Process.myUid()), password);
392     }
393 
394     /**
395      * Check if the keystore for {@code userId} is empty.
396      */
isEmpty(int userId)397     public boolean isEmpty(int userId) {
398         try {
399             return mBinder.isEmpty(userId) != 0;
400         } catch (RemoteException e) {
401             Log.w(TAG, "Cannot connect to keystore", e);
402             return false;
403         }
404     }
405 
406     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
isEmpty()407     public boolean isEmpty() {
408         return isEmpty(UserHandle.myUserId());
409     }
410 
grant(String key, int uid)411     public String grant(String key, int uid) {
412         try {
413             String grantAlias =  mBinder.grant(key, uid);
414             if (grantAlias == "") return null;
415             return grantAlias;
416         } catch (RemoteException e) {
417             Log.w(TAG, "Cannot connect to keystore", e);
418             return null;
419         }
420     }
421 
ungrant(String key, int uid)422     public boolean ungrant(String key, int uid) {
423         try {
424             return mBinder.ungrant(key, uid) == NO_ERROR;
425         } catch (RemoteException e) {
426             Log.w(TAG, "Cannot connect to keystore", e);
427             return false;
428         }
429     }
430 
431     /**
432      * Returns the last modification time of the key in milliseconds since the
433      * epoch. Will return -1L if the key could not be found or other error.
434      */
getmtime(String key, int uid)435     public long getmtime(String key, int uid) {
436         try {
437             final long millis = mBinder.getmtime(key, uid);
438             if (millis == -1L) {
439                 return -1L;
440             }
441 
442             return millis * 1000L;
443         } catch (RemoteException e) {
444             Log.w(TAG, "Cannot connect to keystore", e);
445             return -1L;
446         }
447     }
448 
getmtime(String key)449     public long getmtime(String key) {
450         return getmtime(key, UID_SELF);
451     }
452 
453     // TODO: remove this when it's removed from Settings
isHardwareBacked()454     public boolean isHardwareBacked() {
455         return isHardwareBacked("RSA");
456     }
457 
isHardwareBacked(String keyType)458     public boolean isHardwareBacked(String keyType) {
459         try {
460             return mBinder.is_hardware_backed(keyType.toUpperCase(Locale.US)) == NO_ERROR;
461         } catch (RemoteException e) {
462             Log.w(TAG, "Cannot connect to keystore", e);
463             return false;
464         }
465     }
466 
clearUid(int uid)467     public boolean clearUid(int uid) {
468         try {
469             return mBinder.clear_uid(uid) == NO_ERROR;
470         } catch (RemoteException e) {
471             Log.w(TAG, "Cannot connect to keystore", e);
472             return false;
473         }
474     }
475 
getLastError()476     public int getLastError() {
477         return mError;
478     }
479 
addRngEntropy(byte[] data, int flags)480     public boolean addRngEntropy(byte[] data, int flags) {
481         KeystoreResultPromise promise = new KeystoreResultPromise();
482         try {
483             mBinder.asBinder().linkToDeath(promise, 0);
484             int errorCode = mBinder.addRngEntropy(promise, data, flags);
485             if (errorCode == NO_ERROR) {
486                 return interruptedPreservingGet(promise.getFuture()).getErrorCode() == NO_ERROR;
487             } else {
488                 return false;
489             }
490         } catch (RemoteException e) {
491             Log.w(TAG, "Cannot connect to keystore", e);
492             return false;
493         } catch (ExecutionException e) {
494             Log.e(TAG, "AddRngEntropy completed with exception", e);
495             return false;
496         } finally {
497             mBinder.asBinder().unlinkToDeath(promise, 0);
498         }
499     }
500 
501     private class KeyCharacteristicsCallbackResult {
502         private KeystoreResponse keystoreResponse;
503         private KeyCharacteristics keyCharacteristics;
504 
KeyCharacteristicsCallbackResult(KeystoreResponse keystoreResponse, KeyCharacteristics keyCharacteristics)505         public KeyCharacteristicsCallbackResult(KeystoreResponse keystoreResponse,
506                                                 KeyCharacteristics keyCharacteristics) {
507             this.keystoreResponse = keystoreResponse;
508             this.keyCharacteristics = keyCharacteristics;
509         }
510 
getKeystoreResponse()511         public KeystoreResponse getKeystoreResponse() {
512             return keystoreResponse;
513         }
514 
setKeystoreResponse(KeystoreResponse keystoreResponse)515         public void setKeystoreResponse(KeystoreResponse keystoreResponse) {
516             this.keystoreResponse = keystoreResponse;
517         }
518 
getKeyCharacteristics()519         public KeyCharacteristics getKeyCharacteristics() {
520             return keyCharacteristics;
521         }
522 
setKeyCharacteristics(KeyCharacteristics keyCharacteristics)523         public void setKeyCharacteristics(KeyCharacteristics keyCharacteristics) {
524             this.keyCharacteristics = keyCharacteristics;
525         }
526     }
527 
528     private class KeyCharacteristicsPromise
529             extends android.security.keystore.IKeystoreKeyCharacteristicsCallback.Stub
530             implements IBinder.DeathRecipient {
531         final private CompletableFuture<KeyCharacteristicsCallbackResult> future =
532                 new CompletableFuture<KeyCharacteristicsCallbackResult>();
533         @Override
onFinished(KeystoreResponse keystoreResponse, KeyCharacteristics keyCharacteristics)534         public void onFinished(KeystoreResponse keystoreResponse,
535                                KeyCharacteristics keyCharacteristics)
536                                        throws android.os.RemoteException {
537             future.complete(
538                     new KeyCharacteristicsCallbackResult(keystoreResponse, keyCharacteristics));
539         }
getFuture()540         public final CompletableFuture<KeyCharacteristicsCallbackResult> getFuture() {
541             return future;
542         }
543         @Override
binderDied()544         public void binderDied() {
545             future.completeExceptionally(new RemoteException("Keystore died"));
546         }
547     };
548 
generateKeyInternal(String alias, KeymasterArguments args, byte[] entropy, int uid, int flags, KeyCharacteristics outCharacteristics)549     private int generateKeyInternal(String alias, KeymasterArguments args, byte[] entropy, int uid,
550             int flags, KeyCharacteristics outCharacteristics)
551                     throws RemoteException, ExecutionException {
552         KeyCharacteristicsPromise promise = new KeyCharacteristicsPromise();
553         int error = NO_ERROR;
554         KeyCharacteristicsCallbackResult result = null;
555         try {
556             mBinder.asBinder().linkToDeath(promise, 0);
557             error = mBinder.generateKey(promise, alias, args, entropy, uid, flags);
558             if (error != NO_ERROR) {
559                 Log.e(TAG, "generateKeyInternal failed on request " + error);
560                 return error;
561             }
562             result = interruptedPreservingGet(promise.getFuture());
563         } finally {
564             mBinder.asBinder().unlinkToDeath(promise, 0);
565         }
566 
567         error = result.getKeystoreResponse().getErrorCode();
568         if (error != NO_ERROR) {
569             Log.e(TAG, "generateKeyInternal failed on response " + error);
570             return error;
571         }
572         KeyCharacteristics characteristics = result.getKeyCharacteristics();
573         if (characteristics == null) {
574             Log.e(TAG, "generateKeyInternal got empty key characteristics " + error);
575             return SYSTEM_ERROR;
576         }
577         outCharacteristics.shallowCopyFrom(characteristics);
578         return NO_ERROR;
579     }
580 
generateKey(String alias, KeymasterArguments args, byte[] entropy, int uid, int flags, KeyCharacteristics outCharacteristics)581     public int generateKey(String alias, KeymasterArguments args, byte[] entropy, int uid,
582             int flags, KeyCharacteristics outCharacteristics) {
583         try {
584             entropy = entropy != null ? entropy : new byte[0];
585             args = args != null ? args : new KeymasterArguments();
586             int error = generateKeyInternal(alias, args, entropy, uid, flags, outCharacteristics);
587             if (error == KEY_ALREADY_EXISTS) {
588                 mBinder.del(alias, uid);
589                 error = generateKeyInternal(alias, args, entropy, uid, flags, outCharacteristics);
590             }
591             return error;
592         } catch (RemoteException e) {
593             Log.w(TAG, "Cannot connect to keystore", e);
594             return SYSTEM_ERROR;
595         } catch (ExecutionException e) {
596             Log.e(TAG, "generateKey completed with exception", e);
597             return SYSTEM_ERROR;
598         }
599     }
600 
generateKey(String alias, KeymasterArguments args, byte[] entropy, int flags, KeyCharacteristics outCharacteristics)601     public int generateKey(String alias, KeymasterArguments args, byte[] entropy, int flags,
602             KeyCharacteristics outCharacteristics) {
603         return generateKey(alias, args, entropy, UID_SELF, flags, outCharacteristics);
604     }
605 
getKeyCharacteristics(String alias, KeymasterBlob clientId, KeymasterBlob appId, int uid, KeyCharacteristics outCharacteristics)606     public int getKeyCharacteristics(String alias, KeymasterBlob clientId, KeymasterBlob appId,
607             int uid, KeyCharacteristics outCharacteristics) {
608         KeyCharacteristicsPromise promise = new KeyCharacteristicsPromise();
609         try {
610             mBinder.asBinder().linkToDeath(promise, 0);
611             clientId = clientId != null ? clientId : new KeymasterBlob(new byte[0]);
612             appId = appId != null ? appId : new KeymasterBlob(new byte[0]);
613 
614             int error = mBinder.getKeyCharacteristics(promise, alias, clientId, appId, uid);
615             if (error != NO_ERROR) return error;
616 
617             KeyCharacteristicsCallbackResult result = interruptedPreservingGet(promise.getFuture());
618             error = result.getKeystoreResponse().getErrorCode();
619             if (error != NO_ERROR) return error;
620 
621             KeyCharacteristics characteristics = result.getKeyCharacteristics();
622             if (characteristics == null) return SYSTEM_ERROR;
623             outCharacteristics.shallowCopyFrom(characteristics);
624             return NO_ERROR;
625         } catch (RemoteException e) {
626             Log.w(TAG, "Cannot connect to keystore", e);
627             return SYSTEM_ERROR;
628         } catch (ExecutionException e) {
629             Log.e(TAG, "GetKeyCharacteristics completed with exception", e);
630             return SYSTEM_ERROR;
631         } finally {
632             mBinder.asBinder().unlinkToDeath(promise, 0);
633         }
634     }
635 
getKeyCharacteristics(String alias, KeymasterBlob clientId, KeymasterBlob appId, KeyCharacteristics outCharacteristics)636     public int getKeyCharacteristics(String alias, KeymasterBlob clientId, KeymasterBlob appId,
637             KeyCharacteristics outCharacteristics) {
638         return getKeyCharacteristics(alias, clientId, appId, UID_SELF, outCharacteristics);
639     }
640 
importKeyInternal(String alias, KeymasterArguments args, int format, byte[] keyData, int uid, int flags, KeyCharacteristics outCharacteristics)641     private int importKeyInternal(String alias, KeymasterArguments args, int format, byte[] keyData,
642             int uid, int flags, KeyCharacteristics outCharacteristics)
643                     throws RemoteException, ExecutionException {
644         KeyCharacteristicsPromise promise = new KeyCharacteristicsPromise();
645         mBinder.asBinder().linkToDeath(promise, 0);
646         try {
647             int error = mBinder.importKey(promise, alias, args, format, keyData, uid, flags);
648             if (error != NO_ERROR) return error;
649 
650             KeyCharacteristicsCallbackResult result = interruptedPreservingGet(promise.getFuture());
651 
652             error = result.getKeystoreResponse().getErrorCode();
653             if (error != NO_ERROR) return error;
654 
655             KeyCharacteristics characteristics = result.getKeyCharacteristics();
656             if (characteristics == null) return SYSTEM_ERROR;
657             outCharacteristics.shallowCopyFrom(characteristics);
658             return NO_ERROR;
659         } finally {
660             mBinder.asBinder().unlinkToDeath(promise, 0);
661         }
662     }
663 
importKey(String alias, KeymasterArguments args, int format, byte[] keyData, int uid, int flags, KeyCharacteristics outCharacteristics)664     public int importKey(String alias, KeymasterArguments args, int format, byte[] keyData,
665             int uid, int flags, KeyCharacteristics outCharacteristics) {
666         try {
667             int error = importKeyInternal(alias, args, format, keyData, uid, flags,
668                     outCharacteristics);
669             if (error == KEY_ALREADY_EXISTS) {
670                 mBinder.del(alias, uid);
671                 error = importKeyInternal(alias, args, format, keyData, uid, flags,
672                         outCharacteristics);
673             }
674             return error;
675         } catch (RemoteException e) {
676             Log.w(TAG, "Cannot connect to keystore", e);
677             return SYSTEM_ERROR;
678         } catch (ExecutionException e) {
679             Log.e(TAG, "ImportKey completed with exception", e);
680             return SYSTEM_ERROR;
681         }
682     }
683 
importKey(String alias, KeymasterArguments args, int format, byte[] keyData, int flags, KeyCharacteristics outCharacteristics)684     public int importKey(String alias, KeymasterArguments args, int format, byte[] keyData,
685             int flags, KeyCharacteristics outCharacteristics) {
686         return importKey(alias, args, format, keyData, UID_SELF, flags, outCharacteristics);
687     }
688 
getAlgorithmFromPKCS8(byte[] keyData)689     private String getAlgorithmFromPKCS8(byte[] keyData) {
690         try {
691             final ASN1InputStream bIn = new ASN1InputStream(new ByteArrayInputStream(keyData));
692             final PrivateKeyInfo pki = PrivateKeyInfo.getInstance(bIn.readObject());
693             final String algOid = pki.getPrivateKeyAlgorithm().getAlgorithm().getId();
694             return new AlgorithmId(new ObjectIdentifier(algOid)).getName();
695         } catch (IOException e) {
696             Log.e(TAG, "getAlgorithmFromPKCS8 Failed to parse key data");
697             Log.e(TAG, Log.getStackTraceString(e));
698             return null;
699         }
700     }
701 
makeLegacyArguments(String algorithm)702     private KeymasterArguments makeLegacyArguments(String algorithm) {
703         KeymasterArguments args = new KeymasterArguments();
704         args.addEnum(KeymasterDefs.KM_TAG_ALGORITHM,
705                 KeyProperties.KeyAlgorithm.toKeymasterAsymmetricKeyAlgorithm(algorithm));
706         args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_SIGN);
707         args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_VERIFY);
708         args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_ENCRYPT);
709         args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_DECRYPT);
710         args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_NONE);
711         if (algorithm.equalsIgnoreCase(KeyProperties.KEY_ALGORITHM_RSA)) {
712             args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_RSA_OAEP);
713             args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_ENCRYPT);
714             args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_SIGN);
715             args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_RSA_PSS);
716         }
717         args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_NONE);
718         args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_MD5);
719         args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA1);
720         args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA_2_224);
721         args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA_2_256);
722         args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA_2_384);
723         args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA_2_512);
724         args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED);
725         args.addDate(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME, new Date(Long.MAX_VALUE));
726         args.addDate(KeymasterDefs.KM_TAG_USAGE_EXPIRE_DATETIME, new Date(Long.MAX_VALUE));
727         args.addDate(KeymasterDefs.KM_TAG_ACTIVE_DATETIME, new Date(0));
728         return args;
729     }
730 
importKey(String alias, byte[] keyData, int uid, int flags)731     public boolean importKey(String alias, byte[] keyData, int uid, int flags) {
732         String algorithm = getAlgorithmFromPKCS8(keyData);
733         if (algorithm == null) return false;
734         KeymasterArguments args = makeLegacyArguments(algorithm);
735         KeyCharacteristics out = new KeyCharacteristics();
736         int result =  importKey(alias, args, KeymasterDefs.KM_KEY_FORMAT_PKCS8, keyData, uid,
737                                 flags, out);
738         if (result != NO_ERROR) {
739             Log.e(TAG, Log.getStackTraceString(
740                     new KeyStoreException(result, "legacy key import failed")));
741             return false;
742         }
743         return true;
744     }
745 
importWrappedKeyInternal(String wrappedKeyAlias, byte[] wrappedKey, String wrappingKeyAlias, byte[] maskingKey, KeymasterArguments args, long rootSid, long fingerprintSid, KeyCharacteristics outCharacteristics)746     private int importWrappedKeyInternal(String wrappedKeyAlias, byte[] wrappedKey,
747             String wrappingKeyAlias,
748             byte[] maskingKey, KeymasterArguments args, long rootSid, long fingerprintSid,
749             KeyCharacteristics outCharacteristics)
750                     throws RemoteException, ExecutionException {
751         KeyCharacteristicsPromise promise = new KeyCharacteristicsPromise();
752         mBinder.asBinder().linkToDeath(promise, 0);
753         try {
754             int error = mBinder.importWrappedKey(promise, wrappedKeyAlias, wrappedKey,
755                     wrappingKeyAlias, maskingKey, args, rootSid, fingerprintSid);
756             if (error != NO_ERROR) return error;
757 
758             KeyCharacteristicsCallbackResult result = interruptedPreservingGet(promise.getFuture());
759 
760             error = result.getKeystoreResponse().getErrorCode();
761             if (error != NO_ERROR) return error;
762 
763             KeyCharacteristics characteristics = result.getKeyCharacteristics();
764             if (characteristics == null) return SYSTEM_ERROR;
765             outCharacteristics.shallowCopyFrom(characteristics);
766             return NO_ERROR;
767         } finally {
768             mBinder.asBinder().unlinkToDeath(promise, 0);
769         }
770     }
771 
importWrappedKey(String wrappedKeyAlias, byte[] wrappedKey, String wrappingKeyAlias, byte[] maskingKey, KeymasterArguments args, long rootSid, long fingerprintSid, int uid, KeyCharacteristics outCharacteristics)772     public int importWrappedKey(String wrappedKeyAlias, byte[] wrappedKey,
773             String wrappingKeyAlias,
774             byte[] maskingKey, KeymasterArguments args, long rootSid, long fingerprintSid, int uid,
775             KeyCharacteristics outCharacteristics) {
776         // TODO b/119217337 uid parameter gets silently ignored.
777         try {
778             int error = importWrappedKeyInternal(wrappedKeyAlias, wrappedKey, wrappingKeyAlias,
779                     maskingKey, args, rootSid, fingerprintSid, outCharacteristics);
780             if (error == KEY_ALREADY_EXISTS) {
781                 mBinder.del(wrappedKeyAlias, UID_SELF);
782                 error = importWrappedKeyInternal(wrappedKeyAlias, wrappedKey, wrappingKeyAlias,
783                         maskingKey, args, rootSid, fingerprintSid, outCharacteristics);
784             }
785             return error;
786         } catch (RemoteException e) {
787             Log.w(TAG, "Cannot connect to keystore", e);
788             return SYSTEM_ERROR;
789         } catch (ExecutionException e) {
790             Log.e(TAG, "ImportWrappedKey completed with exception", e);
791             return SYSTEM_ERROR;
792         }
793     }
794 
795     private class ExportKeyPromise
796             extends android.security.keystore.IKeystoreExportKeyCallback.Stub
797             implements IBinder.DeathRecipient {
798         final private CompletableFuture<ExportResult> future = new CompletableFuture<ExportResult>();
799         @Override
onFinished(ExportResult exportKeyResult)800         public void onFinished(ExportResult exportKeyResult) throws android.os.RemoteException {
801             future.complete(exportKeyResult);
802         }
getFuture()803         public final CompletableFuture<ExportResult> getFuture() {
804             return future;
805         }
806         @Override
binderDied()807         public void binderDied() {
808             future.completeExceptionally(new RemoteException("Keystore died"));
809         }
810     };
811 
exportKey(String alias, int format, KeymasterBlob clientId, KeymasterBlob appId, int uid)812     public ExportResult exportKey(String alias, int format, KeymasterBlob clientId,
813             KeymasterBlob appId, int uid) {
814         ExportKeyPromise promise = new ExportKeyPromise();
815         try {
816             mBinder.asBinder().linkToDeath(promise, 0);
817             clientId = clientId != null ? clientId : new KeymasterBlob(new byte[0]);
818             appId = appId != null ? appId : new KeymasterBlob(new byte[0]);
819             int error = mBinder.exportKey(promise, alias, format, clientId, appId, uid);
820             if (error == NO_ERROR) {
821                 return interruptedPreservingGet(promise.getFuture());
822             } else {
823                 return new ExportResult(error);
824             }
825         } catch (RemoteException e) {
826             Log.w(TAG, "Cannot connect to keystore", e);
827             return null;
828         } catch (ExecutionException e) {
829             Log.e(TAG, "ExportKey completed with exception", e);
830             return null;
831         } finally {
832             mBinder.asBinder().unlinkToDeath(promise, 0);
833         }
834     }
exportKey(String alias, int format, KeymasterBlob clientId, KeymasterBlob appId)835     public ExportResult exportKey(String alias, int format, KeymasterBlob clientId,
836             KeymasterBlob appId) {
837         return exportKey(alias, format, clientId, appId, UID_SELF);
838     }
839 
840     private class OperationPromise
841             extends android.security.keystore.IKeystoreOperationResultCallback.Stub
842             implements IBinder.DeathRecipient {
843         final private CompletableFuture<OperationResult> future = new CompletableFuture<OperationResult>();
844         @Override
onFinished(OperationResult operationResult)845         public void onFinished(OperationResult operationResult) throws android.os.RemoteException {
846             future.complete(operationResult);
847         }
getFuture()848         public final CompletableFuture<OperationResult> getFuture() {
849             return future;
850         }
851         @Override
binderDied()852         public void binderDied() {
853             future.completeExceptionally(new RemoteException("Keystore died"));
854         }
855     };
856 
begin(String alias, int purpose, boolean pruneable, KeymasterArguments args, byte[] entropy, int uid)857     public OperationResult begin(String alias, int purpose, boolean pruneable,
858             KeymasterArguments args, byte[] entropy, int uid) {
859         OperationPromise promise = new OperationPromise();
860         try {
861             mBinder.asBinder().linkToDeath(promise, 0);
862             args = args != null ? args : new KeymasterArguments();
863             entropy = entropy != null ? entropy : new byte[0];
864             int errorCode =  mBinder.begin(promise, getToken(), alias, purpose, pruneable, args,
865                                            entropy, uid);
866             if (errorCode == NO_ERROR) {
867                 return interruptedPreservingGet(promise.getFuture());
868             } else {
869                 return new OperationResult(errorCode);
870             }
871         } catch (RemoteException e) {
872             Log.w(TAG, "Cannot connect to keystore", e);
873             return null;
874         } catch (ExecutionException e) {
875             Log.e(TAG, "Begin completed with exception", e);
876             return null;
877         } finally {
878             mBinder.asBinder().unlinkToDeath(promise, 0);
879         }
880     }
881 
begin(String alias, int purpose, boolean pruneable, KeymasterArguments args, byte[] entropy)882     public OperationResult begin(String alias, int purpose, boolean pruneable,
883             KeymasterArguments args, byte[] entropy) {
884         entropy = entropy != null ? entropy : new byte[0];
885         args = args != null ? args : new KeymasterArguments();
886         return begin(alias, purpose, pruneable, args, entropy, UID_SELF);
887     }
888 
update(IBinder token, KeymasterArguments arguments, byte[] input)889     public OperationResult update(IBinder token, KeymasterArguments arguments, byte[] input) {
890         OperationPromise promise = new OperationPromise();
891         try {
892             mBinder.asBinder().linkToDeath(promise, 0);
893             arguments = arguments != null ? arguments : new KeymasterArguments();
894             input = input != null ? input : new byte[0];
895             int errorCode =  mBinder.update(promise, token, arguments, input);
896             if (errorCode == NO_ERROR) {
897                 return interruptedPreservingGet(promise.getFuture());
898             } else {
899                 return new OperationResult(errorCode);
900             }
901         } catch (RemoteException e) {
902             Log.w(TAG, "Cannot connect to keystore", e);
903             return null;
904         } catch (ExecutionException e) {
905             Log.e(TAG, "Update completed with exception", e);
906             return null;
907         } finally {
908             mBinder.asBinder().unlinkToDeath(promise, 0);
909         }
910     }
911 
912     /**
913      * Android KeyStore finish operation.
914      *
915      * @param token Authentication token.
916      * @param arguments Keymaster arguments
917      * @param input Optional additional input data.
918      * @param signature Optional signature to be verified.
919      * @param entropy Optional additional entropy
920      * @return OperationResult that will indicate success or error of the operation.
921      */
finish(IBinder token, KeymasterArguments arguments, byte[] input, byte[] signature, byte[] entropy)922     public OperationResult finish(IBinder token, KeymasterArguments arguments, byte[] input,
923             byte[] signature, byte[] entropy) {
924         OperationPromise promise = new OperationPromise();
925         try {
926             mBinder.asBinder().linkToDeath(promise, 0);
927             arguments = arguments != null ? arguments : new KeymasterArguments();
928             entropy = entropy != null ? entropy : new byte[0];
929             input = input != null ? input : new byte[0];
930             signature = signature != null ? signature : new byte[0];
931             int errorCode = mBinder.finish(promise, token, arguments, input, signature, entropy);
932             if (errorCode == NO_ERROR) {
933                 return interruptedPreservingGet(promise.getFuture());
934             } else {
935                 return new OperationResult(errorCode);
936             }
937         } catch (RemoteException e) {
938             Log.w(TAG, "Cannot connect to keystore", e);
939             return null;
940         } catch (ExecutionException e) {
941             Log.e(TAG, "Finish completed with exception", e);
942             return null;
943         } finally {
944             mBinder.asBinder().unlinkToDeath(promise, 0);
945         }
946     }
947 
finish(IBinder token, KeymasterArguments arguments, byte[] signature)948     public OperationResult finish(IBinder token, KeymasterArguments arguments, byte[] signature) {
949         return finish(token, arguments, null, signature, null);
950     }
951 
952     private class KeystoreResultPromise
953             extends android.security.keystore.IKeystoreResponseCallback.Stub
954             implements IBinder.DeathRecipient {
955         final private CompletableFuture<KeystoreResponse> future = new CompletableFuture<KeystoreResponse>();
956         @Override
onFinished(KeystoreResponse keystoreResponse)957         public void onFinished(KeystoreResponse keystoreResponse) throws android.os.RemoteException {
958             future.complete(keystoreResponse);
959         }
getFuture()960         public final CompletableFuture<KeystoreResponse> getFuture() {
961             return future;
962         }
963         @Override
binderDied()964         public void binderDied() {
965             future.completeExceptionally(new RemoteException("Keystore died"));
966         }
967     };
968 
abort(IBinder token)969     public int abort(IBinder token) {
970         KeystoreResultPromise promise = new KeystoreResultPromise();
971         try {
972             mBinder.asBinder().linkToDeath(promise, 0);
973             int errorCode = mBinder.abort(promise, token);
974             if (errorCode == NO_ERROR) {
975                 return interruptedPreservingGet(promise.getFuture()).getErrorCode();
976             } else {
977                 return errorCode;
978             }
979         } catch (RemoteException e) {
980             Log.w(TAG, "Cannot connect to keystore", e);
981             return SYSTEM_ERROR;
982         } catch (ExecutionException e) {
983             Log.e(TAG, "Abort completed with exception", e);
984             return SYSTEM_ERROR;
985         } finally {
986             mBinder.asBinder().unlinkToDeath(promise, 0);
987         }
988     }
989 
990     /**
991      * Add an authentication record to the keystore authorization table.
992      *
993      * @param authToken The packed bytes of a hw_auth_token_t to be provided to keymaster.
994      * @return {@code KeyStore.NO_ERROR} on success, otherwise an error value corresponding to
995      * a {@code KeymasterDefs.KM_ERROR_} value or {@code KeyStore} ResponseCode.
996      */
addAuthToken(byte[] authToken)997     public int addAuthToken(byte[] authToken) {
998         try {
999             return mBinder.addAuthToken(authToken);
1000         } catch (RemoteException e) {
1001             Log.w(TAG, "Cannot connect to keystore", e);
1002             return SYSTEM_ERROR;
1003         }
1004     }
1005 
1006     /**
1007      * Notify keystore that a user's password has changed.
1008      *
1009      * @param userId the user whose password changed.
1010      * @param newPassword the new password or "" if the password was removed.
1011      */
onUserPasswordChanged(int userId, String newPassword)1012     public boolean onUserPasswordChanged(int userId, String newPassword) {
1013         // Parcel.cpp doesn't support deserializing null strings and treats them as "". Make that
1014         // explicit here.
1015         if (newPassword == null) {
1016             newPassword = "";
1017         }
1018         try {
1019             return mBinder.onUserPasswordChanged(userId, newPassword) == NO_ERROR;
1020         } catch (RemoteException e) {
1021             Log.w(TAG, "Cannot connect to keystore", e);
1022             return false;
1023         }
1024     }
1025 
1026     /**
1027      * Notify keystore that a user was added.
1028      *
1029      * @param userId the new user.
1030      * @param parentId the parent of the new user, or -1 if the user has no parent. If parentId is
1031      * specified then the new user's keystore will be intialized with the same secure lockscreen
1032      * password as the parent.
1033      */
onUserAdded(int userId, int parentId)1034     public void onUserAdded(int userId, int parentId) {
1035         try {
1036             mBinder.onUserAdded(userId, parentId);
1037         } catch (RemoteException e) {
1038             Log.w(TAG, "Cannot connect to keystore", e);
1039         }
1040     }
1041 
1042     /**
1043      * Notify keystore that a user was added.
1044      *
1045      * @param userId the new user.
1046      */
onUserAdded(int userId)1047     public void onUserAdded(int userId) {
1048         onUserAdded(userId, -1);
1049     }
1050 
1051     /**
1052      * Notify keystore that a user was removed.
1053      *
1054      * @param userId the removed user.
1055      */
onUserRemoved(int userId)1056     public void onUserRemoved(int userId) {
1057         try {
1058             mBinder.onUserRemoved(userId);
1059         } catch (RemoteException e) {
1060             Log.w(TAG, "Cannot connect to keystore", e);
1061         }
1062     }
1063 
onUserPasswordChanged(String newPassword)1064     public boolean onUserPasswordChanged(String newPassword) {
1065         return onUserPasswordChanged(UserHandle.getUserId(Process.myUid()), newPassword);
1066     }
1067 
1068     /**
1069      * Notify keystore about the latest user locked state. This is to support keyguard-bound key.
1070      */
onUserLockedStateChanged(int userHandle, boolean locked)1071     public void onUserLockedStateChanged(int userHandle, boolean locked) {
1072         try {
1073             mBinder.onKeyguardVisibilityChanged(locked, userHandle);
1074         } catch (RemoteException e) {
1075             Log.w(TAG, "Failed to update user locked state " + userHandle, e);
1076         }
1077     }
1078 
1079     private class KeyAttestationCallbackResult {
1080         private KeystoreResponse keystoreResponse;
1081         private KeymasterCertificateChain certificateChain;
1082 
KeyAttestationCallbackResult(KeystoreResponse keystoreResponse, KeymasterCertificateChain certificateChain)1083         public KeyAttestationCallbackResult(KeystoreResponse keystoreResponse,
1084                 KeymasterCertificateChain certificateChain) {
1085             this.keystoreResponse = keystoreResponse;
1086             this.certificateChain = certificateChain;
1087         }
1088 
getKeystoreResponse()1089         public KeystoreResponse getKeystoreResponse() {
1090             return keystoreResponse;
1091         }
1092 
setKeystoreResponse(KeystoreResponse keystoreResponse)1093         public void setKeystoreResponse(KeystoreResponse keystoreResponse) {
1094             this.keystoreResponse = keystoreResponse;
1095         }
1096 
getCertificateChain()1097         public KeymasterCertificateChain getCertificateChain() {
1098             return certificateChain;
1099         }
1100 
setCertificateChain(KeymasterCertificateChain certificateChain)1101         public void setCertificateChain(KeymasterCertificateChain certificateChain) {
1102             this.certificateChain = certificateChain;
1103         }
1104     }
1105 
1106     private class CertificateChainPromise
1107             extends android.security.keystore.IKeystoreCertificateChainCallback.Stub
1108             implements IBinder.DeathRecipient {
1109         final private CompletableFuture<KeyAttestationCallbackResult> future = new CompletableFuture<KeyAttestationCallbackResult>();
1110         @Override
onFinished(KeystoreResponse keystoreResponse, KeymasterCertificateChain certificateChain)1111         public void onFinished(KeystoreResponse keystoreResponse,
1112                 KeymasterCertificateChain certificateChain) throws android.os.RemoteException {
1113             future.complete(new KeyAttestationCallbackResult(keystoreResponse, certificateChain));
1114         }
getFuture()1115         public final CompletableFuture<KeyAttestationCallbackResult> getFuture() {
1116             return future;
1117         }
1118         @Override
binderDied()1119         public void binderDied() {
1120             future.completeExceptionally(new RemoteException("Keystore died"));
1121         }
1122     };
1123 
1124 
attestKey( String alias, KeymasterArguments params, KeymasterCertificateChain outChain)1125     public int attestKey(
1126             String alias, KeymasterArguments params, KeymasterCertificateChain outChain) {
1127         CertificateChainPromise promise = new CertificateChainPromise();
1128         try {
1129             mBinder.asBinder().linkToDeath(promise, 0);
1130             if (params == null) {
1131                 params = new KeymasterArguments();
1132             }
1133             if (outChain == null) {
1134                 outChain = new KeymasterCertificateChain();
1135             }
1136             int error = mBinder.attestKey(promise, alias, params);
1137             if (error != NO_ERROR) return error;
1138             KeyAttestationCallbackResult result = interruptedPreservingGet(promise.getFuture());
1139             error = result.getKeystoreResponse().getErrorCode();
1140             if (error == NO_ERROR) {
1141                 outChain.shallowCopyFrom(result.getCertificateChain());
1142             }
1143             return error;
1144         } catch (RemoteException e) {
1145             Log.w(TAG, "Cannot connect to keystore", e);
1146             return SYSTEM_ERROR;
1147         } catch (ExecutionException e) {
1148             Log.e(TAG, "AttestKey completed with exception", e);
1149             return SYSTEM_ERROR;
1150         } finally {
1151             mBinder.asBinder().unlinkToDeath(promise, 0);
1152         }
1153     }
1154 
attestDeviceIds(KeymasterArguments params, KeymasterCertificateChain outChain)1155     public int attestDeviceIds(KeymasterArguments params, KeymasterCertificateChain outChain) {
1156         CertificateChainPromise promise = new CertificateChainPromise();
1157         try {
1158             mBinder.asBinder().linkToDeath(promise, 0);
1159             if (params == null) {
1160                 params = new KeymasterArguments();
1161             }
1162             if (outChain == null) {
1163                 outChain = new KeymasterCertificateChain();
1164             }
1165             int error = mBinder.attestDeviceIds(promise, params);
1166             if (error != NO_ERROR) return error;
1167             KeyAttestationCallbackResult result = interruptedPreservingGet(promise.getFuture());
1168             error = result.getKeystoreResponse().getErrorCode();
1169             if (error == NO_ERROR) {
1170                 outChain.shallowCopyFrom(result.getCertificateChain());
1171             }
1172             return error;
1173         } catch (RemoteException e) {
1174             Log.w(TAG, "Cannot connect to keystore", e);
1175             return SYSTEM_ERROR;
1176         } catch (ExecutionException e) {
1177             Log.e(TAG, "AttestDevicdeIds completed with exception", e);
1178             return SYSTEM_ERROR;
1179         } finally {
1180             mBinder.asBinder().unlinkToDeath(promise, 0);
1181         }
1182     }
1183 
1184     /**
1185      * Notify keystore that the device went off-body.
1186      */
onDeviceOffBody()1187     public void onDeviceOffBody() {
1188         try {
1189             mBinder.onDeviceOffBody();
1190         } catch (RemoteException e) {
1191             Log.w(TAG, "Cannot connect to keystore", e);
1192         }
1193     }
1194 
1195     // Keep in sync with confirmationui/1.0/types.hal.
1196     public static final int CONFIRMATIONUI_OK = 0;
1197     public static final int CONFIRMATIONUI_CANCELED = 1;
1198     public static final int CONFIRMATIONUI_ABORTED = 2;
1199     public static final int CONFIRMATIONUI_OPERATION_PENDING = 3;
1200     public static final int CONFIRMATIONUI_IGNORED = 4;
1201     public static final int CONFIRMATIONUI_SYSTEM_ERROR = 5;
1202     public static final int CONFIRMATIONUI_UNIMPLEMENTED = 6;
1203     public static final int CONFIRMATIONUI_UNEXPECTED = 7;
1204     public static final int CONFIRMATIONUI_UIERROR = 0x10000;
1205     public static final int CONFIRMATIONUI_UIERROR_MISSING_GLYPH = 0x10001;
1206     public static final int CONFIRMATIONUI_UIERROR_MESSAGE_TOO_LONG = 0x10002;
1207     public static final int CONFIRMATIONUI_UIERROR_MALFORMED_UTF8_ENCODING = 0x10003;
1208 
1209     /**
1210      * Requests keystore call into the confirmationui HAL to display a prompt.
1211      *
1212      * @param listener the binder to use for callbacks.
1213      * @param promptText the prompt to display.
1214      * @param extraData extra data / nonce from application.
1215      * @param locale the locale as a BCP 47 langauge tag.
1216      * @param uiOptionsAsFlags the UI options to use, as flags.
1217      * @return one of the {@code CONFIRMATIONUI_*} constants, for
1218      * example {@code KeyStore.CONFIRMATIONUI_OK}.
1219      */
presentConfirmationPrompt(IBinder listener, String promptText, byte[] extraData, String locale, int uiOptionsAsFlags)1220     public int presentConfirmationPrompt(IBinder listener, String promptText, byte[] extraData,
1221                                          String locale, int uiOptionsAsFlags) {
1222         try {
1223             return mBinder.presentConfirmationPrompt(listener, promptText, extraData, locale,
1224                                                      uiOptionsAsFlags);
1225         } catch (RemoteException e) {
1226             Log.w(TAG, "Cannot connect to keystore", e);
1227             return CONFIRMATIONUI_SYSTEM_ERROR;
1228         }
1229     }
1230 
1231     /**
1232      * Requests keystore call into the confirmationui HAL to cancel displaying a prompt.
1233      *
1234      * @param listener the binder passed to the {@link #presentConfirmationPrompt} method.
1235      * @return one of the {@code CONFIRMATIONUI_*} constants, for
1236      * example {@code KeyStore.CONFIRMATIONUI_OK}.
1237      */
cancelConfirmationPrompt(IBinder listener)1238     public int cancelConfirmationPrompt(IBinder listener) {
1239         try {
1240             return mBinder.cancelConfirmationPrompt(listener);
1241         } catch (RemoteException e) {
1242             Log.w(TAG, "Cannot connect to keystore", e);
1243             return CONFIRMATIONUI_SYSTEM_ERROR;
1244         }
1245     }
1246 
1247     /**
1248      * Requests keystore to check if the confirmationui HAL is available.
1249      *
1250      * @return whether the confirmationUI HAL is available.
1251      */
isConfirmationPromptSupported()1252     public boolean isConfirmationPromptSupported() {
1253         try {
1254             return mBinder.isConfirmationPromptSupported();
1255         } catch (RemoteException e) {
1256             Log.w(TAG, "Cannot connect to keystore", e);
1257             return false;
1258         }
1259     }
1260 
1261     /**
1262      * Returns a {@link KeyStoreException} corresponding to the provided keystore/keymaster error
1263      * code.
1264      */
1265     @UnsupportedAppUsage
getKeyStoreException(int errorCode)1266     public static KeyStoreException getKeyStoreException(int errorCode) {
1267         if (errorCode > 0) {
1268             // KeyStore layer error
1269             switch (errorCode) {
1270                 case NO_ERROR:
1271                     return new KeyStoreException(errorCode, "OK");
1272                 case LOCKED:
1273                     return new KeyStoreException(errorCode, "User authentication required");
1274                 case UNINITIALIZED:
1275                     return new KeyStoreException(errorCode, "Keystore not initialized");
1276                 case SYSTEM_ERROR:
1277                     return new KeyStoreException(errorCode, "System error");
1278                 case PERMISSION_DENIED:
1279                     return new KeyStoreException(errorCode, "Permission denied");
1280                 case KEY_NOT_FOUND:
1281                     return new KeyStoreException(errorCode, "Key not found");
1282                 case VALUE_CORRUPTED:
1283                     return new KeyStoreException(errorCode, "Key blob corrupted");
1284                 case OP_AUTH_NEEDED:
1285                     return new KeyStoreException(errorCode, "Operation requires authorization");
1286                 case KEY_PERMANENTLY_INVALIDATED:
1287                     return new KeyStoreException(errorCode, "Key permanently invalidated");
1288                 default:
1289                     return new KeyStoreException(errorCode, String.valueOf(errorCode));
1290             }
1291         } else {
1292             // Keymaster layer error
1293             switch (errorCode) {
1294                 case KeymasterDefs.KM_ERROR_INVALID_AUTHORIZATION_TIMEOUT:
1295                     // The name of this parameter significantly differs between Keymaster and
1296                     // framework APIs. Use the framework wording to make life easier for developers.
1297                     return new KeyStoreException(errorCode,
1298                             "Invalid user authentication validity duration");
1299                 default:
1300                     return new KeyStoreException(errorCode,
1301                             KeymasterDefs.getErrorMessage(errorCode));
1302             }
1303         }
1304     }
1305 
1306     /**
1307      * Returns an {@link InvalidKeyException} corresponding to the provided
1308      * {@link KeyStoreException}.
1309      */
getInvalidKeyException( String keystoreKeyAlias, int uid, KeyStoreException e)1310     public InvalidKeyException getInvalidKeyException(
1311             String keystoreKeyAlias, int uid, KeyStoreException e) {
1312         switch (e.getErrorCode()) {
1313             case LOCKED:
1314                 return new UserNotAuthenticatedException();
1315             case KeymasterDefs.KM_ERROR_KEY_EXPIRED:
1316                 return new KeyExpiredException();
1317             case KeymasterDefs.KM_ERROR_KEY_NOT_YET_VALID:
1318                 return new KeyNotYetValidException();
1319             case KeymasterDefs.KM_ERROR_KEY_USER_NOT_AUTHENTICATED:
1320             case OP_AUTH_NEEDED:
1321             {
1322                 // We now need to determine whether the key/operation can become usable if user
1323                 // authentication is performed, or whether it can never become usable again.
1324                 // User authentication requirements are contained in the key's characteristics. We
1325                 // need to check whether these requirements can be be satisfied by asking the user
1326                 // to authenticate.
1327                 KeyCharacteristics keyCharacteristics = new KeyCharacteristics();
1328                 int getKeyCharacteristicsErrorCode =
1329                         getKeyCharacteristics(keystoreKeyAlias, null, null, uid,
1330                                 keyCharacteristics);
1331                 if (getKeyCharacteristicsErrorCode != NO_ERROR) {
1332                     return new InvalidKeyException(
1333                             "Failed to obtained key characteristics",
1334                             getKeyStoreException(getKeyCharacteristicsErrorCode));
1335                 }
1336                 List<BigInteger> keySids =
1337                         keyCharacteristics.getUnsignedLongs(KeymasterDefs.KM_TAG_USER_SECURE_ID);
1338                 if (keySids.isEmpty()) {
1339                     // Key is not bound to any SIDs -- no amount of authentication will help here.
1340                     return new KeyPermanentlyInvalidatedException();
1341                 }
1342                 long rootSid = GateKeeper.getSecureUserId();
1343                 if ((rootSid != 0) && (keySids.contains(KeymasterArguments.toUint64(rootSid)))) {
1344                     // One of the key's SIDs is the current root SID -- user can be authenticated
1345                     // against that SID.
1346                     return new UserNotAuthenticatedException();
1347                 }
1348 
1349                 final BiometricManager bm = mContext.getSystemService(BiometricManager.class);
1350                 long[] biometricSids = bm.getAuthenticatorIds();
1351 
1352                 // The key must contain every biometric SID. This is because the current API surface
1353                 // treats all biometrics (capable of keystore integration) equally. e.g. if the
1354                 // device has multiple keystore-capable sensors, and one of the sensor's SIDs
1355                 // changed, 1) there is no way for a developer to specify authentication with a
1356                 // specific sensor (the one that hasn't changed), and 2) currently the only
1357                 // signal to developers is the UserNotAuthenticatedException, which doesn't
1358                 // indicate a specific sensor.
1359                 boolean canUnlockViaBiometrics = true;
1360                 for (long sid : biometricSids) {
1361                     if (!keySids.contains(KeymasterArguments.toUint64(sid))) {
1362                         canUnlockViaBiometrics = false;
1363                         break;
1364                     }
1365                 }
1366 
1367                 if (canUnlockViaBiometrics) {
1368                     // All of the biometric SIDs are contained in the key's SIDs.
1369                     return new UserNotAuthenticatedException();
1370                 }
1371 
1372                 // None of the key's SIDs can ever be authenticated
1373                 return new KeyPermanentlyInvalidatedException();
1374             }
1375             case UNINITIALIZED:
1376                 return new KeyPermanentlyInvalidatedException();
1377             default:
1378                 return new InvalidKeyException("Keystore operation failed", e);
1379         }
1380     }
1381 
1382     /**
1383      * Returns an {@link InvalidKeyException} corresponding to the provided keystore/keymaster error
1384      * code.
1385      */
getInvalidKeyException(String keystoreKeyAlias, int uid, int errorCode)1386     public InvalidKeyException getInvalidKeyException(String keystoreKeyAlias, int uid,
1387             int errorCode) {
1388         return getInvalidKeyException(keystoreKeyAlias, uid, getKeyStoreException(errorCode));
1389     }
1390 
interruptedPreservingGet(CompletableFuture<R> future)1391     private static <R> R interruptedPreservingGet(CompletableFuture<R> future)
1392             throws ExecutionException {
1393         boolean wasInterrupted = false;
1394         while (true) {
1395             try {
1396                 R result = future.get();
1397                 if (wasInterrupted) {
1398                     Thread.currentThread().interrupt();
1399                 }
1400                 return result;
1401             } catch (InterruptedException e) {
1402                 wasInterrupted = true;
1403             }
1404         }
1405     }
1406 }
1407