OSDN Git Service

Merge "Prepare KeyChainSnapshot to removing deprecated getTrustedHardwarePublicKey...
authorDmitry Dementyev <dementyev@google.com>
Fri, 23 Mar 2018 17:16:17 +0000 (17:16 +0000)
committerAndroid (Google) Code Review <android-gerrit@google.com>
Fri, 23 Mar 2018 17:16:17 +0000 (17:16 +0000)
core/java/android/security/keystore/recovery/KeyChainSnapshot.java
services/core/java/com/android/server/locksettings/recoverablekeystore/storage/PersistentKeyChainSnapshot.java [deleted file]
services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java
services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/TestData.java
services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/PersistentKeyChainSnapshotTest.java [deleted file]

index 00f54e1..69b9123 100644 (file)
@@ -127,18 +127,13 @@ public final class KeyChainSnapshot implements Parcelable {
     /**
      * CertPath containing the public key used to encrypt {@code encryptedRecoveryKeyBlob}.
      */
-    // TODO: Change to @NonNull
-    public CertPath getTrustedHardwareCertPath() {
-        if (mCertPath == null) {
-            return null;
-        } else {
-            try {
-                return mCertPath.getCertPath();
-            } catch (CertificateException e) {
-                // Rethrow an unchecked exception as it should not happen. If such an issue exists,
-                // an exception should have been thrown during service initialization.
-                throw new BadParcelableException(e);
-            }
+    public @NonNull CertPath getTrustedHardwareCertPath() {
+        try {
+            return mCertPath.getCertPath();
+        } catch (CertificateException e) {
+            // Rethrow an unchecked exception as it should not happen. If such an issue exists,
+            // an exception should have been thrown during service initialization.
+            throw new BadParcelableException(e);
         }
     }
 
@@ -248,13 +243,9 @@ public final class KeyChainSnapshot implements Parcelable {
          * @throws CertificateException if the given certificate path cannot be encoded properly
          * @return This builder.
          */
-        public Builder setTrustedHardwareCertPath(CertPath certPath) throws CertificateException {
-            // TODO: Make it NonNull when the caller code is all updated
-            if (certPath == null) {
-                mInstance.mCertPath = null;
-            } else {
-                mInstance.mCertPath = RecoveryCertPath.createRecoveryCertPath(certPath);
-            }
+        public Builder setTrustedHardwareCertPath(@NonNull CertPath certPath)
+                throws CertificateException {
+            mInstance.mCertPath = RecoveryCertPath.createRecoveryCertPath(certPath);
             return this;
         }
 
@@ -282,7 +273,7 @@ public final class KeyChainSnapshot implements Parcelable {
         }
 
         /**
-         * Sets recovery key blob
+         * Sets recovery key blob.
          *
          * @param encryptedRecoveryKeyBlob The recovery key blob.
          * @return This builder.
@@ -297,7 +288,7 @@ public final class KeyChainSnapshot implements Parcelable {
          * Creates a new {@link KeyChainSnapshot} instance.
          *
          * @return new instance
-         * @throws NullPointerException if some required fields were not set.
+         * @throws NullPointerException if some of the required fields were not set.
          */
         @NonNull public KeyChainSnapshot build() {
             Preconditions.checkCollectionElementsNotNull(mInstance.mKeyChainProtectionParams,
@@ -306,6 +297,7 @@ public final class KeyChainSnapshot implements Parcelable {
                     "entryRecoveryData");
             Preconditions.checkNotNull(mInstance.mEncryptedRecoveryKeyBlob);
             Preconditions.checkNotNull(mInstance.mServerParams);
+            Preconditions.checkNotNull(mInstance.mCertPath);
             return mInstance;
         }
     }
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/PersistentKeyChainSnapshot.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/PersistentKeyChainSnapshot.java
deleted file mode 100644 (file)
index 52381b8..0000000
+++ /dev/null
@@ -1,298 +0,0 @@
-/*
- * 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 com.android.server.locksettings.recoverablekeystore.storage;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.security.keystore.recovery.KeyChainProtectionParams;
-import android.security.keystore.recovery.KeyChainSnapshot;
-import android.security.keystore.recovery.KeyDerivationParams;
-import android.security.keystore.recovery.WrappedApplicationKey;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.ArrayUtils;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * This class provides helper methods serialize and deserialize {@link KeyChainSnapshot}.
- *
- * <p> It is necessary since {@link android.os.Parcelable} is not designed for persistent storage.
- *
- * <p> For every list, length is stored before the elements.
- *
- */
-public class PersistentKeyChainSnapshot {
-    private static final int VERSION = 1;
-    private static final int NULL_LIST_LENGTH = -1;
-
-    private DataInputStream mInput;
-    private DataOutputStream mOut;
-    private ByteArrayOutputStream mOutStream;
-
-    @VisibleForTesting
-    PersistentKeyChainSnapshot() {
-    }
-
-    @VisibleForTesting
-    void initReader(byte[] input) {
-        mInput = new DataInputStream(new ByteArrayInputStream(input));
-    }
-
-    @VisibleForTesting
-    void initWriter() {
-        mOutStream = new ByteArrayOutputStream();
-        mOut = new DataOutputStream(mOutStream);
-    }
-
-    @VisibleForTesting
-    byte[] getOutput() {
-        return mOutStream.toByteArray();
-    }
-
-    /**
-     * Converts {@link KeyChainSnapshot} to its binary representation.
-     *
-     * @param snapshot The snapshot.
-     *
-     * @throws IOException if serialization failed.
-     */
-    public static byte[] serialize(@NonNull KeyChainSnapshot snapshot) throws IOException {
-        PersistentKeyChainSnapshot writer = new PersistentKeyChainSnapshot();
-        writer.initWriter();
-        writer.writeInt(VERSION);
-        writer.writeKeyChainSnapshot(snapshot);
-        return writer.getOutput();
-    }
-
-    /**
-     * deserializes {@link KeyChainSnapshot}.
-     *
-     * @input input - byte array produced by {@link serialize} method.
-     * @throws IOException if parsing failed.
-     */
-    public static @NonNull KeyChainSnapshot deserialize(@NonNull byte[] input)
-            throws IOException {
-        PersistentKeyChainSnapshot reader = new PersistentKeyChainSnapshot();
-        reader.initReader(input);
-        try {
-            int version = reader.readInt();
-            if (version != VERSION) {
-                throw new IOException("Unsupported version " + version);
-            }
-            return reader.readKeyChainSnapshot();
-        } catch (IOException e) {
-            throw new IOException("Malformed KeyChainSnapshot", e);
-        }
-    }
-
-    /**
-     * Must be in sync with {@link KeyChainSnapshot.writeToParcel}
-     */
-    @VisibleForTesting
-    void writeKeyChainSnapshot(KeyChainSnapshot snapshot) throws IOException {
-        writeInt(snapshot.getSnapshotVersion());
-        writeProtectionParamsList(snapshot.getKeyChainProtectionParams());
-        writeBytes(snapshot.getEncryptedRecoveryKeyBlob());
-        writeKeysList(snapshot.getWrappedApplicationKeys());
-
-        writeInt(snapshot.getMaxAttempts());
-        writeLong(snapshot.getCounterId());
-        writeBytes(snapshot.getServerParams());
-        writeBytes(snapshot.getTrustedHardwarePublicKey());
-    }
-
-    @VisibleForTesting
-    KeyChainSnapshot readKeyChainSnapshot() throws IOException {
-        int snapshotVersion = readInt();
-        List<KeyChainProtectionParams> protectionParams = readProtectionParamsList();
-        byte[] encryptedRecoveryKey = readBytes();
-        List<WrappedApplicationKey> keysList = readKeysList();
-
-        int maxAttempts = readInt();
-        long conterId = readLong();
-        byte[] serverParams = readBytes();
-        byte[] trustedHardwarePublicKey = readBytes();
-
-        return new KeyChainSnapshot.Builder()
-                .setSnapshotVersion(snapshotVersion)
-                .setKeyChainProtectionParams(protectionParams)
-                .setEncryptedRecoveryKeyBlob(encryptedRecoveryKey)
-                .setWrappedApplicationKeys(keysList)
-                .setMaxAttempts(maxAttempts)
-                .setCounterId(conterId)
-                .setServerParams(serverParams)
-                .setTrustedHardwarePublicKey(trustedHardwarePublicKey)
-                .build();
-    }
-
-    @VisibleForTesting
-    void writeProtectionParamsList(
-            @NonNull List<KeyChainProtectionParams> ProtectionParamsList) throws IOException {
-        writeInt(ProtectionParamsList.size());
-        for (KeyChainProtectionParams protectionParams : ProtectionParamsList) {
-            writeProtectionParams(protectionParams);
-        }
-    }
-
-    @VisibleForTesting
-    List<KeyChainProtectionParams> readProtectionParamsList() throws IOException {
-        int length = readInt();
-        List<KeyChainProtectionParams> result = new ArrayList<>(length);
-        for (int i = 0; i < length; i++) {
-            result.add(readProtectionParams());
-        }
-        return result;
-    }
-
-    /**
-     * Must be in sync with {@link KeyChainProtectionParams.writeToParcel}
-     */
-    @VisibleForTesting
-    void writeProtectionParams(@NonNull KeyChainProtectionParams protectionParams)
-            throws IOException {
-        if (!ArrayUtils.isEmpty(protectionParams.getSecret())) {
-            // Extra security check.
-            throw new RuntimeException("User generated secret should not be stored");
-        }
-        writeInt(protectionParams.getUserSecretType());
-        writeInt(protectionParams.getLockScreenUiFormat());
-        writeKeyDerivationParams(protectionParams.getKeyDerivationParams());
-        writeBytes(protectionParams.getSecret());
-    }
-
-    @VisibleForTesting
-    KeyChainProtectionParams readProtectionParams() throws IOException {
-        int userSecretType = readInt();
-        int lockScreenUiFormat = readInt();
-        KeyDerivationParams derivationParams = readKeyDerivationParams();
-        byte[] secret = readBytes();
-        return new KeyChainProtectionParams.Builder()
-                .setUserSecretType(userSecretType)
-                .setLockScreenUiFormat(lockScreenUiFormat)
-                .setKeyDerivationParams(derivationParams)
-                .setSecret(secret)
-                .build();
-    }
-
-    /**
-     * Must be in sync with {@link KeyDerivationParams.writeToParcel}
-     */
-    @VisibleForTesting
-    void writeKeyDerivationParams(@NonNull KeyDerivationParams Params) throws IOException {
-        writeInt(Params.getAlgorithm());
-        writeBytes(Params.getSalt());
-    }
-
-    @VisibleForTesting
-    KeyDerivationParams readKeyDerivationParams() throws IOException {
-        int algorithm = readInt();
-        byte[] salt = readBytes();
-        return KeyDerivationParams.createSha256Params(salt);
-    }
-
-    @VisibleForTesting
-    void writeKeysList(@NonNull List<WrappedApplicationKey> applicationKeys) throws IOException {
-        writeInt(applicationKeys.size());
-        for (WrappedApplicationKey keyEntry : applicationKeys) {
-            writeKeyEntry(keyEntry);
-        }
-    }
-
-    @VisibleForTesting
-    List<WrappedApplicationKey> readKeysList() throws IOException {
-        int length = readInt();
-        List<WrappedApplicationKey> result = new ArrayList<>(length);
-        for (int i = 0; i < length; i++) {
-            result.add(readKeyEntry());
-        }
-        return result;
-    }
-
-    /**
-     * Must be in sync with {@link WrappedApplicationKey.writeToParcel}
-     */
-    @VisibleForTesting
-    void writeKeyEntry(@NonNull WrappedApplicationKey keyEntry) throws IOException {
-        mOut.writeUTF(keyEntry.getAlias());
-        writeBytes(keyEntry.getEncryptedKeyMaterial());
-        writeBytes(keyEntry.getAccount());
-    }
-
-    @VisibleForTesting
-    WrappedApplicationKey readKeyEntry() throws IOException {
-        String alias = mInput.readUTF();
-        byte[] keyMaterial = readBytes();
-        byte[] account = readBytes();
-        return new WrappedApplicationKey.Builder()
-                .setAlias(alias)
-                .setEncryptedKeyMaterial(keyMaterial)
-                .setAccount(account)
-                .build();
-    }
-
-    @VisibleForTesting
-    void writeInt(int value) throws IOException {
-        mOut.writeInt(value);
-    }
-
-    @VisibleForTesting
-    int readInt() throws IOException {
-        return mInput.readInt();
-    }
-
-    @VisibleForTesting
-    void writeLong(long value) throws IOException {
-        mOut.writeLong(value);
-    }
-
-    @VisibleForTesting
-    long readLong() throws IOException {
-        return mInput.readLong();
-    }
-
-    @VisibleForTesting
-    void writeBytes(@Nullable byte[] value) throws IOException {
-        if (value == null) {
-            writeInt(NULL_LIST_LENGTH);
-            return;
-        }
-        writeInt(value.length);
-        mOut.write(value, 0, value.length);
-    }
-
-    /**
-     * Reads @code{byte[]} from current position. Converts {@code null} to an empty array.
-     */
-    @VisibleForTesting
-    @NonNull byte[] readBytes() throws IOException {
-        int length = readInt();
-        if (length == NULL_LIST_LENGTH) {
-            return new byte[]{};
-        }
-        byte[] result = new byte[length];
-        mInput.read(result, 0, result.length);
-        return result;
-    }
-}
-
index 25747b8..0ea2317 100644 (file)
@@ -62,7 +62,6 @@ import org.mockito.MockitoAnnotations;
 
 import java.io.File;
 import java.nio.charset.StandardCharsets;
-import java.security.KeyPair;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Random;
@@ -95,7 +94,6 @@ public class KeySyncTaskTest {
     private RecoverySnapshotStorage mRecoverySnapshotStorage;
     private RecoverableKeyStoreDb mRecoverableKeyStoreDb;
     private File mDatabaseFile;
-    private KeyPair mKeyPair;
     private AndroidKeyStoreSecretKey mWrappingKey;
     private PlatformEncryptionKey mEncryptKey;
 
@@ -108,7 +106,6 @@ public class KeySyncTaskTest {
         Context context = InstrumentationRegistry.getTargetContext();
         mDatabaseFile = context.getDatabasePath(DATABASE_FILE_NAME);
         mRecoverableKeyStoreDb = RecoverableKeyStoreDb.newInstance(context);
-        mKeyPair = SecureBox.genKeyPair();
 
         mRecoverableKeyStoreDb.setRecoverySecretTypes(TEST_USER_ID, TEST_RECOVERY_AGENT_UID,
                 new int[] {TYPE_LOCKSCREEN});
@@ -249,8 +246,8 @@ public class KeySyncTaskTest {
                 TEST_RECOVERY_AGENT_UID,
                 TEST_APP_KEY_ALIAS,
                 WrappedKey.fromSecretKey(mEncryptKey, applicationKey));
-        mRecoverableKeyStoreDb.setRecoveryServicePublicKey(
-                TEST_USER_ID, TEST_RECOVERY_AGENT_UID, mKeyPair.getPublic());
+        mRecoverableKeyStoreDb.setRecoveryServiceCertPath(
+                TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TestData.CERT_PATH_1);
         when(mSnapshotListenersStorage.hasListener(TEST_RECOVERY_AGENT_UID)).thenReturn(true);
 
         mKeySyncTask.run();
@@ -265,8 +262,8 @@ public class KeySyncTaskTest {
                 TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_VAULT_HANDLE);
         mRecoverableKeyStoreDb.setPlatformKeyGenerationId(TEST_USER_ID, TEST_GENERATION_ID);
         addApplicationKey(TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_APP_KEY_ALIAS);
-        mRecoverableKeyStoreDb.setRecoveryServicePublicKey(
-                TEST_USER_ID, TEST_RECOVERY_AGENT_UID, mKeyPair.getPublic());
+        mRecoverableKeyStoreDb.setRecoveryServiceCertPath(
+                TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TestData.CERT_PATH_1);
 
         mKeySyncTask.run();
 
@@ -275,8 +272,8 @@ public class KeySyncTaskTest {
 
     @Test
     public void run_sendsEncryptedKeysIfAvailableToSync_withRawPublicKey() throws Exception {
-        mRecoverableKeyStoreDb.setRecoveryServicePublicKey(
-                TEST_USER_ID, TEST_RECOVERY_AGENT_UID, mKeyPair.getPublic());
+        mRecoverableKeyStoreDb.setRecoveryServiceCertPath(
+                TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TestData.CERT_PATH_1);
 
         mRecoverableKeyStoreDb.setServerParams(
                 TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_VAULT_HANDLE);
@@ -301,7 +298,7 @@ public class KeySyncTaskTest {
                 lockScreenHash,
                 keyChainSnapshot.getEncryptedRecoveryKeyBlob(),
                 /*vaultParams=*/ KeySyncUtils.packVaultParams(
-                        mKeyPair.getPublic(),
+                        TestData.CERT_1_PUBLIC_KEY,
                         counterId,
                         /*maxAttempts=*/ 10,
                         TEST_VAULT_HANDLE));
@@ -309,8 +306,8 @@ public class KeySyncTaskTest {
         assertThat(applicationKeys).hasSize(1);
         assertThat(keyChainSnapshot.getCounterId()).isEqualTo(counterId);
         assertThat(keyChainSnapshot.getMaxAttempts()).isEqualTo(10);
-        assertThat(keyChainSnapshot.getTrustedHardwarePublicKey())
-                .isEqualTo(SecureBox.encodePublicKey(mKeyPair.getPublic()));
+        assertThat(keyChainSnapshot.getTrustedHardwareCertPath())
+                .isEqualTo(TestData.CERT_PATH_1);
         assertThat(keyChainSnapshot.getServerParams()).isEqualTo(TEST_VAULT_HANDLE);
         WrappedApplicationKey keyData = applicationKeys.get(0);
         assertEquals(TEST_APP_KEY_ALIAS, keyData.getAlias());
@@ -335,15 +332,14 @@ public class KeySyncTaskTest {
         verify(mSnapshotListenersStorage).recoverySnapshotAvailable(TEST_RECOVERY_AGENT_UID);
         List<WrappedApplicationKey> applicationKeys = keyChainSnapshot.getWrappedApplicationKeys();
         assertThat(applicationKeys).hasSize(1);
-        assertThat(keyChainSnapshot.getTrustedHardwarePublicKey())
-                .isEqualTo(SecureBox.encodePublicKey(
-                        TestData.CERT_PATH_1.getCertificates().get(0).getPublicKey()));
+        assertThat(keyChainSnapshot.getTrustedHardwareCertPath())
+                .isEqualTo(TestData.CERT_PATH_1);
     }
 
     @Test
     public void run_setsCorrectSnapshotVersion() throws Exception {
-        mRecoverableKeyStoreDb.setRecoveryServicePublicKey(
-                TEST_USER_ID, TEST_RECOVERY_AGENT_UID, mKeyPair.getPublic());
+        mRecoverableKeyStoreDb.setRecoveryServiceCertPath(
+                TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TestData.CERT_PATH_1);
         when(mSnapshotListenersStorage.hasListener(TEST_RECOVERY_AGENT_UID)).thenReturn(true);
         addApplicationKey(TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_APP_KEY_ALIAS);
 
@@ -361,8 +357,8 @@ public class KeySyncTaskTest {
 
     @Test
     public void run_recreatesMissingSnapshot() throws Exception {
-        mRecoverableKeyStoreDb.setRecoveryServicePublicKey(
-                TEST_USER_ID, TEST_RECOVERY_AGENT_UID, mKeyPair.getPublic());
+        mRecoverableKeyStoreDb.setRecoveryServiceCertPath(
+                TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TestData.CERT_PATH_1);
         when(mSnapshotListenersStorage.hasListener(TEST_RECOVERY_AGENT_UID)).thenReturn(true);
         addApplicationKey(TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_APP_KEY_ALIAS);
 
@@ -391,8 +387,8 @@ public class KeySyncTaskTest {
                 /*credentialUpdated=*/ false,
                 mPlatformKeyManager);
 
-        mRecoverableKeyStoreDb.setRecoveryServicePublicKey(
-                TEST_USER_ID, TEST_RECOVERY_AGENT_UID, mKeyPair.getPublic());
+        mRecoverableKeyStoreDb.setRecoveryServiceCertPath(
+                TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TestData.CERT_PATH_1);
         when(mSnapshotListenersStorage.hasListener(TEST_RECOVERY_AGENT_UID)).thenReturn(true);
         SecretKey applicationKey =
                 addApplicationKey(TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_APP_KEY_ALIAS);
@@ -417,8 +413,8 @@ public class KeySyncTaskTest {
                 /*credentialUpdated=*/ false,
                 mPlatformKeyManager);
 
-        mRecoverableKeyStoreDb.setRecoveryServicePublicKey(
-                TEST_USER_ID, TEST_RECOVERY_AGENT_UID, mKeyPair.getPublic());
+        mRecoverableKeyStoreDb.setRecoveryServiceCertPath(
+                TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TestData.CERT_PATH_1);
         when(mSnapshotListenersStorage.hasListener(TEST_RECOVERY_AGENT_UID)).thenReturn(true);
         SecretKey applicationKey =
                 addApplicationKey(TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_APP_KEY_ALIAS);
@@ -444,8 +440,8 @@ public class KeySyncTaskTest {
                 /*credentialUpdated=*/ false,
                 mPlatformKeyManager);
 
-        mRecoverableKeyStoreDb.setRecoveryServicePublicKey(
-                TEST_USER_ID, TEST_RECOVERY_AGENT_UID, mKeyPair.getPublic());
+        mRecoverableKeyStoreDb.setRecoveryServiceCertPath(
+                TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TestData.CERT_PATH_1);
         when(mSnapshotListenersStorage.hasListener(TEST_RECOVERY_AGENT_UID)).thenReturn(true);
         SecretKey applicationKey =
                 addApplicationKey(TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_APP_KEY_ALIAS);
@@ -460,10 +456,10 @@ public class KeySyncTaskTest {
 
     @Test
     public void run_sendsEncryptedKeysWithTwoRegisteredAgents() throws Exception {
-        mRecoverableKeyStoreDb.setRecoveryServicePublicKey(
-                TEST_USER_ID, TEST_RECOVERY_AGENT_UID, mKeyPair.getPublic());
-        mRecoverableKeyStoreDb.setRecoveryServicePublicKey(
-                TEST_USER_ID, TEST_RECOVERY_AGENT_UID2, mKeyPair.getPublic());
+        mRecoverableKeyStoreDb.setRecoveryServiceCertPath(
+                TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TestData.CERT_PATH_1);
+        mRecoverableKeyStoreDb.setRecoveryServiceCertPath(
+                TEST_USER_ID, TEST_RECOVERY_AGENT_UID2, TestData.CERT_PATH_1);
         when(mSnapshotListenersStorage.hasListener(TEST_RECOVERY_AGENT_UID)).thenReturn(true);
         when(mSnapshotListenersStorage.hasListener(TEST_RECOVERY_AGENT_UID2)).thenReturn(true);
         addApplicationKey(TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_APP_KEY_ALIAS);
@@ -482,10 +478,10 @@ public class KeySyncTaskTest {
         mRecoverableKeyStoreDb.setRecoverySecretTypes(TEST_USER_ID, TEST_RECOVERY_AGENT_UID2,
                 new int[] {1000});
 
-        mRecoverableKeyStoreDb.setRecoveryServicePublicKey(
-                TEST_USER_ID, TEST_RECOVERY_AGENT_UID, mKeyPair.getPublic());
-        mRecoverableKeyStoreDb.setRecoveryServicePublicKey(
-                TEST_USER_ID, TEST_RECOVERY_AGENT_UID2, mKeyPair.getPublic());
+        mRecoverableKeyStoreDb.setRecoveryServiceCertPath(
+                TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TestData.CERT_PATH_1);
+        mRecoverableKeyStoreDb.setRecoveryServiceCertPath(
+                TEST_USER_ID, TEST_RECOVERY_AGENT_UID2, TestData.CERT_PATH_1);
         when(mSnapshotListenersStorage.hasListener(TEST_RECOVERY_AGENT_UID)).thenReturn(true);
         when(mSnapshotListenersStorage.hasListener(TEST_RECOVERY_AGENT_UID2)).thenReturn(true);
         addApplicationKey(TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_APP_KEY_ALIAS);
@@ -499,10 +495,10 @@ public class KeySyncTaskTest {
 
     @Test
     public void run_notifiesNonregisteredAgent() throws Exception {
-        mRecoverableKeyStoreDb.setRecoveryServicePublicKey(
-                TEST_USER_ID, TEST_RECOVERY_AGENT_UID, mKeyPair.getPublic());
-        mRecoverableKeyStoreDb.setRecoveryServicePublicKey(
-                TEST_USER_ID, TEST_RECOVERY_AGENT_UID2, mKeyPair.getPublic());
+        mRecoverableKeyStoreDb.setRecoveryServiceCertPath(
+                TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TestData.CERT_PATH_1);
+        mRecoverableKeyStoreDb.setRecoveryServiceCertPath(
+                TEST_USER_ID, TEST_RECOVERY_AGENT_UID2, TestData.CERT_PATH_1);
         when(mSnapshotListenersStorage.hasListener(TEST_RECOVERY_AGENT_UID)).thenReturn(true);
         when(mSnapshotListenersStorage.hasListener(TEST_RECOVERY_AGENT_UID2)).thenReturn(false);
         addApplicationKey(TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_APP_KEY_ALIAS);
@@ -562,7 +558,7 @@ public class KeySyncTaskTest {
     private byte[] decryptThmEncryptedKey(
             byte[] lockScreenHash, byte[] encryptedKey, byte[] vaultParams) throws Exception {
         byte[] locallyEncryptedKey = SecureBox.decrypt(
-                mKeyPair.getPrivate(),
+                TestData.CERT_1_PRIVATE_KEY,
                 /*sharedSecret=*/ KeySyncUtils.calculateThmKfHash(lockScreenHash),
                 /*header=*/ KeySyncUtils.concat(THM_ENCRYPTED_RECOVERY_KEY_HEADER, vaultParams),
                 encryptedKey
index b5d6ce8..4b059c6 100644 (file)
@@ -1,11 +1,18 @@
 package com.android.server.locksettings.recoverablekeystore;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import com.android.server.locksettings.recoverablekeystore.certificate.CertUtils;
 
 import java.io.ByteArrayInputStream;
+import java.math.BigInteger;
 import java.nio.charset.StandardCharsets;
-import java.security.cert.CertPath;
+import java.security.KeyFactory;
+import java.security.PrivateKey;
+import java.security.PublicKey;
 import java.security.cert.CertificateFactory;
+import java.security.cert.CertPath;
+import java.security.spec.ECPrivateKeySpec;
 
 public final class TestData {
 
@@ -213,6 +220,44 @@ public final class TestData {
             + "  </value>\n"
             + "</signature>\n";
 
+    public static final PublicKey CERT_1_PUBLIC_KEY;
+    public static final PrivateKey CERT_1_PRIVATE_KEY;
+
+    static {
+        try {
+            CERT_1_PUBLIC_KEY =
+                    SecureBox.decodePublicKey(
+                            new byte[] {
+                                (byte) 0x04, (byte) 0xb8, (byte) 0x00, (byte) 0x11, (byte) 0x18,
+                                (byte) 0x98, (byte) 0x1d, (byte) 0xf0, (byte) 0x6e, (byte) 0xb4,
+                                (byte) 0x94, (byte) 0xfe, (byte) 0x86, (byte) 0xda, (byte) 0x1c,
+                                (byte) 0x07, (byte) 0x8d, (byte) 0x01, (byte) 0xb4, (byte) 0x3a,
+                                (byte) 0xf6, (byte) 0x8d, (byte) 0xdc, (byte) 0x61, (byte) 0xd0,
+                                (byte) 0x46, (byte) 0x49, (byte) 0x95, (byte) 0x0f, (byte) 0x10,
+                                (byte) 0x86, (byte) 0x93, (byte) 0x24, (byte) 0x66, (byte) 0xe0,
+                                (byte) 0x3f, (byte) 0xd2, (byte) 0xdf, (byte) 0xf3, (byte) 0x79,
+                                (byte) 0x20, (byte) 0x1d, (byte) 0x91, (byte) 0x55, (byte) 0xb0,
+                                (byte) 0xe5, (byte) 0xbd, (byte) 0x7a, (byte) 0x8b, (byte) 0x32,
+                                (byte) 0x7d, (byte) 0x25, (byte) 0x53, (byte) 0xa2, (byte) 0xfc,
+                                (byte) 0xa5, (byte) 0x65, (byte) 0xe1, (byte) 0xbd, (byte) 0x21,
+                                (byte) 0x44, (byte) 0x7e, (byte) 0x78, (byte) 0x52, (byte) 0xfa
+                            });
+            CERT_1_PRIVATE_KEY =
+                    decodePrivateKey(
+                            new byte[] {
+                                (byte) 0x70, (byte) 0x01, (byte) 0xc7, (byte) 0x87, (byte) 0x32,
+                                (byte) 0x2f, (byte) 0x1c, (byte) 0x9a, (byte) 0x6e, (byte) 0xb1,
+                                (byte) 0x91, (byte) 0xca, (byte) 0x4e, (byte) 0xb5, (byte) 0x44,
+                                (byte) 0xba, (byte) 0xc8, (byte) 0x68, (byte) 0xc6, (byte) 0x0a,
+                                (byte) 0x76, (byte) 0xcb, (byte) 0xd3, (byte) 0x63, (byte) 0x67,
+                                (byte) 0x7c, (byte) 0xb0, (byte) 0x11, (byte) 0x82, (byte) 0x65,
+                                (byte) 0x77, (byte) 0x01
+                            });
+        } catch (Exception ex) {
+            throw new RuntimeException(ex);
+        }
+    }
+
     public static byte[] getCertPath1Bytes() {
         try {
             return CertUtils.decodeBase64(CERT_PATH_1_BASE64);
@@ -256,4 +301,11 @@ public final class TestData {
     public static byte[] getSigXml() {
         return THM_SIG_XML.getBytes(StandardCharsets.UTF_8);
     }
+
+    private static PrivateKey decodePrivateKey(byte[] keyBytes) throws Exception {
+        assertThat(keyBytes.length).isEqualTo(32);
+        BigInteger priv = new BigInteger(/*signum=*/ 1, keyBytes);
+        KeyFactory keyFactory = KeyFactory.getInstance("EC");
+        return keyFactory.generatePrivate(new ECPrivateKeySpec(priv, SecureBox.EC_PARAM_SPEC));
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/PersistentKeyChainSnapshotTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/PersistentKeyChainSnapshotTest.java
deleted file mode 100644 (file)
index 180345c..0000000
+++ /dev/null
@@ -1,331 +0,0 @@
-/*
- * 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 com.android.server.locksettings.recoverablekeystore.storage;
-
-import static com.google.common.truth.Truth.assertThat;
-import static org.testng.Assert.assertThrows;
-
-import android.security.keystore.recovery.KeyDerivationParams;
-import android.security.keystore.recovery.WrappedApplicationKey;
-import android.security.keystore.recovery.KeyChainSnapshot;
-import android.security.keystore.recovery.KeyChainProtectionParams;
-
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.io.IOException;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class PersistentKeyChainSnapshotTest {
-
-    private static final String ALIAS = "some_key";
-    private static final String ALIAS2 = "another_key";
-    private static final byte[] RECOVERY_KEY_MATERIAL = "recovery_key_data"
-            .getBytes(StandardCharsets.UTF_8);
-    private static final byte[] KEY_MATERIAL = "app_key_data".getBytes(StandardCharsets.UTF_8);
-    private static final byte[] PUBLIC_KEY = "public_key_data".getBytes(StandardCharsets.UTF_8);
-    private static final byte[] SALT = "salt".getBytes(StandardCharsets.UTF_8);
-    private static final int SNAPSHOT_VERSION = 2;
-    private static final int MAX_ATTEMPTS = 10;
-    private static final long COUNTER_ID = 123456789L;
-    private static final byte[] SERVER_PARAMS = "server_params".getBytes(StandardCharsets.UTF_8);
-    private static final byte[] ZERO_BYTES = new byte[0];
-    private static final byte[] ONE_BYTE = new byte[]{(byte) 11};
-    private static final byte[] TWO_BYTES = new byte[]{(byte) 222,(byte) 222};
-
-    @Test
-    public void testWriteInt() throws Exception {
-        PersistentKeyChainSnapshot writer = new PersistentKeyChainSnapshot();
-        writer.initWriter();
-        writer.writeInt(Integer.MIN_VALUE);
-        writer.writeInt(Integer.MAX_VALUE);
-        byte[] result = writer.getOutput();
-
-        PersistentKeyChainSnapshot reader = new PersistentKeyChainSnapshot();
-        reader.initReader(result);
-        assertThat(reader.readInt()).isEqualTo(Integer.MIN_VALUE);
-        assertThat(reader.readInt()).isEqualTo(Integer.MAX_VALUE);
-
-        assertThrows(
-                IOException.class,
-                () -> reader.readInt());
-    }
-
-    @Test
-    public void testWriteLong() throws Exception {
-        PersistentKeyChainSnapshot writer = new PersistentKeyChainSnapshot();
-        writer.initWriter();
-        writer.writeLong(Long.MIN_VALUE);
-        writer.writeLong(Long.MAX_VALUE);
-        byte[] result = writer.getOutput();
-
-        PersistentKeyChainSnapshot reader = new PersistentKeyChainSnapshot();
-        reader.initReader(result);
-        assertThat(reader.readLong()).isEqualTo(Long.MIN_VALUE);
-        assertThat(reader.readLong()).isEqualTo(Long.MAX_VALUE);
-
-        assertThrows(
-                IOException.class,
-                () -> reader.readLong());
-    }
-
-    @Test
-    public void testWriteBytes() throws Exception {
-        PersistentKeyChainSnapshot writer = new PersistentKeyChainSnapshot();
-        writer.initWriter();
-        writer.writeBytes(ZERO_BYTES);
-        writer.writeBytes(ONE_BYTE);
-        writer.writeBytes(TWO_BYTES);
-        byte[] result = writer.getOutput();
-
-        PersistentKeyChainSnapshot reader = new PersistentKeyChainSnapshot();
-        reader.initReader(result);
-        assertThat(reader.readBytes()).isEqualTo(ZERO_BYTES);
-        assertThat(reader.readBytes()).isEqualTo(ONE_BYTE);
-        assertThat(reader.readBytes()).isEqualTo(TWO_BYTES);
-
-        assertThrows(
-                IOException.class,
-                () -> reader.readBytes());
-    }
-
-    @Test
-    public void testReadBytes_returnsNullArrayAsEmpty() throws Exception {
-        PersistentKeyChainSnapshot writer = new PersistentKeyChainSnapshot();
-        writer.initWriter();
-        writer.writeBytes(null);
-        byte[] result = writer.getOutput();
-
-        PersistentKeyChainSnapshot reader = new PersistentKeyChainSnapshot();
-        reader.initReader(result);
-        assertThat(reader.readBytes()).isEqualTo(new byte[]{}); // null -> empty array
-    }
-
-    @Test
-    public void testWriteKeyEntry() throws Exception {
-        PersistentKeyChainSnapshot writer = new PersistentKeyChainSnapshot();
-        writer.initWriter();
-        WrappedApplicationKey entry = new WrappedApplicationKey.Builder()
-                .setAlias(ALIAS)
-                .setEncryptedKeyMaterial(KEY_MATERIAL)
-                .build();
-        writer.writeKeyEntry(entry);
-
-        byte[] result = writer.getOutput();
-
-        PersistentKeyChainSnapshot reader = new PersistentKeyChainSnapshot();
-        reader.initReader(result);
-
-        WrappedApplicationKey copy = reader.readKeyEntry();
-        assertThat(copy.getAlias()).isEqualTo(ALIAS);
-        assertThat(copy.getEncryptedKeyMaterial()).isEqualTo(KEY_MATERIAL);
-
-        assertThrows(
-                IOException.class,
-                () -> reader.readKeyEntry());
-    }
-
-    @Test
-    public void testWriteProtectionParams() throws Exception {
-        PersistentKeyChainSnapshot writer = new PersistentKeyChainSnapshot();
-        writer.initWriter();
-        KeyDerivationParams derivationParams = KeyDerivationParams.createSha256Params(SALT);
-        KeyChainProtectionParams protectionParams =  new KeyChainProtectionParams.Builder()
-                .setUserSecretType(1)
-                .setLockScreenUiFormat(2)
-                .setKeyDerivationParams(derivationParams)
-                .build();
-        writer.writeProtectionParams(protectionParams);
-
-        byte[] result = writer.getOutput();
-
-        PersistentKeyChainSnapshot reader = new PersistentKeyChainSnapshot();
-        reader.initReader(result);
-
-        KeyChainProtectionParams copy = reader.readProtectionParams();
-        assertThat(copy.getUserSecretType()).isEqualTo(1);
-        assertThat(copy.getLockScreenUiFormat()).isEqualTo(2);
-        assertThat(copy.getKeyDerivationParams().getSalt()).isEqualTo(SALT);
-
-        assertThrows(
-                IOException.class,
-                () -> reader.readProtectionParams());
-    }
-
-    @Test
-    public void testKeyChainSnapshot() throws Exception {
-        PersistentKeyChainSnapshot writer = new PersistentKeyChainSnapshot();
-        writer.initWriter();
-
-        KeyDerivationParams derivationParams = KeyDerivationParams.createSha256Params(SALT);
-
-        ArrayList<KeyChainProtectionParams> protectionParamsList = new ArrayList<>();
-        protectionParamsList.add(new KeyChainProtectionParams.Builder()
-                .setUserSecretType(1)
-                .setLockScreenUiFormat(2)
-                .setKeyDerivationParams(derivationParams)
-                .build());
-
-        ArrayList<WrappedApplicationKey> appKeysList = new ArrayList<>();
-        appKeysList.add(new WrappedApplicationKey.Builder()
-                .setAlias(ALIAS)
-                .setEncryptedKeyMaterial(KEY_MATERIAL)
-                .build());
-
-        KeyChainSnapshot snapshot =  new KeyChainSnapshot.Builder()
-                .setSnapshotVersion(SNAPSHOT_VERSION)
-                .setKeyChainProtectionParams(protectionParamsList)
-                .setEncryptedRecoveryKeyBlob(RECOVERY_KEY_MATERIAL)
-                .setWrappedApplicationKeys(appKeysList)
-                .setMaxAttempts(MAX_ATTEMPTS)
-                .setCounterId(COUNTER_ID)
-                .setServerParams(SERVER_PARAMS)
-                .setTrustedHardwarePublicKey(PUBLIC_KEY)
-                .build();
-
-        writer.writeKeyChainSnapshot(snapshot);
-
-        byte[] result = writer.getOutput();
-
-        PersistentKeyChainSnapshot reader = new PersistentKeyChainSnapshot();
-        reader.initReader(result);
-
-        KeyChainSnapshot copy = reader.readKeyChainSnapshot();
-        assertThat(copy.getSnapshotVersion()).isEqualTo(SNAPSHOT_VERSION);
-        assertThat(copy.getKeyChainProtectionParams()).hasSize(1);
-        assertThat(copy.getKeyChainProtectionParams().get(0).getUserSecretType()).isEqualTo(1);
-        assertThat(copy.getEncryptedRecoveryKeyBlob()).isEqualTo(RECOVERY_KEY_MATERIAL);
-        assertThat(copy.getWrappedApplicationKeys()).hasSize(1);
-        assertThat(copy.getWrappedApplicationKeys().get(0).getAlias()).isEqualTo(ALIAS);
-        assertThat(copy.getMaxAttempts()).isEqualTo(MAX_ATTEMPTS);
-        assertThat(copy.getCounterId()).isEqualTo(COUNTER_ID);
-        assertThat(copy.getServerParams()).isEqualTo(SERVER_PARAMS);
-        assertThat(copy.getTrustedHardwarePublicKey()).isEqualTo(PUBLIC_KEY);
-
-        assertThrows(
-                IOException.class,
-                () -> reader.readKeyChainSnapshot());
-
-        verifyDeserialize(snapshot);
-    }
-
-    @Test
-    public void testKeyChainSnapshot_withManyKeysAndProtectionParams() throws Exception {
-        PersistentKeyChainSnapshot writer = new PersistentKeyChainSnapshot();
-        writer.initWriter();
-
-        KeyDerivationParams derivationParams = KeyDerivationParams.createSha256Params(SALT);
-
-        ArrayList<KeyChainProtectionParams> protectionParamsList = new ArrayList<>();
-        protectionParamsList.add(new KeyChainProtectionParams.Builder()
-                .setUserSecretType(1)
-                .setLockScreenUiFormat(2)
-                .setKeyDerivationParams(derivationParams)
-                .build());
-        protectionParamsList.add(new KeyChainProtectionParams.Builder()
-                .setUserSecretType(2)
-                .setLockScreenUiFormat(3)
-                .setKeyDerivationParams(derivationParams)
-                .build());
-        ArrayList<WrappedApplicationKey> appKeysList = new ArrayList<>();
-        appKeysList.add(new WrappedApplicationKey.Builder()
-                .setAlias(ALIAS)
-                .setEncryptedKeyMaterial(KEY_MATERIAL)
-                .build());
-        appKeysList.add(new WrappedApplicationKey.Builder()
-                .setAlias(ALIAS2)
-                .setEncryptedKeyMaterial(KEY_MATERIAL)
-                .build());
-
-
-        KeyChainSnapshot snapshot =  new KeyChainSnapshot.Builder()
-                .setSnapshotVersion(SNAPSHOT_VERSION)
-                .setKeyChainProtectionParams(protectionParamsList)
-                .setEncryptedRecoveryKeyBlob(RECOVERY_KEY_MATERIAL)
-                .setWrappedApplicationKeys(appKeysList)
-                .setMaxAttempts(MAX_ATTEMPTS)
-                .setCounterId(COUNTER_ID)
-                .setServerParams(SERVER_PARAMS)
-                .setTrustedHardwarePublicKey(PUBLIC_KEY)
-                .build();
-
-        writer.writeKeyChainSnapshot(snapshot);
-
-        byte[] result = writer.getOutput();
-
-        PersistentKeyChainSnapshot reader = new PersistentKeyChainSnapshot();
-        reader.initReader(result);
-
-        KeyChainSnapshot copy = reader.readKeyChainSnapshot();
-        assertThat(copy.getSnapshotVersion()).isEqualTo(SNAPSHOT_VERSION);
-        assertThat(copy.getKeyChainProtectionParams().get(0).getUserSecretType()).isEqualTo(1);
-        assertThat(copy.getEncryptedRecoveryKeyBlob()).isEqualTo(RECOVERY_KEY_MATERIAL);
-        assertThat(copy.getWrappedApplicationKeys().get(0).getAlias()).isEqualTo(ALIAS);
-        assertThat(copy.getMaxAttempts()).isEqualTo(MAX_ATTEMPTS);
-        assertThat(copy.getCounterId()).isEqualTo(COUNTER_ID);
-        assertThat(copy.getServerParams()).isEqualTo(SERVER_PARAMS);
-        assertThat(copy.getTrustedHardwarePublicKey()).isEqualTo(PUBLIC_KEY);
-
-        assertThrows(
-                IOException.class,
-                () -> reader.readKeyChainSnapshot());
-
-        verifyDeserialize(snapshot);
-    }
-
-    private void verifyDeserialize(KeyChainSnapshot snapshot) throws Exception {
-        byte[] serialized = PersistentKeyChainSnapshot.serialize(snapshot);
-        KeyChainSnapshot copy = PersistentKeyChainSnapshot.deserialize(serialized);
-        assertThat(copy.getSnapshotVersion())
-                .isEqualTo(snapshot.getSnapshotVersion());
-        assertThat(copy.getKeyChainProtectionParams().size())
-                .isEqualTo(copy.getKeyChainProtectionParams().size());
-        assertThat(copy.getEncryptedRecoveryKeyBlob())
-                .isEqualTo(snapshot.getEncryptedRecoveryKeyBlob());
-        assertThat(copy.getWrappedApplicationKeys().size())
-                .isEqualTo(snapshot.getWrappedApplicationKeys().size());
-        assertThat(copy.getMaxAttempts()).isEqualTo(snapshot.getMaxAttempts());
-        assertThat(copy.getCounterId()).isEqualTo(snapshot.getCounterId());
-        assertThat(copy.getServerParams()).isEqualTo(snapshot.getServerParams());
-        assertThat(copy.getTrustedHardwarePublicKey())
-                .isEqualTo(snapshot.getTrustedHardwarePublicKey());
-    }
-
-    @Test
-    public void testDeserialize_failsForNewerVersion() throws Exception {
-        byte[] newVersion = new byte[]{(byte) 2, (byte) 0, (byte) 0, (byte) 0};
-        assertThrows(
-                IOException.class,
-                () -> PersistentKeyChainSnapshot.deserialize(newVersion));
-    }
-
-    @Test
-    public void testDeserialize_failsForEmptyData() throws Exception {
-        byte[] empty = new byte[]{};
-        assertThrows(
-                IOException.class,
-                () -> PersistentKeyChainSnapshot.deserialize(empty));
-    }
-
-}
-