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 
23 import android.content.Context;
24 import android.hardware.fingerprint.FingerprintManager;
25 import android.os.Binder;
26 import android.os.IBinder;
27 import android.os.Process;
28 import android.os.RemoteException;
29 import android.os.ServiceManager;
30 import android.os.UserHandle;
31 import android.security.keymaster.ExportResult;
32 import android.security.keymaster.KeyCharacteristics;
33 import android.security.keymaster.KeymasterArguments;
34 import android.security.keymaster.KeymasterBlob;
35 import android.security.keymaster.KeymasterDefs;
36 import android.security.keymaster.OperationResult;
37 import android.security.keystore.KeyExpiredException;
38 import android.security.keystore.KeyNotYetValidException;
39 import android.security.keystore.KeyPermanentlyInvalidatedException;
40 import android.security.keystore.UserNotAuthenticatedException;
41 import android.util.Log;
42 
43 import java.math.BigInteger;
44 import java.security.InvalidKeyException;
45 import java.util.List;
46 import java.util.Locale;
47 
48 /**
49  * @hide This should not be made public in its present form because it
50  * assumes that private and secret key bytes are available and would
51  * preclude the use of hardware crypto.
52  */
53 public class KeyStore {
54     private static final String TAG = "KeyStore";
55 
56     // ResponseCodes
57     public static final int NO_ERROR = 1;
58     public static final int LOCKED = 2;
59     public static final int UNINITIALIZED = 3;
60     public static final int SYSTEM_ERROR = 4;
61     public static final int PROTOCOL_ERROR = 5;
62     public static final int PERMISSION_DENIED = 6;
63     public static final int KEY_NOT_FOUND = 7;
64     public static final int VALUE_CORRUPTED = 8;
65     public static final int UNDEFINED_ACTION = 9;
66     public static final int WRONG_PASSWORD = 10;
67 
68     /**
69      * Per operation authentication is needed before this operation is valid.
70      * This is returned from {@link #begin} when begin succeeds but the operation uses
71      * per-operation authentication and must authenticate before calling {@link #update} or
72      * {@link #finish}.
73      */
74     public static final int OP_AUTH_NEEDED = 15;
75 
76     // Used for UID field to indicate the calling UID.
77     public static final int UID_SELF = -1;
78 
79     // Flags for "put" "import" and "generate"
80     public static final int FLAG_NONE = 0;
81 
82     /**
83      * Indicates that this key (or key pair) must be encrypted at rest. This will protect the key
84      * (or key pair) with the secure lock screen credential (e.g., password, PIN, or pattern).
85      *
86      * <p>Note that this requires that the secure lock screen (e.g., password, PIN, pattern) is set
87      * up, otherwise key (or key pair) generation or import will fail. Moreover, this key (or key
88      * pair) will be deleted when the secure lock screen is disabled or reset (e.g., by the user or
89      * a Device Administrator). Finally, this key (or key pair) cannot be used until the user
90      * unlocks the secure lock screen after boot.
91      *
92      * @see KeyguardManager#isDeviceSecure()
93      */
94     public static final int FLAG_ENCRYPTED = 1;
95 
96     // States
97     public enum State { UNLOCKED, LOCKED, UNINITIALIZED };
98 
99     private int mError = NO_ERROR;
100 
101     private final IKeystoreService mBinder;
102     private final Context mContext;
103 
104     private IBinder mToken;
105 
KeyStore(IKeystoreService binder)106     private KeyStore(IKeystoreService binder) {
107         mBinder = binder;
108         mContext = getApplicationContext();
109     }
110 
getApplicationContext()111     public static Context getApplicationContext() {
112         Application application = ActivityThread.currentApplication();
113         if (application == null) {
114             throw new IllegalStateException(
115                     "Failed to obtain application Context from ActivityThread");
116         }
117         return application;
118     }
119 
getInstance()120     public static KeyStore getInstance() {
121         IKeystoreService keystore = IKeystoreService.Stub.asInterface(ServiceManager
122                 .getService("android.security.keystore"));
123         return new KeyStore(keystore);
124     }
125 
getToken()126     private synchronized IBinder getToken() {
127         if (mToken == null) {
128             mToken = new Binder();
129         }
130         return mToken;
131     }
132 
state(int userId)133     public State state(int userId) {
134         final int ret;
135         try {
136             ret = mBinder.getState(userId);
137         } catch (RemoteException e) {
138             Log.w(TAG, "Cannot connect to keystore", e);
139             throw new AssertionError(e);
140         }
141 
142         switch (ret) {
143             case NO_ERROR: return State.UNLOCKED;
144             case LOCKED: return State.LOCKED;
145             case UNINITIALIZED: return State.UNINITIALIZED;
146             default: throw new AssertionError(mError);
147         }
148     }
149 
state()150     public State state() {
151         return state(UserHandle.myUserId());
152     }
153 
isUnlocked()154     public boolean isUnlocked() {
155         return state() == State.UNLOCKED;
156     }
157 
get(String key)158     public byte[] get(String key) {
159         try {
160             return mBinder.get(key);
161         } catch (RemoteException e) {
162             Log.w(TAG, "Cannot connect to keystore", e);
163             return null;
164         }
165     }
166 
put(String key, byte[] value, int uid, int flags)167     public boolean put(String key, byte[] value, int uid, int flags) {
168         return insert(key, value, uid, flags) == NO_ERROR;
169     }
170 
insert(String key, byte[] value, int uid, int flags)171     public int insert(String key, byte[] value, int uid, int flags) {
172         try {
173             return mBinder.insert(key, value, uid, flags);
174         } catch (RemoteException e) {
175             Log.w(TAG, "Cannot connect to keystore", e);
176             return SYSTEM_ERROR;
177         }
178     }
179 
delete(String key, int uid)180     public boolean delete(String key, int uid) {
181         try {
182             return mBinder.del(key, uid) == NO_ERROR;
183         } catch (RemoteException e) {
184             Log.w(TAG, "Cannot connect to keystore", e);
185             return false;
186         }
187     }
188 
delete(String key)189     public boolean delete(String key) {
190         return delete(key, UID_SELF);
191     }
192 
contains(String key, int uid)193     public boolean contains(String key, int uid) {
194         try {
195             return mBinder.exist(key, uid) == NO_ERROR;
196         } catch (RemoteException e) {
197             Log.w(TAG, "Cannot connect to keystore", e);
198             return false;
199         }
200     }
201 
contains(String key)202     public boolean contains(String key) {
203         return contains(key, UID_SELF);
204     }
205 
206     /**
207      * List all entries in the keystore for {@code uid} starting with {@code prefix}.
208      */
list(String prefix, int uid)209     public String[] list(String prefix, int uid) {
210         try {
211             return mBinder.list(prefix, uid);
212         } catch (RemoteException e) {
213             Log.w(TAG, "Cannot connect to keystore", e);
214             return null;
215         }
216     }
217 
list(String prefix)218     public String[] list(String prefix) {
219         return list(prefix, UID_SELF);
220     }
221 
reset()222     public boolean reset() {
223         try {
224             return mBinder.reset() == NO_ERROR;
225         } catch (RemoteException e) {
226             Log.w(TAG, "Cannot connect to keystore", e);
227             return false;
228         }
229     }
230 
231     /**
232      * Attempt to lock the keystore for {@code user}.
233      *
234      * @param user Android user to lock.
235      * @return whether {@code user}'s keystore was locked.
236      */
lock(int userId)237     public boolean lock(int userId) {
238         try {
239             return mBinder.lock(userId) == NO_ERROR;
240         } catch (RemoteException e) {
241             Log.w(TAG, "Cannot connect to keystore", e);
242             return false;
243         }
244     }
245 
lock()246     public boolean lock() {
247         return lock(UserHandle.myUserId());
248     }
249 
250     /**
251      * Attempt to unlock the keystore for {@code user} with the password {@code password}.
252      * This is required before keystore entries created with FLAG_ENCRYPTED can be accessed or
253      * created.
254      *
255      * @param user Android user ID to operate on
256      * @param password user's keystore password. Should be the most recent value passed to
257      * {@link #onUserPasswordChanged} for the user.
258      *
259      * @return whether the keystore was unlocked.
260      */
unlock(int userId, String password)261     public boolean unlock(int userId, String password) {
262         try {
263             mError = mBinder.unlock(userId, password);
264             return mError == NO_ERROR;
265         } catch (RemoteException e) {
266             Log.w(TAG, "Cannot connect to keystore", e);
267             return false;
268         }
269     }
270 
unlock(String password)271     public boolean unlock(String password) {
272         return unlock(UserHandle.getUserId(Process.myUid()), password);
273     }
274 
275     /**
276      * Check if the keystore for {@code userId} is empty.
277      */
isEmpty(int userId)278     public boolean isEmpty(int userId) {
279         try {
280             return mBinder.isEmpty(userId) != 0;
281         } catch (RemoteException e) {
282             Log.w(TAG, "Cannot connect to keystore", e);
283             return false;
284         }
285     }
286 
isEmpty()287     public boolean isEmpty() {
288         return isEmpty(UserHandle.myUserId());
289     }
290 
generate(String key, int uid, int keyType, int keySize, int flags, byte[][] args)291     public boolean generate(String key, int uid, int keyType, int keySize, int flags,
292             byte[][] args) {
293         try {
294             return mBinder.generate(key, uid, keyType, keySize, flags,
295                     new KeystoreArguments(args)) == NO_ERROR;
296         } catch (RemoteException e) {
297             Log.w(TAG, "Cannot connect to keystore", e);
298             return false;
299         }
300     }
301 
importKey(String keyName, byte[] key, int uid, int flags)302     public boolean importKey(String keyName, byte[] key, int uid, int flags) {
303         try {
304             return mBinder.import_key(keyName, key, uid, flags) == NO_ERROR;
305         } catch (RemoteException e) {
306             Log.w(TAG, "Cannot connect to keystore", e);
307             return false;
308         }
309     }
310 
sign(String key, byte[] data)311     public byte[] sign(String key, byte[] data) {
312         try {
313             return mBinder.sign(key, data);
314         } catch (RemoteException e) {
315             Log.w(TAG, "Cannot connect to keystore", e);
316             return null;
317         }
318     }
319 
verify(String key, byte[] data, byte[] signature)320     public boolean verify(String key, byte[] data, byte[] signature) {
321         try {
322             return mBinder.verify(key, data, signature) == NO_ERROR;
323         } catch (RemoteException e) {
324             Log.w(TAG, "Cannot connect to keystore", e);
325             return false;
326         }
327     }
328 
grant(String key, int uid)329     public boolean grant(String key, int uid) {
330         try {
331             return mBinder.grant(key, uid) == NO_ERROR;
332         } catch (RemoteException e) {
333             Log.w(TAG, "Cannot connect to keystore", e);
334             return false;
335         }
336     }
337 
ungrant(String key, int uid)338     public boolean ungrant(String key, int uid) {
339         try {
340             return mBinder.ungrant(key, uid) == NO_ERROR;
341         } catch (RemoteException e) {
342             Log.w(TAG, "Cannot connect to keystore", e);
343             return false;
344         }
345     }
346 
347     /**
348      * Returns the last modification time of the key in milliseconds since the
349      * epoch. Will return -1L if the key could not be found or other error.
350      */
getmtime(String key)351     public long getmtime(String key) {
352         try {
353             final long millis = mBinder.getmtime(key);
354             if (millis == -1L) {
355                 return -1L;
356             }
357 
358             return millis * 1000L;
359         } catch (RemoteException e) {
360             Log.w(TAG, "Cannot connect to keystore", e);
361             return -1L;
362         }
363     }
364 
duplicate(String srcKey, int srcUid, String destKey, int destUid)365     public boolean duplicate(String srcKey, int srcUid, String destKey, int destUid) {
366         try {
367             return mBinder.duplicate(srcKey, srcUid, destKey, destUid) == NO_ERROR;
368         } catch (RemoteException e) {
369             Log.w(TAG, "Cannot connect to keystore", e);
370             return false;
371         }
372     }
373 
374     // TODO: remove this when it's removed from Settings
isHardwareBacked()375     public boolean isHardwareBacked() {
376         return isHardwareBacked("RSA");
377     }
378 
isHardwareBacked(String keyType)379     public boolean isHardwareBacked(String keyType) {
380         try {
381             return mBinder.is_hardware_backed(keyType.toUpperCase(Locale.US)) == NO_ERROR;
382         } catch (RemoteException e) {
383             Log.w(TAG, "Cannot connect to keystore", e);
384             return false;
385         }
386     }
387 
clearUid(int uid)388     public boolean clearUid(int uid) {
389         try {
390             return mBinder.clear_uid(uid) == NO_ERROR;
391         } catch (RemoteException e) {
392             Log.w(TAG, "Cannot connect to keystore", e);
393             return false;
394         }
395     }
396 
getLastError()397     public int getLastError() {
398         return mError;
399     }
400 
addRngEntropy(byte[] data)401     public boolean addRngEntropy(byte[] data) {
402         try {
403             return mBinder.addRngEntropy(data) == NO_ERROR;
404         } catch (RemoteException e) {
405             Log.w(TAG, "Cannot connect to keystore", e);
406             return false;
407         }
408     }
409 
generateKey(String alias, KeymasterArguments args, byte[] entropy, int uid, int flags, KeyCharacteristics outCharacteristics)410     public int generateKey(String alias, KeymasterArguments args, byte[] entropy, int uid,
411             int flags, KeyCharacteristics outCharacteristics) {
412         try {
413             return mBinder.generateKey(alias, args, entropy, uid, flags, outCharacteristics);
414         } catch (RemoteException e) {
415             Log.w(TAG, "Cannot connect to keystore", e);
416             return SYSTEM_ERROR;
417         }
418     }
419 
generateKey(String alias, KeymasterArguments args, byte[] entropy, int flags, KeyCharacteristics outCharacteristics)420     public int generateKey(String alias, KeymasterArguments args, byte[] entropy, int flags,
421             KeyCharacteristics outCharacteristics) {
422         return generateKey(alias, args, entropy, UID_SELF, flags, outCharacteristics);
423     }
424 
getKeyCharacteristics(String alias, KeymasterBlob clientId, KeymasterBlob appId, KeyCharacteristics outCharacteristics)425     public int getKeyCharacteristics(String alias, KeymasterBlob clientId, KeymasterBlob appId,
426             KeyCharacteristics outCharacteristics) {
427         try {
428             return mBinder.getKeyCharacteristics(alias, clientId, appId, outCharacteristics);
429         } catch (RemoteException e) {
430             Log.w(TAG, "Cannot connect to keystore", e);
431             return SYSTEM_ERROR;
432         }
433     }
434 
importKey(String alias, KeymasterArguments args, int format, byte[] keyData, int uid, int flags, KeyCharacteristics outCharacteristics)435     public int importKey(String alias, KeymasterArguments args, int format, byte[] keyData,
436             int uid, int flags, KeyCharacteristics outCharacteristics) {
437         try {
438             return mBinder.importKey(alias, args, format, keyData, uid, flags,
439                     outCharacteristics);
440         } catch (RemoteException e) {
441             Log.w(TAG, "Cannot connect to keystore", e);
442             return SYSTEM_ERROR;
443         }
444     }
445 
importKey(String alias, KeymasterArguments args, int format, byte[] keyData, int flags, KeyCharacteristics outCharacteristics)446     public int importKey(String alias, KeymasterArguments args, int format, byte[] keyData,
447             int flags, KeyCharacteristics outCharacteristics) {
448         return importKey(alias, args, format, keyData, UID_SELF, flags, outCharacteristics);
449     }
450 
exportKey(String alias, int format, KeymasterBlob clientId, KeymasterBlob appId)451     public ExportResult exportKey(String alias, int format, KeymasterBlob clientId,
452             KeymasterBlob appId) {
453         try {
454             return mBinder.exportKey(alias, format, clientId, appId);
455         } catch (RemoteException e) {
456             Log.w(TAG, "Cannot connect to keystore", e);
457             return null;
458         }
459     }
460 
begin(String alias, int purpose, boolean pruneable, KeymasterArguments args, byte[] entropy)461     public OperationResult begin(String alias, int purpose, boolean pruneable,
462             KeymasterArguments args, byte[] entropy) {
463         try {
464             return mBinder.begin(getToken(), alias, purpose, pruneable, args, entropy);
465         } catch (RemoteException e) {
466             Log.w(TAG, "Cannot connect to keystore", e);
467             return null;
468         }
469     }
470 
update(IBinder token, KeymasterArguments arguments, byte[] input)471     public OperationResult update(IBinder token, KeymasterArguments arguments, byte[] input) {
472         try {
473             return mBinder.update(token, arguments, input);
474         } catch (RemoteException e) {
475             Log.w(TAG, "Cannot connect to keystore", e);
476             return null;
477         }
478     }
479 
finish(IBinder token, KeymasterArguments arguments, byte[] signature, byte[] entropy)480     public OperationResult finish(IBinder token, KeymasterArguments arguments, byte[] signature,
481             byte[] entropy) {
482         try {
483             return mBinder.finish(token, arguments, signature, entropy);
484         } catch (RemoteException e) {
485             Log.w(TAG, "Cannot connect to keystore", e);
486             return null;
487         }
488     }
489 
finish(IBinder token, KeymasterArguments arguments, byte[] signature)490     public OperationResult finish(IBinder token, KeymasterArguments arguments, byte[] signature) {
491         return finish(token, arguments, signature, null);
492     }
493 
abort(IBinder token)494     public int abort(IBinder token) {
495         try {
496             return mBinder.abort(token);
497         } catch (RemoteException e) {
498             Log.w(TAG, "Cannot connect to keystore", e);
499             return SYSTEM_ERROR;
500         }
501     }
502 
503     /**
504      * Check if the operation referenced by {@code token} is currently authorized.
505      *
506      * @param token An operation token returned by a call to
507      * {@link #begin(String, int, boolean, KeymasterArguments, byte[], KeymasterArguments) begin}.
508      */
isOperationAuthorized(IBinder token)509     public boolean isOperationAuthorized(IBinder token) {
510         try {
511             return mBinder.isOperationAuthorized(token);
512         } catch (RemoteException e) {
513             Log.w(TAG, "Cannot connect to keystore", e);
514             return false;
515         }
516     }
517 
518     /**
519      * Add an authentication record to the keystore authorization table.
520      *
521      * @param authToken The packed bytes of a hw_auth_token_t to be provided to keymaster.
522      * @return {@code KeyStore.NO_ERROR} on success, otherwise an error value corresponding to
523      * a {@code KeymasterDefs.KM_ERROR_} value or {@code KeyStore} ResponseCode.
524      */
addAuthToken(byte[] authToken)525     public int addAuthToken(byte[] authToken) {
526         try {
527             return mBinder.addAuthToken(authToken);
528         } catch (RemoteException e) {
529             Log.w(TAG, "Cannot connect to keystore", e);
530             return SYSTEM_ERROR;
531         }
532     }
533 
534     /**
535      * Notify keystore that a user's password has changed.
536      *
537      * @param userId the user whose password changed.
538      * @param newPassword the new password or "" if the password was removed.
539      */
onUserPasswordChanged(int userId, String newPassword)540     public boolean onUserPasswordChanged(int userId, String newPassword) {
541         // Parcel.cpp doesn't support deserializing null strings and treats them as "". Make that
542         // explicit here.
543         if (newPassword == null) {
544             newPassword = "";
545         }
546         try {
547             return mBinder.onUserPasswordChanged(userId, newPassword) == NO_ERROR;
548         } catch (RemoteException e) {
549             Log.w(TAG, "Cannot connect to keystore", e);
550             return false;
551         }
552     }
553 
554     /**
555      * Notify keystore that a user was added.
556      *
557      * @param userId the new user.
558      * @param parentId the parent of the new user, or -1 if the user has no parent. If parentId is
559      * specified then the new user's keystore will be intialized with the same secure lockscreen
560      * password as the parent.
561      */
onUserAdded(int userId, int parentId)562     public void onUserAdded(int userId, int parentId) {
563         try {
564             mBinder.onUserAdded(userId, parentId);
565         } catch (RemoteException e) {
566             Log.w(TAG, "Cannot connect to keystore", e);
567         }
568     }
569 
570     /**
571      * Notify keystore that a user was added.
572      *
573      * @param userId the new user.
574      */
onUserAdded(int userId)575     public void onUserAdded(int userId) {
576         onUserAdded(userId, -1);
577     }
578 
579     /**
580      * Notify keystore that a user was removed.
581      *
582      * @param userId the removed user.
583      */
onUserRemoved(int userId)584     public void onUserRemoved(int userId) {
585         try {
586             mBinder.onUserRemoved(userId);
587         } catch (RemoteException e) {
588             Log.w(TAG, "Cannot connect to keystore", e);
589         }
590     }
591 
onUserPasswordChanged(String newPassword)592     public boolean onUserPasswordChanged(String newPassword) {
593         return onUserPasswordChanged(UserHandle.getUserId(Process.myUid()), newPassword);
594     }
595 
596     /**
597      * Returns a {@link KeyStoreException} corresponding to the provided keystore/keymaster error
598      * code.
599      */
getKeyStoreException(int errorCode)600     public static KeyStoreException getKeyStoreException(int errorCode) {
601         if (errorCode > 0) {
602             // KeyStore layer error
603             switch (errorCode) {
604                 case NO_ERROR:
605                     return new KeyStoreException(errorCode, "OK");
606                 case LOCKED:
607                     return new KeyStoreException(errorCode, "User authentication required");
608                 case UNINITIALIZED:
609                     return new KeyStoreException(errorCode, "Keystore not initialized");
610                 case SYSTEM_ERROR:
611                     return new KeyStoreException(errorCode, "System error");
612                 case PERMISSION_DENIED:
613                     return new KeyStoreException(errorCode, "Permission denied");
614                 case KEY_NOT_FOUND:
615                     return new KeyStoreException(errorCode, "Key not found");
616                 case VALUE_CORRUPTED:
617                     return new KeyStoreException(errorCode, "Key blob corrupted");
618                 case OP_AUTH_NEEDED:
619                     return new KeyStoreException(errorCode, "Operation requires authorization");
620                 default:
621                     return new KeyStoreException(errorCode, String.valueOf(errorCode));
622             }
623         } else {
624             // Keymaster layer error
625             switch (errorCode) {
626                 case KeymasterDefs.KM_ERROR_INVALID_AUTHORIZATION_TIMEOUT:
627                     // The name of this parameter significantly differs between Keymaster and
628                     // framework APIs. Use the framework wording to make life easier for developers.
629                     return new KeyStoreException(errorCode,
630                             "Invalid user authentication validity duration");
631                 default:
632                     return new KeyStoreException(errorCode,
633                             KeymasterDefs.getErrorMessage(errorCode));
634             }
635         }
636     }
637 
638     /**
639      * Returns an {@link InvalidKeyException} corresponding to the provided
640      * {@link KeyStoreException}.
641      */
getInvalidKeyException( String keystoreKeyAlias, KeyStoreException e)642     public InvalidKeyException getInvalidKeyException(
643             String keystoreKeyAlias, KeyStoreException e) {
644         switch (e.getErrorCode()) {
645             case LOCKED:
646                 return new UserNotAuthenticatedException();
647             case KeymasterDefs.KM_ERROR_KEY_EXPIRED:
648                 return new KeyExpiredException();
649             case KeymasterDefs.KM_ERROR_KEY_NOT_YET_VALID:
650                 return new KeyNotYetValidException();
651             case KeymasterDefs.KM_ERROR_KEY_USER_NOT_AUTHENTICATED:
652             case OP_AUTH_NEEDED:
653             {
654                 // We now need to determine whether the key/operation can become usable if user
655                 // authentication is performed, or whether it can never become usable again.
656                 // User authentication requirements are contained in the key's characteristics. We
657                 // need to check whether these requirements can be be satisfied by asking the user
658                 // to authenticate.
659                 KeyCharacteristics keyCharacteristics = new KeyCharacteristics();
660                 int getKeyCharacteristicsErrorCode =
661                         getKeyCharacteristics(keystoreKeyAlias, null, null, keyCharacteristics);
662                 if (getKeyCharacteristicsErrorCode != NO_ERROR) {
663                     return new InvalidKeyException(
664                             "Failed to obtained key characteristics",
665                             getKeyStoreException(getKeyCharacteristicsErrorCode));
666                 }
667                 List<BigInteger> keySids =
668                         keyCharacteristics.getUnsignedLongs(KeymasterDefs.KM_TAG_USER_SECURE_ID);
669                 if (keySids.isEmpty()) {
670                     // Key is not bound to any SIDs -- no amount of authentication will help here.
671                     return new KeyPermanentlyInvalidatedException();
672                 }
673                 long rootSid = GateKeeper.getSecureUserId();
674                 if ((rootSid != 0) && (keySids.contains(KeymasterArguments.toUint64(rootSid)))) {
675                     // One of the key's SIDs is the current root SID -- user can be authenticated
676                     // against that SID.
677                     return new UserNotAuthenticatedException();
678                 }
679 
680                 long fingerprintOnlySid = getFingerprintOnlySid();
681                 if ((fingerprintOnlySid != 0)
682                         && (keySids.contains(KeymasterArguments.toUint64(fingerprintOnlySid)))) {
683                     // One of the key's SIDs is the current fingerprint SID -- user can be
684                     // authenticated against that SID.
685                     return new UserNotAuthenticatedException();
686                 }
687 
688                 // None of the key's SIDs can ever be authenticated
689                 return new KeyPermanentlyInvalidatedException();
690             }
691             default:
692                 return new InvalidKeyException("Keystore operation failed", e);
693         }
694     }
695 
getFingerprintOnlySid()696     private long getFingerprintOnlySid() {
697         FingerprintManager fingerprintManager = mContext.getSystemService(FingerprintManager.class);
698         if (fingerprintManager == null) {
699             return 0;
700         }
701 
702         // TODO: Restore USE_FINGERPRINT permission check in
703         // FingerprintManager.getAuthenticatorId once the ID is no longer needed here.
704         return fingerprintManager.getAuthenticatorId();
705     }
706 
707     /**
708      * Returns an {@link InvalidKeyException} corresponding to the provided keystore/keymaster error
709      * code.
710      */
getInvalidKeyException(String keystoreKeyAlias, int errorCode)711     public InvalidKeyException getInvalidKeyException(String keystoreKeyAlias, int errorCode) {
712         return getInvalidKeyException(keystoreKeyAlias, getKeyStoreException(errorCode));
713     }
714 }
715