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