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 18ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstromimport android.app.Activity; 1967c30dfe8e4bff11a4660ac23e8679b5deb59457Brian Carlstromimport android.app.PendingIntent; 20b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstromimport android.content.ComponentName; 21b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstromimport android.content.Context; 22b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstromimport android.content.Intent; 23b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstromimport android.content.ServiceConnection; 24b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstromimport android.os.IBinder; 25b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstromimport android.os.Looper; 26306fe08ce2b06671336e67a87afaa0851f0105ebRobin Leeimport android.os.Process; 27b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstromimport android.os.RemoteException; 28306fe08ce2b06671336e67a87afaa0851f0105ebRobin Leeimport android.os.UserHandle; 29b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstromimport java.io.ByteArrayInputStream; 30d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstromimport java.io.Closeable; 315423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Rootimport java.security.InvalidKeyException; 3293201f545b67da15cb69830a5988810aef52c0b2Brian Carlstromimport java.security.Principal; 33b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstromimport java.security.PrivateKey; 34b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstromimport java.security.cert.Certificate; 35b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstromimport java.security.cert.CertificateException; 36b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstromimport java.security.cert.CertificateFactory; 37b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstromimport java.security.cert.X509Certificate; 38db93b78385d694402760ad63de0795f3902030d9Brian Carlstromimport java.util.List; 39b91773bce1126d28a93f73fbef18f3a79245f24eKenny Rootimport java.util.Locale; 408e9929c4d0730de4c9f01435a7cfe2db8855e24dBrian Carlstromimport java.util.concurrent.BlockingQueue; 418e9929c4d0730de4c9f01435a7cfe2db8855e24dBrian Carlstromimport java.util.concurrent.LinkedBlockingQueue; 425423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root 4312e752225aa96888358294be0d725d499a1c9f03Kenny Rootimport com.android.org.conscrypt.OpenSSLEngine; 4412e752225aa96888358294be0d725d499a1c9f03Kenny Rootimport com.android.org.conscrypt.TrustedCertificateStore; 45b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom 46b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom/** 4793201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * The {@code KeyChain} class provides access to private keys and 4893201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * their corresponding certificate chains in credential storage. 4993201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * 5093201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * <p>Applications accessing the {@code KeyChain} normally go through 5193201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * these steps: 5293201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * 5393201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * <ol> 5493201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * 5593201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * <li>Receive a callback from an {@link javax.net.ssl.X509KeyManager 5693201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * X509KeyManager} that a private key is requested. 5793201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * 5893201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * <li>Call {@link #choosePrivateKeyAlias 5993201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * choosePrivateKeyAlias} to allow the user to select from a 6093201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * list of currently available private keys and corresponding 6193201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * certificate chains. The chosen alias will be returned by the 6293201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * callback {@link KeyChainAliasCallback#alias}, or null if no private 6393201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * key is available or the user cancels the request. 6493201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * 6593201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * <li>Call {@link #getPrivateKey} and {@link #getCertificateChain} to 6693201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * retrieve the credentials to return to the corresponding {@link 6793201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * javax.net.ssl.X509KeyManager} callbacks. 6893201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * 6993201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * </ol> 7093201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * 7193201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * <p>An application may remember the value of a selected alias to 7293201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * avoid prompting the user with {@link #choosePrivateKeyAlias 7393201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * choosePrivateKeyAlias} on subsequent connections. If the alias is 7493201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * no longer valid, null will be returned on lookups using that value 75ca43c458ad0ee8cfa7f5eabc8ba1a65ae473976bBrian Carlstrom * 76ca43c458ad0ee8cfa7f5eabc8ba1a65ae473976bBrian Carlstrom * <p>An application can request the installation of private keys and 77ca43c458ad0ee8cfa7f5eabc8ba1a65ae473976bBrian Carlstrom * certificates via the {@code Intent} provided by {@link 78ca43c458ad0ee8cfa7f5eabc8ba1a65ae473976bBrian Carlstrom * #createInstallIntent}. Private keys installed via this {@code 79ca43c458ad0ee8cfa7f5eabc8ba1a65ae473976bBrian Carlstrom * Intent} will be accessible via {@link #choosePrivateKeyAlias} while 80ca43c458ad0ee8cfa7f5eabc8ba1a65ae473976bBrian Carlstrom * Certificate Authority (CA) certificates will be trusted by all 81ca43c458ad0ee8cfa7f5eabc8ba1a65ae473976bBrian Carlstrom * applications through the default {@code X509TrustManager}. 82b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom */ 8393201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom// TODO reference intent for credential installation when public 84b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrompublic final class KeyChain { 85b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom 86b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom private static final String TAG = "KeyChain"; 87b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom 88b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom /** 89b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom * @hide Also used by KeyChainService implementation 90b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom */ 91b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom public static final String ACCOUNT_TYPE = "com.android.keychain"; 92b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom 93b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom /** 94a365906e670c89674fb3383b5bcb33e682910c29Kenny Root * Package name for KeyChain chooser. 95a365906e670c89674fb3383b5bcb33e682910c29Kenny Root */ 96a365906e670c89674fb3383b5bcb33e682910c29Kenny Root private static final String KEYCHAIN_PACKAGE = "com.android.keychain"; 97a365906e670c89674fb3383b5bcb33e682910c29Kenny Root 98a365906e670c89674fb3383b5bcb33e682910c29Kenny Root /** 99a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * Action to bring up the KeyChainActivity 100a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom */ 101a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom private static final String ACTION_CHOOSER = "com.android.keychain.CHOOSER"; 102a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom 103a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom /** 1041a88d834e8f7d21e714121c011fec82369a2e9f1Kenny Root * Package name for the Certificate Installer. 1051a88d834e8f7d21e714121c011fec82369a2e9f1Kenny Root */ 1061a88d834e8f7d21e714121c011fec82369a2e9f1Kenny Root private static final String CERT_INSTALLER_PACKAGE = "com.android.certinstaller"; 1071a88d834e8f7d21e714121c011fec82369a2e9f1Kenny Root 1081a88d834e8f7d21e714121c011fec82369a2e9f1Kenny Root /** 109a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * Extra for use with {@link #ACTION_CHOOSER} 110ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom * @hide Also used by KeyChainActivity implementation 111b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom */ 112ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom public static final String EXTRA_RESPONSE = "response"; 113b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom 114b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom /** 115a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * Extra for use with {@link #ACTION_CHOOSER} 11667c30dfe8e4bff11a4660ac23e8679b5deb59457Brian Carlstrom * @hide Also used by KeyChainActivity implementation 11767c30dfe8e4bff11a4660ac23e8679b5deb59457Brian Carlstrom */ 11867c30dfe8e4bff11a4660ac23e8679b5deb59457Brian Carlstrom public static final String EXTRA_HOST = "host"; 11967c30dfe8e4bff11a4660ac23e8679b5deb59457Brian Carlstrom 12067c30dfe8e4bff11a4660ac23e8679b5deb59457Brian Carlstrom /** 121a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * Extra for use with {@link #ACTION_CHOOSER} 12267c30dfe8e4bff11a4660ac23e8679b5deb59457Brian Carlstrom * @hide Also used by KeyChainActivity implementation 12367c30dfe8e4bff11a4660ac23e8679b5deb59457Brian Carlstrom */ 12467c30dfe8e4bff11a4660ac23e8679b5deb59457Brian Carlstrom public static final String EXTRA_PORT = "port"; 12567c30dfe8e4bff11a4660ac23e8679b5deb59457Brian Carlstrom 12667c30dfe8e4bff11a4660ac23e8679b5deb59457Brian Carlstrom /** 127a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * Extra for use with {@link #ACTION_CHOOSER} 12867c30dfe8e4bff11a4660ac23e8679b5deb59457Brian Carlstrom * @hide Also used by KeyChainActivity implementation 12967c30dfe8e4bff11a4660ac23e8679b5deb59457Brian Carlstrom */ 13067c30dfe8e4bff11a4660ac23e8679b5deb59457Brian Carlstrom public static final String EXTRA_ALIAS = "alias"; 13167c30dfe8e4bff11a4660ac23e8679b5deb59457Brian Carlstrom 13267c30dfe8e4bff11a4660ac23e8679b5deb59457Brian Carlstrom /** 133a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * Extra for use with {@link #ACTION_CHOOSER} 13467c30dfe8e4bff11a4660ac23e8679b5deb59457Brian Carlstrom * @hide Also used by KeyChainActivity implementation 13567c30dfe8e4bff11a4660ac23e8679b5deb59457Brian Carlstrom */ 13667c30dfe8e4bff11a4660ac23e8679b5deb59457Brian Carlstrom public static final String EXTRA_SENDER = "sender"; 13767c30dfe8e4bff11a4660ac23e8679b5deb59457Brian Carlstrom 13867c30dfe8e4bff11a4660ac23e8679b5deb59457Brian Carlstrom /** 13993ba4fedebb78ba47c24e8472c8960ea8fdc933aSelim Gurun * Action to bring up the CertInstaller. 140a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom */ 141a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom private static final String ACTION_INSTALL = "android.credentials.INSTALL"; 142a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom 143a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom /** 144a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * Optional extra to specify a {@code String} credential name on 145a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * the {@code Intent} returned by {@link #createInstallIntent}. 146a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom */ 147a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom // Compatible with old com.android.certinstaller.CredentialHelper.CERT_NAME_KEY 148a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom public static final String EXTRA_NAME = "name"; 149a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom 150a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom /** 151a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * Optional extra to specify an X.509 certificate to install on 152a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * the {@code Intent} returned by {@link #createInstallIntent}. 153a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * The extra value should be a PEM or ASN.1 DER encoded {@code 154a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * byte[]}. An {@link X509Certificate} can be converted to DER 155a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * encoded bytes with {@link X509Certificate#getEncoded}. 156a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * 157a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * <p>{@link #EXTRA_NAME} may be used to provide a default alias 158a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * name for the installed certificate. 159a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom */ 160a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom // Compatible with old android.security.Credentials.CERTIFICATE 161a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom public static final String EXTRA_CERTIFICATE = "CERT"; 162a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom 163a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom /** 164a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * Optional extra for use with the {@code Intent} returned by 165a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * {@link #createInstallIntent} to specify a PKCS#12 key store to 166a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * install. The extra value should be a {@code byte[]}. The bytes 167a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * may come from an external source or be generated with {@link 168ca43c458ad0ee8cfa7f5eabc8ba1a65ae473976bBrian Carlstrom * java.security.KeyStore#store} on a "PKCS12" instance. 169a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * 170a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * <p>The user will be prompted for the password to load the key store. 171a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * 172a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * <p>The key store will be scanned for {@link 173a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * java.security.KeyStore.PrivateKeyEntry} entries and both the 174a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * private key and associated certificate chain will be installed. 175a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * 176a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * <p>{@link #EXTRA_NAME} may be used to provide a default alias 177a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * name for the installed credentials. 178a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom */ 179a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom // Compatible with old android.security.Credentials.PKCS12 180a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom public static final String EXTRA_PKCS12 = "PKCS12"; 181a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom 18293ba4fedebb78ba47c24e8472c8960ea8fdc933aSelim Gurun 18393ba4fedebb78ba47c24e8472c8960ea8fdc933aSelim Gurun /** 18493ba4fedebb78ba47c24e8472c8960ea8fdc933aSelim Gurun * Broadcast Action: Indicates the trusted storage has changed. Sent when 18593ba4fedebb78ba47c24e8472c8960ea8fdc933aSelim Gurun * one of this happens: 18693ba4fedebb78ba47c24e8472c8960ea8fdc933aSelim Gurun * 18793ba4fedebb78ba47c24e8472c8960ea8fdc933aSelim Gurun * <ul> 18893ba4fedebb78ba47c24e8472c8960ea8fdc933aSelim Gurun * <li>a new CA is added, 18993ba4fedebb78ba47c24e8472c8960ea8fdc933aSelim Gurun * <li>an existing CA is removed or disabled, 19093ba4fedebb78ba47c24e8472c8960ea8fdc933aSelim Gurun * <li>a disabled CA is enabled, 19193ba4fedebb78ba47c24e8472c8960ea8fdc933aSelim Gurun * <li>trusted storage is reset (all user certs are cleared), 19293ba4fedebb78ba47c24e8472c8960ea8fdc933aSelim Gurun * <li>when permission to access a private key is changed. 19393ba4fedebb78ba47c24e8472c8960ea8fdc933aSelim Gurun * </ul> 19493ba4fedebb78ba47c24e8472c8960ea8fdc933aSelim Gurun */ 19593ba4fedebb78ba47c24e8472c8960ea8fdc933aSelim Gurun public static final String ACTION_STORAGE_CHANGED = "android.security.STORAGE_CHANGED"; 19693ba4fedebb78ba47c24e8472c8960ea8fdc933aSelim Gurun 197a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom /** 198a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * Returns an {@code Intent} that can be used for credential 199a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * installation. The intent may be used without any extras, in 200a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * which case the user will be able to install credentials from 201a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * their own source. 202a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * 203a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * <p>Alternatively, {@link #EXTRA_CERTIFICATE} or {@link 204a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * #EXTRA_PKCS12} maybe used to specify the bytes of an X.509 205a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * certificate or a PKCS#12 key store for installation. These 206ca43c458ad0ee8cfa7f5eabc8ba1a65ae473976bBrian Carlstrom * extras may be combined with {@link #EXTRA_NAME} to provide a 207a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * default alias name for credentials being installed. 208a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * 209a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * <p>When used with {@link Activity#startActivityForResult}, 210a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * {@link Activity#RESULT_OK} will be returned if a credential was 211a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * successfully installed, otherwise {@link 212a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * Activity#RESULT_CANCELED} will be returned. 213a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom */ 214a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom public static Intent createInstallIntent() { 215a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom Intent intent = new Intent(ACTION_INSTALL); 2161a88d834e8f7d21e714121c011fec82369a2e9f1Kenny Root intent.setClassName(CERT_INSTALLER_PACKAGE, 217a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom "com.android.certinstaller.CertInstallerMain"); 218a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom return intent; 219a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom } 220a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom 221a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom /** 222ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom * Launches an {@code Activity} for the user to select the alias 223ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom * for a private key and certificate pair for authentication. The 224ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom * selected alias or null will be returned via the 22593201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * KeyChainAliasCallback callback. 22693201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * 22793201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * <p>{@code keyTypes} and {@code issuers} may be used to 22893201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * highlight suggested choices to the user, although to cope with 22993201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * sometimes erroneous values provided by servers, the user may be 23093201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * able to override these suggestions. 23193201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * 23293201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * <p>{@code host} and {@code port} may be used to give the user 23393201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * more context about the server requesting the credentials. 23493201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * 23567c30dfe8e4bff11a4660ac23e8679b5deb59457Brian Carlstrom * <p>{@code alias} allows the chooser to preselect an existing 23667c30dfe8e4bff11a4660ac23e8679b5deb59457Brian Carlstrom * alias which will still be subject to user confirmation. 23767c30dfe8e4bff11a4660ac23e8679b5deb59457Brian Carlstrom * 23893201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * @param activity The {@link Activity} context to use for 23993201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * launching the new sub-Activity to prompt the user to select 24093201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * a private key; used only to call startActivity(); must not 24193201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * be null. 24293201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * @param response Callback to invoke when the request completes; 24393201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * must not be null 24493201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * @param keyTypes The acceptable types of asymmetric keys such as 24593201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * "RSA" or "DSA", or a null array. 24693201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * @param issuers The acceptable certificate issuers for the 24793201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * certificate matching the private key, or null. 24893201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * @param host The host name of the server requesting the 24993201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * certificate, or null if unavailable. 25093201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * @param port The port number of the server requesting the 25193201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * certificate, or -1 if unavailable. 25267c30dfe8e4bff11a4660ac23e8679b5deb59457Brian Carlstrom * @param alias The alias to preselect if available, or null if 25367c30dfe8e4bff11a4660ac23e8679b5deb59457Brian Carlstrom * unavailable. 254b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom */ 25593201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom public static void choosePrivateKeyAlias(Activity activity, KeyChainAliasCallback response, 25693201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom String[] keyTypes, Principal[] issuers, 25767c30dfe8e4bff11a4660ac23e8679b5deb59457Brian Carlstrom String host, int port, 25867c30dfe8e4bff11a4660ac23e8679b5deb59457Brian Carlstrom String alias) { 25993201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom /* 26067c30dfe8e4bff11a4660ac23e8679b5deb59457Brian Carlstrom * TODO currently keyTypes, issuers are unused. They are meant 26167c30dfe8e4bff11a4660ac23e8679b5deb59457Brian Carlstrom * to follow the semantics and purpose of X509KeyManager 26267c30dfe8e4bff11a4660ac23e8679b5deb59457Brian Carlstrom * method arguments. 26393201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * 26493201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * keyTypes would allow the list to be filtered and typically 26593201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * will be set correctly by the server. In practice today, 26693201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * most all users will want only RSA, rarely DSA, and usually 26793201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * only a small number of certs will be available. 26893201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * 26993201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * issuers is typically not useful. Some servers historically 27093201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * will send the entire list of public CAs known to the 27193201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * server. Others will send none. If this is used, if there 27293201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * are no matches after applying the constraint, it should be 27393201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * ignored. 27493201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom */ 275ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom if (activity == null) { 276ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom throw new NullPointerException("activity == null"); 277b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom } 278ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom if (response == null) { 279ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom throw new NullPointerException("response == null"); 280ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom } 281a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom Intent intent = new Intent(ACTION_CHOOSER); 282a365906e670c89674fb3383b5bcb33e682910c29Kenny Root intent.setPackage(KEYCHAIN_PACKAGE); 283ab8b84ad3847788d83da557606aa27d4102e6b52Fred Quintana intent.putExtra(EXTRA_RESPONSE, new AliasResponse(response)); 28467c30dfe8e4bff11a4660ac23e8679b5deb59457Brian Carlstrom intent.putExtra(EXTRA_HOST, host); 28567c30dfe8e4bff11a4660ac23e8679b5deb59457Brian Carlstrom intent.putExtra(EXTRA_PORT, port); 28667c30dfe8e4bff11a4660ac23e8679b5deb59457Brian Carlstrom intent.putExtra(EXTRA_ALIAS, alias); 28767c30dfe8e4bff11a4660ac23e8679b5deb59457Brian Carlstrom // the PendingIntent is used to get calling package name 28867c30dfe8e4bff11a4660ac23e8679b5deb59457Brian Carlstrom intent.putExtra(EXTRA_SENDER, PendingIntent.getActivity(activity, 0, new Intent(), 0)); 289ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom activity.startActivity(intent); 290ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom } 291ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom 29293201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom private static class AliasResponse extends IKeyChainAliasCallback.Stub { 29393201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom private final KeyChainAliasCallback keyChainAliasResponse; 294ab8b84ad3847788d83da557606aa27d4102e6b52Fred Quintana private AliasResponse(KeyChainAliasCallback keyChainAliasResponse) { 295ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom this.keyChainAliasResponse = keyChainAliasResponse; 296ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom } 297ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom @Override public void alias(String alias) { 298ab8b84ad3847788d83da557606aa27d4102e6b52Fred Quintana keyChainAliasResponse.alias(alias); 299ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom } 300ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom } 301b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom 302ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom /** 303ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom * Returns the {@code PrivateKey} for the requested alias, or null 304ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom * if no there is no result. 30593201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * 30693201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * @param alias The alias of the desired private key, typically 30793201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * returned via {@link KeyChainAliasCallback#alias}. 30893201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * @throws KeyChainException if the alias was valid but there was some problem accessing it. 309ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom */ 310ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom public static PrivateKey getPrivateKey(Context context, String alias) 31193201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom throws KeyChainException, InterruptedException { 312ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom if (alias == null) { 313ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom throw new NullPointerException("alias == null"); 314ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom } 315ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom KeyChainConnection keyChainConnection = bind(context); 316ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom try { 3175423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root final IKeyChainService keyChainService = keyChainConnection.getService(); 3185423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root final String keyId = keyChainService.requestPrivateKey(alias); 3195423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root if (keyId == null) { 3205423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root throw new KeyChainException("keystore had a problem"); 3215423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root } 3225423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root 3235423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root final OpenSSLEngine engine = OpenSSLEngine.getInstance("keystore"); 3245423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root return engine.getPrivateKeyById(keyId); 32593201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom } catch (RemoteException e) { 32693201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom throw new KeyChainException(e); 32793201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom } catch (RuntimeException e) { 32893201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom // only certain RuntimeExceptions can be propagated across the IKeyChainService call 32993201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom throw new KeyChainException(e); 3305423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root } catch (InvalidKeyException e) { 3315423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root throw new KeyChainException(e); 332ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom } finally { 333ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom keyChainConnection.close(); 334ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom } 335ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom } 336ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom 337ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom /** 338ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom * Returns the {@code X509Certificate} chain for the requested 339ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom * alias, or null if no there is no result. 34093201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * 34193201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * @param alias The alias of the desired certificate chain, typically 34293201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * returned via {@link KeyChainAliasCallback#alias}. 34393201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * @throws KeyChainException if the alias was valid but there was some problem accessing it. 344ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom */ 345ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom public static X509Certificate[] getCertificateChain(Context context, String alias) 34693201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom throws KeyChainException, InterruptedException { 347ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom if (alias == null) { 348ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom throw new NullPointerException("alias == null"); 349ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom } 350ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom KeyChainConnection keyChainConnection = bind(context); 351ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom try { 352ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom IKeyChainService keyChainService = keyChainConnection.getService(); 3530150e48200a967aead3c2ac6f1283ae2df54c305Kenny Root 3540150e48200a967aead3c2ac6f1283ae2df54c305Kenny Root final byte[] certificateBytes = keyChainService.getCertificate(alias); 3550150e48200a967aead3c2ac6f1283ae2df54c305Kenny Root if (certificateBytes == null) { 3560150e48200a967aead3c2ac6f1283ae2df54c305Kenny Root return null; 3570150e48200a967aead3c2ac6f1283ae2df54c305Kenny Root } 3580150e48200a967aead3c2ac6f1283ae2df54c305Kenny Root 359db93b78385d694402760ad63de0795f3902030d9Brian Carlstrom TrustedCertificateStore store = new TrustedCertificateStore(); 36054e03afcfe34e9875efa56650c1af3ebc8f58a89Kenny Root List<X509Certificate> chain = store 36154e03afcfe34e9875efa56650c1af3ebc8f58a89Kenny Root .getCertificateChain(toCertificate(certificateBytes)); 362db93b78385d694402760ad63de0795f3902030d9Brian Carlstrom return chain.toArray(new X509Certificate[chain.size()]); 363cfba6a07fd24559bfb6bb51007520b8ca3cd5c48Kenny Root } catch (CertificateException e) { 364cfba6a07fd24559bfb6bb51007520b8ca3cd5c48Kenny Root throw new KeyChainException(e); 36593201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom } catch (RemoteException e) { 36693201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom throw new KeyChainException(e); 36793201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom } catch (RuntimeException e) { 36893201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom // only certain RuntimeExceptions can be propagated across the IKeyChainService call 36993201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom throw new KeyChainException(e); 3708e9929c4d0730de4c9f01435a7cfe2db8855e24dBrian Carlstrom } finally { 371d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom keyChainConnection.close(); 372b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom } 373b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom } 374b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom 375bf556ac636a39c1d0fe5451a921b88400dd1c695Kenny Root /** 376bf556ac636a39c1d0fe5451a921b88400dd1c695Kenny Root * Returns {@code true} if the current device's {@code KeyChain} supports a 377bf556ac636a39c1d0fe5451a921b88400dd1c695Kenny Root * specific {@code PrivateKey} type indicated by {@code algorithm} (e.g., 378bf556ac636a39c1d0fe5451a921b88400dd1c695Kenny Root * "RSA"). 379bf556ac636a39c1d0fe5451a921b88400dd1c695Kenny Root */ 3805b7e90ac937857c10a3d49b244ec75ca539b9a22Kenny Root public static boolean isKeyAlgorithmSupported(String algorithm) { 381b91773bce1126d28a93f73fbef18f3a79245f24eKenny Root final String algUpper = algorithm.toUpperCase(Locale.US); 382b91773bce1126d28a93f73fbef18f3a79245f24eKenny Root return "DSA".equals(algUpper) || "EC".equals(algUpper) || "RSA".equals(algUpper); 383bf556ac636a39c1d0fe5451a921b88400dd1c695Kenny Root } 384bf556ac636a39c1d0fe5451a921b88400dd1c695Kenny Root 385bf556ac636a39c1d0fe5451a921b88400dd1c695Kenny Root /** 386bf556ac636a39c1d0fe5451a921b88400dd1c695Kenny Root * Returns {@code true} if the current device's {@code KeyChain} binds any 387bf556ac636a39c1d0fe5451a921b88400dd1c695Kenny Root * {@code PrivateKey} of the given {@code algorithm} to the device once 388bf556ac636a39c1d0fe5451a921b88400dd1c695Kenny Root * imported or generated. This can be used to tell if there is special 389bf556ac636a39c1d0fe5451a921b88400dd1c695Kenny Root * hardware support that can be used to bind keys to the device in a way 390bf556ac636a39c1d0fe5451a921b88400dd1c695Kenny Root * that makes it non-exportable. 391bf556ac636a39c1d0fe5451a921b88400dd1c695Kenny Root */ 3925b7e90ac937857c10a3d49b244ec75ca539b9a22Kenny Root public static boolean isBoundKeyAlgorithm(String algorithm) { 3935b7e90ac937857c10a3d49b244ec75ca539b9a22Kenny Root if (!isKeyAlgorithmSupported(algorithm)) { 394bf556ac636a39c1d0fe5451a921b88400dd1c695Kenny Root return false; 395bf556ac636a39c1d0fe5451a921b88400dd1c695Kenny Root } 396bf556ac636a39c1d0fe5451a921b88400dd1c695Kenny Root 397b91773bce1126d28a93f73fbef18f3a79245f24eKenny Root return KeyStore.getInstance().isHardwareBacked(algorithm); 398bf556ac636a39c1d0fe5451a921b88400dd1c695Kenny Root } 399bf556ac636a39c1d0fe5451a921b88400dd1c695Kenny Root 400f0ae135049048424bceccb0799b12377181b25f0Zoltan Szatmary-Ban /** @hide */ 401f0ae135049048424bceccb0799b12377181b25f0Zoltan Szatmary-Ban public static X509Certificate toCertificate(byte[] bytes) { 402b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom if (bytes == null) { 4038e9929c4d0730de4c9f01435a7cfe2db8855e24dBrian Carlstrom throw new IllegalArgumentException("bytes == null"); 404b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom } 405b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom try { 406b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom CertificateFactory certFactory = CertificateFactory.getInstance("X.509"); 407b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom Certificate cert = certFactory.generateCertificate(new ByteArrayInputStream(bytes)); 408b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom return (X509Certificate) cert; 409b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom } catch (CertificateException e) { 410b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom throw new AssertionError(e); 411b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom } 412b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom } 413b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom 414d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom /** 415d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom * @hide for reuse by CertInstaller and Settings. 416d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom * @see KeyChain#bind 417d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom */ 418d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom public final static class KeyChainConnection implements Closeable { 419d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom private final Context context; 420d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom private final ServiceConnection serviceConnection; 421d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom private final IKeyChainService service; 422d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom private KeyChainConnection(Context context, 423d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom ServiceConnection serviceConnection, 424d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom IKeyChainService service) { 425d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom this.context = context; 426d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom this.serviceConnection = serviceConnection; 427d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom this.service = service; 428d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom } 429d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom @Override public void close() { 430d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom context.unbindService(serviceConnection); 431d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom } 432d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom public IKeyChainService getService() { 433d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom return service; 434d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom } 435d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom } 436d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom 437d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom /** 438d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom * @hide for reuse by CertInstaller and Settings. 439d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom * 440d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom * Caller should call unbindService on the result when finished. 441d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom */ 442d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom public static KeyChainConnection bind(Context context) throws InterruptedException { 443306fe08ce2b06671336e67a87afaa0851f0105ebRobin Lee return bindAsUser(context, Process.myUserHandle()); 444306fe08ce2b06671336e67a87afaa0851f0105ebRobin Lee } 445306fe08ce2b06671336e67a87afaa0851f0105ebRobin Lee 446306fe08ce2b06671336e67a87afaa0851f0105ebRobin Lee /** 447306fe08ce2b06671336e67a87afaa0851f0105ebRobin Lee * @hide 448306fe08ce2b06671336e67a87afaa0851f0105ebRobin Lee */ 449306fe08ce2b06671336e67a87afaa0851f0105ebRobin Lee public static KeyChainConnection bindAsUser(Context context, UserHandle user) 450306fe08ce2b06671336e67a87afaa0851f0105ebRobin Lee throws InterruptedException { 451d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom if (context == null) { 452d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom throw new NullPointerException("context == null"); 453d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom } 454d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom ensureNotOnMainThread(context); 455d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom final BlockingQueue<IKeyChainService> q = new LinkedBlockingQueue<IKeyChainService>(1); 456d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom ServiceConnection keyChainServiceConnection = new ServiceConnection() { 457ab8b84ad3847788d83da557606aa27d4102e6b52Fred Quintana volatile boolean mConnectedAtLeastOnce = false; 458d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom @Override public void onServiceConnected(ComponentName name, IBinder service) { 459ab8b84ad3847788d83da557606aa27d4102e6b52Fred Quintana if (!mConnectedAtLeastOnce) { 460ab8b84ad3847788d83da557606aa27d4102e6b52Fred Quintana mConnectedAtLeastOnce = true; 461ab8b84ad3847788d83da557606aa27d4102e6b52Fred Quintana try { 462ab8b84ad3847788d83da557606aa27d4102e6b52Fred Quintana q.put(IKeyChainService.Stub.asInterface(service)); 463ab8b84ad3847788d83da557606aa27d4102e6b52Fred Quintana } catch (InterruptedException e) { 464ab8b84ad3847788d83da557606aa27d4102e6b52Fred Quintana // will never happen, since the queue starts with one available slot 465ab8b84ad3847788d83da557606aa27d4102e6b52Fred Quintana } 466d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom } 467d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom } 468d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom @Override public void onServiceDisconnected(ComponentName name) {} 469d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom }; 470da51e68e582ffa017543982297c831680d201a91Maggie Benthall Intent intent = new Intent(IKeyChainService.class.getName()); 471da51e68e582ffa017543982297c831680d201a91Maggie Benthall ComponentName comp = intent.resolveSystemService(context.getPackageManager(), 0); 472da51e68e582ffa017543982297c831680d201a91Maggie Benthall intent.setComponent(comp); 473306fe08ce2b06671336e67a87afaa0851f0105ebRobin Lee boolean isBound = context.bindServiceAsUser(intent, 474306fe08ce2b06671336e67a87afaa0851f0105ebRobin Lee keyChainServiceConnection, 475306fe08ce2b06671336e67a87afaa0851f0105ebRobin Lee Context.BIND_AUTO_CREATE, 476306fe08ce2b06671336e67a87afaa0851f0105ebRobin Lee user); 477d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom if (!isBound) { 478d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom throw new AssertionError("could not bind to KeyChainService"); 479d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom } 480d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom return new KeyChainConnection(context, keyChainServiceConnection, q.take()); 481d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom } 482d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom 4838e9929c4d0730de4c9f01435a7cfe2db8855e24dBrian Carlstrom private static void ensureNotOnMainThread(Context context) { 484b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom Looper looper = Looper.myLooper(); 4858e9929c4d0730de4c9f01435a7cfe2db8855e24dBrian Carlstrom if (looper != null && looper == context.getMainLooper()) { 486b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom throw new IllegalStateException( 487b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom "calling this from your main thread can lead to deadlock"); 488b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom } 489b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom } 490b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom} 491