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