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