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
17package android.security;
18
19import android.app.ActivityThread;
20import android.app.Application;
21import android.app.KeyguardManager;
22import android.content.Context;
23import android.hardware.fingerprint.FingerprintManager;
24import android.os.Binder;
25import android.os.IBinder;
26import android.os.Process;
27import android.os.RemoteException;
28import android.os.ServiceManager;
29import android.os.UserHandle;
30import android.security.keymaster.ExportResult;
31import android.security.keymaster.KeyCharacteristics;
32import android.security.keymaster.KeymasterArguments;
33import android.security.keymaster.KeymasterBlob;
34import android.security.keymaster.KeymasterCertificateChain;
35import android.security.keymaster.KeymasterDefs;
36import android.security.keymaster.OperationResult;
37import android.security.keystore.KeyExpiredException;
38import android.security.keystore.KeyNotYetValidException;
39import android.security.keystore.KeyPermanentlyInvalidatedException;
40import android.security.keystore.UserNotAuthenticatedException;
41import android.util.Log;
42
43import java.math.BigInteger;
44import java.security.InvalidKeyException;
45import java.util.List;
46import 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 */
53public 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
106    private KeyStore(IKeystoreService binder) {
107        mBinder = binder;
108        mContext = getApplicationContext();
109    }
110
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
120    public static KeyStore getInstance() {
121        IKeystoreService keystore = IKeystoreService.Stub.asInterface(ServiceManager
122                .getService("android.security.keystore"));
123        return new KeyStore(keystore);
124    }
125
126    private synchronized IBinder getToken() {
127        if (mToken == null) {
128            mToken = new Binder();
129        }
130        return mToken;
131    }
132
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
150    public State state() {
151        return state(UserHandle.myUserId());
152    }
153
154    public boolean isUnlocked() {
155        return state() == State.UNLOCKED;
156    }
157
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
167    public byte[] get(String key) {
168        return get(key, UID_SELF);
169    }
170
171    public boolean put(String key, byte[] value, int uid, int flags) {
172        return insert(key, value, uid, flags) == NO_ERROR;
173    }
174
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
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
194    public boolean delete(String key) {
195        return delete(key, UID_SELF);
196    }
197
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
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     */
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
223    public String[] list(String prefix) {
224        return list(prefix, UID_SELF);
225    }
226
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     */
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
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     */
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
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     */
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
292    public boolean isEmpty() {
293        return isEmpty(UserHandle.myUserId());
294    }
295
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
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
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
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
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
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     */
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
370    public long getmtime(String key) {
371        return getmtime(key, UID_SELF);
372    }
373
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
384    public boolean isHardwareBacked() {
385        return isHardwareBacked("RSA");
386    }
387
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
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
406    public int getLastError() {
407        return mError;
408    }
409
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
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
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
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
444    public int getKeyCharacteristics(String alias, KeymasterBlob clientId, KeymasterBlob appId,
445            KeyCharacteristics outCharacteristics) {
446        return getKeyCharacteristics(alias, clientId, appId, UID_SELF, outCharacteristics);
447    }
448
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
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
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    }
474    public ExportResult exportKey(String alias, int format, KeymasterBlob clientId,
475            KeymasterBlob appId) {
476        return exportKey(alias, format, clientId, appId, UID_SELF);
477    }
478
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
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
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
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
513    public OperationResult finish(IBinder token, KeymasterArguments arguments, byte[] signature) {
514        return finish(token, arguments, signature, null);
515    }
516
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     */
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     */
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     */
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     */
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     */
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     */
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
615    public boolean onUserPasswordChanged(String newPassword) {
616        return onUserPasswordChanged(UserHandle.getUserId(Process.myUid()), newPassword);
617    }
618
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     */
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     */
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
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     */
746    public InvalidKeyException getInvalidKeyException(String keystoreKeyAlias, int uid,
747            int errorCode) {
748        return getInvalidKeyException(keystoreKeyAlias, uid, getKeyStoreException(errorCode));
749    }
750}
751