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 android.app.ActivityThread; 20 import android.app.Application; 21 import android.app.KeyguardManager; 22 import android.content.Context; 23 import android.hardware.fingerprint.FingerprintManager; 24 import android.os.Binder; 25 import android.os.IBinder; 26 import android.os.Process; 27 import android.os.RemoteException; 28 import android.os.ServiceManager; 29 import android.os.UserHandle; 30 import android.security.keymaster.ExportResult; 31 import android.security.keymaster.KeyCharacteristics; 32 import android.security.keymaster.KeymasterArguments; 33 import android.security.keymaster.KeymasterBlob; 34 import android.security.keymaster.KeymasterCertificateChain; 35 import android.security.keymaster.KeymasterDefs; 36 import android.security.keymaster.OperationResult; 37 import android.security.keystore.KeyExpiredException; 38 import android.security.keystore.KeyNotYetValidException; 39 import android.security.keystore.KeyPermanentlyInvalidatedException; 40 import android.security.keystore.UserNotAuthenticatedException; 41 import android.util.Log; 42 43 import java.math.BigInteger; 44 import java.security.InvalidKeyException; 45 import java.util.List; 46 import java.util.Locale; 47 48 /** 49 * @hide This should not be made public in its present form because it 50 * assumes that private and secret key bytes are available and would 51 * preclude the use of hardware crypto. 52 */ 53 public class KeyStore { 54 private static final String TAG = "KeyStore"; 55 56 // ResponseCodes 57 public static final int NO_ERROR = 1; 58 public static final int LOCKED = 2; 59 public static final int UNINITIALIZED = 3; 60 public static final int SYSTEM_ERROR = 4; 61 public static final int PROTOCOL_ERROR = 5; 62 public static final int PERMISSION_DENIED = 6; 63 public static final int KEY_NOT_FOUND = 7; 64 public static final int VALUE_CORRUPTED = 8; 65 public static final int UNDEFINED_ACTION = 9; 66 public static final int WRONG_PASSWORD = 10; 67 68 /** 69 * Per operation authentication is needed before this operation is valid. 70 * This is returned from {@link #begin} when begin succeeds but the operation uses 71 * per-operation authentication and must authenticate before calling {@link #update} or 72 * {@link #finish}. 73 */ 74 public static final int OP_AUTH_NEEDED = 15; 75 76 // Used for UID field to indicate the calling UID. 77 public static final int UID_SELF = -1; 78 79 // Flags for "put" "import" and "generate" 80 public static final int FLAG_NONE = 0; 81 82 /** 83 * Indicates that this key (or key pair) must be encrypted at rest. This will protect the key 84 * (or key pair) with the secure lock screen credential (e.g., password, PIN, or pattern). 85 * 86 * <p>Note that this requires that the secure lock screen (e.g., password, PIN, pattern) is set 87 * up, otherwise key (or key pair) generation or import will fail. Moreover, this key (or key 88 * pair) will be deleted when the secure lock screen is disabled or reset (e.g., by the user or 89 * a Device Administrator). Finally, this key (or key pair) cannot be used until the user 90 * unlocks the secure lock screen after boot. 91 * 92 * @see KeyguardManager#isDeviceSecure() 93 */ 94 public static final int FLAG_ENCRYPTED = 1; 95 96 /** 97 * A private flag that's only available to system server to indicate that this key is part of 98 * device encryption flow so it receives special treatment from keystore. For example this key 99 * will not be super encrypted, and it will be stored separately under an unique UID instead 100 * of the caller UID i.e. SYSTEM. 101 * 102 * Need to be in sync with KeyStoreFlag in system/security/keystore/include/keystore/keystore.h 103 */ 104 public static final int FLAG_CRITICAL_TO_DEVICE_ENCRYPTION = 1 << 3; 105 106 // States 107 public enum State { UNLOCKED, LOCKED, UNINITIALIZED }; 108 109 private int mError = NO_ERROR; 110 111 private final IKeystoreService mBinder; 112 private final Context mContext; 113 114 private IBinder mToken; 115 KeyStore(IKeystoreService binder)116 private KeyStore(IKeystoreService binder) { 117 mBinder = binder; 118 mContext = getApplicationContext(); 119 } 120 getApplicationContext()121 public static Context getApplicationContext() { 122 Application application = ActivityThread.currentApplication(); 123 if (application == null) { 124 throw new IllegalStateException( 125 "Failed to obtain application Context from ActivityThread"); 126 } 127 return application; 128 } 129 getInstance()130 public static KeyStore getInstance() { 131 IKeystoreService keystore = IKeystoreService.Stub.asInterface(ServiceManager 132 .getService("android.security.keystore")); 133 return new KeyStore(keystore); 134 } 135 getToken()136 private synchronized IBinder getToken() { 137 if (mToken == null) { 138 mToken = new Binder(); 139 } 140 return mToken; 141 } 142 state(int userId)143 public State state(int userId) { 144 final int ret; 145 try { 146 ret = mBinder.getState(userId); 147 } catch (RemoteException e) { 148 Log.w(TAG, "Cannot connect to keystore", e); 149 throw new AssertionError(e); 150 } 151 152 switch (ret) { 153 case NO_ERROR: return State.UNLOCKED; 154 case LOCKED: return State.LOCKED; 155 case UNINITIALIZED: return State.UNINITIALIZED; 156 default: throw new AssertionError(mError); 157 } 158 } 159 state()160 public State state() { 161 return state(UserHandle.myUserId()); 162 } 163 isUnlocked()164 public boolean isUnlocked() { 165 return state() == State.UNLOCKED; 166 } 167 get(String key, int uid)168 public byte[] get(String key, int uid) { 169 try { 170 return mBinder.get(key, uid); 171 } catch (RemoteException e) { 172 Log.w(TAG, "Cannot connect to keystore", e); 173 return null; 174 } 175 } 176 get(String key)177 public byte[] get(String key) { 178 return get(key, UID_SELF); 179 } 180 put(String key, byte[] value, int uid, int flags)181 public boolean put(String key, byte[] value, int uid, int flags) { 182 return insert(key, value, uid, flags) == NO_ERROR; 183 } 184 insert(String key, byte[] value, int uid, int flags)185 public int insert(String key, byte[] value, int uid, int flags) { 186 try { 187 return mBinder.insert(key, value, uid, flags); 188 } catch (RemoteException e) { 189 Log.w(TAG, "Cannot connect to keystore", e); 190 return SYSTEM_ERROR; 191 } 192 } 193 delete(String key, int uid)194 public boolean delete(String key, int uid) { 195 try { 196 int ret = mBinder.del(key, uid); 197 return (ret == NO_ERROR || ret == KEY_NOT_FOUND); 198 } catch (RemoteException e) { 199 Log.w(TAG, "Cannot connect to keystore", e); 200 return false; 201 } 202 } 203 delete(String key)204 public boolean delete(String key) { 205 return delete(key, UID_SELF); 206 } 207 contains(String key, int uid)208 public boolean contains(String key, int uid) { 209 try { 210 return mBinder.exist(key, uid) == NO_ERROR; 211 } catch (RemoteException e) { 212 Log.w(TAG, "Cannot connect to keystore", e); 213 return false; 214 } 215 } 216 contains(String key)217 public boolean contains(String key) { 218 return contains(key, UID_SELF); 219 } 220 221 /** 222 * List all entries in the keystore for {@code uid} starting with {@code prefix}. 223 */ list(String prefix, int uid)224 public String[] list(String prefix, int uid) { 225 try { 226 return mBinder.list(prefix, uid); 227 } catch (RemoteException e) { 228 Log.w(TAG, "Cannot connect to keystore", e); 229 return null; 230 } 231 } 232 list(String prefix)233 public String[] list(String prefix) { 234 return list(prefix, UID_SELF); 235 } 236 reset()237 public boolean reset() { 238 try { 239 return mBinder.reset() == NO_ERROR; 240 } catch (RemoteException e) { 241 Log.w(TAG, "Cannot connect to keystore", e); 242 return false; 243 } 244 } 245 246 /** 247 * Attempt to lock the keystore for {@code user}. 248 * 249 * @param user Android user to lock. 250 * @return whether {@code user}'s keystore was locked. 251 */ lock(int userId)252 public boolean lock(int userId) { 253 try { 254 return mBinder.lock(userId) == NO_ERROR; 255 } catch (RemoteException e) { 256 Log.w(TAG, "Cannot connect to keystore", e); 257 return false; 258 } 259 } 260 lock()261 public boolean lock() { 262 return lock(UserHandle.myUserId()); 263 } 264 265 /** 266 * Attempt to unlock the keystore for {@code user} with the password {@code password}. 267 * This is required before keystore entries created with FLAG_ENCRYPTED can be accessed or 268 * created. 269 * 270 * @param user Android user ID to operate on 271 * @param password user's keystore password. Should be the most recent value passed to 272 * {@link #onUserPasswordChanged} for the user. 273 * 274 * @return whether the keystore was unlocked. 275 */ unlock(int userId, String password)276 public boolean unlock(int userId, String password) { 277 try { 278 mError = mBinder.unlock(userId, password); 279 return mError == NO_ERROR; 280 } catch (RemoteException e) { 281 Log.w(TAG, "Cannot connect to keystore", e); 282 return false; 283 } 284 } 285 unlock(String password)286 public boolean unlock(String password) { 287 return unlock(UserHandle.getUserId(Process.myUid()), password); 288 } 289 290 /** 291 * Check if the keystore for {@code userId} is empty. 292 */ isEmpty(int userId)293 public boolean isEmpty(int userId) { 294 try { 295 return mBinder.isEmpty(userId) != 0; 296 } catch (RemoteException e) { 297 Log.w(TAG, "Cannot connect to keystore", e); 298 return false; 299 } 300 } 301 isEmpty()302 public boolean isEmpty() { 303 return isEmpty(UserHandle.myUserId()); 304 } 305 generate(String key, int uid, int keyType, int keySize, int flags, byte[][] args)306 public boolean generate(String key, int uid, int keyType, int keySize, int flags, 307 byte[][] args) { 308 try { 309 return mBinder.generate(key, uid, keyType, keySize, flags, 310 new KeystoreArguments(args)) == NO_ERROR; 311 } catch (RemoteException e) { 312 Log.w(TAG, "Cannot connect to keystore", e); 313 return false; 314 } 315 } 316 importKey(String keyName, byte[] key, int uid, int flags)317 public boolean importKey(String keyName, byte[] key, int uid, int flags) { 318 try { 319 return mBinder.import_key(keyName, key, uid, flags) == NO_ERROR; 320 } catch (RemoteException e) { 321 Log.w(TAG, "Cannot connect to keystore", e); 322 return false; 323 } 324 } 325 sign(String key, byte[] data)326 public byte[] sign(String key, byte[] data) { 327 try { 328 return mBinder.sign(key, data); 329 } catch (RemoteException e) { 330 Log.w(TAG, "Cannot connect to keystore", e); 331 return null; 332 } 333 } 334 verify(String key, byte[] data, byte[] signature)335 public boolean verify(String key, byte[] data, byte[] signature) { 336 try { 337 return mBinder.verify(key, data, signature) == NO_ERROR; 338 } catch (RemoteException e) { 339 Log.w(TAG, "Cannot connect to keystore", e); 340 return false; 341 } 342 } 343 grant(String key, int uid)344 public String grant(String key, int uid) { 345 try { 346 String grantAlias = mBinder.grant(key, uid); 347 if (grantAlias == "") return null; 348 return grantAlias; 349 } catch (RemoteException e) { 350 Log.w(TAG, "Cannot connect to keystore", e); 351 return null; 352 } 353 } 354 ungrant(String key, int uid)355 public boolean ungrant(String key, int uid) { 356 try { 357 return mBinder.ungrant(key, uid) == NO_ERROR; 358 } catch (RemoteException e) { 359 Log.w(TAG, "Cannot connect to keystore", e); 360 return false; 361 } 362 } 363 364 /** 365 * Returns the last modification time of the key in milliseconds since the 366 * epoch. Will return -1L if the key could not be found or other error. 367 */ getmtime(String key, int uid)368 public long getmtime(String key, int uid) { 369 try { 370 final long millis = mBinder.getmtime(key, uid); 371 if (millis == -1L) { 372 return -1L; 373 } 374 375 return millis * 1000L; 376 } catch (RemoteException e) { 377 Log.w(TAG, "Cannot connect to keystore", e); 378 return -1L; 379 } 380 } 381 getmtime(String key)382 public long getmtime(String key) { 383 return getmtime(key, UID_SELF); 384 } 385 duplicate(String srcKey, int srcUid, String destKey, int destUid)386 public boolean duplicate(String srcKey, int srcUid, String destKey, int destUid) { 387 try { 388 return mBinder.duplicate(srcKey, srcUid, destKey, destUid) == NO_ERROR; 389 } catch (RemoteException e) { 390 Log.w(TAG, "Cannot connect to keystore", e); 391 return false; 392 } 393 } 394 395 // TODO: remove this when it's removed from Settings isHardwareBacked()396 public boolean isHardwareBacked() { 397 return isHardwareBacked("RSA"); 398 } 399 isHardwareBacked(String keyType)400 public boolean isHardwareBacked(String keyType) { 401 try { 402 return mBinder.is_hardware_backed(keyType.toUpperCase(Locale.US)) == NO_ERROR; 403 } catch (RemoteException e) { 404 Log.w(TAG, "Cannot connect to keystore", e); 405 return false; 406 } 407 } 408 clearUid(int uid)409 public boolean clearUid(int uid) { 410 try { 411 return mBinder.clear_uid(uid) == NO_ERROR; 412 } catch (RemoteException e) { 413 Log.w(TAG, "Cannot connect to keystore", e); 414 return false; 415 } 416 } 417 getLastError()418 public int getLastError() { 419 return mError; 420 } 421 addRngEntropy(byte[] data)422 public boolean addRngEntropy(byte[] data) { 423 try { 424 return mBinder.addRngEntropy(data) == NO_ERROR; 425 } catch (RemoteException e) { 426 Log.w(TAG, "Cannot connect to keystore", e); 427 return false; 428 } 429 } 430 generateKey(String alias, KeymasterArguments args, byte[] entropy, int uid, int flags, KeyCharacteristics outCharacteristics)431 public int generateKey(String alias, KeymasterArguments args, byte[] entropy, int uid, 432 int flags, KeyCharacteristics outCharacteristics) { 433 try { 434 return mBinder.generateKey(alias, args, entropy, uid, flags, outCharacteristics); 435 } catch (RemoteException e) { 436 Log.w(TAG, "Cannot connect to keystore", e); 437 return SYSTEM_ERROR; 438 } 439 } 440 generateKey(String alias, KeymasterArguments args, byte[] entropy, int flags, KeyCharacteristics outCharacteristics)441 public int generateKey(String alias, KeymasterArguments args, byte[] entropy, int flags, 442 KeyCharacteristics outCharacteristics) { 443 return generateKey(alias, args, entropy, UID_SELF, flags, outCharacteristics); 444 } 445 getKeyCharacteristics(String alias, KeymasterBlob clientId, KeymasterBlob appId, int uid, KeyCharacteristics outCharacteristics)446 public int getKeyCharacteristics(String alias, KeymasterBlob clientId, KeymasterBlob appId, 447 int uid, KeyCharacteristics outCharacteristics) { 448 try { 449 return mBinder.getKeyCharacteristics(alias, clientId, appId, uid, outCharacteristics); 450 } catch (RemoteException e) { 451 Log.w(TAG, "Cannot connect to keystore", e); 452 return SYSTEM_ERROR; 453 } 454 } 455 getKeyCharacteristics(String alias, KeymasterBlob clientId, KeymasterBlob appId, KeyCharacteristics outCharacteristics)456 public int getKeyCharacteristics(String alias, KeymasterBlob clientId, KeymasterBlob appId, 457 KeyCharacteristics outCharacteristics) { 458 return getKeyCharacteristics(alias, clientId, appId, UID_SELF, outCharacteristics); 459 } 460 importKey(String alias, KeymasterArguments args, int format, byte[] keyData, int uid, int flags, KeyCharacteristics outCharacteristics)461 public int importKey(String alias, KeymasterArguments args, int format, byte[] keyData, 462 int uid, int flags, KeyCharacteristics outCharacteristics) { 463 try { 464 return mBinder.importKey(alias, args, format, keyData, uid, flags, 465 outCharacteristics); 466 } catch (RemoteException e) { 467 Log.w(TAG, "Cannot connect to keystore", e); 468 return SYSTEM_ERROR; 469 } 470 } 471 importKey(String alias, KeymasterArguments args, int format, byte[] keyData, int flags, KeyCharacteristics outCharacteristics)472 public int importKey(String alias, KeymasterArguments args, int format, byte[] keyData, 473 int flags, KeyCharacteristics outCharacteristics) { 474 return importKey(alias, args, format, keyData, UID_SELF, flags, outCharacteristics); 475 } 476 exportKey(String alias, int format, KeymasterBlob clientId, KeymasterBlob appId, int uid)477 public ExportResult exportKey(String alias, int format, KeymasterBlob clientId, 478 KeymasterBlob appId, int uid) { 479 try { 480 return mBinder.exportKey(alias, format, clientId, appId, uid); 481 } catch (RemoteException e) { 482 Log.w(TAG, "Cannot connect to keystore", e); 483 return null; 484 } 485 } exportKey(String alias, int format, KeymasterBlob clientId, KeymasterBlob appId)486 public ExportResult exportKey(String alias, int format, KeymasterBlob clientId, 487 KeymasterBlob appId) { 488 return exportKey(alias, format, clientId, appId, UID_SELF); 489 } 490 begin(String alias, int purpose, boolean pruneable, KeymasterArguments args, byte[] entropy, int uid)491 public OperationResult begin(String alias, int purpose, boolean pruneable, 492 KeymasterArguments args, byte[] entropy, int uid) { 493 try { 494 return mBinder.begin(getToken(), alias, purpose, pruneable, args, entropy, uid); 495 } catch (RemoteException e) { 496 Log.w(TAG, "Cannot connect to keystore", e); 497 return null; 498 } 499 } 500 begin(String alias, int purpose, boolean pruneable, KeymasterArguments args, byte[] entropy)501 public OperationResult begin(String alias, int purpose, boolean pruneable, 502 KeymasterArguments args, byte[] entropy) { 503 return begin(alias, purpose, pruneable, args, entropy, UID_SELF); 504 } 505 update(IBinder token, KeymasterArguments arguments, byte[] input)506 public OperationResult update(IBinder token, KeymasterArguments arguments, byte[] input) { 507 try { 508 return mBinder.update(token, arguments, input); 509 } catch (RemoteException e) { 510 Log.w(TAG, "Cannot connect to keystore", e); 511 return null; 512 } 513 } 514 finish(IBinder token, KeymasterArguments arguments, byte[] signature, byte[] entropy)515 public OperationResult finish(IBinder token, KeymasterArguments arguments, byte[] signature, 516 byte[] entropy) { 517 try { 518 return mBinder.finish(token, arguments, signature, entropy); 519 } catch (RemoteException e) { 520 Log.w(TAG, "Cannot connect to keystore", e); 521 return null; 522 } 523 } 524 finish(IBinder token, KeymasterArguments arguments, byte[] signature)525 public OperationResult finish(IBinder token, KeymasterArguments arguments, byte[] signature) { 526 return finish(token, arguments, signature, null); 527 } 528 abort(IBinder token)529 public int abort(IBinder token) { 530 try { 531 return mBinder.abort(token); 532 } catch (RemoteException e) { 533 Log.w(TAG, "Cannot connect to keystore", e); 534 return SYSTEM_ERROR; 535 } 536 } 537 538 /** 539 * Check if the operation referenced by {@code token} is currently authorized. 540 * 541 * @param token An operation token returned by a call to 542 * {@link #begin(String, int, boolean, KeymasterArguments, byte[], KeymasterArguments) begin}. 543 */ isOperationAuthorized(IBinder token)544 public boolean isOperationAuthorized(IBinder token) { 545 try { 546 return mBinder.isOperationAuthorized(token); 547 } catch (RemoteException e) { 548 Log.w(TAG, "Cannot connect to keystore", e); 549 return false; 550 } 551 } 552 553 /** 554 * Add an authentication record to the keystore authorization table. 555 * 556 * @param authToken The packed bytes of a hw_auth_token_t to be provided to keymaster. 557 * @return {@code KeyStore.NO_ERROR} on success, otherwise an error value corresponding to 558 * a {@code KeymasterDefs.KM_ERROR_} value or {@code KeyStore} ResponseCode. 559 */ addAuthToken(byte[] authToken)560 public int addAuthToken(byte[] authToken) { 561 try { 562 return mBinder.addAuthToken(authToken); 563 } catch (RemoteException e) { 564 Log.w(TAG, "Cannot connect to keystore", e); 565 return SYSTEM_ERROR; 566 } 567 } 568 569 /** 570 * Notify keystore that a user's password has changed. 571 * 572 * @param userId the user whose password changed. 573 * @param newPassword the new password or "" if the password was removed. 574 */ onUserPasswordChanged(int userId, String newPassword)575 public boolean onUserPasswordChanged(int userId, String newPassword) { 576 // Parcel.cpp doesn't support deserializing null strings and treats them as "". Make that 577 // explicit here. 578 if (newPassword == null) { 579 newPassword = ""; 580 } 581 try { 582 return mBinder.onUserPasswordChanged(userId, newPassword) == NO_ERROR; 583 } catch (RemoteException e) { 584 Log.w(TAG, "Cannot connect to keystore", e); 585 return false; 586 } 587 } 588 589 /** 590 * Notify keystore that a user was added. 591 * 592 * @param userId the new user. 593 * @param parentId the parent of the new user, or -1 if the user has no parent. If parentId is 594 * specified then the new user's keystore will be intialized with the same secure lockscreen 595 * password as the parent. 596 */ onUserAdded(int userId, int parentId)597 public void onUserAdded(int userId, int parentId) { 598 try { 599 mBinder.onUserAdded(userId, parentId); 600 } catch (RemoteException e) { 601 Log.w(TAG, "Cannot connect to keystore", e); 602 } 603 } 604 605 /** 606 * Notify keystore that a user was added. 607 * 608 * @param userId the new user. 609 */ onUserAdded(int userId)610 public void onUserAdded(int userId) { 611 onUserAdded(userId, -1); 612 } 613 614 /** 615 * Notify keystore that a user was removed. 616 * 617 * @param userId the removed user. 618 */ onUserRemoved(int userId)619 public void onUserRemoved(int userId) { 620 try { 621 mBinder.onUserRemoved(userId); 622 } catch (RemoteException e) { 623 Log.w(TAG, "Cannot connect to keystore", e); 624 } 625 } 626 onUserPasswordChanged(String newPassword)627 public boolean onUserPasswordChanged(String newPassword) { 628 return onUserPasswordChanged(UserHandle.getUserId(Process.myUid()), newPassword); 629 } 630 attestKey( String alias, KeymasterArguments params, KeymasterCertificateChain outChain)631 public int attestKey( 632 String alias, KeymasterArguments params, KeymasterCertificateChain outChain) { 633 try { 634 return mBinder.attestKey(alias, params, outChain); 635 } catch (RemoteException e) { 636 Log.w(TAG, "Cannot connect to keystore", e); 637 return SYSTEM_ERROR; 638 } 639 } 640 attestDeviceIds(KeymasterArguments params, KeymasterCertificateChain outChain)641 public int attestDeviceIds(KeymasterArguments params, KeymasterCertificateChain outChain) { 642 try { 643 return mBinder.attestDeviceIds(params, outChain); 644 } catch (RemoteException e) { 645 Log.w(TAG, "Cannot connect to keystore", e); 646 return SYSTEM_ERROR; 647 } 648 } 649 650 /** 651 * Notify keystore that the device went off-body. 652 */ onDeviceOffBody()653 public void onDeviceOffBody() { 654 try { 655 mBinder.onDeviceOffBody(); 656 } catch (RemoteException e) { 657 Log.w(TAG, "Cannot connect to keystore", e); 658 } 659 } 660 661 /** 662 * Returns a {@link KeyStoreException} corresponding to the provided keystore/keymaster error 663 * code. 664 */ getKeyStoreException(int errorCode)665 public static KeyStoreException getKeyStoreException(int errorCode) { 666 if (errorCode > 0) { 667 // KeyStore layer error 668 switch (errorCode) { 669 case NO_ERROR: 670 return new KeyStoreException(errorCode, "OK"); 671 case LOCKED: 672 return new KeyStoreException(errorCode, "User authentication required"); 673 case UNINITIALIZED: 674 return new KeyStoreException(errorCode, "Keystore not initialized"); 675 case SYSTEM_ERROR: 676 return new KeyStoreException(errorCode, "System error"); 677 case PERMISSION_DENIED: 678 return new KeyStoreException(errorCode, "Permission denied"); 679 case KEY_NOT_FOUND: 680 return new KeyStoreException(errorCode, "Key not found"); 681 case VALUE_CORRUPTED: 682 return new KeyStoreException(errorCode, "Key blob corrupted"); 683 case OP_AUTH_NEEDED: 684 return new KeyStoreException(errorCode, "Operation requires authorization"); 685 default: 686 return new KeyStoreException(errorCode, String.valueOf(errorCode)); 687 } 688 } else { 689 // Keymaster layer error 690 switch (errorCode) { 691 case KeymasterDefs.KM_ERROR_INVALID_AUTHORIZATION_TIMEOUT: 692 // The name of this parameter significantly differs between Keymaster and 693 // framework APIs. Use the framework wording to make life easier for developers. 694 return new KeyStoreException(errorCode, 695 "Invalid user authentication validity duration"); 696 default: 697 return new KeyStoreException(errorCode, 698 KeymasterDefs.getErrorMessage(errorCode)); 699 } 700 } 701 } 702 703 /** 704 * Returns an {@link InvalidKeyException} corresponding to the provided 705 * {@link KeyStoreException}. 706 */ getInvalidKeyException( String keystoreKeyAlias, int uid, KeyStoreException e)707 public InvalidKeyException getInvalidKeyException( 708 String keystoreKeyAlias, int uid, KeyStoreException e) { 709 switch (e.getErrorCode()) { 710 case LOCKED: 711 return new UserNotAuthenticatedException(); 712 case KeymasterDefs.KM_ERROR_KEY_EXPIRED: 713 return new KeyExpiredException(); 714 case KeymasterDefs.KM_ERROR_KEY_NOT_YET_VALID: 715 return new KeyNotYetValidException(); 716 case KeymasterDefs.KM_ERROR_KEY_USER_NOT_AUTHENTICATED: 717 case OP_AUTH_NEEDED: 718 { 719 // We now need to determine whether the key/operation can become usable if user 720 // authentication is performed, or whether it can never become usable again. 721 // User authentication requirements are contained in the key's characteristics. We 722 // need to check whether these requirements can be be satisfied by asking the user 723 // to authenticate. 724 KeyCharacteristics keyCharacteristics = new KeyCharacteristics(); 725 int getKeyCharacteristicsErrorCode = 726 getKeyCharacteristics(keystoreKeyAlias, null, null, uid, 727 keyCharacteristics); 728 if (getKeyCharacteristicsErrorCode != NO_ERROR) { 729 return new InvalidKeyException( 730 "Failed to obtained key characteristics", 731 getKeyStoreException(getKeyCharacteristicsErrorCode)); 732 } 733 List<BigInteger> keySids = 734 keyCharacteristics.getUnsignedLongs(KeymasterDefs.KM_TAG_USER_SECURE_ID); 735 if (keySids.isEmpty()) { 736 // Key is not bound to any SIDs -- no amount of authentication will help here. 737 return new KeyPermanentlyInvalidatedException(); 738 } 739 long rootSid = GateKeeper.getSecureUserId(); 740 if ((rootSid != 0) && (keySids.contains(KeymasterArguments.toUint64(rootSid)))) { 741 // One of the key's SIDs is the current root SID -- user can be authenticated 742 // against that SID. 743 return new UserNotAuthenticatedException(); 744 } 745 746 long fingerprintOnlySid = getFingerprintOnlySid(); 747 if ((fingerprintOnlySid != 0) 748 && (keySids.contains(KeymasterArguments.toUint64(fingerprintOnlySid)))) { 749 // One of the key's SIDs is the current fingerprint SID -- user can be 750 // authenticated against that SID. 751 return new UserNotAuthenticatedException(); 752 } 753 754 // None of the key's SIDs can ever be authenticated 755 return new KeyPermanentlyInvalidatedException(); 756 } 757 case UNINITIALIZED: 758 return new KeyPermanentlyInvalidatedException(); 759 default: 760 return new InvalidKeyException("Keystore operation failed", e); 761 } 762 } 763 getFingerprintOnlySid()764 private long getFingerprintOnlySid() { 765 FingerprintManager fingerprintManager = mContext.getSystemService(FingerprintManager.class); 766 if (fingerprintManager == null) { 767 return 0; 768 } 769 770 // TODO: Restore USE_FINGERPRINT permission check in 771 // FingerprintManager.getAuthenticatorId once the ID is no longer needed here. 772 return fingerprintManager.getAuthenticatorId(); 773 } 774 775 /** 776 * Returns an {@link InvalidKeyException} corresponding to the provided keystore/keymaster error 777 * code. 778 */ getInvalidKeyException(String keystoreKeyAlias, int uid, int errorCode)779 public InvalidKeyException getInvalidKeyException(String keystoreKeyAlias, int uid, 780 int errorCode) { 781 return getInvalidKeyException(keystoreKeyAlias, uid, getKeyStoreException(errorCode)); 782 } 783 } 784