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.ActivityManager;
20import android.app.ActivityThread;
21import android.app.Application;
22import android.app.KeyguardManager;
23import android.content.Context;
24import android.content.pm.PackageManager;
25import android.hardware.fingerprint.FingerprintManager;
26import android.os.Binder;
27import android.os.IBinder;
28import android.os.Process;
29import android.os.RemoteException;
30import android.os.ServiceManager;
31import android.os.UserHandle;
32import android.security.keymaster.ExportResult;
33import android.security.keymaster.KeyCharacteristics;
34import android.security.keymaster.KeymasterArguments;
35import android.security.keymaster.KeymasterBlob;
36import android.security.keymaster.KeymasterCertificateChain;
37import android.security.keymaster.KeymasterDefs;
38import android.security.keymaster.OperationResult;
39import android.security.keystore.KeyExpiredException;
40import android.security.keystore.KeyNotYetValidException;
41import android.security.keystore.KeyPermanentlyInvalidatedException;
42import android.security.keystore.StrongBoxUnavailableException;
43import android.security.keystore.UserNotAuthenticatedException;
44import android.util.Log;
45
46import java.math.BigInteger;
47import java.security.InvalidKeyException;
48import java.util.List;
49import java.util.Locale;
50
51/**
52 * @hide This should not be made public in its present form because it
53 * assumes that private and secret key bytes are available and would
54 * preclude the use of hardware crypto.
55 */
56public class KeyStore {
57    private static final String TAG = "KeyStore";
58
59    // ResponseCodes - see system/security/keystore/include/keystore/keystore.h
60    public static final int NO_ERROR = 1;
61    public static final int LOCKED = 2;
62    public static final int UNINITIALIZED = 3;
63    public static final int SYSTEM_ERROR = 4;
64    public static final int PROTOCOL_ERROR = 5;
65    public static final int PERMISSION_DENIED = 6;
66    public static final int KEY_NOT_FOUND = 7;
67    public static final int VALUE_CORRUPTED = 8;
68    public static final int UNDEFINED_ACTION = 9;
69    public static final int WRONG_PASSWORD = 10;
70    public static final int CANNOT_ATTEST_IDS = -66;
71    public static final int HARDWARE_TYPE_UNAVAILABLE = -68;
72
73    /**
74     * Per operation authentication is needed before this operation is valid.
75     * This is returned from {@link #begin} when begin succeeds but the operation uses
76     * per-operation authentication and must authenticate before calling {@link #update} or
77     * {@link #finish}.
78     */
79    public static final int OP_AUTH_NEEDED = 15;
80
81    // Used for UID field to indicate the calling UID.
82    public static final int UID_SELF = -1;
83
84    // Flags for "put" "import" and "generate"
85    public static final int FLAG_NONE = 0;
86
87    /**
88     * Indicates that this key (or key pair) must be encrypted at rest. This will protect the key
89     * (or key pair) with the secure lock screen credential (e.g., password, PIN, or pattern).
90     *
91     * <p>Note that this requires that the secure lock screen (e.g., password, PIN, pattern) is set
92     * up, otherwise key (or key pair) generation or import will fail. Moreover, this key (or key
93     * pair) will be deleted when the secure lock screen is disabled or reset (e.g., by the user or
94     * a Device Administrator). Finally, this key (or key pair) cannot be used until the user
95     * unlocks the secure lock screen after boot.
96     *
97     * @see KeyguardManager#isDeviceSecure()
98     */
99    public static final int FLAG_ENCRYPTED = 1;
100
101    /**
102     * Select Software keymaster device, which as of this writing is the lowest security
103     * level available on an android device. If neither FLAG_STRONGBOX nor FLAG_SOFTWARE is provided
104     * A TEE based keymaster implementation is implied.
105     *
106     * Need to be in sync with KeyStoreFlag in system/security/keystore/include/keystore/keystore.h
107     * For historical reasons this corresponds to the KEYSTORE_FLAG_FALLBACK flag.
108     */
109    public static final int FLAG_SOFTWARE = 1 << 1;
110
111    /**
112     * A private flag that's only available to system server to indicate that this key is part of
113     * device encryption flow so it receives special treatment from keystore. For example this key
114     * will not be super encrypted, and it will be stored separately under an unique UID instead
115     * of the caller UID i.e. SYSTEM.
116     *
117     * Need to be in sync with KeyStoreFlag in system/security/keystore/include/keystore/keystore.h
118     */
119    public static final int FLAG_CRITICAL_TO_DEVICE_ENCRYPTION = 1 << 3;
120
121    /**
122     * Select Strongbox keymaster device, which as of this writing the the highest security level
123     * available an android devices. If neither FLAG_STRONGBOX nor FLAG_SOFTWARE is provided
124     * A TEE based keymaster implementation is implied.
125     *
126     * Need to be in sync with KeyStoreFlag in system/security/keystore/include/keystore/keystore.h
127     */
128    public static final int FLAG_STRONGBOX = 1 << 4;
129
130    // States
131    public enum State { UNLOCKED, LOCKED, UNINITIALIZED };
132
133    private int mError = NO_ERROR;
134
135    private final IKeystoreService mBinder;
136    private final Context mContext;
137
138    private IBinder mToken;
139
140    private KeyStore(IKeystoreService binder) {
141        mBinder = binder;
142        mContext = getApplicationContext();
143    }
144
145    public static Context getApplicationContext() {
146        Application application = ActivityThread.currentApplication();
147        if (application == null) {
148            throw new IllegalStateException(
149                    "Failed to obtain application Context from ActivityThread");
150        }
151        return application;
152    }
153
154    public static KeyStore getInstance() {
155        IKeystoreService keystore = IKeystoreService.Stub.asInterface(ServiceManager
156                .getService("android.security.keystore"));
157        return new KeyStore(keystore);
158    }
159
160    private synchronized IBinder getToken() {
161        if (mToken == null) {
162            mToken = new Binder();
163        }
164        return mToken;
165    }
166
167    public State state(int userId) {
168        final int ret;
169        try {
170            ret = mBinder.getState(userId);
171        } catch (RemoteException e) {
172            Log.w(TAG, "Cannot connect to keystore", e);
173            throw new AssertionError(e);
174        }
175
176        switch (ret) {
177            case NO_ERROR: return State.UNLOCKED;
178            case LOCKED: return State.LOCKED;
179            case UNINITIALIZED: return State.UNINITIALIZED;
180            default: throw new AssertionError(mError);
181        }
182    }
183
184    public State state() {
185        return state(UserHandle.myUserId());
186    }
187
188    public boolean isUnlocked() {
189        return state() == State.UNLOCKED;
190    }
191
192    public byte[] get(String key, int uid) {
193        try {
194            key = key != null ? key : "";
195            return mBinder.get(key, uid);
196        } catch (RemoteException e) {
197            Log.w(TAG, "Cannot connect to keystore", e);
198            return null;
199        } catch (android.os.ServiceSpecificException e) {
200            Log.w(TAG, "KeyStore exception", e);
201            return null;
202        }
203    }
204
205    public byte[] get(String key) {
206        return get(key, UID_SELF);
207    }
208
209    public boolean put(String key, byte[] value, int uid, int flags) {
210        return insert(key, value, uid, flags) == NO_ERROR;
211    }
212
213    public int insert(String key, byte[] value, int uid, int flags) {
214        try {
215            if (value == null) {
216                value = new byte[0];
217            }
218            return mBinder.insert(key, value, uid, flags);
219        } catch (RemoteException e) {
220            Log.w(TAG, "Cannot connect to keystore", e);
221            return SYSTEM_ERROR;
222        }
223    }
224
225    public boolean delete(String key, int uid) {
226        try {
227            int ret = mBinder.del(key, uid);
228            return (ret == NO_ERROR || ret == KEY_NOT_FOUND);
229        } catch (RemoteException e) {
230            Log.w(TAG, "Cannot connect to keystore", e);
231            return false;
232        }
233    }
234
235    public boolean delete(String key) {
236        return delete(key, UID_SELF);
237    }
238
239    public boolean contains(String key, int uid) {
240        try {
241            return mBinder.exist(key, uid) == NO_ERROR;
242        } catch (RemoteException e) {
243            Log.w(TAG, "Cannot connect to keystore", e);
244            return false;
245        }
246    }
247
248    public boolean contains(String key) {
249        return contains(key, UID_SELF);
250    }
251
252    /**
253     * List all entries in the keystore for {@code uid} starting with {@code prefix}.
254     */
255    public String[] list(String prefix, int uid) {
256        try {
257            return mBinder.list(prefix, uid);
258        } catch (RemoteException e) {
259            Log.w(TAG, "Cannot connect to keystore", e);
260            return null;
261        } catch (android.os.ServiceSpecificException e) {
262            Log.w(TAG, "KeyStore exception", e);
263            return null;
264        }
265    }
266
267    public String[] list(String prefix) {
268        return list(prefix, UID_SELF);
269    }
270
271    public boolean reset() {
272        try {
273            return mBinder.reset() == NO_ERROR;
274        } catch (RemoteException e) {
275            Log.w(TAG, "Cannot connect to keystore", e);
276            return false;
277        }
278    }
279
280    /**
281     * Attempt to lock the keystore for {@code user}.
282     *
283     * @param userId Android user to lock.
284     * @return whether {@code user}'s keystore was locked.
285     */
286    public boolean lock(int userId) {
287        try {
288            return mBinder.lock(userId) == NO_ERROR;
289        } catch (RemoteException e) {
290            Log.w(TAG, "Cannot connect to keystore", e);
291            return false;
292        }
293    }
294
295    public boolean lock() {
296        return lock(UserHandle.myUserId());
297    }
298
299    /**
300     * Attempt to unlock the keystore for {@code user} with the password {@code password}.
301     * This is required before keystore entries created with FLAG_ENCRYPTED can be accessed or
302     * created.
303     *
304     * @param userId Android user ID to operate on
305     * @param password user's keystore password. Should be the most recent value passed to
306     * {@link #onUserPasswordChanged} for the user.
307     *
308     * @return whether the keystore was unlocked.
309     */
310    public boolean unlock(int userId, String password) {
311        try {
312            password = password != null ? password : "";
313            mError = mBinder.unlock(userId, password);
314            return mError == NO_ERROR;
315        } catch (RemoteException e) {
316            Log.w(TAG, "Cannot connect to keystore", e);
317            return false;
318        }
319    }
320
321    public boolean unlock(String password) {
322        return unlock(UserHandle.getUserId(Process.myUid()), password);
323    }
324
325    /**
326     * Check if the keystore for {@code userId} is empty.
327     */
328    public boolean isEmpty(int userId) {
329        try {
330            return mBinder.isEmpty(userId) != 0;
331        } catch (RemoteException e) {
332            Log.w(TAG, "Cannot connect to keystore", e);
333            return false;
334        }
335    }
336
337    public boolean isEmpty() {
338        return isEmpty(UserHandle.myUserId());
339    }
340
341    public boolean generate(String key, int uid, int keyType, int keySize, int flags,
342            byte[][] args) {
343        try {
344            return mBinder.generate(key, uid, keyType, keySize, flags,
345                    new KeystoreArguments(args)) == NO_ERROR;
346        } catch (RemoteException e) {
347            Log.w(TAG, "Cannot connect to keystore", e);
348            return false;
349        }
350    }
351
352    public boolean importKey(String keyName, byte[] key, int uid, int flags) {
353        try {
354            return mBinder.import_key(keyName, key, uid, flags) == NO_ERROR;
355        } catch (RemoteException e) {
356            Log.w(TAG, "Cannot connect to keystore", e);
357            return false;
358        }
359    }
360
361    public byte[] sign(String key, byte[] data) {
362        try {
363            return mBinder.sign(key, data);
364        } catch (RemoteException e) {
365            Log.w(TAG, "Cannot connect to keystore", e);
366            return null;
367        } catch (android.os.ServiceSpecificException e) {
368            Log.w(TAG, "KeyStore exception", e);
369            return null;
370        }
371
372    }
373
374    public boolean verify(String key, byte[] data, byte[] signature) {
375        try {
376            signature = signature != null ? signature : new byte[0];
377            return mBinder.verify(key, data, signature) == NO_ERROR;
378        } catch (RemoteException e) {
379            Log.w(TAG, "Cannot connect to keystore", e);
380            return false;
381        } catch (android.os.ServiceSpecificException e) {
382            Log.w(TAG, "KeyStore exception", e);
383            return false;
384        }
385
386    }
387
388    public String grant(String key, int uid) {
389        try {
390            String grantAlias =  mBinder.grant(key, uid);
391            if (grantAlias == "") return null;
392            return grantAlias;
393        } catch (RemoteException e) {
394            Log.w(TAG, "Cannot connect to keystore", e);
395            return null;
396        }
397    }
398
399    public boolean ungrant(String key, int uid) {
400        try {
401            return mBinder.ungrant(key, uid) == NO_ERROR;
402        } catch (RemoteException e) {
403            Log.w(TAG, "Cannot connect to keystore", e);
404            return false;
405        }
406    }
407
408    /**
409     * Returns the last modification time of the key in milliseconds since the
410     * epoch. Will return -1L if the key could not be found or other error.
411     */
412    public long getmtime(String key, int uid) {
413        try {
414            final long millis = mBinder.getmtime(key, uid);
415            if (millis == -1L) {
416                return -1L;
417            }
418
419            return millis * 1000L;
420        } catch (RemoteException e) {
421            Log.w(TAG, "Cannot connect to keystore", e);
422            return -1L;
423        }
424    }
425
426    public long getmtime(String key) {
427        return getmtime(key, UID_SELF);
428    }
429
430    // TODO: remove this when it's removed from Settings
431    public boolean isHardwareBacked() {
432        return isHardwareBacked("RSA");
433    }
434
435    public boolean isHardwareBacked(String keyType) {
436        try {
437            return mBinder.is_hardware_backed(keyType.toUpperCase(Locale.US)) == NO_ERROR;
438        } catch (RemoteException e) {
439            Log.w(TAG, "Cannot connect to keystore", e);
440            return false;
441        }
442    }
443
444    public boolean clearUid(int uid) {
445        try {
446            return mBinder.clear_uid(uid) == NO_ERROR;
447        } catch (RemoteException e) {
448            Log.w(TAG, "Cannot connect to keystore", e);
449            return false;
450        }
451    }
452
453    public int getLastError() {
454        return mError;
455    }
456
457    public boolean addRngEntropy(byte[] data, int flags) {
458        try {
459            return mBinder.addRngEntropy(data, flags) == NO_ERROR;
460        } catch (RemoteException e) {
461            Log.w(TAG, "Cannot connect to keystore", e);
462            return false;
463        }
464    }
465
466    public int generateKey(String alias, KeymasterArguments args, byte[] entropy, int uid,
467            int flags, KeyCharacteristics outCharacteristics) {
468        try {
469            entropy = entropy != null ? entropy : new byte[0];
470            args = args != null ? args : new KeymasterArguments();
471            return mBinder.generateKey(alias, args, entropy, uid, flags, outCharacteristics);
472        } catch (RemoteException e) {
473            Log.w(TAG, "Cannot connect to keystore", e);
474            return SYSTEM_ERROR;
475        }
476    }
477
478    public int generateKey(String alias, KeymasterArguments args, byte[] entropy, int flags,
479            KeyCharacteristics outCharacteristics) {
480        return generateKey(alias, args, entropy, UID_SELF, flags, outCharacteristics);
481    }
482
483    public int getKeyCharacteristics(String alias, KeymasterBlob clientId, KeymasterBlob appId,
484            int uid, KeyCharacteristics outCharacteristics) {
485        try {
486            clientId = clientId != null ? clientId : new KeymasterBlob(new byte[0]);
487            appId = appId != null ? appId : new KeymasterBlob(new byte[0]);
488            return mBinder.getKeyCharacteristics(alias, clientId, appId, uid, outCharacteristics);
489        } catch (RemoteException e) {
490            Log.w(TAG, "Cannot connect to keystore", e);
491            return SYSTEM_ERROR;
492        }
493    }
494
495    public int getKeyCharacteristics(String alias, KeymasterBlob clientId, KeymasterBlob appId,
496            KeyCharacteristics outCharacteristics) {
497        return getKeyCharacteristics(alias, clientId, appId, UID_SELF, outCharacteristics);
498    }
499
500    public int importKey(String alias, KeymasterArguments args, int format, byte[] keyData,
501            int uid, int flags, KeyCharacteristics outCharacteristics) {
502        try {
503            return mBinder.importKey(alias, args, format, keyData, uid, flags,
504                    outCharacteristics);
505        } catch (RemoteException e) {
506            Log.w(TAG, "Cannot connect to keystore", e);
507            return SYSTEM_ERROR;
508        }
509    }
510
511    public int importKey(String alias, KeymasterArguments args, int format, byte[] keyData,
512            int flags, KeyCharacteristics outCharacteristics) {
513        return importKey(alias, args, format, keyData, UID_SELF, flags, outCharacteristics);
514    }
515
516    public int importWrappedKey(String wrappedKeyAlias, byte[] wrappedKey,
517            String wrappingKeyAlias,
518            byte[] maskingKey, KeymasterArguments args, long rootSid, long fingerprintSid, int uid,
519            KeyCharacteristics outCharacteristics) {
520        try {
521            return mBinder.importWrappedKey(wrappedKeyAlias, wrappedKey, wrappingKeyAlias,
522                    maskingKey, args, rootSid, fingerprintSid, outCharacteristics);
523        } catch (RemoteException e) {
524            Log.w(TAG, "Cannot connect to keystore", e);
525            return SYSTEM_ERROR;
526        }
527    }
528
529    public ExportResult exportKey(String alias, int format, KeymasterBlob clientId,
530            KeymasterBlob appId, int uid) {
531        try {
532            clientId = clientId != null ? clientId : new KeymasterBlob(new byte[0]);
533            appId = appId != null ? appId : new KeymasterBlob(new byte[0]);
534            return mBinder.exportKey(alias, format, clientId, appId, uid);
535        } catch (RemoteException e) {
536            Log.w(TAG, "Cannot connect to keystore", e);
537            return null;
538        }
539    }
540    public ExportResult exportKey(String alias, int format, KeymasterBlob clientId,
541            KeymasterBlob appId) {
542        return exportKey(alias, format, clientId, appId, UID_SELF);
543    }
544
545    public OperationResult begin(String alias, int purpose, boolean pruneable,
546            KeymasterArguments args, byte[] entropy, int uid) {
547        try {
548            args = args != null ? args : new KeymasterArguments();
549            entropy = entropy != null ? entropy : new byte[0];
550            return mBinder.begin(getToken(), alias, purpose, pruneable, args, entropy, uid);
551        } catch (RemoteException e) {
552            Log.w(TAG, "Cannot connect to keystore", e);
553            return null;
554        }
555    }
556
557    public OperationResult begin(String alias, int purpose, boolean pruneable,
558            KeymasterArguments args, byte[] entropy) {
559        entropy = entropy != null ? entropy : new byte[0];
560        args = args != null ? args : new KeymasterArguments();
561        return begin(alias, purpose, pruneable, args, entropy, UID_SELF);
562    }
563
564    public OperationResult update(IBinder token, KeymasterArguments arguments, byte[] input) {
565        try {
566            arguments = arguments != null ? arguments : new KeymasterArguments();
567            input = input != null ? input : new byte[0];
568            return mBinder.update(token, arguments, input);
569        } catch (RemoteException e) {
570            Log.w(TAG, "Cannot connect to keystore", e);
571            return null;
572        }
573    }
574
575    public OperationResult finish(IBinder token, KeymasterArguments arguments, byte[] signature,
576            byte[] entropy) {
577        try {
578            arguments = arguments != null ? arguments : new KeymasterArguments();
579            entropy = entropy != null ? entropy : new byte[0];
580            signature = signature != null ? signature : new byte[0];
581            return mBinder.finish(token, arguments, signature, entropy);
582        } catch (RemoteException e) {
583            Log.w(TAG, "Cannot connect to keystore", e);
584            return null;
585        }
586    }
587
588    public OperationResult finish(IBinder token, KeymasterArguments arguments, byte[] signature) {
589        return finish(token, arguments, signature, null);
590    }
591
592    public int abort(IBinder token) {
593        try {
594            return mBinder.abort(token);
595        } catch (RemoteException e) {
596            Log.w(TAG, "Cannot connect to keystore", e);
597            return SYSTEM_ERROR;
598        }
599    }
600
601    /**
602     * Check if the operation referenced by {@code token} is currently authorized.
603     *
604     * @param token An operation token returned by a call to
605     * {@link #begin(String, int, boolean, KeymasterArguments, byte[], KeymasterArguments) begin}.
606     */
607    public boolean isOperationAuthorized(IBinder token) {
608        try {
609            return mBinder.isOperationAuthorized(token);
610        } catch (RemoteException e) {
611            Log.w(TAG, "Cannot connect to keystore", e);
612            return false;
613        }
614    }
615
616    /**
617     * Add an authentication record to the keystore authorization table.
618     *
619     * @param authToken The packed bytes of a hw_auth_token_t to be provided to keymaster.
620     * @return {@code KeyStore.NO_ERROR} on success, otherwise an error value corresponding to
621     * a {@code KeymasterDefs.KM_ERROR_} value or {@code KeyStore} ResponseCode.
622     */
623    public int addAuthToken(byte[] authToken) {
624        try {
625            return mBinder.addAuthToken(authToken);
626        } catch (RemoteException e) {
627            Log.w(TAG, "Cannot connect to keystore", e);
628            return SYSTEM_ERROR;
629        }
630    }
631
632    /**
633     * Notify keystore that a user's password has changed.
634     *
635     * @param userId the user whose password changed.
636     * @param newPassword the new password or "" if the password was removed.
637     */
638    public boolean onUserPasswordChanged(int userId, String newPassword) {
639        // Parcel.cpp doesn't support deserializing null strings and treats them as "". Make that
640        // explicit here.
641        if (newPassword == null) {
642            newPassword = "";
643        }
644        try {
645            return mBinder.onUserPasswordChanged(userId, newPassword) == NO_ERROR;
646        } catch (RemoteException e) {
647            Log.w(TAG, "Cannot connect to keystore", e);
648            return false;
649        }
650    }
651
652    /**
653     * Notify keystore that a user was added.
654     *
655     * @param userId the new user.
656     * @param parentId the parent of the new user, or -1 if the user has no parent. If parentId is
657     * specified then the new user's keystore will be intialized with the same secure lockscreen
658     * password as the parent.
659     */
660    public void onUserAdded(int userId, int parentId) {
661        try {
662            mBinder.onUserAdded(userId, parentId);
663        } catch (RemoteException e) {
664            Log.w(TAG, "Cannot connect to keystore", e);
665        }
666    }
667
668    /**
669     * Notify keystore that a user was added.
670     *
671     * @param userId the new user.
672     */
673    public void onUserAdded(int userId) {
674        onUserAdded(userId, -1);
675    }
676
677    /**
678     * Notify keystore that a user was removed.
679     *
680     * @param userId the removed user.
681     */
682    public void onUserRemoved(int userId) {
683        try {
684            mBinder.onUserRemoved(userId);
685        } catch (RemoteException e) {
686            Log.w(TAG, "Cannot connect to keystore", e);
687        }
688    }
689
690    public boolean onUserPasswordChanged(String newPassword) {
691        return onUserPasswordChanged(UserHandle.getUserId(Process.myUid()), newPassword);
692    }
693
694    public int attestKey(
695            String alias, KeymasterArguments params, KeymasterCertificateChain outChain) {
696        try {
697            if (params == null) {
698                params = new KeymasterArguments();
699            }
700            if (outChain == null) {
701                outChain = new KeymasterCertificateChain();
702            }
703            return mBinder.attestKey(alias, params, outChain);
704        } catch (RemoteException e) {
705            Log.w(TAG, "Cannot connect to keystore", e);
706            return SYSTEM_ERROR;
707        }
708    }
709
710    public int attestDeviceIds(KeymasterArguments params, KeymasterCertificateChain outChain) {
711        try {
712            if (params == null) {
713                params = new KeymasterArguments();
714            }
715            if (outChain == null) {
716                outChain = new KeymasterCertificateChain();
717            }
718            return mBinder.attestDeviceIds(params, outChain);
719        } catch (RemoteException e) {
720            Log.w(TAG, "Cannot connect to keystore", e);
721            return SYSTEM_ERROR;
722        }
723    }
724
725    /**
726     * Notify keystore that the device went off-body.
727     */
728    public void onDeviceOffBody() {
729        try {
730            mBinder.onDeviceOffBody();
731        } catch (RemoteException e) {
732            Log.w(TAG, "Cannot connect to keystore", e);
733        }
734    }
735
736    // Keep in sync with confirmationui/1.0/types.hal.
737    public static final int CONFIRMATIONUI_OK = 0;
738    public static final int CONFIRMATIONUI_CANCELED = 1;
739    public static final int CONFIRMATIONUI_ABORTED = 2;
740    public static final int CONFIRMATIONUI_OPERATION_PENDING = 3;
741    public static final int CONFIRMATIONUI_IGNORED = 4;
742    public static final int CONFIRMATIONUI_SYSTEM_ERROR = 5;
743    public static final int CONFIRMATIONUI_UNIMPLEMENTED = 6;
744    public static final int CONFIRMATIONUI_UNEXPECTED = 7;
745    public static final int CONFIRMATIONUI_UIERROR = 0x10000;
746    public static final int CONFIRMATIONUI_UIERROR_MISSING_GLYPH = 0x10001;
747    public static final int CONFIRMATIONUI_UIERROR_MESSAGE_TOO_LONG = 0x10002;
748    public static final int CONFIRMATIONUI_UIERROR_MALFORMED_UTF8_ENCODING = 0x10003;
749
750    /**
751     * Requests keystore call into the confirmationui HAL to display a prompt.
752     *
753     * @param listener the binder to use for callbacks.
754     * @param promptText the prompt to display.
755     * @param extraData extra data / nonce from application.
756     * @param locale the locale as a BCP 47 langauge tag.
757     * @param uiOptionsAsFlags the UI options to use, as flags.
758     * @return one of the {@code CONFIRMATIONUI_*} constants, for
759     * example {@code KeyStore.CONFIRMATIONUI_OK}.
760     */
761    public int presentConfirmationPrompt(IBinder listener, String promptText, byte[] extraData,
762                                         String locale, int uiOptionsAsFlags) {
763        try {
764            return mBinder.presentConfirmationPrompt(listener, promptText, extraData, locale,
765                                                     uiOptionsAsFlags);
766        } catch (RemoteException e) {
767            Log.w(TAG, "Cannot connect to keystore", e);
768            return CONFIRMATIONUI_SYSTEM_ERROR;
769        }
770    }
771
772    /**
773     * Requests keystore call into the confirmationui HAL to cancel displaying a prompt.
774     *
775     * @param listener the binder passed to the {@link #presentConfirmationPrompt} method.
776     * @return one of the {@code CONFIRMATIONUI_*} constants, for
777     * example {@code KeyStore.CONFIRMATIONUI_OK}.
778     */
779    public int cancelConfirmationPrompt(IBinder listener) {
780        try {
781            return mBinder.cancelConfirmationPrompt(listener);
782        } catch (RemoteException e) {
783            Log.w(TAG, "Cannot connect to keystore", e);
784            return CONFIRMATIONUI_SYSTEM_ERROR;
785        }
786    }
787
788    /**
789     * Requests keystore to check if the confirmationui HAL is available.
790     *
791     * @return whether the confirmationUI HAL is available.
792     */
793    public boolean isConfirmationPromptSupported() {
794        try {
795            return mBinder.isConfirmationPromptSupported();
796        } catch (RemoteException e) {
797            Log.w(TAG, "Cannot connect to keystore", e);
798            return false;
799        }
800    }
801
802    /**
803     * Returns a {@link KeyStoreException} corresponding to the provided keystore/keymaster error
804     * code.
805     */
806    public static KeyStoreException getKeyStoreException(int errorCode) {
807        if (errorCode > 0) {
808            // KeyStore layer error
809            switch (errorCode) {
810                case NO_ERROR:
811                    return new KeyStoreException(errorCode, "OK");
812                case LOCKED:
813                    return new KeyStoreException(errorCode, "User authentication required");
814                case UNINITIALIZED:
815                    return new KeyStoreException(errorCode, "Keystore not initialized");
816                case SYSTEM_ERROR:
817                    return new KeyStoreException(errorCode, "System error");
818                case PERMISSION_DENIED:
819                    return new KeyStoreException(errorCode, "Permission denied");
820                case KEY_NOT_FOUND:
821                    return new KeyStoreException(errorCode, "Key not found");
822                case VALUE_CORRUPTED:
823                    return new KeyStoreException(errorCode, "Key blob corrupted");
824                case OP_AUTH_NEEDED:
825                    return new KeyStoreException(errorCode, "Operation requires authorization");
826                default:
827                    return new KeyStoreException(errorCode, String.valueOf(errorCode));
828            }
829        } else {
830            // Keymaster layer error
831            switch (errorCode) {
832                case KeymasterDefs.KM_ERROR_INVALID_AUTHORIZATION_TIMEOUT:
833                    // The name of this parameter significantly differs between Keymaster and
834                    // framework APIs. Use the framework wording to make life easier for developers.
835                    return new KeyStoreException(errorCode,
836                            "Invalid user authentication validity duration");
837                default:
838                    return new KeyStoreException(errorCode,
839                            KeymasterDefs.getErrorMessage(errorCode));
840            }
841        }
842    }
843
844    /**
845     * Returns an {@link InvalidKeyException} corresponding to the provided
846     * {@link KeyStoreException}.
847     */
848    public InvalidKeyException getInvalidKeyException(
849            String keystoreKeyAlias, int uid, KeyStoreException e) {
850        switch (e.getErrorCode()) {
851            case LOCKED:
852                return new UserNotAuthenticatedException();
853            case KeymasterDefs.KM_ERROR_KEY_EXPIRED:
854                return new KeyExpiredException();
855            case KeymasterDefs.KM_ERROR_KEY_NOT_YET_VALID:
856                return new KeyNotYetValidException();
857            case KeymasterDefs.KM_ERROR_KEY_USER_NOT_AUTHENTICATED:
858            case OP_AUTH_NEEDED:
859            {
860                // We now need to determine whether the key/operation can become usable if user
861                // authentication is performed, or whether it can never become usable again.
862                // User authentication requirements are contained in the key's characteristics. We
863                // need to check whether these requirements can be be satisfied by asking the user
864                // to authenticate.
865                KeyCharacteristics keyCharacteristics = new KeyCharacteristics();
866                int getKeyCharacteristicsErrorCode =
867                        getKeyCharacteristics(keystoreKeyAlias, null, null, uid,
868                                keyCharacteristics);
869                if (getKeyCharacteristicsErrorCode != NO_ERROR) {
870                    return new InvalidKeyException(
871                            "Failed to obtained key characteristics",
872                            getKeyStoreException(getKeyCharacteristicsErrorCode));
873                }
874                List<BigInteger> keySids =
875                        keyCharacteristics.getUnsignedLongs(KeymasterDefs.KM_TAG_USER_SECURE_ID);
876                if (keySids.isEmpty()) {
877                    // Key is not bound to any SIDs -- no amount of authentication will help here.
878                    return new KeyPermanentlyInvalidatedException();
879                }
880                long rootSid = GateKeeper.getSecureUserId();
881                if ((rootSid != 0) && (keySids.contains(KeymasterArguments.toUint64(rootSid)))) {
882                    // One of the key's SIDs is the current root SID -- user can be authenticated
883                    // against that SID.
884                    return new UserNotAuthenticatedException();
885                }
886
887                long fingerprintOnlySid = getFingerprintOnlySid();
888                if ((fingerprintOnlySid != 0)
889                        && (keySids.contains(KeymasterArguments.toUint64(fingerprintOnlySid)))) {
890                    // One of the key's SIDs is the current fingerprint SID -- user can be
891                    // authenticated against that SID.
892                    return new UserNotAuthenticatedException();
893                }
894
895                // None of the key's SIDs can ever be authenticated
896                return new KeyPermanentlyInvalidatedException();
897            }
898            case UNINITIALIZED:
899                return new KeyPermanentlyInvalidatedException();
900            default:
901                return new InvalidKeyException("Keystore operation failed", e);
902        }
903    }
904
905    private long getFingerprintOnlySid() {
906        final PackageManager packageManager = mContext.getPackageManager();
907        if (!packageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) {
908            return 0;
909        }
910        FingerprintManager fingerprintManager = mContext.getSystemService(FingerprintManager.class);
911        if (fingerprintManager == null) {
912            return 0;
913        }
914
915        // TODO: Restore USE_FINGERPRINT permission check in
916        // FingerprintManager.getAuthenticatorId once the ID is no longer needed here.
917        return fingerprintManager.getAuthenticatorId();
918    }
919
920    /**
921     * Returns an {@link InvalidKeyException} corresponding to the provided keystore/keymaster error
922     * code.
923     */
924    public InvalidKeyException getInvalidKeyException(String keystoreKeyAlias, int uid,
925            int errorCode) {
926        return getInvalidKeyException(keystoreKeyAlias, uid, getKeyStoreException(errorCode));
927    }
928}
929