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; 2059e3baa8ab08c4da270023540ba15268c87e0d67Robin Leeimport android.annotation.WorkerThread; 21ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstromimport android.app.Activity; 2267c30dfe8e4bff11a4660ac23e8679b5deb59457Brian Carlstromimport android.app.PendingIntent; 23b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstromimport android.content.ComponentName; 24b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstromimport android.content.Context; 25b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstromimport android.content.Intent; 26b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstromimport android.content.ServiceConnection; 2739087b1cec6a54e96ab9eafe8317952720790533Robin Leeimport android.net.Uri; 28b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstromimport android.os.IBinder; 29b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstromimport android.os.Looper; 30306fe08ce2b06671336e67a87afaa0851f0105ebRobin Leeimport android.os.Process; 31b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstromimport android.os.RemoteException; 32306fe08ce2b06671336e67a87afaa0851f0105ebRobin Leeimport android.os.UserHandle; 334a0ff7ca984d29bd34b02e54441957cad65e8b53Alex Klyubinimport android.security.keystore.AndroidKeyStoreProvider; 343f8d4d840894468f2be8a5b56ff266cef2d71c50Alex Klyubinimport android.security.keystore.KeyProperties; 353f8d4d840894468f2be8a5b56ff266cef2d71c50Alex Klyubin 36b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstromimport java.io.ByteArrayInputStream; 37d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstromimport java.io.Closeable; 3893201f545b67da15cb69830a5988810aef52c0b2Brian Carlstromimport java.security.Principal; 39b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstromimport java.security.PrivateKey; 404a0ff7ca984d29bd34b02e54441957cad65e8b53Alex Klyubinimport java.security.UnrecoverableKeyException; 41b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstromimport java.security.cert.Certificate; 42b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstromimport java.security.cert.CertificateException; 43b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstromimport java.security.cert.CertificateFactory; 44b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstromimport java.security.cert.X509Certificate; 45db93b78385d694402760ad63de0795f3902030d9Brian Carlstromimport java.util.List; 46b91773bce1126d28a93f73fbef18f3a79245f24eKenny Rootimport java.util.Locale; 478e9929c4d0730de4c9f01435a7cfe2db8855e24dBrian Carlstromimport java.util.concurrent.BlockingQueue; 488e9929c4d0730de4c9f01435a7cfe2db8855e24dBrian Carlstromimport java.util.concurrent.LinkedBlockingQueue; 495423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root 5012e752225aa96888358294be0d725d499a1c9f03Kenny Rootimport com.android.org.conscrypt.TrustedCertificateStore; 51b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom 52b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom/** 5393201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * The {@code KeyChain} class provides access to private keys and 5493201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * their corresponding certificate chains in credential storage. 5593201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * 5693201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * <p>Applications accessing the {@code KeyChain} normally go through 5793201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * these steps: 5893201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * 5993201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * <ol> 6093201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * 6193201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * <li>Receive a callback from an {@link javax.net.ssl.X509KeyManager 6293201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * X509KeyManager} that a private key is requested. 6393201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * 6493201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * <li>Call {@link #choosePrivateKeyAlias 6593201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * choosePrivateKeyAlias} to allow the user to select from a 6693201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * list of currently available private keys and corresponding 6793201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * certificate chains. The chosen alias will be returned by the 6893201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * callback {@link KeyChainAliasCallback#alias}, or null if no private 6993201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * key is available or the user cancels the request. 7093201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * 7193201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * <li>Call {@link #getPrivateKey} and {@link #getCertificateChain} to 7293201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * retrieve the credentials to return to the corresponding {@link 7393201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * javax.net.ssl.X509KeyManager} callbacks. 7493201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * 7593201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * </ol> 7693201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * 7793201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * <p>An application may remember the value of a selected alias to 7893201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * avoid prompting the user with {@link #choosePrivateKeyAlias 7993201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * choosePrivateKeyAlias} on subsequent connections. If the alias is 8093201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * no longer valid, null will be returned on lookups using that value 81ca43c458ad0ee8cfa7f5eabc8ba1a65ae473976bBrian Carlstrom * 82ca43c458ad0ee8cfa7f5eabc8ba1a65ae473976bBrian Carlstrom * <p>An application can request the installation of private keys and 83ca43c458ad0ee8cfa7f5eabc8ba1a65ae473976bBrian Carlstrom * certificates via the {@code Intent} provided by {@link 84ca43c458ad0ee8cfa7f5eabc8ba1a65ae473976bBrian Carlstrom * #createInstallIntent}. Private keys installed via this {@code 85ca43c458ad0ee8cfa7f5eabc8ba1a65ae473976bBrian Carlstrom * Intent} will be accessible via {@link #choosePrivateKeyAlias} while 86ca43c458ad0ee8cfa7f5eabc8ba1a65ae473976bBrian Carlstrom * Certificate Authority (CA) certificates will be trusted by all 87ca43c458ad0ee8cfa7f5eabc8ba1a65ae473976bBrian Carlstrom * applications through the default {@code X509TrustManager}. 88b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom */ 8993201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom// TODO reference intent for credential installation when public 90b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrompublic final class KeyChain { 91b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom 92b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom /** 93b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom * @hide Also used by KeyChainService implementation 94b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom */ 95b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom public static final String ACCOUNT_TYPE = "com.android.keychain"; 96b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom 97b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom /** 98a365906e670c89674fb3383b5bcb33e682910c29Kenny Root * Package name for KeyChain chooser. 99a365906e670c89674fb3383b5bcb33e682910c29Kenny Root */ 100a365906e670c89674fb3383b5bcb33e682910c29Kenny Root private static final String KEYCHAIN_PACKAGE = "com.android.keychain"; 101a365906e670c89674fb3383b5bcb33e682910c29Kenny Root 102a365906e670c89674fb3383b5bcb33e682910c29Kenny Root /** 103a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * Action to bring up the KeyChainActivity 104a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom */ 105a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom private static final String ACTION_CHOOSER = "com.android.keychain.CHOOSER"; 106a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom 107a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom /** 1081a88d834e8f7d21e714121c011fec82369a2e9f1Kenny Root * Package name for the Certificate Installer. 1091a88d834e8f7d21e714121c011fec82369a2e9f1Kenny Root */ 1101a88d834e8f7d21e714121c011fec82369a2e9f1Kenny Root private static final String CERT_INSTALLER_PACKAGE = "com.android.certinstaller"; 1111a88d834e8f7d21e714121c011fec82369a2e9f1Kenny Root 1121a88d834e8f7d21e714121c011fec82369a2e9f1Kenny Root /** 113a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * Extra for use with {@link #ACTION_CHOOSER} 114ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom * @hide Also used by KeyChainActivity implementation 115b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom */ 116ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom public static final String EXTRA_RESPONSE = "response"; 117b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom 118b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom /** 119a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * Extra for use with {@link #ACTION_CHOOSER} 12067c30dfe8e4bff11a4660ac23e8679b5deb59457Brian Carlstrom * @hide Also used by KeyChainActivity implementation 12167c30dfe8e4bff11a4660ac23e8679b5deb59457Brian Carlstrom */ 12239087b1cec6a54e96ab9eafe8317952720790533Robin Lee public static final String EXTRA_URI = "uri"; 1233798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee 1243798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee /** 1253798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee * Extra for use with {@link #ACTION_CHOOSER} 1263798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee * @hide Also used by KeyChainActivity implementation 1273798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee */ 12867c30dfe8e4bff11a4660ac23e8679b5deb59457Brian Carlstrom public static final String EXTRA_ALIAS = "alias"; 12967c30dfe8e4bff11a4660ac23e8679b5deb59457Brian Carlstrom 13067c30dfe8e4bff11a4660ac23e8679b5deb59457Brian Carlstrom /** 131a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * Extra for use with {@link #ACTION_CHOOSER} 13267c30dfe8e4bff11a4660ac23e8679b5deb59457Brian Carlstrom * @hide Also used by KeyChainActivity implementation 13367c30dfe8e4bff11a4660ac23e8679b5deb59457Brian Carlstrom */ 13467c30dfe8e4bff11a4660ac23e8679b5deb59457Brian Carlstrom public static final String EXTRA_SENDER = "sender"; 13567c30dfe8e4bff11a4660ac23e8679b5deb59457Brian Carlstrom 13667c30dfe8e4bff11a4660ac23e8679b5deb59457Brian Carlstrom /** 13793ba4fedebb78ba47c24e8472c8960ea8fdc933aSelim Gurun * Action to bring up the CertInstaller. 138a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom */ 139a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom private static final String ACTION_INSTALL = "android.credentials.INSTALL"; 140a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom 141a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom /** 142a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * Optional extra to specify a {@code String} credential name on 143a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * the {@code Intent} returned by {@link #createInstallIntent}. 144a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom */ 145a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom // Compatible with old com.android.certinstaller.CredentialHelper.CERT_NAME_KEY 146a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom public static final String EXTRA_NAME = "name"; 147a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom 148a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom /** 149a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * Optional extra to specify an X.509 certificate to install on 150a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * the {@code Intent} returned by {@link #createInstallIntent}. 151a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * The extra value should be a PEM or ASN.1 DER encoded {@code 152a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * byte[]}. An {@link X509Certificate} can be converted to DER 153a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * encoded bytes with {@link X509Certificate#getEncoded}. 154a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * 155a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * <p>{@link #EXTRA_NAME} may be used to provide a default alias 156a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * name for the installed certificate. 157a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom */ 158a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom // Compatible with old android.security.Credentials.CERTIFICATE 159a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom public static final String EXTRA_CERTIFICATE = "CERT"; 160a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom 161a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom /** 162a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * Optional extra for use with the {@code Intent} returned by 163a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * {@link #createInstallIntent} to specify a PKCS#12 key store to 164a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * install. The extra value should be a {@code byte[]}. The bytes 165a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * may come from an external source or be generated with {@link 166ca43c458ad0ee8cfa7f5eabc8ba1a65ae473976bBrian Carlstrom * java.security.KeyStore#store} on a "PKCS12" instance. 167a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * 168a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * <p>The user will be prompted for the password to load the key store. 169a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * 170a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * <p>The key store will be scanned for {@link 171a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * java.security.KeyStore.PrivateKeyEntry} entries and both the 172a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * private key and associated certificate chain will be installed. 173a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * 174a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * <p>{@link #EXTRA_NAME} may be used to provide a default alias 175a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * name for the installed credentials. 176a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom */ 177a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom // Compatible with old android.security.Credentials.PKCS12 178a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom public static final String EXTRA_PKCS12 = "PKCS12"; 179a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom 18093ba4fedebb78ba47c24e8472c8960ea8fdc933aSelim Gurun 18193ba4fedebb78ba47c24e8472c8960ea8fdc933aSelim Gurun /** 18293ba4fedebb78ba47c24e8472c8960ea8fdc933aSelim Gurun * Broadcast Action: Indicates the trusted storage has changed. Sent when 18393ba4fedebb78ba47c24e8472c8960ea8fdc933aSelim Gurun * one of this happens: 18493ba4fedebb78ba47c24e8472c8960ea8fdc933aSelim Gurun * 18593ba4fedebb78ba47c24e8472c8960ea8fdc933aSelim Gurun * <ul> 18693ba4fedebb78ba47c24e8472c8960ea8fdc933aSelim Gurun * <li>a new CA is added, 18793ba4fedebb78ba47c24e8472c8960ea8fdc933aSelim Gurun * <li>an existing CA is removed or disabled, 18893ba4fedebb78ba47c24e8472c8960ea8fdc933aSelim Gurun * <li>a disabled CA is enabled, 18993ba4fedebb78ba47c24e8472c8960ea8fdc933aSelim Gurun * <li>trusted storage is reset (all user certs are cleared), 19093ba4fedebb78ba47c24e8472c8960ea8fdc933aSelim Gurun * <li>when permission to access a private key is changed. 19193ba4fedebb78ba47c24e8472c8960ea8fdc933aSelim Gurun * </ul> 19293ba4fedebb78ba47c24e8472c8960ea8fdc933aSelim Gurun */ 19393ba4fedebb78ba47c24e8472c8960ea8fdc933aSelim Gurun public static final String ACTION_STORAGE_CHANGED = "android.security.STORAGE_CHANGED"; 19493ba4fedebb78ba47c24e8472c8960ea8fdc933aSelim Gurun 195a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom /** 196a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * Returns an {@code Intent} that can be used for credential 197a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * installation. The intent may be used without any extras, in 198a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * which case the user will be able to install credentials from 199a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * their own source. 200a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * 201a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * <p>Alternatively, {@link #EXTRA_CERTIFICATE} or {@link 202a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * #EXTRA_PKCS12} maybe used to specify the bytes of an X.509 203a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * certificate or a PKCS#12 key store for installation. These 204ca43c458ad0ee8cfa7f5eabc8ba1a65ae473976bBrian Carlstrom * extras may be combined with {@link #EXTRA_NAME} to provide a 205a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * default alias name for credentials being installed. 206a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * 207a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * <p>When used with {@link Activity#startActivityForResult}, 208a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * {@link Activity#RESULT_OK} will be returned if a credential was 209a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * successfully installed, otherwise {@link 210a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom * Activity#RESULT_CANCELED} will be returned. 211a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom */ 21254bb1596e470144932943046ec7a99551d020ba0Alex Klyubin @NonNull 213a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom public static Intent createInstallIntent() { 214a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom Intent intent = new Intent(ACTION_INSTALL); 2151a88d834e8f7d21e714121c011fec82369a2e9f1Kenny Root intent.setClassName(CERT_INSTALLER_PACKAGE, 216a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom "com.android.certinstaller.CertInstallerMain"); 217a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom return intent; 218a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom } 219a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom 220a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom /** 221ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom * Launches an {@code Activity} for the user to select the alias 222ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom * for a private key and certificate pair for authentication. The 223ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom * selected alias or null will be returned via the 22493201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * KeyChainAliasCallback callback. 22593201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * 2263798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee * <p>The device or profile owner can intercept this before the activity 2273798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee * is shown, to pick a specific private key alias. 2283798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee * 2293798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee * <p>{@code keyTypes} and {@code issuers} may be used to 2303798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee * highlight suggested choices to the user, although to cope with 2313798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee * sometimes erroneous values provided by servers, the user may be 2323798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee * able to override these suggestions. 2333798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee * 2343798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee * <p>{@code host} and {@code port} may be used to give the user 2353798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee * more context about the server requesting the credentials. 2363798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee * 2373798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee * <p>{@code alias} allows the chooser to preselect an existing 2383798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee * alias which will still be subject to user confirmation. 2393798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee * 2403798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee * @param activity The {@link Activity} context to use for 2413798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee * launching the new sub-Activity to prompt the user to select 2423798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee * a private key; used only to call startActivity(); must not 2433798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee * be null. 2443798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee * @param response Callback to invoke when the request completes; 2453798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee * must not be null 2463798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee * @param keyTypes The acceptable types of asymmetric keys such as 2473798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee * "RSA" or "DSA", or a null array. 2483798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee * @param issuers The acceptable certificate issuers for the 2493798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee * certificate matching the private key, or null. 2503798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee * @param host The host name of the server requesting the 2513798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee * certificate, or null if unavailable. 2523798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee * @param port The port number of the server requesting the 2533798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee * certificate, or -1 if unavailable. 2543798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee * @param alias The alias to preselect if available, or null if 2553798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee * unavailable. 2563798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee */ 25754bb1596e470144932943046ec7a99551d020ba0Alex Klyubin public static void choosePrivateKeyAlias(@NonNull Activity activity, 25854bb1596e470144932943046ec7a99551d020ba0Alex Klyubin @NonNull KeyChainAliasCallback response, 2593f8d4d840894468f2be8a5b56ff266cef2d71c50Alex Klyubin @KeyProperties.KeyAlgorithmEnum String[] keyTypes, Principal[] issuers, 26054bb1596e470144932943046ec7a99551d020ba0Alex Klyubin @Nullable String host, int port, @Nullable String alias) { 26139087b1cec6a54e96ab9eafe8317952720790533Robin Lee Uri uri = null; 26239087b1cec6a54e96ab9eafe8317952720790533Robin Lee if (host != null) { 26339087b1cec6a54e96ab9eafe8317952720790533Robin Lee uri = new Uri.Builder() 26439087b1cec6a54e96ab9eafe8317952720790533Robin Lee .authority(host + (port != -1 ? ":" + port : "")) 26539087b1cec6a54e96ab9eafe8317952720790533Robin Lee .build(); 26639087b1cec6a54e96ab9eafe8317952720790533Robin Lee } 26739087b1cec6a54e96ab9eafe8317952720790533Robin Lee choosePrivateKeyAlias(activity, response, keyTypes, issuers, uri, alias); 2683798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee } 2693798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee 2703798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee /** 2713798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee * Launches an {@code Activity} for the user to select the alias 2723798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee * for a private key and certificate pair for authentication. The 2733798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee * selected alias or null will be returned via the 2743798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee * KeyChainAliasCallback callback. 2753798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee * 2763798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee * <p>The device or profile owner can intercept this before the activity 2773798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee * is shown, to pick a specific private key alias.</p> 2783798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee * 27993201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * <p>{@code keyTypes} and {@code issuers} may be used to 28093201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * highlight suggested choices to the user, although to cope with 28193201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * sometimes erroneous values provided by servers, the user may be 28293201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * able to override these suggestions. 28393201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * 28493201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * <p>{@code host} and {@code port} may be used to give the user 28593201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * more context about the server requesting the credentials. 28693201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * 28767c30dfe8e4bff11a4660ac23e8679b5deb59457Brian Carlstrom * <p>{@code alias} allows the chooser to preselect an existing 28867c30dfe8e4bff11a4660ac23e8679b5deb59457Brian Carlstrom * alias which will still be subject to user confirmation. 28967c30dfe8e4bff11a4660ac23e8679b5deb59457Brian Carlstrom * 29093201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * @param activity The {@link Activity} context to use for 29193201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * launching the new sub-Activity to prompt the user to select 29293201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * a private key; used only to call startActivity(); must not 29393201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * be null. 29493201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * @param response Callback to invoke when the request completes; 29593201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * must not be null 29693201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * @param keyTypes The acceptable types of asymmetric keys such as 297cd2329dbfa5aef82c38ffa36a478bbaf5088af92Alex Klyubin * "EC" or "RSA", or a null array. 29893201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * @param issuers The acceptable certificate issuers for the 29993201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * certificate matching the private key, or null. 30039087b1cec6a54e96ab9eafe8317952720790533Robin Lee * @param uri The full URI the server is requesting the certificate 3013798ed5e0b56ab03e7022a9922b50a4a25474033Robin Lee * for, or null if unavailable. 30267c30dfe8e4bff11a4660ac23e8679b5deb59457Brian Carlstrom * @param alias The alias to preselect if available, or null if 30367c30dfe8e4bff11a4660ac23e8679b5deb59457Brian Carlstrom * unavailable. 304b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom */ 30554bb1596e470144932943046ec7a99551d020ba0Alex Klyubin public static void choosePrivateKeyAlias(@NonNull Activity activity, 30654bb1596e470144932943046ec7a99551d020ba0Alex Klyubin @NonNull KeyChainAliasCallback response, 3073f8d4d840894468f2be8a5b56ff266cef2d71c50Alex Klyubin @KeyProperties.KeyAlgorithmEnum String[] keyTypes, Principal[] issuers, 30839087b1cec6a54e96ab9eafe8317952720790533Robin Lee @Nullable Uri uri, @Nullable String alias) { 30993201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom /* 31067c30dfe8e4bff11a4660ac23e8679b5deb59457Brian Carlstrom * TODO currently keyTypes, issuers are unused. They are meant 31167c30dfe8e4bff11a4660ac23e8679b5deb59457Brian Carlstrom * to follow the semantics and purpose of X509KeyManager 31267c30dfe8e4bff11a4660ac23e8679b5deb59457Brian Carlstrom * method arguments. 31393201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * 31493201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * keyTypes would allow the list to be filtered and typically 31593201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * will be set correctly by the server. In practice today, 316cd2329dbfa5aef82c38ffa36a478bbaf5088af92Alex Klyubin * most all users will want only RSA or EC, and usually 31793201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * only a small number of certs will be available. 31893201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * 31993201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * issuers is typically not useful. Some servers historically 32093201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * will send the entire list of public CAs known to the 32193201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * server. Others will send none. If this is used, if there 32293201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * are no matches after applying the constraint, it should be 32393201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * ignored. 32493201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom */ 325ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom if (activity == null) { 326ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom throw new NullPointerException("activity == null"); 327b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom } 328ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom if (response == null) { 329ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom throw new NullPointerException("response == null"); 330ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom } 331a00a2b33ccc6bc079c3ee57a938f62947b48a001Brian Carlstrom Intent intent = new Intent(ACTION_CHOOSER); 332a365906e670c89674fb3383b5bcb33e682910c29Kenny Root intent.setPackage(KEYCHAIN_PACKAGE); 333ab8b84ad3847788d83da557606aa27d4102e6b52Fred Quintana intent.putExtra(EXTRA_RESPONSE, new AliasResponse(response)); 33439087b1cec6a54e96ab9eafe8317952720790533Robin Lee intent.putExtra(EXTRA_URI, uri); 33567c30dfe8e4bff11a4660ac23e8679b5deb59457Brian Carlstrom intent.putExtra(EXTRA_ALIAS, alias); 33667c30dfe8e4bff11a4660ac23e8679b5deb59457Brian Carlstrom // the PendingIntent is used to get calling package name 33767c30dfe8e4bff11a4660ac23e8679b5deb59457Brian Carlstrom intent.putExtra(EXTRA_SENDER, PendingIntent.getActivity(activity, 0, new Intent(), 0)); 338ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom activity.startActivity(intent); 339ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom } 340ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom 34193201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom private static class AliasResponse extends IKeyChainAliasCallback.Stub { 34293201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom private final KeyChainAliasCallback keyChainAliasResponse; 343ab8b84ad3847788d83da557606aa27d4102e6b52Fred Quintana private AliasResponse(KeyChainAliasCallback keyChainAliasResponse) { 344ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom this.keyChainAliasResponse = keyChainAliasResponse; 345ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom } 346ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom @Override public void alias(String alias) { 347ab8b84ad3847788d83da557606aa27d4102e6b52Fred Quintana keyChainAliasResponse.alias(alias); 348ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom } 349ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom } 350b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom 351ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom /** 352ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom * Returns the {@code PrivateKey} for the requested alias, or null 353ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom * if no there is no result. 35493201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * 35559e3baa8ab08c4da270023540ba15268c87e0d67Robin Lee * <p> This method may block while waiting for a connection to another process, and must never 35659e3baa8ab08c4da270023540ba15268c87e0d67Robin Lee * be called from the main thread. 35759e3baa8ab08c4da270023540ba15268c87e0d67Robin Lee * 35859e3baa8ab08c4da270023540ba15268c87e0d67Robin Lee * @param alias The alias of the desired private key, typically returned via 35959e3baa8ab08c4da270023540ba15268c87e0d67Robin Lee * {@link KeyChainAliasCallback#alias}. 36093201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * @throws KeyChainException if the alias was valid but there was some problem accessing it. 36159e3baa8ab08c4da270023540ba15268c87e0d67Robin Lee * @throws IllegalStateException if called from the main thread. 362ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom */ 36359e3baa8ab08c4da270023540ba15268c87e0d67Robin Lee @Nullable @WorkerThread 36454bb1596e470144932943046ec7a99551d020ba0Alex Klyubin public static PrivateKey getPrivateKey(@NonNull Context context, @NonNull String alias) 36593201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom throws KeyChainException, InterruptedException { 366ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom if (alias == null) { 367ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom throw new NullPointerException("alias == null"); 368ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom } 369ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom KeyChainConnection keyChainConnection = bind(context); 370ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom try { 3715423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root final IKeyChainService keyChainService = keyChainConnection.getService(); 3725423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root final String keyId = keyChainService.requestPrivateKey(alias); 3735423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root if (keyId == null) { 3745423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root throw new KeyChainException("keystore had a problem"); 3755423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root } 3764a0ff7ca984d29bd34b02e54441957cad65e8b53Alex Klyubin return AndroidKeyStoreProvider.loadAndroidKeyStorePrivateKeyFromKeystore( 3774a0ff7ca984d29bd34b02e54441957cad65e8b53Alex Klyubin KeyStore.getInstance(), keyId); 37893201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom } catch (RemoteException e) { 37993201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom throw new KeyChainException(e); 38093201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom } catch (RuntimeException e) { 38193201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom // only certain RuntimeExceptions can be propagated across the IKeyChainService call 38293201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom throw new KeyChainException(e); 3834a0ff7ca984d29bd34b02e54441957cad65e8b53Alex Klyubin } catch (UnrecoverableKeyException e) { 3845423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root throw new KeyChainException(e); 385ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom } finally { 386ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom keyChainConnection.close(); 387ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom } 388ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom } 389ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom 390ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom /** 391ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom * Returns the {@code X509Certificate} chain for the requested 392ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom * alias, or null if no there is no result. 39393201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * 39459e3baa8ab08c4da270023540ba15268c87e0d67Robin Lee * <p> This method may block while waiting for a connection to another process, and must never 39559e3baa8ab08c4da270023540ba15268c87e0d67Robin Lee * be called from the main thread. 39659e3baa8ab08c4da270023540ba15268c87e0d67Robin Lee * 39793201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * @param alias The alias of the desired certificate chain, typically 39893201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * returned via {@link KeyChainAliasCallback#alias}. 39993201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom * @throws KeyChainException if the alias was valid but there was some problem accessing it. 40059e3baa8ab08c4da270023540ba15268c87e0d67Robin Lee * @throws IllegalStateException if called from the main thread. 401ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom */ 40259e3baa8ab08c4da270023540ba15268c87e0d67Robin Lee @Nullable @WorkerThread 40354bb1596e470144932943046ec7a99551d020ba0Alex Klyubin public static X509Certificate[] getCertificateChain(@NonNull Context context, 40454bb1596e470144932943046ec7a99551d020ba0Alex Klyubin @NonNull String alias) throws KeyChainException, InterruptedException { 405ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom if (alias == null) { 406ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom throw new NullPointerException("alias == null"); 407ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom } 408ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom KeyChainConnection keyChainConnection = bind(context); 409ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom try { 410ba1a667b1d6c95050f6c88316ac58fe9e0ff878bBrian Carlstrom IKeyChainService keyChainService = keyChainConnection.getService(); 4110150e48200a967aead3c2ac6f1283ae2df54c305Kenny Root 4120150e48200a967aead3c2ac6f1283ae2df54c305Kenny Root final byte[] certificateBytes = keyChainService.getCertificate(alias); 4130150e48200a967aead3c2ac6f1283ae2df54c305Kenny Root if (certificateBytes == null) { 4140150e48200a967aead3c2ac6f1283ae2df54c305Kenny Root return null; 4150150e48200a967aead3c2ac6f1283ae2df54c305Kenny Root } 4160150e48200a967aead3c2ac6f1283ae2df54c305Kenny Root 417db93b78385d694402760ad63de0795f3902030d9Brian Carlstrom TrustedCertificateStore store = new TrustedCertificateStore(); 41854e03afcfe34e9875efa56650c1af3ebc8f58a89Kenny Root List<X509Certificate> chain = store 41954e03afcfe34e9875efa56650c1af3ebc8f58a89Kenny Root .getCertificateChain(toCertificate(certificateBytes)); 420db93b78385d694402760ad63de0795f3902030d9Brian Carlstrom return chain.toArray(new X509Certificate[chain.size()]); 421cfba6a07fd24559bfb6bb51007520b8ca3cd5c48Kenny Root } catch (CertificateException e) { 422cfba6a07fd24559bfb6bb51007520b8ca3cd5c48Kenny Root throw new KeyChainException(e); 42393201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom } catch (RemoteException e) { 42493201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom throw new KeyChainException(e); 42593201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom } catch (RuntimeException e) { 42693201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom // only certain RuntimeExceptions can be propagated across the IKeyChainService call 42793201f545b67da15cb69830a5988810aef52c0b2Brian Carlstrom throw new KeyChainException(e); 4288e9929c4d0730de4c9f01435a7cfe2db8855e24dBrian Carlstrom } finally { 429d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom keyChainConnection.close(); 430b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom } 431b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom } 432b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom 433bf556ac636a39c1d0fe5451a921b88400dd1c695Kenny Root /** 434bf556ac636a39c1d0fe5451a921b88400dd1c695Kenny Root * Returns {@code true} if the current device's {@code KeyChain} supports a 435bf556ac636a39c1d0fe5451a921b88400dd1c695Kenny Root * specific {@code PrivateKey} type indicated by {@code algorithm} (e.g., 436bf556ac636a39c1d0fe5451a921b88400dd1c695Kenny Root * "RSA"). 437bf556ac636a39c1d0fe5451a921b88400dd1c695Kenny Root */ 4384d5443f37f2bc58be8d22ed50024c39a5a1fbc8fAlex Klyubin public static boolean isKeyAlgorithmSupported( 4393f8d4d840894468f2be8a5b56ff266cef2d71c50Alex Klyubin @NonNull @KeyProperties.KeyAlgorithmEnum String algorithm) { 440b91773bce1126d28a93f73fbef18f3a79245f24eKenny Root final String algUpper = algorithm.toUpperCase(Locale.US); 4413f8d4d840894468f2be8a5b56ff266cef2d71c50Alex Klyubin return KeyProperties.KEY_ALGORITHM_EC.equals(algUpper) 4423f8d4d840894468f2be8a5b56ff266cef2d71c50Alex Klyubin || KeyProperties.KEY_ALGORITHM_RSA.equals(algUpper); 443bf556ac636a39c1d0fe5451a921b88400dd1c695Kenny Root } 444bf556ac636a39c1d0fe5451a921b88400dd1c695Kenny Root 445bf556ac636a39c1d0fe5451a921b88400dd1c695Kenny Root /** 446bf556ac636a39c1d0fe5451a921b88400dd1c695Kenny Root * Returns {@code true} if the current device's {@code KeyChain} binds any 447bf556ac636a39c1d0fe5451a921b88400dd1c695Kenny Root * {@code PrivateKey} of the given {@code algorithm} to the device once 448bf556ac636a39c1d0fe5451a921b88400dd1c695Kenny Root * imported or generated. This can be used to tell if there is special 449bf556ac636a39c1d0fe5451a921b88400dd1c695Kenny Root * hardware support that can be used to bind keys to the device in a way 450bf556ac636a39c1d0fe5451a921b88400dd1c695Kenny Root * that makes it non-exportable. 451469cbf5156ad54650726ade59f2ee5aa01359ec2Alex Klyubin * 452469cbf5156ad54650726ade59f2ee5aa01359ec2Alex Klyubin * @deprecated Whether the key is bound to the secure hardware is known only 453469cbf5156ad54650726ade59f2ee5aa01359ec2Alex Klyubin * once the key has been imported. To find out, use: 454469cbf5156ad54650726ade59f2ee5aa01359ec2Alex Klyubin * <pre>{@code 455469cbf5156ad54650726ade59f2ee5aa01359ec2Alex Klyubin * PrivateKey key = ...; // private key from KeyChain 456469cbf5156ad54650726ade59f2ee5aa01359ec2Alex Klyubin * 457469cbf5156ad54650726ade59f2ee5aa01359ec2Alex Klyubin * KeyFactory keyFactory = 458469cbf5156ad54650726ade59f2ee5aa01359ec2Alex Klyubin * KeyFactory.getInstance(key.getAlgorithm(), "AndroidKeyStore"); 459469cbf5156ad54650726ade59f2ee5aa01359ec2Alex Klyubin * KeyInfo keyInfo = keyFactory.getKeySpec(key, KeyInfo.class); 460469cbf5156ad54650726ade59f2ee5aa01359ec2Alex Klyubin * if (keyInfo.isInsideSecureHardware()) { 461469cbf5156ad54650726ade59f2ee5aa01359ec2Alex Klyubin * // The key is bound to the secure hardware of this Android 462469cbf5156ad54650726ade59f2ee5aa01359ec2Alex Klyubin * }}</pre> 463bf556ac636a39c1d0fe5451a921b88400dd1c695Kenny Root */ 464469cbf5156ad54650726ade59f2ee5aa01359ec2Alex Klyubin @Deprecated 4654d5443f37f2bc58be8d22ed50024c39a5a1fbc8fAlex Klyubin public static boolean isBoundKeyAlgorithm( 4663f8d4d840894468f2be8a5b56ff266cef2d71c50Alex Klyubin @NonNull @KeyProperties.KeyAlgorithmEnum String algorithm) { 4675b7e90ac937857c10a3d49b244ec75ca539b9a22Kenny Root if (!isKeyAlgorithmSupported(algorithm)) { 468bf556ac636a39c1d0fe5451a921b88400dd1c695Kenny Root return false; 469bf556ac636a39c1d0fe5451a921b88400dd1c695Kenny Root } 470bf556ac636a39c1d0fe5451a921b88400dd1c695Kenny Root 471b91773bce1126d28a93f73fbef18f3a79245f24eKenny Root return KeyStore.getInstance().isHardwareBacked(algorithm); 472bf556ac636a39c1d0fe5451a921b88400dd1c695Kenny Root } 473bf556ac636a39c1d0fe5451a921b88400dd1c695Kenny Root 474f0ae135049048424bceccb0799b12377181b25f0Zoltan Szatmary-Ban /** @hide */ 47554bb1596e470144932943046ec7a99551d020ba0Alex Klyubin @NonNull 47654bb1596e470144932943046ec7a99551d020ba0Alex Klyubin public static X509Certificate toCertificate(@NonNull byte[] bytes) { 477b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom if (bytes == null) { 4788e9929c4d0730de4c9f01435a7cfe2db8855e24dBrian Carlstrom throw new IllegalArgumentException("bytes == null"); 479b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom } 480b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom try { 481b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom CertificateFactory certFactory = CertificateFactory.getInstance("X.509"); 482b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom Certificate cert = certFactory.generateCertificate(new ByteArrayInputStream(bytes)); 483b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom return (X509Certificate) cert; 484b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom } catch (CertificateException e) { 485b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom throw new AssertionError(e); 486b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom } 487b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom } 488b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom 489d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom /** 490d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom * @hide for reuse by CertInstaller and Settings. 491d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom * @see KeyChain#bind 492d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom */ 493d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom public final static class KeyChainConnection implements Closeable { 494d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom private final Context context; 495d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom private final ServiceConnection serviceConnection; 496d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom private final IKeyChainService service; 497d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom private KeyChainConnection(Context context, 498d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom ServiceConnection serviceConnection, 499d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom IKeyChainService service) { 500d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom this.context = context; 501d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom this.serviceConnection = serviceConnection; 502d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom this.service = service; 503d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom } 504d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom @Override public void close() { 505d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom context.unbindService(serviceConnection); 506d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom } 507d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom public IKeyChainService getService() { 508d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom return service; 509d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom } 510d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom } 511d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom 512d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom /** 513d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom * @hide for reuse by CertInstaller and Settings. 514d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom * 515d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom * Caller should call unbindService on the result when finished. 516d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom */ 51759e3baa8ab08c4da270023540ba15268c87e0d67Robin Lee @WorkerThread 51854bb1596e470144932943046ec7a99551d020ba0Alex Klyubin public static KeyChainConnection bind(@NonNull Context context) throws InterruptedException { 519306fe08ce2b06671336e67a87afaa0851f0105ebRobin Lee return bindAsUser(context, Process.myUserHandle()); 520306fe08ce2b06671336e67a87afaa0851f0105ebRobin Lee } 521306fe08ce2b06671336e67a87afaa0851f0105ebRobin Lee 522306fe08ce2b06671336e67a87afaa0851f0105ebRobin Lee /** 523306fe08ce2b06671336e67a87afaa0851f0105ebRobin Lee * @hide 524306fe08ce2b06671336e67a87afaa0851f0105ebRobin Lee */ 52559e3baa8ab08c4da270023540ba15268c87e0d67Robin Lee @WorkerThread 52654bb1596e470144932943046ec7a99551d020ba0Alex Klyubin public static KeyChainConnection bindAsUser(@NonNull Context context, UserHandle user) 527306fe08ce2b06671336e67a87afaa0851f0105ebRobin Lee throws InterruptedException { 528d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom if (context == null) { 529d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom throw new NullPointerException("context == null"); 530d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom } 531d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom ensureNotOnMainThread(context); 532d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom final BlockingQueue<IKeyChainService> q = new LinkedBlockingQueue<IKeyChainService>(1); 533d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom ServiceConnection keyChainServiceConnection = new ServiceConnection() { 534ab8b84ad3847788d83da557606aa27d4102e6b52Fred Quintana volatile boolean mConnectedAtLeastOnce = false; 535d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom @Override public void onServiceConnected(ComponentName name, IBinder service) { 536ab8b84ad3847788d83da557606aa27d4102e6b52Fred Quintana if (!mConnectedAtLeastOnce) { 537ab8b84ad3847788d83da557606aa27d4102e6b52Fred Quintana mConnectedAtLeastOnce = true; 538ab8b84ad3847788d83da557606aa27d4102e6b52Fred Quintana try { 539ab8b84ad3847788d83da557606aa27d4102e6b52Fred Quintana q.put(IKeyChainService.Stub.asInterface(service)); 540ab8b84ad3847788d83da557606aa27d4102e6b52Fred Quintana } catch (InterruptedException e) { 541ab8b84ad3847788d83da557606aa27d4102e6b52Fred Quintana // will never happen, since the queue starts with one available slot 542ab8b84ad3847788d83da557606aa27d4102e6b52Fred Quintana } 543d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom } 544d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom } 545d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom @Override public void onServiceDisconnected(ComponentName name) {} 546d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom }; 547da51e68e582ffa017543982297c831680d201a91Maggie Benthall Intent intent = new Intent(IKeyChainService.class.getName()); 548da51e68e582ffa017543982297c831680d201a91Maggie Benthall ComponentName comp = intent.resolveSystemService(context.getPackageManager(), 0); 549da51e68e582ffa017543982297c831680d201a91Maggie Benthall intent.setComponent(comp); 550306fe08ce2b06671336e67a87afaa0851f0105ebRobin Lee boolean isBound = context.bindServiceAsUser(intent, 551306fe08ce2b06671336e67a87afaa0851f0105ebRobin Lee keyChainServiceConnection, 552306fe08ce2b06671336e67a87afaa0851f0105ebRobin Lee Context.BIND_AUTO_CREATE, 553306fe08ce2b06671336e67a87afaa0851f0105ebRobin Lee user); 554d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom if (!isBound) { 555d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom throw new AssertionError("could not bind to KeyChainService"); 556d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom } 557d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom return new KeyChainConnection(context, keyChainServiceConnection, q.take()); 558d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom } 559d752472d9abf03fda637d43716bc6bd632e1f5c3Brian Carlstrom 56054bb1596e470144932943046ec7a99551d020ba0Alex Klyubin private static void ensureNotOnMainThread(@NonNull Context context) { 561b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom Looper looper = Looper.myLooper(); 5628e9929c4d0730de4c9f01435a7cfe2db8855e24dBrian Carlstrom if (looper != null && looper == context.getMainLooper()) { 563b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom throw new IllegalStateException( 564b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom "calling this from your main thread can lead to deadlock"); 565b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom } 566b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom } 567b9a07c18e678da35b4c2a618b315fa174a21e818Brian Carlstrom} 568