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