diff options
| author | 2018-03-23 17:16:17 +0000 | |
|---|---|---|
| committer | 2018-03-23 17:16:17 +0000 | |
| commit | 95f2965a749ce81451217bf520b41b2c945ececb (patch) | |
| tree | 31cb5062b3e6fc2989a1e63241f9bfafd1db3c5e | |
| parent | 7ed5fb3e1d61786d1987fdef5c9a9b4591b4930a (diff) | |
| parent | 3b67e06de57549cfa9b4db88b13d105126d7ad94 (diff) | |
Merge "Prepare KeyChainSnapshot to removing deprecated getTrustedHardwarePublicKey method." into pi-dev
5 files changed, 100 insertions, 689 deletions
diff --git a/core/java/android/security/keystore/recovery/KeyChainSnapshot.java b/core/java/android/security/keystore/recovery/KeyChainSnapshot.java index 00f54e16863d..69b9123c3c3e 100644 --- a/core/java/android/security/keystore/recovery/KeyChainSnapshot.java +++ b/core/java/android/security/keystore/recovery/KeyChainSnapshot.java @@ -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 index 52381b8f87d1..000000000000 --- a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/PersistentKeyChainSnapshot.java +++ /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; - } -} - diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java index 25747b801b80..0ea231773aaf 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java @@ -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 diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/TestData.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/TestData.java index b5d6ce8cb74c..4b059c665b54 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/TestData.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/TestData.java @@ -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 index 180345c808e9..000000000000 --- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/PersistentKeyChainSnapshotTest.java +++ /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)); - } - -} - |