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.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.keymaster.ExportResult;
35 import android.security.keymaster.KeyCharacteristics;
36 import android.security.keymaster.KeymasterArguments;
37 import android.security.keymaster.KeymasterBlob;
38 import android.security.keymaster.KeymasterCertificateChain;
39 import android.security.keymaster.KeymasterDefs;
40 import android.security.keymaster.OperationResult;
41 import android.security.keystore.IKeystoreService;
42 import android.security.keystore.KeyExpiredException;
43 import android.security.keystore.KeyNotYetValidException;
44 import android.security.keystore.KeyPermanentlyInvalidatedException;
45 import android.security.keystore.KeyProperties;
46 import android.security.keystore.KeystoreResponse;
47 import android.security.keystore.UserNotAuthenticatedException;
48 import android.util.Log;
49 
50 import com.android.org.bouncycastle.asn1.ASN1InputStream;
51 import com.android.org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
52 
53 import java.io.ByteArrayInputStream;
54 import java.io.IOException;
55 import java.math.BigInteger;
56 import java.security.InvalidKeyException;
57 import java.util.ArrayList;
58 import java.util.Date;
59 import java.util.List;
60 import java.util.Locale;
61 import java.util.concurrent.CompletableFuture;
62 import java.util.concurrent.ExecutionException;
63 
64 import sun.security.util.ObjectIdentifier;
65 import sun.security.x509.AlgorithmId;
66 
67 /**
68  * @hide This should not be made public in its present form because it
69  * assumes that private and secret key bytes are available and would
70  * preclude the use of hardware crypto.
71  */
72 public class KeyStore {
73     private static final String TAG = "KeyStore";
74 
75     // ResponseCodes - see system/security/keystore/include/keystore/keystore.h
76     @UnsupportedAppUsage
77     public static final int NO_ERROR = 1;
78     public static final int LOCKED = 2;
79     public static final int UNINITIALIZED = 3;
80     public static final int SYSTEM_ERROR = 4;
81     public static final int PROTOCOL_ERROR = 5;
82     public static final int PERMISSION_DENIED = 6;
83     public static final int KEY_NOT_FOUND = 7;
84     public static final int VALUE_CORRUPTED = 8;
85     public static final int UNDEFINED_ACTION = 9;
86     public static final int WRONG_PASSWORD = 10;
87     public static final int KEY_ALREADY_EXISTS = 16;
88     public static final int CANNOT_ATTEST_IDS = -66;
89     public static final int HARDWARE_TYPE_UNAVAILABLE = -68;
90 
91     /**
92      * Per operation authentication is needed before this operation is valid.
93      * This is returned from {@link #begin} when begin succeeds but the operation uses
94      * per-operation authentication and must authenticate before calling {@link #update} or
95      * {@link #finish}.
96      */
97     public static final int OP_AUTH_NEEDED = 15;
98 
99     // Used when a user changes their pin, invalidating old auth bound keys.
100     public static final int KEY_PERMANENTLY_INVALIDATED = 17;
101 
102     // Used for UID field to indicate the calling UID.
103     public static final int UID_SELF = -1;
104 
105     // Flags for "put" "import" and "generate"
106     public static final int FLAG_NONE = 0;
107 
108     /**
109      * Indicates that this key (or key pair) must be encrypted at rest. This will protect the key
110      * (or key pair) with the secure lock screen credential (e.g., password, PIN, or pattern).
111      *
112      * <p>Note that this requires that the secure lock screen (e.g., password, PIN, pattern) is set
113      * up, otherwise key (or key pair) generation or import will fail. Moreover, this key (or key
114      * pair) will be deleted when the secure lock screen is disabled or reset (e.g., by the user or
115      * a Device Administrator). Finally, this key (or key pair) cannot be used until the user
116      * unlocks the secure lock screen after boot.
117      *
118      * @see KeyguardManager#isDeviceSecure()
119      */
120     public static final int FLAG_ENCRYPTED = 1;
121 
122     /**
123      * Select Software keymaster device, which as of this writing is the lowest security
124      * level available on an android device. If neither FLAG_STRONGBOX nor FLAG_SOFTWARE is provided
125      * A TEE based keymaster implementation is implied.
126      *
127      * Need to be in sync with KeyStoreFlag in system/security/keystore/include/keystore/keystore.h
128      * For historical reasons this corresponds to the KEYSTORE_FLAG_FALLBACK flag.
129      */
130     public static final int FLAG_SOFTWARE = 1 << 1;
131 
132     /**
133      * A private flag that's only available to system server to indicate that this key is part of
134      * device encryption flow so it receives special treatment from keystore. For example this key
135      * will not be super encrypted, and it will be stored separately under an unique UID instead
136      * of the caller UID i.e. SYSTEM.
137      *
138      * Need to be in sync with KeyStoreFlag in system/security/keystore/include/keystore/keystore.h
139      */
140     public static final int FLAG_CRITICAL_TO_DEVICE_ENCRYPTION = 1 << 3;
141 
142     /**
143      * Select Strongbox keymaster device, which as of this writing the the highest security level
144      * available an android devices. If neither FLAG_STRONGBOX nor FLAG_SOFTWARE is provided
145      * A TEE based keymaster implementation is implied.
146      *
147      * Need to be in sync with KeyStoreFlag in system/security/keystore/include/keystore/keystore.h
148      */
149     public static final int FLAG_STRONGBOX = 1 << 4;
150 
151     // States
152     public enum State {
153         @UnsupportedAppUsage
154         UNLOCKED,
155         @UnsupportedAppUsage
156         LOCKED,
157         UNINITIALIZED
158     };
159 
160     private int mError = NO_ERROR;
161 
162     private final IKeystoreService mBinder;
163     private final Context mContext;
164 
165     private IBinder mToken;
166 
KeyStore(IKeystoreService binder)167     private KeyStore(IKeystoreService binder) {
168         mBinder = binder;
169         mContext = getApplicationContext();
170     }
171 
172     @UnsupportedAppUsage
getApplicationContext()173     public static Context getApplicationContext() {
174         Application application = ActivityThread.currentApplication();
175         if (application == null) {
176             throw new IllegalStateException(
177                     "Failed to obtain application Context from ActivityThread");
178         }
179         return application;
180     }
181 
182     @UnsupportedAppUsage
getInstance()183     public static KeyStore getInstance() {
184         IKeystoreService keystore = IKeystoreService.Stub.asInterface(ServiceManager
185                 .getService("android.security.keystore"));
186         return new KeyStore(keystore);
187     }
188 
getToken()189     private synchronized IBinder getToken() {
190         if (mToken == null) {
191             mToken = new Binder();
192         }
193         return mToken;
194     }
195 
196     @UnsupportedAppUsage
state(int userId)197     public State state(int userId) {
198         final int ret;
199         try {
200             ret = mBinder.getState(userId);
201         } catch (RemoteException e) {
202             Log.w(TAG, "Cannot connect to keystore", e);
203             throw new AssertionError(e);
204         }
205 
206         switch (ret) {
207             case NO_ERROR: return State.UNLOCKED;
208             case LOCKED: return State.LOCKED;
209             case UNINITIALIZED: return State.UNINITIALIZED;
210             default: throw new AssertionError(mError);
211         }
212     }
213 
214     @UnsupportedAppUsage
state()215     public State state() {
216         return state(UserHandle.myUserId());
217     }
218 
isUnlocked()219     public boolean isUnlocked() {
220         return state() == State.UNLOCKED;
221     }
222 
get(String key, int uid)223     public byte[] get(String key, int uid) {
224         return get(key, uid, false);
225     }
226 
227     @UnsupportedAppUsage
get(String key)228     public byte[] get(String key) {
229         return get(key, UID_SELF);
230     }
231 
get(String key, int uid, boolean suppressKeyNotFoundWarning)232     public byte[] get(String key, int uid, boolean suppressKeyNotFoundWarning) {
233         try {
234             key = key != null ? key : "";
235             return mBinder.get(key, uid);
236         } catch (RemoteException e) {
237              Log.w(TAG, "Cannot connect to keystore", e);
238             return null;
239         } catch (android.os.ServiceSpecificException e) {
240             if (!suppressKeyNotFoundWarning || e.errorCode != KEY_NOT_FOUND) {
241                 Log.w(TAG, "KeyStore exception", e);
242             }
243             return null;
244         }
245     }
246 
get(String key, boolean suppressKeyNotFoundWarning)247     public byte[] get(String key, boolean suppressKeyNotFoundWarning) {
248         return get(key, UID_SELF, suppressKeyNotFoundWarning);
249     }
250 
251 
put(String key, byte[] value, int uid, int flags)252     public boolean put(String key, byte[] value, int uid, int flags) {
253         return insert(key, value, uid, flags) == NO_ERROR;
254     }
255 
insert(String key, byte[] value, int uid, int flags)256     public int insert(String key, byte[] value, int uid, int flags) {
257         try {
258             if (value == null) {
259                 value = new byte[0];
260             }
261             int error = mBinder.insert(key, value, uid, flags);
262             if (error == KEY_ALREADY_EXISTS) {
263                 mBinder.del(key, uid);
264                 error = mBinder.insert(key, value, uid, flags);
265             }
266             return error;
267         } catch (RemoteException e) {
268             Log.w(TAG, "Cannot connect to keystore", e);
269             return SYSTEM_ERROR;
270         }
271     }
272 
delete2(String key, int uid)273     int delete2(String key, int uid) {
274         try {
275             return mBinder.del(key, uid);
276         } catch (RemoteException e) {
277             Log.w(TAG, "Cannot connect to keystore", e);
278             return SYSTEM_ERROR;
279         }
280     }
281 
delete(String key, int uid)282     public boolean delete(String key, int uid) {
283         int ret = delete2(key, uid);
284         return ret == NO_ERROR || ret == KEY_NOT_FOUND;
285     }
286 
287     @UnsupportedAppUsage
delete(String key)288     public boolean delete(String key) {
289         return delete(key, UID_SELF);
290     }
291 
contains(String key, int uid)292     public boolean contains(String key, int uid) {
293         try {
294             return mBinder.exist(key, uid) == NO_ERROR;
295         } catch (RemoteException e) {
296             Log.w(TAG, "Cannot connect to keystore", e);
297             return false;
298         }
299     }
300 
contains(String key)301     public boolean contains(String key) {
302         return contains(key, UID_SELF);
303     }
304 
305     /**
306      * List all entries in the keystore for {@code uid} starting with {@code prefix}.
307      */
list(String prefix, int uid)308     public String[] list(String prefix, int uid) {
309         try {
310             return mBinder.list(prefix, uid);
311         } catch (RemoteException e) {
312             Log.w(TAG, "Cannot connect to keystore", e);
313             return null;
314         } catch (android.os.ServiceSpecificException e) {
315             Log.w(TAG, "KeyStore exception", e);
316             return null;
317         }
318     }
319 
320     /**
321      * List uids of all keys that are auth bound to the current user.
322      * Only system is allowed to call this method.
323      */
324     @UnsupportedAppUsage
listUidsOfAuthBoundKeys()325     public int[] listUidsOfAuthBoundKeys() {
326         // uids are returned as a list of strings because list of integers
327         // as an output parameter is not supported by aidl-cpp.
328         List<String> uidsOut = new ArrayList<>();
329         try {
330             int rc = mBinder.listUidsOfAuthBoundKeys(uidsOut);
331             if (rc != NO_ERROR) {
332                 Log.w(TAG, String.format("listUidsOfAuthBoundKeys failed with error code %d", rc));
333                 return null;
334             }
335         } catch (RemoteException e) {
336             Log.w(TAG, "Cannot connect to keystore", e);
337             return null;
338         } catch (android.os.ServiceSpecificException e) {
339             Log.w(TAG, "KeyStore exception", e);
340             return null;
341         }
342         // Turn list of strings into an array of uid integers.
343         return uidsOut.stream().mapToInt(Integer::parseInt).toArray();
344    }
345 
list(String prefix)346     public String[] list(String prefix) {
347         return list(prefix, UID_SELF);
348     }
349 
350     /**
351      * Attempt to lock the keystore for {@code user}.
352      *
353      * @param userId Android user to lock.
354      * @return whether {@code user}'s keystore was locked.
355      */
lock(int userId)356     public boolean lock(int userId) {
357         try {
358             return mBinder.lock(userId) == NO_ERROR;
359         } catch (RemoteException e) {
360             Log.w(TAG, "Cannot connect to keystore", e);
361             return false;
362         }
363     }
364 
lock()365     public boolean lock() {
366         return lock(UserHandle.myUserId());
367     }
368 
369     /**
370      * Attempt to unlock the keystore for {@code user} with the password {@code password}.
371      * This is required before keystore entries created with FLAG_ENCRYPTED can be accessed or
372      * created.
373      *
374      * @param userId Android user ID to operate on
375      * @param password user's keystore password. Should be the most recent value passed to
376      * {@link #onUserPasswordChanged} for the user.
377      *
378      * @return whether the keystore was unlocked.
379      */
unlock(int userId, String password)380     public boolean unlock(int userId, String password) {
381         try {
382             password = password != null ? password : "";
383             mError = mBinder.unlock(userId, password);
384             return mError == NO_ERROR;
385         } catch (RemoteException e) {
386             Log.w(TAG, "Cannot connect to keystore", e);
387             return false;
388         }
389     }
390 
391     @UnsupportedAppUsage
unlock(String password)392     public boolean unlock(String password) {
393         return unlock(UserHandle.getUserId(Process.myUid()), password);
394     }
395 
396     /**
397      * Check if the keystore for {@code userId} is empty.
398      */
isEmpty(int userId)399     public boolean isEmpty(int userId) {
400         try {
401             return mBinder.isEmpty(userId) != 0;
402         } catch (RemoteException e) {
403             Log.w(TAG, "Cannot connect to keystore", e);
404             return false;
405         }
406     }
407 
408     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
isEmpty()409     public boolean isEmpty() {
410         return isEmpty(UserHandle.myUserId());
411     }
412 
grant(String key, int uid)413     public String grant(String key, int uid) {
414         try {
415             String grantAlias =  mBinder.grant(key, uid);
416             if (grantAlias == "") return null;
417             return grantAlias;
418         } catch (RemoteException e) {
419             Log.w(TAG, "Cannot connect to keystore", e);
420             return null;
421         }
422     }
423 
ungrant(String key, int uid)424     public boolean ungrant(String key, int uid) {
425         try {
426             return mBinder.ungrant(key, uid) == NO_ERROR;
427         } catch (RemoteException e) {
428             Log.w(TAG, "Cannot connect to keystore", e);
429             return false;
430         }
431     }
432 
433     /**
434      * Returns the last modification time of the key in milliseconds since the
435      * epoch. Will return -1L if the key could not be found or other error.
436      */
getmtime(String key, int uid)437     public long getmtime(String key, int uid) {
438         try {
439             final long millis = mBinder.getmtime(key, uid);
440             if (millis == -1L) {
441                 return -1L;
442             }
443 
444             return millis * 1000L;
445         } catch (RemoteException e) {
446             Log.w(TAG, "Cannot connect to keystore", e);
447             return -1L;
448         }
449     }
450 
getmtime(String key)451     public long getmtime(String key) {
452         return getmtime(key, UID_SELF);
453     }
454 
455     // TODO: remove this when it's removed from Settings
isHardwareBacked()456     public boolean isHardwareBacked() {
457         return isHardwareBacked("RSA");
458     }
459 
isHardwareBacked(String keyType)460     public boolean isHardwareBacked(String keyType) {
461         try {
462             return mBinder.is_hardware_backed(keyType.toUpperCase(Locale.US)) == NO_ERROR;
463         } catch (RemoteException e) {
464             Log.w(TAG, "Cannot connect to keystore", e);
465             return false;
466         }
467     }
468 
clearUid(int uid)469     public boolean clearUid(int uid) {
470         try {
471             return mBinder.clear_uid(uid) == NO_ERROR;
472         } catch (RemoteException e) {
473             Log.w(TAG, "Cannot connect to keystore", e);
474             return false;
475         }
476     }
477 
getLastError()478     public int getLastError() {
479         return mError;
480     }
481 
addRngEntropy(byte[] data, int flags)482     public boolean addRngEntropy(byte[] data, int flags) {
483         KeystoreResultPromise promise = new KeystoreResultPromise();
484         try {
485             mBinder.asBinder().linkToDeath(promise, 0);
486             int errorCode = mBinder.addRngEntropy(promise, data, flags);
487             if (errorCode == NO_ERROR) {
488                 return interruptedPreservingGet(promise.getFuture()).getErrorCode() == NO_ERROR;
489             } else {
490                 return false;
491             }
492         } catch (RemoteException e) {
493             Log.w(TAG, "Cannot connect to keystore", e);
494             return false;
495         } catch (ExecutionException e) {
496             Log.e(TAG, "AddRngEntropy completed with exception", e);
497             return false;
498         } finally {
499             mBinder.asBinder().unlinkToDeath(promise, 0);
500         }
501     }
502 
503     private class KeyCharacteristicsCallbackResult {
504         private KeystoreResponse keystoreResponse;
505         private KeyCharacteristics keyCharacteristics;
506 
KeyCharacteristicsCallbackResult(KeystoreResponse keystoreResponse, KeyCharacteristics keyCharacteristics)507         public KeyCharacteristicsCallbackResult(KeystoreResponse keystoreResponse,
508                                                 KeyCharacteristics keyCharacteristics) {
509             this.keystoreResponse = keystoreResponse;
510             this.keyCharacteristics = keyCharacteristics;
511         }
512 
getKeystoreResponse()513         public KeystoreResponse getKeystoreResponse() {
514             return keystoreResponse;
515         }
516 
setKeystoreResponse(KeystoreResponse keystoreResponse)517         public void setKeystoreResponse(KeystoreResponse keystoreResponse) {
518             this.keystoreResponse = keystoreResponse;
519         }
520 
getKeyCharacteristics()521         public KeyCharacteristics getKeyCharacteristics() {
522             return keyCharacteristics;
523         }
524 
setKeyCharacteristics(KeyCharacteristics keyCharacteristics)525         public void setKeyCharacteristics(KeyCharacteristics keyCharacteristics) {
526             this.keyCharacteristics = keyCharacteristics;
527         }
528     }
529 
530     private class KeyCharacteristicsPromise
531             extends android.security.keystore.IKeystoreKeyCharacteristicsCallback.Stub
532             implements IBinder.DeathRecipient {
533         final private CompletableFuture<KeyCharacteristicsCallbackResult> future =
534                 new CompletableFuture<KeyCharacteristicsCallbackResult>();
535         @Override
onFinished(KeystoreResponse keystoreResponse, KeyCharacteristics keyCharacteristics)536         public void onFinished(KeystoreResponse keystoreResponse,
537                                KeyCharacteristics keyCharacteristics)
538                                        throws android.os.RemoteException {
539             future.complete(
540                     new KeyCharacteristicsCallbackResult(keystoreResponse, keyCharacteristics));
541         }
getFuture()542         public final CompletableFuture<KeyCharacteristicsCallbackResult> getFuture() {
543             return future;
544         }
545         @Override
binderDied()546         public void binderDied() {
547             future.completeExceptionally(new RemoteException("Keystore died"));
548         }
549     };
550 
generateKeyInternal(String alias, KeymasterArguments args, byte[] entropy, int uid, int flags, KeyCharacteristics outCharacteristics)551     private int generateKeyInternal(String alias, KeymasterArguments args, byte[] entropy, int uid,
552             int flags, KeyCharacteristics outCharacteristics)
553                     throws RemoteException, ExecutionException {
554         KeyCharacteristicsPromise promise = new KeyCharacteristicsPromise();
555         int error = NO_ERROR;
556         KeyCharacteristicsCallbackResult result = null;
557         try {
558             mBinder.asBinder().linkToDeath(promise, 0);
559             error = mBinder.generateKey(promise, alias, args, entropy, uid, flags);
560             if (error != NO_ERROR) {
561                 Log.e(TAG, "generateKeyInternal failed on request " + error);
562                 return error;
563             }
564             result = interruptedPreservingGet(promise.getFuture());
565         } finally {
566             mBinder.asBinder().unlinkToDeath(promise, 0);
567         }
568 
569         error = result.getKeystoreResponse().getErrorCode();
570         if (error != NO_ERROR) {
571             Log.e(TAG, "generateKeyInternal failed on response " + error);
572             return error;
573         }
574         KeyCharacteristics characteristics = result.getKeyCharacteristics();
575         if (characteristics == null) {
576             Log.e(TAG, "generateKeyInternal got empty key cheractariestics " + error);
577             return SYSTEM_ERROR;
578         }
579         outCharacteristics.shallowCopyFrom(characteristics);
580         return NO_ERROR;
581     }
582 
generateKey(String alias, KeymasterArguments args, byte[] entropy, int uid, int flags, KeyCharacteristics outCharacteristics)583     public int generateKey(String alias, KeymasterArguments args, byte[] entropy, int uid,
584             int flags, KeyCharacteristics outCharacteristics) {
585         try {
586             entropy = entropy != null ? entropy : new byte[0];
587             args = args != null ? args : new KeymasterArguments();
588             int error = generateKeyInternal(alias, args, entropy, uid, flags, outCharacteristics);
589             if (error == KEY_ALREADY_EXISTS) {
590                 mBinder.del(alias, uid);
591                 error = generateKeyInternal(alias, args, entropy, uid, flags, outCharacteristics);
592             }
593             return error;
594         } catch (RemoteException e) {
595             Log.w(TAG, "Cannot connect to keystore", e);
596             return SYSTEM_ERROR;
597         } catch (ExecutionException e) {
598             Log.e(TAG, "generateKey completed with exception", e);
599             return SYSTEM_ERROR;
600         }
601     }
602 
generateKey(String alias, KeymasterArguments args, byte[] entropy, int flags, KeyCharacteristics outCharacteristics)603     public int generateKey(String alias, KeymasterArguments args, byte[] entropy, int flags,
604             KeyCharacteristics outCharacteristics) {
605         return generateKey(alias, args, entropy, UID_SELF, flags, outCharacteristics);
606     }
607 
getKeyCharacteristics(String alias, KeymasterBlob clientId, KeymasterBlob appId, int uid, KeyCharacteristics outCharacteristics)608     public int getKeyCharacteristics(String alias, KeymasterBlob clientId, KeymasterBlob appId,
609             int uid, KeyCharacteristics outCharacteristics) {
610         KeyCharacteristicsPromise promise = new KeyCharacteristicsPromise();
611         try {
612             mBinder.asBinder().linkToDeath(promise, 0);
613             clientId = clientId != null ? clientId : new KeymasterBlob(new byte[0]);
614             appId = appId != null ? appId : new KeymasterBlob(new byte[0]);
615 
616             int error = mBinder.getKeyCharacteristics(promise, alias, clientId, appId, uid);
617             if (error != NO_ERROR) return error;
618 
619             KeyCharacteristicsCallbackResult result = interruptedPreservingGet(promise.getFuture());
620             error = result.getKeystoreResponse().getErrorCode();
621             if (error != NO_ERROR) return error;
622 
623             KeyCharacteristics characteristics = result.getKeyCharacteristics();
624             if (characteristics == null) return SYSTEM_ERROR;
625             outCharacteristics.shallowCopyFrom(characteristics);
626             return NO_ERROR;
627         } catch (RemoteException e) {
628             Log.w(TAG, "Cannot connect to keystore", e);
629             return SYSTEM_ERROR;
630         } catch (ExecutionException e) {
631             Log.e(TAG, "GetKeyCharacteristics completed with exception", e);
632             return SYSTEM_ERROR;
633         } finally {
634             mBinder.asBinder().unlinkToDeath(promise, 0);
635         }
636     }
637 
getKeyCharacteristics(String alias, KeymasterBlob clientId, KeymasterBlob appId, KeyCharacteristics outCharacteristics)638     public int getKeyCharacteristics(String alias, KeymasterBlob clientId, KeymasterBlob appId,
639             KeyCharacteristics outCharacteristics) {
640         return getKeyCharacteristics(alias, clientId, appId, UID_SELF, outCharacteristics);
641     }
642 
importKeyInternal(String alias, KeymasterArguments args, int format, byte[] keyData, int uid, int flags, KeyCharacteristics outCharacteristics)643     private int importKeyInternal(String alias, KeymasterArguments args, int format, byte[] keyData,
644             int uid, int flags, KeyCharacteristics outCharacteristics)
645                     throws RemoteException, ExecutionException {
646         KeyCharacteristicsPromise promise = new KeyCharacteristicsPromise();
647         mBinder.asBinder().linkToDeath(promise, 0);
648         try {
649             int error = mBinder.importKey(promise, alias, args, format, keyData, uid, flags);
650             if (error != NO_ERROR) return error;
651 
652             KeyCharacteristicsCallbackResult result = interruptedPreservingGet(promise.getFuture());
653 
654             error = result.getKeystoreResponse().getErrorCode();
655             if (error != NO_ERROR) return error;
656 
657             KeyCharacteristics characteristics = result.getKeyCharacteristics();
658             if (characteristics == null) return SYSTEM_ERROR;
659             outCharacteristics.shallowCopyFrom(characteristics);
660             return NO_ERROR;
661         } finally {
662             mBinder.asBinder().unlinkToDeath(promise, 0);
663         }
664     }
665 
importKey(String alias, KeymasterArguments args, int format, byte[] keyData, int uid, int flags, KeyCharacteristics outCharacteristics)666     public int importKey(String alias, KeymasterArguments args, int format, byte[] keyData,
667             int uid, int flags, KeyCharacteristics outCharacteristics) {
668         try {
669             int error = importKeyInternal(alias, args, format, keyData, uid, flags,
670                     outCharacteristics);
671             if (error == KEY_ALREADY_EXISTS) {
672                 mBinder.del(alias, uid);
673                 error = importKeyInternal(alias, args, format, keyData, uid, flags,
674                         outCharacteristics);
675             }
676             return error;
677         } catch (RemoteException e) {
678             Log.w(TAG, "Cannot connect to keystore", e);
679             return SYSTEM_ERROR;
680         } catch (ExecutionException e) {
681             Log.e(TAG, "ImportKey completed with exception", e);
682             return SYSTEM_ERROR;
683         }
684     }
685 
importKey(String alias, KeymasterArguments args, int format, byte[] keyData, int flags, KeyCharacteristics outCharacteristics)686     public int importKey(String alias, KeymasterArguments args, int format, byte[] keyData,
687             int flags, KeyCharacteristics outCharacteristics) {
688         return importKey(alias, args, format, keyData, UID_SELF, flags, outCharacteristics);
689     }
690 
getAlgorithmFromPKCS8(byte[] keyData)691     private String getAlgorithmFromPKCS8(byte[] keyData) {
692         try {
693             final ASN1InputStream bIn = new ASN1InputStream(new ByteArrayInputStream(keyData));
694             final PrivateKeyInfo pki = PrivateKeyInfo.getInstance(bIn.readObject());
695             final String algOid = pki.getPrivateKeyAlgorithm().getAlgorithm().getId();
696             return new AlgorithmId(new ObjectIdentifier(algOid)).getName();
697         } catch (IOException e) {
698             Log.e(TAG, "getAlgorithmFromPKCS8 Failed to parse key data");
699             Log.e(TAG, Log.getStackTraceString(e));
700             return null;
701         }
702     }
703 
makeLegacyArguments(String algorithm)704     private KeymasterArguments makeLegacyArguments(String algorithm) {
705         KeymasterArguments args = new KeymasterArguments();
706         args.addEnum(KeymasterDefs.KM_TAG_ALGORITHM,
707                 KeyProperties.KeyAlgorithm.toKeymasterAsymmetricKeyAlgorithm(algorithm));
708         args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_SIGN);
709         args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_VERIFY);
710         args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_ENCRYPT);
711         args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_DECRYPT);
712         args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_NONE);
713         if (algorithm.equalsIgnoreCase(KeyProperties.KEY_ALGORITHM_RSA)) {
714             args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_RSA_OAEP);
715             args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_ENCRYPT);
716             args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_SIGN);
717             args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_RSA_PSS);
718         }
719         args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_NONE);
720         args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_MD5);
721         args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA1);
722         args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA_2_224);
723         args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA_2_256);
724         args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA_2_384);
725         args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA_2_512);
726         args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED);
727         args.addDate(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME, new Date(Long.MAX_VALUE));
728         args.addDate(KeymasterDefs.KM_TAG_USAGE_EXPIRE_DATETIME, new Date(Long.MAX_VALUE));
729         args.addDate(KeymasterDefs.KM_TAG_ACTIVE_DATETIME, new Date(0));
730         return args;
731     }
732 
importKey(String alias, byte[] keyData, int uid, int flags)733     public boolean importKey(String alias, byte[] keyData, int uid, int flags) {
734         String algorithm = getAlgorithmFromPKCS8(keyData);
735         if (algorithm == null) return false;
736         KeymasterArguments args = makeLegacyArguments(algorithm);
737         KeyCharacteristics out = new KeyCharacteristics();
738         int result =  importKey(alias, args, KeymasterDefs.KM_KEY_FORMAT_PKCS8, keyData, uid,
739                                 flags, out);
740         if (result != NO_ERROR) {
741             Log.e(TAG, Log.getStackTraceString(
742                     new KeyStoreException(result, "legacy key import failed")));
743             return false;
744         }
745         return true;
746     }
747 
importWrappedKeyInternal(String wrappedKeyAlias, byte[] wrappedKey, String wrappingKeyAlias, byte[] maskingKey, KeymasterArguments args, long rootSid, long fingerprintSid, KeyCharacteristics outCharacteristics)748     private int importWrappedKeyInternal(String wrappedKeyAlias, byte[] wrappedKey,
749             String wrappingKeyAlias,
750             byte[] maskingKey, KeymasterArguments args, long rootSid, long fingerprintSid,
751             KeyCharacteristics outCharacteristics)
752                     throws RemoteException, ExecutionException {
753         KeyCharacteristicsPromise promise = new KeyCharacteristicsPromise();
754         mBinder.asBinder().linkToDeath(promise, 0);
755         try {
756             int error = mBinder.importWrappedKey(promise, wrappedKeyAlias, wrappedKey,
757                     wrappingKeyAlias, maskingKey, args, rootSid, fingerprintSid);
758             if (error != NO_ERROR) return error;
759 
760             KeyCharacteristicsCallbackResult result = interruptedPreservingGet(promise.getFuture());
761 
762             error = result.getKeystoreResponse().getErrorCode();
763             if (error != NO_ERROR) return error;
764 
765             KeyCharacteristics characteristics = result.getKeyCharacteristics();
766             if (characteristics == null) return SYSTEM_ERROR;
767             outCharacteristics.shallowCopyFrom(characteristics);
768             return NO_ERROR;
769         } finally {
770             mBinder.asBinder().unlinkToDeath(promise, 0);
771         }
772     }
773 
importWrappedKey(String wrappedKeyAlias, byte[] wrappedKey, String wrappingKeyAlias, byte[] maskingKey, KeymasterArguments args, long rootSid, long fingerprintSid, int uid, KeyCharacteristics outCharacteristics)774     public int importWrappedKey(String wrappedKeyAlias, byte[] wrappedKey,
775             String wrappingKeyAlias,
776             byte[] maskingKey, KeymasterArguments args, long rootSid, long fingerprintSid, int uid,
777             KeyCharacteristics outCharacteristics) {
778         // TODO b/119217337 uid parameter gets silently ignored.
779         try {
780             int error = importWrappedKeyInternal(wrappedKeyAlias, wrappedKey, wrappingKeyAlias,
781                     maskingKey, args, rootSid, fingerprintSid, outCharacteristics);
782             if (error == KEY_ALREADY_EXISTS) {
783                 mBinder.del(wrappedKeyAlias, UID_SELF);
784                 error = importWrappedKeyInternal(wrappedKeyAlias, wrappedKey, wrappingKeyAlias,
785                         maskingKey, args, rootSid, fingerprintSid, outCharacteristics);
786             }
787             return error;
788         } catch (RemoteException e) {
789             Log.w(TAG, "Cannot connect to keystore", e);
790             return SYSTEM_ERROR;
791         } catch (ExecutionException e) {
792             Log.e(TAG, "ImportWrappedKey completed with exception", e);
793             return SYSTEM_ERROR;
794         }
795     }
796 
797     private class ExportKeyPromise
798             extends android.security.keystore.IKeystoreExportKeyCallback.Stub
799             implements IBinder.DeathRecipient {
800         final private CompletableFuture<ExportResult> future = new CompletableFuture<ExportResult>();
801         @Override
onFinished(ExportResult exportKeyResult)802         public void onFinished(ExportResult exportKeyResult) throws android.os.RemoteException {
803             future.complete(exportKeyResult);
804         }
getFuture()805         public final CompletableFuture<ExportResult> getFuture() {
806             return future;
807         }
808         @Override
binderDied()809         public void binderDied() {
810             future.completeExceptionally(new RemoteException("Keystore died"));
811         }
812     };
813 
exportKey(String alias, int format, KeymasterBlob clientId, KeymasterBlob appId, int uid)814     public ExportResult exportKey(String alias, int format, KeymasterBlob clientId,
815             KeymasterBlob appId, int uid) {
816         ExportKeyPromise promise = new ExportKeyPromise();
817         try {
818             mBinder.asBinder().linkToDeath(promise, 0);
819             clientId = clientId != null ? clientId : new KeymasterBlob(new byte[0]);
820             appId = appId != null ? appId : new KeymasterBlob(new byte[0]);
821             int error = mBinder.exportKey(promise, alias, format, clientId, appId, uid);
822             if (error == NO_ERROR) {
823                 return interruptedPreservingGet(promise.getFuture());
824             } else {
825                 return new ExportResult(error);
826             }
827         } catch (RemoteException e) {
828             Log.w(TAG, "Cannot connect to keystore", e);
829             return null;
830         } catch (ExecutionException e) {
831             Log.e(TAG, "ExportKey completed with exception", e);
832             return null;
833         } finally {
834             mBinder.asBinder().unlinkToDeath(promise, 0);
835         }
836     }
exportKey(String alias, int format, KeymasterBlob clientId, KeymasterBlob appId)837     public ExportResult exportKey(String alias, int format, KeymasterBlob clientId,
838             KeymasterBlob appId) {
839         return exportKey(alias, format, clientId, appId, UID_SELF);
840     }
841 
842     private class OperationPromise
843             extends android.security.keystore.IKeystoreOperationResultCallback.Stub
844             implements IBinder.DeathRecipient {
845         final private CompletableFuture<OperationResult> future = new CompletableFuture<OperationResult>();
846         @Override
onFinished(OperationResult operationResult)847         public void onFinished(OperationResult operationResult) throws android.os.RemoteException {
848             future.complete(operationResult);
849         }
getFuture()850         public final CompletableFuture<OperationResult> getFuture() {
851             return future;
852         }
853         @Override
binderDied()854         public void binderDied() {
855             future.completeExceptionally(new RemoteException("Keystore died"));
856         }
857     };
858 
begin(String alias, int purpose, boolean pruneable, KeymasterArguments args, byte[] entropy, int uid)859     public OperationResult begin(String alias, int purpose, boolean pruneable,
860             KeymasterArguments args, byte[] entropy, int uid) {
861         OperationPromise promise = new OperationPromise();
862         try {
863             mBinder.asBinder().linkToDeath(promise, 0);
864             args = args != null ? args : new KeymasterArguments();
865             entropy = entropy != null ? entropy : new byte[0];
866             int errorCode =  mBinder.begin(promise, getToken(), alias, purpose, pruneable, args,
867                                            entropy, uid);
868             if (errorCode == NO_ERROR) {
869                 return interruptedPreservingGet(promise.getFuture());
870             } else {
871                 return new OperationResult(errorCode);
872             }
873         } catch (RemoteException e) {
874             Log.w(TAG, "Cannot connect to keystore", e);
875             return null;
876         } catch (ExecutionException e) {
877             Log.e(TAG, "Begin completed with exception", e);
878             return null;
879         } finally {
880             mBinder.asBinder().unlinkToDeath(promise, 0);
881         }
882     }
883 
begin(String alias, int purpose, boolean pruneable, KeymasterArguments args, byte[] entropy)884     public OperationResult begin(String alias, int purpose, boolean pruneable,
885             KeymasterArguments args, byte[] entropy) {
886         entropy = entropy != null ? entropy : new byte[0];
887         args = args != null ? args : new KeymasterArguments();
888         return begin(alias, purpose, pruneable, args, entropy, UID_SELF);
889     }
890 
update(IBinder token, KeymasterArguments arguments, byte[] input)891     public OperationResult update(IBinder token, KeymasterArguments arguments, byte[] input) {
892         OperationPromise promise = new OperationPromise();
893         try {
894             mBinder.asBinder().linkToDeath(promise, 0);
895             arguments = arguments != null ? arguments : new KeymasterArguments();
896             input = input != null ? input : new byte[0];
897             int errorCode =  mBinder.update(promise, token, arguments, input);
898             if (errorCode == NO_ERROR) {
899                 return interruptedPreservingGet(promise.getFuture());
900             } else {
901                 return new OperationResult(errorCode);
902             }
903         } catch (RemoteException e) {
904             Log.w(TAG, "Cannot connect to keystore", e);
905             return null;
906         } catch (ExecutionException e) {
907             Log.e(TAG, "Update completed with exception", e);
908             return null;
909         } finally {
910             mBinder.asBinder().unlinkToDeath(promise, 0);
911         }
912     }
913 
914     /**
915      * Android KeyStore finish operation.
916      *
917      * @param token Authentication token.
918      * @param arguments Keymaster arguments
919      * @param input Optional additional input data.
920      * @param signature Optional signature to be verified.
921      * @param entropy Optional additional entropy
922      * @return OperationResult that will indicate success or error of the operation.
923      */
finish(IBinder token, KeymasterArguments arguments, byte[] input, byte[] signature, byte[] entropy)924     public OperationResult finish(IBinder token, KeymasterArguments arguments, byte[] input,
925             byte[] signature, byte[] entropy) {
926         OperationPromise promise = new OperationPromise();
927         try {
928             mBinder.asBinder().linkToDeath(promise, 0);
929             arguments = arguments != null ? arguments : new KeymasterArguments();
930             entropy = entropy != null ? entropy : new byte[0];
931             input = input != null ? input : new byte[0];
932             signature = signature != null ? signature : new byte[0];
933             int errorCode = mBinder.finish(promise, token, arguments, input, signature, entropy);
934             if (errorCode == NO_ERROR) {
935                 return interruptedPreservingGet(promise.getFuture());
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 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, null, 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 interruptedPreservingGet(promise.getFuture()).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 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 = interruptedPreservingGet(promise.getFuture());
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 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 = interruptedPreservingGet(promise.getFuture());
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 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 
interruptedPreservingGet(CompletableFuture<R> future)1416     private static <R> R interruptedPreservingGet(CompletableFuture<R> future)
1417             throws ExecutionException {
1418         boolean wasInterrupted = false;
1419         while (true) {
1420             try {
1421                 R result = future.get();
1422                 if (wasInterrupted) {
1423                     Thread.currentThread().interrupt();
1424                 }
1425                 return result;
1426             } catch (InterruptedException e) {
1427                 wasInterrupted = true;
1428             }
1429         }
1430     }
1431 }
1432