KeyStore.java revision dae79e540844741fc35c648efe8bbb00fc8ab781
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 com.android.org.conscrypt.NativeCrypto;
20
21import android.os.Binder;
22import android.os.IBinder;
23import android.os.RemoteException;
24import android.os.ServiceManager;
25import android.security.keymaster.ExportResult;
26import android.security.keymaster.KeyCharacteristics;
27import android.security.keymaster.KeymasterArguments;
28import android.security.keymaster.KeymasterBlob;
29import android.security.keymaster.OperationResult;
30import android.util.Log;
31
32import java.util.Locale;
33
34/**
35 * @hide This should not be made public in its present form because it
36 * assumes that private and secret key bytes are available and would
37 * preclude the use of hardware crypto.
38 */
39public class KeyStore {
40    private static final String TAG = "KeyStore";
41
42    // ResponseCodes
43    public static final int NO_ERROR = 1;
44    public static final int LOCKED = 2;
45    public static final int UNINITIALIZED = 3;
46    public static final int SYSTEM_ERROR = 4;
47    public static final int PROTOCOL_ERROR = 5;
48    public static final int PERMISSION_DENIED = 6;
49    public static final int KEY_NOT_FOUND = 7;
50    public static final int VALUE_CORRUPTED = 8;
51    public static final int UNDEFINED_ACTION = 9;
52    public static final int WRONG_PASSWORD = 10;
53
54    // Used for UID field to indicate the calling UID.
55    public static final int UID_SELF = -1;
56
57    // Flags for "put" "import" and "generate"
58    public static final int FLAG_NONE = 0;
59    public static final int FLAG_ENCRYPTED = 1;
60
61    // States
62    public enum State { UNLOCKED, LOCKED, UNINITIALIZED };
63
64    private int mError = NO_ERROR;
65
66    private final IKeystoreService mBinder;
67
68    private IBinder mToken;
69
70    private KeyStore(IKeystoreService binder) {
71        mBinder = binder;
72    }
73
74    public static KeyStore getInstance() {
75        IKeystoreService keystore = IKeystoreService.Stub.asInterface(ServiceManager
76                .getService("android.security.keystore"));
77        return new KeyStore(keystore);
78    }
79
80    private synchronized IBinder getToken() {
81        if (mToken == null) {
82            mToken = new Binder();
83        }
84        return mToken;
85    }
86
87    static int getKeyTypeForAlgorithm(String keyType) {
88        if ("RSA".equalsIgnoreCase(keyType)) {
89            return NativeCrypto.EVP_PKEY_RSA;
90        } else if ("EC".equalsIgnoreCase(keyType)) {
91            return NativeCrypto.EVP_PKEY_EC;
92        } else {
93            return -1;
94        }
95    }
96
97    public State state() {
98        final int ret;
99        try {
100            ret = mBinder.test();
101        } catch (RemoteException e) {
102            Log.w(TAG, "Cannot connect to keystore", e);
103            throw new AssertionError(e);
104        }
105
106        switch (ret) {
107            case NO_ERROR: return State.UNLOCKED;
108            case LOCKED: return State.LOCKED;
109            case UNINITIALIZED: return State.UNINITIALIZED;
110            default: throw new AssertionError(mError);
111        }
112    }
113
114    public boolean isUnlocked() {
115        return state() == State.UNLOCKED;
116    }
117
118    public byte[] get(String key) {
119        try {
120            return mBinder.get(key);
121        } catch (RemoteException e) {
122            Log.w(TAG, "Cannot connect to keystore", e);
123            return null;
124        }
125    }
126
127    public boolean put(String key, byte[] value, int uid, int flags) {
128        try {
129            return mBinder.insert(key, value, uid, flags) == NO_ERROR;
130        } catch (RemoteException e) {
131            Log.w(TAG, "Cannot connect to keystore", e);
132            return false;
133        }
134    }
135
136    public boolean delete(String key, int uid) {
137        try {
138            return mBinder.del(key, uid) == NO_ERROR;
139        } catch (RemoteException e) {
140            Log.w(TAG, "Cannot connect to keystore", e);
141            return false;
142        }
143    }
144
145    public boolean delete(String key) {
146        return delete(key, UID_SELF);
147    }
148
149    public boolean contains(String key, int uid) {
150        try {
151            return mBinder.exist(key, uid) == NO_ERROR;
152        } catch (RemoteException e) {
153            Log.w(TAG, "Cannot connect to keystore", e);
154            return false;
155        }
156    }
157
158    public boolean contains(String key) {
159        return contains(key, UID_SELF);
160    }
161
162    public String[] saw(String prefix, int uid) {
163        try {
164            return mBinder.saw(prefix, uid);
165        } catch (RemoteException e) {
166            Log.w(TAG, "Cannot connect to keystore", e);
167            return null;
168        }
169    }
170
171    public String[] saw(String prefix) {
172        return saw(prefix, UID_SELF);
173    }
174
175    public boolean reset() {
176        try {
177            return mBinder.reset() == NO_ERROR;
178        } catch (RemoteException e) {
179            Log.w(TAG, "Cannot connect to keystore", e);
180            return false;
181        }
182    }
183
184    public boolean password(String password) {
185        try {
186            return mBinder.password(password) == NO_ERROR;
187        } catch (RemoteException e) {
188            Log.w(TAG, "Cannot connect to keystore", e);
189            return false;
190        }
191    }
192
193    public boolean lock() {
194        try {
195            return mBinder.lock() == NO_ERROR;
196        } catch (RemoteException e) {
197            Log.w(TAG, "Cannot connect to keystore", e);
198            return false;
199        }
200    }
201
202    public boolean unlock(String password) {
203        try {
204            mError = mBinder.unlock(password);
205            return mError == NO_ERROR;
206        } catch (RemoteException e) {
207            Log.w(TAG, "Cannot connect to keystore", e);
208            return false;
209        }
210    }
211
212    public boolean isEmpty() {
213        try {
214            return mBinder.zero() == KEY_NOT_FOUND;
215        } catch (RemoteException e) {
216            Log.w(TAG, "Cannot connect to keystore", e);
217            return false;
218        }
219    }
220
221    public boolean generate(String key, int uid, int keyType, int keySize, int flags,
222            byte[][] args) {
223        try {
224            return mBinder.generate(key, uid, keyType, keySize, flags,
225                    new KeystoreArguments(args)) == NO_ERROR;
226        } catch (RemoteException e) {
227            Log.w(TAG, "Cannot connect to keystore", e);
228            return false;
229        }
230    }
231
232    public boolean importKey(String keyName, byte[] key, int uid, int flags) {
233        try {
234            return mBinder.import_key(keyName, key, uid, flags) == NO_ERROR;
235        } catch (RemoteException e) {
236            Log.w(TAG, "Cannot connect to keystore", e);
237            return false;
238        }
239    }
240
241    public byte[] getPubkey(String key) {
242        try {
243            return mBinder.get_pubkey(key);
244        } catch (RemoteException e) {
245            Log.w(TAG, "Cannot connect to keystore", e);
246            return null;
247        }
248    }
249
250    public boolean delKey(String key, int uid) {
251        try {
252            return mBinder.del_key(key, uid) == NO_ERROR;
253        } catch (RemoteException e) {
254            Log.w(TAG, "Cannot connect to keystore", e);
255            return false;
256        }
257    }
258
259    public boolean delKey(String key) {
260        return delKey(key, UID_SELF);
261    }
262
263    public byte[] sign(String key, byte[] data) {
264        try {
265            return mBinder.sign(key, data);
266        } catch (RemoteException e) {
267            Log.w(TAG, "Cannot connect to keystore", e);
268            return null;
269        }
270    }
271
272    public boolean verify(String key, byte[] data, byte[] signature) {
273        try {
274            return mBinder.verify(key, data, signature) == NO_ERROR;
275        } catch (RemoteException e) {
276            Log.w(TAG, "Cannot connect to keystore", e);
277            return false;
278        }
279    }
280
281    public boolean grant(String key, int uid) {
282        try {
283            return mBinder.grant(key, uid) == NO_ERROR;
284        } catch (RemoteException e) {
285            Log.w(TAG, "Cannot connect to keystore", e);
286            return false;
287        }
288    }
289
290    public boolean ungrant(String key, int uid) {
291        try {
292            return mBinder.ungrant(key, uid) == NO_ERROR;
293        } catch (RemoteException e) {
294            Log.w(TAG, "Cannot connect to keystore", e);
295            return false;
296        }
297    }
298
299    /**
300     * Returns the last modification time of the key in milliseconds since the
301     * epoch. Will return -1L if the key could not be found or other error.
302     */
303    public long getmtime(String key) {
304        try {
305            final long millis = mBinder.getmtime(key);
306            if (millis == -1L) {
307                return -1L;
308            }
309
310            return millis * 1000L;
311        } catch (RemoteException e) {
312            Log.w(TAG, "Cannot connect to keystore", e);
313            return -1L;
314        }
315    }
316
317    public boolean duplicate(String srcKey, int srcUid, String destKey, int destUid) {
318        try {
319            return mBinder.duplicate(srcKey, srcUid, destKey, destUid) == NO_ERROR;
320        } catch (RemoteException e) {
321            Log.w(TAG, "Cannot connect to keystore", e);
322            return false;
323        }
324    }
325
326    // TODO remove this when it's removed from Settings
327    public boolean isHardwareBacked() {
328        return isHardwareBacked("RSA");
329    }
330
331    public boolean isHardwareBacked(String keyType) {
332        try {
333            return mBinder.is_hardware_backed(keyType.toUpperCase(Locale.US)) == NO_ERROR;
334        } catch (RemoteException e) {
335            Log.w(TAG, "Cannot connect to keystore", e);
336            return false;
337        }
338    }
339
340    public boolean clearUid(int uid) {
341        try {
342            return mBinder.clear_uid(uid) == NO_ERROR;
343        } catch (RemoteException e) {
344            Log.w(TAG, "Cannot connect to keystore", e);
345            return false;
346        }
347    }
348
349    public boolean resetUid(int uid) {
350        try {
351            mError = mBinder.reset_uid(uid);
352            return mError == NO_ERROR;
353        } catch (RemoteException e) {
354            Log.w(TAG, "Cannot connect to keystore", e);
355            return false;
356        }
357    }
358
359    public boolean syncUid(int sourceUid, int targetUid) {
360        try {
361            mError = mBinder.sync_uid(sourceUid, targetUid);
362            return mError == NO_ERROR;
363        } catch (RemoteException e) {
364            Log.w(TAG, "Cannot connect to keystore", e);
365            return false;
366        }
367    }
368
369    public boolean passwordUid(String password, int uid) {
370        try {
371            mError = mBinder.password_uid(password, uid);
372            return mError == NO_ERROR;
373        } catch (RemoteException e) {
374            Log.w(TAG, "Cannot connect to keystore", e);
375            return false;
376        }
377    }
378
379    public int getLastError() {
380        return mError;
381    }
382
383    public boolean addRngEntropy(byte[] data) {
384        try {
385            return mBinder.addRngEntropy(data) == NO_ERROR;
386        } catch (RemoteException e) {
387            Log.w(TAG, "Cannot connect to keystore", e);
388            return false;
389        }
390    }
391
392    public int generateKey(String alias, KeymasterArguments args, byte[] entropy, int uid,
393            int flags, KeyCharacteristics outCharacteristics) {
394        try {
395            return mBinder.generateKey(alias, args, entropy, uid, flags, outCharacteristics);
396        } catch (RemoteException e) {
397            Log.w(TAG, "Cannot connect to keystore", e);
398            return SYSTEM_ERROR;
399        }
400    }
401
402    public int generateKey(String alias, KeymasterArguments args, byte[] entropy, int flags,
403            KeyCharacteristics outCharacteristics) {
404        return generateKey(alias, args, entropy, UID_SELF, flags, outCharacteristics);
405    }
406
407    public int getKeyCharacteristics(String alias, KeymasterBlob clientId, KeymasterBlob appId,
408            KeyCharacteristics outCharacteristics) {
409        try {
410            return mBinder.getKeyCharacteristics(alias, clientId, appId, outCharacteristics);
411        } catch (RemoteException e) {
412            Log.w(TAG, "Cannot connect to keystore", e);
413            return SYSTEM_ERROR;
414        }
415    }
416
417    public int importKey(String alias, KeymasterArguments args, int format, byte[] keyData,
418            int uid, int flags, KeyCharacteristics outCharacteristics) {
419        try {
420            return mBinder.importKey(alias, args, format, keyData, uid, flags,
421                    outCharacteristics);
422        } catch (RemoteException e) {
423            Log.w(TAG, "Cannot connect to keystore", e);
424            return SYSTEM_ERROR;
425        }
426    }
427
428    public int importKey(String alias, KeymasterArguments args, int format, byte[] keyData,
429            int flags, KeyCharacteristics outCharacteristics) {
430        return importKey(alias, args, format, keyData, UID_SELF, flags, outCharacteristics);
431    }
432
433    public ExportResult exportKey(String alias, int format, KeymasterBlob clientId,
434            KeymasterBlob appId) {
435        try {
436            return mBinder.exportKey(alias, format, clientId, appId);
437        } catch (RemoteException e) {
438            Log.w(TAG, "Cannot connect to keystore", e);
439            return null;
440        }
441    }
442
443    public OperationResult begin(String alias, int purpose, boolean pruneable,
444            KeymasterArguments args, byte[] entropy, KeymasterArguments outArgs) {
445        try {
446            return mBinder.begin(getToken(), alias, purpose, pruneable, args, entropy, outArgs);
447        } catch (RemoteException e) {
448            Log.w(TAG, "Cannot connect to keystore", e);
449            return null;
450        }
451    }
452
453    public OperationResult update(IBinder token, KeymasterArguments arguments, byte[] input) {
454        try {
455            return mBinder.update(token, arguments, input);
456        } catch (RemoteException e) {
457            Log.w(TAG, "Cannot connect to keystore", e);
458            return null;
459        }
460    }
461
462    public OperationResult finish(IBinder token, KeymasterArguments arguments, byte[] signature) {
463        try {
464            return mBinder.finish(token, arguments, signature);
465        } catch (RemoteException e) {
466            Log.w(TAG, "Cannot connect to keystore", e);
467            return null;
468        }
469    }
470
471    public int abort(IBinder token) {
472        try {
473            return mBinder.abort(token);
474        } catch (RemoteException e) {
475            Log.w(TAG, "Cannot connect to keystore", e);
476            return SYSTEM_ERROR;
477        }
478    }
479}
480