KeyChain.java revision 3876b1be27e3aefde9a72eb2e4f856e94fc5f946
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(
3773876b1be27e3aefde9a72eb2e4f856e94fc5f946Alex Klyubin                    KeyStore.getInstance(), keyId, KeyStore.UID_SELF);
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()) &#123;
461469cbf5156ad54650726ade59f2ee5aa01359ec2Alex Klyubin     *     // The key is bound to the secure hardware of this Android
462469cbf5156ad54650726ade59f2ee5aa01359ec2Alex Klyubin     * &#125;}</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