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

Commit 73d2f9c4 authored by Dmitry Dementyev's avatar Dmitry Dementyev Committed by Android (Google) Code Review
Browse files

Merge "Refactor KeyStore Recovery Manager."

parents 788df35b 7d8c78a2
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -17,4 +17,4 @@
package android.security.keystore;

/* @hide */
parcelable KeyDerivationParameters;
parcelable KeyDerivationParams;
+13 −18
Original line number Diff line number Diff line
@@ -28,27 +28,22 @@ import java.lang.annotation.RetentionPolicy;

/**
 * Collection of parameters which define a key derivation function.
 * Supports
 * Currently only supports salted SHA-256
 *
 * <ul>
 * <li>SHA256
 * <li>Argon2id
 * </ul>
 * @hide
 */
public final class KeyDerivationParameters implements Parcelable {
public final class KeyDerivationParams implements Parcelable {
    private final int mAlgorithm;
    private byte[] mSalt;

    /** @hide */
    @Retention(RetentionPolicy.SOURCE)
    @IntDef({ALGORITHM_SHA256, ALGORITHM_ARGON2ID})
    @IntDef(prefix = {"ALGORITHM_"}, value = {ALGORITHM_SHA256, ALGORITHM_ARGON2ID})
    public @interface KeyDerivationAlgorithm {
    }

