Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5f138701 authored by Robert Berry's avatar Robert Berry
Browse files

Use better names for associated classes of RecoveryManager

I will also rename RecoveryManager to RecoveryController -- in a separate CL,
as this one is already becoming too large.

Test: adb shell am instrument -w -e package
com.android.server.locksettings.recoverablekeystore
com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner

Change-Id: I2fb4e1f55fb50d95f15c230783c3d289dd71f7f3
parent 9051eda8
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -17,4 +17,4 @@
package android.security.keystore;

/* @hide */
parcelable RecoveryData;
parcelable KeychainProtectionParameter;
+30 −16
Original line number Diff line number Diff line
@@ -28,12 +28,26 @@ import java.lang.annotation.RetentionPolicy;
import java.util.Arrays;

/**
 * Helper class with data necessary to recover Keystore on a new device.
 * It defines UI shown to the user and a way to derive a cryptographic key from user output.
 * A {@link KeychainSnapshot} is protected with a key derived from the user's lock screen. This
 * class wraps all the data necessary to derive the same key on a recovering device:
 *
 * <ul>
 *     <li>UI parameters for the user's lock screen - so that if e.g., the user was using a pattern,
 *         the recovering device can display the pattern UI to the user when asking them to enter
 *         the lock screen from their previous device.
 *     <li>The algorithm used to derive a key from the user's lock screen, e.g. SHA-256 with a salt.
 * </ul>
 *
 * <p>As such, this data is sent along with the {@link KeychainSnapshot} when syncing the current
 * version of the keychain.
 *
 * <p>For now, the recoverable keychain only supports a single layer of protection, which is the
 * user's lock screen. In the future, the keychain will support multiple layers of protection
 * (e.g. an additional keychain password, along with the lock screen).
 *
 * @hide
 */
