1 /*
2  * Copyright (C) 2017 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 
17 package com.android.server.locksettings.recoverablekeystore.storage;
18 
19 import static com.google.common.truth.Truth.assertThat;
20 
21 import static org.junit.Assert.assertArrayEquals;
22 import static org.junit.Assert.assertEquals;
23 import static org.junit.Assert.assertNull;
24 import static org.junit.Assert.assertTrue;
25 
26 import android.content.Context;
27 import android.security.keystore.recovery.RecoveryController;
28 
29 import androidx.test.InstrumentationRegistry;
30 import androidx.test.filters.SmallTest;
31 import androidx.test.runner.AndroidJUnit4;
32 
33 import com.android.server.locksettings.recoverablekeystore.TestData;
34 import com.android.server.locksettings.recoverablekeystore.WrappedKey;
35 
36 import org.junit.After;
37 import org.junit.Before;
38 import org.junit.Test;
39 import org.junit.runner.RunWith;
40 
41 import java.io.File;
42 import java.nio.charset.StandardCharsets;
43 import java.security.KeyPairGenerator;
44 import java.security.PublicKey;
45 import java.security.spec.ECGenParameterSpec;
46 import java.util.List;
47 import java.util.Map;
48 
49 @SmallTest
50 @RunWith(AndroidJUnit4.class)
51 public class RecoverableKeyStoreDbTest {
52     private static final String DATABASE_FILE_NAME = "recoverablekeystore.db";
53 
54     private static final String TEST_ROOT_CERT_ALIAS = "trusted_root";
55     private static final String TEST_ROOT_CERT_ALIAS2 = "another_trusted_root";
56 
57     private RecoverableKeyStoreDb mRecoverableKeyStoreDb;
58     private File mDatabaseFile;
59 
60     private static final byte[] SERVER_PARAMS =
61             new byte[]{1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2};
62 
63     private static final byte[] SERVER_PARAMS2 =
64             new byte[]{1, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4};
65 
66     @Before
setUp()67     public void setUp() {
68         Context context = InstrumentationRegistry.getTargetContext();
69         mDatabaseFile = context.getDatabasePath(DATABASE_FILE_NAME);
70         mRecoverableKeyStoreDb = RecoverableKeyStoreDb.newInstance(context);
71     }
72 
73     @After
tearDown()74     public void tearDown() {
75         mRecoverableKeyStoreDb.close();
76         mDatabaseFile.delete();
77     }
78 
79     @Test
insertKey_replacesOldKey()80     public void insertKey_replacesOldKey() {
81         int userId = 12;
82         int uid = 10009;
83         String alias = "test-alias";
84 
85         byte[] nonce = getUtf8Bytes("nonce1");
86         byte[] keyMaterial = getUtf8Bytes("keymaterial1");
87         byte[] keyMetadata = null;
88         int generationId = 1;
89         WrappedKey wrappedKey = new WrappedKey(nonce, keyMaterial, keyMetadata, generationId);
90         mRecoverableKeyStoreDb.insertKey(userId, uid, alias, wrappedKey);
91 
92         WrappedKey retrievedKey = mRecoverableKeyStoreDb.getKey(uid, alias);
93         assertArrayEquals(nonce, retrievedKey.getNonce());
94         assertArrayEquals(keyMaterial, retrievedKey.getKeyMaterial());
95         assertArrayEquals(keyMetadata, retrievedKey.getKeyMetadata());
96         assertEquals(generationId, retrievedKey.getPlatformKeyGenerationId());
97 
98         nonce = getUtf8Bytes("nonce2");
99         keyMaterial = getUtf8Bytes("keymaterial2");
100         keyMetadata = getUtf8Bytes("keymetadata2");
101         generationId = 2;
102         wrappedKey = new WrappedKey(nonce, keyMaterial, keyMetadata, generationId);
103         mRecoverableKeyStoreDb.insertKey(userId, uid, alias, wrappedKey);
104 
105         retrievedKey = mRecoverableKeyStoreDb.getKey(uid, alias);
106         assertArrayEquals(nonce, retrievedKey.getNonce());
107         assertArrayEquals(keyMaterial, retrievedKey.getKeyMaterial());
108         assertArrayEquals(keyMetadata, retrievedKey.getKeyMetadata());
109         assertEquals(generationId, retrievedKey.getPlatformKeyGenerationId());
110     }
111 
112     @Test
insertKey_allowsTwoUidsToHaveSameAlias()113     public void insertKey_allowsTwoUidsToHaveSameAlias() {
114         int userId = 6;
115         String alias = "pcoulton";
116         WrappedKey key1 = new WrappedKey(
117                 getUtf8Bytes("nonce1"),
118                 getUtf8Bytes("key1"),
119                 /*metadata=*/ null,
120                 /*platformKeyGenerationId=*/ 1);
121         WrappedKey key2 = new WrappedKey(
122                 getUtf8Bytes("nonce2"),
123                 getUtf8Bytes("key2"),
124                 /*metadata=*/ null,
125                 /*platformKeyGenerationId=*/ 1);
126 
127         mRecoverableKeyStoreDb.insertKey(userId, /*uid=*/ 1, alias, key1);
128         mRecoverableKeyStoreDb.insertKey(userId, /*uid=*/ 2, alias, key2);
129 
130         assertArrayEquals(
131                 getUtf8Bytes("nonce1"),
132                 mRecoverableKeyStoreDb.getKey(1, alias).getNonce());
133         assertArrayEquals(
134                 getUtf8Bytes("nonce2"),
135                 mRecoverableKeyStoreDb.getKey(2, alias).getNonce());
136     }
137 
138     @Test
removeKey_removesAKey()139     public void removeKey_removesAKey() {
140         int userId = 6;
141         int uid = 60001;
142         String alias = "rupertbates";
143         WrappedKey key = new WrappedKey(
144                 getUtf8Bytes("nonce1"),
145                 getUtf8Bytes("key1"),
146                 /*metadata=*/ null,
147                 /*platformKeyGenerationId=*/ 1);
148         mRecoverableKeyStoreDb.insertKey(userId, uid, alias, key);
149 
150         assertTrue(mRecoverableKeyStoreDb.removeKey(uid, alias));
151 
152         assertNull(mRecoverableKeyStoreDb.getKey(uid, alias));
153     }
154 
155     @Test
getKey_returnsNullIfNoKey()156     public void getKey_returnsNullIfNoKey() {
157         WrappedKey key = mRecoverableKeyStoreDb.getKey(
158                 /*userId=*/ 1, /*alias=*/ "hello");
159 
160         assertNull(key);
161     }
162 
163     @Test
getKey_returnsInsertedKey()164     public void getKey_returnsInsertedKey() {
165         int userId = 12;
166         int uid = 1009;
167         int generationId = 6;
168         int status = 120;
169         String alias = "test";
170         byte[] nonce = getUtf8Bytes("nonce");
171         byte[] keyMaterial = getUtf8Bytes("keymaterial");
172         byte[] keyMetadata = getUtf8Bytes("keymetametametadata");
173 
174         WrappedKey wrappedKey = new WrappedKey(nonce, keyMaterial, keyMetadata, generationId, 120);
175         mRecoverableKeyStoreDb.insertKey(userId, uid, alias, wrappedKey);
176 
177         WrappedKey retrievedKey = mRecoverableKeyStoreDb.getKey(uid, alias);
178 
179         assertArrayEquals(nonce, retrievedKey.getNonce());
180         assertArrayEquals(keyMaterial, retrievedKey.getKeyMaterial());
181         assertArrayEquals(keyMetadata, retrievedKey.getKeyMetadata());
182         assertEquals(generationId, retrievedKey.getPlatformKeyGenerationId());
183         assertEquals(status,retrievedKey.getRecoveryStatus());
184     }
185 
186     @Test
getAllKeys_getsKeysWithUserIdAndGenerationId()187     public void getAllKeys_getsKeysWithUserIdAndGenerationId() {
188         int userId = 12;
189         int uid = 1009;
190         int generationId = 6;
191 
192         String alias1 = "alias1";
193         byte[] nonce1 = getUtf8Bytes("nonce1");
194         byte[] keyMaterial1 = getUtf8Bytes("keymaterial1");
195         byte[] keyMetadata1 = getUtf8Bytes("keyallmetadata1");
196         WrappedKey wrappedKey1 = new WrappedKey(nonce1, keyMaterial1, keyMetadata1, generationId);
197         mRecoverableKeyStoreDb.insertKey(userId, uid, alias1, wrappedKey1);
198 
199         String alias2 = "alias2";
200         byte[] nonce2 = getUtf8Bytes("nonce2");
201         byte[] keyMaterial2 = getUtf8Bytes("keymaterial2");
202         byte[] keyMetadata2 = null;
203         WrappedKey wrappedKey2 = new WrappedKey(nonce2, keyMaterial2, keyMetadata2, generationId);
204         mRecoverableKeyStoreDb.insertKey(userId, uid, alias2, wrappedKey2);
205 
206         Map<String, WrappedKey> keys = mRecoverableKeyStoreDb.getAllKeys(userId, uid, generationId);
207         assertEquals(2, keys.size());
208 
209         assertTrue(keys.containsKey(alias1));
210         WrappedKey retrievedKey1 = keys.get(alias1);
211         assertArrayEquals(nonce1, retrievedKey1.getNonce());
212         assertArrayEquals(keyMaterial1, retrievedKey1.getKeyMaterial());
213         assertArrayEquals(keyMetadata1, retrievedKey1.getKeyMetadata());
214         assertEquals(generationId, retrievedKey1.getPlatformKeyGenerationId());
215 
216         assertTrue(keys.containsKey(alias2));
217         WrappedKey retrievedKey2 = keys.get(alias2);
218         assertArrayEquals(nonce2, retrievedKey2.getNonce());
219         assertArrayEquals(keyMaterial2, retrievedKey2.getKeyMaterial());
220         assertArrayEquals(keyMetadata2, retrievedKey2.getKeyMetadata());
221         assertEquals(generationId, retrievedKey2.getPlatformKeyGenerationId());
222     }
223 
224     @Test
getAllKeys_doesNotReturnKeysWithBadGenerationId()225     public void getAllKeys_doesNotReturnKeysWithBadGenerationId() {
226         int userId = 12;
227         int uid = 6000;
228         WrappedKey wrappedKey = new WrappedKey(
229                 getUtf8Bytes("nonce"),
230                 getUtf8Bytes("keymaterial"),
231                 /*metadata=*/ null,
232                 /*platformKeyGenerationId=*/ 5);
233         mRecoverableKeyStoreDb.insertKey(
234                 userId, uid, /*alias=*/ "test", wrappedKey);
235 
236         Map<String, WrappedKey> keys = mRecoverableKeyStoreDb.getAllKeys(
237                 userId, uid, /*generationId=*/ 7);
238 
239         assertTrue(keys.isEmpty());
240     }
241 
242     @Test
getAllKeys_doesNotReturnKeysWithBadUserId()243     public void getAllKeys_doesNotReturnKeysWithBadUserId() {
244         int generationId = 12;
245         int uid = 10009;
246         WrappedKey wrappedKey = new WrappedKey(
247                 getUtf8Bytes("nonce"), getUtf8Bytes("keymaterial"), /*metadata=*/ null,
248                 generationId);
249         mRecoverableKeyStoreDb.insertKey(
250                 /*userId=*/ 1, uid, /*alias=*/ "test", wrappedKey);
251 
252         Map<String, WrappedKey> keys = mRecoverableKeyStoreDb.getAllKeys(
253                 /*userId=*/ 2, uid, generationId);
254 
255         assertTrue(keys.isEmpty());
256     }
257 
258     @Test
getPlatformKeyGenerationId_returnsGenerationId()259     public void getPlatformKeyGenerationId_returnsGenerationId() {
260         int userId = 42;
261         int generationId = 24;
262         mRecoverableKeyStoreDb.setPlatformKeyGenerationId(userId, generationId);
263 
264         assertEquals(generationId, mRecoverableKeyStoreDb.getPlatformKeyGenerationId(userId));
265     }
266 
267     @Test
getPlatformKeyGenerationId_returnsMinusOneIfNoEntry()268     public void getPlatformKeyGenerationId_returnsMinusOneIfNoEntry() {
269         assertEquals(-1, mRecoverableKeyStoreDb.getPlatformKeyGenerationId(42));
270     }
271 
272     @Test
setPlatformKeyGenerationId_replacesOldEntry()273     public void setPlatformKeyGenerationId_replacesOldEntry() {
274         int userId = 42;
275         mRecoverableKeyStoreDb.setPlatformKeyGenerationId(userId, 1);
276         mRecoverableKeyStoreDb.setPlatformKeyGenerationId(userId, 2);
277 
278         assertEquals(2, mRecoverableKeyStoreDb.getPlatformKeyGenerationId(userId));
279     }
280 
281     @Test
getUserSerialNumbers_returnsSerialNumbers()282     public void getUserSerialNumbers_returnsSerialNumbers() {
283         int userId = 42;
284         int userId2 = 44;
285         Long serialNumber = 24L;
286         Long serialNumber2 = 25L;
287         mRecoverableKeyStoreDb.setUserSerialNumber(userId, serialNumber);
288         mRecoverableKeyStoreDb.setUserSerialNumber(userId2, serialNumber2);
289 
290         assertEquals(2, mRecoverableKeyStoreDb.getUserSerialNumbers().size());
291         assertEquals(serialNumber, mRecoverableKeyStoreDb.getUserSerialNumbers().get(userId));
292         assertEquals(serialNumber2, mRecoverableKeyStoreDb.getUserSerialNumbers().get(userId2));
293     }
294 
295     @Test
getUserSerialNumbers_returnsMinusOneIfNoEntry()296     public void getUserSerialNumbers_returnsMinusOneIfNoEntry() {
297         int userId = 42;
298         int generationId = 24;
299         Long serialNumber = -1L;
300         // Don't set serial number
301         mRecoverableKeyStoreDb.setPlatformKeyGenerationId(userId, generationId);
302 
303         assertEquals(1, mRecoverableKeyStoreDb.getUserSerialNumbers().size());
304         assertEquals(serialNumber, mRecoverableKeyStoreDb.getUserSerialNumbers().get(userId));
305     }
306 
307     @Test
setUserSerialNumbers_keepsPlatformKeyGenerationId()308     public void setUserSerialNumbers_keepsPlatformKeyGenerationId() {
309         int userId = 42;
310         int generationId = 110;
311         Long serialNumber = 10L;
312 
313         mRecoverableKeyStoreDb.setPlatformKeyGenerationId(userId, generationId);
314         mRecoverableKeyStoreDb.setUserSerialNumber(userId, serialNumber);
315 
316         assertEquals(generationId, mRecoverableKeyStoreDb.getPlatformKeyGenerationId(userId));
317     }
318 
319     @Test
setPlatformKeyGenerationId_keepsUserSerialNumber()320     public void setPlatformKeyGenerationId_keepsUserSerialNumber() {
321         int userId = 42;
322         int generationId = 110;
323         Long serialNumber = 10L;
324 
325         mRecoverableKeyStoreDb.setPlatformKeyGenerationId(userId, generationId);
326         mRecoverableKeyStoreDb.setUserSerialNumber(userId, serialNumber);
327         mRecoverableKeyStoreDb.setPlatformKeyGenerationId(userId, generationId + 1);
328 
329         assertEquals(serialNumber, mRecoverableKeyStoreDb.getUserSerialNumbers().get(userId));
330     }
331 
332     @Test
setPlatformKeyGenerationId_invalidatesExistingKeysForUser()333     public void setPlatformKeyGenerationId_invalidatesExistingKeysForUser() {
334         int userId = 42;
335         int generationId = 110;
336         int uid = 1009;
337         int status = 120;
338         String alias = "test";
339         byte[] nonce = getUtf8Bytes("nonce");
340         byte[] keyMaterial = getUtf8Bytes("keymaterial");
341         byte[] keyMetadata = null;
342 
343         WrappedKey wrappedKey =
344                 new WrappedKey(nonce, keyMaterial, keyMetadata, generationId, status);
345         mRecoverableKeyStoreDb.insertKey(userId, uid, alias, wrappedKey);
346 
347         WrappedKey retrievedKey = mRecoverableKeyStoreDb.getKey(uid, alias);
348         assertThat(retrievedKey.getRecoveryStatus()).isEqualTo(status);
349 
350         mRecoverableKeyStoreDb.setPlatformKeyGenerationId(userId, generationId + 1);
351 
352         retrievedKey = mRecoverableKeyStoreDb.getKey(uid, alias);
353         assertThat(retrievedKey.getRecoveryStatus())
354                 .isEqualTo(RecoveryController.RECOVERY_STATUS_PERMANENT_FAILURE);
355     }
356 
357 
358     @Test
removeUserFromAllTables_removesData()359     public void removeUserFromAllTables_removesData() throws Exception {
360         int userId = 12;
361         int generationId = 24;
362         int[] types = new int[]{1};
363         int uid = 10009;
364         mRecoverableKeyStoreDb.setRecoveryServiceCertSerial(userId, uid,
365                 TEST_ROOT_CERT_ALIAS, 1234L);
366         mRecoverableKeyStoreDb.setPlatformKeyGenerationId(userId, generationId);
367         mRecoverableKeyStoreDb.setActiveRootOfTrust(userId, uid, "root");
368         mRecoverableKeyStoreDb.setRecoverySecretTypes(userId, uid, types);
369 
370         mRecoverableKeyStoreDb.removeUserFromAllTables(userId);
371 
372         // RootOfTrust
373         assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertSerial(userId, uid,
374                 TEST_ROOT_CERT_ALIAS)).isNull();
375         // UserMetadata
376         assertThat(mRecoverableKeyStoreDb.getPlatformKeyGenerationId(userId)).isEqualTo(-1);
377         // RecoveryServiceMetadata
378         assertThat(mRecoverableKeyStoreDb.getRecoverySecretTypes(userId, uid)).isEmpty();
379     }
380 
381     @Test
setRecoveryStatus_withSingleKey()382     public void setRecoveryStatus_withSingleKey() {
383         int userId = 12;
384         int uid = 1009;
385         int generationId = 6;
386         int status = 120;
387         int status2 = 121;
388         String alias = "test";
389         byte[] nonce = getUtf8Bytes("nonce");
390         byte[] keyMaterial = getUtf8Bytes("keymaterial");
391         byte[] keyMetadata = null;
392 
393         WrappedKey wrappedKey = new WrappedKey(nonce, keyMaterial, keyMetadata, generationId,
394                 status);
395         mRecoverableKeyStoreDb.insertKey(userId, uid, alias, wrappedKey);
396 
397         WrappedKey retrievedKey = mRecoverableKeyStoreDb.getKey(uid, alias);
398         assertThat(retrievedKey.getRecoveryStatus()).isEqualTo(status);
399 
400         mRecoverableKeyStoreDb.setRecoveryStatus(uid, alias, status2);
401 
402         retrievedKey = mRecoverableKeyStoreDb.getKey(uid, alias);
403         assertThat(retrievedKey.getRecoveryStatus()).isEqualTo(status2);
404     }
405 
406     @Test
getStatusForAllKeys_with3Keys()407     public void getStatusForAllKeys_with3Keys() {
408         int userId = 12;
409         int uid = 1009;
410         int generationId = 6;
411         int status = 120;
412         int status2 = 121;
413         String alias = "test";
414         String alias2 = "test2";
415         String alias3 = "test3";
416         byte[] nonce = getUtf8Bytes("nonce");
417         byte[] keyMaterial = getUtf8Bytes("keymaterial");
418         byte[] keyMetadata = null;
419 
420         WrappedKey wrappedKey = new WrappedKey(nonce, keyMaterial, keyMetadata, generationId,
421                 status);
422         mRecoverableKeyStoreDb.insertKey(userId, uid, alias2, wrappedKey);
423         WrappedKey wrappedKey2 = new WrappedKey(nonce, keyMaterial, keyMetadata, generationId,
424                 status);
425         mRecoverableKeyStoreDb.insertKey(userId, uid, alias3, wrappedKey2);
426         WrappedKey wrappedKeyWithDefaultStatus = new WrappedKey(nonce, keyMaterial, keyMetadata,
427                 generationId);
428         mRecoverableKeyStoreDb.insertKey(userId, uid, alias, wrappedKeyWithDefaultStatus);
429 
430         Map<String, Integer> statuses = mRecoverableKeyStoreDb.getStatusForAllKeys(uid);
431         assertThat(statuses).hasSize(3);
432         assertThat(statuses).containsEntry(alias,
433                 RecoveryController.RECOVERY_STATUS_SYNC_IN_PROGRESS);
434         assertThat(statuses).containsEntry(alias2, status);
435         assertThat(statuses).containsEntry(alias3, status);
436 
437         int updates = mRecoverableKeyStoreDb.setRecoveryStatus(uid, alias, status2);
438         assertThat(updates).isEqualTo(1);
439         updates = mRecoverableKeyStoreDb.setRecoveryStatus(uid, alias3, status2);
440         assertThat(updates).isEqualTo(1);
441         statuses = mRecoverableKeyStoreDb.getStatusForAllKeys(uid);
442 
443         assertThat(statuses).hasSize(3);
444         assertThat(statuses).containsEntry(alias, status2); // updated from default
445         assertThat(statuses).containsEntry(alias2, status);
446         assertThat(statuses).containsEntry(alias3, status2); // updated
447     }
448 
449     @Test
setRecoveryStatus_withEmptyDatabase()450     public void setRecoveryStatus_withEmptyDatabase() throws Exception{
451         int uid = 1009;
452         String alias = "test";
453         int status = 120;
454         int updates = mRecoverableKeyStoreDb.setRecoveryStatus(uid, alias, status);
455         assertThat(updates).isEqualTo(0); // database was empty
456     }
457 
458 
459     @Test
getStatusForAllKeys_withEmptyDatabase()460     public void getStatusForAllKeys_withEmptyDatabase() {
461         int uid = 1009;
462         Map<String, Integer> statuses = mRecoverableKeyStoreDb.getStatusForAllKeys(uid);
463         assertThat(statuses).hasSize(0);
464     }
465 
466     @Test
testInvalidateKeysForUser_withSingleKey()467     public void testInvalidateKeysForUser_withSingleKey() {
468         int userId = 12;
469         int uid = 1009;
470         int generationId = 6;
471         int status = 120;
472         int status2 = 121;
473         String alias = "test";
474         byte[] nonce = getUtf8Bytes("nonce");
475         byte[] keyMaterial = getUtf8Bytes("keymaterial");
476         byte[] keyMetadata = null;
477 
478         WrappedKey wrappedKey = new WrappedKey(nonce, keyMaterial, keyMetadata, generationId,
479                 status);
480         mRecoverableKeyStoreDb.insertKey(userId, uid, alias, wrappedKey);
481 
482         WrappedKey retrievedKey = mRecoverableKeyStoreDb.getKey(uid, alias);
483         assertThat(retrievedKey.getRecoveryStatus()).isEqualTo(status);
484 
485         mRecoverableKeyStoreDb.setRecoveryStatus(uid, alias, status2);
486         mRecoverableKeyStoreDb.invalidateKeysForUser(userId);
487 
488         retrievedKey = mRecoverableKeyStoreDb.getKey(uid, alias);
489         assertThat(retrievedKey.getRecoveryStatus())
490                 .isEqualTo(RecoveryController.RECOVERY_STATUS_PERMANENT_FAILURE);
491     }
492 
493     @Test
testInvalidateKeysForUserIdOnCustomScreenLock()494     public void testInvalidateKeysForUserIdOnCustomScreenLock() {
495         int userId = 12;
496         int uid = 1009;
497         int generationId = 6;
498         int status = 120;
499         int status2 = 121;
500         String alias = "test";
501         byte[] nonce = getUtf8Bytes("nonce");
502         byte[] keyMaterial = getUtf8Bytes("keymaterial");
503         byte[] keyMetadata = null;
504 
505         WrappedKey wrappedKey = new WrappedKey(nonce, keyMaterial, keyMetadata, generationId,
506                 status);
507         mRecoverableKeyStoreDb.insertKey(userId, uid, alias, wrappedKey);
508 
509         WrappedKey retrievedKey = mRecoverableKeyStoreDb.getKey(uid, alias);
510         assertThat(retrievedKey.getRecoveryStatus()).isEqualTo(status);
511 
512         mRecoverableKeyStoreDb.setRecoveryStatus(uid, alias, status2);
513         mRecoverableKeyStoreDb.invalidateKeysForUserIdOnCustomScreenLock(userId);
514 
515         retrievedKey = mRecoverableKeyStoreDb.getKey(uid, alias);
516         assertThat(retrievedKey.getRecoveryStatus())
517             .isEqualTo(RecoveryController.RECOVERY_STATUS_PERMANENT_FAILURE);
518     }
519 
520     @Test
setRecoveryServicePublicKey_replaceOldKey()521     public void setRecoveryServicePublicKey_replaceOldKey() throws Exception {
522         int userId = 12;
523         int uid = 10009;
524         PublicKey pubkey1 = genRandomPublicKey();
525         PublicKey pubkey2 = genRandomPublicKey();
526         mRecoverableKeyStoreDb.setRecoveryServicePublicKey(userId, uid, pubkey1);
527         mRecoverableKeyStoreDb.setRecoveryServicePublicKey(userId, uid, pubkey2);
528         assertThat(mRecoverableKeyStoreDb.getRecoveryServicePublicKey(userId, uid)).isEqualTo(
529                 pubkey2);
530     }
531 
532     @Test
getRecoveryServicePublicKey_returnsNullIfNoKey()533     public void getRecoveryServicePublicKey_returnsNullIfNoKey() throws Exception {
534         int userId = 12;
535         int uid = 10009;
536         assertThat(mRecoverableKeyStoreDb.getRecoveryServicePublicKey(userId, uid)).isNull();
537 
538         mRecoverableKeyStoreDb.setServerParams(userId, uid, SERVER_PARAMS);
539         assertThat(mRecoverableKeyStoreDb.getRecoveryServicePublicKey(userId, uid)).isNull();
540     }
541 
542     @Test
getRecoveryServicePublicKey_returnsInsertedKey()543     public void getRecoveryServicePublicKey_returnsInsertedKey() throws Exception {
544         int userId = 12;
545         int uid = 10009;
546         PublicKey pubkey = genRandomPublicKey();
547         mRecoverableKeyStoreDb.setRecoveryServicePublicKey(userId, uid, pubkey);
548         assertThat(mRecoverableKeyStoreDb.getRecoveryServicePublicKey(userId, uid)).isEqualTo(
549                 pubkey);
550     }
551 
552     @Test
setRecoveryServiceCertPath_replaceOldValue()553     public void setRecoveryServiceCertPath_replaceOldValue() throws Exception {
554         int userId = 12;
555         int uid = 10009;
556         mRecoverableKeyStoreDb.setRecoveryServiceCertPath(userId, uid, TEST_ROOT_CERT_ALIAS,
557                 TestData.CERT_PATH_1);
558         mRecoverableKeyStoreDb.setRecoveryServiceCertPath(userId, uid, TEST_ROOT_CERT_ALIAS,
559                 TestData.CERT_PATH_2);
560         assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertPath(userId, uid,
561                 TEST_ROOT_CERT_ALIAS)).isEqualTo(TestData.CERT_PATH_2);
562     }
563 
564     @Test
setRecoveryServiceCertPath_updateValuesForCorrectRootCert()565     public void setRecoveryServiceCertPath_updateValuesForCorrectRootCert() throws Exception {
566         int userId = 12;
567         int uid = 10009;
568         mRecoverableKeyStoreDb.setRecoveryServiceCertPath(userId, uid, TEST_ROOT_CERT_ALIAS,
569                 TestData.CERT_PATH_1);
570         mRecoverableKeyStoreDb.setRecoveryServiceCertPath(userId, uid, TEST_ROOT_CERT_ALIAS2,
571                 TestData.CERT_PATH_1);
572 
573         assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertPath(userId, uid,
574                 TEST_ROOT_CERT_ALIAS)).isEqualTo(TestData.CERT_PATH_1);
575         assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertPath(userId, uid,
576                 TEST_ROOT_CERT_ALIAS2)).isEqualTo(TestData.CERT_PATH_1);
577 
578         mRecoverableKeyStoreDb.setRecoveryServiceCertPath(userId, uid, TEST_ROOT_CERT_ALIAS2,
579                 TestData.CERT_PATH_2);
580 
581         assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertPath(userId, uid,
582                 TEST_ROOT_CERT_ALIAS)).isEqualTo(TestData.CERT_PATH_1);
583         assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertPath(userId, uid,
584                 TEST_ROOT_CERT_ALIAS2)).isEqualTo(TestData.CERT_PATH_2);
585     }
586 
587     @Test
getRecoveryServiceCertPath_returnsNullIfNoValue()588     public void getRecoveryServiceCertPath_returnsNullIfNoValue() throws Exception {
589         int userId = 12;
590         int uid = 10009;
591         assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertPath(userId, uid,
592                 TEST_ROOT_CERT_ALIAS)).isNull();
593     }
594 
595     @Test
getRecoveryServiceCertPath_returnsInsertedValue()596     public void getRecoveryServiceCertPath_returnsInsertedValue() throws Exception {
597         int userId = 12;
598         int uid = 10009;
599         mRecoverableKeyStoreDb.setRecoveryServiceCertPath(userId, uid, TEST_ROOT_CERT_ALIAS,
600                 TestData.CERT_PATH_1);
601         assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertPath(userId, uid,
602                 TEST_ROOT_CERT_ALIAS)).isEqualTo(TestData.CERT_PATH_1);
603     }
604 
605     @Test
setRecoveryServiceCertSerial_replaceOldValue()606     public void setRecoveryServiceCertSerial_replaceOldValue() throws Exception {
607         int userId = 12;
608         int uid = 10009;
609 
610         mRecoverableKeyStoreDb.setRecoveryServiceCertSerial(userId, uid, TEST_ROOT_CERT_ALIAS, 1L);
611         mRecoverableKeyStoreDb.setRecoveryServiceCertSerial(userId, uid, TEST_ROOT_CERT_ALIAS, 3L);
612         assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertSerial(userId, uid,
613                 TEST_ROOT_CERT_ALIAS)).isEqualTo(3L);
614     }
615 
616     @Test
setRecoveryServiceCertSerial_updateValuesForCorrectRootCert()617     public void setRecoveryServiceCertSerial_updateValuesForCorrectRootCert() throws Exception {
618         int userId = 12;
619         int uid = 10009;
620         mRecoverableKeyStoreDb.setRecoveryServiceCertSerial(userId, uid, TEST_ROOT_CERT_ALIAS, 1L);
621         mRecoverableKeyStoreDb.setRecoveryServiceCertSerial(userId, uid, TEST_ROOT_CERT_ALIAS2, 1L);
622 
623         assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertSerial(userId, uid,
624                 TEST_ROOT_CERT_ALIAS)).isEqualTo(1L);
625         assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertSerial(userId, uid,
626                 TEST_ROOT_CERT_ALIAS2)).isEqualTo(1L);
627 
628         mRecoverableKeyStoreDb.setRecoveryServiceCertSerial(userId, uid, TEST_ROOT_CERT_ALIAS2, 3L);
629 
630         assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertSerial(userId, uid,
631                 TEST_ROOT_CERT_ALIAS)).isEqualTo(1L);
632         assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertSerial(userId, uid,
633                 TEST_ROOT_CERT_ALIAS2)).isEqualTo(3L);
634     }
635 
636     @Test
getRecoveryServiceCertSerial_returnsNullIfNoValue()637     public void getRecoveryServiceCertSerial_returnsNullIfNoValue() throws Exception {
638         int userId = 12;
639         int uid = 10009;
640         assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertSerial(userId, uid,
641                 TEST_ROOT_CERT_ALIAS)).isNull();
642         assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertSerial(userId, uid,
643                 TEST_ROOT_CERT_ALIAS2)).isNull();
644     }
645 
646     @Test
getRecoveryServiceCertSerial_returnsInsertedValue()647     public void getRecoveryServiceCertSerial_returnsInsertedValue() throws Exception {
648         int userId = 12;
649         int uid = 10009;
650         mRecoverableKeyStoreDb.setRecoveryServiceCertSerial(userId, uid,
651                 TEST_ROOT_CERT_ALIAS, 1234L);
652         assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertSerial(userId, uid,
653                 TEST_ROOT_CERT_ALIAS)).isEqualTo(1234L);
654     }
655 
656     @Test
getRecoveryAgents_returnsUidIfSet()657     public void getRecoveryAgents_returnsUidIfSet() throws Exception {
658         int userId = 12;
659         int uid = 190992;
660         mRecoverableKeyStoreDb.setRecoveryServicePublicKey(userId, uid, genRandomPublicKey());
661 
662         assertThat(mRecoverableKeyStoreDb.getRecoveryAgents(userId)).contains(uid);
663     }
664 
665     @Test
getRecoveryAgents_returnsEmptyListIfThereAreNoAgents()666     public void getRecoveryAgents_returnsEmptyListIfThereAreNoAgents() throws Exception {
667         int userId = 12;
668         assertThat(mRecoverableKeyStoreDb.getRecoveryAgents(userId)).isEmpty();
669         assertThat(mRecoverableKeyStoreDb.getRecoveryAgents(userId)).isNotNull();
670     }
671 
672     @Test
getRecoveryAgents_withTwoAgents()673     public void getRecoveryAgents_withTwoAgents() throws Exception {
674         int userId = 12;
675         int uid1 = 190992;
676         int uid2 = 190993;
677         mRecoverableKeyStoreDb.setRecoveryServicePublicKey(userId, uid1, genRandomPublicKey());
678         mRecoverableKeyStoreDb.setRecoveryServicePublicKey(userId, uid2, genRandomPublicKey());
679         List<Integer> agents = mRecoverableKeyStoreDb.getRecoveryAgents(userId);
680 
681         assertThat(agents).hasSize(2);
682         assertThat(agents).contains(uid1);
683         assertThat(agents).contains(uid2);
684     }
685 
686     @Test
setActiveRootOfTrust_emptyDefaultValue()687     public void setActiveRootOfTrust_emptyDefaultValue() throws Exception {
688         int userId = 12;
689         int uid = 10009;
690         assertThat(mRecoverableKeyStoreDb.getActiveRootOfTrust(userId, uid)).isEqualTo(null);
691     }
692 
693     @Test
setActiveRootOfTrust_updateValue()694     public void setActiveRootOfTrust_updateValue() throws Exception {
695         int userId = 12;
696         int uid = 10009;
697         mRecoverableKeyStoreDb.setActiveRootOfTrust(userId, uid, "root");
698         assertThat(mRecoverableKeyStoreDb.getActiveRootOfTrust(userId, uid)).isEqualTo("root");
699 
700         mRecoverableKeyStoreDb.setActiveRootOfTrust(userId, uid, "root2");
701         assertThat(mRecoverableKeyStoreDb.getActiveRootOfTrust(userId, uid)).isEqualTo("root2");
702     }
703 
704     @Test
setRecoverySecretTypes_emptyDefaultValue()705     public void setRecoverySecretTypes_emptyDefaultValue() throws Exception {
706         int userId = 12;
707         int uid = 10009;
708         assertThat(mRecoverableKeyStoreDb.getRecoverySecretTypes(userId, uid)).isEqualTo(
709                 new int[]{}); // default
710     }
711 
712     @Test
setRecoverySecretTypes_updateValue()713     public void setRecoverySecretTypes_updateValue() throws Exception {
714         int userId = 12;
715         int uid = 10009;
716         int[] types1 = new int[]{1};
717         int[] types2 = new int[]{2};
718 
719         mRecoverableKeyStoreDb.setRecoverySecretTypes(userId, uid, types1);
720         assertThat(mRecoverableKeyStoreDb.getRecoverySecretTypes(userId, uid)).isEqualTo(types1);
721         mRecoverableKeyStoreDb.setRecoverySecretTypes(userId, uid, types2);
722         assertThat(mRecoverableKeyStoreDb.getRecoverySecretTypes(userId, uid)).isEqualTo(types2);
723     }
724 
725     @Test
setRecoverySecretTypes_withMultiElementArrays()726     public void setRecoverySecretTypes_withMultiElementArrays() throws Exception {
727         int userId = 12;
728         int uid = 10009;
729         int[] types1 = new int[]{11, 2000};
730         int[] types2 = new int[]{1, 2, 3};
731         int[] types3 = new int[]{};
732 
733         mRecoverableKeyStoreDb.setRecoverySecretTypes(userId, uid, types1);
734         assertThat(mRecoverableKeyStoreDb.getRecoverySecretTypes(userId, uid)).isEqualTo(
735                 types1);
736         mRecoverableKeyStoreDb.setRecoverySecretTypes(userId, uid, types2);
737         assertThat(mRecoverableKeyStoreDb.getRecoverySecretTypes(userId, uid)).isEqualTo(
738                 types2);
739         mRecoverableKeyStoreDb.setRecoverySecretTypes(userId, uid, types3);
740         assertThat(mRecoverableKeyStoreDb.getRecoverySecretTypes(userId, uid)).isEqualTo(
741                 types3);
742     }
743 
744     @Test
setRecoverySecretTypes_withDifferentUid()745     public void setRecoverySecretTypes_withDifferentUid() throws Exception {
746         int userId = 12;
747         int uid1 = 10011;
748         int uid2 = 10012;
749         int[] types1 = new int[]{1};
750         int[] types2 = new int[]{2};
751 
752         mRecoverableKeyStoreDb.setRecoverySecretTypes(userId, uid1, types1);
753         mRecoverableKeyStoreDb.setRecoverySecretTypes(userId, uid2, types2);
754         assertThat(mRecoverableKeyStoreDb.getRecoverySecretTypes(userId, uid1)).isEqualTo(
755                 types1);
756         assertThat(mRecoverableKeyStoreDb.getRecoverySecretTypes(userId, uid2)).isEqualTo(
757                 types2);
758     }
759 
760     @Test
setRecoveryServiceMetadataMethods()761     public void setRecoveryServiceMetadataMethods() throws Exception {
762         int userId = 12;
763         int uid = 10009;
764 
765         PublicKey pubkey1 = genRandomPublicKey();
766         int[] types1 = new int[]{1};
767 
768         PublicKey pubkey2 = genRandomPublicKey();
769         int[] types2 = new int[]{2};
770 
771         mRecoverableKeyStoreDb.setRecoveryServicePublicKey(userId, uid, pubkey1);
772         mRecoverableKeyStoreDb.setRecoverySecretTypes(userId, uid, types1);
773         mRecoverableKeyStoreDb.setServerParams(userId, uid, SERVER_PARAMS);
774 
775         assertThat(mRecoverableKeyStoreDb.getRecoverySecretTypes(userId, uid)).isEqualTo(
776                 types1);
777         assertThat(mRecoverableKeyStoreDb.getServerParams(userId, uid)).isEqualTo(
778                 SERVER_PARAMS);
779         assertThat(mRecoverableKeyStoreDb.getRecoveryServicePublicKey(userId, uid)).isEqualTo(
780                 pubkey1);
781 
782         // Check that the methods don't interfere with each other.
783         mRecoverableKeyStoreDb.setRecoveryServicePublicKey(userId, uid, pubkey2);
784         mRecoverableKeyStoreDb.setRecoverySecretTypes(userId, uid, types2);
785         mRecoverableKeyStoreDb.setServerParams(userId, uid, SERVER_PARAMS2);
786 
787         assertThat(mRecoverableKeyStoreDb.getRecoverySecretTypes(userId, uid)).isEqualTo(
788                 types2);
789         assertThat(mRecoverableKeyStoreDb.getServerParams(userId, uid)).isEqualTo(
790                 SERVER_PARAMS2);
791         assertThat(mRecoverableKeyStoreDb.getRecoveryServicePublicKey(userId, uid)).isEqualTo(
792                 pubkey2);
793     }
794 
795     @Test
setServerParams_replaceOldValue()796     public void setServerParams_replaceOldValue() throws Exception {
797         int userId = 12;
798         int uid = 10009;
799 
800         mRecoverableKeyStoreDb.setServerParams(userId, uid, SERVER_PARAMS);
801         mRecoverableKeyStoreDb.setServerParams(userId, uid, SERVER_PARAMS2);
802         assertThat(mRecoverableKeyStoreDb.getServerParams(userId, uid)).isEqualTo(
803                 SERVER_PARAMS2);
804     }
805 
806     @Test
getServerParams_returnsNullIfNoValue()807     public void getServerParams_returnsNullIfNoValue() throws Exception {
808         int userId = 12;
809         int uid = 10009;
810         assertThat(mRecoverableKeyStoreDb.getServerParams(userId, uid)).isNull();
811 
812         PublicKey pubkey = genRandomPublicKey();
813         mRecoverableKeyStoreDb.setRecoveryServicePublicKey(userId, uid, pubkey);
814         assertThat(mRecoverableKeyStoreDb.getServerParams(userId, uid)).isNull();
815     }
816 
817     @Test
getServerParams_returnsInsertedValue()818     public void getServerParams_returnsInsertedValue() throws Exception {
819         int userId = 12;
820         int uid = 10009;
821         mRecoverableKeyStoreDb.setServerParams(userId, uid, SERVER_PARAMS);
822         assertThat(mRecoverableKeyStoreDb.getServerParams(userId, uid)).isEqualTo(SERVER_PARAMS);
823     }
824 
825     @Test
setCounterId_defaultValueAndTwoUpdates()826     public void setCounterId_defaultValueAndTwoUpdates() throws Exception {
827         int userId = 12;
828         int uid = 10009;
829         long value1 = 111L;
830         long value2 = 222L;
831         assertThat(mRecoverableKeyStoreDb.getCounterId(userId, uid)).isNull();
832 
833         mRecoverableKeyStoreDb.setCounterId(userId, uid, value1);
834         assertThat(mRecoverableKeyStoreDb.getCounterId(userId, uid)).isEqualTo(
835                 value1);
836 
837         mRecoverableKeyStoreDb.setCounterId(userId, uid, value2);
838         assertThat(mRecoverableKeyStoreDb.getCounterId(userId, uid)).isEqualTo(
839                 value2);
840     }
841 
842     @Test
setSnapshotVersion_defaultValueAndTwoUpdates()843     public void setSnapshotVersion_defaultValueAndTwoUpdates() throws Exception {
844         int userId = 12;
845         int uid = 10009;
846         long value1 = 111L;
847         long value2 = 222L;
848         assertThat(mRecoverableKeyStoreDb.getSnapshotVersion(userId, uid)).isNull();
849         mRecoverableKeyStoreDb.setSnapshotVersion(userId, uid, value1);
850         assertThat(mRecoverableKeyStoreDb.getSnapshotVersion(userId, uid)).isEqualTo(
851                 value1);
852         mRecoverableKeyStoreDb.setSnapshotVersion(userId, uid, value2);
853         assertThat(mRecoverableKeyStoreDb.getSnapshotVersion(userId, uid)).isEqualTo(
854                 value2);
855     }
856 
857     @Test
setShouldCreateSnapshot_defaultValueAndTwoUpdates()858     public void setShouldCreateSnapshot_defaultValueAndTwoUpdates() throws Exception {
859         int userId = 12;
860         int uid = 10009;
861         boolean value1 = true;
862         boolean value2 = false;
863         assertThat(mRecoverableKeyStoreDb.getShouldCreateSnapshot(userId, uid)).isEqualTo(false);
864         mRecoverableKeyStoreDb.setShouldCreateSnapshot(userId, uid, value1);
865         assertThat(mRecoverableKeyStoreDb.getShouldCreateSnapshot(userId, uid)).isEqualTo(value1);
866         mRecoverableKeyStoreDb.setShouldCreateSnapshot(userId, uid, value2);
867         assertThat(mRecoverableKeyStoreDb.getShouldCreateSnapshot(userId, uid)).isEqualTo(
868                 value2);
869     }
870 
871     @Test
setRecoveryServiceMetadataEntry_allowsAUserToHaveTwoUids()872     public void setRecoveryServiceMetadataEntry_allowsAUserToHaveTwoUids() throws Exception {
873         int userId = 12;
874         int uid1 = 10009;
875         int uid2 = 20009;
876         PublicKey pubkey = genRandomPublicKey();
877         mRecoverableKeyStoreDb.setRecoveryServicePublicKey(userId, uid1, pubkey);
878         mRecoverableKeyStoreDb.setRecoveryServicePublicKey(userId, uid2, pubkey);
879         assertThat(mRecoverableKeyStoreDb.getRecoveryServicePublicKey(userId, uid1)).isEqualTo(
880                 pubkey);
881         assertThat(mRecoverableKeyStoreDb.getRecoveryServicePublicKey(userId, uid2)).isEqualTo(
882                 pubkey);
883     }
884 
885     @Test
setRecoveryServiceMetadataEntry_allowsTwoUsersToHaveTheSameUid()886     public void setRecoveryServiceMetadataEntry_allowsTwoUsersToHaveTheSameUid() throws Exception {
887         int userId1 = 12;
888         int userId2 = 23;
889         int uid = 10009;
890         PublicKey pubkey = genRandomPublicKey();
891         mRecoverableKeyStoreDb.setRecoveryServicePublicKey(userId1, uid, pubkey);
892         mRecoverableKeyStoreDb.setRecoveryServicePublicKey(userId2, uid, pubkey);
893         assertThat(mRecoverableKeyStoreDb.getRecoveryServicePublicKey(userId1, uid)).isEqualTo(
894                 pubkey);
895         assertThat(mRecoverableKeyStoreDb.getRecoveryServicePublicKey(userId2, uid)).isEqualTo(
896                 pubkey);
897     }
898 
899     @Test
setRecoveryServiceMetadataEntry_updatesColumnsSeparately()900     public void setRecoveryServiceMetadataEntry_updatesColumnsSeparately() throws Exception {
901         int userId = 12;
902         int uid = 10009;
903         PublicKey pubkey1 = genRandomPublicKey();
904         PublicKey pubkey2 = genRandomPublicKey();
905 
906         mRecoverableKeyStoreDb.setRecoveryServicePublicKey(userId, uid, pubkey1);
907         assertThat(mRecoverableKeyStoreDb.getRecoveryServicePublicKey(userId, uid)).isEqualTo(
908                 pubkey1);
909         assertThat(mRecoverableKeyStoreDb.getServerParams(userId, uid)).isNull();
910 
911         mRecoverableKeyStoreDb.setServerParams(userId, uid, SERVER_PARAMS);
912         assertThat(mRecoverableKeyStoreDb.getRecoveryServicePublicKey(userId, uid)).isEqualTo(
913                 pubkey1);
914         assertThat(mRecoverableKeyStoreDb.getServerParams(userId, uid)).isEqualTo(SERVER_PARAMS);
915 
916         mRecoverableKeyStoreDb.setRecoveryServicePublicKey(userId, uid, pubkey2);
917         assertThat(mRecoverableKeyStoreDb.getRecoveryServicePublicKey(userId, uid)).isEqualTo(
918                 pubkey2);
919         assertThat(mRecoverableKeyStoreDb.getServerParams(userId, uid)).isEqualTo(SERVER_PARAMS);
920     }
921 
getUtf8Bytes(String s)922     private static byte[] getUtf8Bytes(String s) {
923         return s.getBytes(StandardCharsets.UTF_8);
924     }
925 
genRandomPublicKey()926     private static PublicKey genRandomPublicKey() throws Exception {
927         KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC");
928         keyPairGenerator.initialize(new ECGenParameterSpec("secp256r1"));
929         return keyPairGenerator.generateKeyPair().getPublic();
930     }
931 }
932