1b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom/* 2b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom * Copyright (C) 2011 The Android Open Source Project 3b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom * 4b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom * Licensed under the Apache License, Version 2.0 (the "License"); 5b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom * you may not use this file except in compliance with the License. 6b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom * You may obtain a copy of the License at 7b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom * 8b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom * http://www.apache.org/licenses/LICENSE-2.0 9b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom * 10b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom * Unless required by applicable law or agreed to in writing, software 11b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom * distributed under the License is distributed on an "AS IS" BASIS, 12b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom * See the License for the specific language governing permissions and 14b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom * limitations under the License. 15b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom */ 16b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrompackage android.security; 17b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom 1854bb1596e470144932943046ec7a99551d020ba0Alex Klyubinimport android.annotation.NonNull; 1954bb1596e470144932943046ec7a99551d020ba0Alex Klyubinimport android.annotation.Nullable; 200f3f60b576aedc78524d50da3dadada2201e63c2Jeff Sharkeyimport android.annotation.SdkConstant; 2159e3baa8ab08c4da270023540ba15268c87e0d67Robin Leeimport android.annotation.WorkerThread; 220f3f60b576aedc78524d50da3dadada2201e63c2Jeff Sharkeyimport android.annotation.SdkConstant.SdkConstantType; 23ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstromimport android.app.Activity; 2467c30dfe8e4bff11a4660ac23e8679b5deb59457Brian Carlstromimport android.app.PendingIntent; 25da23618043667e9cee680688b7413f65b400516eRobin Leeimport android.app.Service; 26b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstromimport android.content.ComponentName; 27b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstromimport android.content.Context; 28b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstromimport android.content.Intent; 29b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstromimport android.content.ServiceConnection; 3039087b1cec6a54e96ab9eafe8317952720790533Robin Leeimport android.net.Uri; 310a17db1cc5942ea000ca87bb72853de57a15ec64Jeff Sharkeyimport android.os.Binder; 32721afae8f1deb2e064d0f973ec3304a07b3e9739Chad Brubakerimport android.os.Build; 33b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstromimport android.os.IBinder; 34b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstromimport android.os.Looper; 35306fe08ce2b06671336e67a87afaa0851f0105ebRobin Leeimport android.os.Process; 36b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstromimport android.os.RemoteException; 37306fe08ce2b06671336e67a87afaa0851f0105ebRobin Leeimport android.os.UserHandle; 384a0ff7ca984d29bd34b02e54441957cad65e8b53Alex Klyubinimport android.security.keystore.AndroidKeyStoreProvider; 393f8d4d840894468f2be8a5b56ff266cef2d71c50Alex Klyubinimport android.security.keystore.KeyProperties; 403f8d4d840894468f2be8a5b56ff266cef2d71c50Alex Klyubin 41b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstromimport java.io.ByteArrayInputStream; 42d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstromimport java.io.Closeable; 4393201f545b67da15cb69830a5988810aef52c0b2Brian Carlstromimport java.security.Principal; 44b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstromimport java.security.PrivateKey; 454a0ff7ca984d29bd34b02e54441957cad65e8b53Alex Klyubinimport java.security.UnrecoverableKeyException; 46b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstromimport java.security.cert.Certificate; 47b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstromimport java.security.cert.CertificateException; 48b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstromimport java.security.cert.CertificateFactory; 49b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstromimport java.security.cert.X509Certificate; 50b43659170824dd8d753d9249fe6ccfd37c6221aeRubin Xuimport java.util.ArrayList; 51b43659170824dd8d753d9249fe6ccfd37c6221aeRubin Xuimport java.util.Collection; 52db93b78385d694402760ad63de0795f3902030d9Brian Carlstromimport java.util.List; 53b91773bce1126d28a93f73fbef18f3a79245f24eKenny Rootimport java.util.Locale; 548e9929c4d0730de4c9f01435a7cfe2db8855e24dBrian Carlstromimport java.util.concurrent.BlockingQueue; 558e9929c4d0730de4c9f01435a7cfe2db8855e24dBrian Carlstromimport java.util.concurrent.LinkedBlockingQueue; 565423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root 5712e752225aa96888358294be0d725d499a1c9f03Kenny Rootimport com.android.org.conscrypt.TrustedCertificateStore; 58b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom 59b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom/** 6093201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * The {@code KeyChain} class provides access to private keys and 6193201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * their corresponding certificate chains in credential storage. 6293201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * 6393201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * <p>Applications accessing the {@code KeyChain} normally go through 6493201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * these steps: 6593201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * 6693201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * <ol> 6793201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * 6893201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * <li>Receive a callback from an {@link javax.net.ssl.X509KeyManager 6993201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * X509KeyManager} that a private key is requested. 7093201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * 7193201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * <li>Call {@link #choosePrivateKeyAlias 7293201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * choosePrivateKeyAlias} to allow the user to select from a 7393201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * list of currently available private keys and corresponding 7493201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * certificate chains. The chosen alias will be returned by the 7593201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * callback {@link KeyChainAliasCallback#alias}, or null if no private 7693201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * key is available or the user cancels the request. 7793201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * 7893201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * <li>Call {@link #getPrivateKey} and {@link #getCertificateChain} to 7993201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * retrieve the credentials to return to the corresponding {@link 8093201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * javax.net.ssl.X509KeyManager} callbacks. 8193201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * 8293201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * </ol> 8393201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * 8493201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * <p>An application may remember the value of a selected alias to 8593201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * avoid prompting the user with {@link #choosePrivateKeyAlias 8693201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * choosePrivateKeyAlias} on subsequent connections. If the alias is 8793201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * no longer valid, null will be returned on lookups using that value 88ca43c458ad0ee8cfa7f5eabc8ba1a65ae473976bBrian Carlstrom * 89ca43c458ad0ee8cfa7f5eabc8ba1a65ae473976bBrian Carlstrom * <p>An application can request the installation of private keys and 90ca43c458ad0ee8cfa7f5eabc8ba1a65ae473976bBrian Carlstrom * certificates via the {@code Intent} provided by {@link 91ca43c458ad0ee8cfa7f5eabc8ba1a65ae473976bBrian Carlstrom * #createInstallIntent}. Private keys installed via this {@code 92ca43c458ad0ee8cfa7f5eabc8ba1a65ae473976bBrian Carlstrom * Intent} will be accessible via {@link #choosePrivateKeyAlias} while 93ca43c458ad0ee8cfa7f5eabc8ba1a65ae473976bBrian Carlstrom * Certificate Authority (CA) certificates will be trusted by all 94ca43c458ad0ee8cfa7f5eabc8ba1a65ae473976bBrian Carlstrom * applications through the default {@code X509TrustManager}. 95b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom */ 9693201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom// TODO reference intent for credential installation when public 97b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrompublic final class KeyChain { 98b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom 99b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom /** 100b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom * @hide Also used by KeyChainService implementation 101b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom */ 102b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom public static final String ACCOUNT_TYPE = "com.android.keychain"; 103b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom 104b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom /** 105a365906e670c89674fb3383b5bcb33e682910c29Kenny Root * Package name for KeyChain chooser. 106a365906e670c89674fb3383b5bcb33e682910c29Kenny Root */ 107a365906e670c89674fb3383b5bcb33e682910c29Kenny Root private static final String KEYCHAIN_PACKAGE = "com.android.keychain"; 108a365906e670c89674fb3383b5bcb33e682910c29Kenny Root 109a365906e670c89674fb3383b5bcb33e682910c29Kenny Root /** 110a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * Action to bring up the KeyChainActivity 111a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom */ 112a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom private static final String ACTION_CHOOSER = "com.android.keychain.CHOOSER"; 113a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom 114a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom /** 1151a88d834e8f7d21e714121c011fec82369a2e9f1Kenny Root * Package name for the Certificate Installer. 1161a88d834e8f7d21e714121c011fec82369a2e9f1Kenny Root */ 1171a88d834e8f7d21e714121c011fec82369a2e9f1Kenny Root private static final String CERT_INSTALLER_PACKAGE = "com.android.certinstaller"; 1181a88d834e8f7d21e714121c011fec82369a2e9f1Kenny Root 1191a88d834e8f7d21e714121c011fec82369a2e9f1Kenny Root /** 120a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * Extra for use with {@link #ACTION_CHOOSER} 121ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom * @hide Also used by KeyChainActivity implementation 122b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom */ 123ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom public static final String EXTRA_RESPONSE = "response"; 124b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom 125b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom /** 126a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * Extra for use with {@link #ACTION_CHOOSER} 12767c30dfe8e4bff11a4660ac23e8679b5deb59457Brian Carlstrom * @hide Also used by KeyChainActivity implementation 12867c30dfe8e4bff11a4660ac23e8679b5deb59457Brian Carlstrom */ 12939087b1cec6a54e96ab9eafe8317952720790533Robin Lee public static final String EXTRA_URI = "uri"; 1303798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee 1313798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee /** 1323798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee * Extra for use with {@link #ACTION_CHOOSER} 1333798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee * @hide Also used by KeyChainActivity implementation 1343798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee */ 13567c30dfe8e4bff11a4660ac23e8679b5deb59457Brian Carlstrom public static final String EXTRA_ALIAS = "alias"; 13667c30dfe8e4bff11a4660ac23e8679b5deb59457Brian Carlstrom 13767c30dfe8e4bff11a4660ac23e8679b5deb59457Brian Carlstrom /** 138a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * Extra for use with {@link #ACTION_CHOOSER} 13967c30dfe8e4bff11a4660ac23e8679b5deb59457Brian Carlstrom * @hide Also used by KeyChainActivity implementation 14067c30dfe8e4bff11a4660ac23e8679b5deb59457Brian Carlstrom */ 14167c30dfe8e4bff11a4660ac23e8679b5deb59457Brian Carlstrom public static final String EXTRA_SENDER = "sender"; 14267c30dfe8e4bff11a4660ac23e8679b5deb59457Brian Carlstrom 14367c30dfe8e4bff11a4660ac23e8679b5deb59457Brian Carlstrom /** 14493ba4fedebb78ba47c24e8472c8960ea8fdc933aSelim Gurun * Action to bring up the CertInstaller. 145a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom */ 146a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom private static final String ACTION_INSTALL = "android.credentials.INSTALL"; 147a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom 148a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom /** 149a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * Optional extra to specify a {@code String} credential name on 150a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * the {@code Intent} returned by {@link #createInstallIntent}. 151a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom */ 152a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom // Compatible with old com.android.certinstaller.CredentialHelper.CERT_NAME_KEY 153a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom public static final String EXTRA_NAME = "name"; 154a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom 155a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom /** 156a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * Optional extra to specify an X.509 certificate to install on 157a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * the {@code Intent} returned by {@link #createInstallIntent}. 158a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * The extra value should be a PEM or ASN.1 DER encoded {@code 159a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * byte[]}. An {@link X509Certificate} can be converted to DER 160a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * encoded bytes with {@link X509Certificate#getEncoded}. 161a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * 162a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * <p>{@link #EXTRA_NAME} may be used to provide a default alias 163a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * name for the installed certificate. 164a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom */ 165a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom // Compatible with old android.security.Credentials.CERTIFICATE 166a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom public static final String EXTRA_CERTIFICATE = "CERT"; 167a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom 168a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom /** 169a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * Optional extra for use with the {@code Intent} returned by 170a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * {@link #createInstallIntent} to specify a PKCS#12 key store to 171a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * install. The extra value should be a {@code byte[]}. The bytes 172a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * may come from an external source or be generated with {@link 173ca43c458ad0ee8cfa7f5eabc8ba1a65ae473976bBrian Carlstrom * java.security.KeyStore#store} on a "PKCS12" instance. 174a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * 175a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * <p>The user will be prompted for the password to load the key store. 176a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * 177a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * <p>The key store will be scanned for {@link 178a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * java.security.KeyStore.PrivateKeyEntry} entries and both the 179a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * private key and associated certificate chain will be installed. 180a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * 181a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * <p>{@link #EXTRA_NAME} may be used to provide a default alias 182a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * name for the installed credentials. 183a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom */ 184a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom // Compatible with old android.security.Credentials.PKCS12 185a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom public static final String EXTRA_PKCS12 = "PKCS12"; 186a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom 18793ba4fedebb78ba47c24e8472c8960ea8fdc933aSelim Gurun /** 18893ba4fedebb78ba47c24e8472c8960ea8fdc933aSelim Gurun * Broadcast Action: Indicates the trusted storage has changed. Sent when 18993ba4fedebb78ba47c24e8472c8960ea8fdc933aSelim Gurun * one of this happens: 19093ba4fedebb78ba47c24e8472c8960ea8fdc933aSelim Gurun * 19193ba4fedebb78ba47c24e8472c8960ea8fdc933aSelim Gurun * <ul> 19293ba4fedebb78ba47c24e8472c8960ea8fdc933aSelim Gurun * <li>a new CA is added, 19393ba4fedebb78ba47c24e8472c8960ea8fdc933aSelim Gurun * <li>an existing CA is removed or disabled, 19493ba4fedebb78ba47c24e8472c8960ea8fdc933aSelim Gurun * <li>a disabled CA is enabled, 19593ba4fedebb78ba47c24e8472c8960ea8fdc933aSelim Gurun * <li>trusted storage is reset (all user certs are cleared), 19693ba4fedebb78ba47c24e8472c8960ea8fdc933aSelim Gurun * <li>when permission to access a private key is changed. 19793ba4fedebb78ba47c24e8472c8960ea8fdc933aSelim Gurun * </ul> 1984de59ef3238c4bf4b8c994b83be2c703ffad2a5bChad Brubaker * 199dbf01c12d0b9f3fe3b3262529a97e4fe294f5eb8Chad Brubaker * @deprecated Use {@link #ACTION_KEYCHAIN_CHANGED}, {@link #ACTION_TRUST_STORE_CHANGED} or 200721afae8f1deb2e064d0f973ec3304a07b3e9739Chad Brubaker * {@link #ACTION_KEY_ACCESS_CHANGED}. Apps that target a version higher than 2018b651bf7d54f23549c8a7baa27dbed38a35465e4Chad Brubaker * {@link Build.VERSION_CODES#N_MR1} will only receive this broadcast if they register for it 2028b651bf7d54f23549c8a7baa27dbed38a35465e4Chad Brubaker * at runtime. 20393ba4fedebb78ba47c24e8472c8960ea8fdc933aSelim Gurun */ 2040f3f60b576aedc78524d50da3dadada2201e63c2Jeff Sharkey @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 20593ba4fedebb78ba47c24e8472c8960ea8fdc933aSelim Gurun public static final String ACTION_STORAGE_CHANGED = "android.security.STORAGE_CHANGED"; 20693ba4fedebb78ba47c24e8472c8960ea8fdc933aSelim Gurun 207a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom /** 2084de59ef3238c4bf4b8c994b83be2c703ffad2a5bChad Brubaker * Broadcast Action: Indicates the contents of the keychain has changed. Sent when a KeyChain 2094de59ef3238c4bf4b8c994b83be2c703ffad2a5bChad Brubaker * entry is added, modified or removed. 2104de59ef3238c4bf4b8c994b83be2c703ffad2a5bChad Brubaker */ 2110f3f60b576aedc78524d50da3dadada2201e63c2Jeff Sharkey @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 2124de59ef3238c4bf4b8c994b83be2c703ffad2a5bChad Brubaker public static final String ACTION_KEYCHAIN_CHANGED = "android.security.action.KEYCHAIN_CHANGED"; 2134de59ef3238c4bf4b8c994b83be2c703ffad2a5bChad Brubaker 2144de59ef3238c4bf4b8c994b83be2c703ffad2a5bChad Brubaker /** 2154de59ef3238c4bf4b8c994b83be2c703ffad2a5bChad Brubaker * Broadcast Action: Indicates the contents of the trusted certificate store has changed. Sent 2164de59ef3238c4bf4b8c994b83be2c703ffad2a5bChad Brubaker * when one the following occurs: 2174de59ef3238c4bf4b8c994b83be2c703ffad2a5bChad Brubaker * 2184de59ef3238c4bf4b8c994b83be2c703ffad2a5bChad Brubaker * <ul> 2194de59ef3238c4bf4b8c994b83be2c703ffad2a5bChad Brubaker * <li>A pre-installed CA is disabled or re-enabled</li> 2204de59ef3238c4bf4b8c994b83be2c703ffad2a5bChad Brubaker * <li>A CA is added or removed from the trust store</li> 2214de59ef3238c4bf4b8c994b83be2c703ffad2a5bChad Brubaker * </ul> 2224de59ef3238c4bf4b8c994b83be2c703ffad2a5bChad Brubaker */ 2230f3f60b576aedc78524d50da3dadada2201e63c2Jeff Sharkey @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 2244de59ef3238c4bf4b8c994b83be2c703ffad2a5bChad Brubaker public static final String ACTION_TRUST_STORE_CHANGED = 2254de59ef3238c4bf4b8c994b83be2c703ffad2a5bChad Brubaker "android.security.action.TRUST_STORE_CHANGED"; 2264de59ef3238c4bf4b8c994b83be2c703ffad2a5bChad Brubaker 2274de59ef3238c4bf4b8c994b83be2c703ffad2a5bChad Brubaker /** 2284de59ef3238c4bf4b8c994b83be2c703ffad2a5bChad Brubaker * Broadcast Action: Indicates that the access permissions for a private key have changed. 2294de59ef3238c4bf4b8c994b83be2c703ffad2a5bChad Brubaker * 2304de59ef3238c4bf4b8c994b83be2c703ffad2a5bChad Brubaker */ 2310f3f60b576aedc78524d50da3dadada2201e63c2Jeff Sharkey @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 2324de59ef3238c4bf4b8c994b83be2c703ffad2a5bChad Brubaker public static final String ACTION_KEY_ACCESS_CHANGED = 2334de59ef3238c4bf4b8c994b83be2c703ffad2a5bChad Brubaker "android.security.action.KEY_ACCESS_CHANGED"; 2344de59ef3238c4bf4b8c994b83be2c703ffad2a5bChad Brubaker 2354de59ef3238c4bf4b8c994b83be2c703ffad2a5bChad Brubaker /** 2364de59ef3238c4bf4b8c994b83be2c703ffad2a5bChad Brubaker * Used as a String extra field in {@link #ACTION_KEY_ACCESS_CHANGED} to supply the alias of 2374de59ef3238c4bf4b8c994b83be2c703ffad2a5bChad Brubaker * the key. 2384de59ef3238c4bf4b8c994b83be2c703ffad2a5bChad Brubaker */ 2394de59ef3238c4bf4b8c994b83be2c703ffad2a5bChad Brubaker public static final String EXTRA_KEY_ALIAS = "android.security.extra.KEY_ALIAS"; 2404de59ef3238c4bf4b8c994b83be2c703ffad2a5bChad Brubaker 2414de59ef3238c4bf4b8c994b83be2c703ffad2a5bChad Brubaker /** 2424de59ef3238c4bf4b8c994b83be2c703ffad2a5bChad Brubaker * Used as a boolean extra field in {@link #ACTION_KEY_ACCESS_CHANGED} to supply if the key is 2434de59ef3238c4bf4b8c994b83be2c703ffad2a5bChad Brubaker * accessible to the application. 2444de59ef3238c4bf4b8c994b83be2c703ffad2a5bChad Brubaker */ 2454de59ef3238c4bf4b8c994b83be2c703ffad2a5bChad Brubaker public static final String EXTRA_KEY_ACCESSIBLE = "android.security.extra.KEY_ACCESSIBLE"; 2464de59ef3238c4bf4b8c994b83be2c703ffad2a5bChad Brubaker 2474de59ef3238c4bf4b8c994b83be2c703ffad2a5bChad Brubaker /** 248a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * Returns an {@code Intent} that can be used for credential 249a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * installation. The intent may be used without any extras, in 250a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * which case the user will be able to install credentials from 251a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * their own source. 252a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * 253a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * <p>Alternatively, {@link #EXTRA_CERTIFICATE} or {@link 254a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * #EXTRA_PKCS12} maybe used to specify the bytes of an X.509 255a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * certificate or a PKCS#12 key store for installation. These 256ca43c458ad0ee8cfa7f5eabc8ba1a65ae473976bBrian Carlstrom * extras may be combined with {@link #EXTRA_NAME} to provide a 257a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * default alias name for credentials being installed. 258a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * 259a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * <p>When used with {@link Activity#startActivityForResult}, 260a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * {@link Activity#RESULT_OK} will be returned if a credential was 261a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * successfully installed, otherwise {@link 262a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * Activity#RESULT_CANCELED} will be returned. 263a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom */ 26454bb1596e470144932943046ec7a99551d020ba0Alex Klyubin @NonNull 265a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom public static Intent createInstallIntent() { 266a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom Intent intent = new Intent(ACTION_INSTALL); 2671a88d834e8f7d21e714121c011fec82369a2e9f1Kenny Root intent.setClassName(CERT_INSTALLER_PACKAGE, 268a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom "com.android.certinstaller.CertInstallerMain"); 269a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom return intent; 270a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom } 271a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom 272a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom /** 273ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom * Launches an {@code Activity} for the user to select the alias 274ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom * for a private key and certificate pair for authentication. The 275ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom * selected alias or null will be returned via the 27693201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * KeyChainAliasCallback callback. 27793201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * 2783798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee * <p>The device or profile owner can intercept this before the activity 2793798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee * is shown, to pick a specific private key alias. 2803798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee * 2813798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee * <p>{@code keyTypes} and {@code issuers} may be used to 2823798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee * highlight suggested choices to the user, although to cope with 2833798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee * sometimes erroneous values provided by servers, the user may be 2843798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee * able to override these suggestions. 2853798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee * 2863798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee * <p>{@code host} and {@code port} may be used to give the user 2873798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee * more context about the server requesting the credentials. 2883798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee * 2893798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee * <p>{@code alias} allows the chooser to preselect an existing 2903798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee * alias which will still be subject to user confirmation. 2913798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee * 2923798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee * @param activity The {@link Activity} context to use for 2933798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee * launching the new sub-Activity to prompt the user to select 2943798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee * a private key; used only to call startActivity(); must not 2953798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee * be null. 2963798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee * @param response Callback to invoke when the request completes; 2973798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee * must not be null 2983798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee * @param keyTypes The acceptable types of asymmetric keys such as 2993798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee * "RSA" or "DSA", or a null array. 3003798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee * @param issuers The acceptable certificate issuers for the 3013798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee * certificate matching the private key, or null. 3023798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee * @param host The host name of the server requesting the 3033798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee * certificate, or null if unavailable. 3043798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee * @param port The port number of the server requesting the 3053798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee * certificate, or -1 if unavailable. 3063798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee * @param alias The alias to preselect if available, or null if 3073798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee * unavailable. 3083798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee */ 30954bb1596e470144932943046ec7a99551d020ba0Alex Klyubin public static void choosePrivateKeyAlias(@NonNull Activity activity, 31054bb1596e470144932943046ec7a99551d020ba0Alex Klyubin @NonNull KeyChainAliasCallback response, 3113f8d4d840894468f2be8a5b56ff266cef2d71c50Alex Klyubin @KeyProperties.KeyAlgorithmEnum String[] keyTypes, Principal[] issuers, 31254bb1596e470144932943046ec7a99551d020ba0Alex Klyubin @Nullable String host, int port, @Nullable String alias) { 31339087b1cec6a54e96ab9eafe8317952720790533Robin Lee Uri uri = null; 31439087b1cec6a54e96ab9eafe8317952720790533Robin Lee if (host != null) { 31539087b1cec6a54e96ab9eafe8317952720790533Robin Lee uri = new Uri.Builder() 31639087b1cec6a54e96ab9eafe8317952720790533Robin Lee .authority(host + (port != -1 ? ":" + port : "")) 31739087b1cec6a54e96ab9eafe8317952720790533Robin Lee .build(); 31839087b1cec6a54e96ab9eafe8317952720790533Robin Lee } 31939087b1cec6a54e96ab9eafe8317952720790533Robin Lee choosePrivateKeyAlias(activity, response, keyTypes, issuers, uri, alias); 3203798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee } 3213798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee 3223798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee /** 3233798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee * Launches an {@code Activity} for the user to select the alias 3243798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee * for a private key and certificate pair for authentication. The 3253798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee * selected alias or null will be returned via the 3263798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee * KeyChainAliasCallback callback. 3273798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee * 3283798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee * <p>The device or profile owner can intercept this before the activity 3293798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee * is shown, to pick a specific private key alias.</p> 3303798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee * 33193201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * <p>{@code keyTypes} and {@code issuers} may be used to 33293201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * highlight suggested choices to the user, although to cope with 33393201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * sometimes erroneous values provided by servers, the user may be 33493201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * able to override these suggestions. 33593201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * 33693201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * <p>{@code host} and {@code port} may be used to give the user 33793201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * more context about the server requesting the credentials. 33893201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * 33967c30dfe8e4bff11a4660ac23e8679b5deb59457Brian Carlstrom * <p>{@code alias} allows the chooser to preselect an existing 34067c30dfe8e4bff11a4660ac23e8679b5deb59457Brian Carlstrom * alias which will still be subject to user confirmation. 34167c30dfe8e4bff11a4660ac23e8679b5deb59457Brian Carlstrom * 34293201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * @param activity The {@link Activity} context to use for 34393201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * launching the new sub-Activity to prompt the user to select 34493201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * a private key; used only to call startActivity(); must not 34593201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * be null. 34693201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * @param response Callback to invoke when the request completes; 34793201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * must not be null 34893201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * @param keyTypes The acceptable types of asymmetric keys such as 349cd2329dbfa5aef82c38ffa36a478bbaf5088af92Alex Klyubin * "EC" or "RSA", or a null array. 35093201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * @param issuers The acceptable certificate issuers for the 35193201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * certificate matching the private key, or null. 35239087b1cec6a54e96ab9eafe8317952720790533Robin Lee * @param uri The full URI the server is requesting the certificate 3533798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee * for, or null if unavailable. 35467c30dfe8e4bff11a4660ac23e8679b5deb59457Brian Carlstrom * @param alias The alias to preselect if available, or null if 35567c30dfe8e4bff11a4660ac23e8679b5deb59457Brian Carlstrom * unavailable. 356b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom */ 35754bb1596e470144932943046ec7a99551d020ba0Alex Klyubin public static void choosePrivateKeyAlias(@NonNull Activity activity, 35854bb1596e470144932943046ec7a99551d020ba0Alex Klyubin @NonNull KeyChainAliasCallback response, 3593f8d4d840894468f2be8a5b56ff266cef2d71c50Alex Klyubin @KeyProperties.KeyAlgorithmEnum String[] keyTypes, Principal[] issuers, 36039087b1cec6a54e96ab9eafe8317952720790533Robin Lee @Nullable Uri uri, @Nullable String alias) { 36193201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom /* 36267c30dfe8e4bff11a4660ac23e8679b5deb59457Brian Carlstrom * TODO currently keyTypes, issuers are unused. They are meant 36367c30dfe8e4bff11a4660ac23e8679b5deb59457Brian Carlstrom * to follow the semantics and purpose of X509KeyManager 36467c30dfe8e4bff11a4660ac23e8679b5deb59457Brian Carlstrom * method arguments. 36593201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * 36693201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * keyTypes would allow the list to be filtered and typically 36793201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * will be set correctly by the server. In practice today, 368cd2329dbfa5aef82c38ffa36a478bbaf5088af92Alex Klyubin * most all users will want only RSA or EC, and usually 36993201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * only a small number of certs will be available. 37093201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * 37193201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * issuers is typically not useful. Some servers historically 37293201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * will send the entire list of public CAs known to the 37393201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * server. Others will send none. If this is used, if there 37493201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * are no matches after applying the constraint, it should be 37593201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * ignored. 37693201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom */ 377ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom if (activity == null) { 378ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom throw new NullPointerException("activity == null"); 379b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom } 380ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom if (response == null) { 381ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom throw new NullPointerException("response == null"); 382ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom } 383a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom Intent intent = new Intent(ACTION_CHOOSER); 384a365906e670c89674fb3383b5bcb33e682910c29Kenny Root intent.setPackage(KEYCHAIN_PACKAGE); 385ab8b84ad3847788d83da557606aa27d4102e6b52Fred Quintana intent.putExtra(EXTRA_RESPONSE, new AliasResponse(response)); 38639087b1cec6a54e96ab9eafe8317952720790533Robin Lee intent.putExtra(EXTRA_URI, uri); 38767c30dfe8e4bff11a4660ac23e8679b5deb59457Brian Carlstrom intent.putExtra(EXTRA_ALIAS, alias); 38867c30dfe8e4bff11a4660ac23e8679b5deb59457Brian Carlstrom // the PendingIntent is used to get calling package name 38967c30dfe8e4bff11a4660ac23e8679b5deb59457Brian Carlstrom intent.putExtra(EXTRA_SENDER, PendingIntent.getActivity(activity, 0, new Intent(), 0)); 390ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom activity.startActivity(intent); 391ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom } 392ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom 39393201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom private static class AliasResponse extends IKeyChainAliasCallback.Stub { 39493201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom private final KeyChainAliasCallback keyChainAliasResponse; 395ab8b84ad3847788d83da557606aa27d4102e6b52Fred Quintana private AliasResponse(KeyChainAliasCallback keyChainAliasResponse) { 396ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom this.keyChainAliasResponse = keyChainAliasResponse; 397ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom } 398ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom @Override public void alias(String alias) { 399ab8b84ad3847788d83da557606aa27d4102e6b52Fred Quintana keyChainAliasResponse.alias(alias); 400ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom } 401ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom } 402b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom 403ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom /** 404ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom * Returns the {@code PrivateKey} for the requested alias, or null 4053a435f03906778677b846baa7ebedadd3119e892Robin Lee * if there is no result. 40693201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * 40759e3baa8ab08c4da270023540ba15268c87e0d67Robin Lee * <p> This method may block while waiting for a connection to another process, and must never 40859e3baa8ab08c4da270023540ba15268c87e0d67Robin Lee * be called from the main thread. 409da23618043667e9cee680688b7413f65b400516eRobin Lee * <p> As {@link Activity} and {@link Service} contexts are short-lived and can be destroyed 410da23618043667e9cee680688b7413f65b400516eRobin Lee * at any time from the main thread, it is safer to rely on a long-lived context such as one 411da23618043667e9cee680688b7413f65b400516eRobin Lee * returned from {@link Context#getApplicationContext()}. 41259e3baa8ab08c4da270023540ba15268c87e0d67Robin Lee * 41359e3baa8ab08c4da270023540ba15268c87e0d67Robin Lee * @param alias The alias of the desired private key, typically returned via 41459e3baa8ab08c4da270023540ba15268c87e0d67Robin Lee * {@link KeyChainAliasCallback#alias}. 41593201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * @throws KeyChainException if the alias was valid but there was some problem accessing it. 41659e3baa8ab08c4da270023540ba15268c87e0d67Robin Lee * @throws IllegalStateException if called from the main thread. 417ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom */ 41859e3baa8ab08c4da270023540ba15268c87e0d67Robin Lee @Nullable @WorkerThread 41954bb1596e470144932943046ec7a99551d020ba0Alex Klyubin public static PrivateKey getPrivateKey(@NonNull Context context, @NonNull String alias) 42093201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom throws KeyChainException, InterruptedException { 421ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom if (alias == null) { 422ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom throw new NullPointerException("alias == null"); 423ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom } 424dea66146038a28e9c7da2ad04a6119cfd83de2f8Shawn Willden if (context == null) { 425dea66146038a28e9c7da2ad04a6119cfd83de2f8Shawn Willden throw new NullPointerException("context == null"); 426dea66146038a28e9c7da2ad04a6119cfd83de2f8Shawn Willden } 42728d68b14566f1f7f5ceb7cff2b1b31212f83ed1eRobin Lee 42828d68b14566f1f7f5ceb7cff2b1b31212f83ed1eRobin Lee final String keyId; 42928d68b14566f1f7f5ceb7cff2b1b31212f83ed1eRobin Lee try (KeyChainConnection keyChainConnection = bind(context.getApplicationContext())) { 43028d68b14566f1f7f5ceb7cff2b1b31212f83ed1eRobin Lee keyId = keyChainConnection.getService().requestPrivateKey(alias); 43193201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom } catch (RemoteException e) { 43293201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom throw new KeyChainException(e); 43393201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom } catch (RuntimeException e) { 43493201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom // only certain RuntimeExceptions can be propagated across the IKeyChainService call 43593201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom throw new KeyChainException(e); 43628d68b14566f1f7f5ceb7cff2b1b31212f83ed1eRobin Lee } 43728d68b14566f1f7f5ceb7cff2b1b31212f83ed1eRobin Lee 43828d68b14566f1f7f5ceb7cff2b1b31212f83ed1eRobin Lee if (keyId == null) { 43928d68b14566f1f7f5ceb7cff2b1b31212f83ed1eRobin Lee return null; 44028d68b14566f1f7f5ceb7cff2b1b31212f83ed1eRobin Lee } else { 44128d68b14566f1f7f5ceb7cff2b1b31212f83ed1eRobin Lee try { 44228d68b14566f1f7f5ceb7cff2b1b31212f83ed1eRobin Lee return AndroidKeyStoreProvider.loadAndroidKeyStorePrivateKeyFromKeystore( 44328d68b14566f1f7f5ceb7cff2b1b31212f83ed1eRobin Lee KeyStore.getInstance(), keyId, KeyStore.UID_SELF); 44428d68b14566f1f7f5ceb7cff2b1b31212f83ed1eRobin Lee } catch (RuntimeException | UnrecoverableKeyException e) { 44528d68b14566f1f7f5ceb7cff2b1b31212f83ed1eRobin Lee throw new KeyChainException(e); 44628d68b14566f1f7f5ceb7cff2b1b31212f83ed1eRobin Lee } 447ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom } 448ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom } 449ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom 450ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom /** 451ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom * Returns the {@code X509Certificate} chain for the requested 452b43659170824dd8d753d9249fe6ccfd37c6221aeRubin Xu * alias, or null if there is no result. 453b43659170824dd8d753d9249fe6ccfd37c6221aeRubin Xu * <p> 454b43659170824dd8d753d9249fe6ccfd37c6221aeRubin Xu * <strong>Note:</strong> If a certificate chain was explicitly specified when the alias was 455b43659170824dd8d753d9249fe6ccfd37c6221aeRubin Xu * installed, this method will return that chain. If only the client certificate was specified 456b43659170824dd8d753d9249fe6ccfd37c6221aeRubin Xu * at the installation time, this method will try to build a certificate chain using all 457b43659170824dd8d753d9249fe6ccfd37c6221aeRubin Xu * available trust anchors (preinstalled and user-added). 45893201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * 45959e3baa8ab08c4da270023540ba15268c87e0d67Robin Lee * <p> This method may block while waiting for a connection to another process, and must never 46059e3baa8ab08c4da270023540ba15268c87e0d67Robin Lee * be called from the main thread. 461da23618043667e9cee680688b7413f65b400516eRobin Lee * <p> As {@link Activity} and {@link Service} contexts are short-lived and can be destroyed 462da23618043667e9cee680688b7413f65b400516eRobin Lee * at any time from the main thread, it is safer to rely on a long-lived context such as one 463da23618043667e9cee680688b7413f65b400516eRobin Lee * returned from {@link Context#getApplicationContext()}. 46459e3baa8ab08c4da270023540ba15268c87e0d67Robin Lee * 46593201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * @param alias The alias of the desired certificate chain, typically 46693201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * returned via {@link KeyChainAliasCallback#alias}. 46793201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * @throws KeyChainException if the alias was valid but there was some problem accessing it. 46859e3baa8ab08c4da270023540ba15268c87e0d67Robin Lee * @throws IllegalStateException if called from the main thread. 469ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom */ 47059e3baa8ab08c4da270023540ba15268c87e0d67Robin Lee @Nullable @WorkerThread 47154bb1596e470144932943046ec7a99551d020ba0Alex Klyubin public static X509Certificate[] getCertificateChain(@NonNull Context context, 47254bb1596e470144932943046ec7a99551d020ba0Alex Klyubin @NonNull String alias) throws KeyChainException, InterruptedException { 473ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom if (alias == null) { 474ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom throw new NullPointerException("alias == null"); 475ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom } 4760150e48200a967aead3c2ac6f1283ae2df54c305Kenny Root 47728d68b14566f1f7f5ceb7cff2b1b31212f83ed1eRobin Lee final byte[] certificateBytes; 47828d68b14566f1f7f5ceb7cff2b1b31212f83ed1eRobin Lee final byte[] certChainBytes; 47928d68b14566f1f7f5ceb7cff2b1b31212f83ed1eRobin Lee try (KeyChainConnection keyChainConnection = bind(context.getApplicationContext())) { 48028d68b14566f1f7f5ceb7cff2b1b31212f83ed1eRobin Lee IKeyChainService keyChainService = keyChainConnection.getService(); 48128d68b14566f1f7f5ceb7cff2b1b31212f83ed1eRobin Lee certificateBytes = keyChainService.getCertificate(alias); 4820150e48200a967aead3c2ac6f1283ae2df54c305Kenny Root if (certificateBytes == null) { 4830150e48200a967aead3c2ac6f1283ae2df54c305Kenny Root return null; 4840150e48200a967aead3c2ac6f1283ae2df54c305Kenny Root } 48528d68b14566f1f7f5ceb7cff2b1b31212f83ed1eRobin Lee certChainBytes = keyChainService.getCaCertificates(alias); 48628d68b14566f1f7f5ceb7cff2b1b31212f83ed1eRobin Lee } catch (RemoteException e) { 48728d68b14566f1f7f5ceb7cff2b1b31212f83ed1eRobin Lee throw new KeyChainException(e); 48828d68b14566f1f7f5ceb7cff2b1b31212f83ed1eRobin Lee } catch (RuntimeException e) { 48928d68b14566f1f7f5ceb7cff2b1b31212f83ed1eRobin Lee // only certain RuntimeExceptions can be propagated across the IKeyChainService call 49028d68b14566f1f7f5ceb7cff2b1b31212f83ed1eRobin Lee throw new KeyChainException(e); 49128d68b14566f1f7f5ceb7cff2b1b31212f83ed1eRobin Lee } 49228d68b14566f1f7f5ceb7cff2b1b31212f83ed1eRobin Lee 49328d68b14566f1f7f5ceb7cff2b1b31212f83ed1eRobin Lee try { 494b43659170824dd8d753d9249fe6ccfd37c6221aeRubin Xu X509Certificate leafCert = toCertificate(certificateBytes); 495b43659170824dd8d753d9249fe6ccfd37c6221aeRubin Xu // If the keypair is installed with a certificate chain by either 496b43659170824dd8d753d9249fe6ccfd37c6221aeRubin Xu // DevicePolicyManager.installKeyPair or CertInstaller, return that chain. 497b43659170824dd8d753d9249fe6ccfd37c6221aeRubin Xu if (certChainBytes != null && certChainBytes.length != 0) { 498b43659170824dd8d753d9249fe6ccfd37c6221aeRubin Xu Collection<X509Certificate> chain = toCertificates(certChainBytes); 499b43659170824dd8d753d9249fe6ccfd37c6221aeRubin Xu ArrayList<X509Certificate> fullChain = new ArrayList<>(chain.size() + 1); 500b43659170824dd8d753d9249fe6ccfd37c6221aeRubin Xu fullChain.add(leafCert); 501b43659170824dd8d753d9249fe6ccfd37c6221aeRubin Xu fullChain.addAll(chain); 502b43659170824dd8d753d9249fe6ccfd37c6221aeRubin Xu return fullChain.toArray(new X509Certificate[fullChain.size()]); 503b43659170824dd8d753d9249fe6ccfd37c6221aeRubin Xu } else { 504b43659170824dd8d753d9249fe6ccfd37c6221aeRubin Xu // If there isn't a certificate chain, either due to a pre-existing keypair 505b43659170824dd8d753d9249fe6ccfd37c6221aeRubin Xu // installed before N, or no chain is explicitly installed under the new logic, 506b43659170824dd8d753d9249fe6ccfd37c6221aeRubin Xu // fall back to old behavior of constructing the chain from trusted credentials. 507b43659170824dd8d753d9249fe6ccfd37c6221aeRubin Xu // 508b43659170824dd8d753d9249fe6ccfd37c6221aeRubin Xu // This logic exists to maintain old behaviour for already installed keypair, at 509b43659170824dd8d753d9249fe6ccfd37c6221aeRubin Xu // the cost of potentially returning extra certificate chain for new clients who 510b43659170824dd8d753d9249fe6ccfd37c6221aeRubin Xu // explicitly installed only the client certificate without a chain. The latter 511b43659170824dd8d753d9249fe6ccfd37c6221aeRubin Xu // case is actually no different from pre-N behaviour of getCertificateChain(), 512b43659170824dd8d753d9249fe6ccfd37c6221aeRubin Xu // in that sense this change introduces no regression. Besides the returned chain 513b43659170824dd8d753d9249fe6ccfd37c6221aeRubin Xu // is still valid so the consumer of the chain should have no problem verifying it. 514b43659170824dd8d753d9249fe6ccfd37c6221aeRubin Xu TrustedCertificateStore store = new TrustedCertificateStore(); 515b43659170824dd8d753d9249fe6ccfd37c6221aeRubin Xu List<X509Certificate> chain = store.getCertificateChain(leafCert); 516b43659170824dd8d753d9249fe6ccfd37c6221aeRubin Xu return chain.toArray(new X509Certificate[chain.size()]); 517b43659170824dd8d753d9249fe6ccfd37c6221aeRubin Xu } 51828d68b14566f1f7f5ceb7cff2b1b31212f83ed1eRobin Lee } catch (CertificateException | RuntimeException e) { 51993201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom throw new KeyChainException(e); 520b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom } 521b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom } 522b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom 523bf556ac636a39c1d0fe5451a921b88400dd1c695Kenny Root /** 524bf556ac636a39c1d0fe5451a921b88400dd1c695Kenny Root * Returns {@code true} if the current device's {@code KeyChain} supports a 525bf556ac636a39c1d0fe5451a921b88400dd1c695Kenny Root * specific {@code PrivateKey} type indicated by {@code algorithm} (e.g., 526bf556ac636a39c1d0fe5451a921b88400dd1c695Kenny Root * "RSA"). 527bf556ac636a39c1d0fe5451a921b88400dd1c695Kenny Root */ 5284d5443f37f2bc58be8d22ed50024c39a5a1fbc8fAlex Klyubin public static boolean isKeyAlgorithmSupported( 5293f8d4d840894468f2be8a5b56ff266cef2d71c50Alex Klyubin @NonNull @KeyProperties.KeyAlgorithmEnum String algorithm) { 530b91773bce1126d28a93f73fbef18f3a79245f24eKenny Root final String algUpper = algorithm.toUpperCase(Locale.US); 5313f8d4d840894468f2be8a5b56ff266cef2d71c50Alex Klyubin return KeyProperties.KEY_ALGORITHM_EC.equals(algUpper) 5323f8d4d840894468f2be8a5b56ff266cef2d71c50Alex Klyubin || KeyProperties.KEY_ALGORITHM_RSA.equals(algUpper); 533bf556ac636a39c1d0fe5451a921b88400dd1c695Kenny Root } 534bf556ac636a39c1d0fe5451a921b88400dd1c695Kenny Root 535bf556ac636a39c1d0fe5451a921b88400dd1c695Kenny Root /** 536bf556ac636a39c1d0fe5451a921b88400dd1c695Kenny Root * Returns {@code true} if the current device's {@code KeyChain} binds any 537bf556ac636a39c1d0fe5451a921b88400dd1c695Kenny Root * {@code PrivateKey} of the given {@code algorithm} to the device once 538bf556ac636a39c1d0fe5451a921b88400dd1c695Kenny Root * imported or generated. This can be used to tell if there is special 539bf556ac636a39c1d0fe5451a921b88400dd1c695Kenny Root * hardware support that can be used to bind keys to the device in a way 540bf556ac636a39c1d0fe5451a921b88400dd1c695Kenny Root * that makes it non-exportable. 541469cbf5156ad54650726ade59f2ee5aa01359ec2Alex Klyubin * 542469cbf5156ad54650726ade59f2ee5aa01359ec2Alex Klyubin * @deprecated Whether the key is bound to the secure hardware is known only 543469cbf5156ad54650726ade59f2ee5aa01359ec2Alex Klyubin * once the key has been imported. To find out, use: 544469cbf5156ad54650726ade59f2ee5aa01359ec2Alex Klyubin * <pre>{@code 545469cbf5156ad54650726ade59f2ee5aa01359ec2Alex Klyubin * PrivateKey key = ...; // private key from KeyChain 546469cbf5156ad54650726ade59f2ee5aa01359ec2Alex Klyubin * 547469cbf5156ad54650726ade59f2ee5aa01359ec2Alex Klyubin * KeyFactory keyFactory = 548469cbf5156ad54650726ade59f2ee5aa01359ec2Alex Klyubin * KeyFactory.getInstance(key.getAlgorithm(), "AndroidKeyStore"); 549469cbf5156ad54650726ade59f2ee5aa01359ec2Alex Klyubin * KeyInfo keyInfo = keyFactory.getKeySpec(key, KeyInfo.class); 55071fbb81b14958b80fe55738607740c6630e4e9daNeil Fuller * if (keyInfo.isInsideSecureHardware()) { 551469cbf5156ad54650726ade59f2ee5aa01359ec2Alex Klyubin * // The key is bound to the secure hardware of this Android 55271fbb81b14958b80fe55738607740c6630e4e9daNeil Fuller * }}</pre> 553bf556ac636a39c1d0fe5451a921b88400dd1c695Kenny Root */ 554469cbf5156ad54650726ade59f2ee5aa01359ec2Alex Klyubin @Deprecated 5554d5443f37f2bc58be8d22ed50024c39a5a1fbc8fAlex Klyubin public static boolean isBoundKeyAlgorithm( 5563f8d4d840894468f2be8a5b56ff266cef2d71c50Alex Klyubin @NonNull @KeyProperties.KeyAlgorithmEnum String algorithm) { 5575b7e90ac937857c10a3d49b244ec75ca539b9a22Kenny Root if (!isKeyAlgorithmSupported(algorithm)) { 558bf556ac636a39c1d0fe5451a921b88400dd1c695Kenny Root return false; 559bf556ac636a39c1d0fe5451a921b88400dd1c695Kenny Root } 560bf556ac636a39c1d0fe5451a921b88400dd1c695Kenny Root 561b91773bce1126d28a93f73fbef18f3a79245f24eKenny Root return KeyStore.getInstance().isHardwareBacked(algorithm); 562bf556ac636a39c1d0fe5451a921b88400dd1c695Kenny Root } 563bf556ac636a39c1d0fe5451a921b88400dd1c695Kenny Root 564f0ae135049048424bceccb0799b12377181b25f0Zoltan Szatmary-Ban /** @hide */ 56554bb1596e470144932943046ec7a99551d020ba0Alex Klyubin @NonNull 56654bb1596e470144932943046ec7a99551d020ba0Alex Klyubin public static X509Certificate toCertificate(@NonNull byte[] bytes) { 567b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom if (bytes == null) { 5688e9929c4d0730de4c9f01435a7cfe2db8855e24dBrian Carlstrom throw new IllegalArgumentException("bytes == null"); 569b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom } 570b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom try { 571b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom CertificateFactory certFactory = CertificateFactory.getInstance("X.509"); 572b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom Certificate cert = certFactory.generateCertificate(new ByteArrayInputStream(bytes)); 573b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom return (X509Certificate) cert; 574b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom } catch (CertificateException e) { 575b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom throw new AssertionError(e); 576b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom } 577b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom } 578b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom 579b43659170824dd8d753d9249fe6ccfd37c6221aeRubin Xu /** @hide */ 580b43659170824dd8d753d9249fe6ccfd37c6221aeRubin Xu @NonNull 581b43659170824dd8d753d9249fe6ccfd37c6221aeRubin Xu public static Collection<X509Certificate> toCertificates(@NonNull byte[] bytes) { 582b43659170824dd8d753d9249fe6ccfd37c6221aeRubin Xu if (bytes == null) { 583b43659170824dd8d753d9249fe6ccfd37c6221aeRubin Xu throw new IllegalArgumentException("bytes == null"); 584b43659170824dd8d753d9249fe6ccfd37c6221aeRubin Xu } 585b43659170824dd8d753d9249fe6ccfd37c6221aeRubin Xu try { 586b43659170824dd8d753d9249fe6ccfd37c6221aeRubin Xu CertificateFactory certFactory = CertificateFactory.getInstance("X.509"); 587b43659170824dd8d753d9249fe6ccfd37c6221aeRubin Xu return (Collection<X509Certificate>) certFactory.generateCertificates( 588b43659170824dd8d753d9249fe6ccfd37c6221aeRubin Xu new ByteArrayInputStream(bytes)); 589b43659170824dd8d753d9249fe6ccfd37c6221aeRubin Xu } catch (CertificateException e) { 590b43659170824dd8d753d9249fe6ccfd37c6221aeRubin Xu throw new AssertionError(e); 591b43659170824dd8d753d9249fe6ccfd37c6221aeRubin Xu } 592b43659170824dd8d753d9249fe6ccfd37c6221aeRubin Xu } 593b43659170824dd8d753d9249fe6ccfd37c6221aeRubin Xu 594d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom /** 595d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom * @hide for reuse by CertInstaller and Settings. 596d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom * @see KeyChain#bind 597d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom */ 5987f5c91c6bce6a8ff2414549219a321a98a98ab31Robin Lee public static class KeyChainConnection implements Closeable { 599d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom private final Context context; 600d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom private final ServiceConnection serviceConnection; 601d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom private final IKeyChainService service; 6027eeab2cdd99f84ecef12ebbb92e0731b26508da1phweiss protected KeyChainConnection(Context context, 6037eeab2cdd99f84ecef12ebbb92e0731b26508da1phweiss ServiceConnection serviceConnection, 6047eeab2cdd99f84ecef12ebbb92e0731b26508da1phweiss IKeyChainService service) { 605d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom this.context = context; 606d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom this.serviceConnection = serviceConnection; 607d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom this.service = service; 608d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom } 609d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom @Override public void close() { 610d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom context.unbindService(serviceConnection); 611d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom } 612d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom public IKeyChainService getService() { 613d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom return service; 614d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom } 615d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom } 616d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom 617d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom /** 618d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom * @hide for reuse by CertInstaller and Settings. 619d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom * 620d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom * Caller should call unbindService on the result when finished. 621d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom */ 62259e3baa8ab08c4da270023540ba15268c87e0d67Robin Lee @WorkerThread 62354bb1596e470144932943046ec7a99551d020ba0Alex Klyubin public static KeyChainConnection bind(@NonNull Context context) throws InterruptedException { 624306fe08ce2b06671336e67a87afaa0851f0105ebRobin Lee return bindAsUser(context, Process.myUserHandle()); 625306fe08ce2b06671336e67a87afaa0851f0105ebRobin Lee } 626306fe08ce2b06671336e67a87afaa0851f0105ebRobin Lee 627306fe08ce2b06671336e67a87afaa0851f0105ebRobin Lee /** 628306fe08ce2b06671336e67a87afaa0851f0105ebRobin Lee * @hide 629306fe08ce2b06671336e67a87afaa0851f0105ebRobin Lee */ 63059e3baa8ab08c4da270023540ba15268c87e0d67Robin Lee @WorkerThread 63154bb1596e470144932943046ec7a99551d020ba0Alex Klyubin public static KeyChainConnection bindAsUser(@NonNull Context context, UserHandle user) 632306fe08ce2b06671336e67a87afaa0851f0105ebRobin Lee throws InterruptedException { 633d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom if (context == null) { 634d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom throw new NullPointerException("context == null"); 635d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom } 636d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom ensureNotOnMainThread(context); 637d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom final BlockingQueue<IKeyChainService> q = new LinkedBlockingQueue<IKeyChainService>(1); 638d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom ServiceConnection keyChainServiceConnection = new ServiceConnection() { 639ab8b84ad3847788d83da557606aa27d4102e6b52Fred Quintana volatile boolean mConnectedAtLeastOnce = false; 640d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom @Override public void onServiceConnected(ComponentName name, IBinder service) { 641ab8b84ad3847788d83da557606aa27d4102e6b52Fred Quintana if (!mConnectedAtLeastOnce) { 642ab8b84ad3847788d83da557606aa27d4102e6b52Fred Quintana mConnectedAtLeastOnce = true; 643ab8b84ad3847788d83da557606aa27d4102e6b52Fred Quintana try { 6440a17db1cc5942ea000ca87bb72853de57a15ec64Jeff Sharkey q.put(IKeyChainService.Stub.asInterface(Binder.allowBlocking(service))); 645ab8b84ad3847788d83da557606aa27d4102e6b52Fred Quintana } catch (InterruptedException e) { 646ab8b84ad3847788d83da557606aa27d4102e6b52Fred Quintana // will never happen, since the queue starts with one available slot 647ab8b84ad3847788d83da557606aa27d4102e6b52Fred Quintana } 648d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom } 649d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom } 650d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom @Override public void onServiceDisconnected(ComponentName name) {} 651d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom }; 652da51e68e582ffa017543982297c831680d201a91Maggie Benthall Intent intent = new Intent(IKeyChainService.class.getName()); 653da51e68e582ffa017543982297c831680d201a91Maggie Benthall ComponentName comp = intent.resolveSystemService(context.getPackageManager(), 0); 654da51e68e582ffa017543982297c831680d201a91Maggie Benthall intent.setComponent(comp); 65521bcbc54dd6b1f029f4973bef27c20e55d057432Robin Lee if (comp == null || !context.bindServiceAsUser( 65621bcbc54dd6b1f029f4973bef27c20e55d057432Robin Lee intent, keyChainServiceConnection, Context.BIND_AUTO_CREATE, user)) { 657d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom throw new AssertionError("could not bind to KeyChainService"); 658d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom } 659d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom return new KeyChainConnection(context, keyChainServiceConnection, q.take()); 660d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom } 661d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom 66254bb1596e470144932943046ec7a99551d020ba0Alex Klyubin private static void ensureNotOnMainThread(@NonNull Context context) { 663b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom Looper looper = Looper.myLooper(); 6648e9929c4d0730de4c9f01435a7cfe2db8855e24dBrian Carlstrom if (looper != null && looper == context.getMainLooper()) { 665b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom throw new IllegalStateException( 666b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom "calling this from your main thread can lead to deadlock"); 667b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom } 668b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom } 669b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom} 670