    /**
     * Salted SHA256
     * @hide
     */
    public static final int ALGORITHM_SHA256 = 1;

@@ -62,11 +57,11 @@ public final class KeyDerivationParameters implements Parcelable {
    /**
     * Creates instance of the class to to derive key using salted SHA256 hash.
     */
    public static KeyDerivationParameters createSha256Parameters(@NonNull byte[] salt) {
        return new KeyDerivationParameters(ALGORITHM_SHA256, salt);
    public static KeyDerivationParams createSha256Params(@NonNull byte[] salt) {
        return new KeyDerivationParams(ALGORITHM_SHA256, salt);
    }

    private KeyDerivationParameters(@KeyDerivationAlgorithm int algorithm, @NonNull byte[] salt) {
    private KeyDerivationParams(@KeyDerivationAlgorithm int algorithm, @NonNull byte[] salt) {
        mAlgorithm = algorithm;
        mSalt = Preconditions.checkNotNull(salt);
    }
@@ -85,14 +80,14 @@ public final class KeyDerivationParameters implements Parcelable {
        return mSalt;
    }

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

        public KeyDerivationParameters[] newArray(int length) {
            return new KeyDerivationParameters[length];
        public KeyDerivationParams[] newArray(int length) {
            return new KeyDerivationParams[length];
        }
    };

@@ -108,7 +103,7 @@ public final class KeyDerivationParameters implements Parcelable {
    /**
     * @hide
     */
    protected KeyDerivationParameters(Parcel in) {
    protected KeyDerivationParams(Parcel in) {
        mAlgorithm = in.readInt();
        mSalt = in.createByteArray();
    }
+1 −2
Original line number Diff line number Diff line
@@ -38,7 +38,7 @@ import java.util.List;
 * @hide
 */
public final class RecoveryData implements Parcelable {
    private Integer mSnapshotVersion;
    private int mSnapshotVersion;
    private List<RecoveryMetadata> mRecoveryMetadata;
    private List<EntryRecoveryData> mEntryRecoveryData;
    private byte[] mEncryptedRecoveryKeyBlob;
@@ -163,7 +163,6 @@ public final class RecoveryData implements Parcelable {
         * @throws NullPointerException if some required fields were not set.
         */
        public @NonNull RecoveryData build() {
            Preconditions.checkNotNull(mInstance.mSnapshotVersion);
            Preconditions.checkCollectionElementsNotNull(mInstance.mRecoveryMetadata,
                    "recoveryMetadata");
            Preconditions.checkCollectionElementsNotNull(mInstance.mEntryRecoveryData,
+8 −112
Original line number Diff line number Diff line
@@ -23,8 +23,6 @@ import android.content.pm.PackageManager.NameNotFoundException;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.ServiceSpecificException;
import android.security.KeyStore;
import android.util.AndroidException;

import com.android.internal.widget.ILockSettings;

@@ -39,64 +37,6 @@ import java.util.Map;
 */
public class RecoveryManager {

    public static final int NO_ERROR = KeyStore.NO_ERROR;
    public static final int SYSTEM_ERROR = KeyStore.SYSTEM_ERROR;

    /**
     * Failed because the loader has not been initialized with a recovery public key yet.
     */
    public static final int ERROR_UNINITIALIZED_RECOVERY_PUBLIC_KEY = 20;

    /**
     * Failed because no snapshot is yet pending to be synced for the user.
     */
    public static final int ERROR_NO_SNAPSHOT_PENDING = 21;

    /**
     * Failed due to an error internal to AndroidKeyStore.
     */
    public static final int ERROR_KEYSTORE_INTERNAL_ERROR = 22;

    /**
     * Failed because the user does not have a lock screen set.
     */
    public static final int ERROR_INSECURE_USER = 24;

    /**
     * Failed because of an internal database error.
     */
    public static final int ERROR_DATABASE_ERROR = 25;

    /**
     * Failed because the provided certificate was not a valid X509 certificate.
     */
    public static final int ERROR_BAD_X509_CERTIFICATE = 26;

    /**
     * Should never be thrown - some algorithm that all AOSP implementations must support is
     * not available.
     */
    public static final int ERROR_UNEXPECTED_MISSING_ALGORITHM = 27;

    /**
     * The caller is attempting to perform an operation that is not yet fully supported in the API.
     */
    public static final int ERROR_NOT_YET_SUPPORTED = 28;

    /**
     * Error thrown if decryption failed. This might be because the tag is wrong, the key is wrong,
     * the data has become corrupted, the data has been tampered with, etc.
     */
    public static final int ERROR_DECRYPTION_FAILED = 29;

    /**
     * Rate limit is enforced to prevent using too many trusted remote devices, since each device
     * can have its own number of user secret guesses allowed.
     *
     * @hide
     */
    public static final int ERROR_RATE_LIMIT_EXCEEDED = 30;

    /** Key has been successfully synced. */
    public static final int RECOVERY_STATUS_SYNCED = 0;
    /** Waiting for recovery agent to sync the key. */
@@ -121,47 +61,6 @@ public class RecoveryManager {
        return new RecoveryManager(lockSettings);
    }

    /**
     * Exceptions returned by {@link RecoveryManager}.
     */
    public static class RecoveryManagerException extends AndroidException {
        private int mErrorCode;

        /**
         * Creates new {@link #RecoveryManagerException} instance from the error code.
         *
         * @param errorCode An error code, as listed at the top of this file.
         * @param message The associated error message.
         * @hide
         */
        public static RecoveryManagerException fromErrorCode(
                int errorCode, String message) {
            return new RecoveryManagerException(errorCode, message);
        }

        /**
         * Creates new {@link #RecoveryManagerException} from {@link
         * ServiceSpecificException}.
         *
         * @param e exception thrown on service side.
         * @hide
         */
        static RecoveryManagerException fromServiceSpecificException(
                ServiceSpecificException e) throws RecoveryManagerException {
            throw RecoveryManagerException.fromErrorCode(e.errorCode, e.getMessage());
        }

        private RecoveryManagerException(int errorCode, String message) {
            super(message);
            mErrorCode = errorCode;
        }

        /** Returns errorCode. */
        public int getErrorCode() {
            return mErrorCode;
        }
    }

    /**
     * Initializes key recovery service for the calling application. RecoveryManager
     * randomly chooses one of the keys from the list and keeps it to use for future key export
@@ -260,15 +159,14 @@ public class RecoveryManager {
     * {@code RecoveryData.getEncryptedRecoveryKeyBlob()}. The same value must be included
     * in vaultParams {@link #startRecoverySession}
     *
     * @param serverParameters included in recovery key blob.
     * @param serverParams included in recovery key blob.
     * @see #getRecoveryData
     * @throws RecoveryManagerException If parameters rotation is rate limited.
     * @hide
     */
    public void setServerParameters(long serverParameters)
            throws RecoveryManagerException {
    public void setServerParams(byte[] serverParams) throws RecoveryManagerException {
        try {
            mBinder.setServerParameters(serverParameters);
            mBinder.setServerParams(serverParams);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        } catch (ServiceSpecificException e) {
@@ -309,20 +207,17 @@ public class RecoveryManager {
     *   <li>{@link #RECOVERY_STATUS_PERMANENT_FAILURE}
     * </ul>
     *
     * @param packageName Application whose recoverable keys' statuses are to be retrieved. if
     *     {@code null} caller's package will be used.
     * @return {@code Map} from KeyStore alias to recovery status.
     * @see #setRecoveryStatus
     * @hide
     */
    public Map<String, Integer> getRecoveryStatus(@Nullable String packageName)
    public Map<String, Integer> getRecoveryStatus()
            throws RecoveryManagerException {
        try {
            // IPC doesn't support generic Maps.
            @SuppressWarnings("unchecked")
            Map<String, Integer> result =
                    (Map<String, Integer>)
                            mBinder.getRecoveryStatus(packageName);
                    (Map<String, Integer>) mBinder.getRecoveryStatus(/*packageName=*/ null);
            return result;
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
@@ -414,8 +309,9 @@ public class RecoveryManager {
     * return recovery key.
     *
     * @param sessionId ID for recovery session.
     * @param verifierPublicKey Certificate with Public key used to create the recovery blob on the
     *     source device. Keystore will verify the certificate using root of trust.
     * @param verifierPublicKey Encoded {@code java.security.cert.X509Certificate} with Public key
     * used to create the recovery blob on the source device.
     * Keystore will verify the certificate using root of trust.
     * @param vaultParams Must match the parameters in the corresponding field in the recovery blob.
     *     Used to limit number of guesses.
     * @param vaultChallenge Data passed from server for this recovery session and used to prevent
+111 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.security.keystore;

import android.os.ServiceSpecificException;

/**
 * Exception thrown by {@link RecoveryManager} methods.
 *
 * @hide
 */
public class RecoveryManagerException extends Exception {
    /**
     * Failed because the loader has not been initialized with a recovery public key yet.
     */
    public static final int ERROR_UNINITIALIZED_RECOVERY_PUBLIC_KEY = 20;

    /**
     * Failed because no snapshot is yet pending to be synced for the user.
     */
    public static final int ERROR_NO_SNAPSHOT_PENDING = 21;

    /**
     * Failed due to an error internal to AndroidKeyStore.
     */
    public static final int ERROR_KEYSTORE_INTERNAL_ERROR = 22;

    /**
     * Failed because the user does not have a lock screen set.
     */
    public static final int ERROR_INSECURE_USER = 24;

    /**
     * Failed because of an internal database error.
     */
    public static final int ERROR_DATABASE_ERROR = 25;

    /**
     * Failed because the provided certificate was not a valid X509 certificate.
     */
    public static final int ERROR_BAD_X509_CERTIFICATE = 26;

    /**
     * Should never be thrown - some algorithm that all AOSP implementations must support is
     * not available.
     */
    public static final int ERROR_UNEXPECTED_MISSING_ALGORITHM = 27;

    /**
     * Error thrown if decryption failed. This might be because the tag is wrong, the key is wrong,
     * the data has become corrupted, the data has been tampered with, etc.
     */
    public static final int ERROR_DECRYPTION_FAILED = 28;

    /**
     * Rate limit is enforced to prevent using too many trusted remote devices, since each device
     * can have its own number of user secret guesses allowed.
     *
     * @hide
     */
    public static final int ERROR_RATE_LIMIT_EXCEEDED = 29;

    private int mErrorCode;

    /**
     * Creates new {@link #RecoveryManagerException} instance from the error code.
     *
     * @param errorCode An error code, as listed at the top of this file.
     * @param message The associated error message.
     * @hide
     */
    public static RecoveryManagerException fromErrorCode(
            int errorCode, String message) {
        return new RecoveryManagerException(errorCode, message);
    }
    /**
     * Creates new {@link #RecoveryManagerException} from {@link
     * ServiceSpecificException}.
     *
     * @param e exception thrown on service side.
     * @hide
     */
    static RecoveryManagerException fromServiceSpecificException(
            ServiceSpecificException e) throws RecoveryManagerException {
        throw RecoveryManagerException.fromErrorCode(e.errorCode, e.getMessage());
    }

    private RecoveryManagerException(int errorCode, String message) {
        super(message);
        mErrorCode = errorCode;
    }

    /** Returns errorCode. */
    public int getErrorCode() {
        return mErrorCode;
    }
}
Loading