Home | History | Annotate | Download | only in security
      1 /*
      2  * Copyright (C) 2009 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.security;
     18 
     19 import android.app.ActivityThread;
     20 import android.app.Application;
     21 import android.app.KeyguardManager;
     22 import android.content.Context;
     23 import android.hardware.fingerprint.FingerprintManager;
     24 import android.os.Binder;
     25 import android.os.IBinder;
     26 import android.os.Process;
     27 import android.os.RemoteException;
     28 import android.os.ServiceManager;
     29 import android.os.UserHandle;
     30 import android.security.keymaster.ExportResult;
     31 import android.security.keymaster.KeyCharacteristics;
     32 import android.security.keymaster.KeymasterArguments;
     33 import android.security.keymaster.KeymasterBlob;
     34 import android.security.keymaster.KeymasterCertificateChain;
     35 import android.security.keymaster.KeymasterDefs;
     36 import android.security.keymaster.OperationResult;
     37 import android.security.keystore.KeyExpiredException;
     38 import android.security.keystore.KeyNotYetValidException;
     39 import android.security.keystore.KeyPermanentlyInvalidatedException;
     40 import android.security.keystore.UserNotAuthenticatedException;
     41 import android.util.Log;
     42 
     43 import java.math.BigInteger;
     44 import java.security.InvalidKeyException;
     45 import java.util.List;
     46 import java.util.Locale;
     47 
     48 /**
     49  * @hide This should not be made public in its present form because it
     50  * assumes that private and secret key bytes are available and would
     51  * preclude the use of hardware crypto.
     52  */
     53 public class KeyStore {
     54     private static final String TAG = "KeyStore";
     55 
     56     // ResponseCodes
     57     public static final int NO_ERROR = 1;
     58     public static final int LOCKED = 2;
     59     public static final int UNINITIALIZED = 3;
     60     public static final int SYSTEM_ERROR = 4;
     61     public static final int PROTOCOL_ERROR = 5;
     62     public static final int PERMISSION_DENIED = 6;
     63     public static final int KEY_NOT_FOUND = 7;
     64     public static final int VALUE_CORRUPTED = 8;
     65     public static final int UNDEFINED_ACTION = 9;
     66     public static final int WRONG_PASSWORD = 10;
     67 
     68     /**
     69      * Per operation authentication is needed before this operation is valid.
     70      * This is returned from {@link #begin} when begin succeeds but the operation uses
     71      * per-operation authentication and must authenticate before calling {@link #update} or
     72      * {@link #finish}.
     73      */
     74     public static final int OP_AUTH_NEEDED = 15;
     75 
     76     // Used for UID field to indicate the calling UID.
     77     public static final int UID_SELF = -1;
     78 
     79     // Flags for "put" "import" and "generate"
     80     public static final int FLAG_NONE = 0;
     81 
     82     /**
     83      * Indicates that this key (or key pair) must be encrypted at rest. This will protect the key
     84      * (or key pair) with the secure lock screen credential (e.g., password, PIN, or pattern).
     85      *
     86      * <p>Note that this requires that the secure lock screen (e.g., password, PIN, pattern) is set
     87      * up, otherwise key (or key pair) generation or import will fail. Moreover, this key (or key
     88      * pair) will be deleted when the secure lock screen is disabled or reset (e.g., by the user or
     89      * a Device Administrator). Finally, this key (or key pair) cannot be used until the user
     90      * unlocks the secure lock screen after boot.
     91      *
     92      * @see KeyguardManager#isDeviceSecure()
     93      */
     94     public static final int FLAG_ENCRYPTED = 1;
     95 
     96     // States
     97     public enum State { UNLOCKED, LOCKED, UNINITIALIZED };
     98 
     99     private int mError = NO_ERROR;
    100 
    101     private final IKeystoreService mBinder;
    102     private final Context mContext;
    103 
    104     private IBinder mToken;
    105 
    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