blob: 2f4da86bf38f52733aa07f42795be04e290ed8c5 [file] [log] [blame]
Robert Berry25f51352018-03-28 20:26:57 +01001/*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server.locksettings.recoverablekeystore.serialization;
18
19import static com.google.common.truth.Truth.assertThat;
20
21import android.security.keystore.recovery.KeyChainProtectionParams;
22import android.security.keystore.recovery.KeyChainSnapshot;
23import android.security.keystore.recovery.KeyDerivationParams;
24import android.security.keystore.recovery.WrappedApplicationKey;
25import android.support.test.InstrumentationRegistry;
26import android.support.test.filters.SmallTest;
27import android.support.test.runner.AndroidJUnit4;
28
29import com.android.server.locksettings.recoverablekeystore.TestData;
30
31import org.junit.Test;
32import org.junit.runner.RunWith;
33
34import java.io.ByteArrayInputStream;
35import java.io.ByteArrayOutputStream;
36import java.security.cert.CertPath;
37import java.util.ArrayList;
38import java.util.List;
39
40@SmallTest
41@RunWith(AndroidJUnit4.class)
42public class KeyChainSnapshotSerializerTest {
43 private static final int COUNTER_ID = 2134;
44 private static final int SNAPSHOT_VERSION = 125;
45 private static final int MAX_ATTEMPTS = 21;
46 private static final byte[] SERVER_PARAMS = new byte[] { 8, 2, 4 };
47 private static final byte[] KEY_BLOB = new byte[] { 124, 53, 53, 53 };
Robert Berry56588372018-03-29 12:07:17 +010048 private static final byte[] PUBLIC_KEY_BLOB = new byte[] { 6, 6, 6, 6, 6, 6, 7 };
Robert Berry25f51352018-03-28 20:26:57 +010049 private static final CertPath CERT_PATH = TestData.CERT_PATH_1;
50 private static final int SECRET_TYPE = KeyChainProtectionParams.TYPE_LOCKSCREEN;
51 private static final int LOCK_SCREEN_UI = KeyChainProtectionParams.UI_FORMAT_PASSWORD;
52 private static final byte[] SALT = new byte[] { 5, 4, 3, 2, 1 };
53 private static final int MEMORY_DIFFICULTY = 45;
54 private static final int ALGORITHM = KeyDerivationParams.ALGORITHM_SCRYPT;
55 private static final byte[] SECRET = new byte[] { 1, 2, 3, 4 };
56
57 private static final String TEST_KEY_1_ALIAS = "key1";
58 private static final byte[] TEST_KEY_1_BYTES = new byte[] { 66, 77, 88 };
59
60 private static final String TEST_KEY_2_ALIAS = "key2";
61 private static final byte[] TEST_KEY_2_BYTES = new byte[] { 99, 33, 11 };
62
63 private static final String TEST_KEY_3_ALIAS = "key3";
64 private static final byte[] TEST_KEY_3_BYTES = new byte[] { 2, 8, 100 };
65
66 @Test
67 public void roundTrip_persistsCounterId() throws Exception {
68 assertThat(roundTrip().getCounterId()).isEqualTo(COUNTER_ID);
69 }
70
71 @Test
72 public void roundTrip_persistsSnapshotVersion() throws Exception {
73 assertThat(roundTrip().getSnapshotVersion()).isEqualTo(SNAPSHOT_VERSION);
74 }
75
76 @Test
77 public void roundTrip_persistsMaxAttempts() throws Exception {
78 assertThat(roundTrip().getMaxAttempts()).isEqualTo(MAX_ATTEMPTS);
79 }
80
81 @Test
82 public void roundTrip_persistsRecoveryKey() throws Exception {
83 assertThat(roundTrip().getEncryptedRecoveryKeyBlob()).isEqualTo(KEY_BLOB);
84 }
85
86 @Test
87 public void roundTrip_persistsServerParams() throws Exception {
88 assertThat(roundTrip().getServerParams()).isEqualTo(SERVER_PARAMS);
89 }
90
91 @Test
92 public void roundTrip_persistsCertPath() throws Exception {
93 assertThat(roundTrip().getTrustedHardwareCertPath()).isEqualTo(CERT_PATH);
94 }
95
96 @Test
Robert Berry56588372018-03-29 12:07:17 +010097 public void roundTrip_persistsBackendPublicKey() throws Exception {
98 assertThat(roundTrip().getTrustedHardwarePublicKey()).isEqualTo(PUBLIC_KEY_BLOB);
99 }
100
101 @Test
Robert Berry25f51352018-03-28 20:26:57 +0100102 public void roundTrip_persistsParamsList() throws Exception {
103 assertThat(roundTrip().getKeyChainProtectionParams()).hasSize(1);
104 }
105
106 @Test
107 public void roundTripParams_persistsUserSecretType() throws Exception {
108 assertThat(roundTripParams().getUserSecretType()).isEqualTo(SECRET_TYPE);
109 }
110
111 @Test
112 public void roundTripParams_persistsLockScreenUi() throws Exception {
113 assertThat(roundTripParams().getLockScreenUiFormat()).isEqualTo(LOCK_SCREEN_UI);
114 }
115
116 @Test
117 public void roundTripParams_persistsSalt() throws Exception {
118 assertThat(roundTripParams().getKeyDerivationParams().getSalt()).isEqualTo(SALT);
119 }
120
121 @Test
122 public void roundTripParams_persistsAlgorithm() throws Exception {
123 assertThat(roundTripParams().getKeyDerivationParams().getAlgorithm()).isEqualTo(ALGORITHM);
124 }
125
126 @Test
127 public void roundTripParams_persistsMemoryDifficulty() throws Exception {
128 assertThat(roundTripParams().getKeyDerivationParams().getMemoryDifficulty())
129 .isEqualTo(MEMORY_DIFFICULTY);
130 }
131
132 @Test
133 public void roundTripParams_doesNotPersistSecret() throws Exception {
134 assertThat(roundTripParams().getSecret()).isEmpty();
135 }
136
137 @Test
138 public void roundTripKeys_hasCorrectLength() throws Exception {
139 assertThat(roundTripKeys()).hasSize(3);
140 }
141
142 @Test
143 public void roundTripKeys_0_persistsAlias() throws Exception {
144 assertThat(roundTripKeys().get(0).getAlias()).isEqualTo(TEST_KEY_1_ALIAS);
145 }
146
147 @Test
148 public void roundTripKeys_0_persistsKeyBytes() throws Exception {
149 assertThat(roundTripKeys().get(0).getEncryptedKeyMaterial()).isEqualTo(TEST_KEY_1_BYTES);
150 }
151
152 @Test
153 public void roundTripKeys_1_persistsAlias() throws Exception {
154 assertThat(roundTripKeys().get(1).getAlias()).isEqualTo(TEST_KEY_2_ALIAS);
155 }
156
157 @Test
158 public void roundTripKeys_1_persistsKeyBytes() throws Exception {
159 assertThat(roundTripKeys().get(1).getEncryptedKeyMaterial()).isEqualTo(TEST_KEY_2_BYTES);
160 }
161
162 @Test
163 public void roundTripKeys_2_persistsAlias() throws Exception {
164 assertThat(roundTripKeys().get(2).getAlias()).isEqualTo(TEST_KEY_3_ALIAS);
165 }
166
167 @Test
168 public void roundTripKeys_2_persistsKeyBytes() throws Exception {
169 assertThat(roundTripKeys().get(2).getEncryptedKeyMaterial()).isEqualTo(TEST_KEY_3_BYTES);
170 }
171
Robert Berry56588372018-03-29 12:07:17 +0100172 @Test
173 public void serialize_doesNotThrowForNullPublicKey() throws Exception {
174 KeyChainSnapshotSerializer.serialize(
175 createTestKeyChainSnapshotNoPublicKey(), new ByteArrayOutputStream());
176 }
177
Robert Berry25f51352018-03-28 20:26:57 +0100178 private static List<WrappedApplicationKey> roundTripKeys() throws Exception {
179 return roundTrip().getWrappedApplicationKeys();
180 }
181
182 private static KeyChainProtectionParams roundTripParams() throws Exception {
183 return roundTrip().getKeyChainProtectionParams().get(0);
184 }
185
186 public static KeyChainSnapshot roundTrip() throws Exception {
187 KeyChainSnapshot snapshot = createTestKeyChainSnapshot();
188 ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
189 KeyChainSnapshotSerializer.serialize(snapshot, byteArrayOutputStream);
190 return KeyChainSnapshotDeserializer.deserialize(
191 new ByteArrayInputStream(byteArrayOutputStream.toByteArray()));
192 }
193
194 private static KeyChainSnapshot createTestKeyChainSnapshot() throws Exception {
Robert Berry56588372018-03-29 12:07:17 +0100195 return new KeyChainSnapshot.Builder()
196 .setCounterId(COUNTER_ID)
197 .setSnapshotVersion(SNAPSHOT_VERSION)
198 .setServerParams(SERVER_PARAMS)
199 .setMaxAttempts(MAX_ATTEMPTS)
200 .setEncryptedRecoveryKeyBlob(KEY_BLOB)
201 .setKeyChainProtectionParams(createKeyChainProtectionParamsList())
202 .setWrappedApplicationKeys(createKeys())
203 .setTrustedHardwareCertPath(CERT_PATH)
204 .setTrustedHardwarePublicKey(PUBLIC_KEY_BLOB)
205 .build();
206 }
207
208 private static KeyChainSnapshot createTestKeyChainSnapshotNoPublicKey() throws Exception {
209 return new KeyChainSnapshot.Builder()
210 .setCounterId(COUNTER_ID)
211 .setSnapshotVersion(SNAPSHOT_VERSION)
212 .setServerParams(SERVER_PARAMS)
213 .setMaxAttempts(MAX_ATTEMPTS)
214 .setEncryptedRecoveryKeyBlob(KEY_BLOB)
215 .setKeyChainProtectionParams(createKeyChainProtectionParamsList())
216 .setWrappedApplicationKeys(createKeys())
217 .setTrustedHardwareCertPath(CERT_PATH)
218 .build();
219 }
220
221 private static List<WrappedApplicationKey> createKeys() {
222 ArrayList<WrappedApplicationKey> keyList = new ArrayList<>();
223 keyList.add(createKey(TEST_KEY_1_ALIAS, TEST_KEY_1_BYTES));
224 keyList.add(createKey(TEST_KEY_2_ALIAS, TEST_KEY_2_BYTES));
225 keyList.add(createKey(TEST_KEY_3_ALIAS, TEST_KEY_3_BYTES));
226 return keyList;
227 }
228
229 private static List<KeyChainProtectionParams> createKeyChainProtectionParamsList() {
Robert Berry25f51352018-03-28 20:26:57 +0100230 KeyDerivationParams keyDerivationParams =
231 KeyDerivationParams.createScryptParams(SALT, MEMORY_DIFFICULTY);
232 KeyChainProtectionParams keyChainProtectionParams = new KeyChainProtectionParams.Builder()
233 .setKeyDerivationParams(keyDerivationParams)
234 .setUserSecretType(SECRET_TYPE)
235 .setLockScreenUiFormat(LOCK_SCREEN_UI)
236 .setSecret(SECRET)
237 .build();
238 ArrayList<KeyChainProtectionParams> keyChainProtectionParamsList =
239 new ArrayList<>(1);
240 keyChainProtectionParamsList.add(keyChainProtectionParams);
Robert Berry56588372018-03-29 12:07:17 +0100241 return keyChainProtectionParamsList;
Robert Berry25f51352018-03-28 20:26:57 +0100242 }
243
244 private static WrappedApplicationKey createKey(String alias, byte[] bytes) {
245 return new WrappedApplicationKey.Builder()
246 .setAlias(alias)
247 .setEncryptedKeyMaterial(bytes)
248 .build();
249 }
250}