• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2009 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.security;
18 
19 import android.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     /**
97      * A private flag that's only available to system server to indicate that this key is part of
98      * device encryption flow so it receives special treatment from keystore. For example this key
99      * will not be super encrypted, and it will be stored separately under an unique UID instead
100      * of the caller UID i.e. SYSTEM.
101      *
102      * Need to be in sync with KeyStoreFlag in system/security/keystore/include/keystore/keystore.h
103      */
104     public static final int FLAG_CRITICAL_TO_DEVICE_ENCRYPTION = 1 << 3;
105 
106     // States
107     public enum State { UNLOCKED, LOCKED, UNINITIALIZED };
108 
109     private int mError = NO_ERROR;
110 
111     private final IKeystoreService mBinder;
112     private final Context mContext;
113 
114     private IBinder mToken;
115 
KeyStore(IKeystoreService binder)116     private KeyStore(IKeystoreService binder) {
117         mBinder = binder;
118         mContext = getApplicationContext();
119     }
120 
getApplicationContext()121     public static Context getApplicationContext() {
122         Application application = ActivityThread.currentApplication();
123         if (application == null) {
124             throw new IllegalStateException(
125                     "Failed to obtain application Context from ActivityThread");
126         }
127         return application;
128     }
129 
getInstance()130     public static KeyStore getInstance() {
131         IKeystoreService keystore = IKeystoreService.Stub.asInterface(ServiceManager
132                 .getService("android.security.keystore"));
133         return new KeyStore(keystore);
134     }
135 
getToken()136     private synchronized IBinder getToken() {
137         if (mToken == null) {
138             mToken = new Binder();
139         }
140         return mToken;
141     }
142 
state(int userId)143     public State state(int userId) {
144         final int ret;
145         try {
146             ret = mBinder.getState(userId);
147         } catch (RemoteException e) {
148             Log.w(TAG, "Cannot connect to keystore", e);
149             throw new AssertionError(e);
150         }
151 
152         switch (ret) {
153             case NO_ERROR: return State.UNLOCKED;
154             case LOCKED: return State.LOCKED;
155             case UNINITIALIZED: return State.UNINITIALIZED;
156             default: throw new AssertionError(mError);
157         }
158     }
159 
state()160     public State state() {
161         return state(UserHandle.myUserId());
162     }
163 
isUnlocked()164     public boolean isUnlocked() {
165         return state() == State.UNLOCKED;
166     }
167 
get(String key, int uid)168     public byte[] get(String key, int uid) {
169         try {
170             return mBinder.get(key, uid);
171         } catch (RemoteException e) {
172             Log.w(TAG, "Cannot connect to keystore", e);
173             return null;
174         }
175     }
176 
get(String key)177     public byte[] get(String key) {
178         return get(key, UID_SELF);
179     }
180 
put(String key, byte[] value, int uid, int flags)181     public boolean put(String key, byte[] value, int uid, int flags) {
182         return insert(key, value, uid, flags) == NO_ERROR;
183     }
184 
insert(String key, byte[] value, int uid, int flags)185     public int insert(String key, byte[] value, int uid, int flags) {
186         try {
187             return mBinder.insert(key, value, uid, flags);
188         } catch (RemoteException e) {
189             Log.w(TAG, "Cannot connect to keystore", e);
190             return SYSTEM_ERROR;
191         }
192     }
193 
delete(String key, int uid)194     public boolean delete(String key, int uid) {
195         try {
196             int ret = mBinder.del(key, uid);
197             return (ret == NO_ERROR || ret == KEY_NOT_FOUND);
198         } catch (RemoteException e) {
199             Log.w(TAG, "Cannot connect to keystore", e);
200             return false;
201         }
202     }
203 
delete(String key)204     public boolean delete(String key) {
205         return delete(key, UID_SELF);
206     }
207 
contains(String key, int uid)208     public boolean contains(String key, int uid) {
209         try {
210             return mBinder.exist(key, uid) == NO_ERROR;
211         } catch (RemoteException e) {
212             Log.w(TAG, "Cannot connect to keystore", e);
213             return false;
214         }
215     }
216 
contains(String key)217     public boolean contains(String key) {
218         return contains(key, UID_SELF);
219     }
220 
221     /**
222      * List all entries in the keystore for {@code uid} starting with {@code prefix}.
223      */
list(String prefix, int uid)224     public String[] list(String prefix, int uid) {
225         try {
226             return mBinder.list(prefix, uid);
227         } catch (RemoteException e) {
228             Log.w(TAG, "Cannot connect to keystore", e);
229             return null;
230         }
231     }
232 
list(String prefix)233     public String[] list(String prefix) {
234         return list(prefix, UID_SELF);
235     }
236 
reset()237     public boolean reset() {
238         try {
239             return mBinder.reset() == NO_ERROR;
240         } catch (RemoteException e) {
241             Log.w(TAG, "Cannot connect to keystore", e);
242             return false;
243         }
244     }
245 
246     /**
247      * Attempt to lock the keystore for {@code user}.
248      *
249      * @param user Android user to lock.
250      * @return whether {@code user}'s keystore was locked.
251      */
lock(int userId)252     public boolean lock(int userId) {
253         try {
254             return mBinder.lock(userId) == NO_ERROR;
255         } catch (RemoteException e) {
256             Log.w(TAG, "Cannot connect to keystore", e);
257             return false;
258         }
259     }
260 
lock()261     public boolean lock() {
262         return lock(UserHandle.myUserId());
263     }
264 
265     /**
266      * Attempt to unlock the keystore for {@code user} with the password {@code password}.
267      * This is required before keystore entries created with FLAG_ENCRYPTED can be accessed or
268      * created.
269      *
270      * @param user Android user ID to operate on
271      * @param password user's keystore password. Should be the most recent value passed to
272      * {@link #onUserPasswordChanged} for the user.
273      *
274      * @return whether the keystore was unlocked.
275      */
unlock(int userId, String password)276     public boolean unlock(int userId, String password) {
277         try {
278             mError = mBinder.unlock(userId, password);
279             return mError == NO_ERROR;
280         } catch (RemoteException e) {
281             Log.w(TAG, "Cannot connect to keystore", e);
282             return false;
283         }
284     }
285 
unlock(String password)286     public boolean unlock(String password) {
287         return unlock(UserHandle.getUserId(Process.myUid()), password);
288     }
289 
290     /**
291      * Check if the keystore for {@code userId} is empty.
292      */
isEmpty(int userId)293     public boolean isEmpty(int userId) {
294         try {
295             return mBinder.isEmpty(userId) != 0;
296         } catch (RemoteException e) {
297             Log.w(TAG, "Cannot connect to keystore", e);
298             return false;
299         }
300     }
301 
isEmpty()302     public boolean isEmpty() {
303         return isEmpty(UserHandle.myUserId());
304     }
305 
generate(String key, int uid, int keyType, int keySize, int flags, byte[][] args)306     public boolean generate(String key, int uid, int keyType, int keySize, int flags,
307             byte[][] args) {
308         try {
309             return mBinder.generate(key, uid, keyType, keySize, flags,
310                     new KeystoreArguments(args)) == NO_ERROR;
311         } catch (RemoteException e) {
312             Log.w(TAG, "Cannot connect to keystore", e);
313             return false;
314         }
315     }
316 
importKey(String keyName, byte[] key, int uid, int flags)317     public boolean importKey(String keyName, byte[] key, int uid, int flags) {
318         try {
319             return mBinder.import_key(keyName, key, uid, flags) == NO_ERROR;
320         } catch (RemoteException e) {
321             Log.w(TAG, "Cannot connect to keystore", e);
322             return false;
323         }
324     }
325 
sign(String key, byte[] data)326     public byte[] sign(String key, byte[] data) {
327         try {
328             return mBinder.sign(key, data);
329         } catch (RemoteException e) {
330             Log.w(TAG, "Cannot connect to keystore", e);
331             return null;
332         }
333     }
334 
verify(String key, byte[] data, byte[] signature)335     public boolean verify(String key, byte[] data, byte[] signature) {
336         try {
337             return mBinder.verify(key, data, signature) == NO_ERROR;
338         } catch (RemoteException e) {
339             Log.w(TAG, "Cannot connect to keystore", e);
340             return false;
341         }
342     }
343 
grant(String key, int uid)344     public String grant(String key, int uid) {
345         try {
346             String grantAlias =  mBinder.grant(key, uid);
347             if (grantAlias == "") return null;
348             return grantAlias;
349         } catch (RemoteException e) {
350             Log.w(TAG, "Cannot connect to keystore", e);
351             return null;
352         }
353     }
354 
ungrant(String key, int uid)355     public boolean ungrant(String key, int uid) {
356         try {
357             return mBinder.ungrant(key, uid) == NO_ERROR;
358         } catch (RemoteException e) {
359             Log.w(TAG, "Cannot connect to keystore", e);
360             return false;
361         }
362     }
363 
364     /**
365      * Returns the last modification time of the key in milliseconds since the
366      * epoch. Will return -1L if the key could not be found or other error.
367      */
getmtime(String key, int uid)368     public long getmtime(String key, int uid) {
369         try {
370             final long millis = mBinder.getmtime(key, uid);
371             if (millis == -1L) {
372                 return -1L;
373             }
374 
375             return millis * 1000L;
376         } catch (RemoteException e) {
377             Log.w(TAG, "Cannot connect to keystore", e);
378             return -1L;
379         }
380     }
381 
getmtime(String key)382     public long getmtime(String key) {
383         return getmtime(key, UID_SELF);
384     }
385 
duplicate(String srcKey, int srcUid, String destKey, int destUid)386     public boolean duplicate(String srcKey, int srcUid, String destKey, int destUid) {
387         try {
388             return mBinder.duplicate(srcKey, srcUid, destKey, destUid) == NO_ERROR;
389         } catch (RemoteException e) {
390             Log.w(TAG, "Cannot connect to keystore", e);
391             return false;
392         }
393     }
394 
395     // TODO: remove this when it's removed from Settings
isHardwareBacked()396     public boolean isHardwareBacked() {
397         return isHardwareBacked("RSA");
398     }
399 
isHardwareBacked(String keyType)400     public boolean isHardwareBacked(String keyType) {
401         try {
402             return mBinder.is_hardware_backed(keyType.toUpperCase(Locale.US)) == NO_ERROR;
403         } catch (RemoteException e) {
404             Log.w(TAG, "Cannot connect to keystore", e);
405             return false;
406         }
407     }
408 
clearUid(int uid)409     public boolean clearUid(int uid) {
410         try {
411             return mBinder.clear_uid(uid) == NO_ERROR;
412         } catch (RemoteException e) {
413             Log.w(TAG, "Cannot connect to keystore", e);
414             return false;
415         }
416     }
417 
getLastError()418     public int getLastError() {
419         return mError;
420     }
421 
addRngEntropy(byte[] data)422     public boolean addRngEntropy(byte[] data) {
423         try {
424             return mBinder.addRngEntropy(data) == NO_ERROR;
425         } catch (RemoteException e) {
426             Log.w(TAG, "Cannot connect to keystore", e);
427             return false;
428         }
429     }
430 
generateKey(String alias, KeymasterArguments args, byte[] entropy, int uid, int flags, KeyCharacteristics outCharacteristics)431     public int generateKey(String alias, KeymasterArguments args, byte[] entropy, int uid,
432             int flags, KeyCharacteristics outCharacteristics) {
433         try {
434             return mBinder.generateKey(alias, args, entropy, uid, flags, outCharacteristics);
435         } catch (RemoteException e) {
436             Log.w(TAG, "Cannot connect to keystore", e);
437             return SYSTEM_ERROR;
438         }
439     }
440 
generateKey(String alias, KeymasterArguments args, byte[] entropy, int flags, KeyCharacteristics outCharacteristics)441     public int generateKey(String alias, KeymasterArguments args, byte[] entropy, int flags,
442             KeyCharacteristics outCharacteristics) {
443         return generateKey(alias, args, entropy, UID_SELF, flags, outCharacteristics);
444     }
445 
getKeyCharacteristics(String alias, KeymasterBlob clientId, KeymasterBlob appId, int uid, KeyCharacteristics outCharacteristics)446     public int getKeyCharacteristics(String alias, KeymasterBlob clientId, KeymasterBlob appId,
447             int uid, KeyCharacteristics outCharacteristics) {
448         try {
449             return mBinder.getKeyCharacteristics(alias, clientId, appId, uid, outCharacteristics);
450         } catch (RemoteException e) {
451             Log.w(TAG, "Cannot connect to keystore", e);
452             return SYSTEM_ERROR;
453         }
454     }
455 
getKeyCharacteristics(String alias, KeymasterBlob clientId, KeymasterBlob appId, KeyCharacteristics outCharacteristics)456     public int getKeyCharacteristics(String alias, KeymasterBlob clientId, KeymasterBlob appId,
457             KeyCharacteristics outCharacteristics) {
458         return getKeyCharacteristics(alias, clientId, appId, UID_SELF, outCharacteristics);
459     }
460 
importKey(String alias, KeymasterArguments args, int format, byte[] keyData, int uid, int flags, KeyCharacteristics outCharacteristics)461     public int importKey(String alias, KeymasterArguments args, int format, byte[] keyData,
462             int uid, int flags, KeyCharacteristics outCharacteristics) {
463         try {
464             return mBinder.importKey(alias, args, format, keyData, uid, flags,
465                     outCharacteristics);
466         } catch (RemoteException e) {
467             Log.w(TAG, "Cannot connect to keystore", e);
468             return SYSTEM_ERROR;
469         }
470     }
471 
importKey(String alias, KeymasterArguments args, int format, byte[] keyData, int flags, KeyCharacteristics outCharacteristics)472     public int importKey(String alias, KeymasterArguments args, int format, byte[] keyData,
473             int flags, KeyCharacteristics outCharacteristics) {
474         return importKey(alias, args, format, keyData, UID_SELF, flags, outCharacteristics);
475     }
476 
exportKey(String alias, int format, KeymasterBlob clientId, KeymasterBlob appId, int uid)477     public ExportResult exportKey(String alias, int format, KeymasterBlob clientId,
478             KeymasterBlob appId, int uid) {
479         try {
480             return mBinder.exportKey(alias, format, clientId, appId, uid);
481         } catch (RemoteException e) {
482             Log.w(TAG, "Cannot connect to keystore", e);
483             return null;
484         }
485     }
exportKey(String alias, int format, KeymasterBlob clientId, KeymasterBlob appId)486     public ExportResult exportKey(String alias, int format, KeymasterBlob clientId,
487             KeymasterBlob appId) {
488         return exportKey(alias, format, clientId, appId, UID_SELF);
489     }
490 
begin(String alias, int purpose, boolean pruneable, KeymasterArguments args, byte[] entropy, int uid)491     public OperationResult begin(String alias, int purpose, boolean pruneable,
492             KeymasterArguments args, byte[] entropy, int uid) {
493         try {
494             return mBinder.begin(getToken(), alias, purpose, pruneable, args, entropy, uid);
495         } catch (RemoteException e) {
496             Log.w(TAG, "Cannot connect to keystore", e);
497             return null;
498         }
499     }
500 
begin(String alias, int purpose, boolean pruneable, KeymasterArguments args, byte[] entropy)501     public OperationResult begin(String alias, int purpose, boolean pruneable,
502             KeymasterArguments args, byte[] entropy) {
503         return begin(alias, purpose, pruneable, args, entropy, UID_SELF);
504     }
505 
update(IBinder token, KeymasterArguments arguments, byte[] input)506     public OperationResult update(IBinder token, KeymasterArguments arguments, byte[] input) {
507         try {
508             return mBinder.update(token, arguments, input);
509         } catch (RemoteException e) {
510             Log.w(TAG, "Cannot connect to keystore", e);
511             return null;
512         }
513     }
514 
finish(IBinder token, KeymasterArguments arguments, byte[] signature, byte[] entropy)515     public OperationResult finish(IBinder token, KeymasterArguments arguments, byte[] signature,
516             byte[] entropy) {
517         try {
518             return mBinder.finish(token, arguments, signature, entropy);
519         } catch (RemoteException e) {
520             Log.w(TAG, "Cannot connect to keystore", e);
521             return null;
522         }
523     }
524 
finish(IBinder token, KeymasterArguments arguments, byte[] signature)525     public OperationResult finish(IBinder token, KeymasterArguments arguments, byte[] signature) {
526         return finish(token, arguments, signature, null);
527     }
528 
abort(IBinder token)529     public int abort(IBinder token) {
530         try {
531             return mBinder.abort(token);
532         } catch (RemoteException e) {
533             Log.w(TAG, "Cannot connect to keystore", e);
534             return SYSTEM_ERROR;
535         }
536     }
537 
538     /**
539      * Check if the operation referenced by {@code token} is currently authorized.
540      *
541      * @param token An operation token returned by a call to
542      * {@link #begin(String, int, boolean, KeymasterArguments, byte[], KeymasterArguments) begin}.
543      */
isOperationAuthorized(IBinder token)544     public boolean isOperationAuthorized(IBinder token) {
545         try {
546             return mBinder.isOperationAuthorized(token);
547         } catch (RemoteException e) {
548             Log.w(TAG, "Cannot connect to keystore", e);
549             return false;
550         }
551     }
552 
553     /**
554      * Add an authentication record to the keystore authorization table.
555      *
556      * @param authToken The packed bytes of a hw_auth_token_t to be provided to keymaster.
557      * @return {@code KeyStore.NO_ERROR} on success, otherwise an error value corresponding to
558      * a {@code KeymasterDefs.KM_ERROR_} value or {@code KeyStore} ResponseCode.
559      */
addAuthToken(byte[] authToken)560     public int addAuthToken(byte[] authToken) {
561         try {
562             return mBinder.addAuthToken(authToken);
563         } catch (RemoteException e) {
564             Log.w(TAG, "Cannot connect to keystore", e);
565             return SYSTEM_ERROR;
566         }
567     }
568 
569     /**
570      * Notify keystore that a user's password has changed.
571      *
572      * @param userId the user whose password changed.
573      * @param newPassword the new password or "" if the password was removed.
574      */
onUserPasswordChanged(int userId, String newPassword)575     public boolean onUserPasswordChanged(int userId, String newPassword) {
576         // Parcel.cpp doesn't support deserializing null strings and treats them as "". Make that
577         // explicit here.
578         if (newPassword == null) {
579             newPassword = "";
580         }
581         try {
582             return mBinder.onUserPasswordChanged(userId, newPassword) == NO_ERROR;
583         } catch (RemoteException e) {
584             Log.w(TAG, "Cannot connect to keystore", e);
585             return false;
586         }
587     }
588 
589     /**
590      * Notify keystore that a user was added.
591      *
592      * @param userId the new user.
593      * @param parentId the parent of the new user, or -1 if the user has no parent. If parentId is
594      * specified then the new user's keystore will be intialized with the same secure lockscreen
595      * password as the parent.
596      */
onUserAdded(int userId, int parentId)597     public void onUserAdded(int userId, int parentId) {
598         try {
599             mBinder.onUserAdded(userId, parentId);
600         } catch (RemoteException e) {
601             Log.w(TAG, "Cannot connect to keystore", e);
602         }
603     }
604 
605     /**
606      * Notify keystore that a user was added.
607      *
608      * @param userId the new user.
609      */
onUserAdded(int userId)610     public void onUserAdded(int userId) {
611         onUserAdded(userId, -1);
612     }
613 
614     /**
615      * Notify keystore that a user was removed.
616      *
617      * @param userId the removed user.
618      */
onUserRemoved(int userId)619     public void onUserRemoved(int userId) {
620         try {
621             mBinder.onUserRemoved(userId);
622         } catch (RemoteException e) {
623             Log.w(TAG, "Cannot connect to keystore", e);
624         }
625     }
626 
onUserPasswordChanged(String newPassword)627     public boolean onUserPasswordChanged(String newPassword) {
628         return onUserPasswordChanged(UserHandle.getUserId(Process.myUid()), newPassword);
629     }
630 
attestKey( String alias, KeymasterArguments params, KeymasterCertificateChain outChain)631     public int attestKey(
632             String alias, KeymasterArguments params, KeymasterCertificateChain outChain) {
633         try {
634             return mBinder.attestKey(alias, params, outChain);
635         } catch (RemoteException e) {
636             Log.w(TAG, "Cannot connect to keystore", e);
637             return SYSTEM_ERROR;
638         }
639     }
640 
attestDeviceIds(KeymasterArguments params, KeymasterCertificateChain outChain)641     public int attestDeviceIds(KeymasterArguments params, KeymasterCertificateChain outChain) {
642         try {
643             return mBinder.attestDeviceIds(params, outChain);
644         } catch (RemoteException e) {
645             Log.w(TAG, "Cannot connect to keystore", e);
646             return SYSTEM_ERROR;
647         }
648     }
649 
650     /**
651      * Notify keystore that the device went off-body.
652      */
onDeviceOffBody()653     public void onDeviceOffBody() {
654         try {
655             mBinder.onDeviceOffBody();
656         } catch (RemoteException e) {
657             Log.w(TAG, "Cannot connect to keystore", e);
658         }
659     }
660 
661     /**
662      * Returns a {@link KeyStoreException} corresponding to the provided keystore/keymaster error
663      * code.
664      */
getKeyStoreException(int errorCode)665     public static KeyStoreException getKeyStoreException(int errorCode) {
666         if (errorCode > 0) {
667             // KeyStore layer error
668             switch (errorCode) {
669                 case NO_ERROR:
670                     return new KeyStoreException(errorCode, "OK");
671                 case LOCKED:
672                     return new KeyStoreException(errorCode, "User authentication required");
673                 case UNINITIALIZED:
674                     return new KeyStoreException(errorCode, "Keystore not initialized");
675                 case SYSTEM_ERROR:
676                     return new KeyStoreException(errorCode, "System error");
677                 case PERMISSION_DENIED:
678                     return new KeyStoreException(errorCode, "Permission denied");
679                 case KEY_NOT_FOUND:
680                     return new KeyStoreException(errorCode, "Key not found");
681                 case VALUE_CORRUPTED:
682                     return new KeyStoreException(errorCode, "Key blob corrupted");
683                 case OP_AUTH_NEEDED:
684                     return new KeyStoreException(errorCode, "Operation requires authorization");
685                 default:
686                     return new KeyStoreException(errorCode, String.valueOf(errorCode));
687             }
688         } else {
689             // Keymaster layer error
690             switch (errorCode) {
691                 case KeymasterDefs.KM_ERROR_INVALID_AUTHORIZATION_TIMEOUT:
692                     // The name of this parameter significantly differs between Keymaster and
693                     // framework APIs. Use the framework wording to make life easier for developers.
694                     return new KeyStoreException(errorCode,
695                             "Invalid user authentication validity duration");
696                 default:
697                     return new KeyStoreException(errorCode,
698                             KeymasterDefs.getErrorMessage(errorCode));
699             }
700         }
701     }
702 
703     /**
704      * Returns an {@link InvalidKeyException} corresponding to the provided
705      * {@link KeyStoreException}.
706      */
getInvalidKeyException( String keystoreKeyAlias, int uid, KeyStoreException e)707     public InvalidKeyException getInvalidKeyException(
708             String keystoreKeyAlias, int uid, KeyStoreException e) {
709         switch (e.getErrorCode()) {
710             case LOCKED:
711                 return new UserNotAuthenticatedException();
712             case KeymasterDefs.KM_ERROR_KEY_EXPIRED:
713                 return new KeyExpiredException();
714             case KeymasterDefs.KM_ERROR_KEY_NOT_YET_VALID:
715                 return new KeyNotYetValidException();
716             case KeymasterDefs.KM_ERROR_KEY_USER_NOT_AUTHENTICATED:
717             case OP_AUTH_NEEDED:
718             {
719                 // We now need to determine whether the key/operation can become usable if user
720                 // authentication is performed, or whether it can never become usable again.
721                 // User authentication requirements are contained in the key's characteristics. We
722                 // need to check whether these requirements can be be satisfied by asking the user
723                 // to authenticate.
724                 KeyCharacteristics keyCharacteristics = new KeyCharacteristics();
725                 int getKeyCharacteristicsErrorCode =
726                         getKeyCharacteristics(keystoreKeyAlias, null, null, uid,
727                                 keyCharacteristics);
728                 if (getKeyCharacteristicsErrorCode != NO_ERROR) {
729                     return new InvalidKeyException(
730                             "Failed to obtained key characteristics",
731                             getKeyStoreException(getKeyCharacteristicsErrorCode));
732                 }
733                 List<BigInteger> keySids =
734                         keyCharacteristics.getUnsignedLongs(KeymasterDefs.KM_TAG_USER_SECURE_ID);
735                 if (keySids.isEmpty()) {
736                     // Key is not bound to any SIDs -- no amount of authentication will help here.
737                     return new KeyPermanentlyInvalidatedException();
738                 }
739                 long rootSid = GateKeeper.getSecureUserId();
740                 if ((rootSid != 0) && (keySids.contains(KeymasterArguments.toUint64(rootSid)))) {
741                     // One of the key's SIDs is the current root SID -- user can be authenticated
742                     // against that SID.
743                     return new UserNotAuthenticatedException();
744                 }
745 
746                 long fingerprintOnlySid = getFingerprintOnlySid();
747                 if ((fingerprintOnlySid != 0)
748                         && (keySids.contains(KeymasterArguments.toUint64(fingerprintOnlySid)))) {
749                     // One of the key's SIDs is the current fingerprint SID -- user can be
750                     // authenticated against that SID.
751                     return new UserNotAuthenticatedException();
752                 }
753 
754                 // None of the key's SIDs can ever be authenticated
755                 return new KeyPermanentlyInvalidatedException();
756             }
757             case UNINITIALIZED:
758                 return new KeyPermanentlyInvalidatedException();
759             default:
760                 return new InvalidKeyException("Keystore operation failed", e);
761         }
762     }
763 
getFingerprintOnlySid()764     private long getFingerprintOnlySid() {
765         FingerprintManager fingerprintManager = mContext.getSystemService(FingerprintManager.class);
766         if (fingerprintManager == null) {
767             return 0;
768         }
769 
770         // TODO: Restore USE_FINGERPRINT permission check in
771         // FingerprintManager.getAuthenticatorId once the ID is no longer needed here.
772         return fingerprintManager.getAuthenticatorId();
773     }
774 
775     /**
776      * Returns an {@link InvalidKeyException} corresponding to the provided keystore/keymaster error
777      * code.
778      */
getInvalidKeyException(String keystoreKeyAlias, int uid, int errorCode)779     public InvalidKeyException getInvalidKeyException(String keystoreKeyAlias, int uid,
780             int errorCode) {
781         return getInvalidKeyException(keystoreKeyAlias, uid, getKeyStoreException(errorCode));
782     }
783 }
784