KeyStore.java revision 40485f5aac5bc02fb3b24ad03ac71f724e4c340a
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.KeymasterDefs; 30import android.security.keymaster.OperationResult; 31import android.util.Log; 32 33import java.security.InvalidKeyException; 34import java.util.Locale; 35 36/** 37 * @hide This should not be made public in its present form because it 38 * assumes that private and secret key bytes are available and would 39 * preclude the use of hardware crypto. 40 */ 41public class KeyStore { 42 private static final String TAG = "KeyStore"; 43 44 // ResponseCodes 45 public static final int NO_ERROR = 1; 46 public static final int LOCKED = 2; 47 public static final int UNINITIALIZED = 3; 48 public static final int SYSTEM_ERROR = 4; 49 public static final int PROTOCOL_ERROR = 5; 50 public static final int PERMISSION_DENIED = 6; 51 public static final int KEY_NOT_FOUND = 7; 52 public static final int VALUE_CORRUPTED = 8; 53 public static final int UNDEFINED_ACTION = 9; 54 public static final int WRONG_PASSWORD = 10; 55 56 // Used for UID field to indicate the calling UID. 57 public static final int UID_SELF = -1; 58 59 // Flags for "put" "import" and "generate" 60 public static final int FLAG_NONE = 0; 61 public static final int FLAG_ENCRYPTED = 1; 62 63 // States 64 public enum State { UNLOCKED, LOCKED, UNINITIALIZED }; 65 66 private int mError = NO_ERROR; 67 68 private final IKeystoreService mBinder; 69 70 private IBinder mToken; 71 72 private KeyStore(IKeystoreService binder) { 73 mBinder = binder; 74 } 75 76 public static KeyStore getInstance() { 77 IKeystoreService keystore = IKeystoreService.Stub.asInterface(ServiceManager 78 .getService("android.security.keystore")); 79 return new KeyStore(keystore); 80 } 81 82 private synchronized IBinder getToken() { 83 if (mToken == null) { 84 mToken = new Binder(); 85 } 86 return mToken; 87 } 88 89 static int getKeyTypeForAlgorithm(String keyType) { 90 if ("RSA".equalsIgnoreCase(keyType)) { 91 return NativeCrypto.EVP_PKEY_RSA; 92 } else if ("EC".equalsIgnoreCase(keyType)) { 93 return NativeCrypto.EVP_PKEY_EC; 94 } else { 95 return -1; 96 } 97 } 98 99 public State state() { 100 final int ret; 101 try { 102 ret = mBinder.test(); 103 } catch (RemoteException e) { 104 Log.w(TAG, "Cannot connect to keystore", e); 105 throw new AssertionError(e); 106 } 107 108 switch (ret) { 109 case NO_ERROR: return State.UNLOCKED; 110 case LOCKED: return State.LOCKED; 111 case UNINITIALIZED: return State.UNINITIALIZED; 112 default: throw new AssertionError(mError); 113 } 114 } 115 116 public boolean isUnlocked() { 117 return state() == State.UNLOCKED; 118 } 119 120 public byte[] get(String key) { 121 try { 122 return mBinder.get(key); 123 } catch (RemoteException e) { 124 Log.w(TAG, "Cannot connect to keystore", e); 125 return null; 126 } 127 } 128 129 public boolean put(String key, byte[] value, int uid, int flags) { 130 try { 131 return mBinder.insert(key, value, uid, flags) == NO_ERROR; 132 } catch (RemoteException e) { 133 Log.w(TAG, "Cannot connect to keystore", e); 134 return false; 135 } 136 } 137 138 public boolean delete(String key, int uid) { 139 try { 140 return mBinder.del(key, uid) == NO_ERROR; 141 } catch (RemoteException e) { 142 Log.w(TAG, "Cannot connect to keystore", e); 143 return false; 144 } 145 } 146 147 public boolean delete(String key) { 148 return delete(key, UID_SELF); 149 } 150 151 public boolean contains(String key, int uid) { 152 try { 153 return mBinder.exist(key, uid) == NO_ERROR; 154 } catch (RemoteException e) { 155 Log.w(TAG, "Cannot connect to keystore", e); 156 return false; 157 } 158 } 159 160 public boolean contains(String key) { 161 return contains(key, UID_SELF); 162 } 163 164 public String[] saw(String prefix, int uid) { 165 try { 166 return mBinder.saw(prefix, uid); 167 } catch (RemoteException e) { 168 Log.w(TAG, "Cannot connect to keystore", e); 169 return null; 170 } 171 } 172 173 public String[] saw(String prefix) { 174 return saw(prefix, UID_SELF); 175 } 176 177 public boolean reset() { 178 try { 179 return mBinder.reset() == NO_ERROR; 180 } catch (RemoteException e) { 181 Log.w(TAG, "Cannot connect to keystore", e); 182 return false; 183 } 184 } 185 186 public boolean password(String password) { 187 try { 188 return mBinder.password(password) == NO_ERROR; 189 } catch (RemoteException e) { 190 Log.w(TAG, "Cannot connect to keystore", e); 191 return false; 192 } 193 } 194 195 public boolean lock() { 196 try { 197 return mBinder.lock() == NO_ERROR; 198 } catch (RemoteException e) { 199 Log.w(TAG, "Cannot connect to keystore", e); 200 return false; 201 } 202 } 203 204 public boolean unlock(String password) { 205 try { 206 mError = mBinder.unlock(password); 207 return mError == NO_ERROR; 208 } catch (RemoteException e) { 209 Log.w(TAG, "Cannot connect to keystore", e); 210 return false; 211 } 212 } 213 214 public boolean isEmpty() { 215 try { 216 return mBinder.zero() == KEY_NOT_FOUND; 217 } catch (RemoteException e) { 218 Log.w(TAG, "Cannot connect to keystore", e); 219 return false; 220 } 221 } 222 223 public boolean generate(String key, int uid, int keyType, int keySize, int flags, 224 byte[][] args) { 225 try { 226 return mBinder.generate(key, uid, keyType, keySize, flags, 227 new KeystoreArguments(args)) == NO_ERROR; 228 } catch (RemoteException e) { 229 Log.w(TAG, "Cannot connect to keystore", e); 230 return false; 231 } 232 } 233 234 public boolean importKey(String keyName, byte[] key, int uid, int flags) { 235 try { 236 return mBinder.import_key(keyName, key, uid, flags) == NO_ERROR; 237 } catch (RemoteException e) { 238 Log.w(TAG, "Cannot connect to keystore", e); 239 return false; 240 } 241 } 242 243 public byte[] getPubkey(String key) { 244 try { 245 return mBinder.get_pubkey(key); 246 } catch (RemoteException e) { 247 Log.w(TAG, "Cannot connect to keystore", e); 248 return null; 249 } 250 } 251 252 public boolean delKey(String key, int uid) { 253 try { 254 return mBinder.del_key(key, uid) == NO_ERROR; 255 } catch (RemoteException e) { 256 Log.w(TAG, "Cannot connect to keystore", e); 257 return false; 258 } 259 } 260 261 public boolean delKey(String key) { 262 return delKey(key, UID_SELF); 263 } 264 265 public byte[] sign(String key, byte[] data) { 266 try { 267 return mBinder.sign(key, data); 268 } catch (RemoteException e) { 269 Log.w(TAG, "Cannot connect to keystore", e); 270 return null; 271 } 272 } 273 274 public boolean verify(String key, byte[] data, byte[] signature) { 275 try { 276 return mBinder.verify(key, data, signature) == NO_ERROR; 277 } catch (RemoteException e) { 278 Log.w(TAG, "Cannot connect to keystore", e); 279 return false; 280 } 281 } 282 283 public boolean grant(String key, int uid) { 284 try { 285 return mBinder.grant(key, uid) == NO_ERROR; 286 } catch (RemoteException e) { 287 Log.w(TAG, "Cannot connect to keystore", e); 288 return false; 289 } 290 } 291 292 public boolean ungrant(String key, int uid) { 293 try { 294 return mBinder.ungrant(key, uid) == NO_ERROR; 295 } catch (RemoteException e) { 296 Log.w(TAG, "Cannot connect to keystore", e); 297 return false; 298 } 299 } 300 301 /** 302 * Returns the last modification time of the key in milliseconds since the 303 * epoch. Will return -1L if the key could not be found or other error. 304 */ 305 public long getmtime(String key) { 306 try { 307 final long millis = mBinder.getmtime(key); 308 if (millis == -1L) { 309 return -1L; 310 } 311 312 return millis * 1000L; 313 } catch (RemoteException e) { 314 Log.w(TAG, "Cannot connect to keystore", e); 315 return -1L; 316 } 317 } 318 319 public boolean duplicate(String srcKey, int srcUid, String destKey, int destUid) { 320 try { 321 return mBinder.duplicate(srcKey, srcUid, destKey, destUid) == NO_ERROR; 322 } catch (RemoteException e) { 323 Log.w(TAG, "Cannot connect to keystore", e); 324 return false; 325 } 326 } 327 328 // TODO remove this when it's removed from Settings 329 public boolean isHardwareBacked() { 330 return isHardwareBacked("RSA"); 331 } 332 333 public boolean isHardwareBacked(String keyType) { 334 try { 335 return mBinder.is_hardware_backed(keyType.toUpperCase(Locale.US)) == NO_ERROR; 336 } catch (RemoteException e) { 337 Log.w(TAG, "Cannot connect to keystore", e); 338 return false; 339 } 340 } 341 342 public boolean clearUid(int uid) { 343 try { 344 return mBinder.clear_uid(uid) == NO_ERROR; 345 } catch (RemoteException e) { 346 Log.w(TAG, "Cannot connect to keystore", e); 347 return false; 348 } 349 } 350 351 public boolean resetUid(int uid) { 352 try { 353 mError = mBinder.reset_uid(uid); 354 return mError == NO_ERROR; 355 } catch (RemoteException e) { 356 Log.w(TAG, "Cannot connect to keystore", e); 357 return false; 358 } 359 } 360 361 public boolean syncUid(int sourceUid, int targetUid) { 362 try { 363 mError = mBinder.sync_uid(sourceUid, targetUid); 364 return mError == NO_ERROR; 365 } catch (RemoteException e) { 366 Log.w(TAG, "Cannot connect to keystore", e); 367 return false; 368 } 369 } 370 371 public boolean passwordUid(String password, int uid) { 372 try { 373 mError = mBinder.password_uid(password, uid); 374 return mError == NO_ERROR; 375 } catch (RemoteException e) { 376 Log.w(TAG, "Cannot connect to keystore", e); 377 return false; 378 } 379 } 380 381 public int getLastError() { 382 return mError; 383 } 384 385 public boolean addRngEntropy(byte[] data) { 386 try { 387 return mBinder.addRngEntropy(data) == NO_ERROR; 388 } catch (RemoteException e) { 389 Log.w(TAG, "Cannot connect to keystore", e); 390 return false; 391 } 392 } 393 394 public int generateKey(String alias, KeymasterArguments args, byte[] entropy, int uid, 395 int flags, KeyCharacteristics outCharacteristics) { 396 try { 397 return mBinder.generateKey(alias, args, entropy, uid, flags, outCharacteristics); 398 } catch (RemoteException e) { 399 Log.w(TAG, "Cannot connect to keystore", e); 400 return SYSTEM_ERROR; 401 } 402 } 403 404 public int generateKey(String alias, KeymasterArguments args, byte[] entropy, int flags, 405 KeyCharacteristics outCharacteristics) { 406 return generateKey(alias, args, entropy, UID_SELF, flags, outCharacteristics); 407 } 408 409 public int getKeyCharacteristics(String alias, KeymasterBlob clientId, KeymasterBlob appId, 410 KeyCharacteristics outCharacteristics) { 411 try { 412 return mBinder.getKeyCharacteristics(alias, clientId, appId, outCharacteristics); 413 } catch (RemoteException e) { 414 Log.w(TAG, "Cannot connect to keystore", e); 415 return SYSTEM_ERROR; 416 } 417 } 418 419 public int importKey(String alias, KeymasterArguments args, int format, byte[] keyData, 420 int uid, int flags, KeyCharacteristics outCharacteristics) { 421 try { 422 return mBinder.importKey(alias, args, format, keyData, uid, flags, 423 outCharacteristics); 424 } catch (RemoteException e) { 425 Log.w(TAG, "Cannot connect to keystore", e); 426 return SYSTEM_ERROR; 427 } 428 } 429 430 public int importKey(String alias, KeymasterArguments args, int format, byte[] keyData, 431 int flags, KeyCharacteristics outCharacteristics) { 432 return importKey(alias, args, format, keyData, UID_SELF, flags, outCharacteristics); 433 } 434 435 public ExportResult exportKey(String alias, int format, KeymasterBlob clientId, 436 KeymasterBlob appId) { 437 try { 438 return mBinder.exportKey(alias, format, clientId, appId); 439 } catch (RemoteException e) { 440 Log.w(TAG, "Cannot connect to keystore", e); 441 return null; 442 } 443 } 444 445 public OperationResult begin(String alias, int purpose, boolean pruneable, 446 KeymasterArguments args, byte[] entropy, KeymasterArguments outArgs) { 447 try { 448 return mBinder.begin(getToken(), alias, purpose, pruneable, args, entropy, outArgs); 449 } catch (RemoteException e) { 450 Log.w(TAG, "Cannot connect to keystore", e); 451 return null; 452 } 453 } 454 455 public OperationResult update(IBinder token, KeymasterArguments arguments, byte[] input) { 456 try { 457 return mBinder.update(token, arguments, input); 458 } catch (RemoteException e) { 459 Log.w(TAG, "Cannot connect to keystore", e); 460 return null; 461 } 462 } 463 464 public OperationResult finish(IBinder token, KeymasterArguments arguments, byte[] signature) { 465 try { 466 return mBinder.finish(token, arguments, signature); 467 } catch (RemoteException e) { 468 Log.w(TAG, "Cannot connect to keystore", e); 469 return null; 470 } 471 } 472 473 public int abort(IBinder token) { 474 try { 475 return mBinder.abort(token); 476 } catch (RemoteException e) { 477 Log.w(TAG, "Cannot connect to keystore", e); 478 return SYSTEM_ERROR; 479 } 480 } 481 482 /** 483 * Check if the operation referenced by {@code token} is currently authorized. 484 * 485 * @param token An operation token returned by a call to {@link KeyStore.begin}. 486 */ 487 public boolean isOperationAuthorized(IBinder token) { 488 try { 489 return mBinder.isOperationAuthorized(token); 490 } catch (RemoteException e) { 491 Log.w(TAG, "Cannot connect to keystore", e); 492 return false; 493 } 494 } 495 496 /** 497 * Add an authentication record to the keystore authorization table. 498 * 499 * @param authToken The packed bytes of a hw_auth_token_t to be provided to keymaster. 500 * @return {@code KeyStore.NO_ERROR} on success, otherwise an error value corresponding to 501 * a {@code KeymasterDefs.KM_ERROR_} value or {@code KeyStore} ResponseCode. 502 */ 503 public int addAuthToken(byte[] authToken) { 504 try { 505 return mBinder.addAuthToken(authToken); 506 } catch (RemoteException e) { 507 Log.w(TAG, "Cannot connect to keystore", e); 508 return SYSTEM_ERROR; 509 } 510 } 511 512 /** 513 * Returns a {@link KeyStoreException} corresponding to the provided keystore/keymaster error 514 * code. 515 */ 516 static KeyStoreException getKeyStoreException(int errorCode) { 517 if (errorCode > 0) { 518 // KeyStore layer error 519 switch (errorCode) { 520 case NO_ERROR: 521 return new KeyStoreException(errorCode, "OK"); 522 case LOCKED: 523 return new KeyStoreException(errorCode, "Keystore locked"); 524 case UNINITIALIZED: 525 return new KeyStoreException(errorCode, "Keystore not initialized"); 526 case SYSTEM_ERROR: 527 return new KeyStoreException(errorCode, "System error"); 528 case PERMISSION_DENIED: 529 return new KeyStoreException(errorCode, "Permission denied"); 530 case KEY_NOT_FOUND: 531 return new KeyStoreException(errorCode, "Key not found"); 532 case VALUE_CORRUPTED: 533 return new KeyStoreException(errorCode, "Key blob corrupted"); 534 default: 535 return new KeyStoreException(errorCode, String.valueOf(errorCode)); 536 } 537 } else { 538 // Keymaster layer error 539 switch (errorCode) { 540 case KeymasterDefs.KM_ERROR_INVALID_AUTHORIZATION_TIMEOUT: 541 // The name of this parameter significantly differs between Keymaster and 542 // framework APIs. Use the framework wording to make life easier for developers. 543 return new KeyStoreException(errorCode, 544 "Invalid user authentication validity duration"); 545 default: 546 return new KeyStoreException(errorCode, 547 KeymasterDefs.getErrorMessage(errorCode)); 548 } 549 } 550 } 551 552 /** 553 * Returns an {@link InvalidKeyException} corresponding to the provided 554 * {@link KeyStoreException}. 555 */ 556 static InvalidKeyException getInvalidKeyException(KeyStoreException e) { 557 switch (e.getErrorCode()) { 558 case KeymasterDefs.KM_ERROR_KEY_EXPIRED: 559 return new KeyExpiredException(); 560 case KeymasterDefs.KM_ERROR_KEY_NOT_YET_VALID: 561 return new KeyNotYetValidException(); 562 case KeymasterDefs.KM_ERROR_KEY_USER_NOT_AUTHENTICATED: 563 return new UserNotAuthenticatedException(); 564 // TODO: Handle TBD Keymaster error code "invalid key: new fingerprint enrolled" 565 // case KeymasterDefs.KM_ERROR_TBD 566 // return new NewFingerprintEnrolledException(); 567 default: 568 return new InvalidKeyException("Keystore operation failed", e); 569 } 570 } 571 572 /** 573 * Returns an {@link InvalidKeyException} corresponding to the provided keystore/keymaster error 574 * code. 575 */ 576 static InvalidKeyException getInvalidKeyException(int errorCode) { 577 return getInvalidKeyException(getKeyStoreException(errorCode)); 578 } 579} 580