KeyStore.java revision 590c068e8380ba73a6571ddf797d4ce02b390bcb
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,
209                    new KeystoreArguments(args)) == NO_ERROR;
210        } catch (RemoteException e) {
211            Log.w(TAG, "Cannot connect to keystore", e);
212            return false;
213        }
214    }
215
216    public boolean importKey(String keyName, byte[] key, int uid, int flags) {
217        try {
218            return mBinder.import_key(keyName, key, uid, flags) == NO_ERROR;
219        } catch (RemoteException e) {
220            Log.w(TAG, "Cannot connect to keystore", e);
221            return false;
222        }
223    }
224
225    public byte[] getPubkey(String key) {
226        try {
227            return mBinder.get_pubkey(key);
228        } catch (RemoteException e) {
229            Log.w(TAG, "Cannot connect to keystore", e);
230            return null;
231        }
232    }
233
234    public boolean delKey(String key, int uid) {
235        try {
236            return mBinder.del_key(key, uid) == NO_ERROR;
237        } catch (RemoteException e) {
238            Log.w(TAG, "Cannot connect to keystore", e);
239            return false;
240        }
241    }
242
243    public boolean delKey(String key) {
244        return delKey(key, UID_SELF);
245    }
246
247    public byte[] sign(String key, byte[] data) {
248        try {
249            return mBinder.sign(key, data);
250        } catch (RemoteException e) {
251            Log.w(TAG, "Cannot connect to keystore", e);
252            return null;
253        }
254    }
255
256    public boolean verify(String key, byte[] data, byte[] signature) {
257        try {
258            return mBinder.verify(key, data, signature) == NO_ERROR;
259        } catch (RemoteException e) {
260            Log.w(TAG, "Cannot connect to keystore", e);
261            return false;
262        }
263    }
264
265    public boolean grant(String key, int uid) {
266        try {
267            return mBinder.grant(key, uid) == NO_ERROR;
268        } catch (RemoteException e) {
269            Log.w(TAG, "Cannot connect to keystore", e);
270            return false;
271        }
272    }
273
274    public boolean ungrant(String key, int uid) {
275        try {
276            return mBinder.ungrant(key, uid) == NO_ERROR;
277        } catch (RemoteException e) {
278            Log.w(TAG, "Cannot connect to keystore", e);
279            return false;
280        }
281    }
282
283    /**
284     * Returns the last modification time of the key in milliseconds since the
285     * epoch. Will return -1L if the key could not be found or other error.
286     */
287    public long getmtime(String key) {
288        try {
289            final long millis = mBinder.getmtime(key);
290            if (millis == -1L) {
291                return -1L;
292            }
293
294            return millis * 1000L;
295        } catch (RemoteException e) {
296            Log.w(TAG, "Cannot connect to keystore", e);
297            return -1L;
298        }
299    }
300
301    public boolean duplicate(String srcKey, int srcUid, String destKey, int destUid) {
302        try {
303            return mBinder.duplicate(srcKey, srcUid, destKey, destUid) == NO_ERROR;
304        } catch (RemoteException e) {
305            Log.w(TAG, "Cannot connect to keystore", e);
306            return false;
307        }
308    }
309
310    // TODO remove this when it's removed from Settings
311    public boolean isHardwareBacked() {
312        return isHardwareBacked("RSA");
313    }
314
315    public boolean isHardwareBacked(String keyType) {
316        try {
317            return mBinder.is_hardware_backed(keyType.toUpperCase(Locale.US)) == NO_ERROR;
318        } catch (RemoteException e) {
319            Log.w(TAG, "Cannot connect to keystore", e);
320            return false;
321        }
322    }
323
324    public boolean clearUid(int uid) {
325        try {
326            return mBinder.clear_uid(uid) == NO_ERROR;
327        } catch (RemoteException e) {
328            Log.w(TAG, "Cannot connect to keystore", e);
329            return false;
330        }
331    }
332
333    public boolean resetUid(int uid) {
334        try {
335            mError = mBinder.reset_uid(uid);
336            return mError == NO_ERROR;
337        } catch (RemoteException e) {
338            Log.w(TAG, "Cannot connect to keystore", e);
339            return false;
340        }
341    }
342
343    public boolean syncUid(int sourceUid, int targetUid) {
344        try {
345            mError = mBinder.sync_uid(sourceUid, targetUid);
346            return mError == NO_ERROR;
347        } catch (RemoteException e) {
348            Log.w(TAG, "Cannot connect to keystore", e);
349            return false;
350        }
351    }
352
353    public boolean passwordUid(String password, int uid) {
354        try {
355            mError = mBinder.password_uid(password, uid);
356            return mError == NO_ERROR;
357        } catch (RemoteException e) {
358            Log.w(TAG, "Cannot connect to keystore", e);
359            return false;
360        }
361    }
362
363    public int getLastError() {
364        return mError;
365    }
366}
367