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

Commit 588a06f5 authored by Robert Berry's avatar Robert Berry Committed by Android (Google) Code Review
Browse files

Merge "Revert "Use RecoverySession object to hide session IDs""

parents 20f29fda 9fa87627
Loading
Loading
Loading
Loading
+0 −54
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 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;

/**
 * An attempt to recover a keychain protected by remote secure hardware.
 *
 * @hide
 */
public class RecoveryClaim {

    private final RecoverySession mRecoverySession;
    private final byte[] mClaimBytes;

    RecoveryClaim(RecoverySession recoverySession, byte[] claimBytes) {
        mRecoverySession = recoverySession;
        mClaimBytes = claimBytes;
    }

    /**
     * Returns the session associated with the recovery attempt. This is used to match the symmetric
     * key, which remains internal to the framework, for decrypting the claim response.
     *
     * @return The session data.
     */
    public RecoverySession getRecoverySession() {
        return mRecoverySession;
    }

    /**
     * Returns the encrypted claim's bytes.
     *
     * <p>This should be sent by the recovery agent to the remote secure hardware, which will use
     * it to decrypt the keychain, before sending it re-encrypted with the session's symmetric key
     * to the device.
     */
    public byte[] getClaimBytes() {
        return mClaimBytes;
    }
}
+12 −28
Original line number Diff line number Diff line
@@ -23,7 +23,6 @@ import android.content.pm.PackageManager.NameNotFoundException;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.ServiceSpecificException;
import android.util.Log;

import com.android.internal.widget.ILockSettings;

@@ -37,7 +36,6 @@ import java.util.Map;
 * @hide
 */
public class RecoveryManager {
    private static final String TAG = "RecoveryController";

