KeyStore.java revision 3876b1be27e3aefde9a72eb2e4f856e94fc5f946
1/*
2 * Copyright (C) 2009 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.security;
18
19import android.app.ActivityThread;
20import android.app.Application;
21import android.app.KeyguardManager;
22
23import android.content.Context;
24import android.hardware.fingerprint.FingerprintManager;
25import android.os.Binder;
26import android.os.IBinder;
27import android.os.Process;
28import android.os.RemoteException;
29import android.os.ServiceManager;
30import android.os.UserHandle;
31import android.security.keymaster.ExportResult;
32import android.security.keymaster.KeyCharacteristics;
33import android.security.keymaster.KeymasterArguments;
34import android.security.keymaster.KeymasterBlob;
35import android.security.keymaster.KeymasterDefs;
36import android.security.keymaster.OperationResult;
37import android.security.keystore.KeyExpiredException;
38import android.security.keystore.KeyNotYetValidException;
39import android.security.keystore.KeyPermanentlyInvalidatedException;
40import android.security.keystore.UserNotAuthenticatedException;
41import android.util.Log;
42
43import java.math.BigInteger;
44import java.security.InvalidKeyException;
45import java.util.List;
46import java.util.Locale;
47
48/**
49 * @hide This should not be made public in its present form because it
50 * assumes that private and secret key bytes are available and would
51 * preclude the use of hardware crypto.
52 */
53public class KeyStore {
54    private static final String TAG = "KeyStore";
55
56    // ResponseCodes
57    public static final int NO_ERROR = 1;
58    public static final int LOCKED = 2;
59    public static final int UNINITIALIZED = 3;
60    public static final int SYSTEM_ERROR = 4;
61    public static final int PROTOCOL_ERROR = 5;
62    public static final int PERMISSION_DENIED = 6;
63    public static final int KEY_NOT_FOUND = 7;
64    public static final int VALUE_CORRUPTED = 8;
65    public static final int UNDEFINED_ACTION = 9;
66    public static final int WRONG_PASSWORD = 10;
67
68    /**
69     * Per operation authentication is needed before this operation is valid.
70     * This is returned from {@link #begin} when begin succeeds but the operation uses
71     * per-operation authentication and must authenticate before calling {@link #update} or
72     * {@link #finish}.
73     */
74    public static final int OP_AUTH_NEEDED = 15;
75
76    // Used for UID field to indicate the calling UID.
77    public static final int UID_SELF = -1;
78
79    // Flags for "put" "import" and "generate"
80    public static final int FLAG_NONE = 0;
81
82    /**
83     * Indicates that this key (or key pair) must be encrypted at rest. This will protect the key
84     * (or key pair) with the secure lock screen credential (e.g., password, PIN, or pattern).
85     *
86     * <p>Note that this requires that the secure lock screen (e.g., password, PIN, pattern) is set
87     * up, otherwise key (or key pair) generation or import will fail. Moreover, this key (or key
88     * pair) will be deleted when the secure lock screen is disabled or reset (e.g., by the user or
89     * a Device Administrator). Finally, this key (or key pair) cannot be used until the user
90     * unlocks the secure lock screen after boot.
91     *
92     * @see KeyguardManager#isDeviceSecure()
93     */
94    public static final int FLAG_ENCRYPTED = 1;
95
96    // States
97    public enum State { UNLOCKED, LOCKED, UNINITIALIZED };
98
99    private int mError = NO_ERROR;
100
101    private final IKeystoreService mBinder;
102    private final Context mContext;
103
104    private IBinder mToken;
105
106    private KeyStore(IKeystoreService binder) {
107        mBinder = binder;
108        mContext = getApplicationContext();
109    }
110
111    public static Context getApplicationContext() {
112        Application application = ActivityThread.currentApplication();
113        if (application == null) {
114            throw new IllegalStateException(
115                    "Failed to obtain application Context from ActivityThread");
116        }
117        return application;
118    }
119
120    public static KeyStore getInstance() {
121        IKeystoreService keystore = IKeystoreService.Stub.asInterface(ServiceManager
122                .getService("android.security.keystore"));
123        return new KeyStore(keystore);
124    }
125
126    private synchronized IBinder getToken() {
127        if (mToken == null) {
128            mToken = new Binder();
129        }
130        return mToken;
131    }
132
133    public State state(int userId) {
134        final int ret;
135        try {
136            ret = mBinder.getState(userId);
137        } catch (RemoteException e) {
138            Log.w(TAG, "Cannot connect to keystore", e);
139            throw new AssertionError(e);
140        }
141
142        switch (ret) {
143            case NO_ERROR: return State.UNLOCKED;
144            case LOCKED: return State.LOCKED;
145            case UNINITIALIZED: return State.UNINITIALIZED;
146            default: throw new AssertionError(mError);
147        }
148    }
149
150    public State state() {
151        return state(UserHandle.myUserId());
152    }
153
154    public boolean isUnlocked() {
155        return state() == State.UNLOCKED;
156    }
157
158    public byte[] get(String key) {
159        try {
160            return mBinder.get(key);
161        } catch (RemoteException e) {
162            Log.w(TAG, "Cannot connect to keystore", e);
163            return null;
164        }
165    }
166
167    public boolean put(String key, byte[] value, int uid, int flags) {
168        return insert(key, value, uid, flags) == NO_ERROR;
169    }
170
171    public int insert(String key, byte[] value, int uid, int flags) {
172        try {
173            return mBinder.insert(key, value, uid, flags);
174        } catch (RemoteException e) {
175            Log.w(TAG, "Cannot connect to keystore", e);
176            return SYSTEM_ERROR;
177        }
178    }
179
180    public boolean delete(String key, int uid) {
181        try {
182            return mBinder.del(key, uid) == NO_ERROR;
183        } catch (RemoteException e) {
184            Log.w(TAG, "Cannot connect to keystore", e);
185            return false;
186        }
187    }
188
189    public boolean delete(String key) {
190        return delete(key, UID_SELF);
191    }
192
193    public boolean contains(String key, int uid) {
194        try {
195            return mBinder.exist(key, uid) == NO_ERROR;
196        } catch (RemoteException e) {
197            Log.w(TAG, "Cannot connect to keystore", e);
198            return false;
199        }
200    }
201
202    public boolean contains(String key) {
203        return contains(key, UID_SELF);
204    }
205
206    /**
207     * List all entries in the keystore for {@code uid} starting with {@code prefix}.
208     */
209    public String[] list(String prefix, int uid) {
210        try {
211            return mBinder.list(prefix, uid);
212        } catch (RemoteException e) {
213            Log.w(TAG, "Cannot connect to keystore", e);
214            return null;
215        }
216    }
217
218    public String[] list(String prefix) {
219        return list(prefix, UID_SELF);
220    }
221
222    public boolean reset() {
223        try {
224            return mBinder.reset() == NO_ERROR;
225        } catch (RemoteException e) {
226            Log.w(TAG, "Cannot connect to keystore", e);
227            return false;
228        }
229    }
230
231    /**
232     * Attempt to lock the keystore for {@code user}.
233     *
234     * @param user Android user to lock.
235     * @return whether {@code user}'s keystore was locked.
236     */
237    public boolean lock(int userId) {
238        try {
239            return mBinder.lock(userId) == NO_ERROR;
240        } catch (RemoteException e) {
241            Log.w(TAG, "Cannot connect to keystore", e);
242            return false;
243        }
244    }
245
246    public boolean lock() {
247        return lock(UserHandle.myUserId());
248    }
249
250    /**
251     * Attempt to unlock the keystore for {@code user} with the password {@code password}.
252     * This is required before keystore entries created with FLAG_ENCRYPTED can be accessed or
253     * created.
254     *
255     * @param user Android user ID to operate on
256     * @param password user's keystore password. Should be the most recent value passed to
257     * {@link #onUserPasswordChanged} for the user.
258     *
259     * @return whether the keystore was unlocked.
260     */
261    public boolean unlock(int userId, String password) {
262        try {
263            mError = mBinder.unlock(userId, password);
264            return mError == NO_ERROR;
265        } catch (RemoteException e) {
266            Log.w(TAG, "Cannot connect to keystore", e);
267            return false;
268        }
269    }
270
271    public boolean unlock(String password) {
272        return unlock(UserHandle.getUserId(Process.myUid()), password);
273    }
274
275    /**
276     * Check if the keystore for {@code userId} is empty.
277     */
278    public boolean isEmpty(int userId) {
279        try {
280            return mBinder.isEmpty(userId) != 0;
281        } catch (RemoteException e) {
282            Log.w(TAG, "Cannot connect to keystore", e);
283            return false;
284        }
285    }
286
287    public boolean isEmpty() {
288        return isEmpty(UserHandle.myUserId());
289    }
290
291    public boolean generate(String key, int uid, int keyType, int keySize, int flags,
292            byte[][] args) {
293        try {
294            return mBinder.generate(key, uid, keyType, keySize, flags,
295                    new KeystoreArguments(args)) == NO_ERROR;
296        } catch (RemoteException e) {
297            Log.w(TAG, "Cannot connect to keystore", e);
298            return false;
299        }
300    }
301
302    public boolean importKey(String keyName, byte[] key, int uid, int flags) {
303        try {
304            return mBinder.import_key(keyName, key, uid, flags) == NO_ERROR;
305        } catch (RemoteException e) {
306            Log.w(TAG, "Cannot connect to keystore", e);
307            return false;
308        }
309    }
310
311    public byte[] sign(String key, byte[] data) {
312        try {
313            return mBinder.sign(key, data);
314        } catch (RemoteException e) {
315            Log.w(TAG, "Cannot connect to keystore", e);
316            return null;
317        }
318    }
319
320    public boolean verify(String key, byte[] data, byte[] signature) {
321        try {
322            return mBinder.verify(key, data, signature) == NO_ERROR;
323        } catch (RemoteException e) {
324            Log.w(TAG, "Cannot connect to keystore", e);
325            return false;
326        }
327    }
328
329    public boolean grant(String key, int uid) {
330        try {
331            return mBinder.grant(key, uid) == NO_ERROR;
332        } catch (RemoteException e) {
333            Log.w(TAG, "Cannot connect to keystore", e);
334            return false;
335        }
336    }
337
338    public boolean ungrant(String key, int uid) {
339        try {
340            return mBinder.ungrant(key, uid) == NO_ERROR;
341        } catch (RemoteException e) {
342            Log.w(TAG, "Cannot connect to keystore", e);
343            return false;
344        }
345    }
346
347    /**
348     * Returns the last modification time of the key in milliseconds since the
349     * epoch. Will return -1L if the key could not be found or other error.
350     */
351    public long getmtime(String key) {
352        try {
353            final long millis = mBinder.getmtime(key);
354            if (millis == -1L) {
355                return -1L;
356            }
357
358            return millis * 1000L;
359        } catch (RemoteException e) {
360            Log.w(TAG, "Cannot connect to keystore", e);
361            return -1L;
362        }
363    }
364
365    public boolean duplicate(String srcKey, int srcUid, String destKey, int destUid) {
366        try {
367            return mBinder.duplicate(srcKey, srcUid, destKey, destUid) == NO_ERROR;
368        } catch (RemoteException e) {
369            Log.w(TAG, "Cannot connect to keystore", e);
370            return false;
371        }
372    }
373
374    // TODO: remove this when it's removed from Settings
375    public boolean isHardwareBacked() {
376        return isHardwareBacked("RSA");
377    }
378
379    public boolean isHardwareBacked(String keyType) {
380        try {
381            return mBinder.is_hardware_backed(keyType.toUpperCase(Locale.US)) == NO_ERROR;
382        } catch (RemoteException e) {
383            Log.w(TAG, "Cannot connect to keystore", e);
384            return false;
385        }
386    }
387
388    public boolean clearUid(int uid) {
389        try {
390            return mBinder.clear_uid(uid) == NO_ERROR;
391        } catch (RemoteException e) {
392            Log.w(TAG, "Cannot connect to keystore", e);
393            return false;
394        }
395    }
396
397    public int getLastError() {
398        return mError;
399    }
400
401    public boolean addRngEntropy(byte[] data) {
402        try {
403            return mBinder.addRngEntropy(data) == NO_ERROR;
404        } catch (RemoteException e) {
405            Log.w(TAG, "Cannot connect to keystore", e);
406            return false;
407        }
408    }
409
410    public int generateKey(String alias, KeymasterArguments args, byte[] entropy, int uid,
411            int flags, KeyCharacteristics outCharacteristics) {
412        try {
413            return mBinder.generateKey(alias, args, entropy, uid, flags, outCharacteristics);
414        } catch (RemoteException e) {
415            Log.w(TAG, "Cannot connect to keystore", e);
416            return SYSTEM_ERROR;
417        }
418    }
419
420    public int generateKey(String alias, KeymasterArguments args, byte[] entropy, int flags,
421            KeyCharacteristics outCharacteristics) {
422        return generateKey(alias, args, entropy, UID_SELF, flags, outCharacteristics);
423    }
424
425    public int getKeyCharacteristics(String alias, KeymasterBlob clientId, KeymasterBlob appId,
426            KeyCharacteristics outCharacteristics) {
427        try {
428            return mBinder.getKeyCharacteristics(alias, clientId, appId, outCharacteristics);
429        } catch (RemoteException e) {
430            Log.w(TAG, "Cannot connect to keystore", e);
431            return SYSTEM_ERROR;
432        }
433    }
434
435    public int importKey(String alias, KeymasterArguments args, int format, byte[] keyData,
436            int uid, int flags, KeyCharacteristics outCharacteristics) {
437        try {
438            return mBinder.importKey(alias, args, format, keyData, uid, flags,
439                    outCharacteristics);
440        } catch (RemoteException e) {
441            Log.w(TAG, "Cannot connect to keystore", e);
442            return SYSTEM_ERROR;
443        }
444    }
445
446    public int importKey(String alias, KeymasterArguments args, int format, byte[] keyData,
447            int flags, KeyCharacteristics outCharacteristics) {
448        return importKey(alias, args, format, keyData, UID_SELF, flags, outCharacteristics);
449    }
450
451    public ExportResult exportKey(String alias, int format, KeymasterBlob clientId,
452            KeymasterBlob appId) {
453        try {
454            return mBinder.exportKey(alias, format, clientId, appId);
455        } catch (RemoteException e) {
456            Log.w(TAG, "Cannot connect to keystore", e);
457            return null;
458        }
459    }
460
461    public OperationResult begin(String alias, int purpose, boolean pruneable,
462            KeymasterArguments args, byte[] entropy) {
463        try {
464            return mBinder.begin(getToken(), alias, purpose, pruneable, args, entropy);
465        } catch (RemoteException e) {
466            Log.w(TAG, "Cannot connect to keystore", e);
467            return null;
468        }
469    }
470
471    public OperationResult update(IBinder token, KeymasterArguments arguments, byte[] input) {
472        try {
473            return mBinder.update(token, arguments, input);
474        } catch (RemoteException e) {
475            Log.w(TAG, "Cannot connect to keystore", e);
476            return null;
477        }
478    }
479
480    public OperationResult finish(IBinder token, KeymasterArguments arguments, byte[] signature,
481            byte[] entropy) {
482        try {
483            return mBinder.finish(token, arguments, signature, entropy);
484        } catch (RemoteException e) {
485            Log.w(TAG, "Cannot connect to keystore", e);
486            return null;
487        }
488    }
489
490    public OperationResult finish(IBinder token, KeymasterArguments arguments, byte[] signature) {
491        return finish(token, arguments, signature, null);
492    }
493
494    public int abort(IBinder token) {
495        try {
496            return mBinder.abort(token);
497        } catch (RemoteException e) {
498            Log.w(TAG, "Cannot connect to keystore", e);
499            return SYSTEM_ERROR;
500        }
501    }
502
503    /**
504     * Check if the operation referenced by {@code token} is currently authorized.
505     *
506     * @param token An operation token returned by a call to
507     * {@link #begin(String, int, boolean, KeymasterArguments, byte[], KeymasterArguments) begin}.
508     */
509    public boolean isOperationAuthorized(IBinder token) {
510        try {
511            return mBinder.isOperationAuthorized(token);
512        } catch (RemoteException e) {
513            Log.w(TAG, "Cannot connect to keystore", e);
514            return false;
515        }
516    }
517
518    /**
519     * Add an authentication record to the keystore authorization table.
520     *
521     * @param authToken The packed bytes of a hw_auth_token_t to be provided to keymaster.
522     * @return {@code KeyStore.NO_ERROR} on success, otherwise an error value corresponding to
523     * a {@code KeymasterDefs.KM_ERROR_} value or {@code KeyStore} ResponseCode.
524     */
525    public int addAuthToken(byte[] authToken) {
526        try {
527            return mBinder.addAuthToken(authToken);
528        } catch (RemoteException e) {
529            Log.w(TAG, "Cannot connect to keystore", e);
530            return SYSTEM_ERROR;
531        }
532    }
533
534    /**
535     * Notify keystore that a user's password has changed.
536     *
537     * @param userId the user whose password changed.
538     * @param newPassword the new password or "" if the password was removed.
539     */
540    public boolean onUserPasswordChanged(int userId, String newPassword) {
541        // Parcel.cpp doesn't support deserializing null strings and treats them as "". Make that
542        // explicit here.
543        if (newPassword == null) {
544            newPassword = "";
545        }
546        try {
547            return mBinder.onUserPasswordChanged(userId, newPassword) == NO_ERROR;
548        } catch (RemoteException e) {
549            Log.w(TAG, "Cannot connect to keystore", e);
550            return false;
551        }
552    }
553
554    /**
555     * Notify keystore that a user was added.
556     *
557     * @param userId the new user.
558     * @param parentId the parent of the new user, or -1 if the user has no parent. If parentId is
559     * specified then the new user's keystore will be intialized with the same secure lockscreen
560     * password as the parent.
561     */
562    public void onUserAdded(int userId, int parentId) {
563        try {
564            mBinder.onUserAdded(userId, parentId);
565        } catch (RemoteException e) {
566            Log.w(TAG, "Cannot connect to keystore", e);
567        }
568    }
569
570    /**
571     * Notify keystore that a user was added.
572     *
573     * @param userId the new user.
574     */
575    public void onUserAdded(int userId) {
576        onUserAdded(userId, -1);
577    }
578
579    /**
580     * Notify keystore that a user was removed.
581     *
582     * @param userId the removed user.
583     */
584    public void onUserRemoved(int userId) {
585        try {
586            mBinder.onUserRemoved(userId);
587        } catch (RemoteException e) {
588            Log.w(TAG, "Cannot connect to keystore", e);
589        }
590    }
591
592    public boolean onUserPasswordChanged(String newPassword) {
593        return onUserPasswordChanged(UserHandle.getUserId(Process.myUid()), newPassword);
594    }
595
596    /**
597     * Returns a {@link KeyStoreException} corresponding to the provided keystore/keymaster error
598     * code.
599     */
600    public static KeyStoreException getKeyStoreException(int errorCode) {
601        if (errorCode > 0) {
602            // KeyStore layer error
603            switch (errorCode) {
604                case NO_ERROR:
605                    return new KeyStoreException(errorCode, "OK");
606                case LOCKED:
607                    return new KeyStoreException(errorCode, "User authentication required");
608                case UNINITIALIZED:
609                    return new KeyStoreException(errorCode, "Keystore not initialized");
610                case SYSTEM_ERROR:
611                    return new KeyStoreException(errorCode, "System error");
612                case PERMISSION_DENIED:
613                    return new KeyStoreException(errorCode, "Permission denied");
614                case KEY_NOT_FOUND:
615                    return new KeyStoreException(errorCode, "Key not found");
616                case VALUE_CORRUPTED:
617                    return new KeyStoreException(errorCode, "Key blob corrupted");
618                case OP_AUTH_NEEDED:
619                    return new KeyStoreException(errorCode, "Operation requires authorization");
620                default:
621                    return new KeyStoreException(errorCode, String.valueOf(errorCode));
622            }
623        } else {
624            // Keymaster layer error
625            switch (errorCode) {
626                case KeymasterDefs.KM_ERROR_INVALID_AUTHORIZATION_TIMEOUT:
627                    // The name of this parameter significantly differs between Keymaster and
628                    // framework APIs. Use the framework wording to make life easier for developers.
629                    return new KeyStoreException(errorCode,
630                            "Invalid user authentication validity duration");
631                default:
632                    return new KeyStoreException(errorCode,
633                            KeymasterDefs.getErrorMessage(errorCode));
634            }
635        }
636    }
637
638    /**
639     * Returns an {@link InvalidKeyException} corresponding to the provided
640     * {@link KeyStoreException}.
641     */
642    public InvalidKeyException getInvalidKeyException(
643            String keystoreKeyAlias, int uid, KeyStoreException e) {
644        switch (e.getErrorCode()) {
645            case LOCKED:
646                return new UserNotAuthenticatedException();
647            case KeymasterDefs.KM_ERROR_KEY_EXPIRED:
648                return new KeyExpiredException();
649            case KeymasterDefs.KM_ERROR_KEY_NOT_YET_VALID:
650                return new KeyNotYetValidException();
651            case KeymasterDefs.KM_ERROR_KEY_USER_NOT_AUTHENTICATED:
652            case OP_AUTH_NEEDED:
653            {
654                // We now need to determine whether the key/operation can become usable if user
655                // authentication is performed, or whether it can never become usable again.
656                // User authentication requirements are contained in the key's characteristics. We
657                // need to check whether these requirements can be be satisfied by asking the user
658                // to authenticate.
659                KeyCharacteristics keyCharacteristics = new KeyCharacteristics();
660                int getKeyCharacteristicsErrorCode =
661                        getKeyCharacteristics(keystoreKeyAlias, null, null, uid,
662                                keyCharacteristics);
663                if (getKeyCharacteristicsErrorCode != NO_ERROR) {
664                    return new InvalidKeyException(
665                            "Failed to obtained key characteristics",
666                            getKeyStoreException(getKeyCharacteristicsErrorCode));
667                }
668                List<BigInteger> keySids =
669                        keyCharacteristics.getUnsignedLongs(KeymasterDefs.KM_TAG_USER_SECURE_ID);
670                if (keySids.isEmpty()) {
671                    // Key is not bound to any SIDs -- no amount of authentication will help here.
672                    return new KeyPermanentlyInvalidatedException();
673                }
674                long rootSid = GateKeeper.getSecureUserId();
675                if ((rootSid != 0) && (keySids.contains(KeymasterArguments.toUint64(rootSid)))) {
676                    // One of the key's SIDs is the current root SID -- user can be authenticated
677                    // against that SID.
678                    return new UserNotAuthenticatedException();
679                }
680
681                long fingerprintOnlySid = getFingerprintOnlySid();
682                if ((fingerprintOnlySid != 0)
683                        && (keySids.contains(KeymasterArguments.toUint64(fingerprintOnlySid)))) {
684                    // One of the key's SIDs is the current fingerprint SID -- user can be
685                    // authenticated against that SID.
686                    return new UserNotAuthenticatedException();
687                }
688
689                // None of the key's SIDs can ever be authenticated
690                return new KeyPermanentlyInvalidatedException();
691            }
692            default:
693                return new InvalidKeyException("Keystore operation failed", e);
694        }
695    }
696
697    private long getFingerprintOnlySid() {
698        FingerprintManager fingerprintManager = mContext.getSystemService(FingerprintManager.class);
699        if (fingerprintManager == null) {
700            return 0;
701        }
702
703        // TODO: Restore USE_FINGERPRINT permission check in
704        // FingerprintManager.getAuthenticatorId once the ID is no longer needed here.
705        return fingerprintManager.getAuthenticatorId();
706    }
707
708    /**
709     * Returns an {@link InvalidKeyException} corresponding to the provided keystore/keymaster error
710     * code.
711     */
712    public InvalidKeyException getInvalidKeyException(String keystoreKeyAlias, int uid,
713            int errorCode) {
714        return getInvalidKeyException(keystoreKeyAlias, uid, getKeyStoreException(errorCode));
715    }
716}
717