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