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.content.Context;
23 import android.hardware.fingerprint.FingerprintManager;
24 import android.os.Binder;
25 import android.os.IBinder;
26 import android.os.Process;
27 import android.os.RemoteException;
28 import android.os.ServiceManager;
29 import android.os.UserHandle;
30 import android.security.keymaster.ExportResult;
31 import android.security.keymaster.KeyCharacteristics;
32 import android.security.keymaster.KeymasterArguments;
33 import android.security.keymaster.KeymasterBlob;
34 import android.security.keymaster.KeymasterCertificateChain;
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, int uid)158     public byte[] get(String key, int uid) {
159         try {
160             return mBinder.get(key, uid);
161         } catch (RemoteException e) {
162             Log.w(TAG, "Cannot connect to keystore", e);
163             return null;
164         }
165     }
166 
get(String key)167     public byte[] get(String key) {
168         return get(key, UID_SELF);
169     }
170 
put(String key, byte[] value, int uid, int flags)171     public boolean put(String key, byte[] value, int uid, int flags) {
172         return insert(key, value, uid, flags) == NO_ERROR;
173     }
174 
insert(String key, byte[] value, int uid, int flags)175     public int insert(String key, byte[] value, int uid, int flags) {
176         try {
177             return mBinder.insert(key, value, uid, flags);
178         } catch (RemoteException e) {
179             Log.w(TAG, "Cannot connect to keystore", e);
180             return SYSTEM_ERROR;
181         }
182     }
183 
delete(String key, int uid)184     public boolean delete(String key, int uid) {
185         try {
186             int ret = mBinder.del(key, uid);
187             return (ret == NO_ERROR || ret == KEY_NOT_FOUND);
188         } catch (RemoteException e) {
189             Log.w(TAG, "Cannot connect to keystore", e);
190             return false;
191         }
192     }
193 
delete(String key)194     public boolean delete(String key) {
195         return delete(key, UID_SELF);
196     }
197 
contains(String key, int uid)198     public boolean contains(String key, int uid) {
199         try {
200             return mBinder.exist(key, uid) == NO_ERROR;
201         } catch (RemoteException e) {
202             Log.w(TAG, "Cannot connect to keystore", e);
203             return false;
204         }
205     }
206 
contains(String key)207     public boolean contains(String key) {
208         return contains(key, UID_SELF);
209     }
210 
211     /**
212      * List all entries in the keystore for {@code uid} starting with {@code prefix}.
213      */
list(String prefix, int uid)214     public String[] list(String prefix, int uid) {
215         try {
216             return mBinder.list(prefix, uid);
217         } catch (RemoteException e) {
218             Log.w(TAG, "Cannot connect to keystore", e);
219             return null;
220         }
221     }
222 
list(String prefix)223     public String[] list(String prefix) {
224         return list(prefix, UID_SELF);
225     }
226 
reset()227     public boolean reset() {
228         try {
229             return mBinder.reset() == NO_ERROR;
230         } catch (RemoteException e) {
231             Log.w(TAG, "Cannot connect to keystore", e);
232             return false;
233         }
234     }
235 
236     /**
237      * Attempt to lock the keystore for {@code user}.
238      *
239      * @param user Android user to lock.
240      * @return whether {@code user}'s keystore was locked.
241      */
lock(int userId)242     public boolean lock(int userId) {
243         try {
244             return mBinder.lock(userId) == NO_ERROR;
245         } catch (RemoteException e) {
246             Log.w(TAG, "Cannot connect to keystore", e);
247             return false;
248         }
249     }
250 
lock()251     public boolean lock() {
252         return lock(UserHandle.myUserId());
253     }
254 
255     /**
256      * Attempt to unlock the keystore for {@code user} with the password {@code password}.
257      * This is required before keystore entries created with FLAG_ENCRYPTED can be accessed or
258      * created.
259      *
260      * @param user Android user ID to operate on
261      * @param password user's keystore password. Should be the most recent value passed to
262      * {@link #onUserPasswordChanged} for the user.
263      *
264      * @return whether the keystore was unlocked.
265      */
unlock(int userId, String password)266     public boolean unlock(int userId, String password) {
267         try {
268             mError = mBinder.unlock(userId, password);
269             return mError == NO_ERROR;
270         } catch (RemoteException e) {
271             Log.w(TAG, "Cannot connect to keystore", e);
272             return false;
273         }
274     }
275 
unlock(String password)276     public boolean unlock(String password) {
277         return unlock(UserHandle.getUserId(Process.myUid()), password);
278     }
279 
280     /**
281      * Check if the keystore for {@code userId} is empty.
282      */
isEmpty(int userId)283     public boolean isEmpty(int userId) {
284         try {
285             return mBinder.isEmpty(userId) != 0;
286         } catch (RemoteException e) {
287             Log.w(TAG, "Cannot connect to keystore", e);
288             return false;
289         }
290     }
291 
isEmpty()292     public boolean isEmpty() {
293         return isEmpty(UserHandle.myUserId());
294     }
295 
generate(String key, int uid, int keyType, int keySize, int flags, byte[][] args)296     public boolean generate(String key, int uid, int keyType, int keySize, int flags,
297             byte[][] args) {
298         try {
299             return mBinder.generate(key, uid, keyType, keySize, flags,
300                     new KeystoreArguments(args)) == NO_ERROR;
301         } catch (RemoteException e) {
302             Log.w(TAG, "Cannot connect to keystore", e);
303             return false;
304         }
305     }
306 
importKey(String keyName, byte[] key, int uid, int flags)307     public boolean importKey(String keyName, byte[] key, int uid, int flags) {
308         try {
309             return mBinder.import_key(keyName, key, uid, flags) == NO_ERROR;
310         } catch (RemoteException e) {
311             Log.w(TAG, "Cannot connect to keystore", e);
312             return false;
313         }
314     }
315 
sign(String key, byte[] data)316     public byte[] sign(String key, byte[] data) {
317         try {
318             return mBinder.sign(key, data);
319         } catch (RemoteException e) {
320             Log.w(TAG, "Cannot connect to keystore", e);
321             return null;
322         }
323     }
324 
verify(String key, byte[] data, byte[] signature)325     public boolean verify(String key, byte[] data, byte[] signature) {
326         try {
327             return mBinder.verify(key, data, signature) == NO_ERROR;
328         } catch (RemoteException e) {
329             Log.w(TAG, "Cannot connect to keystore", e);
330             return false;
331         }
332     }
333 
grant(String key, int uid)334     public boolean grant(String key, int uid) {
335         try {
336             return mBinder.grant(key, uid) == NO_ERROR;
337         } catch (RemoteException e) {
338             Log.w(TAG, "Cannot connect to keystore", e);
339             return false;
340         }
341     }
342 
ungrant(String key, int uid)343     public boolean ungrant(String key, int uid) {
344         try {
345             return mBinder.ungrant(key, uid) == NO_ERROR;
346         } catch (RemoteException e) {
347             Log.w(TAG, "Cannot connect to keystore", e);
348             return false;
349         }
350     }
351 
352     /**
353      * Returns the last modification time of the key in milliseconds since the
354      * epoch. Will return -1L if the key could not be found or other error.
355      */
getmtime(String key, int uid)356     public long getmtime(String key, int uid) {
357         try {
358             final long millis = mBinder.getmtime(key, uid);
359             if (millis == -1L) {
360                 return -1L;
361             }
362 
363             return millis * 1000L;
364         } catch (RemoteException e) {
365             Log.w(TAG, "Cannot connect to keystore", e);
366             return -1L;
367         }
368     }
369 
getmtime(String key)370     public long getmtime(String key) {
371         return getmtime(key, UID_SELF);
372     }
373 
duplicate(String srcKey, int srcUid, String destKey, int destUid)374     public boolean duplicate(String srcKey, int srcUid, String destKey, int destUid) {
375         try {
376             return mBinder.duplicate(srcKey, srcUid, destKey, destUid) == NO_ERROR;
377         } catch (RemoteException e) {
378             Log.w(TAG, "Cannot connect to keystore", e);
379             return false;
380         }
381     }
382 
383     // TODO: remove this when it's removed from Settings
isHardwareBacked()384     public boolean isHardwareBacked() {
385         return isHardwareBacked("RSA");
386     }
387 
isHardwareBacked(String keyType)388     public boolean isHardwareBacked(String keyType) {
389         try {
390             return mBinder.is_hardware_backed(keyType.toUpperCase(Locale.US)) == NO_ERROR;
391         } catch (RemoteException e) {
392             Log.w(TAG, "Cannot connect to keystore", e);
393             return false;
394         }
395     }
396 
clearUid(int uid)397     public boolean clearUid(int uid) {
398         try {
399             return mBinder.clear_uid(uid) == NO_ERROR;
400         } catch (RemoteException e) {
401             Log.w(TAG, "Cannot connect to keystore", e);
402             return false;
403         }
404     }
405 
getLastError()406     public int getLastError() {
407         return mError;
408     }
409 
addRngEntropy(byte[] data)410     public boolean addRngEntropy(byte[] data) {
411         try {
412             return mBinder.addRngEntropy(data) == NO_ERROR;
413         } catch (RemoteException e) {
414             Log.w(TAG, "Cannot connect to keystore", e);
415             return false;
416         }
417     }
418 
generateKey(String alias, KeymasterArguments args, byte[] entropy, int uid, int flags, KeyCharacteristics outCharacteristics)419     public int generateKey(String alias, KeymasterArguments args, byte[] entropy, int uid,
420             int flags, KeyCharacteristics outCharacteristics) {
421         try {
422             return mBinder.generateKey(alias, args, entropy, uid, flags, outCharacteristics);
423         } catch (RemoteException e) {
424             Log.w(TAG, "Cannot connect to keystore", e);
425             return SYSTEM_ERROR;
426         }
427     }
428 
generateKey(String alias, KeymasterArguments args, byte[] entropy, int flags, KeyCharacteristics outCharacteristics)429     public int generateKey(String alias, KeymasterArguments args, byte[] entropy, int flags,
430             KeyCharacteristics outCharacteristics) {
431         return generateKey(alias, args, entropy, UID_SELF, flags, outCharacteristics);
432     }
433 
getKeyCharacteristics(String alias, KeymasterBlob clientId, KeymasterBlob appId, int uid, KeyCharacteristics outCharacteristics)434     public int getKeyCharacteristics(String alias, KeymasterBlob clientId, KeymasterBlob appId,
435             int uid, KeyCharacteristics outCharacteristics) {
436         try {
437             return mBinder.getKeyCharacteristics(alias, clientId, appId, uid, outCharacteristics);
438         } catch (RemoteException e) {
439             Log.w(TAG, "Cannot connect to keystore", e);
440             return SYSTEM_ERROR;
441         }
442     }
443 
getKeyCharacteristics(String alias, KeymasterBlob clientId, KeymasterBlob appId, KeyCharacteristics outCharacteristics)444     public int getKeyCharacteristics(String alias, KeymasterBlob clientId, KeymasterBlob appId,
445             KeyCharacteristics outCharacteristics) {
446         return getKeyCharacteristics(alias, clientId, appId, UID_SELF, outCharacteristics);
447     }
448 
importKey(String alias, KeymasterArguments args, int format, byte[] keyData, int uid, int flags, KeyCharacteristics outCharacteristics)449     public int importKey(String alias, KeymasterArguments args, int format, byte[] keyData,
450             int uid, int flags, KeyCharacteristics outCharacteristics) {
451         try {
452             return mBinder.importKey(alias, args, format, keyData, uid, flags,
453                     outCharacteristics);
454         } catch (RemoteException e) {
455             Log.w(TAG, "Cannot connect to keystore", e);
456             return SYSTEM_ERROR;
457         }
458     }
459 
importKey(String alias, KeymasterArguments args, int format, byte[] keyData, int flags, KeyCharacteristics outCharacteristics)460     public int importKey(String alias, KeymasterArguments args, int format, byte[] keyData,
461             int flags, KeyCharacteristics outCharacteristics) {
462         return importKey(alias, args, format, keyData, UID_SELF, flags, outCharacteristics);
463     }
464 
exportKey(String alias, int format, KeymasterBlob clientId, KeymasterBlob appId, int uid)465     public ExportResult exportKey(String alias, int format, KeymasterBlob clientId,
466             KeymasterBlob appId, int uid) {
467         try {
468             return mBinder.exportKey(alias, format, clientId, appId, uid);
469         } catch (RemoteException e) {
470             Log.w(TAG, "Cannot connect to keystore", e);
471             return null;
472         }
473     }
exportKey(String alias, int format, KeymasterBlob clientId, KeymasterBlob appId)474     public ExportResult exportKey(String alias, int format, KeymasterBlob clientId,
475             KeymasterBlob appId) {
476         return exportKey(alias, format, clientId, appId, UID_SELF);
477     }
478 
begin(String alias, int purpose, boolean pruneable, KeymasterArguments args, byte[] entropy, int uid)479     public OperationResult begin(String alias, int purpose, boolean pruneable,
480             KeymasterArguments args, byte[] entropy, int uid) {
481         try {
482             return mBinder.begin(getToken(), alias, purpose, pruneable, args, entropy, uid);
483         } catch (RemoteException e) {
484             Log.w(TAG, "Cannot connect to keystore", e);
485             return null;
486         }
487     }
488 
begin(String alias, int purpose, boolean pruneable, KeymasterArguments args, byte[] entropy)489     public OperationResult begin(String alias, int purpose, boolean pruneable,
490             KeymasterArguments args, byte[] entropy) {
491         return begin(alias, purpose, pruneable, args, entropy, UID_SELF);
492     }
493 
update(IBinder token, KeymasterArguments arguments, byte[] input)494     public OperationResult update(IBinder token, KeymasterArguments arguments, byte[] input) {
495         try {
496             return mBinder.update(token, arguments, input);
497         } catch (RemoteException e) {
498             Log.w(TAG, "Cannot connect to keystore", e);
499             return null;
500         }
501     }
502 
finish(IBinder token, KeymasterArguments arguments, byte[] signature, byte[] entropy)503     public OperationResult finish(IBinder token, KeymasterArguments arguments, byte[] signature,
504             byte[] entropy) {
505         try {
506             return mBinder.finish(token, arguments, signature, entropy);
507         } catch (RemoteException e) {
508             Log.w(TAG, "Cannot connect to keystore", e);
509             return null;
510         }
511     }
512 
finish(IBinder token, KeymasterArguments arguments, byte[] signature)513     public OperationResult finish(IBinder token, KeymasterArguments arguments, byte[] signature) {
514         return finish(token, arguments, signature, null);
515     }
516 
abort(IBinder token)517     public int abort(IBinder token) {
518         try {
519             return mBinder.abort(token);
520         } catch (RemoteException e) {
521             Log.w(TAG, "Cannot connect to keystore", e);
522             return SYSTEM_ERROR;
523         }
524     }
525 
526     /**
527      * Check if the operation referenced by {@code token} is currently authorized.
528      *
529      * @param token An operation token returned by a call to
530      * {@link #begin(String, int, boolean, KeymasterArguments, byte[], KeymasterArguments) begin}.
531      */
isOperationAuthorized(IBinder token)532     public boolean isOperationAuthorized(IBinder token) {
533         try {
534             return mBinder.isOperationAuthorized(token);
535         } catch (RemoteException e) {
536             Log.w(TAG, "Cannot connect to keystore", e);
537             return false;
538         }
539     }
540 
541     /**
542      * Add an authentication record to the keystore authorization table.
543      *
544      * @param authToken The packed bytes of a hw_auth_token_t to be provided to keymaster.
545      * @return {@code KeyStore.NO_ERROR} on success, otherwise an error value corresponding to
546      * a {@code KeymasterDefs.KM_ERROR_} value or {@code KeyStore} ResponseCode.
547      */
addAuthToken(byte[] authToken)548     public int addAuthToken(byte[] authToken) {
549         try {
550             return mBinder.addAuthToken(authToken);
551         } catch (RemoteException e) {
552             Log.w(TAG, "Cannot connect to keystore", e);
553             return SYSTEM_ERROR;
554         }
555     }
556 
557     /**
558      * Notify keystore that a user's password has changed.
559      *
560      * @param userId the user whose password changed.
561      * @param newPassword the new password or "" if the password was removed.
562      */
onUserPasswordChanged(int userId, String newPassword)563     public boolean onUserPasswordChanged(int userId, String newPassword) {
564         // Parcel.cpp doesn't support deserializing null strings and treats them as "". Make that
565         // explicit here.
566         if (newPassword == null) {
567             newPassword = "";
568         }
569         try {
570             return mBinder.onUserPasswordChanged(userId, newPassword) == NO_ERROR;
571         } catch (RemoteException e) {
572             Log.w(TAG, "Cannot connect to keystore", e);
573             return false;
574         }
575     }
576 
577     /**
578      * Notify keystore that a user was added.
579      *
580      * @param userId the new user.
581      * @param parentId the parent of the new user, or -1 if the user has no parent. If parentId is
582      * specified then the new user's keystore will be intialized with the same secure lockscreen
583      * password as the parent.
584      */
onUserAdded(int userId, int parentId)585     public void onUserAdded(int userId, int parentId) {
586         try {
587             mBinder.onUserAdded(userId, parentId);
588         } catch (RemoteException e) {
589             Log.w(TAG, "Cannot connect to keystore", e);
590         }
591     }
592 
593     /**
594      * Notify keystore that a user was added.
595      *
596      * @param userId the new user.
597      */
onUserAdded(int userId)598     public void onUserAdded(int userId) {
599         onUserAdded(userId, -1);
600     }
601 
602     /**
603      * Notify keystore that a user was removed.
604      *
605      * @param userId the removed user.
606      */
onUserRemoved(int userId)607     public void onUserRemoved(int userId) {
608         try {
609             mBinder.onUserRemoved(userId);
610         } catch (RemoteException e) {
611             Log.w(TAG, "Cannot connect to keystore", e);
612         }
613     }
614 
onUserPasswordChanged(String newPassword)615     public boolean onUserPasswordChanged(String newPassword) {
616         return onUserPasswordChanged(UserHandle.getUserId(Process.myUid()), newPassword);
617     }
618 
attestKey( String alias, KeymasterArguments params, KeymasterCertificateChain outChain)619     public int attestKey(
620             String alias, KeymasterArguments params, KeymasterCertificateChain outChain) {
621         try {
622             return mBinder.attestKey(alias, params, outChain);
623         } catch (RemoteException e) {
624             Log.w(TAG, "Cannot connect to keystore", e);
625             return SYSTEM_ERROR;
626         }
627     }
628 
629 
630     /**
631      * Returns a {@link KeyStoreException} corresponding to the provided keystore/keymaster error
632      * code.
633      */
getKeyStoreException(int errorCode)634     public static KeyStoreException getKeyStoreException(int errorCode) {
635         if (errorCode > 0) {
636             // KeyStore layer error
637             switch (errorCode) {
638                 case NO_ERROR:
639                     return new KeyStoreException(errorCode, "OK");
640                 case LOCKED:
641                     return new KeyStoreException(errorCode, "User authentication required");
642                 case UNINITIALIZED:
643                     return new KeyStoreException(errorCode, "Keystore not initialized");
644                 case SYSTEM_ERROR:
645                     return new KeyStoreException(errorCode, "System error");
646                 case PERMISSION_DENIED:
647                     return new KeyStoreException(errorCode, "Permission denied");
648                 case KEY_NOT_FOUND:
649                     return new KeyStoreException(errorCode, "Key not found");
650                 case VALUE_CORRUPTED:
651                     return new KeyStoreException(errorCode, "Key blob corrupted");
652                 case OP_AUTH_NEEDED:
653                     return new KeyStoreException(errorCode, "Operation requires authorization");
654                 default:
655                     return new KeyStoreException(errorCode, String.valueOf(errorCode));
656             }
657         } else {
658             // Keymaster layer error
659             switch (errorCode) {
660                 case KeymasterDefs.KM_ERROR_INVALID_AUTHORIZATION_TIMEOUT:
661                     // The name of this parameter significantly differs between Keymaster and
662                     // framework APIs. Use the framework wording to make life easier for developers.
663                     return new KeyStoreException(errorCode,
664                             "Invalid user authentication validity duration");
665                 default:
666                     return new KeyStoreException(errorCode,
667                             KeymasterDefs.getErrorMessage(errorCode));
668             }
669         }
670     }
671 
672     /**
673      * Returns an {@link InvalidKeyException} corresponding to the provided
674      * {@link KeyStoreException}.
675      */
getInvalidKeyException( String keystoreKeyAlias, int uid, KeyStoreException e)676     public InvalidKeyException getInvalidKeyException(
677             String keystoreKeyAlias, int uid, KeyStoreException e) {
678         switch (e.getErrorCode()) {
679             case LOCKED:
680                 return new UserNotAuthenticatedException();
681             case KeymasterDefs.KM_ERROR_KEY_EXPIRED:
682                 return new KeyExpiredException();
683             case KeymasterDefs.KM_ERROR_KEY_NOT_YET_VALID:
684                 return new KeyNotYetValidException();
685             case KeymasterDefs.KM_ERROR_KEY_USER_NOT_AUTHENTICATED:
686             case OP_AUTH_NEEDED:
687             {
688                 // We now need to determine whether the key/operation can become usable if user
689                 // authentication is performed, or whether it can never become usable again.
690                 // User authentication requirements are contained in the key's characteristics. We
691                 // need to check whether these requirements can be be satisfied by asking the user
692                 // to authenticate.
693                 KeyCharacteristics keyCharacteristics = new KeyCharacteristics();
694                 int getKeyCharacteristicsErrorCode =
695                         getKeyCharacteristics(keystoreKeyAlias, null, null, uid,
696                                 keyCharacteristics);
697                 if (getKeyCharacteristicsErrorCode != NO_ERROR) {
698                     return new InvalidKeyException(
699                             "Failed to obtained key characteristics",
700                             getKeyStoreException(getKeyCharacteristicsErrorCode));
701                 }
702                 List<BigInteger> keySids =
703                         keyCharacteristics.getUnsignedLongs(KeymasterDefs.KM_TAG_USER_SECURE_ID);
704                 if (keySids.isEmpty()) {
705                     // Key is not bound to any SIDs -- no amount of authentication will help here.
706                     return new KeyPermanentlyInvalidatedException();
707                 }
708                 long rootSid = GateKeeper.getSecureUserId();
709                 if ((rootSid != 0) && (keySids.contains(KeymasterArguments.toUint64(rootSid)))) {
710                     // One of the key's SIDs is the current root SID -- user can be authenticated
711                     // against that SID.
712                     return new UserNotAuthenticatedException();
713                 }
714 
715                 long fingerprintOnlySid = getFingerprintOnlySid();
716                 if ((fingerprintOnlySid != 0)
717                         && (keySids.contains(KeymasterArguments.toUint64(fingerprintOnlySid)))) {
718                     // One of the key's SIDs is the current fingerprint SID -- user can be
719                     // authenticated against that SID.
720                     return new UserNotAuthenticatedException();
721                 }
722 
723                 // None of the key's SIDs can ever be authenticated
724                 return new KeyPermanentlyInvalidatedException();
725             }
726             default:
727                 return new InvalidKeyException("Keystore operation failed", e);
728         }
729     }
730 
getFingerprintOnlySid()731     private long getFingerprintOnlySid() {
732         FingerprintManager fingerprintManager = mContext.getSystemService(FingerprintManager.class);
733         if (fingerprintManager == null) {
734             return 0;
735         }
736 
737         // TODO: Restore USE_FINGERPRINT permission check in
738         // FingerprintManager.getAuthenticatorId once the ID is no longer needed here.
739         return fingerprintManager.getAuthenticatorId();
740     }
741 
742     /**
743      * Returns an {@link InvalidKeyException} corresponding to the provided keystore/keymaster error
744      * code.
745      */
getInvalidKeyException(String keystoreKeyAlias, int uid, int errorCode)746     public InvalidKeyException getInvalidKeyException(String keystoreKeyAlias, int uid,
747             int errorCode) {
748         return getInvalidKeyException(keystoreKeyAlias, uid, getKeyStoreException(errorCode));
749     }
750 }
751