181ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry/*
281ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry * Copyright (C) 2017 The Android Open Source Project
381ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry *
481ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry * Licensed under the Apache License, Version 2.0 (the "License");
581ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry * you may not use this file except in compliance with the License.
681ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry * You may obtain a copy of the License at
781ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry *
881ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry *      http://www.apache.org/licenses/LICENSE-2.0
981ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry *
1081ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry * Unless required by applicable law or agreed to in writing, software
1181ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry * distributed under the License is distributed on an "AS IS" BASIS,
1281ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1381ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry * See the License for the specific language governing permissions and
1481ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry * limitations under the License.
1581ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry */
1681ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry
1781ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berrypackage android.security.keystore.recovery;
1881ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry
1981ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berryimport android.annotation.NonNull;
2081ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berryimport android.annotation.Nullable;
210916e7ca44aba5e6c89d75007da805697fdace9eDmitry Dementyevimport android.annotation.RequiresPermission;
22f8ae5deba2911b7bc8441df31c0504eaaa687addDmitry Dementyevimport android.annotation.SystemApi;
23b95c90ce2d10a93c680b2ddbdf7ad61feb3abf5aBo Zhuimport android.app.KeyguardManager;
2481ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berryimport android.app.PendingIntent;
250916e7ca44aba5e6c89d75007da805697fdace9eDmitry Dementyevimport android.content.Context;
2681ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berryimport android.content.pm.PackageManager.NameNotFoundException;
2781ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berryimport android.os.RemoteException;
2881ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berryimport android.os.ServiceManager;
2981ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berryimport android.os.ServiceSpecificException;
3029b9de5b8a9b38290c2855890ae1f7a93c0b8421Dmitry Dementyevimport android.security.KeyStore;
3129b9de5b8a9b38290c2855890ae1f7a93c0b8421Dmitry Dementyevimport android.security.keystore.AndroidKeyStoreProvider;
3281ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry
3381ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berryimport com.android.internal.widget.ILockSettings;
3481ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry
3529b9de5b8a9b38290c2855890ae1f7a93c0b8421Dmitry Dementyevimport java.security.Key;
3629b9de5b8a9b38290c2855890ae1f7a93c0b8421Dmitry Dementyevimport java.security.UnrecoverableKeyException;
37c1742e51378c3ec99a0e5df14dc0c77bcca0d16aAseem Kumarimport java.security.cert.CertPath;
380916e7ca44aba5e6c89d75007da805697fdace9eDmitry Dementyevimport java.security.cert.CertificateException;
3993d002ca5f94facfec75359999c910f914d7b7c4Robert Berryimport java.security.cert.X509Certificate;
400916e7ca44aba5e6c89d75007da805697fdace9eDmitry Dementyevimport java.util.ArrayList;
4181ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berryimport java.util.List;
4281ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berryimport java.util.Map;
4381ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry
4481ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry/**
4593f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry * Backs up cryptographic keys to remote secure hardware, encrypted with the user's lock screen.
4681ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry *
4741d2dd2f266eb8dc50afcda253f04f1c7e9ccc0eBo Zhu * <p>A system app with the {@code android.permission.RECOVER_KEYSTORE} permission may generate or
4893f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry * import recoverable keys using this class. To generate a key, the app must call
4993f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry * {@link #generateKey(String)} with the desired alias for the key. This returns an AndroidKeyStore
5093f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry * reference to a 256-bit {@link javax.crypto.SecretKey}, which can be used for AES/GCM/NoPadding.
5193f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry * In order to get the same key again at a later time, the app can call {@link #getKey(String)} with
5293f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry * the same alias. If a key is generated in this way the key's raw material is never directly
5393f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry * exposed to the calling app. The system app may also import key material using
5493f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry * {@link #importKey(String, byte[])}. The app may only generate and import keys for its own
5593f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry * {@code uid}.
5681ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry *
5793f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry * <p>The same system app must also register a Recovery Agent to manage syncing recoverable keys to
5893f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry * remote secure hardware. The Recovery Agent is a service that registers itself with the controller
5993f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry * as follows:
6081ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry *
6193f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry * <ul>
6293f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry *     <li>Invokes {@link #initRecoveryService(String, byte[], byte[])}
6393f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry *     <ul>
6493f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry *         <li>The first argument is the alias of the root certificate used to verify trusted
6593f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry *         hardware modules. Each trusted hardware module must have a public key signed with this
6693f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry *         root of trust. Roots of trust must be shipped with the framework. The app can list all
6793f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry *         valid roots of trust by calling {@link #getRootCertificates()}.
6893f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry *         <li>The second argument is the UTF-8 bytes of the XML listing file. It lists the X509
6993f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry *         certificates containing the public keys of all available remote trusted hardware modules.
7093f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry *         Each of the X509 certificates can be validated against the chosen root of trust.
7193f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry *         <li>The third argument is the UTF-8 bytes of the XML signing file. The file contains a
7293f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry *         signature of the XML listing file. The signature can be validated against the chosen root
7393f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry *         of trust.
7493f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry *     </ul>
7593f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry *     <p>This will cause the controller to choose a random public key from the list. From then
7693f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry *     on the controller will attempt to sync the key chain with the trusted hardware module to whom
7793f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry *     that key belongs.
7893f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry *     <li>Invokes {@link #setServerParams(byte[])} with a byte string that identifies the device
7993f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry *     to a remote server. This server may act as the front-end to the trusted hardware modules. It
8093f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry *     is up to the Recovery Agent to decide how best to identify devices, but this could be, e.g.,
8193f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry *     based on the <a href="https://developers.google.com/instance-id/">Instance ID</a> of the
8293f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry *     system app.
8393f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry *     <li>Invokes {@link #setRecoverySecretTypes(int[])} with a list of types of secret used to
8493f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry *     secure the recoverable key chain. For now only
8593f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry *     {@link KeyChainProtectionParams#TYPE_LOCKSCREEN} is supported.
8693f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry *     <li>Invokes {@link #setSnapshotCreatedPendingIntent(PendingIntent)} with a
8793f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry *     {@link PendingIntent} that is to be invoked whenever a new snapshot is created. Although the
8893f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry *     controller can create snapshots without the Recovery Agent registering this intent, it is a
8993f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry *     good idea to register the intent so that the Recovery Agent is able to sync this snapshot to
9093f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry *     the trusted hardware module as soon as it is available.
9193f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry * </ul>
9293f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry *
9393f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry * <p>The trusted hardware module's public key MUST be generated on secure hardware with protections
9493f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry * equivalent to those described in the
9593f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry * <a href="https://developer.android.com/preview/features/security/ckv-whitepaper.html">Google
9693f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry * Cloud Key Vault Service whitepaper</a>. The trusted hardware module itself must protect the key
9793f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry * chain from brute-forcing using the methods also described in the whitepaper: i.e., it should
9893f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry * limit the number of allowed attempts to enter the lock screen. If the number of attempts is
9993f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry * exceeded the key material must no longer be recoverable.
10093f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry *
10193f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry * <p>A recoverable key chain snapshot is considered pending if any of the following conditions
10293f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry * are met:
10393f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry *
10493f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry * <ul>
10593f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry *     <li>The system app mutates the key chain. i.e., generates, imports, or removes a key.
10693f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry *     <li>The user changes their lock screen.
10793f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry * </ul>
10893f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry *
10993f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry * <p>Whenever the user unlocks their device, if a snapshot is pending, the Recovery Controller
11093f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry * generates a new snapshot. It follows these steps to do so:
11193f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry *
11293f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry * <ul>
11393f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry *     <li>Generates a 256-bit AES key using {@link java.security.SecureRandom}. This is the
11493f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry *     Recovery Key.
11593f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry *     <li>Wraps the key material of all keys in the recoverable key chain with the Recovery Key.
11693f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry *     <li>Encrypts the Recovery Key with both the public key of the trusted hardware module and a
11793f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry *     symmetric key derived from the user's lock screen.
11893f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry * </ul>
11993f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry *
12093f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry * <p>The controller then writes this snapshot to disk, and uses the {@link PendingIntent} that was
12193f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry * set by the Recovery Agent during initialization to inform it that a new snapshot is available.
12293f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry * The snapshot only contains keys for that Recovery Agent's {@code uid} - i.e., keys the agent's
12393f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry * app itself generated. If multiple Recovery Agents exist on the device, each will be notified of
12493f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry * their new snapshots, and each snapshots' keys will be only those belonging to the same
12593f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry * {@code uid}.
12693f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry *
12793f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry * <p>The Recovery Agent retrieves its most recent snapshot by calling
12893f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry * {@link #getKeyChainSnapshot()}. It syncs the snapshot to the remote server. The snapshot contains
12993f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry * the public key used for encryption, which the server uses to forward the encrypted recovery key
13093f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry * to the correct trusted hardware module. The snapshot also contains the server params, which are
13193f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry * used to identify this device to the server.
13293f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry *
13393f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry * <p>The client uses the server params to identify a device whose key chain it wishes to restore.
13493f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry * This may be on a different device to the device that originally synced the key chain. The client
13593f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry * sends the server params identifying the previous device to the server. The server returns the
13693f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry * X509 certificate identifying the trusted hardware module in which the encrypted Recovery Key is
13793f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry * stored. It also returns some vault parameters identifying that particular Recovery Key to the
13893f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry * trusted hardware module. And it also returns a vault challenge, which is used as part of the
13993f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry * vault opening protocol to ensure the recovery claim is fresh. See the whitepaper for more
14093f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry * details.
14193f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry *
14293f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry * <p>The key chain is recovered via a {@link RecoverySession}. A Recovery Agent creates one by
14393f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry * invoking {@link #createRecoverySession()}. It then invokes
14493f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry * {@link RecoverySession#start(String, CertPath, byte[], byte[], List)} with these arguments:
14593f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry *
14693f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry * <ul>
14793f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry *     <li>The alias of the root of trust used to verify the trusted hardware module.
14893f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry *     <li>The X509 certificate of the trusted hardware module.
14993f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry *     <li>The vault parameters used to identify the Recovery Key to the trusted hardware module.
15093f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry *     <li>The vault challenge, as issued by the trusted hardware module.
15193f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry *     <li>A list of secrets, corresponding to the secrets used to protect the key chain. At the
15293f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry *     moment this is a single {@link KeyChainProtectionParams} containing the lock screen of the
15393f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry *     device whose key chain is to be recovered.
15493f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry * </ul>
15593f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry *
15693f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry * <p>This method returns a byte array containing the Recovery Claim, which can be issued to the
15793f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry * remote trusted hardware module. It is encrypted with the trusted hardware module's public key
15893f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry * (which has itself been certified with the root of trust). It also contains an ephemeral symmetric
15993f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry * key generated for this recovery session, which the remote trusted hardware module uses to encrypt
16093f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry * its responses. This is the Session Key.
16193f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry *
16293f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry * <p>If the lock screen provided is correct, the remote trusted hardware module decrypts one of the
16393f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry * layers of lock-screen encryption from the Recovery Key. It then returns this key, encrypted with
16493f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry * the Session Key to the Recovery Agent. As the Recovery Agent does not know the Session Key, it
16593f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry * must then invoke {@link RecoverySession#recoverKeyChainSnapshot(byte[], List)} with the encrypted
16693f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry * Recovery Key and the list of wrapped application keys. The controller then decrypts the layer of
16793f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry * encryption provided by the Session Key, and uses the lock screen to decrypt the final layer of
16893f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry * encryption. It then uses the Recovery Key to decrypt all of the wrapped application keys, and
16993f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry * imports them into its own KeyStore. The Recovery Agent's app may then access these keys by
17093f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry * calling {@link #getKey(String)}. Only this app's {@code uid} may access the keys that have been
17193f38d7b3a5bda2bd9bcc7def67936370b40e306Robert Berry * recovered.
17281ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry *
17381ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry * @hide
17481ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry */
175f8ae5deba2911b7bc8441df31c0504eaaa687addDmitry Dementyev@SystemApi
17681ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berrypublic class RecoveryController {
17781ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry    private static final String TAG = "RecoveryController";
17881ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry
17981ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry    /** Key has been successfully synced. */
18081ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry    public static final int RECOVERY_STATUS_SYNCED = 0;
18181ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry    /** Waiting for recovery agent to sync the key. */
18281ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry    public static final int RECOVERY_STATUS_SYNC_IN_PROGRESS = 1;
18381ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry    /** Key cannot be synced. */
18481ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry    public static final int RECOVERY_STATUS_PERMANENT_FAILURE = 3;
18581ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry
18681ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry    /**
18781ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry     * Failed because no snapshot is yet pending to be synced for the user.
18881ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry     *
18981ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry     * @hide
19081ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry     */
19181ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry    public static final int ERROR_NO_SNAPSHOT_PENDING = 21;
19281ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry
19381ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry    /**
19481ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry     * Failed due to an error internal to the recovery service. This is unexpected and indicates
19581ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry     * either a problem with the logic in the service, or a problem with a dependency of the
19681ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry     * service (such as AndroidKeyStore).
19781ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry     *
19881ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry     * @hide
19981ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry     */
20081ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry    public static final int ERROR_SERVICE_INTERNAL_ERROR = 22;
20181ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry
20281ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry    /**
20381ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry     * Failed because the user does not have a lock screen set.
20481ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry     *
20581ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry     * @hide
20681ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry     */
20781ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry    public static final int ERROR_INSECURE_USER = 23;
20881ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry
20981ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry    /**
21081ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry     * Error thrown when attempting to use a recovery session that has since been closed.
21181ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry     *
21281ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry     * @hide
21381ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry     */
21481ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry    public static final int ERROR_SESSION_EXPIRED = 24;
21581ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry
21681ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry    /**
2177f414d94fc4f6bd34325f3865b51e8d11acb52adBo Zhu     * Failed because the format of the provided certificate is incorrect, e.g., cannot be decoded
2187f414d94fc4f6bd34325f3865b51e8d11acb52adBo Zhu     * properly or misses necessary fields.
2197f414d94fc4f6bd34325f3865b51e8d11acb52adBo Zhu     *
2207f414d94fc4f6bd34325f3865b51e8d11acb52adBo Zhu     * <p>Note that this is different from {@link #ERROR_INVALID_CERTIFICATE}, which implies the
2217f414d94fc4f6bd34325f3865b51e8d11acb52adBo Zhu     * certificate has a correct format but cannot be validated.
22281ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry     *
22381ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry     * @hide
22481ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry     */
22581ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry    public static final int ERROR_BAD_CERTIFICATE_FORMAT = 25;
22681ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry
22781ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry    /**
22881ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry     * Error thrown if decryption failed. This might be because the tag is wrong, the key is wrong,
22981ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry     * the data has become corrupted, the data has been tampered with, etc.
23081ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry     *
23181ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry     * @hide
23281ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry     */
23381ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry    public static final int ERROR_DECRYPTION_FAILED = 26;
23481ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry
2352c8e5383c836d2dfa39b0be6bfa281285667a880Bo Zhu    /**
2362c8e5383c836d2dfa39b0be6bfa281285667a880Bo Zhu     * Error thrown if the format of a given key is invalid. This might be because the key has a
2372c8e5383c836d2dfa39b0be6bfa281285667a880Bo Zhu     * wrong length, invalid content, etc.
2382c8e5383c836d2dfa39b0be6bfa281285667a880Bo Zhu     *
2392c8e5383c836d2dfa39b0be6bfa281285667a880Bo Zhu     * @hide
2402c8e5383c836d2dfa39b0be6bfa281285667a880Bo Zhu     */
2412c8e5383c836d2dfa39b0be6bfa281285667a880Bo Zhu    public static final int ERROR_INVALID_KEY_FORMAT = 27;
2422c8e5383c836d2dfa39b0be6bfa281285667a880Bo Zhu
2437f414d94fc4f6bd34325f3865b51e8d11acb52adBo Zhu    /**
2447f414d94fc4f6bd34325f3865b51e8d11acb52adBo Zhu     * Failed because the provided certificate cannot be validated, e.g., is expired or has invalid
2457f414d94fc4f6bd34325f3865b51e8d11acb52adBo Zhu     * signatures.
2467f414d94fc4f6bd34325f3865b51e8d11acb52adBo Zhu     *
2477f414d94fc4f6bd34325f3865b51e8d11acb52adBo Zhu     * <p>Note that this is different from {@link #ERROR_BAD_CERTIFICATE_FORMAT}, which denotes
2487f414d94fc4f6bd34325f3865b51e8d11acb52adBo Zhu     * incorrect certificate formats, e.g., due to wrong encoding or structure.
2497f414d94fc4f6bd34325f3865b51e8d11acb52adBo Zhu     *
2507f414d94fc4f6bd34325f3865b51e8d11acb52adBo Zhu     * @hide
2517f414d94fc4f6bd34325f3865b51e8d11acb52adBo Zhu     */
2527f414d94fc4f6bd34325f3865b51e8d11acb52adBo Zhu    public static final int ERROR_INVALID_CERTIFICATE = 28;
25381ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry
25423174b7eaeb93918451c36bbbfad94bafd44bdd6Aseem Kumar
25523174b7eaeb93918451c36bbbfad94bafd44bdd6Aseem Kumar    /**
25623174b7eaeb93918451c36bbbfad94bafd44bdd6Aseem Kumar     * Failed because the provided certificate contained serial version which is lower that the
25723174b7eaeb93918451c36bbbfad94bafd44bdd6Aseem Kumar     * version device is already initialized with. It is not possible to downgrade serial version of
25823174b7eaeb93918451c36bbbfad94bafd44bdd6Aseem Kumar     * the provided certificate.
25923174b7eaeb93918451c36bbbfad94bafd44bdd6Aseem Kumar     *
26023174b7eaeb93918451c36bbbfad94bafd44bdd6Aseem Kumar     * @hide
26123174b7eaeb93918451c36bbbfad94bafd44bdd6Aseem Kumar     */
26223174b7eaeb93918451c36bbbfad94bafd44bdd6Aseem Kumar    public static final int ERROR_DOWNGRADE_CERTIFICATE = 29;
26323174b7eaeb93918451c36bbbfad94bafd44bdd6Aseem Kumar
26481ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry    private final ILockSettings mBinder;
26529b9de5b8a9b38290c2855890ae1f7a93c0b8421Dmitry Dementyev    private final KeyStore mKeyStore;
26681ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry
26729b9de5b8a9b38290c2855890ae1f7a93c0b8421Dmitry Dementyev    private RecoveryController(ILockSettings binder, KeyStore keystore) {
26881ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry        mBinder = binder;
26929b9de5b8a9b38290c2855890ae1f7a93c0b8421Dmitry Dementyev        mKeyStore = keystore;
27081ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry    }
27181ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry
27281ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry    /**
2730916e7ca44aba5e6c89d75007da805697fdace9eDmitry Dementyev     * Internal method used by {@code RecoverySession}.
2740916e7ca44aba5e6c89d75007da805697fdace9eDmitry Dementyev     *
2750916e7ca44aba5e6c89d75007da805697fdace9eDmitry Dementyev     * @hide
2760916e7ca44aba5e6c89d75007da805697fdace9eDmitry Dementyev     */
2770916e7ca44aba5e6c89d75007da805697fdace9eDmitry Dementyev    ILockSettings getBinder() {
2780916e7ca44aba5e6c89d75007da805697fdace9eDmitry Dementyev        return mBinder;
2790916e7ca44aba5e6c89d75007da805697fdace9eDmitry Dementyev    }
2800916e7ca44aba5e6c89d75007da805697fdace9eDmitry Dementyev
2810916e7ca44aba5e6c89d75007da805697fdace9eDmitry Dementyev    /**
28281ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry     * Gets a new instance of the class.
28381ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry     */
284c1742e51378c3ec99a0e5df14dc0c77bcca0d16aAseem Kumar    @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
28516d9db57f513eb13eeb2486d2d4770f59faf5550Dmitry Dementyev    @NonNull public static RecoveryController getInstance(@NonNull Context context) {
28681ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry        ILockSettings lockSettings =
28781ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry                ILockSettings.Stub.asInterface(ServiceManager.getService("lock_settings"));
28829b9de5b8a9b38290c2855890ae1f7a93c0b8421Dmitry Dementyev        return new RecoveryController(lockSettings, KeyStore.getInstance());
28981ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry    }
29081ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry
29181ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry    /**
292b95c90ce2d10a93c680b2ddbdf7ad61feb3abf5aBo Zhu     * Checks whether the recoverable key store is currently available.
293b95c90ce2d10a93c680b2ddbdf7ad61feb3abf5aBo Zhu     *
294b95c90ce2d10a93c680b2ddbdf7ad61feb3abf5aBo Zhu     * <p>If it returns true, the device must currently be using a screen lock that is supported for
295b95c90ce2d10a93c680b2ddbdf7ad61feb3abf5aBo Zhu     * use with the recoverable key store, i.e. AOSP PIN, pattern or password.
296b95c90ce2d10a93c680b2ddbdf7ad61feb3abf5aBo Zhu     */
297b95c90ce2d10a93c680b2ddbdf7ad61feb3abf5aBo Zhu    @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
298b95c90ce2d10a93c680b2ddbdf7ad61feb3abf5aBo Zhu    public static boolean isRecoverableKeyStoreEnabled(@NonNull Context context) {
299b95c90ce2d10a93c680b2ddbdf7ad61feb3abf5aBo Zhu        KeyguardManager keyguardManager = context.getSystemService(KeyguardManager.class);
300b95c90ce2d10a93c680b2ddbdf7ad61feb3abf5aBo Zhu        return keyguardManager != null && keyguardManager.isDeviceSecure();
301b95c90ce2d10a93c680b2ddbdf7ad61feb3abf5aBo Zhu    }
302b95c90ce2d10a93c680b2ddbdf7ad61feb3abf5aBo Zhu
303b95c90ce2d10a93c680b2ddbdf7ad61feb3abf5aBo Zhu    /**
304c157e21249b01cca18e6712d69c719f245db51a7Robert Berry     * @deprecated Use {@link #initRecoveryService(String, byte[], byte[])} instead.
3053990ee1c9fcd8f801220edec94e6bef3009809b5Jeff Sharkey     * @removed
3067f414d94fc4f6bd34325f3865b51e8d11acb52adBo Zhu     */
3077f414d94fc4f6bd34325f3865b51e8d11acb52adBo Zhu    @Deprecated
3087f414d94fc4f6bd34325f3865b51e8d11acb52adBo Zhu    @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
3097f414d94fc4f6bd34325f3865b51e8d11acb52adBo Zhu    public void initRecoveryService(
3107f414d94fc4f6bd34325f3865b51e8d11acb52adBo Zhu            @NonNull String rootCertificateAlias, @NonNull byte[] signedPublicKeyList)
3117f414d94fc4f6bd34325f3865b51e8d11acb52adBo Zhu            throws CertificateException, InternalRecoveryServiceException {
312745d2c98f9467f1befb7ec3a6c485333d4f1b437Dmitry Dementyev        throw new UnsupportedOperationException();
3137f414d94fc4f6bd34325f3865b51e8d11acb52adBo Zhu    }
3147f414d94fc4f6bd34325f3865b51e8d11acb52adBo Zhu
3157f414d94fc4f6bd34325f3865b51e8d11acb52adBo Zhu    /**
3167f414d94fc4f6bd34325f3865b51e8d11acb52adBo Zhu     * Initializes the recovery service for the calling application. The detailed steps should be:
3177f414d94fc4f6bd34325f3865b51e8d11acb52adBo Zhu     * <ol>
3187f414d94fc4f6bd34325f3865b51e8d11acb52adBo Zhu     *     <li>Parse {@code signatureFile} to get relevant information.
3197f414d94fc4f6bd34325f3865b51e8d11acb52adBo Zhu     *     <li>Validate the signer's X509 certificate, contained in {@code signatureFile}, against
3207f414d94fc4f6bd34325f3865b51e8d11acb52adBo Zhu     *         the root certificate pre-installed in the OS and chosen by {@code
3217f414d94fc4f6bd34325f3865b51e8d11acb52adBo Zhu     *         rootCertificateAlias}.
3227f414d94fc4f6bd34325f3865b51e8d11acb52adBo Zhu     *     <li>Verify the public-key signature, contained in {@code signatureFile}, and verify it
3237f414d94fc4f6bd34325f3865b51e8d11acb52adBo Zhu     *         against the entire {@code certificateFile}.
3247f414d94fc4f6bd34325f3865b51e8d11acb52adBo Zhu     *     <li>Parse {@code certificateFile} to get relevant information.
3257f414d94fc4f6bd34325f3865b51e8d11acb52adBo Zhu     *     <li>Check the serial number, contained in {@code certificateFile}, and skip the following
3267f414d94fc4f6bd34325f3865b51e8d11acb52adBo Zhu     *         steps if the serial number is not larger than the one previously stored.
3277f414d94fc4f6bd34325f3865b51e8d11acb52adBo Zhu     *     <li>Randomly choose a X509 certificate from the endpoint X509 certificates, contained in
3287f414d94fc4f6bd34325f3865b51e8d11acb52adBo Zhu     *         {@code certificateFile}, and validate it against the root certificate pre-installed
3297f414d94fc4f6bd34325f3865b51e8d11acb52adBo Zhu     *         in the OS and chosen by {@code rootCertificateAlias}.
3307f414d94fc4f6bd34325f3865b51e8d11acb52adBo Zhu     *     <li>Store the chosen X509 certificate and the serial in local database for later use.
3317f414d94fc4f6bd34325f3865b51e8d11acb52adBo Zhu     * </ol>
33281ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry     *
3337f414d94fc4f6bd34325f3865b51e8d11acb52adBo Zhu     * @param rootCertificateAlias the alias of a root certificate pre-installed in the OS
3347f414d94fc4f6bd34325f3865b51e8d11acb52adBo Zhu     * @param certificateFile the binary content of the XML file containing a list of recovery
3357f414d94fc4f6bd34325f3865b51e8d11acb52adBo Zhu     *     service X509 certificates, and other metadata including the serial number
3367f414d94fc4f6bd34325f3865b51e8d11acb52adBo Zhu     * @param signatureFile the binary content of the XML file containing the public-key signature
3377f414d94fc4f6bd34325f3865b51e8d11acb52adBo Zhu     *     of the entire certificate file, and a signer's X509 certificate
3387f414d94fc4f6bd34325f3865b51e8d11acb52adBo Zhu     * @throws CertificateException if the given certificate files cannot be parsed or validated
33981ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry     * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery
34081ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry     *     service.
34181ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry     */
3420916e7ca44aba5e6c89d75007da805697fdace9eDmitry Dementyev    @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
34381ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry    public void initRecoveryService(
3447f414d94fc4f6bd34325f3865b51e8d11acb52adBo Zhu            @NonNull String rootCertificateAlias, @NonNull byte[] certificateFile,
3457f414d94fc4f6bd34325f3865b51e8d11acb52adBo Zhu            @NonNull byte[] signatureFile)
3460916e7ca44aba5e6c89d75007da805697fdace9eDmitry Dementyev            throws CertificateException, InternalRecoveryServiceException {
34781ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry        try {
3487f414d94fc4f6bd34325f3865b51e8d11acb52adBo Zhu            mBinder.initRecoveryServiceWithSigFile(
3497f414d94fc4f6bd34325f3865b51e8d11acb52adBo Zhu                    rootCertificateAlias, certificateFile, signatureFile);
35081ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry        } catch (RemoteException e) {
35181ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry            throw e.rethrowFromSystemServer();
35281ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry        } catch (ServiceSpecificException e) {
3537f414d94fc4f6bd34325f3865b51e8d11acb52adBo Zhu            if (e.errorCode == ERROR_BAD_CERTIFICATE_FORMAT
3547f414d94fc4f6bd34325f3865b51e8d11acb52adBo Zhu                    || e.errorCode == ERROR_INVALID_CERTIFICATE) {
35541d2dd2f266eb8dc50afcda253f04f1c7e9ccc0eBo Zhu                throw new CertificateException("Invalid certificate for recovery service", e);
35681ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry            }
35723174b7eaeb93918451c36bbbfad94bafd44bdd6Aseem Kumar            if (e.errorCode == ERROR_DOWNGRADE_CERTIFICATE) {
35823174b7eaeb93918451c36bbbfad94bafd44bdd6Aseem Kumar                throw new CertificateException(
35923174b7eaeb93918451c36bbbfad94bafd44bdd6Aseem Kumar                        "Downgrading certificate serial version isn't supported.", e);
36023174b7eaeb93918451c36bbbfad94bafd44bdd6Aseem Kumar            }
36181ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry            throw wrapUnexpectedServiceSpecificException(e);
36281ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry        }
36381ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry    }
36481ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry
36581ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry    /**
366c157e21249b01cca18e6712d69c719f245db51a7Robert Berry     * @deprecated Use {@link #getKeyChainSnapshot()}
3673990ee1c9fcd8f801220edec94e6bef3009809b5Jeff Sharkey     * @removed
36881ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry     */
36956f06b4d111f99f72d4232b43037fea2f6246e7dRobert Berry    @Deprecated
3700916e7ca44aba5e6c89d75007da805697fdace9eDmitry Dementyev    @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
37156f06b4d111f99f72d4232b43037fea2f6246e7dRobert Berry    public @Nullable KeyChainSnapshot getRecoveryData() throws InternalRecoveryServiceException {
372745d2c98f9467f1befb7ec3a6c485333d4f1b437Dmitry Dementyev        throw new UnsupportedOperationException();
373b4fb98777006bc3c2bb038d50473663fbc92932cDmitry Dementyev    }
374b4fb98777006bc3c2bb038d50473663fbc92932cDmitry Dementyev
375b4fb98777006bc3c2bb038d50473663fbc92932cDmitry Dementyev    /**
376b4fb98777006bc3c2bb038d50473663fbc92932cDmitry Dementyev     * Returns data necessary to store all recoverable keys. Key material is
377b4fb98777006bc3c2bb038d50473663fbc92932cDmitry Dementyev     * encrypted with user secret and recovery public key.
378b4fb98777006bc3c2bb038d50473663fbc92932cDmitry Dementyev     *
379b4fb98777006bc3c2bb038d50473663fbc92932cDmitry Dementyev     * @return Data necessary to recover keystore or {@code null} if snapshot is not available.
380b4fb98777006bc3c2bb038d50473663fbc92932cDmitry Dementyev     * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery
381b4fb98777006bc3c2bb038d50473663fbc92932cDmitry Dementyev     *     service.
382b4fb98777006bc3c2bb038d50473663fbc92932cDmitry Dementyev     */
383b4fb98777006bc3c2bb038d50473663fbc92932cDmitry Dementyev    @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
384b4fb98777006bc3c2bb038d50473663fbc92932cDmitry Dementyev    public @Nullable KeyChainSnapshot getKeyChainSnapshot()
38581ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry            throws InternalRecoveryServiceException {
38681ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry        try {
387b4fb98777006bc3c2bb038d50473663fbc92932cDmitry Dementyev            return mBinder.getKeyChainSnapshot();
38881ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry        } catch (RemoteException e) {
38981ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry            throw e.rethrowFromSystemServer();
39081ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry        } catch (ServiceSpecificException e) {
39181ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry            if (e.errorCode == ERROR_NO_SNAPSHOT_PENDING) {
39281ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry                return null;
39381ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry            }
39481ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry            throw wrapUnexpectedServiceSpecificException(e);
39581ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry        }
39681ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry    }
39781ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry
39881ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry    /**
39981ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry     * Sets a listener which notifies recovery agent that new recovery snapshot is available. {@link
4001e6a9dcecb92b4a9a8d3c60372821ba7cd830873Dmitry Dementyev     * #getKeyChainSnapshot} can be used to get the snapshot. Note that every recovery agent can
4011e6a9dcecb92b4a9a8d3c60372821ba7cd830873Dmitry Dementyev     * have at most one registered listener at any time.
40281ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry     *
40381ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry     * @param intent triggered when new snapshot is available. Unregisters listener if the value is
40481ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry     *     {@code null}.
40581ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry     * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery
40681ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry     *     service.
40781ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry     */
4080916e7ca44aba5e6c89d75007da805697fdace9eDmitry Dementyev    @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
40981ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry    public void setSnapshotCreatedPendingIntent(@Nullable PendingIntent intent)
41081ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry            throws InternalRecoveryServiceException {
41181ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry        try {
41281ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry            mBinder.setSnapshotCreatedPendingIntent(intent);
41381ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry        } catch (RemoteException e) {
41481ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry            throw e.rethrowFromSystemServer();
41581ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry        } catch (ServiceSpecificException e) {
41681ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry            throw wrapUnexpectedServiceSpecificException(e);
41781ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry        }
41881ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry    }
41981ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry
42081ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry    /**
4210916e7ca44aba5e6c89d75007da805697fdace9eDmitry Dementyev     * Server parameters used to generate new recovery key blobs. This value will be included in
4220916e7ca44aba5e6c89d75007da805697fdace9eDmitry Dementyev     * {@code KeyChainSnapshot.getEncryptedRecoveryKeyBlob()}. The same value must be included
423c1742e51378c3ec99a0e5df14dc0c77bcca0d16aAseem Kumar     * in vaultParams {@link RecoverySession#start(CertPath, byte[], byte[], List)}.
42481ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry     *
4250916e7ca44aba5e6c89d75007da805697fdace9eDmitry Dementyev     * @param serverParams included in recovery key blob.
4261e6a9dcecb92b4a9a8d3c60372821ba7cd830873Dmitry Dementyev     * @see #getKeyChainSnapshot
42781ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry     * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery
42881ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry     *     service.
42981ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry     */
4300916e7ca44aba5e6c89d75007da805697fdace9eDmitry Dementyev    @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
4311e6a9dcecb92b4a9a8d3c60372821ba7cd830873Dmitry Dementyev    public void setServerParams(@NonNull byte[] serverParams)
4321e6a9dcecb92b4a9a8d3c60372821ba7cd830873Dmitry Dementyev            throws InternalRecoveryServiceException {
43381ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry        try {
4340916e7ca44aba5e6c89d75007da805697fdace9eDmitry Dementyev            mBinder.setServerParams(serverParams);
43581ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry        } catch (RemoteException e) {
43681ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry            throw e.rethrowFromSystemServer();
43781ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry        } catch (ServiceSpecificException e) {
43881ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry            throw wrapUnexpectedServiceSpecificException(e);
43981ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry        }
44081ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry    }
44181ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry
44281ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry    /**
443c157e21249b01cca18e6712d69c719f245db51a7Robert Berry     * @deprecated Use {@link #getAliases()}.
4443990ee1c9fcd8f801220edec94e6bef3009809b5Jeff Sharkey     * @removed
44581ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry     */
44656f06b4d111f99f72d4232b43037fea2f6246e7dRobert Berry    @Deprecated
447c1742e51378c3ec99a0e5df14dc0c77bcca0d16aAseem Kumar    @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
4480916e7ca44aba5e6c89d75007da805697fdace9eDmitry Dementyev    public List<String> getAliases(@Nullable String packageName)
449f8ae5deba2911b7bc8441df31c0504eaaa687addDmitry Dementyev            throws InternalRecoveryServiceException {
450745d2c98f9467f1befb7ec3a6c485333d4f1b437Dmitry Dementyev        throw new UnsupportedOperationException();
45156f06b4d111f99f72d4232b43037fea2f6246e7dRobert Berry    }
45256f06b4d111f99f72d4232b43037fea2f6246e7dRobert Berry
45356f06b4d111f99f72d4232b43037fea2f6246e7dRobert Berry    /**
45456f06b4d111f99f72d4232b43037fea2f6246e7dRobert Berry     * Returns a list of aliases of keys belonging to the application.
45556f06b4d111f99f72d4232b43037fea2f6246e7dRobert Berry     */
456c1742e51378c3ec99a0e5df14dc0c77bcca0d16aAseem Kumar    @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
4571e6a9dcecb92b4a9a8d3c60372821ba7cd830873Dmitry Dementyev    public @NonNull List<String> getAliases() throws InternalRecoveryServiceException {
45881ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry        try {
45956f06b4d111f99f72d4232b43037fea2f6246e7dRobert Berry            Map<String, Integer> allStatuses = mBinder.getRecoveryStatus();
4600916e7ca44aba5e6c89d75007da805697fdace9eDmitry Dementyev            return new ArrayList<>(allStatuses.keySet());
46181ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry        } catch (RemoteException e) {
46281ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry            throw e.rethrowFromSystemServer();
46381ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry        } catch (ServiceSpecificException e) {
46481ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry            throw wrapUnexpectedServiceSpecificException(e);
46581ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry        }
46681ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry    }
46781ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry
46881ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry    /**
469c157e21249b01cca18e6712d69c719f245db51a7Robert Berry     * @deprecated Use {@link #setRecoveryStatus(String, int)}
4703990ee1c9fcd8f801220edec94e6bef3009809b5Jeff Sharkey     * @removed
47181ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry     */
472bbe02ae8a3dd07989d61bbb739bfd863123c5489Robert Berry    @Deprecated
4730916e7ca44aba5e6c89d75007da805697fdace9eDmitry Dementyev    @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
47481ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry    public void setRecoveryStatus(
4750916e7ca44aba5e6c89d75007da805697fdace9eDmitry Dementyev            @NonNull String packageName, String alias, int status)
47681ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry            throws NameNotFoundException, InternalRecoveryServiceException {
477745d2c98f9467f1befb7ec3a6c485333d4f1b437Dmitry Dementyev        throw new UnsupportedOperationException();
478bbe02ae8a3dd07989d61bbb739bfd863123c5489Robert Berry    }
479bbe02ae8a3dd07989d61bbb739bfd863123c5489Robert Berry
480bbe02ae8a3dd07989d61bbb739bfd863123c5489Robert Berry    /**
481bbe02ae8a3dd07989d61bbb739bfd863123c5489Robert Berry     * Sets the recovery status for given key. It is used to notify the keystore that the key was
482bbe02ae8a3dd07989d61bbb739bfd863123c5489Robert Berry     * successfully stored on the server or that there was an error. An application can check this
483bbe02ae8a3dd07989d61bbb739bfd863123c5489Robert Berry     * value using {@link #getRecoveryStatus(String, String)}.
484bbe02ae8a3dd07989d61bbb739bfd863123c5489Robert Berry     *
485bbe02ae8a3dd07989d61bbb739bfd863123c5489Robert Berry     * @param alias The alias of the key whose status to set.
486bbe02ae8a3dd07989d61bbb739bfd863123c5489Robert Berry     * @param status The status of the key. One of {@link #RECOVERY_STATUS_SYNCED},
487bbe02ae8a3dd07989d61bbb739bfd863123c5489Robert Berry     *     {@link #RECOVERY_STATUS_SYNC_IN_PROGRESS} or {@link #RECOVERY_STATUS_PERMANENT_FAILURE}.
488bbe02ae8a3dd07989d61bbb739bfd863123c5489Robert Berry     * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery
489bbe02ae8a3dd07989d61bbb739bfd863123c5489Robert Berry     *     service.
490bbe02ae8a3dd07989d61bbb739bfd863123c5489Robert Berry     */
491bbe02ae8a3dd07989d61bbb739bfd863123c5489Robert Berry    @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
4921e6a9dcecb92b4a9a8d3c60372821ba7cd830873Dmitry Dementyev    public void setRecoveryStatus(@NonNull String alias, int status)
493bbe02ae8a3dd07989d61bbb739bfd863123c5489Robert Berry            throws InternalRecoveryServiceException {
49481ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry        try {
495bbe02ae8a3dd07989d61bbb739bfd863123c5489Robert Berry            mBinder.setRecoveryStatus(alias, status);
49681ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry        } catch (RemoteException e) {
49781ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry            throw e.rethrowFromSystemServer();
49881ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry        } catch (ServiceSpecificException e) {
49981ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry            throw wrapUnexpectedServiceSpecificException(e);
50081ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry        }
50181ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry    }
50281ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry
50381ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry    /**
504c157e21249b01cca18e6712d69c719f245db51a7Robert Berry     * @deprecated Use {@link #getRecoveryStatus(String)}.
5053990ee1c9fcd8f801220edec94e6bef3009809b5Jeff Sharkey     * @removed
50656f06b4d111f99f72d4232b43037fea2f6246e7dRobert Berry     */
50756f06b4d111f99f72d4232b43037fea2f6246e7dRobert Berry    @Deprecated
508c1742e51378c3ec99a0e5df14dc0c77bcca0d16aAseem Kumar    @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
50956f06b4d111f99f72d4232b43037fea2f6246e7dRobert Berry    public int getRecoveryStatus(String packageName, String alias)
51056f06b4d111f99f72d4232b43037fea2f6246e7dRobert Berry            throws InternalRecoveryServiceException {
511745d2c98f9467f1befb7ec3a6c485333d4f1b437Dmitry Dementyev        throw new UnsupportedOperationException();
51256f06b4d111f99f72d4232b43037fea2f6246e7dRobert Berry    }
51356f06b4d111f99f72d4232b43037fea2f6246e7dRobert Berry
51456f06b4d111f99f72d4232b43037fea2f6246e7dRobert Berry    /**
51556f06b4d111f99f72d4232b43037fea2f6246e7dRobert Berry     * Returns the recovery status for the key with the given {@code alias}.
51681ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry     *
51781ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry     * <ul>
51881ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry     *   <li>{@link #RECOVERY_STATUS_SYNCED}
51981ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry     *   <li>{@link #RECOVERY_STATUS_SYNC_IN_PROGRESS}
52081ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry     *   <li>{@link #RECOVERY_STATUS_PERMANENT_FAILURE}
52181ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry     * </ul>
52281ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry     *
52356f06b4d111f99f72d4232b43037fea2f6246e7dRobert Berry     * @see #setRecoveryStatus(String, int)
52481ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry     * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery
52581ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry     *     service.
52681ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry     */
527c1742e51378c3ec99a0e5df14dc0c77bcca0d16aAseem Kumar    @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
5281e6a9dcecb92b4a9a8d3c60372821ba7cd830873Dmitry Dementyev    public int getRecoveryStatus(@NonNull String alias) throws InternalRecoveryServiceException {
52981ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry        try {
53056f06b4d111f99f72d4232b43037fea2f6246e7dRobert Berry            Map<String, Integer> allStatuses = mBinder.getRecoveryStatus();
5310916e7ca44aba5e6c89d75007da805697fdace9eDmitry Dementyev            Integer status = allStatuses.get(alias);
5320916e7ca44aba5e6c89d75007da805697fdace9eDmitry Dementyev            if (status == null) {
5330916e7ca44aba5e6c89d75007da805697fdace9eDmitry Dementyev                return RecoveryController.RECOVERY_STATUS_PERMANENT_FAILURE;
5340916e7ca44aba5e6c89d75007da805697fdace9eDmitry Dementyev            } else {
5350916e7ca44aba5e6c89d75007da805697fdace9eDmitry Dementyev                return status;
5360916e7ca44aba5e6c89d75007da805697fdace9eDmitry Dementyev            }
53781ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry        } catch (RemoteException e) {
53881ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry            throw e.rethrowFromSystemServer();
53981ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry        } catch (ServiceSpecificException e) {
54081ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry            throw wrapUnexpectedServiceSpecificException(e);
54181ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry        }
54281ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry    }
54381ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry
54481ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry    /**
54581ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry     * Specifies a set of secret types used for end-to-end keystore encryption. Knowing all of them
54681ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry     * is necessary to recover data.
54781ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry     *
548933dfc1cd6041d1e77d169be91818d5b31e36edcAseem Kumar     * @param secretTypes {@link KeyChainProtectionParams#TYPE_LOCKSCREEN}
54981ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry     * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery
55081ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry     *     service.
55181ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry     */
552c1742e51378c3ec99a0e5df14dc0c77bcca0d16aAseem Kumar    @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
55381ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry    public void setRecoverySecretTypes(
5540916e7ca44aba5e6c89d75007da805697fdace9eDmitry Dementyev            @NonNull @KeyChainProtectionParams.UserSecretType int[] secretTypes)
55581ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry            throws InternalRecoveryServiceException {
55681ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry        try {
55781ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry            mBinder.setRecoverySecretTypes(secretTypes);
55881ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry        } catch (RemoteException e) {
55981ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry            throw e.rethrowFromSystemServer();
56081ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry        } catch (ServiceSpecificException e) {
56181ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry            throw wrapUnexpectedServiceSpecificException(e);
56281ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry        }
56381ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry    }
56481ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry
56581ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry    /**
56681ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry     * Defines a set of secret types used for end-to-end keystore encryption. Knowing all of them is
5670916e7ca44aba5e6c89d75007da805697fdace9eDmitry Dementyev     * necessary to generate KeyChainSnapshot.
56881ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry     *
56981ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry     * @return list of recovery secret types
5700916e7ca44aba5e6c89d75007da805697fdace9eDmitry Dementyev     * @see KeyChainSnapshot
57181ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry     * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery
57281ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry     *     service.
57381ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry     */
574c1742e51378c3ec99a0e5df14dc0c77bcca0d16aAseem Kumar    @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
5750916e7ca44aba5e6c89d75007da805697fdace9eDmitry Dementyev    public @NonNull @KeyChainProtectionParams.UserSecretType int[] getRecoverySecretTypes()
57681ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry            throws InternalRecoveryServiceException {
57781ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry        try {
57881ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry            return mBinder.getRecoverySecretTypes();
57981ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry        } catch (RemoteException e) {
58081ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry            throw e.rethrowFromSystemServer();
58181ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry        } catch (ServiceSpecificException e) {
58281ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry            throw wrapUnexpectedServiceSpecificException(e);
58381ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry        }
58481ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry    }
58581ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry
58681ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry    /**
587c157e21249b01cca18e6712d69c719f245db51a7Robert Berry     * Deprecated.
588c157e21249b01cca18e6712d69c719f245db51a7Robert Berry     * Generates a AES256/GCM/NoPADDING key called {@code alias} and loads it into the recoverable
589c157e21249b01cca18e6712d69c719f245db51a7Robert Berry     * key store. Returns the raw material of the key.
590c157e21249b01cca18e6712d69c719f245db51a7Robert Berry     *
591c157e21249b01cca18e6712d69c719f245db51a7Robert Berry     * @param alias The key alias.
592c157e21249b01cca18e6712d69c719f245db51a7Robert Berry     * @param account The account associated with the key
593c157e21249b01cca18e6712d69c719f245db51a7Robert Berry     * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery
594c157e21249b01cca18e6712d69c719f245db51a7Robert Berry     *     service.
595c157e21249b01cca18e6712d69c719f245db51a7Robert Berry     * @throws LockScreenRequiredException if the user has not set a lock screen. This is required
596c157e21249b01cca18e6712d69c719f245db51a7Robert Berry     *     to generate recoverable keys, as the snapshots are encrypted using a key derived from the
597c157e21249b01cca18e6712d69c719f245db51a7Robert Berry     *     lock screen.
5983990ee1c9fcd8f801220edec94e6bef3009809b5Jeff Sharkey     * @deprecated Use {@link #generateKey(String)}
5993990ee1c9fcd8f801220edec94e6bef3009809b5Jeff Sharkey     * @removed
600c157e21249b01cca18e6712d69c719f245db51a7Robert Berry     */
6013990ee1c9fcd8f801220edec94e6bef3009809b5Jeff Sharkey    @Deprecated
602c157e21249b01cca18e6712d69c719f245db51a7Robert Berry    @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
603c157e21249b01cca18e6712d69c719f245db51a7Robert Berry    public byte[] generateAndStoreKey(@NonNull String alias, byte[] account)
604c157e21249b01cca18e6712d69c719f245db51a7Robert Berry            throws InternalRecoveryServiceException, LockScreenRequiredException {
605c157e21249b01cca18e6712d69c719f245db51a7Robert Berry        throw new UnsupportedOperationException("Operation is not supported, use generateKey");
606c157e21249b01cca18e6712d69c719f245db51a7Robert Berry    }
607c157e21249b01cca18e6712d69c719f245db51a7Robert Berry
608c157e21249b01cca18e6712d69c719f245db51a7Robert Berry    /**
609c157e21249b01cca18e6712d69c719f245db51a7Robert Berry     * @deprecated Use {@link #generateKey(String)}.
6103990ee1c9fcd8f801220edec94e6bef3009809b5Jeff Sharkey     * @removed
611a3b994798d870244f11b56ae0bdfb870924402a8Robert Berry     */
612a3b994798d870244f11b56ae0bdfb870924402a8Robert Berry    @Deprecated
613c1742e51378c3ec99a0e5df14dc0c77bcca0d16aAseem Kumar    @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
614a3b994798d870244f11b56ae0bdfb870924402a8Robert Berry    public Key generateKey(@NonNull String alias, byte[] account)
615a3b994798d870244f11b56ae0bdfb870924402a8Robert Berry            throws InternalRecoveryServiceException, LockScreenRequiredException {
616745d2c98f9467f1befb7ec3a6c485333d4f1b437Dmitry Dementyev        throw new UnsupportedOperationException();
617a3b994798d870244f11b56ae0bdfb870924402a8Robert Berry    }
618a3b994798d870244f11b56ae0bdfb870924402a8Robert Berry
619a3b994798d870244f11b56ae0bdfb870924402a8Robert Berry    /**
620a3b994798d870244f11b56ae0bdfb870924402a8Robert Berry     * Generates a recoverable key with the given {@code alias}.
62129b9de5b8a9b38290c2855890ae1f7a93c0b8421Dmitry Dementyev     *
62229b9de5b8a9b38290c2855890ae1f7a93c0b8421Dmitry Dementyev     * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery
62329b9de5b8a9b38290c2855890ae1f7a93c0b8421Dmitry Dementyev     *     service.
624a3b994798d870244f11b56ae0bdfb870924402a8Robert Berry     * @throws LockScreenRequiredException if the user does not have a lock screen set. A lock
625a3b994798d870244f11b56ae0bdfb870924402a8Robert Berry     *     screen is required to generate recoverable keys.
62629b9de5b8a9b38290c2855890ae1f7a93c0b8421Dmitry Dementyev     */
627c1742e51378c3ec99a0e5df14dc0c77bcca0d16aAseem Kumar    @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
6280bbaf189c259f7d3154737c4284023921dc821b0Dmitry Dementyev    public @NonNull Key generateKey(@NonNull String alias) throws InternalRecoveryServiceException,
629a3b994798d870244f11b56ae0bdfb870924402a8Robert Berry            LockScreenRequiredException {
63029b9de5b8a9b38290c2855890ae1f7a93c0b8421Dmitry Dementyev        try {
631a3b994798d870244f11b56ae0bdfb870924402a8Robert Berry            String grantAlias = mBinder.generateKey(alias);
63229b9de5b8a9b38290c2855890ae1f7a93c0b8421Dmitry Dementyev            if (grantAlias == null) {
633a3b994798d870244f11b56ae0bdfb870924402a8Robert Berry                throw new InternalRecoveryServiceException("null grant alias");
63429b9de5b8a9b38290c2855890ae1f7a93c0b8421Dmitry Dementyev            }
6354a5c87def075c805d4fcae7ff01dd2e78ec27b1aRobert Berry            return getKeyFromGrant(grantAlias);
6362c8e5383c836d2dfa39b0be6bfa281285667a880Bo Zhu        } catch (RemoteException e) {
6372c8e5383c836d2dfa39b0be6bfa281285667a880Bo Zhu            throw e.rethrowFromSystemServer();
6382c8e5383c836d2dfa39b0be6bfa281285667a880Bo Zhu        } catch (UnrecoverableKeyException e) {
6392c8e5383c836d2dfa39b0be6bfa281285667a880Bo Zhu            throw new InternalRecoveryServiceException("Failed to get key from keystore", e);
6402c8e5383c836d2dfa39b0be6bfa281285667a880Bo Zhu        } catch (ServiceSpecificException e) {
6412c8e5383c836d2dfa39b0be6bfa281285667a880Bo Zhu            if (e.errorCode == ERROR_INSECURE_USER) {
6422c8e5383c836d2dfa39b0be6bfa281285667a880Bo Zhu                throw new LockScreenRequiredException(e.getMessage());
6432c8e5383c836d2dfa39b0be6bfa281285667a880Bo Zhu            }
6442c8e5383c836d2dfa39b0be6bfa281285667a880Bo Zhu            throw wrapUnexpectedServiceSpecificException(e);
6452c8e5383c836d2dfa39b0be6bfa281285667a880Bo Zhu        }
6462c8e5383c836d2dfa39b0be6bfa281285667a880Bo Zhu    }
6472c8e5383c836d2dfa39b0be6bfa281285667a880Bo Zhu
6482c8e5383c836d2dfa39b0be6bfa281285667a880Bo Zhu    /**
6492c8e5383c836d2dfa39b0be6bfa281285667a880Bo Zhu     * Imports a 256-bit recoverable AES key with the given {@code alias} and the raw bytes {@code
6502c8e5383c836d2dfa39b0be6bfa281285667a880Bo Zhu     * keyBytes}.
6512c8e5383c836d2dfa39b0be6bfa281285667a880Bo Zhu     *
6522c8e5383c836d2dfa39b0be6bfa281285667a880Bo Zhu     * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery
6532c8e5383c836d2dfa39b0be6bfa281285667a880Bo Zhu     *     service.
6542c8e5383c836d2dfa39b0be6bfa281285667a880Bo Zhu     * @throws LockScreenRequiredException if the user does not have a lock screen set. A lock
6552c8e5383c836d2dfa39b0be6bfa281285667a880Bo Zhu     *     screen is required to generate recoverable keys.
6562c8e5383c836d2dfa39b0be6bfa281285667a880Bo Zhu     *
6572c8e5383c836d2dfa39b0be6bfa281285667a880Bo Zhu     */
658c1742e51378c3ec99a0e5df14dc0c77bcca0d16aAseem Kumar    @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
6590bbaf189c259f7d3154737c4284023921dc821b0Dmitry Dementyev    public @NonNull Key importKey(@NonNull String alias, @NonNull byte[] keyBytes)
6602c8e5383c836d2dfa39b0be6bfa281285667a880Bo Zhu            throws InternalRecoveryServiceException, LockScreenRequiredException {
6612c8e5383c836d2dfa39b0be6bfa281285667a880Bo Zhu        try {
6622c8e5383c836d2dfa39b0be6bfa281285667a880Bo Zhu            String grantAlias = mBinder.importKey(alias, keyBytes);
6632c8e5383c836d2dfa39b0be6bfa281285667a880Bo Zhu            if (grantAlias == null) {
6642c8e5383c836d2dfa39b0be6bfa281285667a880Bo Zhu                throw new InternalRecoveryServiceException("Null grant alias");
6652c8e5383c836d2dfa39b0be6bfa281285667a880Bo Zhu            }
666c5ab69469d53ffc5b55e91c5374da8b03dd4661cBo Zhu            return getKeyFromGrant(grantAlias);
66729b9de5b8a9b38290c2855890ae1f7a93c0b8421Dmitry Dementyev        } catch (RemoteException e) {
66829b9de5b8a9b38290c2855890ae1f7a93c0b8421Dmitry Dementyev            throw e.rethrowFromSystemServer();
66929b9de5b8a9b38290c2855890ae1f7a93c0b8421Dmitry Dementyev        } catch (UnrecoverableKeyException e) {
670a3b994798d870244f11b56ae0bdfb870924402a8Robert Berry            throw new InternalRecoveryServiceException("Failed to get key from keystore", e);
67129b9de5b8a9b38290c2855890ae1f7a93c0b8421Dmitry Dementyev        } catch (ServiceSpecificException e) {
67229b9de5b8a9b38290c2855890ae1f7a93c0b8421Dmitry Dementyev            if (e.errorCode == ERROR_INSECURE_USER) {
67329b9de5b8a9b38290c2855890ae1f7a93c0b8421Dmitry Dementyev                throw new LockScreenRequiredException(e.getMessage());
67429b9de5b8a9b38290c2855890ae1f7a93c0b8421Dmitry Dementyev            }
67529b9de5b8a9b38290c2855890ae1f7a93c0b8421Dmitry Dementyev            throw wrapUnexpectedServiceSpecificException(e);
67629b9de5b8a9b38290c2855890ae1f7a93c0b8421Dmitry Dementyev        }
67729b9de5b8a9b38290c2855890ae1f7a93c0b8421Dmitry Dementyev    }
67829b9de5b8a9b38290c2855890ae1f7a93c0b8421Dmitry Dementyev
67929b9de5b8a9b38290c2855890ae1f7a93c0b8421Dmitry Dementyev    /**
68029b9de5b8a9b38290c2855890ae1f7a93c0b8421Dmitry Dementyev     * Gets a key called {@code alias} from the recoverable key store.
68129b9de5b8a9b38290c2855890ae1f7a93c0b8421Dmitry Dementyev     *
68229b9de5b8a9b38290c2855890ae1f7a93c0b8421Dmitry Dementyev     * @param alias The key alias.
68329b9de5b8a9b38290c2855890ae1f7a93c0b8421Dmitry Dementyev     * @return The key.
68429b9de5b8a9b38290c2855890ae1f7a93c0b8421Dmitry Dementyev     * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery
68529b9de5b8a9b38290c2855890ae1f7a93c0b8421Dmitry Dementyev     *     service.
68629b9de5b8a9b38290c2855890ae1f7a93c0b8421Dmitry Dementyev     * @throws UnrecoverableKeyException if key is permanently invalidated or not found.
68729b9de5b8a9b38290c2855890ae1f7a93c0b8421Dmitry Dementyev     */
688c1742e51378c3ec99a0e5df14dc0c77bcca0d16aAseem Kumar    @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
68929b9de5b8a9b38290c2855890ae1f7a93c0b8421Dmitry Dementyev    public @Nullable Key getKey(@NonNull String alias)
69029b9de5b8a9b38290c2855890ae1f7a93c0b8421Dmitry Dementyev            throws InternalRecoveryServiceException, UnrecoverableKeyException {
69129b9de5b8a9b38290c2855890ae1f7a93c0b8421Dmitry Dementyev        try {
69229b9de5b8a9b38290c2855890ae1f7a93c0b8421Dmitry Dementyev            String grantAlias = mBinder.getKey(alias);
69372f5755721ad22d4711e9e9cc8ef6107db91466aRobert Berry            if (grantAlias == null || "".equals(grantAlias)) {
69429b9de5b8a9b38290c2855890ae1f7a93c0b8421Dmitry Dementyev                return null;
69529b9de5b8a9b38290c2855890ae1f7a93c0b8421Dmitry Dementyev            }
6964a5c87def075c805d4fcae7ff01dd2e78ec27b1aRobert Berry            return getKeyFromGrant(grantAlias);
69729b9de5b8a9b38290c2855890ae1f7a93c0b8421Dmitry Dementyev        } catch (RemoteException e) {
69829b9de5b8a9b38290c2855890ae1f7a93c0b8421Dmitry Dementyev            throw e.rethrowFromSystemServer();
69929b9de5b8a9b38290c2855890ae1f7a93c0b8421Dmitry Dementyev        } catch (ServiceSpecificException e) {
70029b9de5b8a9b38290c2855890ae1f7a93c0b8421Dmitry Dementyev            throw wrapUnexpectedServiceSpecificException(e);
70129b9de5b8a9b38290c2855890ae1f7a93c0b8421Dmitry Dementyev        }
70229b9de5b8a9b38290c2855890ae1f7a93c0b8421Dmitry Dementyev    }
70329b9de5b8a9b38290c2855890ae1f7a93c0b8421Dmitry Dementyev
70429b9de5b8a9b38290c2855890ae1f7a93c0b8421Dmitry Dementyev    /**
7054a5c87def075c805d4fcae7ff01dd2e78ec27b1aRobert Berry     * Returns the key with the given {@code grantAlias}.
7064a5c87def075c805d4fcae7ff01dd2e78ec27b1aRobert Berry     */
7070bbaf189c259f7d3154737c4284023921dc821b0Dmitry Dementyev    @NonNull Key getKeyFromGrant(@NonNull String grantAlias) throws UnrecoverableKeyException {
7084a5c87def075c805d4fcae7ff01dd2e78ec27b1aRobert Berry        return AndroidKeyStoreProvider.loadAndroidKeyStoreKeyFromKeystore(
7094a5c87def075c805d4fcae7ff01dd2e78ec27b1aRobert Berry                mKeyStore,
7104a5c87def075c805d4fcae7ff01dd2e78ec27b1aRobert Berry                grantAlias,
7114a5c87def075c805d4fcae7ff01dd2e78ec27b1aRobert Berry                KeyStore.UID_SELF);
7124a5c87def075c805d4fcae7ff01dd2e78ec27b1aRobert Berry    }
7134a5c87def075c805d4fcae7ff01dd2e78ec27b1aRobert Berry
7144a5c87def075c805d4fcae7ff01dd2e78ec27b1aRobert Berry    /**
71581ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry     * Removes a key called {@code alias} from the recoverable key store.
71681ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry     *
71781ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry     * @param alias The key alias.
71881ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry     * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery
71981ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry     *     service.
72081ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry     */
721c1742e51378c3ec99a0e5df14dc0c77bcca0d16aAseem Kumar    @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
72281ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry    public void removeKey(@NonNull String alias) throws InternalRecoveryServiceException {
72381ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry        try {
72481ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry            mBinder.removeKey(alias);
72581ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry        } catch (RemoteException e) {
72681ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry            throw e.rethrowFromSystemServer();
72781ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry        } catch (ServiceSpecificException e) {
72881ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry            throw wrapUnexpectedServiceSpecificException(e);
72981ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry        }
73081ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry    }
73181ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry
732e04e09ad87c218e1ddb66ac78e95af66cb0452ffRobert Berry    /**
733e04e09ad87c218e1ddb66ac78e95af66cb0452ffRobert Berry     * Returns a new {@link RecoverySession}.
734e04e09ad87c218e1ddb66ac78e95af66cb0452ffRobert Berry     *
735e04e09ad87c218e1ddb66ac78e95af66cb0452ffRobert Berry     * <p>A recovery session is required to restore keys from a remote store.
736e04e09ad87c218e1ddb66ac78e95af66cb0452ffRobert Berry     */
737c1742e51378c3ec99a0e5df14dc0c77bcca0d16aAseem Kumar    @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
7381e6a9dcecb92b4a9a8d3c60372821ba7cd830873Dmitry Dementyev    public @NonNull RecoverySession createRecoverySession() {
739e04e09ad87c218e1ddb66ac78e95af66cb0452ffRobert Berry        return RecoverySession.newInstance(this);
740e04e09ad87c218e1ddb66ac78e95af66cb0452ffRobert Berry    }
741e04e09ad87c218e1ddb66ac78e95af66cb0452ffRobert Berry
74293d002ca5f94facfec75359999c910f914d7b7c4Robert Berry    @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
7430bbaf189c259f7d3154737c4284023921dc821b0Dmitry Dementyev    public @NonNull Map<String, X509Certificate> getRootCertificates() {
74493d002ca5f94facfec75359999c910f914d7b7c4Robert Berry        return TrustedRootCertificates.getRootCertificates();
74593d002ca5f94facfec75359999c910f914d7b7c4Robert Berry    }
74693d002ca5f94facfec75359999c910f914d7b7c4Robert Berry
7470916e7ca44aba5e6c89d75007da805697fdace9eDmitry Dementyev    InternalRecoveryServiceException wrapUnexpectedServiceSpecificException(
74881ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry            ServiceSpecificException e) {
74981ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry        if (e.errorCode == ERROR_SERVICE_INTERNAL_ERROR) {
75081ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry            return new InternalRecoveryServiceException(e.getMessage());
75181ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry        }
75281ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry
75381ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry        // Should never happen. If it does, it's a bug, and we need to update how the method that
75481ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry        // called this throws its exceptions.
75581ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry        return new InternalRecoveryServiceException("Unexpected error code for method: "
75681ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry                + e.errorCode, e);
75781ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry    }
75881ee34bf957dffe020442e3f0c6c06817397ebf0Robert Berry}
759