KeyStore.java revision 21a76df55cf4b956f4d34f57c7b9e694d0363f54
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.RemoteException;
22import android.os.ServiceManager;
23import android.util.Log;
24
25import java.util.Locale;
26
27/**
28 * @hide This should not be made public in its present form because it
29 * assumes that private and secret key bytes are available and would
30 * preclude the use of hardware crypto.
31 */
32public class KeyStore {
33    private static final String TAG = "KeyStore";
34
35    // ResponseCodes
36    public static final int NO_ERROR = 1;
37    public static final int LOCKED = 2;
38    public static final int UNINITIALIZED = 3;
39    public static final int SYSTEM_ERROR = 4;
40    public static final int PROTOCOL_ERROR = 5;
41    public static final int PERMISSION_DENIED = 6;
42    public static final int KEY_NOT_FOUND = 7;
43    public static final int VALUE_CORRUPTED = 8;
44    public static final int UNDEFINED_ACTION = 9;
45    public static final int WRONG_PASSWORD = 10;
46
47    // Used for UID field to indicate the calling UID.
48    public static final int UID_SELF = -1;
49
50    // Flags for "put" "import" and "generate"
51    public static final int FLAG_NONE = 0;
52    public static final int FLAG_ENCRYPTED = 1;
53
54    // States
55    public enum State { UNLOCKED, LOCKED, UNINITIALIZED };
56
57    private int mError = NO_ERROR;
58
59    private final IKeystoreService mBinder;
60
61    private KeyStore(IKeystoreService binder) {
62        mBinder = binder;
63    }
64
65    public static KeyStore getInstance() {
66        IKeystoreService keystore = IKeystoreService.Stub.asInterface(ServiceManager
67                .getService("android.security.keystore"));
68        return new KeyStore(keystore);
69    }
70
71    static int getKeyTypeForAlgorithm(String keyType) {
72        if ("RSA".equalsIgnoreCase(keyType)) {
73            return NativeCrypto.EVP_PKEY_RSA;
74        } else if ("EC".equalsIgnoreCase(keyType)) {
75            return NativeCrypto.EVP_PKEY_EC;
76        } else {
77            return -1;
78        }
79    }
80
81    public State state() {
82        final int ret;
83        try {
84            ret = mBinder.test();
85        } catch (RemoteException e) {
86            Log.w(TAG, "Cannot connect to keystore", e);
87            throw new AssertionError(e);
88        }
89
90        switch (ret) {
91            case NO_ERROR: return State.UNLOCKED;
92            case LOCKED: return State.LOCKED;
93            case UNINITIALIZED: return State.UNINITIALIZED;
94            default: throw new AssertionError(mError);
95        }
96    }
97
98    public boolean isUnlocked() {
99        return state() == State.UNLOCKED;
100    }
101
102    public byte[] get(String key) {
103        try {
104            return mBinder.get(key);
105        } catch (RemoteException e) {
106            Log.w(TAG, "Cannot connect to keystore", e);
107            return null;
108        }
109    }
110
111    public boolean put(String key, byte[] value, int uid, int flags) {
112        try {
113            return mBinder.insert(key, value, uid, flags) == NO_ERROR;
114        } catch (RemoteException e) {
115            Log.w(TAG, "Cannot connect to keystore", e);
116            return false;
117        }
118    }
119
120    public boolean delete(String key, int uid) {
121        try {
122            return mBinder.del(key, uid) == NO_ERROR;
123        } catch (RemoteException e) {
124            Log.w(TAG, "Cannot connect to keystore", e);
125            return false;
126        }
127    }
128
129    public boolean delete(String key) {
130        return delete(key, UID_SELF);
131    }
132
133    public boolean contains(String key, int uid) {
134        try {
135            return mBinder.exist(key, uid) == NO_ERROR;
136        } catch (RemoteException e) {
137            Log.w(TAG, "Cannot connect to keystore", e);
138            return false;
139        }
140    }
141
142    public boolean contains(String key) {
143        return contains(key, UID_SELF);
144    }
145
146    public String[] saw(String prefix, int uid) {
147        try {
148            return mBinder.saw(prefix, uid);
149        } catch (RemoteException e) {
150            Log.w(TAG, "Cannot connect to keystore", e);
151            return null;
152        }
153    }
154
155    public String[] saw(String prefix) {
156        return saw(prefix, UID_SELF);
157    }
158
159    public boolean reset() {
160        try {
161            return mBinder.reset() == NO_ERROR;
162        } catch (RemoteException e) {
163            Log.w(TAG, "Cannot connect to keystore", e);
164            return false;
165        }
166    }
167
168    public boolean password(String password) {
169        try {
170            return mBinder.password(password) == NO_ERROR;
171        } catch (RemoteException e) {
172            Log.w(TAG, "Cannot connect to keystore", e);
173            return false;
174        }
175    }
176
177    public boolean lock() {
178        try {
179            return mBinder.lock() == NO_ERROR;
180        } catch (RemoteException e) {
181            Log.w(TAG, "Cannot connect to keystore", e);
182            return false;
183        }
184    }
185
186    public boolean unlock(String password) {
187        try {
188            mError = mBinder.unlock(password);
189            return mError == NO_ERROR;
190        } catch (RemoteException e) {
191            Log.w(TAG, "Cannot connect to keystore", e);
192            return false;
193        }
194    }
195
196    public boolean isEmpty() {
197        try {
198            return mBinder.zero() == KEY_NOT_FOUND;
199        } catch (RemoteException e) {
200            Log.w(TAG, "Cannot connect to keystore", e);
201            return false;
202        }
203    }
204
205    public boolean generate(String key, int uid, int keyType, int keySize, int flags,
206            byte[][] args) {
207        try {
208            return mBinder.generate(key, uid, keyType, keySize, flags, args) == NO_ERROR;
209        } catch (RemoteException e) {
210            Log.w(TAG, "Cannot connect to keystore", e);
211            return false;
212        }
213    }
214
215    public boolean importKey(String keyName, byte[] key, int uid, int flags) {
216        try {
217            return mBinder.import_key(keyName, key, uid, flags) == NO_ERROR;
218        } catch (RemoteException e) {
219            Log.w(TAG, "Cannot connect to keystore", e);
220            return false;
221        }
222    }
223
224    public byte[] getPubkey(String key) {
225        try {
226            return mBinder.get_pubkey(key);
227        } catch (RemoteException e) {
228            Log.w(TAG, "Cannot connect to keystore", e);
229            return null;
230        }
231    }
232
233    public boolean delKey(String key, int uid) {
234        try {
235            return mBinder.del_key(key, uid) == NO_ERROR;
236        } catch (RemoteException e) {
237            Log.w(TAG, "Cannot connect to keystore", e);
238            return false;
239        }
240    }
241
242    public boolean delKey(String key) {
243        return delKey(key, UID_SELF);
244    }
245
246    public byte[] sign(String key, byte[] data) {
247        try {
248            return mBinder.sign(key, data);
249        } catch (RemoteException e) {
250            Log.w(TAG, "Cannot connect to keystore", e);
251            return null;
252        }
253    }
254
255    public boolean verify(String key, byte[] data, byte[] signature) {
256        try {
257            return mBinder.verify(key, data, signature) == NO_ERROR;
258        } catch (RemoteException e) {
259            Log.w(TAG, "Cannot connect to keystore", e);
260            return false;
261        }
262    }
263
264    public boolean grant(String key, int uid) {
265        try {
266            return mBinder.grant(key, uid) == NO_ERROR;
267        } catch (RemoteException e) {
268            Log.w(TAG, "Cannot connect to keystore", e);
269            return false;
270        }
271    }
272
273    public boolean ungrant(String key, int uid) {
274        try {
275            return mBinder.ungrant(key, uid) == NO_ERROR;
276        } catch (RemoteException e) {
277            Log.w(TAG, "Cannot connect to keystore", e);
278            return false;
279        }
280    }
281
282    /**
283     * Returns the last modification time of the key in milliseconds since the
284     * epoch. Will return -1L if the key could not be found or other error.
285     */
286    public long getmtime(String key) {
287        try {
288            final long millis = mBinder.getmtime(key);
289            if (millis == -1L) {
290                return -1L;
291            }
292
293            return millis * 1000L;
294        } catch (RemoteException e) {
295            Log.w(TAG, "Cannot connect to keystore", e);
296            return -1L;
297        }
298    }
299
300    public boolean duplicate(String srcKey, int srcUid, String destKey, int destUid) {
301        try {
302            return mBinder.duplicate(srcKey, srcUid, destKey, destUid) == NO_ERROR;
303        } catch (RemoteException e) {
304            Log.w(TAG, "Cannot connect to keystore", e);
305            return false;
306        }
307    }
308
309    // TODO remove this when it's removed from Settings
310    public boolean isHardwareBacked() {
311        return isHardwareBacked("RSA");
312    }
313
314    public boolean isHardwareBacked(String keyType) {
315        try {
316            return mBinder.is_hardware_backed(keyType.toUpperCase(Locale.US)) == NO_ERROR;
317        } catch (RemoteException e) {
318            Log.w(TAG, "Cannot connect to keystore", e);
319            return false;
320        }
321    }
322
323    public boolean clearUid(int uid) {
324        try {
325            return mBinder.clear_uid(uid) == NO_ERROR;
326        } catch (RemoteException e) {
327            Log.w(TAG, "Cannot connect to keystore", e);
328            return false;
329        }
330    }
331
332    public boolean resetUid(int uid) {
333        try {
334            mError = mBinder.reset_uid(uid);
335            return mError == NO_ERROR;
336        } catch (RemoteException e) {
337            Log.w(TAG, "Cannot connect to keystore", e);
338            return false;
339        }
340    }
341
342    public boolean syncUid(int sourceUid, int targetUid) {
343        try {
344            mError = mBinder.sync_uid(sourceUid, targetUid);
345            return mError == NO_ERROR;
346        } catch (RemoteException e) {
347            Log.w(TAG, "Cannot connect to keystore", e);
348            return false;
349        }
350    }
351
352    public boolean passwordUid(String password, int uid) {
353        try {
354            mError = mBinder.password_uid(password, uid);
355            return mError == NO_ERROR;
356        } catch (RemoteException e) {
357            Log.w(TAG, "Cannot connect to keystore", e);
358            return false;
359        }
360    }
361
362    public int getLastError() {
363        return mError;
364    }
365}
366