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.ActivityManager;
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.fingerprint.FingerprintManager;
26 import android.os.Binder;
27 import android.os.IBinder;
28 import android.os.Process;
29 import android.os.RemoteException;
30 import android.os.ServiceManager;
31 import android.os.UserHandle;
32 import android.security.keymaster.ExportResult;
33 import android.security.keymaster.KeyCharacteristics;
34 import android.security.keymaster.KeymasterArguments;
35 import android.security.keymaster.KeymasterBlob;
36 import android.security.keymaster.KeymasterCertificateChain;
37 import android.security.keymaster.KeymasterDefs;
38 import android.security.keymaster.OperationResult;
39 import android.security.keystore.KeyExpiredException;
40 import android.security.keystore.KeyNotYetValidException;
41 import android.security.keystore.KeyPermanentlyInvalidatedException;
42 import android.security.keystore.StrongBoxUnavailableException;
43 import android.security.keystore.UserNotAuthenticatedException;
44 import android.util.Log;
45 
46 import java.math.BigInteger;
47 import java.security.InvalidKeyException;
48 import java.util.List;
49 import java.util.Locale;
50 
51 /**
52  * @hide This should not be made public in its present form because it
53  * assumes that private and secret key bytes are available and would
54  * preclude the use of hardware crypto.
55  */
56 public class KeyStore {
57     private static final String TAG = "KeyStore";
58 
59     // ResponseCodes - see system/security/keystore/include/keystore/keystore.h
60     public static final int NO_ERROR = 1;
61     public static final int LOCKED = 2;
62     public static final int UNINITIALIZED = 3;
63     public static final int SYSTEM_ERROR = 4;
64     public static final int PROTOCOL_ERROR = 5;
65     public static final int PERMISSION_DENIED = 6;
66     public static final int KEY_NOT_FOUND = 7;
67     public static final int VALUE_CORRUPTED = 8;
68     public static final int UNDEFINED_ACTION = 9;
69     public static final int WRONG_PASSWORD = 10;
70     public static final int CANNOT_ATTEST_IDS = -66;
71     public static final int HARDWARE_TYPE_UNAVAILABLE = -68;
72 
73     /**
74      * Per operation authentication is needed before this operation is valid.
75      * This is returned from {@link #begin} when begin succeeds but the operation uses
76      * per-operation authentication and must authenticate before calling {@link #update} or
77      * {@link #finish}.
78      */
79     public static final int OP_AUTH_NEEDED = 15;
80 
81     // Used for UID field to indicate the calling UID.
82     public static final int UID_SELF = -1;
83 
84     // Flags for "put" "import" and "generate"
85     public static final int FLAG_NONE = 0;
86 
87     /**
88      * Indicates that this key (or key pair) must be encrypted at rest. This will protect the key
89      * (or key pair) with the secure lock screen credential (e.g., password, PIN, or pattern).
90      *
91      * <p>Note that this requires that the secure lock screen (e.g., password, PIN, pattern) is set
92      * up, otherwise key (or key pair) generation or import will fail. Moreover, this key (or key
93      * pair) will be deleted when the secure lock screen is disabled or reset (e.g., by the user or
94      * a Device Administrator). Finally, this key (or key pair) cannot be used until the user
95      * unlocks the secure lock screen after boot.
96      *
97      * @see KeyguardManager#isDeviceSecure()
98      */
99     public static final int FLAG_ENCRYPTED = 1;
100 
101     /**
102      * Select Software keymaster device, which as of this writing is the lowest security
103      * level available on an android device. If neither FLAG_STRONGBOX nor FLAG_SOFTWARE is provided
104      * A TEE based keymaster implementation is implied.
105      *
106      * Need to be in sync with KeyStoreFlag in system/security/keystore/include/keystore/keystore.h
107      * For historical reasons this corresponds to the KEYSTORE_FLAG_FALLBACK flag.
108      */
109     public static final int FLAG_SOFTWARE = 1 << 1;
110 
111     /**
112      * A private flag that's only available to system server to indicate that this key is part of
113      * device encryption flow so it receives special treatment from keystore. For example this key
114      * will not be super encrypted, and it will be stored separately under an unique UID instead
115      * of the caller UID i.e. SYSTEM.
116      *
117      * Need to be in sync with KeyStoreFlag in system/security/keystore/include/keystore/keystore.h
118      */
119     public static final int FLAG_CRITICAL_TO_DEVICE_ENCRYPTION = 1 << 3;
120 
121     /**
122      * Select Strongbox keymaster device, which as of this writing the the highest security level
123      * available an android devices. If neither FLAG_STRONGBOX nor FLAG_SOFTWARE is provided
124      * A TEE based keymaster implementation is implied.
125      *
126      * Need to be in sync with KeyStoreFlag in system/security/keystore/include/keystore/keystore.h
127      */
128     public static final int FLAG_STRONGBOX = 1 << 4;
129 
130     // States
131     public enum State { UNLOCKED, LOCKED, UNINITIALIZED };
132 
133     private int mError = NO_ERROR;
134 
135     private final IKeystoreService mBinder;
136     private final Context mContext;
137 
138     private IBinder mToken;
139 
KeyStore(IKeystoreService binder)140     private KeyStore(IKeystoreService binder) {
141         mBinder = binder;
142         mContext = getApplicationContext();
143     }
144 
getApplicationContext()145     public static Context getApplicationContext() {
146         Application application = ActivityThread.currentApplication();
147         if (application == null) {
148             throw new IllegalStateException(
149                     "Failed to obtain application Context from ActivityThread");
150         }
151         return application;
152     }
153 
getInstance()154     public static KeyStore getInstance() {
155         IKeystoreService keystore = IKeystoreService.Stub.asInterface(ServiceManager
156                 .getService("android.security.keystore"));
157         return new KeyStore(keystore);
158     }
159 
getToken()160     private synchronized IBinder getToken() {
161         if (mToken == null) {
162             mToken = new Binder();
163         }
164         return mToken;
165     }
166 
state(int userId)167     public State state(int userId) {
168         final int ret;
169         try {
170             ret = mBinder.getState(userId);
171         } catch (RemoteException e) {
172             Log.w(TAG, "Cannot connect to keystore", e);
173             throw new AssertionError(e);
174         }
175 
176         switch (ret) {
177             case NO_ERROR: return State.UNLOCKED;
178             case LOCKED: return State.LOCKED;
179             case UNINITIALIZED: return State.UNINITIALIZED;
180             default: throw new AssertionError(mError);
181         }
182     }
183 
state()184     public State state() {
185         return state(UserHandle.myUserId());
186     }
187 
isUnlocked()188     public boolean isUnlocked() {
189         return state() == State.UNLOCKED;
190     }
191 
get(String key, int uid)192     public byte[] get(String key, int uid) {
193         try {
194             key = key != null ? key : "";
195             return mBinder.get(key, uid);
196         } catch (RemoteException e) {
197             Log.w(TAG, "Cannot connect to keystore", e);
198             return null;
199         } catch (android.os.ServiceSpecificException e) {
200             Log.w(TAG, "KeyStore exception", e);
201             return null;
202         }
203     }
204 
get(String key)205     public byte[] get(String key) {
206         return get(key, UID_SELF);
207     }
208 
put(String key, byte[] value, int uid, int flags)209     public boolean put(String key, byte[] value, int uid, int flags) {
210         return insert(key, value, uid, flags) == NO_ERROR;
211     }
212 
insert(String key, byte[] value, int uid, int flags)213     public int insert(String key, byte[] value, int uid, int flags) {
214         try {
215             if (value == null) {
216                 value = new byte[0];
217             }
218             return mBinder.insert(key, value, uid, flags);
219         } catch (RemoteException e) {
220             Log.w(TAG, "Cannot connect to keystore", e);
221             return SYSTEM_ERROR;
222         }
223     }
224 
delete(String key, int uid)225     public boolean delete(String key, int uid) {
226         try {
227             int ret = mBinder.del(key, uid);
228             return (ret == NO_ERROR || ret == KEY_NOT_FOUND);
229         } catch (RemoteException e) {
230             Log.w(TAG, "Cannot connect to keystore", e);
231             return false;
232         }
233     }
234 
delete(String key)235     public boolean delete(String key) {
236         return delete(key, UID_SELF);
237     }
238 
contains(String key, int uid)239     public boolean contains(String key, int uid) {
240         try {
241             return mBinder.exist(key, uid) == NO_ERROR;
242         } catch (RemoteException e) {
243             Log.w(TAG, "Cannot connect to keystore", e);
244             return false;
245         }
246     }
247 
contains(String key)248     public boolean contains(String key) {
249         return contains(key, UID_SELF);
250     }
251 
252     /**
253      * List all entries in the keystore for {@code uid} starting with {@code prefix}.
254      */
list(String prefix, int uid)255     public String[] list(String prefix, int uid) {
256         try {
257             return mBinder.list(prefix, uid);
258         } catch (RemoteException e) {
259             Log.w(TAG, "Cannot connect to keystore", e);
260             return null;
261         } catch (android.os.ServiceSpecificException e) {
262             Log.w(TAG, "KeyStore exception", e);
263             return null;
264         }
265     }
266 
list(String prefix)267     public String[] list(String prefix) {
268         return list(prefix, UID_SELF);
269     }
270 
reset()271     public boolean reset() {
272         try {
273             return mBinder.reset() == NO_ERROR;
274         } catch (RemoteException e) {
275             Log.w(TAG, "Cannot connect to keystore", e);
276             return false;
277         }
278     }
279 
280     /**
281      * Attempt to lock the keystore for {@code user}.
282      *
283      * @param userId Android user to lock.
284      * @return whether {@code user}'s keystore was locked.
285      */
lock(int userId)286     public boolean lock(int userId) {
287         try {
288             return mBinder.lock(userId) == NO_ERROR;
289         } catch (RemoteException e) {
290             Log.w(TAG, "Cannot connect to keystore", e);
291             return false;
292         }
293     }
294 
lock()295     public boolean lock() {
296         return lock(UserHandle.myUserId());
297     }
298 
299     /**
300      * Attempt to unlock the keystore for {@code user} with the password {@code password}.
301      * This is required before keystore entries created with FLAG_ENCRYPTED can be accessed or
302      * created.
303      *
304      * @param userId Android user ID to operate on
305      * @param password user's keystore password. Should be the most recent value passed to
306      * {@link #onUserPasswordChanged} for the user.
307      *
308      * @return whether the keystore was unlocked.
309      */
unlock(int userId, String password)310     public boolean unlock(int userId, String password) {
311         try {
312             password = password != null ? password : "";
313             mError = mBinder.unlock(userId, password);
314             return mError == NO_ERROR;
315         } catch (RemoteException e) {
316             Log.w(TAG, "Cannot connect to keystore", e);
317             return false;
318         }
319     }
320 
unlock(String password)321     public boolean unlock(String password) {
322         return unlock(UserHandle.getUserId(Process.myUid()), password);
323     }
324 
325     /**
326      * Check if the keystore for {@code userId} is empty.
327      */
isEmpty(int userId)328     public boolean isEmpty(int userId) {
329         try {
330             return mBinder.isEmpty(userId) != 0;
331         } catch (RemoteException e) {
332             Log.w(TAG, "Cannot connect to keystore", e);
333             return false;
334         }
335     }
336 
isEmpty()337     public boolean isEmpty() {
338         return isEmpty(UserHandle.myUserId());
339     }
340 
generate(String key, int uid, int keyType, int keySize, int flags, byte[][] args)341     public boolean generate(String key, int uid, int keyType, int keySize, int flags,
342             byte[][] args) {
343         try {
344             return mBinder.generate(key, uid, keyType, keySize, flags,
345                     new KeystoreArguments(args)) == NO_ERROR;
346         } catch (RemoteException e) {
347             Log.w(TAG, "Cannot connect to keystore", e);
348             return false;
349         }
350     }
351 
importKey(String keyName, byte[] key, int uid, int flags)352     public boolean importKey(String keyName, byte[] key, int uid, int flags) {
353         try {
354             return mBinder.import_key(keyName, key, uid, flags) == NO_ERROR;
355         } catch (RemoteException e) {
356             Log.w(TAG, "Cannot connect to keystore", e);
357             return false;
358         }
359     }
360 
sign(String key, byte[] data)361     public byte[] sign(String key, byte[] data) {
362         try {
363             return mBinder.sign(key, data);
364         } catch (RemoteException e) {
365             Log.w(TAG, "Cannot connect to keystore", e);
366             return null;
367         } catch (android.os.ServiceSpecificException e) {
368             Log.w(TAG, "KeyStore exception", e);
369             return null;
370         }
371 
372     }
373 
verify(String key, byte[] data, byte[] signature)374     public boolean verify(String key, byte[] data, byte[] signature) {
375         try {
376             signature = signature != null ? signature : new byte[0];
377             return mBinder.verify(key, data, signature) == NO_ERROR;
378         } catch (RemoteException e) {
379             Log.w(TAG, "Cannot connect to keystore", e);
380             return false;
381         } catch (android.os.ServiceSpecificException e) {
382             Log.w(TAG, "KeyStore exception", e);
383             return false;
384         }
385 
386     }
387 
grant(String key, int uid)388     public String grant(String key, int uid) {
389         try {
390             String grantAlias =  mBinder.grant(key, uid);
391             if (grantAlias == "") return null;
392             return grantAlias;
393         } catch (RemoteException e) {
394             Log.w(TAG, "Cannot connect to keystore", e);
395             return null;
396         }
397     }
398 
ungrant(String key, int uid)399     public boolean ungrant(String key, int uid) {
400         try {
401             return mBinder.ungrant(key, uid) == NO_ERROR;
402         } catch (RemoteException e) {
403             Log.w(TAG, "Cannot connect to keystore", e);
404             return false;
405         }
406     }
407 
408     /**
409      * Returns the last modification time of the key in milliseconds since the
410      * epoch. Will return -1L if the key could not be found or other error.
411      */
getmtime(String key, int uid)412     public long getmtime(String key, int uid) {
413         try {
414             final long millis = mBinder.getmtime(key, uid);
415             if (millis == -1L) {
416                 return -1L;
417             }
418 
419             return millis * 1000L;
420         } catch (RemoteException e) {
421             Log.w(TAG, "Cannot connect to keystore", e);
422             return -1L;
423         }
424     }
425 
getmtime(String key)426     public long getmtime(String key) {
427         return getmtime(key, UID_SELF);
428     }
429 
430     // TODO: remove this when it's removed from Settings
isHardwareBacked()431     public boolean isHardwareBacked() {
432         return isHardwareBacked("RSA");
433     }
434 
isHardwareBacked(String keyType)435     public boolean isHardwareBacked(String keyType) {
436         try {
437             return mBinder.is_hardware_backed(keyType.toUpperCase(Locale.US)) == NO_ERROR;
438         } catch (RemoteException e) {
439             Log.w(TAG, "Cannot connect to keystore", e);
440             return false;
441         }
442     }
443 
clearUid(int uid)444     public boolean clearUid(int uid) {
445         try {
446             return mBinder.clear_uid(uid) == NO_ERROR;
447         } catch (RemoteException e) {
448             Log.w(TAG, "Cannot connect to keystore", e);
449             return false;
450         }
451     }
452 
getLastError()453     public int getLastError() {
454         return mError;
455     }
456 
addRngEntropy(byte[] data, int flags)457     public boolean addRngEntropy(byte[] data, int flags) {
458         try {
459             return mBinder.addRngEntropy(data, flags) == NO_ERROR;
460         } catch (RemoteException e) {
461             Log.w(TAG, "Cannot connect to keystore", e);
462             return false;
463         }
464     }
465 
generateKey(String alias, KeymasterArguments args, byte[] entropy, int uid, int flags, KeyCharacteristics outCharacteristics)466     public int generateKey(String alias, KeymasterArguments args, byte[] entropy, int uid,
467             int flags, KeyCharacteristics outCharacteristics) {
468         try {
469             entropy = entropy != null ? entropy : new byte[0];
470             args = args != null ? args : new KeymasterArguments();
471             return mBinder.generateKey(alias, args, entropy, uid, flags, outCharacteristics);
472         } catch (RemoteException e) {
473             Log.w(TAG, "Cannot connect to keystore", e);
474             return SYSTEM_ERROR;
475         }
476     }
477 
generateKey(String alias, KeymasterArguments args, byte[] entropy, int flags, KeyCharacteristics outCharacteristics)478     public int generateKey(String alias, KeymasterArguments args, byte[] entropy, int flags,
479             KeyCharacteristics outCharacteristics) {
480         return generateKey(alias, args, entropy, UID_SELF, flags, outCharacteristics);
481     }
482 
getKeyCharacteristics(String alias, KeymasterBlob clientId, KeymasterBlob appId, int uid, KeyCharacteristics outCharacteristics)483     public int getKeyCharacteristics(String alias, KeymasterBlob clientId, KeymasterBlob appId,
484             int uid, KeyCharacteristics outCharacteristics) {
485         try {
486             clientId = clientId != null ? clientId : new KeymasterBlob(new byte[0]);
487             appId = appId != null ? appId : new KeymasterBlob(new byte[0]);
488             return mBinder.getKeyCharacteristics(alias, clientId, appId, uid, outCharacteristics);
489         } catch (RemoteException e) {
490             Log.w(TAG, "Cannot connect to keystore", e);
491             return SYSTEM_ERROR;
492         }
493     }
494 
getKeyCharacteristics(String alias, KeymasterBlob clientId, KeymasterBlob appId, KeyCharacteristics outCharacteristics)495     public int getKeyCharacteristics(String alias, KeymasterBlob clientId, KeymasterBlob appId,
496             KeyCharacteristics outCharacteristics) {
497         return getKeyCharacteristics(alias, clientId, appId, UID_SELF, outCharacteristics);
498     }
499 
importKey(String alias, KeymasterArguments args, int format, byte[] keyData, int uid, int flags, KeyCharacteristics outCharacteristics)500     public int importKey(String alias, KeymasterArguments args, int format, byte[] keyData,
501             int uid, int flags, KeyCharacteristics outCharacteristics) {
502         try {
503             return mBinder.importKey(alias, args, format, keyData, uid, flags,
504                     outCharacteristics);
505         } catch (RemoteException e) {
506             Log.w(TAG, "Cannot connect to keystore", e);
507             return SYSTEM_ERROR;
508         }
509     }
510 
importKey(String alias, KeymasterArguments args, int format, byte[] keyData, int flags, KeyCharacteristics outCharacteristics)511     public int importKey(String alias, KeymasterArguments args, int format, byte[] keyData,
512             int flags, KeyCharacteristics outCharacteristics) {
513         return importKey(alias, args, format, keyData, UID_SELF, flags, outCharacteristics);
514     }
515 
importWrappedKey(String wrappedKeyAlias, byte[] wrappedKey, String wrappingKeyAlias, byte[] maskingKey, KeymasterArguments args, long rootSid, long fingerprintSid, int uid, KeyCharacteristics outCharacteristics)516     public int importWrappedKey(String wrappedKeyAlias, byte[] wrappedKey,
517             String wrappingKeyAlias,
518             byte[] maskingKey, KeymasterArguments args, long rootSid, long fingerprintSid, int uid,
519             KeyCharacteristics outCharacteristics) {
520         try {
521             return mBinder.importWrappedKey(wrappedKeyAlias, wrappedKey, wrappingKeyAlias,
522                     maskingKey, args, rootSid, fingerprintSid, outCharacteristics);
523         } catch (RemoteException e) {
524             Log.w(TAG, "Cannot connect to keystore", e);
525             return SYSTEM_ERROR;
526         }
527     }
528 
exportKey(String alias, int format, KeymasterBlob clientId, KeymasterBlob appId, int uid)529     public ExportResult exportKey(String alias, int format, KeymasterBlob clientId,
530             KeymasterBlob appId, int uid) {
531         try {
532             clientId = clientId != null ? clientId : new KeymasterBlob(new byte[0]);
533             appId = appId != null ? appId : new KeymasterBlob(new byte[0]);
534             return mBinder.exportKey(alias, format, clientId, appId, uid);
535         } catch (RemoteException e) {
536             Log.w(TAG, "Cannot connect to keystore", e);
537             return null;
538         }
539     }
exportKey(String alias, int format, KeymasterBlob clientId, KeymasterBlob appId)540     public ExportResult exportKey(String alias, int format, KeymasterBlob clientId,
541             KeymasterBlob appId) {
542         return exportKey(alias, format, clientId, appId, UID_SELF);
543     }
544 
begin(String alias, int purpose, boolean pruneable, KeymasterArguments args, byte[] entropy, int uid)545     public OperationResult begin(String alias, int purpose, boolean pruneable,
546             KeymasterArguments args, byte[] entropy, int uid) {
547         try {
548             args = args != null ? args : new KeymasterArguments();
549             entropy = entropy != null ? entropy : new byte[0];
550             return mBinder.begin(getToken(), alias, purpose, pruneable, args, entropy, uid);
551         } catch (RemoteException e) {
552             Log.w(TAG, "Cannot connect to keystore", e);
553             return null;
554         }
555     }
556 
begin(String alias, int purpose, boolean pruneable, KeymasterArguments args, byte[] entropy)557     public OperationResult begin(String alias, int purpose, boolean pruneable,
558             KeymasterArguments args, byte[] entropy) {
559         entropy = entropy != null ? entropy : new byte[0];
560         args = args != null ? args : new KeymasterArguments();
561         return begin(alias, purpose, pruneable, args, entropy, UID_SELF);
562     }
563 
update(IBinder token, KeymasterArguments arguments, byte[] input)564     public OperationResult update(IBinder token, KeymasterArguments arguments, byte[] input) {
565         try {
566             arguments = arguments != null ? arguments : new KeymasterArguments();
567             input = input != null ? input : new byte[0];
568             return mBinder.update(token, arguments, input);
569         } catch (RemoteException e) {
570             Log.w(TAG, "Cannot connect to keystore", e);
571             return null;
572         }
573     }
574 
finish(IBinder token, KeymasterArguments arguments, byte[] signature, byte[] entropy)575     public OperationResult finish(IBinder token, KeymasterArguments arguments, byte[] signature,
576             byte[] entropy) {
577         try {
578             arguments = arguments != null ? arguments : new KeymasterArguments();
579             entropy = entropy != null ? entropy : new byte[0];
580             signature = signature != null ? signature : new byte[0];
581             return mBinder.finish(token, arguments, signature, entropy);
582         } catch (RemoteException e) {
583             Log.w(TAG, "Cannot connect to keystore", e);
584             return null;
585         }
586     }
587 
finish(IBinder token, KeymasterArguments arguments, byte[] signature)588     public OperationResult finish(IBinder token, KeymasterArguments arguments, byte[] signature) {
589         return finish(token, arguments, signature, null);
590     }
591 
abort(IBinder token)592     public int abort(IBinder token) {
593         try {
594             return mBinder.abort(token);
595         } catch (RemoteException e) {
596             Log.w(TAG, "Cannot connect to keystore", e);
597             return SYSTEM_ERROR;
598         }
599     }
600 
601     /**
602      * Check if the operation referenced by {@code token} is currently authorized.
603      *
604      * @param token An operation token returned by a call to
605      * {@link #begin(String, int, boolean, KeymasterArguments, byte[], KeymasterArguments) begin}.
606      */
isOperationAuthorized(IBinder token)607     public boolean isOperationAuthorized(IBinder token) {
608         try {
609             return mBinder.isOperationAuthorized(token);
610         } catch (RemoteException e) {
611             Log.w(TAG, "Cannot connect to keystore", e);
612             return false;
613         }
614     }
615 
616     /**
617      * Add an authentication record to the keystore authorization table.
618      *
619      * @param authToken The packed bytes of a hw_auth_token_t to be provided to keymaster.
620      * @return {@code KeyStore.NO_ERROR} on success, otherwise an error value corresponding to
621      * a {@code KeymasterDefs.KM_ERROR_} value or {@code KeyStore} ResponseCode.
622      */
addAuthToken(byte[] authToken)623     public int addAuthToken(byte[] authToken) {
624         try {
625             return mBinder.addAuthToken(authToken);
626         } catch (RemoteException e) {
627             Log.w(TAG, "Cannot connect to keystore", e);
628             return SYSTEM_ERROR;
629         }
630     }
631 
632     /**
633      * Notify keystore that a user's password has changed.
634      *
635      * @param userId the user whose password changed.
636      * @param newPassword the new password or "" if the password was removed.
637      */
onUserPasswordChanged(int userId, String newPassword)638     public boolean onUserPasswordChanged(int userId, String newPassword) {
639         // Parcel.cpp doesn't support deserializing null strings and treats them as "". Make that
640         // explicit here.
641         if (newPassword == null) {
642             newPassword = "";
643         }
644         try {
645             return mBinder.onUserPasswordChanged(userId, newPassword) == NO_ERROR;
646         } catch (RemoteException e) {
647             Log.w(TAG, "Cannot connect to keystore", e);
648             return false;
649         }
650     }
651 
652     /**
653      * Notify keystore that a user was added.
654      *
655      * @param userId the new user.
656      * @param parentId the parent of the new user, or -1 if the user has no parent. If parentId is
657      * specified then the new user's keystore will be intialized with the same secure lockscreen
658      * password as the parent.
659      */
onUserAdded(int userId, int parentId)660     public void onUserAdded(int userId, int parentId) {
661         try {
662             mBinder.onUserAdded(userId, parentId);
663         } catch (RemoteException e) {
664             Log.w(TAG, "Cannot connect to keystore", e);
665         }
666     }
667 
668     /**
669      * Notify keystore that a user was added.
670      *
671      * @param userId the new user.
672      */
onUserAdded(int userId)673     public void onUserAdded(int userId) {
674         onUserAdded(userId, -1);
675     }
676 
677     /**
678      * Notify keystore that a user was removed.
679      *
680      * @param userId the removed user.
681      */
onUserRemoved(int userId)682     public void onUserRemoved(int userId) {
683         try {
684             mBinder.onUserRemoved(userId);
685         } catch (RemoteException e) {
686             Log.w(TAG, "Cannot connect to keystore", e);
687         }
688     }
689 
onUserPasswordChanged(String newPassword)690     public boolean onUserPasswordChanged(String newPassword) {
691         return onUserPasswordChanged(UserHandle.getUserId(Process.myUid()), newPassword);
692     }
693 
attestKey( String alias, KeymasterArguments params, KeymasterCertificateChain outChain)694     public int attestKey(
695             String alias, KeymasterArguments params, KeymasterCertificateChain outChain) {
696         try {
697             if (params == null) {
698                 params = new KeymasterArguments();
699             }
700             if (outChain == null) {
701                 outChain = new KeymasterCertificateChain();
702             }
703             return mBinder.attestKey(alias, params, outChain);
704         } catch (RemoteException e) {
705             Log.w(TAG, "Cannot connect to keystore", e);
706             return SYSTEM_ERROR;
707         }
708     }
709 
attestDeviceIds(KeymasterArguments params, KeymasterCertificateChain outChain)710     public int attestDeviceIds(KeymasterArguments params, KeymasterCertificateChain outChain) {
711         try {
712             if (params == null) {
713                 params = new KeymasterArguments();
714             }
715             if (outChain == null) {
716                 outChain = new KeymasterCertificateChain();
717             }
718             return mBinder.attestDeviceIds(params, outChain);
719         } catch (RemoteException e) {
720             Log.w(TAG, "Cannot connect to keystore", e);
721             return SYSTEM_ERROR;
722         }
723     }
724 
725     /**
726      * Notify keystore that the device went off-body.
727      */
onDeviceOffBody()728     public void onDeviceOffBody() {
729         try {
730             mBinder.onDeviceOffBody();
731         } catch (RemoteException e) {
732             Log.w(TAG, "Cannot connect to keystore", e);
733         }
734     }
735 
736     // Keep in sync with confirmationui/1.0/types.hal.
737     public static final int CONFIRMATIONUI_OK = 0;
738     public static final int CONFIRMATIONUI_CANCELED = 1;
739     public static final int CONFIRMATIONUI_ABORTED = 2;
740     public static final int CONFIRMATIONUI_OPERATION_PENDING = 3;
741     public static final int CONFIRMATIONUI_IGNORED = 4;
742     public static final int CONFIRMATIONUI_SYSTEM_ERROR = 5;
743     public static final int CONFIRMATIONUI_UNIMPLEMENTED = 6;
744     public static final int CONFIRMATIONUI_UNEXPECTED = 7;
745     public static final int CONFIRMATIONUI_UIERROR = 0x10000;
746     public static final int CONFIRMATIONUI_UIERROR_MISSING_GLYPH = 0x10001;
747     public static final int CONFIRMATIONUI_UIERROR_MESSAGE_TOO_LONG = 0x10002;
748     public static final int CONFIRMATIONUI_UIERROR_MALFORMED_UTF8_ENCODING = 0x10003;
749 
750     /**
751      * Requests keystore call into the confirmationui HAL to display a prompt.
752      *
753      * @param listener the binder to use for callbacks.
754      * @param promptText the prompt to display.
755      * @param extraData extra data / nonce from application.
756      * @param locale the locale as a BCP 47 langauge tag.
757      * @param uiOptionsAsFlags the UI options to use, as flags.
758      * @return one of the {@code CONFIRMATIONUI_*} constants, for
759      * example {@code KeyStore.CONFIRMATIONUI_OK}.
760      */
presentConfirmationPrompt(IBinder listener, String promptText, byte[] extraData, String locale, int uiOptionsAsFlags)761     public int presentConfirmationPrompt(IBinder listener, String promptText, byte[] extraData,
762                                          String locale, int uiOptionsAsFlags) {
763         try {
764             return mBinder.presentConfirmationPrompt(listener, promptText, extraData, locale,
765                                                      uiOptionsAsFlags);
766         } catch (RemoteException e) {
767             Log.w(TAG, "Cannot connect to keystore", e);
768             return CONFIRMATIONUI_SYSTEM_ERROR;
769         }
770     }
771 
772     /**
773      * Requests keystore call into the confirmationui HAL to cancel displaying a prompt.
774      *
775      * @param listener the binder passed to the {@link #presentConfirmationPrompt} method.
776      * @return one of the {@code CONFIRMATIONUI_*} constants, for
777      * example {@code KeyStore.CONFIRMATIONUI_OK}.
778      */
cancelConfirmationPrompt(IBinder listener)779     public int cancelConfirmationPrompt(IBinder listener) {
780         try {
781             return mBinder.cancelConfirmationPrompt(listener);
782         } catch (RemoteException e) {
783             Log.w(TAG, "Cannot connect to keystore", e);
784             return CONFIRMATIONUI_SYSTEM_ERROR;
785         }
786     }
787 
788     /**
789      * Requests keystore to check if the confirmationui HAL is available.
790      *
791      * @return whether the confirmationUI HAL is available.
792      */
isConfirmationPromptSupported()793     public boolean isConfirmationPromptSupported() {
794         try {
795             return mBinder.isConfirmationPromptSupported();
796         } catch (RemoteException e) {
797             Log.w(TAG, "Cannot connect to keystore", e);
798             return false;
799         }
800     }
801 
802     /**
803      * Returns a {@link KeyStoreException} corresponding to the provided keystore/keymaster error
804      * code.
805      */
getKeyStoreException(int errorCode)806     public static KeyStoreException getKeyStoreException(int errorCode) {
807         if (errorCode > 0) {
808             // KeyStore layer error
809             switch (errorCode) {
810                 case NO_ERROR:
811                     return new KeyStoreException(errorCode, "OK");
812                 case LOCKED:
813                     return new KeyStoreException(errorCode, "User authentication required");
814                 case UNINITIALIZED:
815                     return new KeyStoreException(errorCode, "Keystore not initialized");
816                 case SYSTEM_ERROR:
817                     return new KeyStoreException(errorCode, "System error");
818                 case PERMISSION_DENIED:
819                     return new KeyStoreException(errorCode, "Permission denied");
820                 case KEY_NOT_FOUND:
821                     return new KeyStoreException(errorCode, "Key not found");
822                 case VALUE_CORRUPTED:
823                     return new KeyStoreException(errorCode, "Key blob corrupted");
824                 case OP_AUTH_NEEDED:
825                     return new KeyStoreException(errorCode, "Operation requires authorization");
826                 default:
827                     return new KeyStoreException(errorCode, String.valueOf(errorCode));
828             }
829         } else {
830             // Keymaster layer error
831             switch (errorCode) {
832                 case KeymasterDefs.KM_ERROR_INVALID_AUTHORIZATION_TIMEOUT:
833                     // The name of this parameter significantly differs between Keymaster and
834                     // framework APIs. Use the framework wording to make life easier for developers.
835                     return new KeyStoreException(errorCode,
836                             "Invalid user authentication validity duration");
837                 default:
838                     return new KeyStoreException(errorCode,
839                             KeymasterDefs.getErrorMessage(errorCode));
840             }
841         }
842     }
843 
844     /**
845      * Returns an {@link InvalidKeyException} corresponding to the provided
846      * {@link KeyStoreException}.
847      */
getInvalidKeyException( String keystoreKeyAlias, int uid, KeyStoreException e)848     public InvalidKeyException getInvalidKeyException(
849             String keystoreKeyAlias, int uid, KeyStoreException e) {
850         switch (e.getErrorCode()) {
851             case LOCKED:
852                 return new UserNotAuthenticatedException();
853             case KeymasterDefs.KM_ERROR_KEY_EXPIRED:
854                 return new KeyExpiredException();
855             case KeymasterDefs.KM_ERROR_KEY_NOT_YET_VALID:
856                 return new KeyNotYetValidException();
857             case KeymasterDefs.KM_ERROR_KEY_USER_NOT_AUTHENTICATED:
858             case OP_AUTH_NEEDED:
859             {
860                 // We now need to determine whether the key/operation can become usable if user
861                 // authentication is performed, or whether it can never become usable again.
862                 // User authentication requirements are contained in the key's characteristics. We
863                 // need to check whether these requirements can be be satisfied by asking the user
864                 // to authenticate.
865                 KeyCharacteristics keyCharacteristics = new KeyCharacteristics();
866                 int getKeyCharacteristicsErrorCode =
867                         getKeyCharacteristics(keystoreKeyAlias, null, null, uid,
868                                 keyCharacteristics);
869                 if (getKeyCharacteristicsErrorCode != NO_ERROR) {
870                     return new InvalidKeyException(
871                             "Failed to obtained key characteristics",
872                             getKeyStoreException(getKeyCharacteristicsErrorCode));
873                 }
874                 List<BigInteger> keySids =
875                         keyCharacteristics.getUnsignedLongs(KeymasterDefs.KM_TAG_USER_SECURE_ID);
876                 if (keySids.isEmpty()) {
877                     // Key is not bound to any SIDs -- no amount of authentication will help here.
878                     return new KeyPermanentlyInvalidatedException();
879                 }
880                 long rootSid = GateKeeper.getSecureUserId();
881                 if ((rootSid != 0) && (keySids.contains(KeymasterArguments.toUint64(rootSid)))) {
882                     // One of the key's SIDs is the current root SID -- user can be authenticated
883                     // against that SID.
884                     return new UserNotAuthenticatedException();
885                 }
886 
887                 long fingerprintOnlySid = getFingerprintOnlySid();
888                 if ((fingerprintOnlySid != 0)
889                         && (keySids.contains(KeymasterArguments.toUint64(fingerprintOnlySid)))) {
890                     // One of the key's SIDs is the current fingerprint SID -- user can be
891                     // authenticated against that SID.
892                     return new UserNotAuthenticatedException();
893                 }
894 
895                 // None of the key's SIDs can ever be authenticated
896                 return new KeyPermanentlyInvalidatedException();
897             }
898             case UNINITIALIZED:
899                 return new KeyPermanentlyInvalidatedException();
900             default:
901                 return new InvalidKeyException("Keystore operation failed", e);
902         }
903     }
904 
getFingerprintOnlySid()905     private long getFingerprintOnlySid() {
906         final PackageManager packageManager = mContext.getPackageManager();
907         if (!packageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) {
908             return 0;
909         }
910         FingerprintManager fingerprintManager = mContext.getSystemService(FingerprintManager.class);
911         if (fingerprintManager == null) {
912             return 0;
913         }
914 
915         // TODO: Restore USE_FINGERPRINT permission check in
916         // FingerprintManager.getAuthenticatorId once the ID is no longer needed here.
917         return fingerprintManager.getAuthenticatorId();
918     }
919 
920     /**
921      * Returns an {@link InvalidKeyException} corresponding to the provided keystore/keymaster error
922      * code.
923      */
getInvalidKeyException(String keystoreKeyAlias, int uid, int errorCode)924     public InvalidKeyException getInvalidKeyException(String keystoreKeyAlias, int uid,
925             int errorCode) {
926         return getInvalidKeyException(keystoreKeyAlias, uid, getKeyStoreException(errorCode));
927     }
928 }
929