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.compat.annotation.UnsupportedAppUsage; 23 import android.content.Context; 24 import android.hardware.biometrics.BiometricManager; 25 import android.os.Binder; 26 import android.os.Build; 27 import android.os.IBinder; 28 import android.os.Process; 29 import android.os.RemoteException; 30 import android.os.ServiceManager; 31 import android.os.UserHandle; 32 import android.security.keymaster.ExportResult; 33 import android.security.keymaster.KeyCharacteristics; 34 import android.security.keymaster.KeymasterArguments; 35 import android.security.keymaster.KeymasterBlob; 36 import android.security.keymaster.KeymasterCertificateChain; 37 import android.security.keymaster.KeymasterDefs; 38 import android.security.keymaster.OperationResult; 39 import android.security.keystore.IKeystoreService; 40 import android.security.keystore.KeyExpiredException; 41 import android.security.keystore.KeyNotYetValidException; 42 import android.security.keystore.KeyPermanentlyInvalidatedException; 43 import android.security.keystore.KeyProperties; 44 import android.security.keystore.KeystoreResponse; 45 import android.security.keystore.UserNotAuthenticatedException; 46 import android.util.Log; 47 48 import com.android.org.bouncycastle.asn1.ASN1InputStream; 49 import com.android.org.bouncycastle.asn1.pkcs.PrivateKeyInfo; 50 51 import java.io.ByteArrayInputStream; 52 import java.io.IOException; 53 import java.math.BigInteger; 54 import java.security.InvalidKeyException; 55 import java.util.ArrayList; 56 import java.util.Date; 57 import java.util.List; 58 import java.util.Locale; 59 import java.util.concurrent.CompletableFuture; 60 import java.util.concurrent.ExecutionException; 61 62 import sun.security.util.ObjectIdentifier; 63 import sun.security.x509.AlgorithmId; 64 65 /** 66 * @hide This should not be made public in its present form because it 67 * assumes that private and secret key bytes are available and would 68 * preclude the use of hardware crypto. 69 */ 70 public class KeyStore { 71 private static final String TAG = "KeyStore"; 72 73 // ResponseCodes - see system/security/keystore/include/keystore/keystore.h 74 @UnsupportedAppUsage 75 public static final int NO_ERROR = 1; 76 public static final int LOCKED = 2; 77 public static final int UNINITIALIZED = 3; 78 public static final int SYSTEM_ERROR = 4; 79 public static final int PROTOCOL_ERROR = 5; 80 public static final int PERMISSION_DENIED = 6; 81 public static final int KEY_NOT_FOUND = 7; 82 public static final int VALUE_CORRUPTED = 8; 83 public static final int UNDEFINED_ACTION = 9; 84 public static final int WRONG_PASSWORD = 10; 85 public static final int KEY_ALREADY_EXISTS = 16; 86 public static final int CANNOT_ATTEST_IDS = -66; 87 public static final int HARDWARE_TYPE_UNAVAILABLE = -68; 88 89 /** 90 * Per operation authentication is needed before this operation is valid. 91 * This is returned from {@link #begin} when begin succeeds but the operation uses 92 * per-operation authentication and must authenticate before calling {@link #update} or 93 * {@link #finish}. 94 */ 95 public static final int OP_AUTH_NEEDED = 15; 96 97 // Used when a user changes their pin, invalidating old auth bound keys. 98 public static final int KEY_PERMANENTLY_INVALIDATED = 17; 99 100 // Used for UID field to indicate the calling UID. 101 public static final int UID_SELF = -1; 102 103 // Flags for "put" "import" and "generate" 104 public static final int FLAG_NONE = 0; 105 106 /** 107 * Indicates that this key (or key pair) must be encrypted at rest. This will protect the key 108 * (or key pair) with the secure lock screen credential (e.g., password, PIN, or pattern). 109 * 110 * <p>Note that this requires that the secure lock screen (e.g., password, PIN, pattern) is set 111 * up, otherwise key (or key pair) generation or import will fail. Moreover, this key (or key 112 * pair) will be deleted when the secure lock screen is disabled or reset (e.g., by the user or 113 * a Device Administrator). Finally, this key (or key pair) cannot be used until the user 114 * unlocks the secure lock screen after boot. 115 * 116 * @see KeyguardManager#isDeviceSecure() 117 */ 118 public static final int FLAG_ENCRYPTED = 1; 119 120 /** 121 * Select Software keymaster device, which as of this writing is the lowest security 122 * level available on an android device. If neither FLAG_STRONGBOX nor FLAG_SOFTWARE is provided 123 * A TEE based keymaster implementation is implied. 124 * 125 * Need to be in sync with KeyStoreFlag in system/security/keystore/include/keystore/keystore.h 126 * For historical reasons this corresponds to the KEYSTORE_FLAG_FALLBACK flag. 127 */ 128 public static final int FLAG_SOFTWARE = 1 << 1; 129 130 /** 131 * A private flag that's only available to system server to indicate that this key is part of 132 * device encryption flow so it receives special treatment from keystore. For example this key 133 * will not be super encrypted, and it will be stored separately under an unique UID instead 134 * of the caller UID i.e. SYSTEM. 135 * 136 * Need to be in sync with KeyStoreFlag in system/security/keystore/include/keystore/keystore.h 137 */ 138 public static final int FLAG_CRITICAL_TO_DEVICE_ENCRYPTION = 1 << 3; 139 140 /** 141 * Select Strongbox keymaster device, which as of this writing the the highest security level 142 * available an android devices. If neither FLAG_STRONGBOX nor FLAG_SOFTWARE is provided 143 * A TEE based keymaster implementation is implied. 144 * 145 * Need to be in sync with KeyStoreFlag in system/security/keystore/include/keystore/keystore.h 146 */ 147 public static final int FLAG_STRONGBOX = 1 << 4; 148 149 // States 150 public enum State { 151 @UnsupportedAppUsage 152 UNLOCKED, 153 @UnsupportedAppUsage 154 LOCKED, 155 UNINITIALIZED 156 }; 157 158 private int mError = NO_ERROR; 159 160 private final IKeystoreService mBinder; 161 private final Context mContext; 162 163 private IBinder mToken; 164 KeyStore(IKeystoreService binder)165 private KeyStore(IKeystoreService binder) { 166 mBinder = binder; 167 mContext = getApplicationContext(); 168 } 169 170 @UnsupportedAppUsage getApplicationContext()171 public static Context getApplicationContext() { 172 Application application = ActivityThread.currentApplication(); 173 if (application == null) { 174 throw new IllegalStateException( 175 "Failed to obtain application Context from ActivityThread"); 176 } 177 return application; 178 } 179 180 @UnsupportedAppUsage getInstance()181 public static KeyStore getInstance() { 182 IKeystoreService keystore = IKeystoreService.Stub.asInterface(ServiceManager 183 .getService("android.security.keystore")); 184 return new KeyStore(keystore); 185 } 186 getToken()187 private synchronized IBinder getToken() { 188 if (mToken == null) { 189 mToken = new Binder(); 190 } 191 return mToken; 192 } 193 194 @UnsupportedAppUsage state(int userId)195 public State state(int userId) { 196 final int ret; 197 try { 198 ret = mBinder.getState(userId); 199 } catch (RemoteException e) { 200 Log.w(TAG, "Cannot connect to keystore", e); 201 throw new AssertionError(e); 202 } 203 204 switch (ret) { 205 case NO_ERROR: return State.UNLOCKED; 206 case LOCKED: return State.LOCKED; 207 case UNINITIALIZED: return State.UNINITIALIZED; 208 default: throw new AssertionError(mError); 209 } 210 } 211 212 @UnsupportedAppUsage state()213 public State state() { 214 return state(UserHandle.myUserId()); 215 } 216 isUnlocked()217 public boolean isUnlocked() { 218 return state() == State.UNLOCKED; 219 } 220 get(String key, int uid)221 public byte[] get(String key, int uid) { 222 return get(key, uid, false); 223 } 224 225 @UnsupportedAppUsage get(String key)226 public byte[] get(String key) { 227 return get(key, UID_SELF); 228 } 229 get(String key, int uid, boolean suppressKeyNotFoundWarning)230 public byte[] get(String key, int uid, boolean suppressKeyNotFoundWarning) { 231 try { 232 key = key != null ? key : ""; 233 return mBinder.get(key, uid); 234 } catch (RemoteException e) { 235 Log.w(TAG, "Cannot connect to keystore", e); 236 return null; 237 } catch (android.os.ServiceSpecificException e) { 238 if (!suppressKeyNotFoundWarning || e.errorCode != KEY_NOT_FOUND) { 239 Log.w(TAG, "KeyStore exception", e); 240 } 241 return null; 242 } 243 } 244 get(String key, boolean suppressKeyNotFoundWarning)245 public byte[] get(String key, boolean suppressKeyNotFoundWarning) { 246 return get(key, UID_SELF, suppressKeyNotFoundWarning); 247 } 248 249 put(String key, byte[] value, int uid, int flags)250 public boolean put(String key, byte[] value, int uid, int flags) { 251 return insert(key, value, uid, flags) == NO_ERROR; 252 } 253 insert(String key, byte[] value, int uid, int flags)254 public int insert(String key, byte[] value, int uid, int flags) { 255 try { 256 if (value == null) { 257 value = new byte[0]; 258 } 259 int error = mBinder.insert(key, value, uid, flags); 260 if (error == KEY_ALREADY_EXISTS) { 261 mBinder.del(key, uid); 262 error = mBinder.insert(key, value, uid, flags); 263 } 264 return error; 265 } catch (RemoteException e) { 266 Log.w(TAG, "Cannot connect to keystore", e); 267 return SYSTEM_ERROR; 268 } 269 } 270 delete2(String key, int uid)271 int delete2(String key, int uid) { 272 try { 273 return mBinder.del(key, uid); 274 } catch (RemoteException e) { 275 Log.w(TAG, "Cannot connect to keystore", e); 276 return SYSTEM_ERROR; 277 } 278 } 279 delete(String key, int uid)280 public boolean delete(String key, int uid) { 281 int ret = delete2(key, uid); 282 return ret == NO_ERROR || ret == KEY_NOT_FOUND; 283 } 284 285 @UnsupportedAppUsage delete(String key)286 public boolean delete(String key) { 287 return delete(key, UID_SELF); 288 } 289 contains(String key, int uid)290 public boolean contains(String key, int uid) { 291 try { 292 return mBinder.exist(key, uid) == NO_ERROR; 293 } catch (RemoteException e) { 294 Log.w(TAG, "Cannot connect to keystore", e); 295 return false; 296 } 297 } 298 contains(String key)299 public boolean contains(String key) { 300 return contains(key, UID_SELF); 301 } 302 303 /** 304 * List all entries in the keystore for {@code uid} starting with {@code prefix}. 305 */ list(String prefix, int uid)306 public String[] list(String prefix, int uid) { 307 try { 308 return mBinder.list(prefix, uid); 309 } catch (RemoteException e) { 310 Log.w(TAG, "Cannot connect to keystore", e); 311 return null; 312 } catch (android.os.ServiceSpecificException e) { 313 Log.w(TAG, "KeyStore exception", e); 314 return null; 315 } 316 } 317 318 /** 319 * List uids of all keys that are auth bound to the current user. 320 * Only system is allowed to call this method. 321 */ 322 @UnsupportedAppUsage listUidsOfAuthBoundKeys()323 public int[] listUidsOfAuthBoundKeys() { 324 // uids are returned as a list of strings because list of integers 325 // as an output parameter is not supported by aidl-cpp. 326 List<String> uidsOut = new ArrayList<>(); 327 try { 328 int rc = mBinder.listUidsOfAuthBoundKeys(uidsOut); 329 if (rc != NO_ERROR) { 330 Log.w(TAG, String.format("listUidsOfAuthBoundKeys failed with error code %d", rc)); 331 return null; 332 } 333 } catch (RemoteException e) { 334 Log.w(TAG, "Cannot connect to keystore", e); 335 return null; 336 } catch (android.os.ServiceSpecificException e) { 337 Log.w(TAG, "KeyStore exception", e); 338 return null; 339 } 340 // Turn list of strings into an array of uid integers. 341 return uidsOut.stream().mapToInt(Integer::parseInt).toArray(); 342 } 343 list(String prefix)344 public String[] list(String prefix) { 345 return list(prefix, UID_SELF); 346 } 347 348 /** 349 * Attempt to lock the keystore for {@code user}. 350 * 351 * @param userId Android user to lock. 352 * @return whether {@code user}'s keystore was locked. 353 */ lock(int userId)354 public boolean lock(int userId) { 355 try { 356 return mBinder.lock(userId) == NO_ERROR; 357 } catch (RemoteException e) { 358 Log.w(TAG, "Cannot connect to keystore", e); 359 return false; 360 } 361 } 362 lock()363 public boolean lock() { 364 return lock(UserHandle.myUserId()); 365 } 366 367 /** 368 * Attempt to unlock the keystore for {@code user} with the password {@code password}. 369 * This is required before keystore entries created with FLAG_ENCRYPTED can be accessed or 370 * created. 371 * 372 * @param userId Android user ID to operate on 373 * @param password user's keystore password. Should be the most recent value passed to 374 * {@link #onUserPasswordChanged} for the user. 375 * 376 * @return whether the keystore was unlocked. 377 */ unlock(int userId, String password)378 public boolean unlock(int userId, String password) { 379 try { 380 password = password != null ? password : ""; 381 mError = mBinder.unlock(userId, password); 382 return mError == NO_ERROR; 383 } catch (RemoteException e) { 384 Log.w(TAG, "Cannot connect to keystore", e); 385 return false; 386 } 387 } 388 389 @UnsupportedAppUsage unlock(String password)390 public boolean unlock(String password) { 391 return unlock(UserHandle.getUserId(Process.myUid()), password); 392 } 393 394 /** 395 * Check if the keystore for {@code userId} is empty. 396 */ isEmpty(int userId)397 public boolean isEmpty(int userId) { 398 try { 399 return mBinder.isEmpty(userId) != 0; 400 } catch (RemoteException e) { 401 Log.w(TAG, "Cannot connect to keystore", e); 402 return false; 403 } 404 } 405 406 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) isEmpty()407 public boolean isEmpty() { 408 return isEmpty(UserHandle.myUserId()); 409 } 410 grant(String key, int uid)411 public String grant(String key, int uid) { 412 try { 413 String grantAlias = mBinder.grant(key, uid); 414 if (grantAlias == "") return null; 415 return grantAlias; 416 } catch (RemoteException e) { 417 Log.w(TAG, "Cannot connect to keystore", e); 418 return null; 419 } 420 } 421 ungrant(String key, int uid)422 public boolean ungrant(String key, int uid) { 423 try { 424 return mBinder.ungrant(key, uid) == NO_ERROR; 425 } catch (RemoteException e) { 426 Log.w(TAG, "Cannot connect to keystore", e); 427 return false; 428 } 429 } 430 431 /** 432 * Returns the last modification time of the key in milliseconds since the 433 * epoch. Will return -1L if the key could not be found or other error. 434 */ getmtime(String key, int uid)435 public long getmtime(String key, int uid) { 436 try { 437 final long millis = mBinder.getmtime(key, uid); 438 if (millis == -1L) { 439 return -1L; 440 } 441 442 return millis * 1000L; 443 } catch (RemoteException e) { 444 Log.w(TAG, "Cannot connect to keystore", e); 445 return -1L; 446 } 447 } 448 getmtime(String key)449 public long getmtime(String key) { 450 return getmtime(key, UID_SELF); 451 } 452 453 // TODO: remove this when it's removed from Settings isHardwareBacked()454 public boolean isHardwareBacked() { 455 return isHardwareBacked("RSA"); 456 } 457 isHardwareBacked(String keyType)458 public boolean isHardwareBacked(String keyType) { 459 try { 460 return mBinder.is_hardware_backed(keyType.toUpperCase(Locale.US)) == NO_ERROR; 461 } catch (RemoteException e) { 462 Log.w(TAG, "Cannot connect to keystore", e); 463 return false; 464 } 465 } 466 clearUid(int uid)467 public boolean clearUid(int uid) { 468 try { 469 return mBinder.clear_uid(uid) == NO_ERROR; 470 } catch (RemoteException e) { 471 Log.w(TAG, "Cannot connect to keystore", e); 472 return false; 473 } 474 } 475 getLastError()476 public int getLastError() { 477 return mError; 478 } 479 addRngEntropy(byte[] data, int flags)480 public boolean addRngEntropy(byte[] data, int flags) { 481 KeystoreResultPromise promise = new KeystoreResultPromise(); 482 try { 483 mBinder.asBinder().linkToDeath(promise, 0); 484 int errorCode = mBinder.addRngEntropy(promise, data, flags); 485 if (errorCode == NO_ERROR) { 486 return interruptedPreservingGet(promise.getFuture()).getErrorCode() == NO_ERROR; 487 } else { 488 return false; 489 } 490 } catch (RemoteException e) { 491 Log.w(TAG, "Cannot connect to keystore", e); 492 return false; 493 } catch (ExecutionException e) { 494 Log.e(TAG, "AddRngEntropy completed with exception", e); 495 return false; 496 } finally { 497 mBinder.asBinder().unlinkToDeath(promise, 0); 498 } 499 } 500 501 private class KeyCharacteristicsCallbackResult { 502 private KeystoreResponse keystoreResponse; 503 private KeyCharacteristics keyCharacteristics; 504 KeyCharacteristicsCallbackResult(KeystoreResponse keystoreResponse, KeyCharacteristics keyCharacteristics)505 public KeyCharacteristicsCallbackResult(KeystoreResponse keystoreResponse, 506 KeyCharacteristics keyCharacteristics) { 507 this.keystoreResponse = keystoreResponse; 508 this.keyCharacteristics = keyCharacteristics; 509 } 510 getKeystoreResponse()511 public KeystoreResponse getKeystoreResponse() { 512 return keystoreResponse; 513 } 514 setKeystoreResponse(KeystoreResponse keystoreResponse)515 public void setKeystoreResponse(KeystoreResponse keystoreResponse) { 516 this.keystoreResponse = keystoreResponse; 517 } 518 getKeyCharacteristics()519 public KeyCharacteristics getKeyCharacteristics() { 520 return keyCharacteristics; 521 } 522 setKeyCharacteristics(KeyCharacteristics keyCharacteristics)523 public void setKeyCharacteristics(KeyCharacteristics keyCharacteristics) { 524 this.keyCharacteristics = keyCharacteristics; 525 } 526 } 527 528 private class KeyCharacteristicsPromise 529 extends android.security.keystore.IKeystoreKeyCharacteristicsCallback.Stub 530 implements IBinder.DeathRecipient { 531 final private CompletableFuture<KeyCharacteristicsCallbackResult> future = 532 new CompletableFuture<KeyCharacteristicsCallbackResult>(); 533 @Override onFinished(KeystoreResponse keystoreResponse, KeyCharacteristics keyCharacteristics)534 public void onFinished(KeystoreResponse keystoreResponse, 535 KeyCharacteristics keyCharacteristics) 536 throws android.os.RemoteException { 537 future.complete( 538 new KeyCharacteristicsCallbackResult(keystoreResponse, keyCharacteristics)); 539 } getFuture()540 public final CompletableFuture<KeyCharacteristicsCallbackResult> getFuture() { 541 return future; 542 } 543 @Override binderDied()544 public void binderDied() { 545 future.completeExceptionally(new RemoteException("Keystore died")); 546 } 547 }; 548 generateKeyInternal(String alias, KeymasterArguments args, byte[] entropy, int uid, int flags, KeyCharacteristics outCharacteristics)549 private int generateKeyInternal(String alias, KeymasterArguments args, byte[] entropy, int uid, 550 int flags, KeyCharacteristics outCharacteristics) 551 throws RemoteException, ExecutionException { 552 KeyCharacteristicsPromise promise = new KeyCharacteristicsPromise(); 553 int error = NO_ERROR; 554 KeyCharacteristicsCallbackResult result = null; 555 try { 556 mBinder.asBinder().linkToDeath(promise, 0); 557 error = mBinder.generateKey(promise, alias, args, entropy, uid, flags); 558 if (error != NO_ERROR) { 559 Log.e(TAG, "generateKeyInternal failed on request " + error); 560 return error; 561 } 562 result = interruptedPreservingGet(promise.getFuture()); 563 } finally { 564 mBinder.asBinder().unlinkToDeath(promise, 0); 565 } 566 567 error = result.getKeystoreResponse().getErrorCode(); 568 if (error != NO_ERROR) { 569 Log.e(TAG, "generateKeyInternal failed on response " + error); 570 return error; 571 } 572 KeyCharacteristics characteristics = result.getKeyCharacteristics(); 573 if (characteristics == null) { 574 Log.e(TAG, "generateKeyInternal got empty key characteristics " + error); 575 return SYSTEM_ERROR; 576 } 577 outCharacteristics.shallowCopyFrom(characteristics); 578 return NO_ERROR; 579 } 580 generateKey(String alias, KeymasterArguments args, byte[] entropy, int uid, int flags, KeyCharacteristics outCharacteristics)581 public int generateKey(String alias, KeymasterArguments args, byte[] entropy, int uid, 582 int flags, KeyCharacteristics outCharacteristics) { 583 try { 584 entropy = entropy != null ? entropy : new byte[0]; 585 args = args != null ? args : new KeymasterArguments(); 586 int error = generateKeyInternal(alias, args, entropy, uid, flags, outCharacteristics); 587 if (error == KEY_ALREADY_EXISTS) { 588 mBinder.del(alias, uid); 589 error = generateKeyInternal(alias, args, entropy, uid, flags, outCharacteristics); 590 } 591 return error; 592 } catch (RemoteException e) { 593 Log.w(TAG, "Cannot connect to keystore", e); 594 return SYSTEM_ERROR; 595 } catch (ExecutionException e) { 596 Log.e(TAG, "generateKey completed with exception", e); 597 return SYSTEM_ERROR; 598 } 599 } 600 generateKey(String alias, KeymasterArguments args, byte[] entropy, int flags, KeyCharacteristics outCharacteristics)601 public int generateKey(String alias, KeymasterArguments args, byte[] entropy, int flags, 602 KeyCharacteristics outCharacteristics) { 603 return generateKey(alias, args, entropy, UID_SELF, flags, outCharacteristics); 604 } 605 getKeyCharacteristics(String alias, KeymasterBlob clientId, KeymasterBlob appId, int uid, KeyCharacteristics outCharacteristics)606 public int getKeyCharacteristics(String alias, KeymasterBlob clientId, KeymasterBlob appId, 607 int uid, KeyCharacteristics outCharacteristics) { 608 KeyCharacteristicsPromise promise = new KeyCharacteristicsPromise(); 609 try { 610 mBinder.asBinder().linkToDeath(promise, 0); 611 clientId = clientId != null ? clientId : new KeymasterBlob(new byte[0]); 612 appId = appId != null ? appId : new KeymasterBlob(new byte[0]); 613 614 int error = mBinder.getKeyCharacteristics(promise, alias, clientId, appId, uid); 615 if (error != NO_ERROR) return error; 616 617 KeyCharacteristicsCallbackResult result = interruptedPreservingGet(promise.getFuture()); 618 error = result.getKeystoreResponse().getErrorCode(); 619 if (error != NO_ERROR) return error; 620 621 KeyCharacteristics characteristics = result.getKeyCharacteristics(); 622 if (characteristics == null) return SYSTEM_ERROR; 623 outCharacteristics.shallowCopyFrom(characteristics); 624 return NO_ERROR; 625 } catch (RemoteException e) { 626 Log.w(TAG, "Cannot connect to keystore", e); 627 return SYSTEM_ERROR; 628 } catch (ExecutionException e) { 629 Log.e(TAG, "GetKeyCharacteristics completed with exception", e); 630 return SYSTEM_ERROR; 631 } finally { 632 mBinder.asBinder().unlinkToDeath(promise, 0); 633 } 634 } 635 getKeyCharacteristics(String alias, KeymasterBlob clientId, KeymasterBlob appId, KeyCharacteristics outCharacteristics)636 public int getKeyCharacteristics(String alias, KeymasterBlob clientId, KeymasterBlob appId, 637 KeyCharacteristics outCharacteristics) { 638 return getKeyCharacteristics(alias, clientId, appId, UID_SELF, outCharacteristics); 639 } 640 importKeyInternal(String alias, KeymasterArguments args, int format, byte[] keyData, int uid, int flags, KeyCharacteristics outCharacteristics)641 private int importKeyInternal(String alias, KeymasterArguments args, int format, byte[] keyData, 642 int uid, int flags, KeyCharacteristics outCharacteristics) 643 throws RemoteException, ExecutionException { 644 KeyCharacteristicsPromise promise = new KeyCharacteristicsPromise(); 645 mBinder.asBinder().linkToDeath(promise, 0); 646 try { 647 int error = mBinder.importKey(promise, alias, args, format, keyData, uid, flags); 648 if (error != NO_ERROR) return error; 649 650 KeyCharacteristicsCallbackResult result = interruptedPreservingGet(promise.getFuture()); 651 652 error = result.getKeystoreResponse().getErrorCode(); 653 if (error != NO_ERROR) return error; 654 655 KeyCharacteristics characteristics = result.getKeyCharacteristics(); 656 if (characteristics == null) return SYSTEM_ERROR; 657 outCharacteristics.shallowCopyFrom(characteristics); 658 return NO_ERROR; 659 } finally { 660 mBinder.asBinder().unlinkToDeath(promise, 0); 661 } 662 } 663 importKey(String alias, KeymasterArguments args, int format, byte[] keyData, int uid, int flags, KeyCharacteristics outCharacteristics)664 public int importKey(String alias, KeymasterArguments args, int format, byte[] keyData, 665 int uid, int flags, KeyCharacteristics outCharacteristics) { 666 try { 667 int error = importKeyInternal(alias, args, format, keyData, uid, flags, 668 outCharacteristics); 669 if (error == KEY_ALREADY_EXISTS) { 670 mBinder.del(alias, uid); 671 error = importKeyInternal(alias, args, format, keyData, uid, flags, 672 outCharacteristics); 673 } 674 return error; 675 } catch (RemoteException e) { 676 Log.w(TAG, "Cannot connect to keystore", e); 677 return SYSTEM_ERROR; 678 } catch (ExecutionException e) { 679 Log.e(TAG, "ImportKey completed with exception", e); 680 return SYSTEM_ERROR; 681 } 682 } 683 importKey(String alias, KeymasterArguments args, int format, byte[] keyData, int flags, KeyCharacteristics outCharacteristics)684 public int importKey(String alias, KeymasterArguments args, int format, byte[] keyData, 685 int flags, KeyCharacteristics outCharacteristics) { 686 return importKey(alias, args, format, keyData, UID_SELF, flags, outCharacteristics); 687 } 688 getAlgorithmFromPKCS8(byte[] keyData)689 private String getAlgorithmFromPKCS8(byte[] keyData) { 690 try { 691 final ASN1InputStream bIn = new ASN1InputStream(new ByteArrayInputStream(keyData)); 692 final PrivateKeyInfo pki = PrivateKeyInfo.getInstance(bIn.readObject()); 693 final String algOid = pki.getPrivateKeyAlgorithm().getAlgorithm().getId(); 694 return new AlgorithmId(new ObjectIdentifier(algOid)).getName(); 695 } catch (IOException e) { 696 Log.e(TAG, "getAlgorithmFromPKCS8 Failed to parse key data"); 697 Log.e(TAG, Log.getStackTraceString(e)); 698 return null; 699 } 700 } 701 makeLegacyArguments(String algorithm)702 private KeymasterArguments makeLegacyArguments(String algorithm) { 703 KeymasterArguments args = new KeymasterArguments(); 704 args.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, 705 KeyProperties.KeyAlgorithm.toKeymasterAsymmetricKeyAlgorithm(algorithm)); 706 args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_SIGN); 707 args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_VERIFY); 708 args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_ENCRYPT); 709 args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_DECRYPT); 710 args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_NONE); 711 if (algorithm.equalsIgnoreCase(KeyProperties.KEY_ALGORITHM_RSA)) { 712 args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_RSA_OAEP); 713 args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_ENCRYPT); 714 args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_SIGN); 715 args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_RSA_PSS); 716 } 717 args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_NONE); 718 args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_MD5); 719 args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA1); 720 args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA_2_224); 721 args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA_2_256); 722 args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA_2_384); 723 args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA_2_512); 724 args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED); 725 args.addDate(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME, new Date(Long.MAX_VALUE)); 726 args.addDate(KeymasterDefs.KM_TAG_USAGE_EXPIRE_DATETIME, new Date(Long.MAX_VALUE)); 727 args.addDate(KeymasterDefs.KM_TAG_ACTIVE_DATETIME, new Date(0)); 728 return args; 729 } 730 importKey(String alias, byte[] keyData, int uid, int flags)731 public boolean importKey(String alias, byte[] keyData, int uid, int flags) { 732 String algorithm = getAlgorithmFromPKCS8(keyData); 733 if (algorithm == null) return false; 734 KeymasterArguments args = makeLegacyArguments(algorithm); 735 KeyCharacteristics out = new KeyCharacteristics(); 736 int result = importKey(alias, args, KeymasterDefs.KM_KEY_FORMAT_PKCS8, keyData, uid, 737 flags, out); 738 if (result != NO_ERROR) { 739 Log.e(TAG, Log.getStackTraceString( 740 new KeyStoreException(result, "legacy key import failed"))); 741 return false; 742 } 743 return true; 744 } 745 importWrappedKeyInternal(String wrappedKeyAlias, byte[] wrappedKey, String wrappingKeyAlias, byte[] maskingKey, KeymasterArguments args, long rootSid, long fingerprintSid, KeyCharacteristics outCharacteristics)746 private int importWrappedKeyInternal(String wrappedKeyAlias, byte[] wrappedKey, 747 String wrappingKeyAlias, 748 byte[] maskingKey, KeymasterArguments args, long rootSid, long fingerprintSid, 749 KeyCharacteristics outCharacteristics) 750 throws RemoteException, ExecutionException { 751 KeyCharacteristicsPromise promise = new KeyCharacteristicsPromise(); 752 mBinder.asBinder().linkToDeath(promise, 0); 753 try { 754 int error = mBinder.importWrappedKey(promise, wrappedKeyAlias, wrappedKey, 755 wrappingKeyAlias, maskingKey, args, rootSid, fingerprintSid); 756 if (error != NO_ERROR) return error; 757 758 KeyCharacteristicsCallbackResult result = interruptedPreservingGet(promise.getFuture()); 759 760 error = result.getKeystoreResponse().getErrorCode(); 761 if (error != NO_ERROR) return error; 762 763 KeyCharacteristics characteristics = result.getKeyCharacteristics(); 764 if (characteristics == null) return SYSTEM_ERROR; 765 outCharacteristics.shallowCopyFrom(characteristics); 766 return NO_ERROR; 767 } finally { 768 mBinder.asBinder().unlinkToDeath(promise, 0); 769 } 770 } 771 importWrappedKey(String wrappedKeyAlias, byte[] wrappedKey, String wrappingKeyAlias, byte[] maskingKey, KeymasterArguments args, long rootSid, long fingerprintSid, int uid, KeyCharacteristics outCharacteristics)772 public int importWrappedKey(String wrappedKeyAlias, byte[] wrappedKey, 773 String wrappingKeyAlias, 774 byte[] maskingKey, KeymasterArguments args, long rootSid, long fingerprintSid, int uid, 775 KeyCharacteristics outCharacteristics) { 776 // TODO b/119217337 uid parameter gets silently ignored. 777 try { 778 int error = importWrappedKeyInternal(wrappedKeyAlias, wrappedKey, wrappingKeyAlias, 779 maskingKey, args, rootSid, fingerprintSid, outCharacteristics); 780 if (error == KEY_ALREADY_EXISTS) { 781 mBinder.del(wrappedKeyAlias, UID_SELF); 782 error = importWrappedKeyInternal(wrappedKeyAlias, wrappedKey, wrappingKeyAlias, 783 maskingKey, args, rootSid, fingerprintSid, outCharacteristics); 784 } 785 return error; 786 } catch (RemoteException e) { 787 Log.w(TAG, "Cannot connect to keystore", e); 788 return SYSTEM_ERROR; 789 } catch (ExecutionException e) { 790 Log.e(TAG, "ImportWrappedKey completed with exception", e); 791 return SYSTEM_ERROR; 792 } 793 } 794 795 private class ExportKeyPromise 796 extends android.security.keystore.IKeystoreExportKeyCallback.Stub 797 implements IBinder.DeathRecipient { 798 final private CompletableFuture<ExportResult> future = new CompletableFuture<ExportResult>(); 799 @Override onFinished(ExportResult exportKeyResult)800 public void onFinished(ExportResult exportKeyResult) throws android.os.RemoteException { 801 future.complete(exportKeyResult); 802 } getFuture()803 public final CompletableFuture<ExportResult> getFuture() { 804 return future; 805 } 806 @Override binderDied()807 public void binderDied() { 808 future.completeExceptionally(new RemoteException("Keystore died")); 809 } 810 }; 811 exportKey(String alias, int format, KeymasterBlob clientId, KeymasterBlob appId, int uid)812 public ExportResult exportKey(String alias, int format, KeymasterBlob clientId, 813 KeymasterBlob appId, int uid) { 814 ExportKeyPromise promise = new ExportKeyPromise(); 815 try { 816 mBinder.asBinder().linkToDeath(promise, 0); 817 clientId = clientId != null ? clientId : new KeymasterBlob(new byte[0]); 818 appId = appId != null ? appId : new KeymasterBlob(new byte[0]); 819 int error = mBinder.exportKey(promise, alias, format, clientId, appId, uid); 820 if (error == NO_ERROR) { 821 return interruptedPreservingGet(promise.getFuture()); 822 } else { 823 return new ExportResult(error); 824 } 825 } catch (RemoteException e) { 826 Log.w(TAG, "Cannot connect to keystore", e); 827 return null; 828 } catch (ExecutionException e) { 829 Log.e(TAG, "ExportKey completed with exception", e); 830 return null; 831 } finally { 832 mBinder.asBinder().unlinkToDeath(promise, 0); 833 } 834 } exportKey(String alias, int format, KeymasterBlob clientId, KeymasterBlob appId)835 public ExportResult exportKey(String alias, int format, KeymasterBlob clientId, 836 KeymasterBlob appId) { 837 return exportKey(alias, format, clientId, appId, UID_SELF); 838 } 839 840 private class OperationPromise 841 extends android.security.keystore.IKeystoreOperationResultCallback.Stub 842 implements IBinder.DeathRecipient { 843 final private CompletableFuture<OperationResult> future = new CompletableFuture<OperationResult>(); 844 @Override onFinished(OperationResult operationResult)845 public void onFinished(OperationResult operationResult) throws android.os.RemoteException { 846 future.complete(operationResult); 847 } getFuture()848 public final CompletableFuture<OperationResult> getFuture() { 849 return future; 850 } 851 @Override binderDied()852 public void binderDied() { 853 future.completeExceptionally(new RemoteException("Keystore died")); 854 } 855 }; 856 begin(String alias, int purpose, boolean pruneable, KeymasterArguments args, byte[] entropy, int uid)857 public OperationResult begin(String alias, int purpose, boolean pruneable, 858 KeymasterArguments args, byte[] entropy, int uid) { 859 OperationPromise promise = new OperationPromise(); 860 try { 861 mBinder.asBinder().linkToDeath(promise, 0); 862 args = args != null ? args : new KeymasterArguments(); 863 entropy = entropy != null ? entropy : new byte[0]; 864 int errorCode = mBinder.begin(promise, getToken(), alias, purpose, pruneable, args, 865 entropy, uid); 866 if (errorCode == NO_ERROR) { 867 return interruptedPreservingGet(promise.getFuture()); 868 } else { 869 return new OperationResult(errorCode); 870 } 871 } catch (RemoteException e) { 872 Log.w(TAG, "Cannot connect to keystore", e); 873 return null; 874 } catch (ExecutionException e) { 875 Log.e(TAG, "Begin completed with exception", e); 876 return null; 877 } finally { 878 mBinder.asBinder().unlinkToDeath(promise, 0); 879 } 880 } 881 begin(String alias, int purpose, boolean pruneable, KeymasterArguments args, byte[] entropy)882 public OperationResult begin(String alias, int purpose, boolean pruneable, 883 KeymasterArguments args, byte[] entropy) { 884 entropy = entropy != null ? entropy : new byte[0]; 885 args = args != null ? args : new KeymasterArguments(); 886 return begin(alias, purpose, pruneable, args, entropy, UID_SELF); 887 } 888 update(IBinder token, KeymasterArguments arguments, byte[] input)889 public OperationResult update(IBinder token, KeymasterArguments arguments, byte[] input) { 890 OperationPromise promise = new OperationPromise(); 891 try { 892 mBinder.asBinder().linkToDeath(promise, 0); 893 arguments = arguments != null ? arguments : new KeymasterArguments(); 894 input = input != null ? input : new byte[0]; 895 int errorCode = mBinder.update(promise, token, arguments, input); 896 if (errorCode == NO_ERROR) { 897 return interruptedPreservingGet(promise.getFuture()); 898 } else { 899 return new OperationResult(errorCode); 900 } 901 } catch (RemoteException e) { 902 Log.w(TAG, "Cannot connect to keystore", e); 903 return null; 904 } catch (ExecutionException e) { 905 Log.e(TAG, "Update completed with exception", e); 906 return null; 907 } finally { 908 mBinder.asBinder().unlinkToDeath(promise, 0); 909 } 910 } 911 912 /** 913 * Android KeyStore finish operation. 914 * 915 * @param token Authentication token. 916 * @param arguments Keymaster arguments 917 * @param input Optional additional input data. 918 * @param signature Optional signature to be verified. 919 * @param entropy Optional additional entropy 920 * @return OperationResult that will indicate success or error of the operation. 921 */ finish(IBinder token, KeymasterArguments arguments, byte[] input, byte[] signature, byte[] entropy)922 public OperationResult finish(IBinder token, KeymasterArguments arguments, byte[] input, 923 byte[] signature, byte[] entropy) { 924 OperationPromise promise = new OperationPromise(); 925 try { 926 mBinder.asBinder().linkToDeath(promise, 0); 927 arguments = arguments != null ? arguments : new KeymasterArguments(); 928 entropy = entropy != null ? entropy : new byte[0]; 929 input = input != null ? input : new byte[0]; 930 signature = signature != null ? signature : new byte[0]; 931 int errorCode = mBinder.finish(promise, token, arguments, input, signature, entropy); 932 if (errorCode == NO_ERROR) { 933 return interruptedPreservingGet(promise.getFuture()); 934 } else { 935 return new OperationResult(errorCode); 936 } 937 } catch (RemoteException e) { 938 Log.w(TAG, "Cannot connect to keystore", e); 939 return null; 940 } catch (ExecutionException e) { 941 Log.e(TAG, "Finish completed with exception", e); 942 return null; 943 } finally { 944 mBinder.asBinder().unlinkToDeath(promise, 0); 945 } 946 } 947 finish(IBinder token, KeymasterArguments arguments, byte[] signature)948 public OperationResult finish(IBinder token, KeymasterArguments arguments, byte[] signature) { 949 return finish(token, arguments, null, signature, null); 950 } 951 952 private class KeystoreResultPromise 953 extends android.security.keystore.IKeystoreResponseCallback.Stub 954 implements IBinder.DeathRecipient { 955 final private CompletableFuture<KeystoreResponse> future = new CompletableFuture<KeystoreResponse>(); 956 @Override onFinished(KeystoreResponse keystoreResponse)957 public void onFinished(KeystoreResponse keystoreResponse) throws android.os.RemoteException { 958 future.complete(keystoreResponse); 959 } getFuture()960 public final CompletableFuture<KeystoreResponse> getFuture() { 961 return future; 962 } 963 @Override binderDied()964 public void binderDied() { 965 future.completeExceptionally(new RemoteException("Keystore died")); 966 } 967 }; 968 abort(IBinder token)969 public int abort(IBinder token) { 970 KeystoreResultPromise promise = new KeystoreResultPromise(); 971 try { 972 mBinder.asBinder().linkToDeath(promise, 0); 973 int errorCode = mBinder.abort(promise, token); 974 if (errorCode == NO_ERROR) { 975 return interruptedPreservingGet(promise.getFuture()).getErrorCode(); 976 } else { 977 return errorCode; 978 } 979 } catch (RemoteException e) { 980 Log.w(TAG, "Cannot connect to keystore", e); 981 return SYSTEM_ERROR; 982 } catch (ExecutionException e) { 983 Log.e(TAG, "Abort completed with exception", e); 984 return SYSTEM_ERROR; 985 } finally { 986 mBinder.asBinder().unlinkToDeath(promise, 0); 987 } 988 } 989 990 /** 991 * Add an authentication record to the keystore authorization table. 992 * 993 * @param authToken The packed bytes of a hw_auth_token_t to be provided to keymaster. 994 * @return {@code KeyStore.NO_ERROR} on success, otherwise an error value corresponding to 995 * a {@code KeymasterDefs.KM_ERROR_} value or {@code KeyStore} ResponseCode. 996 */ addAuthToken(byte[] authToken)997 public int addAuthToken(byte[] authToken) { 998 try { 999 return mBinder.addAuthToken(authToken); 1000 } catch (RemoteException e) { 1001 Log.w(TAG, "Cannot connect to keystore", e); 1002 return SYSTEM_ERROR; 1003 } 1004 } 1005 1006 /** 1007 * Notify keystore that a user's password has changed. 1008 * 1009 * @param userId the user whose password changed. 1010 * @param newPassword the new password or "" if the password was removed. 1011 */ onUserPasswordChanged(int userId, String newPassword)1012 public boolean onUserPasswordChanged(int userId, String newPassword) { 1013 // Parcel.cpp doesn't support deserializing null strings and treats them as "". Make that 1014 // explicit here. 1015 if (newPassword == null) { 1016 newPassword = ""; 1017 } 1018 try { 1019 return mBinder.onUserPasswordChanged(userId, newPassword) == NO_ERROR; 1020 } catch (RemoteException e) { 1021 Log.w(TAG, "Cannot connect to keystore", e); 1022 return false; 1023 } 1024 } 1025 1026 /** 1027 * Notify keystore that a user was added. 1028 * 1029 * @param userId the new user. 1030 * @param parentId the parent of the new user, or -1 if the user has no parent. If parentId is 1031 * specified then the new user's keystore will be intialized with the same secure lockscreen 1032 * password as the parent. 1033 */ onUserAdded(int userId, int parentId)1034 public void onUserAdded(int userId, int parentId) { 1035 try { 1036 mBinder.onUserAdded(userId, parentId); 1037 } catch (RemoteException e) { 1038 Log.w(TAG, "Cannot connect to keystore", e); 1039 } 1040 } 1041 1042 /** 1043 * Notify keystore that a user was added. 1044 * 1045 * @param userId the new user. 1046 */ onUserAdded(int userId)1047 public void onUserAdded(int userId) { 1048 onUserAdded(userId, -1); 1049 } 1050 1051 /** 1052 * Notify keystore that a user was removed. 1053 * 1054 * @param userId the removed user. 1055 */ onUserRemoved(int userId)1056 public void onUserRemoved(int userId) { 1057 try { 1058 mBinder.onUserRemoved(userId); 1059 } catch (RemoteException e) { 1060 Log.w(TAG, "Cannot connect to keystore", e); 1061 } 1062 } 1063 onUserPasswordChanged(String newPassword)1064 public boolean onUserPasswordChanged(String newPassword) { 1065 return onUserPasswordChanged(UserHandle.getUserId(Process.myUid()), newPassword); 1066 } 1067 1068 /** 1069 * Notify keystore about the latest user locked state. This is to support keyguard-bound key. 1070 */ onUserLockedStateChanged(int userHandle, boolean locked)1071 public void onUserLockedStateChanged(int userHandle, boolean locked) { 1072 try { 1073 mBinder.onKeyguardVisibilityChanged(locked, userHandle); 1074 } catch (RemoteException e) { 1075 Log.w(TAG, "Failed to update user locked state " + userHandle, e); 1076 } 1077 } 1078 1079 private class KeyAttestationCallbackResult { 1080 private KeystoreResponse keystoreResponse; 1081 private KeymasterCertificateChain certificateChain; 1082 KeyAttestationCallbackResult(KeystoreResponse keystoreResponse, KeymasterCertificateChain certificateChain)1083 public KeyAttestationCallbackResult(KeystoreResponse keystoreResponse, 1084 KeymasterCertificateChain certificateChain) { 1085 this.keystoreResponse = keystoreResponse; 1086 this.certificateChain = certificateChain; 1087 } 1088 getKeystoreResponse()1089 public KeystoreResponse getKeystoreResponse() { 1090 return keystoreResponse; 1091 } 1092 setKeystoreResponse(KeystoreResponse keystoreResponse)1093 public void setKeystoreResponse(KeystoreResponse keystoreResponse) { 1094 this.keystoreResponse = keystoreResponse; 1095 } 1096 getCertificateChain()1097 public KeymasterCertificateChain getCertificateChain() { 1098 return certificateChain; 1099 } 1100 setCertificateChain(KeymasterCertificateChain certificateChain)1101 public void setCertificateChain(KeymasterCertificateChain certificateChain) { 1102 this.certificateChain = certificateChain; 1103 } 1104 } 1105 1106 private class CertificateChainPromise 1107 extends android.security.keystore.IKeystoreCertificateChainCallback.Stub 1108 implements IBinder.DeathRecipient { 1109 final private CompletableFuture<KeyAttestationCallbackResult> future = new CompletableFuture<KeyAttestationCallbackResult>(); 1110 @Override onFinished(KeystoreResponse keystoreResponse, KeymasterCertificateChain certificateChain)1111 public void onFinished(KeystoreResponse keystoreResponse, 1112 KeymasterCertificateChain certificateChain) throws android.os.RemoteException { 1113 future.complete(new KeyAttestationCallbackResult(keystoreResponse, certificateChain)); 1114 } getFuture()1115 public final CompletableFuture<KeyAttestationCallbackResult> getFuture() { 1116 return future; 1117 } 1118 @Override binderDied()1119 public void binderDied() { 1120 future.completeExceptionally(new RemoteException("Keystore died")); 1121 } 1122 }; 1123 1124 attestKey( String alias, KeymasterArguments params, KeymasterCertificateChain outChain)1125 public int attestKey( 1126 String alias, KeymasterArguments params, KeymasterCertificateChain outChain) { 1127 CertificateChainPromise promise = new CertificateChainPromise(); 1128 try { 1129 mBinder.asBinder().linkToDeath(promise, 0); 1130 if (params == null) { 1131 params = new KeymasterArguments(); 1132 } 1133 if (outChain == null) { 1134 outChain = new KeymasterCertificateChain(); 1135 } 1136 int error = mBinder.attestKey(promise, alias, params); 1137 if (error != NO_ERROR) return error; 1138 KeyAttestationCallbackResult result = interruptedPreservingGet(promise.getFuture()); 1139 error = result.getKeystoreResponse().getErrorCode(); 1140 if (error == NO_ERROR) { 1141 outChain.shallowCopyFrom(result.getCertificateChain()); 1142 } 1143 return error; 1144 } catch (RemoteException e) { 1145 Log.w(TAG, "Cannot connect to keystore", e); 1146 return SYSTEM_ERROR; 1147 } catch (ExecutionException e) { 1148 Log.e(TAG, "AttestKey completed with exception", e); 1149 return SYSTEM_ERROR; 1150 } finally { 1151 mBinder.asBinder().unlinkToDeath(promise, 0); 1152 } 1153 } 1154 attestDeviceIds(KeymasterArguments params, KeymasterCertificateChain outChain)1155 public int attestDeviceIds(KeymasterArguments params, KeymasterCertificateChain outChain) { 1156 CertificateChainPromise promise = new CertificateChainPromise(); 1157 try { 1158 mBinder.asBinder().linkToDeath(promise, 0); 1159 if (params == null) { 1160 params = new KeymasterArguments(); 1161 } 1162 if (outChain == null) { 1163 outChain = new KeymasterCertificateChain(); 1164 } 1165 int error = mBinder.attestDeviceIds(promise, params); 1166 if (error != NO_ERROR) return error; 1167 KeyAttestationCallbackResult result = interruptedPreservingGet(promise.getFuture()); 1168 error = result.getKeystoreResponse().getErrorCode(); 1169 if (error == NO_ERROR) { 1170 outChain.shallowCopyFrom(result.getCertificateChain()); 1171 } 1172 return error; 1173 } catch (RemoteException e) { 1174 Log.w(TAG, "Cannot connect to keystore", e); 1175 return SYSTEM_ERROR; 1176 } catch (ExecutionException e) { 1177 Log.e(TAG, "AttestDevicdeIds completed with exception", e); 1178 return SYSTEM_ERROR; 1179 } finally { 1180 mBinder.asBinder().unlinkToDeath(promise, 0); 1181 } 1182 } 1183 1184 /** 1185 * Notify keystore that the device went off-body. 1186 */ onDeviceOffBody()1187 public void onDeviceOffBody() { 1188 try { 1189 mBinder.onDeviceOffBody(); 1190 } catch (RemoteException e) { 1191 Log.w(TAG, "Cannot connect to keystore", e); 1192 } 1193 } 1194 1195 // Keep in sync with confirmationui/1.0/types.hal. 1196 public static final int CONFIRMATIONUI_OK = 0; 1197 public static final int CONFIRMATIONUI_CANCELED = 1; 1198 public static final int CONFIRMATIONUI_ABORTED = 2; 1199 public static final int CONFIRMATIONUI_OPERATION_PENDING = 3; 1200 public static final int CONFIRMATIONUI_IGNORED = 4; 1201 public static final int CONFIRMATIONUI_SYSTEM_ERROR = 5; 1202 public static final int CONFIRMATIONUI_UNIMPLEMENTED = 6; 1203 public static final int CONFIRMATIONUI_UNEXPECTED = 7; 1204 public static final int CONFIRMATIONUI_UIERROR = 0x10000; 1205 public static final int CONFIRMATIONUI_UIERROR_MISSING_GLYPH = 0x10001; 1206 public static final int CONFIRMATIONUI_UIERROR_MESSAGE_TOO_LONG = 0x10002; 1207 public static final int CONFIRMATIONUI_UIERROR_MALFORMED_UTF8_ENCODING = 0x10003; 1208 1209 /** 1210 * Requests keystore call into the confirmationui HAL to display a prompt. 1211 * 1212 * @param listener the binder to use for callbacks. 1213 * @param promptText the prompt to display. 1214 * @param extraData extra data / nonce from application. 1215 * @param locale the locale as a BCP 47 langauge tag. 1216 * @param uiOptionsAsFlags the UI options to use, as flags. 1217 * @return one of the {@code CONFIRMATIONUI_*} constants, for 1218 * example {@code KeyStore.CONFIRMATIONUI_OK}. 1219 */ presentConfirmationPrompt(IBinder listener, String promptText, byte[] extraData, String locale, int uiOptionsAsFlags)1220 public int presentConfirmationPrompt(IBinder listener, String promptText, byte[] extraData, 1221 String locale, int uiOptionsAsFlags) { 1222 try { 1223 return mBinder.presentConfirmationPrompt(listener, promptText, extraData, locale, 1224 uiOptionsAsFlags); 1225 } catch (RemoteException e) { 1226 Log.w(TAG, "Cannot connect to keystore", e); 1227 return CONFIRMATIONUI_SYSTEM_ERROR; 1228 } 1229 } 1230 1231 /** 1232 * Requests keystore call into the confirmationui HAL to cancel displaying a prompt. 1233 * 1234 * @param listener the binder passed to the {@link #presentConfirmationPrompt} method. 1235 * @return one of the {@code CONFIRMATIONUI_*} constants, for 1236 * example {@code KeyStore.CONFIRMATIONUI_OK}. 1237 */ cancelConfirmationPrompt(IBinder listener)1238 public int cancelConfirmationPrompt(IBinder listener) { 1239 try { 1240 return mBinder.cancelConfirmationPrompt(listener); 1241 } catch (RemoteException e) { 1242 Log.w(TAG, "Cannot connect to keystore", e); 1243 return CONFIRMATIONUI_SYSTEM_ERROR; 1244 } 1245 } 1246 1247 /** 1248 * Requests keystore to check if the confirmationui HAL is available. 1249 * 1250 * @return whether the confirmationUI HAL is available. 1251 */ isConfirmationPromptSupported()1252 public boolean isConfirmationPromptSupported() { 1253 try { 1254 return mBinder.isConfirmationPromptSupported(); 1255 } catch (RemoteException e) { 1256 Log.w(TAG, "Cannot connect to keystore", e); 1257 return false; 1258 } 1259 } 1260 1261 /** 1262 * Returns a {@link KeyStoreException} corresponding to the provided keystore/keymaster error 1263 * code. 1264 */ 1265 @UnsupportedAppUsage getKeyStoreException(int errorCode)1266 public static KeyStoreException getKeyStoreException(int errorCode) { 1267 if (errorCode > 0) { 1268 // KeyStore layer error 1269 switch (errorCode) { 1270 case NO_ERROR: 1271 return new KeyStoreException(errorCode, "OK"); 1272 case LOCKED: 1273 return new KeyStoreException(errorCode, "User authentication required"); 1274 case UNINITIALIZED: 1275 return new KeyStoreException(errorCode, "Keystore not initialized"); 1276 case SYSTEM_ERROR: 1277 return new KeyStoreException(errorCode, "System error"); 1278 case PERMISSION_DENIED: 1279 return new KeyStoreException(errorCode, "Permission denied"); 1280 case KEY_NOT_FOUND: 1281 return new KeyStoreException(errorCode, "Key not found"); 1282 case VALUE_CORRUPTED: 1283 return new KeyStoreException(errorCode, "Key blob corrupted"); 1284 case OP_AUTH_NEEDED: 1285 return new KeyStoreException(errorCode, "Operation requires authorization"); 1286 case KEY_PERMANENTLY_INVALIDATED: 1287 return new KeyStoreException(errorCode, "Key permanently invalidated"); 1288 default: 1289 return new KeyStoreException(errorCode, String.valueOf(errorCode)); 1290 } 1291 } else { 1292 // Keymaster layer error 1293 switch (errorCode) { 1294 case KeymasterDefs.KM_ERROR_INVALID_AUTHORIZATION_TIMEOUT: 1295 // The name of this parameter significantly differs between Keymaster and 1296 // framework APIs. Use the framework wording to make life easier for developers. 1297 return new KeyStoreException(errorCode, 1298 "Invalid user authentication validity duration"); 1299 default: 1300 return new KeyStoreException(errorCode, 1301 KeymasterDefs.getErrorMessage(errorCode)); 1302 } 1303 } 1304 } 1305 1306 /** 1307 * Returns an {@link InvalidKeyException} corresponding to the provided 1308 * {@link KeyStoreException}. 1309 */ getInvalidKeyException( String keystoreKeyAlias, int uid, KeyStoreException e)1310 public InvalidKeyException getInvalidKeyException( 1311 String keystoreKeyAlias, int uid, KeyStoreException e) { 1312 switch (e.getErrorCode()) { 1313 case LOCKED: 1314 return new UserNotAuthenticatedException(); 1315 case KeymasterDefs.KM_ERROR_KEY_EXPIRED: 1316 return new KeyExpiredException(); 1317 case KeymasterDefs.KM_ERROR_KEY_NOT_YET_VALID: 1318 return new KeyNotYetValidException(); 1319 case KeymasterDefs.KM_ERROR_KEY_USER_NOT_AUTHENTICATED: 1320 case OP_AUTH_NEEDED: 1321 { 1322 // We now need to determine whether the key/operation can become usable if user 1323 // authentication is performed, or whether it can never become usable again. 1324 // User authentication requirements are contained in the key's characteristics. We 1325 // need to check whether these requirements can be be satisfied by asking the user 1326 // to authenticate. 1327 KeyCharacteristics keyCharacteristics = new KeyCharacteristics(); 1328 int getKeyCharacteristicsErrorCode = 1329 getKeyCharacteristics(keystoreKeyAlias, null, null, uid, 1330 keyCharacteristics); 1331 if (getKeyCharacteristicsErrorCode != NO_ERROR) { 1332 return new InvalidKeyException( 1333 "Failed to obtained key characteristics", 1334 getKeyStoreException(getKeyCharacteristicsErrorCode)); 1335 } 1336 List<BigInteger> keySids = 1337 keyCharacteristics.getUnsignedLongs(KeymasterDefs.KM_TAG_USER_SECURE_ID); 1338 if (keySids.isEmpty()) { 1339 // Key is not bound to any SIDs -- no amount of authentication will help here. 1340 return new KeyPermanentlyInvalidatedException(); 1341 } 1342 long rootSid = GateKeeper.getSecureUserId(); 1343 if ((rootSid != 0) && (keySids.contains(KeymasterArguments.toUint64(rootSid)))) { 1344 // One of the key's SIDs is the current root SID -- user can be authenticated 1345 // against that SID. 1346 return new UserNotAuthenticatedException(); 1347 } 1348 1349 final BiometricManager bm = mContext.getSystemService(BiometricManager.class); 1350 long[] biometricSids = bm.getAuthenticatorIds(); 1351 1352 // The key must contain every biometric SID. This is because the current API surface 1353 // treats all biometrics (capable of keystore integration) equally. e.g. if the 1354 // device has multiple keystore-capable sensors, and one of the sensor's SIDs 1355 // changed, 1) there is no way for a developer to specify authentication with a 1356 // specific sensor (the one that hasn't changed), and 2) currently the only 1357 // signal to developers is the UserNotAuthenticatedException, which doesn't 1358 // indicate a specific sensor. 1359 boolean canUnlockViaBiometrics = true; 1360 for (long sid : biometricSids) { 1361 if (!keySids.contains(KeymasterArguments.toUint64(sid))) { 1362 canUnlockViaBiometrics = false; 1363 break; 1364 } 1365 } 1366 1367 if (canUnlockViaBiometrics) { 1368 // All of the biometric SIDs are contained in the key's SIDs. 1369 return new UserNotAuthenticatedException(); 1370 } 1371 1372 // None of the key's SIDs can ever be authenticated 1373 return new KeyPermanentlyInvalidatedException(); 1374 } 1375 case UNINITIALIZED: 1376 return new KeyPermanentlyInvalidatedException(); 1377 default: 1378 return new InvalidKeyException("Keystore operation failed", e); 1379 } 1380 } 1381 1382 /** 1383 * Returns an {@link InvalidKeyException} corresponding to the provided keystore/keymaster error 1384 * code. 1385 */ getInvalidKeyException(String keystoreKeyAlias, int uid, int errorCode)1386 public InvalidKeyException getInvalidKeyException(String keystoreKeyAlias, int uid, 1387 int errorCode) { 1388 return getInvalidKeyException(keystoreKeyAlias, uid, getKeyStoreException(errorCode)); 1389 } 1390 interruptedPreservingGet(CompletableFuture<R> future)1391 private static <R> R interruptedPreservingGet(CompletableFuture<R> future) 1392 throws ExecutionException { 1393 boolean wasInterrupted = false; 1394 while (true) { 1395 try { 1396 R result = future.get(); 1397 if (wasInterrupted) { 1398 Thread.currentThread().interrupt(); 1399 } 1400 return result; 1401 } catch (InterruptedException e) { 1402 wasInterrupted = true; 1403 } 1404 } 1405 } 1406 } 1407