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

Commit bd8d1a53 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Update recoverKeys to return raw material"

parents 749713e4 bd4c43c6
Loading
Loading
Loading
Loading
+5 −3
Original line number Diff line number Diff line
@@ -423,19 +423,21 @@ public class RecoverableKeyStoreLoader {
    /**
     * Imports keys.
     *
     * @param sessionId Id for recovery session, same as in = {@link startRecoverySession}.
     * @param sessionId Id for recovery session, same as in
     *     {@link #startRecoverySession(String, byte[], byte[], byte[], List)} on}.
     * @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
     *     KeyEntryRecoveryData}. Caller is responsibility to perform certificates check.
     * @return Map from alias to raw key material.
     */
    public void recoverKeys(
    public Map<String, byte[]> recoverKeys(
            @NonNull String sessionId,
            @NonNull byte[] recoveryKeyBlob,
            @NonNull List<KeyEntryRecoveryData> applicationKeys)
            throws RecoverableKeyStoreLoaderException {
        try {
            mBinder.recoverKeys(
            return (Map<String, byte[]>) mBinder.recoverKeys(
                    sessionId, recoveryKeyBlob, applicationKeys, UserHandle.getCallingUserId());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
+1 −1
Original line number Diff line number Diff line
@@ -78,6 +78,6 @@ interface ILockSettings {
    byte[] startRecoverySession(in String sessionId,
            in byte[] verifierPublicKey, in byte[] vaultParams, in byte[] vaultChallenge,
            in List<KeyStoreRecoveryMetadata> secrets, int userId);
    void recoverKeys(in String sessionId, in byte[] recoveryKeyBlob,
    Map/*<String, byte[]>*/ recoverKeys(in String sessionId, in byte[] recoveryKeyBlob,
            in List<KeyEntryRecoveryData> applicationKeys, int userId);
}
+3 −3
Original line number Diff line number Diff line
@@ -2021,11 +2021,11 @@ public class LockSettingsService extends ILockSettings.Stub {
    }

    @Override
    public void recoverKeys(@NonNull String sessionId, @NonNull byte[] recoveryKeyBlob,
    public Map<String, byte[]> recoverKeys(@NonNull String sessionId, @NonNull byte[] recoveryKeyBlob,
            @NonNull List<KeyEntryRecoveryData> applicationKeys, @UserIdInt int userId)
            throws RemoteException {
        mRecoverableKeyStoreManager.recoverKeys(sessionId, recoveryKeyBlob, applicationKeys,
                userId);
        return mRecoverableKeyStoreManager.recoverKeys(
                sessionId, recoveryKeyBlob, applicationKeys, userId);
    }

    private static final String[] VALID_SETTINGS = new String[] {
+11 −9
Original line number Diff line number Diff line
@@ -42,6 +42,7 @@ import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
@@ -308,8 +309,6 @@ public class RecoverableKeyStoreManager {
     * Invoked by a recovery agent after a successful recovery claim is sent to the remote vault
     * service.
     *
     * <p>TODO: should also load into AndroidKeyStore.
     *
     * @param sessionId The session ID used to generate the claim. See
     *     {@link #startRecoverySession(String, byte[], byte[], byte[], List, int)}.
     * @param encryptedRecoveryKey The encrypted recovery key blob returned by the remote vault
@@ -317,9 +316,10 @@ public class RecoverableKeyStoreManager {
     * @param applicationKeys The encrypted key blobs returned by the remote vault service. These
     *     were wrapped with the recovery key.
     * @param uid The uid of the recovery agent.
     * @return Map from alias to raw key material.
     * @throws RemoteException if an error occurred recovering the keys.
     */
    public void recoverKeys(
    public Map<String, byte[]> recoverKeys(
            @NonNull String sessionId,
            @NonNull byte[] encryptedRecoveryKey,
            @NonNull List<KeyEntryRecoveryData> applicationKeys,
@@ -335,7 +335,7 @@ public class RecoverableKeyStoreManager {

        try {
            byte[] recoveryKey = decryptRecoveryKey(sessionEntry, encryptedRecoveryKey);
            recoverApplicationKeys(recoveryKey, applicationKeys);
            return recoverApplicationKeys(recoveryKey, applicationKeys);
        } finally {
            sessionEntry.destroy();
            mRecoverySessionStorage.remove(uid);
@@ -370,20 +370,21 @@ public class RecoverableKeyStoreManager {
    /**
     * Uses {@code recoveryKey} to decrypt {@code applicationKeys}.
     *
     * <p>TODO: and load them into store?
     *
     * @return Map from alias to raw key material.
     * @throws RemoteException if an error occurred decrypting the keys.
     */
    private void recoverApplicationKeys(
    private Map<String, byte[]> recoverApplicationKeys(
            @NonNull byte[] recoveryKey,
            @NonNull List<KeyEntryRecoveryData> applicationKeys) throws RemoteException {
        HashMap<String, byte[]> keyMaterialByAlias = new HashMap<>();
        for (KeyEntryRecoveryData applicationKey : applicationKeys) {
            String alias = new String(applicationKey.getAlias(), StandardCharsets.UTF_8);
            byte[] encryptedKeyMaterial = applicationKey.getEncryptedKeyMaterial();

            try {
                // TODO: put decrypted key material in appropriate AndroidKeyStore
                byte[] keyMaterial =
                        KeySyncUtils.decryptApplicationKey(recoveryKey, encryptedKeyMaterial);
                keyMaterialByAlias.put(alias, keyMaterial);
            } catch (NoSuchAlgorithmException e) {
                // Should never happen: all the algorithms used are required by AOSP implementations
                throw new RemoteException(
@@ -399,6 +400,7 @@ public class RecoverableKeyStoreManager {
                    /*writeableStackTrace=*/ true);
            }
        }
        return keyMaterialByAlias;
    }

    /**
+10 −6
Original line number Diff line number Diff line
@@ -285,7 +285,7 @@ public class RecoverableKeyStoreManagerTest {
    }

    @Test
    public void recoverKeys_doesNotThrowIfAllIsOk() throws Exception {
    public void recoverKeys_returnsDecryptedKeys() throws Exception {
        mRecoverableKeyStoreManager.startRecoverySession(
                TEST_SESSION_ID,
                TEST_PUBLIC_KEY,
@@ -302,16 +302,19 @@ public class RecoverableKeyStoreManagerTest {
        SecretKey recoveryKey = randomRecoveryKey();
        byte[] encryptedClaimResponse = encryptClaimResponse(
                keyClaimant, TEST_SECRET, TEST_VAULT_PARAMS, recoveryKey);
        byte[] applicationKeyBytes = randomBytes(32);
        KeyEntryRecoveryData applicationKey = new KeyEntryRecoveryData(
                TEST_ALIAS.getBytes(StandardCharsets.UTF_8),
                randomEncryptedApplicationKey(recoveryKey)
        );
                encryptedApplicationKey(recoveryKey, applicationKeyBytes));

        mRecoverableKeyStoreManager.recoverKeys(
        Map<String, byte[]> recoveredKeys = mRecoverableKeyStoreManager.recoverKeys(
                TEST_SESSION_ID,
                encryptedClaimResponse,
                ImmutableList.of(applicationKey),
                TEST_USER_ID);

        assertThat(recoveredKeys).hasSize(1);
        assertThat(recoveredKeys.get(TEST_ALIAS)).isEqualTo(applicationKeyBytes);
    }

    @Test
@@ -387,9 +390,10 @@ public class RecoverableKeyStoreManagerTest {
        assertThat(statuses).containsEntry(alias2, status); // updated
    }

    private static byte[] randomEncryptedApplicationKey(SecretKey recoveryKey) throws Exception {
    private static byte[] encryptedApplicationKey(
            SecretKey recoveryKey, byte[] applicationKey) throws Exception {
        return KeySyncUtils.encryptKeysWithRecoveryKey(recoveryKey, ImmutableMap.of(
                "alias", new SecretKeySpec(randomBytes(32), "AES")
                "alias", new SecretKeySpec(applicationKey, "AES")
        )).get("alias");
    }