    /** Key has been successfully synced. */
    public static final int RECOVERY_STATUS_SYNCED = 0;
@@ -373,6 +371,7 @@ public class RecoveryManager {
     * The method generates symmetric key for a session, which trusted remote device can use to
     * return recovery key.
     *
     * @param sessionId ID for recovery session.
     * @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.
@@ -381,31 +380,30 @@ public class RecoveryManager {
     * @param vaultChallenge Data passed from server for this recovery session and used to prevent
     *     replay attacks
     * @param secrets Secrets provided by user, the method only uses type and secret fields.
     * @return The recovery claim. Claim provides a binary blob with recovery claim. It is
     *     encrypted with verifierPublicKey and contains a proof of user secrets, session symmetric
     *     key and parameters necessary to identify the counter with the number of failed recovery
     *     attempts.
     * @return Binary blob with recovery claim. It is encrypted with verifierPublicKey and contains
     *     a proof of user secrets, session symmetric key and parameters necessary to identify the
     *     counter with the number of failed recovery attempts.
     * @throws BadCertificateFormatException if the {@code verifierPublicKey} is in an incorrect
     *     format.
     * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery
     *     service.
     */
    @NonNull public RecoveryClaim startRecoverySession(
    public @NonNull byte[] startRecoverySession(
            @NonNull String sessionId,
            @NonNull byte[] verifierPublicKey,
            @NonNull byte[] vaultParams,
            @NonNull byte[] vaultChallenge,
            @NonNull List<KeychainProtectionParams> secrets)
            throws BadCertificateFormatException, InternalRecoveryServiceException {
        try {
            RecoverySession recoverySession = RecoverySession.newInstance(this);
            byte[] recoveryClaim =
                    mBinder.startRecoverySession(
                            recoverySession.getSessionId(),
                            sessionId,
                            verifierPublicKey,
                            vaultParams,
                            vaultChallenge,
                            secrets);
            return new RecoveryClaim(recoverySession, recoveryClaim);
            return recoveryClaim;
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        } catch (ServiceSpecificException e) {
@@ -419,8 +417,8 @@ public class RecoveryManager {
    /**
     * Imports keys.
     *
     * @param session Related recovery session, as originally created by invoking
     *        {@link #startRecoverySession(byte[], byte[], byte[], List)}.
     * @param sessionId Id for recovery session, same as in
     *     {@link #startRecoverySession(String, byte[], byte[], byte[], List)}.
     * @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
@@ -431,14 +429,14 @@ public class RecoveryManager {
     * @throws InternalRecoveryServiceException if an error occurs internal to the recovery service.
     */
    public Map<String, byte[]> recoverKeys(
            @NonNull RecoverySession session,
            @NonNull String sessionId,
            @NonNull byte[] recoveryKeyBlob,
            @NonNull List<WrappedApplicationKey> applicationKeys)
            throws SessionExpiredException, DecryptionFailedException,
            InternalRecoveryServiceException {
        try {
            return (Map<String, byte[]>) mBinder.recoverKeys(
                    session.getSessionId(), recoveryKeyBlob, applicationKeys);
                    sessionId, recoveryKeyBlob, applicationKeys);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        } catch (ServiceSpecificException e) {
@@ -452,20 +450,6 @@ public class RecoveryManager {
        }
    }

    /**
     * Deletes all data associated with {@code session}. Should not be invoked directly but via
     * {@link RecoverySession#close()}.
     *
     * @hide
     */
    void closeSession(RecoverySession session) {
        try {
            mBinder.closeSession(session.getSessionId());
        } catch (RemoteException | ServiceSpecificException e) {
            Log.e(TAG, "Unexpected error trying to close session", e);
        }
    }

    /**
     * Generates a key called {@code alias} and loads it into the recoverable key store. Returns the
     * raw material of the key.
+0 −71
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 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 java.security.SecureRandom;

/**
 * Session to recover a {@link KeychainSnapshot} from the remote trusted hardware, initiated by a
 * recovery agent.
 *
 * @hide
 */
public class RecoverySession implements AutoCloseable {

    private static final int SESSION_ID_LENGTH_BYTES = 16;

    private final String mSessionId;
    private final RecoveryManager mRecoveryManager;

    private RecoverySession(RecoveryManager recoveryManager, String sessionId) {
        mRecoveryManager = recoveryManager;
        mSessionId = sessionId;
    }

    /**
     * A new session, started by {@code recoveryManager}.
     */
    static RecoverySession newInstance(RecoveryManager recoveryManager) {
        return new RecoverySession(recoveryManager, newSessionId());
    }

    /**
     * Returns a new random session ID.
     */
    private static String newSessionId() {
        SecureRandom secureRandom = new SecureRandom();
        byte[] sessionId = new byte[SESSION_ID_LENGTH_BYTES];
        secureRandom.nextBytes(sessionId);
        StringBuilder sb = new StringBuilder();
        for (byte b : sessionId) {
            sb.append(Byte.toHexString(b, /*upperCase=*/ false));
        }
        return sb.toString();
    }

    /**
     * An internal session ID, used by the framework to match recovery claims to snapshot responses.
     */
    String getSessionId() {
        return mSessionId;
    }

    @Override
    public void close() {
        mRecoveryManager.closeSession(this);
    }
}
+0 −1
Original line number Diff line number Diff line
@@ -81,5 +81,4 @@ interface ILockSettings {
            in List<KeychainProtectionParams> secrets);
    Map/*<String, byte[]>*/ recoverKeys(in String sessionId, in byte[] recoveryKeyBlob,
            in List<WrappedApplicationKey> applicationKeys);
     void closeSession(in String sessionId);
}
+0 −5
Original line number Diff line number Diff line
@@ -2028,11 +2028,6 @@ public class LockSettingsService extends ILockSettings.Stub {
                vaultParams, vaultChallenge, secrets);
    }

    @Override
    public void closeSession(@NonNull String sessionId) throws RemoteException {
        mRecoverableKeyStoreManager.closeSession(sessionId);
    }

    @Override
    public Map<String, byte[]> recoverKeys(@NonNull String sessionId,
            @NonNull byte[] recoveryKeyBlob, @NonNull List<WrappedApplicationKey> applicationKeys)
Loading