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 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) 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 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 100 public boolean isUnlocked() { 101 return state() == State.UNLOCKED; 102 } 103 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 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 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 131 public boolean delete(String key) { 132 return delete(key, UID_SELF); 133 } 134 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 144 public boolean contains(String key) { 145 return contains(key, UID_SELF); 146 } 147 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 157 public String[] saw(String prefix) { 158 return saw(prefix, UID_SELF); 159 } 160 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 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 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 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 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 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 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 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 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 244 public boolean delKey(String key) { 245 return delKey(key, UID_SELF); 246 } 247 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 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 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 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 */ 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 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 312 public boolean isHardwareBacked() { 313 return isHardwareBacked("RSA"); 314 } 315 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 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 334 public int getLastError() { 335 return mError; 336 } 337 } 338