1 /* 2 * Copyright (C) 2011 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 package android.security; 17 18 import static android.security.Credentials.ACTION_MANAGE_CREDENTIALS; 19 20 import android.Manifest; 21 import android.annotation.NonNull; 22 import android.annotation.Nullable; 23 import android.annotation.RequiresPermission; 24 import android.annotation.SdkConstant; 25 import android.annotation.SdkConstant.SdkConstantType; 26 import android.annotation.SystemApi; 27 import android.annotation.TestApi; 28 import android.annotation.WorkerThread; 29 import android.app.Activity; 30 import android.app.PendingIntent; 31 import android.app.Service; 32 import android.content.ComponentName; 33 import android.content.Context; 34 import android.content.Intent; 35 import android.content.ServiceConnection; 36 import android.net.Uri; 37 import android.os.Binder; 38 import android.os.Handler; 39 import android.os.IBinder; 40 import android.os.Looper; 41 import android.os.Process; 42 import android.os.RemoteException; 43 import android.os.UserHandle; 44 import android.os.UserManager; 45 import android.security.keystore.KeyPermanentlyInvalidatedException; 46 import android.security.keystore.KeyProperties; 47 import android.system.keystore2.Domain; 48 import android.system.keystore2.KeyDescriptor; 49 import android.util.Log; 50 51 import com.android.org.conscrypt.TrustedCertificateStore; 52 53 import java.io.ByteArrayInputStream; 54 import java.io.Closeable; 55 import java.io.Serializable; 56 import java.security.KeyPair; 57 import java.security.Principal; 58 import java.security.PrivateKey; 59 import java.security.UnrecoverableKeyException; 60 import java.security.cert.Certificate; 61 import java.security.cert.CertificateException; 62 import java.security.cert.CertificateFactory; 63 import java.security.cert.X509Certificate; 64 import java.util.ArrayList; 65 import java.util.Collection; 66 import java.util.List; 67 import java.util.Locale; 68 import java.util.concurrent.CountDownLatch; 69 import java.util.concurrent.atomic.AtomicReference; 70 71 import javax.security.auth.x500.X500Principal; 72 73 /** 74 * The {@code KeyChain} class provides access to private keys and 75 * their corresponding certificate chains in credential storage. 76 * 77 * <p>Applications accessing the {@code KeyChain} normally go through 78 * these steps: 79 * 80 * <ol> 81 * 82 * <li>Receive a callback from an {@link javax.net.ssl.X509KeyManager 83 * X509KeyManager} that a private key is requested. 84 * 85 * <li>Call {@link #choosePrivateKeyAlias 86 * choosePrivateKeyAlias} to allow the user to select from a 87 * list of currently available private keys and corresponding 88 * certificate chains. The chosen alias will be returned by the 89 * callback {@link KeyChainAliasCallback#alias}, or null if no private 90 * key is available or the user cancels the request. 91 * 92 * <li>Call {@link #getPrivateKey} and {@link #getCertificateChain} to 93 * retrieve the credentials to return to the corresponding {@link 94 * javax.net.ssl.X509KeyManager} callbacks. 95 * 96 * </ol> 97 * 98 * <p>An application may remember the value of a selected alias to 99 * avoid prompting the user with {@link #choosePrivateKeyAlias 100 * choosePrivateKeyAlias} on subsequent connections. If the alias is 101 * no longer valid, null will be returned on lookups using that value 102 * 103 * <p>An application can request the installation of private keys and 104 * certificates via the {@code Intent} provided by {@link 105 * #createInstallIntent}. Private keys installed via this {@code 106 * Intent} will be accessible via {@link #choosePrivateKeyAlias} while 107 * Certificate Authority (CA) certificates will be trusted by all 108 * applications through the default {@code X509TrustManager}. 109 */ 110 // TODO reference intent for credential installation when public 111 public final class KeyChain { 112 113 /** 114 * @hide 115 */ 116 public static final String LOG = "KeyChain"; 117 118 /** 119 * @hide Also used by KeyChainService implementation 120 */ 121 public static final String ACCOUNT_TYPE = "com.android.keychain"; 122 123 /** 124 * Package name for KeyChain chooser. 125 */ 126 private static final String KEYCHAIN_PACKAGE = "com.android.keychain"; 127 128 /** 129 * Action to bring up the KeyChainActivity 130 */ 131 private static final String ACTION_CHOOSER = "com.android.keychain.CHOOSER"; 132 133 /** 134 * Package name for the Certificate Installer. 135 */ 136 private static final String CERT_INSTALLER_PACKAGE = "com.android.certinstaller"; 137 138 /** 139 * Package name for Settings. 140 */ 141 private static final String SETTINGS_PACKAGE = "com.android.settings"; 142 143 /** 144 * Extra for use with {@link #ACTION_CHOOSER} 145 * @hide Also used by KeyChainActivity implementation 146 */ 147 public static final String EXTRA_RESPONSE = "response"; 148 149 /** 150 * Extra for use with {@link #ACTION_CHOOSER} 151 * @hide Also used by KeyChainActivity implementation 152 */ 153 public static final String EXTRA_URI = "uri"; 154 155 /** 156 * Extra for use with {@link #ACTION_CHOOSER} 157 * @hide Also used by KeyChainActivity implementation 158 */ 159 public static final String EXTRA_ALIAS = "alias"; 160 161 /** 162 * Extra for use with {@link #ACTION_CHOOSER} 163 * @hide Also used by KeyChainActivity implementation 164 */ 165 public static final String EXTRA_SENDER = "sender"; 166 167 /** 168 * Extra for use with {@link #ACTION_CHOOSER} 169 * @hide Also used by KeyChainActivity implementation 170 */ 171 public static final String EXTRA_KEY_TYPES = "key_types"; 172 173 /** 174 * Extra for use with {@link #ACTION_CHOOSER} 175 * @hide Also used by KeyChainActivity implementation 176 */ 177 public static final String EXTRA_ISSUERS = "issuers"; 178 179 /** 180 * Action to bring up the CertInstaller. 181 */ 182 private static final String ACTION_INSTALL = "android.credentials.INSTALL"; 183 184 /** 185 * Optional extra to specify a {@code String} credential name on 186 * the {@code Intent} returned by {@link #createInstallIntent}. 187 */ 188 // Compatible with old com.android.certinstaller.CredentialHelper.CERT_NAME_KEY 189 public static final String EXTRA_NAME = "name"; 190 191 /** 192 * Optional extra to specify an X.509 certificate to install on 193 * the {@code Intent} returned by {@link #createInstallIntent}. 194 * The extra value should be a PEM or ASN.1 DER encoded {@code 195 * byte[]}. An {@link X509Certificate} can be converted to DER 196 * encoded bytes with {@link X509Certificate#getEncoded}. 197 * 198 * <p>{@link #EXTRA_NAME} may be used to provide a default alias 199 * name for the installed certificate. 200 */ 201 // Compatible with old android.security.Credentials.CERTIFICATE 202 public static final String EXTRA_CERTIFICATE = "CERT"; 203 204 /** 205 * Optional extra for use with the {@code Intent} returned by 206 * {@link #createInstallIntent} to specify a PKCS#12 key store to 207 * install. The extra value should be a {@code byte[]}. The bytes 208 * may come from an external source or be generated with {@link 209 * java.security.KeyStore#store} on a "PKCS12" instance. 210 * 211 * <p>The user will be prompted for the password to load the key store. 212 * 213 * <p>The key store will be scanned for {@link 214 * java.security.KeyStore.PrivateKeyEntry} entries and both the 215 * private key and associated certificate chain will be installed. 216 * 217 * <p>{@link #EXTRA_NAME} may be used to provide a default alias 218 * name for the installed credentials. 219 */ 220 // Compatible with old android.security.Credentials.PKCS12 221 public static final String EXTRA_PKCS12 = "PKCS12"; 222 223 /** 224 * Extra used by {@link #createManageCredentialsIntent(AppUriAuthenticationPolicy)} to specify 225 * the authentication policy of the credential management app. 226 * 227 * <p>The authentication policy declares which alias for a private key and certificate pair 228 * should be used for authentication, given a list of apps and URIs. 229 * 230 * <p>The extra value should be a {@link AppUriAuthenticationPolicy}. 231 * 232 * @hide 233 */ 234 public static final String EXTRA_AUTHENTICATION_POLICY = 235 "android.security.extra.AUTHENTICATION_POLICY"; 236 237 /** 238 * Broadcast Action: Indicates the trusted storage has changed. Sent when 239 * one of this happens: 240 * 241 * <ul> 242 * <li>a new CA is added, 243 * <li>an existing CA is removed or disabled, 244 * <li>a disabled CA is enabled, 245 * <li>trusted storage is reset (all user certs are cleared), 246 * <li>when permission to access a private key is changed. 247 * </ul> 248 * 249 * @deprecated Use {@link #ACTION_KEYCHAIN_CHANGED}, {@link #ACTION_TRUST_STORE_CHANGED} or 250 * {@link #ACTION_KEY_ACCESS_CHANGED}. Apps that target a version higher than 251 * {@link android.os.Build.VERSION_CODES#N_MR1} will only receive this broadcast if they 252 * register for it at runtime. 253 */ 254 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 255 public static final String ACTION_STORAGE_CHANGED = "android.security.STORAGE_CHANGED"; 256 257 /** 258 * Broadcast Action: Indicates the contents of the keychain has changed. Sent when a KeyChain 259 * entry is added, modified or removed. 260 */ 261 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 262 public static final String ACTION_KEYCHAIN_CHANGED = "android.security.action.KEYCHAIN_CHANGED"; 263 264 /** 265 * Broadcast Action: Indicates the contents of the trusted certificate store has changed. Sent 266 * when one the following occurs: 267 * 268 * <ul> 269 * <li>A pre-installed CA is disabled or re-enabled</li> 270 * <li>A CA is added or removed from the trust store</li> 271 * </ul> 272 */ 273 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 274 public static final String ACTION_TRUST_STORE_CHANGED = 275 "android.security.action.TRUST_STORE_CHANGED"; 276 277 /** 278 * Broadcast Action: Indicates that the access permissions for a private key have changed. 279 * 280 */ 281 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 282 public static final String ACTION_KEY_ACCESS_CHANGED = 283 "android.security.action.KEY_ACCESS_CHANGED"; 284 285 /** 286 * Used as a String extra field in {@link #ACTION_KEY_ACCESS_CHANGED} to supply the alias of 287 * the key. 288 */ 289 public static final String EXTRA_KEY_ALIAS = "android.security.extra.KEY_ALIAS"; 290 291 /** 292 * Used as a boolean extra field in {@link #ACTION_KEY_ACCESS_CHANGED} to supply if the key is 293 * accessible to the application. 294 */ 295 public static final String EXTRA_KEY_ACCESSIBLE = "android.security.extra.KEY_ACCESSIBLE"; 296 297 /** 298 * Indicates that a call to {@link #generateKeyPair} was successful. 299 * @hide 300 */ 301 public static final int KEY_GEN_SUCCESS = 0; 302 303 /** 304 * An alias was missing from the key specifications when calling {@link #generateKeyPair}. 305 * @hide 306 */ 307 public static final int KEY_GEN_MISSING_ALIAS = 1; 308 309 /** 310 * A key attestation challenge was provided to {@link #generateKeyPair}, but it shouldn't 311 * have been provided. 312 * @hide 313 */ 314 public static final int KEY_GEN_SUPERFLUOUS_ATTESTATION_CHALLENGE = 2; 315 316 /** 317 * Algorithm not supported by {@link #generateKeyPair} 318 * @hide 319 */ 320 public static final int KEY_GEN_NO_SUCH_ALGORITHM = 3; 321 322 /** 323 * Invalid algorithm parameters when calling {@link #generateKeyPair} 324 * @hide 325 */ 326 public static final int KEY_GEN_INVALID_ALGORITHM_PARAMETERS = 4; 327 328 /** 329 * Keystore is not available when calling {@link #generateKeyPair} 330 * @hide 331 */ 332 public static final int KEY_GEN_NO_KEYSTORE_PROVIDER = 5; 333 334 /** 335 * StrongBox unavailable when calling {@link #generateKeyPair} 336 * @hide 337 */ 338 public static final int KEY_GEN_STRONGBOX_UNAVAILABLE = 6; 339 340 /** 341 * General failure while calling {@link #generateKeyPair} 342 * @hide 343 */ 344 public static final int KEY_GEN_FAILURE = 7; 345 346 /** 347 * Successful call to {@link #attestKey} 348 * @hide 349 */ 350 public static final int KEY_ATTESTATION_SUCCESS = 0; 351 352 /** 353 * Attestation challenge missing when calling {@link #attestKey} 354 * @hide 355 */ 356 public static final int KEY_ATTESTATION_MISSING_CHALLENGE = 1; 357 358 /** 359 * The caller requested Device ID attestation when calling {@link #attestKey}, but has no 360 * permissions to get device identifiers. 361 * @hide 362 */ 363 public static final int KEY_ATTESTATION_CANNOT_COLLECT_DATA = 2; 364 365 /** 366 * The underlying hardware does not support Device ID attestation or cannot attest to the 367 * identifiers that are stored on the device. This indicates permanent inability 368 * to get attestation records on the device. 369 * @hide 370 */ 371 public static final int KEY_ATTESTATION_CANNOT_ATTEST_IDS = 3; 372 373 /** 374 * General failure when calling {@link #attestKey} 375 * @hide 376 */ 377 public static final int KEY_ATTESTATION_FAILURE = 4; 378 379 /** 380 * Used by DPC or delegated app in 381 * {@link android.app.admin.DeviceAdminReceiver#onChoosePrivateKeyAlias} or 382 * {@link android.app.admin.DelegatedAdminReceiver#onChoosePrivateKeyAlias} to identify that 383 * the requesting app is not granted access to any key, and nor will the user be able to grant 384 * access manually. 385 */ 386 public static final String KEY_ALIAS_SELECTION_DENIED = 387 "android:alias-selection-denied"; 388 389 /** 390 * Returns an {@code Intent} that can be used for credential 391 * installation. The intent may be used without any extras, in 392 * which case the user will be able to install credentials from 393 * their own source. 394 * 395 * <p>Alternatively, {@link #EXTRA_CERTIFICATE} or {@link 396 * #EXTRA_PKCS12} maybe used to specify the bytes of an X.509 397 * certificate or a PKCS#12 key store for installation. These 398 * extras may be combined with {@link #EXTRA_NAME} to provide a 399 * default alias name for credentials being installed. 400 * 401 * <p>When used with {@link Activity#startActivityForResult}, 402 * {@link Activity#RESULT_OK} will be returned if a credential was 403 * successfully installed, otherwise {@link 404 * Activity#RESULT_CANCELED} will be returned. 405 * 406 * <p>Starting from {@link android.os.Build.VERSION_CODES#R}, the intent returned by this 407 * method cannot be used for installing CA certificates. Since CA certificates can only be 408 * installed via Settings, the app should provide the user with a file containing the 409 * CA certificate. One way to do this would be to use the {@link android.provider.MediaStore} 410 * API to write the certificate to the {@link android.provider.MediaStore.Downloads} 411 * collection. 412 */ 413 @NonNull createInstallIntent()414 public static Intent createInstallIntent() { 415 Intent intent = new Intent(ACTION_INSTALL); 416 intent.setClassName(CERT_INSTALLER_PACKAGE, 417 "com.android.certinstaller.CertInstallerMain"); 418 return intent; 419 } 420 421 /** 422 * Returns an {@code Intent} that should be used by an app to request to manage the user's 423 * credentials. This is limited to unmanaged devices. The authentication policy must be 424 * provided to be able to make this request successfully. 425 * 426 * <p> This intent should be started using {@link Activity#startActivityForResult(Intent, int)} 427 * to verify whether the request was successful and whether the user accepted or denied the 428 * request. If the user successfully receives and accepts the request, the result code will be 429 * {@link Activity#RESULT_OK}, otherwise the result code will be 430 * {@link Activity#RESULT_CANCELED}. 431 * 432 * <p> {@link KeyChain#isCredentialManagementApp(Context)} should be used to determine whether 433 * an app is already the credential management app. 434 * 435 * @param policy The authentication policy determines which alias for a private key and 436 * certificate pair should be used for authentication. 437 */ 438 @NonNull createManageCredentialsIntent(@onNull AppUriAuthenticationPolicy policy)439 public static Intent createManageCredentialsIntent(@NonNull AppUriAuthenticationPolicy policy) { 440 Intent intent = new Intent(ACTION_MANAGE_CREDENTIALS); 441 intent.setComponent(ComponentName.createRelative(SETTINGS_PACKAGE, 442 ".security.RequestManageCredentials")); 443 intent.putExtra(EXTRA_AUTHENTICATION_POLICY, policy); 444 return intent; 445 } 446 447 /** 448 * Launches an {@code Activity} for the user to select the alias 449 * for a private key and certificate pair for authentication. The 450 * selected alias or null will be returned via the 451 * KeyChainAliasCallback callback. 452 * 453 * <p>A device policy controller (as a device or profile owner) can 454 * intercept the request before the activity is shown, to pick a 455 * specific private key alias by implementing 456 * {@link android.app.admin.DeviceAdminReceiver#onChoosePrivateKeyAlias 457 * onChoosePrivateKeyAlias}. 458 * 459 * <p>{@code keyTypes} and {@code issuers} may be used to 460 * narrow down suggested choices to the user. If either {@code keyTypes} 461 * or {@code issuers} is specified and non-empty, and there are no 462 * matching certificates in the KeyChain, then the certificate 463 * selection prompt would be suppressed entirely. 464 * 465 * <p>{@code host} and {@code port} may be used to give the user 466 * more context about the server requesting the credentials. 467 * 468 * <p>{@code alias} allows the caller to preselect an existing 469 * alias which will still be subject to user confirmation. 470 * 471 * @param activity The {@link Activity} context to use for 472 * launching the new sub-Activity to prompt the user to select 473 * a private key; used only to call startActivity(); must not 474 * be null. 475 * @param response Callback to invoke when the request completes; 476 * must not be null. 477 * @param keyTypes The acceptable types of asymmetric keys such as 478 * "RSA", "EC" or null. 479 * @param issuers The acceptable certificate issuers for the 480 * certificate matching the private key, or null. 481 * @param host The host name of the server requesting the 482 * certificate, or null if unavailable. 483 * @param port The port number of the server requesting the 484 * certificate, or -1 if unavailable. 485 * @param alias The alias to preselect if available, or null if 486 * unavailable. 487 */ choosePrivateKeyAlias(@onNull Activity activity, @NonNull KeyChainAliasCallback response, @Nullable @KeyProperties.KeyAlgorithmEnum String[] keyTypes, @Nullable Principal[] issuers, @Nullable String host, int port, @Nullable String alias)488 public static void choosePrivateKeyAlias(@NonNull Activity activity, 489 @NonNull KeyChainAliasCallback response, 490 @Nullable @KeyProperties.KeyAlgorithmEnum String[] keyTypes, 491 @Nullable Principal[] issuers, 492 @Nullable String host, int port, @Nullable String alias) { 493 Uri uri = null; 494 if (host != null) { 495 uri = new Uri.Builder() 496 .authority(host + (port != -1 ? ":" + port : "")) 497 .build(); 498 } 499 choosePrivateKeyAlias(activity, response, keyTypes, issuers, uri, alias); 500 } 501 502 /** 503 * Launches an {@code Activity} for the user to select the alias 504 * for a private key and certificate pair for authentication. The 505 * selected alias or null will be returned via the 506 * KeyChainAliasCallback callback. 507 * 508 * <p>A device policy controller (as a device or profile owner) can 509 * intercept the request before the activity is shown, to pick a 510 * specific private key alias by implementing 511 * {@link android.app.admin.DeviceAdminReceiver#onChoosePrivateKeyAlias 512 * onChoosePrivateKeyAlias}. 513 * 514 * <p>{@code keyTypes} and {@code issuers} may be used to 515 * narrow down suggested choices to the user. If either {@code keyTypes} 516 * or {@code issuers} is specified and non-empty, and there are no 517 * matching certificates in the KeyChain, then the certificate 518 * selection prompt would be suppressed entirely. 519 * 520 * <p>{@code uri} may be used to give the user more context about 521 * the server requesting the credentials. 522 * 523 * <p>{@code alias} allows the caller to preselect an existing 524 * alias which will still be subject to user confirmation. 525 * 526 * @param activity The {@link Activity} context to use for 527 * launching the new sub-Activity to prompt the user to select 528 * a private key; used only to call startActivity(); must not 529 * be null. 530 * @param response Callback to invoke when the request completes; 531 * must not be null. 532 * @param keyTypes The acceptable types of asymmetric keys such as 533 * "RSA", "EC" or null. 534 * @param issuers The acceptable certificate issuers for the 535 * certificate matching the private key, or null. 536 * @param uri The full URI the server is requesting the certificate 537 * for, or null if unavailable. 538 * @param alias The alias to preselect if available, or null if 539 * unavailable. 540 * @throws IllegalArgumentException if the specified issuers are not 541 * of type {@code X500Principal}. 542 */ choosePrivateKeyAlias(@onNull Activity activity, @NonNull KeyChainAliasCallback response, @Nullable @KeyProperties.KeyAlgorithmEnum String[] keyTypes, @Nullable Principal[] issuers, @Nullable Uri uri, @Nullable String alias)543 public static void choosePrivateKeyAlias(@NonNull Activity activity, 544 @NonNull KeyChainAliasCallback response, 545 @Nullable @KeyProperties.KeyAlgorithmEnum String[] keyTypes, 546 @Nullable Principal[] issuers, 547 @Nullable Uri uri, @Nullable String alias) { 548 /* 549 * Specifying keyTypes excludes certificates with different key types 550 * from the list of certificates presented to the user. 551 * In practice today, most servers would require RSA or EC 552 * certificates. 553 * 554 * Specifying issuers narrows down the list by filtering out 555 * certificates with issuers which are not matching the provided ones. 556 * This has been reported to Chrome several times (crbug.com/731769). 557 * There's no concrete description on what to do when the client has no 558 * certificates that match the provided issuers. 559 * To be conservative, Android will not present the user with any 560 * certificates to choose from. 561 * If the list of issuers is empty then the client may send any 562 * certificate, see: 563 * https://tools.ietf.org/html/rfc5246#section-7.4.4 564 */ 565 if (activity == null) { 566 throw new NullPointerException("activity == null"); 567 } 568 if (response == null) { 569 throw new NullPointerException("response == null"); 570 } 571 Intent intent = new Intent(ACTION_CHOOSER); 572 intent.setPackage(KEYCHAIN_PACKAGE); 573 intent.putExtra(EXTRA_RESPONSE, new AliasResponse(response)); 574 intent.putExtra(EXTRA_URI, uri); 575 intent.putExtra(EXTRA_ALIAS, alias); 576 intent.putExtra(EXTRA_KEY_TYPES, keyTypes); 577 ArrayList<byte[]> issuersList = new ArrayList(); 578 if (issuers != null) { 579 for (Principal issuer: issuers) { 580 // In a TLS client context (like Chrome), issuers would only 581 // be specified as X500Principals. No other use cases for 582 // specifying principals have been brought up. Under these 583 // circumstances, only allow issuers specified as 584 // X500Principals. 585 if (!(issuer instanceof X500Principal)) { 586 throw new IllegalArgumentException(String.format( 587 "Issuer %s is of type %s, not X500Principal", 588 issuer.toString(), issuer.getClass())); 589 } 590 // Pass the DER-encoded issuer as that's the most accurate 591 // representation and what is sent over the wire. 592 issuersList.add(((X500Principal) issuer).getEncoded()); 593 } 594 } 595 intent.putExtra(EXTRA_ISSUERS, (Serializable) issuersList); 596 // the PendingIntent is used to get calling package name 597 intent.putExtra(EXTRA_SENDER, PendingIntent.getActivity(activity, 0, new Intent(), 598 PendingIntent.FLAG_IMMUTABLE)); 599 activity.startActivity(intent); 600 } 601 602 /** 603 * Check whether the caller is the credential management app {@code CredentialManagementApp}. 604 * The credential management app has the ability to manage the user's KeyChain credentials 605 * on unmanaged devices. 606 * 607 * <p> {@link KeyChain#createManageCredentialsIntent} should be used by an app to request to 608 * become the credential management app. The user must approve this request before the app can 609 * manage the user's credentials. There can only be one credential management on the device. 610 * 611 * @return {@code true} if the caller is the credential management app. 612 */ 613 @WorkerThread isCredentialManagementApp(@onNull Context context)614 public static boolean isCredentialManagementApp(@NonNull Context context) { 615 boolean isCredentialManagementApp = false; 616 try (KeyChainConnection keyChainConnection = KeyChain.bind(context)) { 617 isCredentialManagementApp = keyChainConnection.getService() 618 .isCredentialManagementApp(context.getPackageName()); 619 } catch (RemoteException e) { 620 e.rethrowAsRuntimeException(); 621 } catch (InterruptedException e) { 622 throw new RuntimeException("Interrupted while checking whether the caller is the " 623 + "credential management app.", e); 624 } catch (SecurityException e) { 625 isCredentialManagementApp = false; 626 } 627 return isCredentialManagementApp; 628 } 629 630 /** 631 * Called by the credential management app to get the authentication policy 632 * {@link AppUriAuthenticationPolicy}. 633 * 634 * @return the credential management app's authentication policy. 635 * @throws SecurityException if the caller is not the credential management app. 636 */ 637 @WorkerThread 638 @NonNull getCredentialManagementAppPolicy( @onNull Context context)639 public static AppUriAuthenticationPolicy getCredentialManagementAppPolicy( 640 @NonNull Context context) throws SecurityException { 641 AppUriAuthenticationPolicy policy = null; 642 try (KeyChainConnection keyChainConnection = KeyChain.bind(context)) { 643 policy = keyChainConnection.getService().getCredentialManagementAppPolicy(); 644 } catch (RemoteException e) { 645 e.rethrowAsRuntimeException(); 646 } catch (InterruptedException e) { 647 throw new RuntimeException( 648 "Interrupted while getting credential management app policy.", e); 649 } 650 return policy; 651 } 652 653 /** 654 * Set a credential management app. The credential management app has the ability to manage 655 * the user's KeyChain credentials on unmanaged devices. 656 * 657 * <p>There can only be one credential management on the device. If another app requests to 658 * become the credential management app, then the existing credential management app will 659 * no longer be able to manage credentials. 660 * 661 * @param packageName The package name of the credential management app 662 * @param authenticationPolicy The authentication policy of the credential management app. This 663 * policy determines which alias for a private key and certificate 664 * pair should be used for authentication. 665 * @return {@code true} if the credential management app was successfully added. 666 * @hide 667 */ 668 @TestApi 669 @WorkerThread 670 @RequiresPermission(Manifest.permission.MANAGE_CREDENTIAL_MANAGEMENT_APP) setCredentialManagementApp(@onNull Context context, @NonNull String packageName, @NonNull AppUriAuthenticationPolicy authenticationPolicy)671 public static boolean setCredentialManagementApp(@NonNull Context context, 672 @NonNull String packageName, @NonNull AppUriAuthenticationPolicy authenticationPolicy) { 673 try (KeyChainConnection keyChainConnection = KeyChain.bind(context)) { 674 keyChainConnection.getService() 675 .setCredentialManagementApp(packageName, authenticationPolicy); 676 return true; 677 } catch (RemoteException | InterruptedException e) { 678 Log.w(LOG, "Set credential management app failed", e); 679 Thread.currentThread().interrupt(); 680 return false; 681 } 682 } 683 684 /** 685 * Called by the credential management app {@code CredentialManagementApp} to unregister as 686 * the credential management app and stop managing the user's credentials. 687 * 688 * <p> All credentials previously installed by the credential management app will be removed 689 * from the user's device. 690 * 691 * <p> An app holding {@code MANAGE_CREDENTIAL_MANAGEMENT_APP} permission can also call this 692 * method to remove the current credential management app, even if it's not the current 693 * credential management app itself. 694 * 695 * @return {@code true} if the credential management app was successfully removed. 696 */ 697 @WorkerThread 698 @RequiresPermission(value = Manifest.permission.MANAGE_CREDENTIAL_MANAGEMENT_APP, 699 conditional = true) removeCredentialManagementApp(@onNull Context context)700 public static boolean removeCredentialManagementApp(@NonNull Context context) { 701 try (KeyChainConnection keyChainConnection = KeyChain.bind(context)) { 702 keyChainConnection.getService().removeCredentialManagementApp(); 703 return true; 704 } catch (RemoteException | InterruptedException e) { 705 Log.w(LOG, "Remove credential management app failed", e); 706 Thread.currentThread().interrupt(); 707 return false; 708 } 709 } 710 711 private static class AliasResponse extends IKeyChainAliasCallback.Stub { 712 private final KeyChainAliasCallback keyChainAliasResponse; AliasResponse(KeyChainAliasCallback keyChainAliasResponse)713 private AliasResponse(KeyChainAliasCallback keyChainAliasResponse) { 714 this.keyChainAliasResponse = keyChainAliasResponse; 715 } alias(String alias)716 @Override public void alias(String alias) { 717 keyChainAliasResponse.alias(alias); 718 } 719 } 720 721 /** 722 * Returns the {@code PrivateKey} for the requested alias, or null if the alias does not exist 723 * or the caller has no permission to access it (see note on exceptions below). 724 * 725 * <p> This method may block while waiting for a connection to another process, and must never 726 * be called from the main thread. 727 * <p> As {@link Activity} and {@link Service} contexts are short-lived and can be destroyed 728 * at any time from the main thread, it is safer to rely on a long-lived context such as one 729 * returned from {@link Context#getApplicationContext()}. 730 * 731 * <p> If the caller provides a valid alias to which it was not granted access, then the 732 * caller must invoke {@link #choosePrivateKeyAlias} again to get another valid alias 733 * or a grant to access the same alias. 734 * <p>On Android versions prior to Q, when a key associated with the specified alias is 735 * unavailable, the method will throw a {@code KeyChainException} rather than return null. 736 * If the exception's cause (as obtained by calling {@code KeyChainException.getCause()}) 737 * is a throwable of type {@code IllegalStateException} then the caller lacks a grant 738 * to access the key and certificates associated with this alias. 739 * 740 * @param alias The alias of the desired private key, typically returned via 741 * {@link KeyChainAliasCallback#alias}. 742 * @throws KeyChainException if the alias was valid but there was some problem accessing it. 743 * @throws IllegalStateException if called from the main thread. 744 */ 745 @Nullable @WorkerThread getPrivateKey(@onNull Context context, @NonNull String alias)746 public static PrivateKey getPrivateKey(@NonNull Context context, @NonNull String alias) 747 throws KeyChainException, InterruptedException { 748 KeyPair keyPair = getKeyPair(context, alias); 749 if (keyPair != null) { 750 return keyPair.getPrivate(); 751 } 752 753 return null; 754 } 755 756 /** 757 * This prefix is used to disambiguate grant aliase strings from normal key alias strings. 758 * Technically, a key alias string can use the same prefix. However, a collision does not 759 * lead to privilege escalation, because grants are access controlled in the Keystore daemon. 760 * @hide 761 */ 762 public static final String GRANT_ALIAS_PREFIX = "ks2_keychain_grant_id:"; 763 getGrantDescriptor(String keyid)764 private static KeyDescriptor getGrantDescriptor(String keyid) { 765 KeyDescriptor result = new KeyDescriptor(); 766 result.domain = Domain.GRANT; 767 result.blob = null; 768 result.alias = null; 769 try { 770 result.nspace = Long.parseUnsignedLong( 771 keyid.substring(GRANT_ALIAS_PREFIX.length()), 16 /* radix */); 772 } catch (NumberFormatException e) { 773 return null; 774 } 775 return result; 776 } 777 778 /** @hide */ getGrantString(KeyDescriptor key)779 public static String getGrantString(KeyDescriptor key) { 780 return String.format(GRANT_ALIAS_PREFIX + "%016X", key.nspace); 781 } 782 783 /** @hide */ 784 @Nullable @WorkerThread getKeyPair(@onNull Context context, @NonNull String alias)785 public static KeyPair getKeyPair(@NonNull Context context, @NonNull String alias) 786 throws KeyChainException, InterruptedException { 787 if (alias == null) { 788 throw new NullPointerException("alias == null"); 789 } 790 if (context == null) { 791 throw new NullPointerException("context == null"); 792 } 793 794 final String keyId; 795 try (KeyChainConnection keyChainConnection = bind(context.getApplicationContext())) { 796 keyId = keyChainConnection.getService().requestPrivateKey(alias); 797 } catch (RemoteException e) { 798 throw new KeyChainException(e); 799 } catch (RuntimeException e) { 800 // only certain RuntimeExceptions can be propagated across the IKeyChainService call 801 throw new KeyChainException(e); 802 } 803 804 if (keyId == null) { 805 return null; 806 } 807 808 try { 809 return android.security.keystore2.AndroidKeyStoreProvider 810 .loadAndroidKeyStoreKeyPairFromKeystore( 811 KeyStore2.getInstance(), 812 getGrantDescriptor(keyId)); 813 } catch (UnrecoverableKeyException | KeyPermanentlyInvalidatedException e) { 814 throw new KeyChainException(e); 815 } 816 } 817 818 /** 819 * Returns the {@code X509Certificate} chain for the requested alias, or null if the alias 820 * does not exist or the caller has no permission to access it (see note on exceptions 821 * in {@link #getPrivateKey}). 822 * 823 * <p> 824 * <strong>Note:</strong> If a certificate chain was explicitly specified when the alias was 825 * installed, this method will return that chain. If only the client certificate was specified 826 * at the installation time, this method will try to build a certificate chain using all 827 * available trust anchors (preinstalled and user-added). 828 * 829 * <p> This method may block while waiting for a connection to another process, and must never 830 * be called from the main thread. 831 * <p> As {@link Activity} and {@link Service} contexts are short-lived and can be destroyed 832 * at any time from the main thread, it is safer to rely on a long-lived context such as one 833 * returned from {@link Context#getApplicationContext()}. 834 * <p> In case the caller specifies an alias for which it lacks a grant, it must call 835 * {@link #choosePrivateKeyAlias} again. See {@link #getPrivateKey} for more details on 836 * coping with this scenario. 837 * 838 * @param alias The alias of the desired certificate chain, typically 839 * returned via {@link KeyChainAliasCallback#alias}. 840 * @throws KeyChainException if the alias was valid but there was some problem accessing it. 841 * @throws IllegalStateException if called from the main thread. 842 */ 843 @Nullable @WorkerThread getCertificateChain(@onNull Context context, @NonNull String alias)844 public static X509Certificate[] getCertificateChain(@NonNull Context context, 845 @NonNull String alias) throws KeyChainException, InterruptedException { 846 if (alias == null) { 847 throw new NullPointerException("alias == null"); 848 } 849 850 final byte[] certificateBytes; 851 final byte[] certChainBytes; 852 try (KeyChainConnection keyChainConnection = bind(context.getApplicationContext())) { 853 IKeyChainService keyChainService = keyChainConnection.getService(); 854 certificateBytes = keyChainService.getCertificate(alias); 855 if (certificateBytes == null) { 856 return null; 857 } 858 certChainBytes = keyChainService.getCaCertificates(alias); 859 } catch (RemoteException e) { 860 throw new KeyChainException(e); 861 } catch (RuntimeException e) { 862 // only certain RuntimeExceptions can be propagated across the IKeyChainService call 863 throw new KeyChainException(e); 864 } 865 866 try { 867 X509Certificate leafCert = toCertificate(certificateBytes); 868 // If the keypair is installed with a certificate chain by either 869 // DevicePolicyManager.installKeyPair or CertInstaller, return that chain. 870 if (certChainBytes != null && certChainBytes.length != 0) { 871 Collection<X509Certificate> chain = toCertificates(certChainBytes); 872 ArrayList<X509Certificate> fullChain = new ArrayList<>(chain.size() + 1); 873 fullChain.add(leafCert); 874 fullChain.addAll(chain); 875 return fullChain.toArray(new X509Certificate[fullChain.size()]); 876 } else { 877 // If there isn't a certificate chain, either due to a pre-existing keypair 878 // installed before N, or no chain is explicitly installed under the new logic, 879 // fall back to old behavior of constructing the chain from trusted credentials. 880 // 881 // This logic exists to maintain old behaviour for already installed keypair, at 882 // the cost of potentially returning extra certificate chain for new clients who 883 // explicitly installed only the client certificate without a chain. The latter 884 // case is actually no different from pre-N behaviour of getCertificateChain(), 885 // in that sense this change introduces no regression. Besides the returned chain 886 // is still valid so the consumer of the chain should have no problem verifying it. 887 TrustedCertificateStore store = new TrustedCertificateStore(); 888 List<X509Certificate> chain = store.getCertificateChain(leafCert); 889 return chain.toArray(new X509Certificate[chain.size()]); 890 } 891 } catch (CertificateException | RuntimeException e) { 892 throw new KeyChainException(e); 893 } 894 } 895 896 /** 897 * Returns {@code true} if the current device's {@code KeyChain} supports a 898 * specific {@code PrivateKey} type indicated by {@code algorithm} (e.g., 899 * "RSA"). 900 */ isKeyAlgorithmSupported( @onNull @eyProperties.KeyAlgorithmEnum String algorithm)901 public static boolean isKeyAlgorithmSupported( 902 @NonNull @KeyProperties.KeyAlgorithmEnum String algorithm) { 903 final String algUpper = algorithm.toUpperCase(Locale.US); 904 return KeyProperties.KEY_ALGORITHM_EC.equals(algUpper) 905 || KeyProperties.KEY_ALGORITHM_RSA.equals(algUpper); 906 } 907 908 /** 909 * Returns {@code true} if the current device's {@code KeyChain} binds any 910 * {@code PrivateKey} of the given {@code algorithm} to the device once 911 * imported or generated. This can be used to tell if there is special 912 * hardware support that can be used to bind keys to the device in a way 913 * that makes it non-exportable. 914 * 915 * @deprecated Whether the key is bound to the secure hardware is known only 916 * once the key has been imported. To find out, use: 917 * <pre>{@code 918 * PrivateKey key = ...; // private key from KeyChain 919 * 920 * KeyFactory keyFactory = 921 * KeyFactory.getInstance(key.getAlgorithm(), "AndroidKeyStore"); 922 * KeyInfo keyInfo = keyFactory.getKeySpec(key, KeyInfo.class); 923 * if (keyInfo.isInsideSecureHardware()) { 924 * // The key is bound to the secure hardware of this Android 925 * }}</pre> 926 */ 927 @Deprecated isBoundKeyAlgorithm( @onNull @eyProperties.KeyAlgorithmEnum String algorithm)928 public static boolean isBoundKeyAlgorithm( 929 @NonNull @KeyProperties.KeyAlgorithmEnum String algorithm) { 930 // All supported algorithms are hardware backed. Individual keys may not be. 931 return true; 932 } 933 934 /** @hide */ 935 @NonNull toCertificate(@onNull byte[] bytes)936 public static X509Certificate toCertificate(@NonNull byte[] bytes) { 937 if (bytes == null) { 938 throw new IllegalArgumentException("bytes == null"); 939 } 940 try { 941 CertificateFactory certFactory = CertificateFactory.getInstance("X.509"); 942 Certificate cert = certFactory.generateCertificate(new ByteArrayInputStream(bytes)); 943 return (X509Certificate) cert; 944 } catch (CertificateException e) { 945 throw new AssertionError(e); 946 } 947 } 948 949 /** @hide */ 950 @NonNull toCertificates(@onNull byte[] bytes)951 public static Collection<X509Certificate> toCertificates(@NonNull byte[] bytes) { 952 if (bytes == null) { 953 throw new IllegalArgumentException("bytes == null"); 954 } 955 try { 956 CertificateFactory certFactory = CertificateFactory.getInstance("X.509"); 957 return (Collection<X509Certificate>) certFactory.generateCertificates( 958 new ByteArrayInputStream(bytes)); 959 } catch (CertificateException e) { 960 throw new AssertionError(e); 961 } 962 } 963 964 /** 965 * @hide for reuse by CertInstaller and Settings. 966 * @see KeyChain#bind 967 */ 968 public static class KeyChainConnection implements Closeable { 969 private final Context mContext; 970 private final ServiceConnection mServiceConnection; 971 private final IKeyChainService mService; KeyChainConnection(Context context, ServiceConnection serviceConnection, IKeyChainService service)972 protected KeyChainConnection(Context context, 973 ServiceConnection serviceConnection, 974 IKeyChainService service) { 975 this.mContext = context; 976 this.mServiceConnection = serviceConnection; 977 this.mService = service; 978 } close()979 @Override public void close() { 980 mContext.unbindService(mServiceConnection); 981 } 982 983 /** returns the service binder. */ getService()984 public IKeyChainService getService() { 985 return mService; 986 } 987 } 988 989 /** 990 * Bind to KeyChainService in the current user. 991 * Caller should call unbindService on the result when finished. 992 * 993 *@throws InterruptedException if interrupted during binding. 994 *@throws AssertionError if unable to bind to KeyChainService. 995 * @hide for reuse by CertInstaller and Settings. 996 */ 997 @WorkerThread bind(@onNull Context context)998 public static KeyChainConnection bind(@NonNull Context context) throws InterruptedException { 999 return bindAsUser(context, Process.myUserHandle()); 1000 } 1001 1002 /** 1003 * Bind to KeyChainService in the target user. 1004 * Caller should call unbindService on the result when finished. 1005 * 1006 * @throws InterruptedException if interrupted during binding. 1007 * @throws AssertionError if unable to bind to KeyChainService. 1008 * @hide 1009 */ 1010 @WorkerThread bindAsUser(@onNull Context context, UserHandle user)1011 public static KeyChainConnection bindAsUser(@NonNull Context context, UserHandle user) 1012 throws InterruptedException { 1013 return bindAsUser(context, null, user); 1014 } 1015 1016 /** 1017 * Returns a persistable grant string that allows WiFi stack to access the key using Keystore 1018 * SSL engine. 1019 * 1020 * @return grant string or null if key is not granted or doesn't exist. 1021 * 1022 * The key should be granted to Process.WIFI_UID. 1023 * @hide 1024 */ 1025 @SystemApi 1026 @Nullable 1027 @WorkerThread getWifiKeyGrantAsUser( @onNull Context context, @NonNull UserHandle user, @NonNull String alias)1028 public static String getWifiKeyGrantAsUser( 1029 @NonNull Context context, @NonNull UserHandle user, @NonNull String alias) { 1030 try (KeyChainConnection keyChainConnection = 1031 bindAsUser(context.getApplicationContext(), user)) { 1032 return keyChainConnection.getService().getWifiKeyGrantAsUser(alias); 1033 } catch (RemoteException | RuntimeException e) { 1034 Log.i(LOG, "Couldn't get grant for wifi", e); 1035 return null; 1036 } catch (InterruptedException e) { 1037 Thread.currentThread().interrupt(); 1038 Log.i(LOG, "Interrupted while getting grant for wifi", e); 1039 return null; 1040 } 1041 } 1042 1043 /** 1044 * Returns whether the key is granted to WiFi stack. 1045 * @hide 1046 */ 1047 @SystemApi 1048 @WorkerThread hasWifiKeyGrantAsUser( @onNull Context context, @NonNull UserHandle user, @NonNull String alias)1049 public static boolean hasWifiKeyGrantAsUser( 1050 @NonNull Context context, @NonNull UserHandle user, @NonNull String alias) { 1051 try (KeyChainConnection keyChainConnection = 1052 bindAsUser(context.getApplicationContext(), user)) { 1053 return keyChainConnection.getService().hasGrant(Process.WIFI_UID, alias); 1054 } catch (RemoteException | RuntimeException e) { 1055 Log.i(LOG, "Couldn't query grant for wifi", e); 1056 return false; 1057 } catch (InterruptedException e) { 1058 Thread.currentThread().interrupt(); 1059 Log.i(LOG, "Interrupted while querying grant for wifi", e); 1060 return false; 1061 } 1062 } 1063 1064 /** 1065 * Bind to KeyChainService in the target user. 1066 * Caller should call unbindService on the result when finished. 1067 * 1068 * @throws InterruptedException if interrupted during binding. 1069 * @throws AssertionError if unable to bind to KeyChainService. 1070 * @hide 1071 */ bindAsUser(@onNull Context context, @Nullable Handler handler, UserHandle user)1072 public static KeyChainConnection bindAsUser(@NonNull Context context, @Nullable Handler handler, 1073 UserHandle user) throws InterruptedException { 1074 1075 if (context == null) { 1076 throw new NullPointerException("context == null"); 1077 } 1078 if (handler == null) { 1079 ensureNotOnMainThread(context); 1080 } 1081 if (!UserManager.get(context).isUserUnlocked(user)) { 1082 throw new IllegalStateException("User must be unlocked"); 1083 } 1084 1085 final CountDownLatch countDownLatch = new CountDownLatch(1); 1086 final AtomicReference<IKeyChainService> keyChainService = new AtomicReference<>(); 1087 ServiceConnection keyChainServiceConnection = new ServiceConnection() { 1088 volatile boolean mConnectedAtLeastOnce = false; 1089 @Override public void onServiceConnected(ComponentName name, IBinder service) { 1090 if (!mConnectedAtLeastOnce) { 1091 mConnectedAtLeastOnce = true; 1092 keyChainService.set( 1093 IKeyChainService.Stub.asInterface(Binder.allowBlocking(service))); 1094 countDownLatch.countDown(); 1095 } 1096 } 1097 @Override public void onBindingDied(ComponentName name) { 1098 if (!mConnectedAtLeastOnce) { 1099 mConnectedAtLeastOnce = true; 1100 countDownLatch.countDown(); 1101 } 1102 } 1103 @Override public void onServiceDisconnected(ComponentName name) {} 1104 }; 1105 Intent intent = new Intent(IKeyChainService.class.getName()); 1106 ComponentName comp = intent.resolveSystemService(context.getPackageManager(), 0); 1107 if (comp == null) { 1108 throw new AssertionError("could not resolve KeyChainService"); 1109 } 1110 intent.setComponent(comp); 1111 final boolean bindSucceed; 1112 if (handler != null) { 1113 bindSucceed = context.bindServiceAsUser( 1114 intent, keyChainServiceConnection, Context.BIND_AUTO_CREATE, handler, user); 1115 } else { 1116 bindSucceed = context.bindServiceAsUser( 1117 intent, keyChainServiceConnection, Context.BIND_AUTO_CREATE, user); 1118 } 1119 if (!bindSucceed) { 1120 throw new AssertionError("could not bind to KeyChainService"); 1121 } 1122 countDownLatch.await(); 1123 IKeyChainService service = keyChainService.get(); 1124 if (service != null) { 1125 return new KeyChainConnection(context, keyChainServiceConnection, service); 1126 } else { 1127 context.unbindService(keyChainServiceConnection); 1128 throw new AssertionError("KeyChainService died while binding"); 1129 } 1130 } 1131 ensureNotOnMainThread(@onNull Context context)1132 private static void ensureNotOnMainThread(@NonNull Context context) { 1133 Looper looper = Looper.myLooper(); 1134 if (looper != null && looper == context.getMainLooper()) { 1135 throw new IllegalStateException( 1136 "calling this from your main thread can lead to deadlock"); 1137 } 1138 } 1139 } 1140