• 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 boolean grant(String key, int uid) {
345         try {
346             return mBinder.grant(key, uid) == NO_ERROR;
347         } catch (RemoteException e) {
348             Log.w(TAG, "Cannot connect to keystore", e);
349             return false;
350         }
351     }
352 
ungrant(String key, int uid)353     public boolean ungrant(String key, int uid) {
354         try {
355             return mBinder.ungrant(key, uid) == NO_ERROR;
356         } catch (RemoteException e) {
357             Log.w(TAG, "Cannot connect to keystore", e);
358             return false;
359         }
360     }
361 
362     /**
363      * Returns the last modification time of the key in milliseconds since the
364      * epoch. Will return -1L if the key could not be found or other error.
365      */
getmtime(String key, int uid)366     public long getmtime(String key, int uid) {
367         try {
368             final long millis = mBinder.getmtime(key, uid);
369             if (millis == -1L) {
370                 return -1L;
371             }
372 
373             return millis * 1000L;
374         } catch (RemoteException e) {
375             Log.w(TAG, "Cannot connect to keystore", e);
376             return -1L;
377         }
378     }
379 
getmtime(String key)380     public long getmtime(String key) {
381         return getmtime(key, UID_SELF);
382     }
383 
duplicate(String srcKey, int srcUid, String destKey, int destUid)384     public boolean duplicate(String srcKey, int srcUid, String destKey, int destUid) {
385         try {
386             return mBinder.duplicate(srcKey, srcUid, destKey, destUid) == NO_ERROR;
387         } catch (RemoteException e) {
388             Log.w(TAG, "Cannot connect to keystore", e);
389             return false;
390         }
391     }
392 
393     // TODO: remove this when it's removed from Settings
isHardwareBacked()394     public boolean isHardwareBacked() {
395         return isHardwareBacked("RSA");
396     }
397 
isHardwareBacked(String keyType)398     public boolean isHardwareBacked(String keyType) {
399         try {
400             return mBinder.is_hardware_backed(keyType.toUpperCase(Locale.US)) == NO_ERROR;
401         } catch (RemoteException e) {
402             Log.w(TAG, "Cannot connect to keystore", e);
403             return false;
404         }
405     }
406 
clearUid(int uid)407     public boolean clearUid(int uid) {
408         try {
409             return mBinder.clear_uid(uid) == NO_ERROR;
410         } catch (RemoteException e) {
411             Log.w(TAG, "Cannot connect to keystore", e);
412             return false;
413         }
414     }
415 
getLastError()416     public int getLastError() {
417         return mError;
418     }
419 
addRngEntropy(byte[] data)420     public boolean addRngEntropy(byte[] data) {
421         try {
422             return mBinder.addRngEntropy(data) == NO_ERROR;
423         } catch (RemoteException e) {
424             Log.w(TAG, "Cannot connect to keystore", e);
425             return false;
426         }
427     }
428 
generateKey(String alias, KeymasterArguments args, byte[] entropy, int uid, int flags, KeyCharacteristics outCharacteristics)429     public int generateKey(String alias, KeymasterArguments args, byte[] entropy, int uid,
430             int flags, KeyCharacteristics outCharacteristics) {
431         try {
432             return mBinder.generateKey(alias, args, entropy, uid, flags, outCharacteristics);
433         } catch (RemoteException e) {
434             Log.w(TAG, "Cannot connect to keystore", e);
435             return SYSTEM_ERROR;
436         }
437     }
438 
generateKey(String alias, KeymasterArguments args, byte[] entropy, int flags, KeyCharacteristics outCharacteristics)439     public int generateKey(String alias, KeymasterArguments args, byte[] entropy, int flags,
440             KeyCharacteristics outCharacteristics) {
441         return generateKey(alias, args, entropy, UID_SELF, flags, outCharacteristics);
442     }
443 
getKeyCharacteristics(String alias, KeymasterBlob clientId, KeymasterBlob appId, int uid, KeyCharacteristics outCharacteristics)444     public int getKeyCharacteristics(String alias, KeymasterBlob clientId, KeymasterBlob appId,
445             int uid, KeyCharacteristics outCharacteristics) {
446         try {
447             return mBinder.getKeyCharacteristics(alias, clientId, appId, uid, outCharacteristics);
448         } catch (RemoteException e) {
449             Log.w(TAG, "Cannot connect to keystore", e);
450             return SYSTEM_ERROR;
451         }
452     }
453 
getKeyCharacteristics(String alias, KeymasterBlob clientId, KeymasterBlob appId, KeyCharacteristics outCharacteristics)454     public int getKeyCharacteristics(String alias, KeymasterBlob clientId, KeymasterBlob appId,
455             KeyCharacteristics outCharacteristics) {
456         return getKeyCharacteristics(alias, clientId, appId, UID_SELF, outCharacteristics);
457     }
458 
importKey(String alias, KeymasterArguments args, int format, byte[] keyData, int uid, int flags, KeyCharacteristics outCharacteristics)459     public int importKey(String alias, KeymasterArguments args, int format, byte[] keyData,
460             int uid, int flags, KeyCharacteristics outCharacteristics) {
461         try {
462             return mBinder.importKey(alias, args, format, keyData, uid, flags,
463                     outCharacteristics);
464         } catch (RemoteException e) {
465             Log.w(TAG, "Cannot connect to keystore", e);
466             return SYSTEM_ERROR;
467         }
468     }
469 
importKey(String alias, KeymasterArguments args, int format, byte[] keyData, int flags, KeyCharacteristics outCharacteristics)470     public int importKey(String alias, KeymasterArguments args, int format, byte[] keyData,
471             int flags, KeyCharacteristics outCharacteristics) {
472         return importKey(alias, args, format, keyData, UID_SELF, flags, outCharacteristics);
473     }
474 
exportKey(String alias, int format, KeymasterBlob clientId, KeymasterBlob appId, int uid)475     public ExportResult exportKey(String alias, int format, KeymasterBlob clientId,
476             KeymasterBlob appId, int uid) {
477         try {
478             return mBinder.exportKey(alias, format, clientId, appId, uid);
479         } catch (RemoteException e) {
480             Log.w(TAG, "Cannot connect to keystore", e);
481             return null;
482         }
483     }
exportKey(String alias, int format, KeymasterBlob clientId, KeymasterBlob appId)484     public ExportResult exportKey(String alias, int format, KeymasterBlob clientId,
485             KeymasterBlob appId) {
486         return exportKey(alias, format, clientId, appId, UID_SELF);
487     }
488 
begin(String alias, int purpose, boolean pruneable, KeymasterArguments args, byte[] entropy, int uid)489     public OperationResult begin(String alias, int purpose, boolean pruneable,
490             KeymasterArguments args, byte[] entropy, int uid) {
491         try {
492             return mBinder.begin(getToken(), alias, purpose, pruneable, args, entropy, uid);
493         } catch (RemoteException e) {
494             Log.w(TAG, "Cannot connect to keystore", e);
495             return null;
496         }
497     }
498 
begin(String alias, int purpose, boolean pruneable, KeymasterArguments args, byte[] entropy)499     public OperationResult begin(String alias, int purpose, boolean pruneable,
500             KeymasterArguments args, byte[] entropy) {
501         return begin(alias, purpose, pruneable, args, entropy, UID_SELF);
502     }
503 
update(IBinder token, KeymasterArguments arguments, byte[] input)504     public OperationResult update(IBinder token, KeymasterArguments arguments, byte[] input) {
505         try {
506             return mBinder.update(token, arguments, input);
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, byte[] entropy)513     public OperationResult finish(IBinder token, KeymasterArguments arguments, byte[] signature,
514             byte[] entropy) {
515         try {
516             return mBinder.finish(token, arguments, signature, entropy);
517         } catch (RemoteException e) {
518             Log.w(TAG, "Cannot connect to keystore", e);
519             return null;
520         }
521     }
522 
finish(IBinder token, KeymasterArguments arguments, byte[] signature)523     public OperationResult finish(IBinder token, KeymasterArguments arguments, byte[] signature) {
524         return finish(token, arguments, signature, null);
525     }
526 
abort(IBinder token)527     public int abort(IBinder token) {
528         try {
529             return mBinder.abort(token);
530         } catch (RemoteException e) {
531             Log.w(TAG, "Cannot connect to keystore", e);
532             return SYSTEM_ERROR;
533         }
534     }
535 
536     /**
537      * Check if the operation referenced by {@code token} is currently authorized.
538      *
539      * @param token An operation token returned by a call to
540      * {@link #begin(String, int, boolean, KeymasterArguments, byte[], KeymasterArguments) begin}.
541      */
isOperationAuthorized(IBinder token)542     public boolean isOperationAuthorized(IBinder token) {
543         try {
544             return mBinder.isOperationAuthorized(token);
545         } catch (RemoteException e) {
546             Log.w(TAG, "Cannot connect to keystore", e);
547             return false;
548         }
549     }
550 
551     /**
552      * Add an authentication record to the keystore authorization table.
553      *
554      * @param authToken The packed bytes of a hw_auth_token_t to be provided to keymaster.
555      * @return {@code KeyStore.NO_ERROR} on success, otherwise an error value corresponding to
556      * a {@code KeymasterDefs.KM_ERROR_} value or {@code KeyStore} ResponseCode.
557      */
addAuthToken(byte[] authToken)558     public int addAuthToken(byte[] authToken) {
559         try {
560             return mBinder.addAuthToken(authToken);
561         } catch (RemoteException e) {
562             Log.w(TAG, "Cannot connect to keystore", e);
563             return SYSTEM_ERROR;
564         }
565     }
566 
567     /**
568      * Notify keystore that a user's password has changed.
569      *
570      * @param userId the user whose password changed.
571      * @param newPassword the new password or "" if the password was removed.
572      */
onUserPasswordChanged(int userId, String newPassword)573     public boolean onUserPasswordChanged(int userId, String newPassword) {
574         // Parcel.cpp doesn't support deserializing null strings and treats them as "". Make that
575         // explicit here.
576         if (newPassword == null) {
577             newPassword = "";
578         }
579         try {
580             return mBinder.onUserPasswordChanged(userId, newPassword) == NO_ERROR;
581         } catch (RemoteException e) {
582             Log.w(TAG, "Cannot connect to keystore", e);
583             return false;
584         }
585     }
586 
587     /**
588      * Notify keystore that a user was added.
589      *
590      * @param userId the new user.
591      * @param parentId the parent of the new user, or -1 if the user has no parent. If parentId is
592      * specified then the new user's keystore will be intialized with the same secure lockscreen
593      * password as the parent.
594      */
onUserAdded(int userId, int parentId)595     public void onUserAdded(int userId, int parentId) {
596         try {
597             mBinder.onUserAdded(userId, parentId);
598         } catch (RemoteException e) {
599             Log.w(TAG, "Cannot connect to keystore", e);
600         }
601     }
602 
603     /**
604      * Notify keystore that a user was added.
605      *
606      * @param userId the new user.
607      */
onUserAdded(int userId)608     public void onUserAdded(int userId) {
609         onUserAdded(userId, -1);
610     }
611 
612     /**
613      * Notify keystore that a user was removed.
614      *
615      * @param userId the removed user.
616      */
onUserRemoved(int userId)617     public void onUserRemoved(int userId) {
618         try {
619             mBinder.onUserRemoved(userId);
620         } catch (RemoteException e) {
621             Log.w(TAG, "Cannot connect to keystore", e);
622         }
623     }
624 
onUserPasswordChanged(String newPassword)625     public boolean onUserPasswordChanged(String newPassword) {
626         return onUserPasswordChanged(UserHandle.getUserId(Process.myUid()), newPassword);
627     }
628 
attestKey( String alias, KeymasterArguments params, KeymasterCertificateChain outChain)629     public int attestKey(
630             String alias, KeymasterArguments params, KeymasterCertificateChain outChain) {
631         try {
632             return mBinder.attestKey(alias, params, outChain);
633         } catch (RemoteException e) {
634             Log.w(TAG, "Cannot connect to keystore", e);
635             return SYSTEM_ERROR;
636         }
637     }
638 
attestDeviceIds(KeymasterArguments params, KeymasterCertificateChain outChain)639     public int attestDeviceIds(KeymasterArguments params, KeymasterCertificateChain outChain) {
640         try {
641             return mBinder.attestDeviceIds(params, outChain);
642         } catch (RemoteException e) {
643             Log.w(TAG, "Cannot connect to keystore", e);
644             return SYSTEM_ERROR;
645         }
646     }
647 
648     /**
649      * Notify keystore that the device went off-body.
650      */
onDeviceOffBody()651     public void onDeviceOffBody() {
652         try {
653             mBinder.onDeviceOffBody();
654         } catch (RemoteException e) {
655             Log.w(TAG, "Cannot connect to keystore", e);
656         }
657     }
658 
659     /**
660      * Returns a {@link KeyStoreException} corresponding to the provided keystore/keymaster error
661      * code.
662      */
getKeyStoreException(int errorCode)663     public static KeyStoreException getKeyStoreException(int errorCode) {
664         if (errorCode > 0) {
665             // KeyStore layer error
666             switch (errorCode) {
667                 case NO_ERROR:
668                     return new KeyStoreException(errorCode, "OK");
669                 case LOCKED:
670                     return new KeyStoreException(errorCode, "User authentication required");
671                 case UNINITIALIZED:
672                     return new KeyStoreException(errorCode, "Keystore not initialized");
673                 case SYSTEM_ERROR:
674                     return new KeyStoreException(errorCode, "System error");
675                 case PERMISSION_DENIED:
676                     return new KeyStoreException(errorCode, "Permission denied");
677                 case KEY_NOT_FOUND:
678                     return new KeyStoreException(errorCode, "Key not found");
679                 case VALUE_CORRUPTED:
680                     return new KeyStoreException(errorCode, "Key blob corrupted");
681                 case OP_AUTH_NEEDED:
682                     return new KeyStoreException(errorCode, "Operation requires authorization");
683                 default:
684                     return new KeyStoreException(errorCode, String.valueOf(errorCode));
685             }
686         } else {
687             // Keymaster layer error
688             switch (errorCode) {
689                 case KeymasterDefs.KM_ERROR_INVALID_AUTHORIZATION_TIMEOUT:
690                     // The name of this parameter significantly differs between Keymaster and
691                     // framework APIs. Use the framework wording to make life easier for developers.
692                     return new KeyStoreException(errorCode,
693                             "Invalid user authentication validity duration");
694                 default:
695                     return new KeyStoreException(errorCode,
696                             KeymasterDefs.getErrorMessage(errorCode));
697             }
698         }
699     }
700 
701     /**
702      * Returns an {@link InvalidKeyException} corresponding to the provided
703      * {@link KeyStoreException}.
704      */
getInvalidKeyException( String keystoreKeyAlias, int uid, KeyStoreException e)705     public InvalidKeyException getInvalidKeyException(
706             String keystoreKeyAlias, int uid, KeyStoreException e) {
707         switch (e.getErrorCode()) {
708             case LOCKED:
709                 return new UserNotAuthenticatedException();
710             case KeymasterDefs.KM_ERROR_KEY_EXPIRED:
711                 return new KeyExpiredException();
712             case KeymasterDefs.KM_ERROR_KEY_NOT_YET_VALID:
713                 return new KeyNotYetValidException();
714             case KeymasterDefs.KM_ERROR_KEY_USER_NOT_AUTHENTICATED:
715             case OP_AUTH_NEEDED:
716             {
717                 // We now need to determine whether the key/operation can become usable if user
718                 // authentication is performed, or whether it can never become usable again.
719                 // User authentication requirements are contained in the key's characteristics. We
720                 // need to check whether these requirements can be be satisfied by asking the user
721                 // to authenticate.
722                 KeyCharacteristics keyCharacteristics = new KeyCharacteristics();
723                 int getKeyCharacteristicsErrorCode =
724                         getKeyCharacteristics(keystoreKeyAlias, null, null, uid,
725                                 keyCharacteristics);
726                 if (getKeyCharacteristicsErrorCode != NO_ERROR) {
727                     return new InvalidKeyException(
728                             "Failed to obtained key characteristics",
729                             getKeyStoreException(getKeyCharacteristicsErrorCode));
730                 }
731                 List<BigInteger> keySids =
732                         keyCharacteristics.getUnsignedLongs(KeymasterDefs.KM_TAG_USER_SECURE_ID);
733                 if (keySids.isEmpty()) {
734                     // Key is not bound to any SIDs -- no amount of authentication will help here.
735                     return new KeyPermanentlyInvalidatedException();
736                 }
737                 long rootSid = GateKeeper.getSecureUserId();
738                 if ((rootSid != 0) && (keySids.contains(KeymasterArguments.toUint64(rootSid)))) {
739                     // One of the key's SIDs is the current root SID -- user can be authenticated
740                     // against that SID.
741                     return new UserNotAuthenticatedException();
742                 }
743 
744                 long fingerprintOnlySid = getFingerprintOnlySid();
745                 if ((fingerprintOnlySid != 0)
746                         && (keySids.contains(KeymasterArguments.toUint64(fingerprintOnlySid)))) {
747                     // One of the key's SIDs is the current fingerprint SID -- user can be
748                     // authenticated against that SID.
749                     return new UserNotAuthenticatedException();
750                 }
751 
752                 // None of the key's SIDs can ever be authenticated
753                 return new KeyPermanentlyInvalidatedException();
754             }
755             default:
756                 return new InvalidKeyException("Keystore operation failed", e);
757         }
758     }
759 
getFingerprintOnlySid()760     private long getFingerprintOnlySid() {
761         FingerprintManager fingerprintManager = mContext.getSystemService(FingerprintManager.class);
762         if (fingerprintManager == null) {
763             return 0;
764         }
765 
766         // TODO: Restore USE_FINGERPRINT permission check in
767         // FingerprintManager.getAuthenticatorId once the ID is no longer needed here.
768         return fingerprintManager.getAuthenticatorId();
769     }
770 
771     /**
772      * Returns an {@link InvalidKeyException} corresponding to the provided keystore/keymaster error
773      * code.
774      */
getInvalidKeyException(String keystoreKeyAlias, int uid, int errorCode)775     public InvalidKeyException getInvalidKeyException(String keystoreKeyAlias, int uid,
776             int errorCode) {
777         return getInvalidKeyException(keystoreKeyAlias, uid, getKeyStoreException(errorCode));
778     }
779 }
780