public final class RecoveryMetadata implements Parcelable {
public final class KeychainProtectionParameter implements Parcelable {
    /** @hide */
    @Retention(RetentionPolicy.SOURCE)
    @IntDef({TYPE_LOCKSCREEN, TYPE_CUSTOM_PASSWORD})
@@ -88,7 +102,7 @@ public final class RecoveryMetadata implements Parcelable {
     * @link {#clearSecret} to overwrite its value in memory.
     * @hide
     */
    public RecoveryMetadata(@UserSecretType int userSecretType,
    public KeychainProtectionParameter(@UserSecretType int userSecretType,
            @LockScreenUiFormat int lockScreenUiFormat,
            @NonNull KeyDerivationParams keyDerivationParams,
            @NonNull byte[] secret) {
@@ -98,7 +112,7 @@ public final class RecoveryMetadata implements Parcelable {
        mSecret = Preconditions.checkNotNull(secret);
    }

    private RecoveryMetadata() {
    private KeychainProtectionParameter() {

    }

@@ -141,10 +155,10 @@ public final class RecoveryMetadata implements Parcelable {
    }

    /**
     * Builder for creating {@link RecoveryMetadata}.
     * Builder for creating {@link KeychainProtectionParameter}.
     */
    public static class Builder {
        private RecoveryMetadata mInstance = new RecoveryMetadata();
        private KeychainProtectionParameter mInstance = new KeychainProtectionParameter();

        /**
         * Sets user secret type.
@@ -198,14 +212,14 @@ public final class RecoveryMetadata implements Parcelable {


        /**
         * Creates a new {@link RecoveryMetadata} instance.
         * Creates a new {@link KeychainProtectionParameter} instance.
         * The instance will include default values, if {@link setSecret}
         * or {@link setUserSecretType} were not called.
         *
         * @return new instance
         * @throws NullPointerException if some required fields were not set.
         */
        public @NonNull RecoveryMetadata build() {
        @NonNull public KeychainProtectionParameter build() {
            if (mInstance.mUserSecretType == null) {
                mInstance.mUserSecretType = TYPE_LOCKSCREEN;
            }
@@ -235,14 +249,14 @@ public final class RecoveryMetadata implements Parcelable {
        Arrays.fill(mSecret, (byte) 0);
    }

    public static final Parcelable.Creator<RecoveryMetadata> CREATOR =
            new Parcelable.Creator<RecoveryMetadata>() {
        public RecoveryMetadata createFromParcel(Parcel in) {
            return new RecoveryMetadata(in);
    public static final Parcelable.Creator<KeychainProtectionParameter> CREATOR =
            new Parcelable.Creator<KeychainProtectionParameter>() {
        public KeychainProtectionParameter createFromParcel(Parcel in) {
            return new KeychainProtectionParameter(in);
        }

        public RecoveryMetadata[] newArray(int length) {
            return new RecoveryMetadata[length];
        public KeychainProtectionParameter[] newArray(int length) {
            return new KeychainProtectionParameter[length];
        }
    };

@@ -260,7 +274,7 @@ public final class RecoveryMetadata implements Parcelable {
    /**
     * @hide
     */
    protected RecoveryMetadata(Parcel in) {
    protected KeychainProtectionParameter(Parcel in) {
        mUserSecretType = in.readInt();
        mLockScreenUiFormat = in.readInt();
        mKeyDerivationParams = in.readTypedObject(KeyDerivationParams.CREATOR);
+1 −1
Original line number Diff line number Diff line
@@ -17,4 +17,4 @@
package android.security.keystore;

/* @hide */
parcelable RecoveryMetadata;
parcelable KeychainSnapshot;
+45 −38
Original line number Diff line number Diff line
@@ -25,42 +25,48 @@ import com.android.internal.util.Preconditions;
import java.util.List;

/**
 * Helper class which returns data necessary to recover keys.
 * Contains
 * A snapshot of a version of the keystore. Two events can trigger the generation of a new snapshot:
 *
 * <ul>
 * <li>Snapshot version.
 * <li>Recovery metadata with UI and key derivation parameters.
 * <li>List of application keys encrypted by recovery key.
 * <li>Encrypted recovery key.
 *     <li>The user's lock screen changes. (A key derived from the user's lock screen is used to
 *         protected the keychain, which is why this forces a new snapshot.)
 *     <li>A key is added to or removed from the recoverable keychain.
 * </ul>
 *
 * <p>The snapshot data is also encrypted with the remote trusted hardware's public key, so even
 * the recovery agent itself should not be able to decipher the data. The recovery agent sends an
 * instance of this to the remote trusted hardware whenever a new snapshot is generated. During a
 * recovery flow, the recovery agent retrieves a snapshot from the remote trusted hardware. It then
 * sends it to the framework, where it is decrypted using the user's lock screen from their previous
 * device.
 *
 * @hide
 */
public final class RecoveryData implements Parcelable {
public final class KeychainSnapshot implements Parcelable {
    private int mSnapshotVersion;
    private List<RecoveryMetadata> mRecoveryMetadata;
    private List<EntryRecoveryData> mEntryRecoveryData;
    private List<KeychainProtectionParameter> mKeychainProtectionParams;
    private List<WrappedApplicationKey> mEntryRecoveryData;
    private byte[] mEncryptedRecoveryKeyBlob;

    /**
     * @hide
     * Deprecated, consider using builder.
     */
    public RecoveryData(
    public KeychainSnapshot(
            int snapshotVersion,
            @NonNull List<RecoveryMetadata> recoveryMetadata,
            @NonNull List<EntryRecoveryData> entryRecoveryData,
            @NonNull List<KeychainProtectionParameter> keychainProtectionParams,
            @NonNull List<WrappedApplicationKey> wrappedApplicationKeys,
            @NonNull byte[] encryptedRecoveryKeyBlob) {
        mSnapshotVersion = snapshotVersion;
        mRecoveryMetadata =
                Preconditions.checkCollectionElementsNotNull(recoveryMetadata, "recoveryMetadata");
        mEntryRecoveryData = Preconditions.checkCollectionElementsNotNull(entryRecoveryData,
                "entryRecoveryData");
        mKeychainProtectionParams =
                Preconditions.checkCollectionElementsNotNull(keychainProtectionParams,
                        "keychainProtectionParams");
        mEntryRecoveryData = Preconditions.checkCollectionElementsNotNull(wrappedApplicationKeys,
                "wrappedApplicationKeys");
        mEncryptedRecoveryKeyBlob = Preconditions.checkNotNull(encryptedRecoveryKeyBlob);
    }

    private RecoveryData() {
    private KeychainSnapshot() {

    }

@@ -75,15 +81,15 @@ public final class RecoveryData implements Parcelable {
    /**
     * UI and key derivation parameters. Note that combination of secrets may be used.
     */
    public @NonNull List<RecoveryMetadata> getRecoveryMetadata() {
        return mRecoveryMetadata;
    public @NonNull List<KeychainProtectionParameter> getKeychainProtectionParams() {
        return mKeychainProtectionParams;
    }

    /**
     * List of application keys, with key material encrypted by
     * the recovery key ({@link #getEncryptedRecoveryKeyBlob}).
     */
    public @NonNull List<EntryRecoveryData> getEntryRecoveryData() {
    public @NonNull List<WrappedApplicationKey> getWrappedApplicationKeys() {
        return mEntryRecoveryData;
    }

@@ -94,22 +100,22 @@ public final class RecoveryData implements Parcelable {
        return mEncryptedRecoveryKeyBlob;
    }

    public static final Parcelable.Creator<RecoveryData> CREATOR =
            new Parcelable.Creator<RecoveryData>() {
        public RecoveryData createFromParcel(Parcel in) {
            return new RecoveryData(in);
    public static final Parcelable.Creator<KeychainSnapshot> CREATOR =
            new Parcelable.Creator<KeychainSnapshot>() {
        public KeychainSnapshot createFromParcel(Parcel in) {
            return new KeychainSnapshot(in);
        }

        public RecoveryData[] newArray(int length) {
            return new RecoveryData[length];
        public KeychainSnapshot[] newArray(int length) {
            return new KeychainSnapshot[length];
        }
    };

    /**
     * Builder for creating {@link RecoveryData}.
     * Builder for creating {@link KeychainSnapshot}.
     */
    public static class Builder {
        private RecoveryData mInstance = new RecoveryData();
        private KeychainSnapshot mInstance = new KeychainSnapshot();

        /**
         * Snapshot version for given account.
@@ -128,8 +134,9 @@ public final class RecoveryData implements Parcelable {
         * @param recoveryMetadata The UI and key derivation parameters
         * @return This builder.
         */
        public Builder setRecoveryMetadata(@NonNull List<RecoveryMetadata> recoveryMetadata) {
            mInstance.mRecoveryMetadata = recoveryMetadata;
        public Builder setKeychainProtectionParams(
                @NonNull List<KeychainProtectionParameter> recoveryMetadata) {
            mInstance.mKeychainProtectionParams = recoveryMetadata;
            return this;
        }

@@ -139,7 +146,7 @@ public final class RecoveryData implements Parcelable {
         * @param entryRecoveryData List of application keys
         * @return This builder.
         */
        public Builder setEntryRecoveryData(List<EntryRecoveryData> entryRecoveryData) {
        public Builder setWrappedApplicationKeys(List<WrappedApplicationKey> entryRecoveryData) {
            mInstance.mEntryRecoveryData = entryRecoveryData;
            return this;
        }
@@ -157,13 +164,13 @@ public final class RecoveryData implements Parcelable {


        /**
         * Creates a new {@link RecoveryData} instance.
         * Creates a new {@link KeychainSnapshot} instance.
         *
         * @return new instance
         * @throws NullPointerException if some required fields were not set.
         */
        public @NonNull RecoveryData build() {
            Preconditions.checkCollectionElementsNotNull(mInstance.mRecoveryMetadata,
        @NonNull public KeychainSnapshot build() {
            Preconditions.checkCollectionElementsNotNull(mInstance.mKeychainProtectionParams,
                    "recoveryMetadata");
            Preconditions.checkCollectionElementsNotNull(mInstance.mEntryRecoveryData,
                    "entryRecoveryData");
@@ -178,7 +185,7 @@ public final class RecoveryData implements Parcelable {
    @Override
    public void writeToParcel(Parcel out, int flags) {
        out.writeInt(mSnapshotVersion);
        out.writeTypedList(mRecoveryMetadata);
        out.writeTypedList(mKeychainProtectionParams);
        out.writeByteArray(mEncryptedRecoveryKeyBlob);
        out.writeTypedList(mEntryRecoveryData);
    }
@@ -186,11 +193,11 @@ public final class RecoveryData implements Parcelable {
    /**
     * @hide
     */
    protected RecoveryData(Parcel in) {
    protected KeychainSnapshot(Parcel in) {
        mSnapshotVersion = in.readInt();
        mRecoveryMetadata = in.createTypedArrayList(RecoveryMetadata.CREATOR);
        mKeychainProtectionParams = in.createTypedArrayList(KeychainProtectionParameter.CREATOR);
        mEncryptedRecoveryKeyBlob = in.createByteArray();
        mEntryRecoveryData = in.createTypedArrayList(EntryRecoveryData.CREATOR);
        mEntryRecoveryData = in.createTypedArrayList(WrappedApplicationKey.CREATOR);
    }

    @Override
+18 −17
Original line number Diff line number Diff line
@@ -99,11 +99,11 @@ public class RecoveryManager {
     * @return Data necessary to recover keystore.
     * @hide
     */
    public @NonNull RecoveryData getRecoveryData(@NonNull byte[] account)
    @NonNull public KeychainSnapshot getRecoveryData(@NonNull byte[] account)
            throws RecoveryManagerException {
        try {
            RecoveryData recoveryData = mBinder.getRecoveryData(account);
            return recoveryData;
            KeychainSnapshot keychainSnapshot = mBinder.getRecoveryData(account);
            return keychainSnapshot;
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        } catch (ServiceSpecificException e) {
@@ -136,7 +136,7 @@ public class RecoveryManager {
     * version. Version zero is used, if no snapshots were created for the account.
     *
     * @return Map from recovery agent accounts to snapshot versions.
     * @see RecoveryData#getSnapshotVersion
     * @see KeychainSnapshot#getSnapshotVersion
     * @hide
     */
    public @NonNull Map<byte[], Integer> getRecoverySnapshotVersions()
@@ -156,7 +156,7 @@ public class RecoveryManager {

    /**
     * Server parameters used to generate new recovery key blobs. This value will be included in
     * {@code RecoveryData.getEncryptedRecoveryKeyBlob()}. The same value must be included
     * {@code KeychainSnapshot.getEncryptedRecoveryKeyBlob()}. The same value must be included
     * in vaultParams {@link #startRecoverySession}
     *
     * @param serverParams included in recovery key blob.
@@ -230,11 +230,11 @@ public class RecoveryManager {
     * Specifies a set of secret types used for end-to-end keystore encryption. Knowing all of them
     * is necessary to recover data.
     *
     * @param secretTypes {@link RecoveryMetadata#TYPE_LOCKSCREEN} or {@link
     *     RecoveryMetadata#TYPE_CUSTOM_PASSWORD}
     * @param secretTypes {@link KeychainProtectionParameter#TYPE_LOCKSCREEN} or {@link
     *     KeychainProtectionParameter#TYPE_CUSTOM_PASSWORD}
     */
    public void setRecoverySecretTypes(
            @NonNull @RecoveryMetadata.UserSecretType int[] secretTypes)
            @NonNull @KeychainProtectionParameter.UserSecretType int[] secretTypes)
            throws RecoveryManagerException {
        try {
            mBinder.setRecoverySecretTypes(secretTypes);
@@ -247,12 +247,12 @@ public class RecoveryManager {

    /**
     * Defines a set of secret types used for end-to-end keystore encryption. Knowing all of them is
     * necessary to generate RecoveryData.
     * necessary to generate KeychainSnapshot.
     *
     * @return list of recovery secret types
     * @see RecoveryData
     * @see KeychainSnapshot
     */
    public @NonNull @RecoveryMetadata.UserSecretType int[] getRecoverySecretTypes()
    @NonNull public @KeychainProtectionParameter.UserSecretType int[] getRecoverySecretTypes()
            throws RecoveryManagerException {
        try {
            return mBinder.getRecoverySecretTypes();
@@ -271,7 +271,8 @@ public class RecoveryManager {
     * @return list of recovery secret types
     * @hide
     */
    public @NonNull @RecoveryMetadata.UserSecretType int[] getPendingRecoverySecretTypes()
    @NonNull
    public @KeychainProtectionParameter.UserSecretType int[] getPendingRecoverySecretTypes()
            throws RecoveryManagerException {
        try {
            return mBinder.getPendingRecoverySecretTypes();
@@ -285,14 +286,14 @@ public class RecoveryManager {
    /**
     * Method notifies KeyStore that a user-generated secret is available. This method generates a
     * symmetric session key which a trusted remote device can use to return a recovery key. Caller
     * should use {@link RecoveryMetadata#clearSecret} to override the secret value in
     * should use {@link KeychainProtectionParameter#clearSecret} to override the secret value in
     * memory.
     *
     * @param recoverySecret user generated secret together with parameters necessary to regenerate
     *     it on a new device.
     * @hide
     */
    public void recoverySecretAvailable(@NonNull RecoveryMetadata recoverySecret)
    public void recoverySecretAvailable(@NonNull KeychainProtectionParameter recoverySecret)
            throws RecoveryManagerException {
        try {
            mBinder.recoverySecretAvailable(recoverySecret);
@@ -326,7 +327,7 @@ public class RecoveryManager {
            @NonNull byte[] verifierPublicKey,
            @NonNull byte[] vaultParams,
            @NonNull byte[] vaultChallenge,
            @NonNull List<RecoveryMetadata> secrets)
            @NonNull List<KeychainProtectionParameter> secrets)
            throws RecoveryManagerException {
        try {
            byte[] recoveryClaim =
@@ -352,13 +353,13 @@ public class RecoveryManager {
     * @param recoveryKeyBlob Recovery blob encrypted by symmetric key generated for this session.
     * @param applicationKeys Application keys. Key material can be decrypted using recoveryKeyBlob
     *     and session. KeyStore only uses package names from the application info in {@link
     *     EntryRecoveryData}. Caller is responsibility to perform certificates check.
     *     WrappedApplicationKey}. Caller is responsibility to perform certificates check.
     * @return Map from alias to raw key material.
     */
    public Map<String, byte[]> recoverKeys(
            @NonNull String sessionId,
            @NonNull byte[] recoveryKeyBlob,
            @NonNull List<EntryRecoveryData> applicationKeys)
            @NonNull List<WrappedApplicationKey> applicationKeys)
            throws RecoveryManagerException {
        try {
            return (Map<String, byte[]>) mBinder.recoverKeys(
Loading