blob: fdcf2544f597600714b27445fab8620f11929350 [file] [log] [blame]
David Drysdale2566fb32024-07-09 14:46:37 +01001// Copyright 2020, The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Database tests.
16
17use super::*;
18use crate::key_parameter::{
19 Algorithm, BlockMode, Digest, EcCurve, HardwareAuthenticatorType, KeyOrigin, KeyParameter,
20 KeyParameterValue, KeyPurpose, PaddingMode, SecurityLevel,
21};
22use crate::key_perm_set;
23use crate::permission::{KeyPerm, KeyPermSet};
24use crate::super_key::{SuperKeyManager, USER_AFTER_FIRST_UNLOCK_SUPER_KEY, SuperEncryptionAlgorithm, SuperKeyType};
25use keystore2_test_utils::TempDir;
26use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
27 HardwareAuthToken::HardwareAuthToken,
28 HardwareAuthenticatorType::HardwareAuthenticatorType as kmhw_authenticator_type,
29};
30use android_hardware_security_secureclock::aidl::android::hardware::security::secureclock::{
31 Timestamp::Timestamp,
32};
33use std::cell::RefCell;
34use std::collections::BTreeMap;
35use std::fmt::Write;
36use std::sync::atomic::{AtomicU8, Ordering};
37use std::sync::Arc;
38use std::thread;
39use std::time::{Duration, SystemTime};
40use crate::utils::AesGcm;
41#[cfg(disabled)]
42use std::time::Instant;
43
44pub fn new_test_db() -> Result<KeystoreDB> {
David Drysdaleda897432024-06-24 15:57:35 +010045 new_test_db_at("file::memory:")
46}
47
48fn new_test_db_at(path: &str) -> Result<KeystoreDB> {
49 let conn = KeystoreDB::make_connection(path)?;
David Drysdale2566fb32024-07-09 14:46:37 +010050
51 let mut db = KeystoreDB { conn, gc: None, perboot: Arc::new(perboot::PerbootDB::new()) };
52 db.with_transaction(Immediate("TX_new_test_db"), |tx| {
53 KeystoreDB::init_tables(tx).context("Failed to initialize tables.").no_gc()
54 })?;
55 Ok(db)
56}
57
58fn rebind_alias(
59 db: &mut KeystoreDB,
60 newid: &KeyIdGuard,
61 alias: &str,
62 domain: Domain,
63 namespace: i64,
64) -> Result<bool> {
65 db.with_transaction(Immediate("TX_rebind_alias"), |tx| {
66 KeystoreDB::rebind_alias(tx, newid, alias, &domain, &namespace, KeyType::Client).no_gc()
67 })
68 .context(ks_err!())
69}
70
71#[test]
72fn datetime() -> Result<()> {
73 let conn = Connection::open_in_memory()?;
74 conn.execute("CREATE TABLE test (ts DATETIME);", [])?;
75 let now = SystemTime::now();
76 let duration = Duration::from_secs(1000);
77 let then = now.checked_sub(duration).unwrap();
78 let soon = now.checked_add(duration).unwrap();
79 conn.execute(
80 "INSERT INTO test (ts) VALUES (?), (?), (?);",
81 params![DateTime::try_from(now)?, DateTime::try_from(then)?, DateTime::try_from(soon)?],
82 )?;
83 let mut stmt = conn.prepare("SELECT ts FROM test ORDER BY ts ASC;")?;
84 let mut rows = stmt.query([])?;
85 assert_eq!(DateTime::try_from(then)?, rows.next()?.unwrap().get(0)?);
86 assert_eq!(DateTime::try_from(now)?, rows.next()?.unwrap().get(0)?);
87 assert_eq!(DateTime::try_from(soon)?, rows.next()?.unwrap().get(0)?);
88 assert!(rows.next()?.is_none());
89 assert!(DateTime::try_from(then)? < DateTime::try_from(now)?);
90 assert!(DateTime::try_from(then)? < DateTime::try_from(soon)?);
91 assert!(DateTime::try_from(now)? < DateTime::try_from(soon)?);
92 Ok(())
93}
94
95// Ensure that we're using the "injected" random function, not the real one.
96#[test]
97fn test_mocked_random() {
98 let rand1 = random();
99 let rand2 = random();
100 let rand3 = random();
101 if rand1 == rand2 {
102 assert_eq!(rand2 + 1, rand3);
103 } else {
104 assert_eq!(rand1 + 1, rand2);
105 assert_eq!(rand2, rand3);
106 }
107}
108
109// Test that we have the correct tables.
110#[test]
111fn test_tables() -> Result<()> {
112 let db = new_test_db()?;
113 let tables = db
114 .conn
115 .prepare("SELECT name from persistent.sqlite_master WHERE type='table' ORDER BY name;")?
116 .query_map(params![], |row| row.get(0))?
117 .collect::<rusqlite::Result<Vec<String>>>()?;
118 assert_eq!(tables.len(), 6);
119 assert_eq!(tables[0], "blobentry");
120 assert_eq!(tables[1], "blobmetadata");
121 assert_eq!(tables[2], "grant");
122 assert_eq!(tables[3], "keyentry");
123 assert_eq!(tables[4], "keymetadata");
124 assert_eq!(tables[5], "keyparameter");
125 Ok(())
126}
127
128#[test]
129fn test_auth_token_table_invariant() -> Result<()> {
130 let mut db = new_test_db()?;
131 let auth_token1 = HardwareAuthToken {
132 challenge: i64::MAX,
133 userId: 200,
134 authenticatorId: 200,
135 authenticatorType: kmhw_authenticator_type(kmhw_authenticator_type::PASSWORD.0),
136 timestamp: Timestamp { milliSeconds: 500 },
137 mac: String::from("mac").into_bytes(),
138 };
139 db.insert_auth_token(&auth_token1);
140 let auth_tokens_returned = get_auth_tokens(&db);
141 assert_eq!(auth_tokens_returned.len(), 1);
142
143 // insert another auth token with the same values for the columns in the UNIQUE constraint
144 // of the auth token table and different value for timestamp
145 let auth_token2 = HardwareAuthToken {
146 challenge: i64::MAX,
147 userId: 200,
148 authenticatorId: 200,
149 authenticatorType: kmhw_authenticator_type(kmhw_authenticator_type::PASSWORD.0),
150 timestamp: Timestamp { milliSeconds: 600 },
151 mac: String::from("mac").into_bytes(),
152 };
153
154 db.insert_auth_token(&auth_token2);
155 let mut auth_tokens_returned = get_auth_tokens(&db);
156 assert_eq!(auth_tokens_returned.len(), 1);
157
158 if let Some(auth_token) = auth_tokens_returned.pop() {
159 assert_eq!(auth_token.auth_token.timestamp.milliSeconds, 600);
160 }
161
162 // insert another auth token with the different values for the columns in the UNIQUE
163 // constraint of the auth token table
164 let auth_token3 = HardwareAuthToken {
165 challenge: i64::MAX,
166 userId: 201,
167 authenticatorId: 200,
168 authenticatorType: kmhw_authenticator_type(kmhw_authenticator_type::PASSWORD.0),
169 timestamp: Timestamp { milliSeconds: 600 },
170 mac: String::from("mac").into_bytes(),
171 };
172
173 db.insert_auth_token(&auth_token3);
174 let auth_tokens_returned = get_auth_tokens(&db);
175 assert_eq!(auth_tokens_returned.len(), 2);
176
177 Ok(())
178}
179
180// utility function for test_auth_token_table_invariant()
181fn get_auth_tokens(db: &KeystoreDB) -> Vec<AuthTokenEntry> {
182 db.perboot.get_all_auth_token_entries()
183}
184
185fn create_key_entry(
186 db: &mut KeystoreDB,
187 domain: &Domain,
188 namespace: &i64,
189 key_type: KeyType,
190 km_uuid: &Uuid,
191) -> Result<KeyIdGuard> {
192 db.with_transaction(Immediate("TX_create_key_entry"), |tx| {
193 KeystoreDB::create_key_entry_internal(tx, domain, namespace, key_type, km_uuid).no_gc()
194 })
195}
196
197#[test]
198fn test_persistence_for_files() -> Result<()> {
199 let temp_dir = TempDir::new("persistent_db_test")?;
200 let mut db = KeystoreDB::new(temp_dir.path(), None)?;
201
202 create_key_entry(&mut db, &Domain::APP, &100, KeyType::Client, &KEYSTORE_UUID)?;
203 let entries = get_keyentry(&db)?;
204 assert_eq!(entries.len(), 1);
205
206 let db = KeystoreDB::new(temp_dir.path(), None)?;
207
208 let entries_new = get_keyentry(&db)?;
209 assert_eq!(entries, entries_new);
210 Ok(())
211}
212
213#[test]
214fn test_create_key_entry() -> Result<()> {
215 fn extractor(ke: &KeyEntryRow) -> (Domain, i64, Option<&str>, Uuid) {
216 (ke.domain.unwrap(), ke.namespace.unwrap(), ke.alias.as_deref(), ke.km_uuid.unwrap())
217 }
218
219 let mut db = new_test_db()?;
220
221 create_key_entry(&mut db, &Domain::APP, &100, KeyType::Client, &KEYSTORE_UUID)?;
222 create_key_entry(&mut db, &Domain::SELINUX, &101, KeyType::Client, &KEYSTORE_UUID)?;
223
224 let entries = get_keyentry(&db)?;
225 assert_eq!(entries.len(), 2);
226 assert_eq!(extractor(&entries[0]), (Domain::APP, 100, None, KEYSTORE_UUID));
227 assert_eq!(extractor(&entries[1]), (Domain::SELINUX, 101, None, KEYSTORE_UUID));
228
229 // Test that we must pass in a valid Domain.
230 check_result_is_error_containing_string(
231 create_key_entry(&mut db, &Domain::GRANT, &102, KeyType::Client, &KEYSTORE_UUID),
232 &format!("Domain {:?} must be either App or SELinux.", Domain::GRANT),
233 );
234 check_result_is_error_containing_string(
235 create_key_entry(&mut db, &Domain::BLOB, &103, KeyType::Client, &KEYSTORE_UUID),
236 &format!("Domain {:?} must be either App or SELinux.", Domain::BLOB),
237 );
238 check_result_is_error_containing_string(
239 create_key_entry(&mut db, &Domain::KEY_ID, &104, KeyType::Client, &KEYSTORE_UUID),
240 &format!("Domain {:?} must be either App or SELinux.", Domain::KEY_ID),
241 );
242
243 Ok(())
244}
245
246#[test]
247fn test_rebind_alias() -> Result<()> {
248 fn extractor(ke: &KeyEntryRow) -> (Option<Domain>, Option<i64>, Option<&str>, Option<Uuid>) {
249 (ke.domain, ke.namespace, ke.alias.as_deref(), ke.km_uuid)
250 }
251
252 let mut db = new_test_db()?;
253 create_key_entry(&mut db, &Domain::APP, &42, KeyType::Client, &KEYSTORE_UUID)?;
254 create_key_entry(&mut db, &Domain::APP, &42, KeyType::Client, &KEYSTORE_UUID)?;
255 let entries = get_keyentry(&db)?;
256 assert_eq!(entries.len(), 2);
257 assert_eq!(extractor(&entries[0]), (Some(Domain::APP), Some(42), None, Some(KEYSTORE_UUID)));
258 assert_eq!(extractor(&entries[1]), (Some(Domain::APP), Some(42), None, Some(KEYSTORE_UUID)));
259
260 // Test that the first call to rebind_alias sets the alias.
261 rebind_alias(&mut db, &KEY_ID_LOCK.get(entries[0].id), "foo", Domain::APP, 42)?;
262 let entries = get_keyentry(&db)?;
263 assert_eq!(entries.len(), 2);
264 assert_eq!(
265 extractor(&entries[0]),
266 (Some(Domain::APP), Some(42), Some("foo"), Some(KEYSTORE_UUID))
267 );
268 assert_eq!(extractor(&entries[1]), (Some(Domain::APP), Some(42), None, Some(KEYSTORE_UUID)));
269
270 // Test that the second call to rebind_alias also empties the old one.
271 rebind_alias(&mut db, &KEY_ID_LOCK.get(entries[1].id), "foo", Domain::APP, 42)?;
272 let entries = get_keyentry(&db)?;
273 assert_eq!(entries.len(), 2);
274 assert_eq!(extractor(&entries[0]), (None, None, None, Some(KEYSTORE_UUID)));
275 assert_eq!(
276 extractor(&entries[1]),
277 (Some(Domain::APP), Some(42), Some("foo"), Some(KEYSTORE_UUID))
278 );
279
280 // Test that we must pass in a valid Domain.
281 check_result_is_error_containing_string(
282 rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::GRANT, 42),
283 &format!("Domain {:?} must be either App or SELinux.", Domain::GRANT),
284 );
285 check_result_is_error_containing_string(
286 rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::BLOB, 42),
287 &format!("Domain {:?} must be either App or SELinux.", Domain::BLOB),
288 );
289 check_result_is_error_containing_string(
290 rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::KEY_ID, 42),
291 &format!("Domain {:?} must be either App or SELinux.", Domain::KEY_ID),
292 );
293
294 // Test that we correctly handle setting an alias for something that does not exist.
295 check_result_is_error_containing_string(
296 rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::SELINUX, 42),
297 "Expected to update a single entry but instead updated 0",
298 );
299 // Test that we correctly abort the transaction in this case.
300 let entries = get_keyentry(&db)?;
301 assert_eq!(entries.len(), 2);
302 assert_eq!(extractor(&entries[0]), (None, None, None, Some(KEYSTORE_UUID)));
303 assert_eq!(
304 extractor(&entries[1]),
305 (Some(Domain::APP), Some(42), Some("foo"), Some(KEYSTORE_UUID))
306 );
307
308 Ok(())
309}
310
311#[test]
312fn test_grant_ungrant() -> Result<()> {
313 const CALLER_UID: u32 = 15;
314 const GRANTEE_UID: u32 = 12;
315 const SELINUX_NAMESPACE: i64 = 7;
316
317 let mut db = new_test_db()?;
318 db.conn.execute(
319 "INSERT INTO persistent.keyentry (id, key_type, domain, namespace, alias, state, km_uuid)
320 VALUES (1, 0, 0, 15, 'key', 1, ?), (2, 0, 2, 7, 'yek', 1, ?);",
321 params![KEYSTORE_UUID, KEYSTORE_UUID],
322 )?;
323 let app_key = KeyDescriptor {
324 domain: super::Domain::APP,
325 nspace: 0,
326 alias: Some("key".to_string()),
327 blob: None,
328 };
329 const PVEC1: KeyPermSet = key_perm_set![KeyPerm::Use, KeyPerm::GetInfo];
330 const PVEC2: KeyPermSet = key_perm_set![KeyPerm::Use];
331
332 // Reset totally predictable random number generator in case we
333 // are not the first test running on this thread.
334 reset_random();
335 let next_random = 0i64;
336
337 let app_granted_key = db
338 .grant(&app_key, CALLER_UID, GRANTEE_UID, PVEC1, |k, a| {
339 assert_eq!(*a, PVEC1);
340 assert_eq!(
341 *k,
342 KeyDescriptor {
343 domain: super::Domain::APP,
344 // namespace must be set to the caller_uid.
345 nspace: CALLER_UID as i64,
346 alias: Some("key".to_string()),
347 blob: None,
348 }
349 );
350 Ok(())
351 })
352 .unwrap();
353
354 assert_eq!(
355 app_granted_key,
356 KeyDescriptor {
357 domain: super::Domain::GRANT,
358 // The grantid is next_random due to the mock random number generator.
359 nspace: next_random,
360 alias: None,
361 blob: None,
362 }
363 );
364
365 let selinux_key = KeyDescriptor {
366 domain: super::Domain::SELINUX,
367 nspace: SELINUX_NAMESPACE,
368 alias: Some("yek".to_string()),
369 blob: None,
370 };
371
372 let selinux_granted_key = db
373 .grant(&selinux_key, CALLER_UID, 12, PVEC1, |k, a| {
374 assert_eq!(*a, PVEC1);
375 assert_eq!(
376 *k,
377 KeyDescriptor {
378 domain: super::Domain::SELINUX,
379 // namespace must be the supplied SELinux
380 // namespace.
381 nspace: SELINUX_NAMESPACE,
382 alias: Some("yek".to_string()),
383 blob: None,
384 }
385 );
386 Ok(())
387 })
388 .unwrap();
389
390 assert_eq!(
391 selinux_granted_key,
392 KeyDescriptor {
393 domain: super::Domain::GRANT,
394 // The grantid is next_random + 1 due to the mock random number generator.
395 nspace: next_random + 1,
396 alias: None,
397 blob: None,
398 }
399 );
400
401 // This should update the existing grant with PVEC2.
402 let selinux_granted_key = db
403 .grant(&selinux_key, CALLER_UID, 12, PVEC2, |k, a| {
404 assert_eq!(*a, PVEC2);
405 assert_eq!(
406 *k,
407 KeyDescriptor {
408 domain: super::Domain::SELINUX,
409 // namespace must be the supplied SELinux
410 // namespace.
411 nspace: SELINUX_NAMESPACE,
412 alias: Some("yek".to_string()),
413 blob: None,
414 }
415 );
416 Ok(())
417 })
418 .unwrap();
419
420 assert_eq!(
421 selinux_granted_key,
422 KeyDescriptor {
423 domain: super::Domain::GRANT,
424 // Same grant id as before. The entry was only updated.
425 nspace: next_random + 1,
426 alias: None,
427 blob: None,
428 }
429 );
430
431 {
432 // Limiting scope of stmt, because it borrows db.
433 let mut stmt = db
434 .conn
435 .prepare("SELECT id, grantee, keyentryid, access_vector FROM persistent.grant;")?;
436 let mut rows = stmt.query_map::<(i64, u32, i64, KeyPermSet), _, _>([], |row| {
437 Ok((row.get(0)?, row.get(1)?, row.get(2)?, KeyPermSet::from(row.get::<_, i32>(3)?)))
438 })?;
439
440 let r = rows.next().unwrap().unwrap();
441 assert_eq!(r, (next_random, GRANTEE_UID, 1, PVEC1));
442 let r = rows.next().unwrap().unwrap();
443 assert_eq!(r, (next_random + 1, GRANTEE_UID, 2, PVEC2));
444 assert!(rows.next().is_none());
445 }
446
447 debug_dump_keyentry_table(&mut db)?;
448 println!("app_key {:?}", app_key);
449 println!("selinux_key {:?}", selinux_key);
450
451 db.ungrant(&app_key, CALLER_UID, GRANTEE_UID, |_| Ok(()))?;
452 db.ungrant(&selinux_key, CALLER_UID, GRANTEE_UID, |_| Ok(()))?;
453
454 Ok(())
455}
456
457static TEST_KEY_BLOB: &[u8] = b"my test blob";
458static TEST_CERT_BLOB: &[u8] = b"my test cert";
459static TEST_CERT_CHAIN_BLOB: &[u8] = b"my test cert_chain";
460
461#[test]
462fn test_set_blob() -> Result<()> {
463 let key_id = KEY_ID_LOCK.get(3000);
464 let mut db = new_test_db()?;
465 let mut blob_metadata = BlobMetaData::new();
466 blob_metadata.add(BlobMetaEntry::KmUuid(KEYSTORE_UUID));
467 db.set_blob(&key_id, SubComponentType::KEY_BLOB, Some(TEST_KEY_BLOB), Some(&blob_metadata))?;
468 db.set_blob(&key_id, SubComponentType::CERT, Some(TEST_CERT_BLOB), None)?;
469 db.set_blob(&key_id, SubComponentType::CERT_CHAIN, Some(TEST_CERT_CHAIN_BLOB), None)?;
470 drop(key_id);
471
472 let mut stmt = db.conn.prepare(
473 "SELECT subcomponent_type, keyentryid, blob, id FROM persistent.blobentry
474 ORDER BY subcomponent_type ASC;",
475 )?;
476 let mut rows = stmt.query_map::<((SubComponentType, i64, Vec<u8>), i64), _, _>([], |row| {
477 Ok(((row.get(0)?, row.get(1)?, row.get(2)?), row.get(3)?))
478 })?;
479 let (r, id) = rows.next().unwrap().unwrap();
480 assert_eq!(r, (SubComponentType::KEY_BLOB, 3000, TEST_KEY_BLOB.to_vec()));
481 let (r, _) = rows.next().unwrap().unwrap();
482 assert_eq!(r, (SubComponentType::CERT, 3000, TEST_CERT_BLOB.to_vec()));
483 let (r, _) = rows.next().unwrap().unwrap();
484 assert_eq!(r, (SubComponentType::CERT_CHAIN, 3000, TEST_CERT_CHAIN_BLOB.to_vec()));
485
486 drop(rows);
487 drop(stmt);
488
489 assert_eq!(
490 db.with_transaction(Immediate("TX_test"), |tx| {
491 BlobMetaData::load_from_db(id, tx).no_gc()
492 })
493 .expect("Should find blob metadata."),
494 blob_metadata
495 );
496 Ok(())
497}
498
499static TEST_ALIAS: &str = "my super duper key";
500
501#[test]
502fn test_insert_and_load_full_keyentry_domain_app() -> Result<()> {
503 let mut db = new_test_db()?;
504 let key_id = make_test_key_entry(&mut db, Domain::APP, 1, TEST_ALIAS, None)
505 .context("test_insert_and_load_full_keyentry_domain_app")?
506 .0;
507 let (_key_guard, key_entry) = db
508 .load_key_entry(
509 &KeyDescriptor {
510 domain: Domain::APP,
511 nspace: 0,
512 alias: Some(TEST_ALIAS.to_string()),
513 blob: None,
514 },
515 KeyType::Client,
516 KeyEntryLoadBits::BOTH,
517 1,
518 |_k, _av| Ok(()),
519 )
520 .unwrap();
521 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
522
523 db.unbind_key(
524 &KeyDescriptor {
525 domain: Domain::APP,
526 nspace: 0,
527 alias: Some(TEST_ALIAS.to_string()),
528 blob: None,
529 },
530 KeyType::Client,
531 1,
532 |_, _| Ok(()),
533 )
534 .unwrap();
535
536 assert_eq!(
537 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
538 db.load_key_entry(
539 &KeyDescriptor {
540 domain: Domain::APP,
541 nspace: 0,
542 alias: Some(TEST_ALIAS.to_string()),
543 blob: None,
544 },
545 KeyType::Client,
546 KeyEntryLoadBits::NONE,
547 1,
548 |_k, _av| Ok(()),
549 )
550 .unwrap_err()
551 .root_cause()
552 .downcast_ref::<KsError>()
553 );
554
555 Ok(())
556}
557
558#[test]
559fn test_insert_and_load_certificate_entry_domain_app() -> Result<()> {
560 let mut db = new_test_db()?;
561
562 db.store_new_certificate(
563 &KeyDescriptor {
564 domain: Domain::APP,
565 nspace: 1,
566 alias: Some(TEST_ALIAS.to_string()),
567 blob: None,
568 },
569 KeyType::Client,
570 TEST_CERT_BLOB,
571 &KEYSTORE_UUID,
572 )
573 .expect("Trying to insert cert.");
574
575 let (_key_guard, mut key_entry) = db
576 .load_key_entry(
577 &KeyDescriptor {
578 domain: Domain::APP,
579 nspace: 1,
580 alias: Some(TEST_ALIAS.to_string()),
581 blob: None,
582 },
583 KeyType::Client,
584 KeyEntryLoadBits::PUBLIC,
585 1,
586 |_k, _av| Ok(()),
587 )
588 .expect("Trying to read certificate entry.");
589
590 assert!(key_entry.pure_cert());
591 assert!(key_entry.cert().is_none());
592 assert_eq!(key_entry.take_cert_chain(), Some(TEST_CERT_BLOB.to_vec()));
593
594 db.unbind_key(
595 &KeyDescriptor {
596 domain: Domain::APP,
597 nspace: 1,
598 alias: Some(TEST_ALIAS.to_string()),
599 blob: None,
600 },
601 KeyType::Client,
602 1,
603 |_, _| Ok(()),
604 )
605 .unwrap();
606
607 assert_eq!(
608 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
609 db.load_key_entry(
610 &KeyDescriptor {
611 domain: Domain::APP,
612 nspace: 1,
613 alias: Some(TEST_ALIAS.to_string()),
614 blob: None,
615 },
616 KeyType::Client,
617 KeyEntryLoadBits::NONE,
618 1,
619 |_k, _av| Ok(()),
620 )
621 .unwrap_err()
622 .root_cause()
623 .downcast_ref::<KsError>()
624 );
625
626 Ok(())
627}
628
629#[test]
630fn test_insert_and_load_full_keyentry_domain_selinux() -> Result<()> {
631 let mut db = new_test_db()?;
632 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, None)
633 .context("test_insert_and_load_full_keyentry_domain_selinux")?
634 .0;
635 let (_key_guard, key_entry) = db
636 .load_key_entry(
637 &KeyDescriptor {
638 domain: Domain::SELINUX,
639 nspace: 1,
640 alias: Some(TEST_ALIAS.to_string()),
641 blob: None,
642 },
643 KeyType::Client,
644 KeyEntryLoadBits::BOTH,
645 1,
646 |_k, _av| Ok(()),
647 )
648 .unwrap();
649 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
650
651 db.unbind_key(
652 &KeyDescriptor {
653 domain: Domain::SELINUX,
654 nspace: 1,
655 alias: Some(TEST_ALIAS.to_string()),
656 blob: None,
657 },
658 KeyType::Client,
659 1,
660 |_, _| Ok(()),
661 )
662 .unwrap();
663
664 assert_eq!(
665 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
666 db.load_key_entry(
667 &KeyDescriptor {
668 domain: Domain::SELINUX,
669 nspace: 1,
670 alias: Some(TEST_ALIAS.to_string()),
671 blob: None,
672 },
673 KeyType::Client,
674 KeyEntryLoadBits::NONE,
675 1,
676 |_k, _av| Ok(()),
677 )
678 .unwrap_err()
679 .root_cause()
680 .downcast_ref::<KsError>()
681 );
682
683 Ok(())
684}
685
686#[test]
687fn test_insert_and_load_full_keyentry_domain_key_id() -> Result<()> {
688 let mut db = new_test_db()?;
689 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, None)
690 .context("test_insert_and_load_full_keyentry_domain_key_id")?
691 .0;
692 let (_, key_entry) = db
693 .load_key_entry(
694 &KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
695 KeyType::Client,
696 KeyEntryLoadBits::BOTH,
697 1,
698 |_k, _av| Ok(()),
699 )
700 .unwrap();
701
702 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
703
704 db.unbind_key(
705 &KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
706 KeyType::Client,
707 1,
708 |_, _| Ok(()),
709 )
710 .unwrap();
711
712 assert_eq!(
713 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
714 db.load_key_entry(
715 &KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
716 KeyType::Client,
717 KeyEntryLoadBits::NONE,
718 1,
719 |_k, _av| Ok(()),
720 )
721 .unwrap_err()
722 .root_cause()
723 .downcast_ref::<KsError>()
724 );
725
726 Ok(())
727}
728
729#[test]
730fn test_check_and_update_key_usage_count_with_limited_use_key() -> Result<()> {
731 let mut db = new_test_db()?;
732 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, Some(123))
733 .context("test_check_and_update_key_usage_count_with_limited_use_key")?
734 .0;
735 // Update the usage count of the limited use key.
736 db.check_and_update_key_usage_count(key_id)?;
737
738 let (_key_guard, key_entry) = db.load_key_entry(
739 &KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
740 KeyType::Client,
741 KeyEntryLoadBits::BOTH,
742 1,
743 |_k, _av| Ok(()),
744 )?;
745
746 // The usage count is decremented now.
747 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, Some(122)));
748
749 Ok(())
750}
751
752#[test]
753fn test_check_and_update_key_usage_count_with_exhausted_limited_use_key() -> Result<()> {
754 let mut db = new_test_db()?;
755 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, Some(1))
756 .context("test_check_and_update_key_usage_count_with_exhausted_limited_use_key")?
757 .0;
758 // Update the usage count of the limited use key.
759 db.check_and_update_key_usage_count(key_id).expect(concat!(
760 "In test_check_and_update_key_usage_count_with_exhausted_limited_use_key: ",
761 "This should succeed."
762 ));
763
764 // Try to update the exhausted limited use key.
765 let e = db.check_and_update_key_usage_count(key_id).expect_err(concat!(
766 "In test_check_and_update_key_usage_count_with_exhausted_limited_use_key: ",
767 "This should fail."
768 ));
769 assert_eq!(
770 &KsError::Km(ErrorCode::INVALID_KEY_BLOB),
771 e.root_cause().downcast_ref::<KsError>().unwrap()
772 );
773
774 Ok(())
775}
776
777#[test]
778fn test_insert_and_load_full_keyentry_from_grant() -> Result<()> {
779 let mut db = new_test_db()?;
780 let key_id = make_test_key_entry(&mut db, Domain::APP, 1, TEST_ALIAS, None)
781 .context("test_insert_and_load_full_keyentry_from_grant")?
782 .0;
783
784 let granted_key = db
785 .grant(
786 &KeyDescriptor {
787 domain: Domain::APP,
788 nspace: 0,
789 alias: Some(TEST_ALIAS.to_string()),
790 blob: None,
791 },
792 1,
793 2,
794 key_perm_set![KeyPerm::Use],
795 |_k, _av| Ok(()),
796 )
797 .unwrap();
798
799 debug_dump_grant_table(&mut db)?;
800
801 let (_key_guard, key_entry) = db
802 .load_key_entry(&granted_key, KeyType::Client, KeyEntryLoadBits::BOTH, 2, |k, av| {
803 assert_eq!(Domain::GRANT, k.domain);
804 assert!(av.unwrap().includes(KeyPerm::Use));
805 Ok(())
806 })
807 .unwrap();
808
809 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
810
811 db.unbind_key(&granted_key, KeyType::Client, 2, |_, _| Ok(())).unwrap();
812
813 assert_eq!(
814 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
815 db.load_key_entry(&granted_key, KeyType::Client, KeyEntryLoadBits::NONE, 2, |_k, _av| Ok(
816 ()
817 ),)
818 .unwrap_err()
819 .root_cause()
820 .downcast_ref::<KsError>()
821 );
822
823 Ok(())
824}
825
826// This test attempts to load a key by key id while the caller is not the owner
827// but a grant exists for the given key and the caller.
828#[test]
829fn test_insert_and_load_full_keyentry_from_grant_by_key_id() -> Result<()> {
830 let mut db = new_test_db()?;
831 const OWNER_UID: u32 = 1u32;
832 const GRANTEE_UID: u32 = 2u32;
833 const SOMEONE_ELSE_UID: u32 = 3u32;
834 let key_id = make_test_key_entry(&mut db, Domain::APP, OWNER_UID as i64, TEST_ALIAS, None)
835 .context("test_insert_and_load_full_keyentry_from_grant_by_key_id")?
836 .0;
837
838 db.grant(
839 &KeyDescriptor {
840 domain: Domain::APP,
841 nspace: 0,
842 alias: Some(TEST_ALIAS.to_string()),
843 blob: None,
844 },
845 OWNER_UID,
846 GRANTEE_UID,
847 key_perm_set![KeyPerm::Use],
848 |_k, _av| Ok(()),
849 )
850 .unwrap();
851
852 debug_dump_grant_table(&mut db)?;
853
854 let id_descriptor =
855 KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, ..Default::default() };
856
857 let (_, key_entry) = db
858 .load_key_entry(
859 &id_descriptor,
860 KeyType::Client,
861 KeyEntryLoadBits::BOTH,
862 GRANTEE_UID,
863 |k, av| {
864 assert_eq!(Domain::APP, k.domain);
865 assert_eq!(OWNER_UID as i64, k.nspace);
866 assert!(av.unwrap().includes(KeyPerm::Use));
867 Ok(())
868 },
869 )
870 .unwrap();
871
872 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
873
874 let (_, key_entry) = db
875 .load_key_entry(
876 &id_descriptor,
877 KeyType::Client,
878 KeyEntryLoadBits::BOTH,
879 SOMEONE_ELSE_UID,
880 |k, av| {
881 assert_eq!(Domain::APP, k.domain);
882 assert_eq!(OWNER_UID as i64, k.nspace);
883 assert!(av.is_none());
884 Ok(())
885 },
886 )
887 .unwrap();
888
889 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
890
891 db.unbind_key(&id_descriptor, KeyType::Client, OWNER_UID, |_, _| Ok(())).unwrap();
892
893 assert_eq!(
894 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
895 db.load_key_entry(
896 &id_descriptor,
897 KeyType::Client,
898 KeyEntryLoadBits::NONE,
899 GRANTEE_UID,
900 |_k, _av| Ok(()),
901 )
902 .unwrap_err()
903 .root_cause()
904 .downcast_ref::<KsError>()
905 );
906
907 Ok(())
908}
909
910// Creates a key migrates it to a different location and then tries to access it by the old
911// and new location.
912#[test]
913fn test_migrate_key_app_to_app() -> Result<()> {
914 let mut db = new_test_db()?;
915 const SOURCE_UID: u32 = 1u32;
916 const DESTINATION_UID: u32 = 2u32;
917 static SOURCE_ALIAS: &str = "SOURCE_ALIAS";
918 static DESTINATION_ALIAS: &str = "DESTINATION_ALIAS";
919 let key_id_guard =
920 make_test_key_entry(&mut db, Domain::APP, SOURCE_UID as i64, SOURCE_ALIAS, None)
921 .context("test_insert_and_load_full_keyentry_from_grant_by_key_id")?;
922
923 let source_descriptor: KeyDescriptor = KeyDescriptor {
924 domain: Domain::APP,
925 nspace: -1,
926 alias: Some(SOURCE_ALIAS.to_string()),
927 blob: None,
928 };
929
930 let destination_descriptor: KeyDescriptor = KeyDescriptor {
931 domain: Domain::APP,
932 nspace: -1,
933 alias: Some(DESTINATION_ALIAS.to_string()),
934 blob: None,
935 };
936
937 let key_id = key_id_guard.id();
938
939 db.migrate_key_namespace(key_id_guard, &destination_descriptor, DESTINATION_UID, |_k| Ok(()))
940 .unwrap();
941
942 let (_, key_entry) = db
943 .load_key_entry(
944 &destination_descriptor,
945 KeyType::Client,
946 KeyEntryLoadBits::BOTH,
947 DESTINATION_UID,
948 |k, av| {
949 assert_eq!(Domain::APP, k.domain);
950 assert_eq!(DESTINATION_UID as i64, k.nspace);
951 assert!(av.is_none());
952 Ok(())
953 },
954 )
955 .unwrap();
956
957 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
958
959 assert_eq!(
960 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
961 db.load_key_entry(
962 &source_descriptor,
963 KeyType::Client,
964 KeyEntryLoadBits::NONE,
965 SOURCE_UID,
966 |_k, _av| Ok(()),
967 )
968 .unwrap_err()
969 .root_cause()
970 .downcast_ref::<KsError>()
971 );
972
973 Ok(())
974}
975
976// Creates a key migrates it to a different location and then tries to access it by the old
977// and new location.
978#[test]
979fn test_migrate_key_app_to_selinux() -> Result<()> {
980 let mut db = new_test_db()?;
981 const SOURCE_UID: u32 = 1u32;
982 const DESTINATION_UID: u32 = 2u32;
983 const DESTINATION_NAMESPACE: i64 = 1000i64;
984 static SOURCE_ALIAS: &str = "SOURCE_ALIAS";
985 static DESTINATION_ALIAS: &str = "DESTINATION_ALIAS";
986 let key_id_guard =
987 make_test_key_entry(&mut db, Domain::APP, SOURCE_UID as i64, SOURCE_ALIAS, None)
988 .context("test_insert_and_load_full_keyentry_from_grant_by_key_id")?;
989
990 let source_descriptor: KeyDescriptor = KeyDescriptor {
991 domain: Domain::APP,
992 nspace: -1,
993 alias: Some(SOURCE_ALIAS.to_string()),
994 blob: None,
995 };
996
997 let destination_descriptor: KeyDescriptor = KeyDescriptor {
998 domain: Domain::SELINUX,
999 nspace: DESTINATION_NAMESPACE,
1000 alias: Some(DESTINATION_ALIAS.to_string()),
1001 blob: None,
1002 };
1003
1004 let key_id = key_id_guard.id();
1005
1006 db.migrate_key_namespace(key_id_guard, &destination_descriptor, DESTINATION_UID, |_k| Ok(()))
1007 .unwrap();
1008
1009 let (_, key_entry) = db
1010 .load_key_entry(
1011 &destination_descriptor,
1012 KeyType::Client,
1013 KeyEntryLoadBits::BOTH,
1014 DESTINATION_UID,
1015 |k, av| {
1016 assert_eq!(Domain::SELINUX, k.domain);
1017 assert_eq!(DESTINATION_NAMESPACE, k.nspace);
1018 assert!(av.is_none());
1019 Ok(())
1020 },
1021 )
1022 .unwrap();
1023
1024 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
1025
1026 assert_eq!(
1027 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
1028 db.load_key_entry(
1029 &source_descriptor,
1030 KeyType::Client,
1031 KeyEntryLoadBits::NONE,
1032 SOURCE_UID,
1033 |_k, _av| Ok(()),
1034 )
1035 .unwrap_err()
1036 .root_cause()
1037 .downcast_ref::<KsError>()
1038 );
1039
1040 Ok(())
1041}
1042
1043// Creates two keys and tries to migrate the first to the location of the second which
1044// is expected to fail.
1045#[test]
1046fn test_migrate_key_destination_occupied() -> Result<()> {
1047 let mut db = new_test_db()?;
1048 const SOURCE_UID: u32 = 1u32;
1049 const DESTINATION_UID: u32 = 2u32;
1050 static SOURCE_ALIAS: &str = "SOURCE_ALIAS";
1051 static DESTINATION_ALIAS: &str = "DESTINATION_ALIAS";
1052 let key_id_guard =
1053 make_test_key_entry(&mut db, Domain::APP, SOURCE_UID as i64, SOURCE_ALIAS, None)
1054 .context("test_insert_and_load_full_keyentry_from_grant_by_key_id")?;
1055 make_test_key_entry(&mut db, Domain::APP, DESTINATION_UID as i64, DESTINATION_ALIAS, None)
1056 .context("test_insert_and_load_full_keyentry_from_grant_by_key_id")?;
1057
1058 let destination_descriptor: KeyDescriptor = KeyDescriptor {
1059 domain: Domain::APP,
1060 nspace: -1,
1061 alias: Some(DESTINATION_ALIAS.to_string()),
1062 blob: None,
1063 };
1064
1065 assert_eq!(
1066 Some(&KsError::Rc(ResponseCode::INVALID_ARGUMENT)),
1067 db.migrate_key_namespace(key_id_guard, &destination_descriptor, DESTINATION_UID, |_k| Ok(
1068 ()
1069 ))
1070 .unwrap_err()
1071 .root_cause()
1072 .downcast_ref::<KsError>()
1073 );
1074
1075 Ok(())
1076}
1077
1078#[test]
1079fn test_upgrade_0_to_1() {
1080 const ALIAS1: &str = "test_upgrade_0_to_1_1";
1081 const ALIAS2: &str = "test_upgrade_0_to_1_2";
1082 const ALIAS3: &str = "test_upgrade_0_to_1_3";
1083 const UID: u32 = 33;
1084 let temp_dir = Arc::new(TempDir::new("test_upgrade_0_to_1").unwrap());
1085 let mut db = KeystoreDB::new(temp_dir.path(), None).unwrap();
1086 let key_id_untouched1 =
1087 make_test_key_entry(&mut db, Domain::APP, UID as i64, ALIAS1, None).unwrap().id();
1088 let key_id_untouched2 =
1089 make_bootlevel_key_entry(&mut db, Domain::APP, UID as i64, ALIAS2, false).unwrap().id();
1090 let key_id_deleted =
1091 make_bootlevel_key_entry(&mut db, Domain::APP, UID as i64, ALIAS3, true).unwrap().id();
1092
1093 let (_, key_entry) = db
1094 .load_key_entry(
1095 &KeyDescriptor {
1096 domain: Domain::APP,
1097 nspace: -1,
1098 alias: Some(ALIAS1.to_string()),
1099 blob: None,
1100 },
1101 KeyType::Client,
1102 KeyEntryLoadBits::BOTH,
1103 UID,
1104 |k, av| {
1105 assert_eq!(Domain::APP, k.domain);
1106 assert_eq!(UID as i64, k.nspace);
1107 assert!(av.is_none());
1108 Ok(())
1109 },
1110 )
1111 .unwrap();
1112 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id_untouched1, None));
1113 let (_, key_entry) = db
1114 .load_key_entry(
1115 &KeyDescriptor {
1116 domain: Domain::APP,
1117 nspace: -1,
1118 alias: Some(ALIAS2.to_string()),
1119 blob: None,
1120 },
1121 KeyType::Client,
1122 KeyEntryLoadBits::BOTH,
1123 UID,
1124 |k, av| {
1125 assert_eq!(Domain::APP, k.domain);
1126 assert_eq!(UID as i64, k.nspace);
1127 assert!(av.is_none());
1128 Ok(())
1129 },
1130 )
1131 .unwrap();
1132 assert_eq!(key_entry, make_bootlevel_test_key_entry_test_vector(key_id_untouched2, false));
1133 let (_, key_entry) = db
1134 .load_key_entry(
1135 &KeyDescriptor {
1136 domain: Domain::APP,
1137 nspace: -1,
1138 alias: Some(ALIAS3.to_string()),
1139 blob: None,
1140 },
1141 KeyType::Client,
1142 KeyEntryLoadBits::BOTH,
1143 UID,
1144 |k, av| {
1145 assert_eq!(Domain::APP, k.domain);
1146 assert_eq!(UID as i64, k.nspace);
1147 assert!(av.is_none());
1148 Ok(())
1149 },
1150 )
1151 .unwrap();
1152 assert_eq!(key_entry, make_bootlevel_test_key_entry_test_vector(key_id_deleted, true));
1153
1154 db.with_transaction(Immediate("TX_test"), |tx| KeystoreDB::from_0_to_1(tx).no_gc()).unwrap();
1155
1156 let (_, key_entry) = db
1157 .load_key_entry(
1158 &KeyDescriptor {
1159 domain: Domain::APP,
1160 nspace: -1,
1161 alias: Some(ALIAS1.to_string()),
1162 blob: None,
1163 },
1164 KeyType::Client,
1165 KeyEntryLoadBits::BOTH,
1166 UID,
1167 |k, av| {
1168 assert_eq!(Domain::APP, k.domain);
1169 assert_eq!(UID as i64, k.nspace);
1170 assert!(av.is_none());
1171 Ok(())
1172 },
1173 )
1174 .unwrap();
1175 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id_untouched1, None));
1176 let (_, key_entry) = db
1177 .load_key_entry(
1178 &KeyDescriptor {
1179 domain: Domain::APP,
1180 nspace: -1,
1181 alias: Some(ALIAS2.to_string()),
1182 blob: None,
1183 },
1184 KeyType::Client,
1185 KeyEntryLoadBits::BOTH,
1186 UID,
1187 |k, av| {
1188 assert_eq!(Domain::APP, k.domain);
1189 assert_eq!(UID as i64, k.nspace);
1190 assert!(av.is_none());
1191 Ok(())
1192 },
1193 )
1194 .unwrap();
1195 assert_eq!(key_entry, make_bootlevel_test_key_entry_test_vector(key_id_untouched2, false));
1196 assert_eq!(
1197 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
1198 db.load_key_entry(
1199 &KeyDescriptor {
1200 domain: Domain::APP,
1201 nspace: -1,
1202 alias: Some(ALIAS3.to_string()),
1203 blob: None,
1204 },
1205 KeyType::Client,
1206 KeyEntryLoadBits::BOTH,
1207 UID,
1208 |k, av| {
1209 assert_eq!(Domain::APP, k.domain);
1210 assert_eq!(UID as i64, k.nspace);
1211 assert!(av.is_none());
1212 Ok(())
1213 },
1214 )
1215 .unwrap_err()
1216 .root_cause()
1217 .downcast_ref::<KsError>()
1218 );
1219}
1220
1221static KEY_LOCK_TEST_ALIAS: &str = "my super duper locked key";
1222
1223#[test]
1224fn test_insert_and_load_full_keyentry_domain_app_concurrently() -> Result<()> {
1225 let handle = {
1226 let temp_dir = Arc::new(TempDir::new("id_lock_test")?);
1227 let temp_dir_clone = temp_dir.clone();
1228 let mut db = KeystoreDB::new(temp_dir.path(), None)?;
1229 let key_id = make_test_key_entry(&mut db, Domain::APP, 33, KEY_LOCK_TEST_ALIAS, None)
1230 .context("test_insert_and_load_full_keyentry_domain_app")?
1231 .0;
1232 let (_key_guard, key_entry) = db
1233 .load_key_entry(
1234 &KeyDescriptor {
1235 domain: Domain::APP,
1236 nspace: 0,
1237 alias: Some(KEY_LOCK_TEST_ALIAS.to_string()),
1238 blob: None,
1239 },
1240 KeyType::Client,
1241 KeyEntryLoadBits::BOTH,
1242 33,
1243 |_k, _av| Ok(()),
1244 )
1245 .unwrap();
1246 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
1247 let state = Arc::new(AtomicU8::new(1));
1248 let state2 = state.clone();
1249
1250 // Spawning a second thread that attempts to acquire the key id lock
1251 // for the same key as the primary thread. The primary thread then
1252 // waits, thereby forcing the secondary thread into the second stage
1253 // of acquiring the lock (see KEY ID LOCK 2/2 above).
1254 // The test succeeds if the secondary thread observes the transition
1255 // of `state` from 1 to 2, despite having a whole second to overtake
1256 // the primary thread.
1257 let handle = thread::spawn(move || {
1258 let temp_dir = temp_dir_clone;
1259 let mut db = KeystoreDB::new(temp_dir.path(), None).unwrap();
1260 assert!(db
1261 .load_key_entry(
1262 &KeyDescriptor {
1263 domain: Domain::APP,
1264 nspace: 0,
1265 alias: Some(KEY_LOCK_TEST_ALIAS.to_string()),
1266 blob: None,
1267 },
1268 KeyType::Client,
1269 KeyEntryLoadBits::BOTH,
1270 33,
1271 |_k, _av| Ok(()),
1272 )
1273 .is_ok());
1274 // We should only see a 2 here because we can only return
1275 // from load_key_entry when the `_key_guard` expires,
1276 // which happens at the end of the scope.
1277 assert_eq!(2, state2.load(Ordering::Relaxed));
1278 });
1279
1280 thread::sleep(std::time::Duration::from_millis(1000));
1281
1282 assert_eq!(Ok(1), state.compare_exchange(1, 2, Ordering::Relaxed, Ordering::Relaxed));
1283
1284 // Return the handle from this scope so we can join with the
1285 // secondary thread after the key id lock has expired.
1286 handle
1287 // This is where the `_key_guard` goes out of scope,
1288 // which is the reason for concurrent load_key_entry on the same key
1289 // to unblock.
1290 };
1291 // Join with the secondary thread and unwrap, to propagate failing asserts to the
1292 // main test thread. We will not see failing asserts in secondary threads otherwise.
1293 handle.join().unwrap();
1294 Ok(())
1295}
1296
1297#[test]
1298fn test_database_busy_error_code() {
1299 let temp_dir =
1300 TempDir::new("test_database_busy_error_code_").expect("Failed to create temp dir.");
1301
1302 let mut db1 = KeystoreDB::new(temp_dir.path(), None).expect("Failed to open database1.");
1303 let mut db2 = KeystoreDB::new(temp_dir.path(), None).expect("Failed to open database2.");
1304
1305 let _tx1 = db1
1306 .conn
1307 .transaction_with_behavior(rusqlite::TransactionBehavior::Immediate)
1308 .expect("Failed to create first transaction.");
1309
1310 let error = db2
1311 .conn
1312 .transaction_with_behavior(rusqlite::TransactionBehavior::Immediate)
1313 .context("Transaction begin failed.")
1314 .expect_err("This should fail.");
1315 let root_cause = error.root_cause();
1316 if let Some(rusqlite::ffi::Error { code: rusqlite::ErrorCode::DatabaseBusy, .. }) =
1317 root_cause.downcast_ref::<rusqlite::ffi::Error>()
1318 {
1319 return;
1320 }
1321 panic!(
1322 "Unexpected error {:?} \n{:?} \n{:?}",
1323 error,
1324 root_cause,
1325 root_cause.downcast_ref::<rusqlite::ffi::Error>()
1326 )
1327}
1328
1329#[cfg(disabled)]
1330#[test]
1331fn test_large_number_of_concurrent_db_manipulations() -> Result<()> {
1332 let temp_dir = Arc::new(
1333 TempDir::new("test_large_number_of_concurrent_db_manipulations_")
1334 .expect("Failed to create temp dir."),
1335 );
1336
1337 let test_begin = Instant::now();
1338
1339 const KEY_COUNT: u32 = 500u32;
1340 let mut db =
1341 new_test_db_with_gc(temp_dir.path(), |_, _| Ok(())).expect("Failed to open database.");
1342 const OPEN_DB_COUNT: u32 = 50u32;
1343
1344 let mut actual_key_count = KEY_COUNT;
1345 // First insert KEY_COUNT keys.
1346 for count in 0..KEY_COUNT {
1347 if Instant::now().duration_since(test_begin) >= Duration::from_secs(15) {
1348 actual_key_count = count;
1349 break;
1350 }
1351 let alias = format!("test_alias_{}", count);
1352 make_test_key_entry(&mut db, Domain::APP, 1, &alias, None)
1353 .expect("Failed to make key entry.");
1354 }
1355
1356 // Insert more keys from a different thread and into a different namespace.
1357 let temp_dir1 = temp_dir.clone();
1358 let handle1 = thread::spawn(move || {
1359 let mut db =
1360 new_test_db_with_gc(temp_dir1.path(), |_, _| Ok(())).expect("Failed to open database.");
1361
1362 for count in 0..actual_key_count {
1363 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
1364 return;
1365 }
1366 let alias = format!("test_alias_{}", count);
1367 make_test_key_entry(&mut db, Domain::APP, 2, &alias, None)
1368 .expect("Failed to make key entry.");
1369 }
1370
1371 // then unbind them again.
1372 for count in 0..actual_key_count {
1373 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
1374 return;
1375 }
1376 let key = KeyDescriptor {
1377 domain: Domain::APP,
1378 nspace: -1,
1379 alias: Some(format!("test_alias_{}", count)),
1380 blob: None,
1381 };
1382 db.unbind_key(&key, KeyType::Client, 2, |_, _| Ok(())).expect("Unbind Failed.");
1383 }
1384 });
1385
1386 // And start unbinding the first set of keys.
1387 let temp_dir2 = temp_dir.clone();
1388 let handle2 = thread::spawn(move || {
1389 let mut db =
1390 new_test_db_with_gc(temp_dir2.path(), |_, _| Ok(())).expect("Failed to open database.");
1391
1392 for count in 0..actual_key_count {
1393 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
1394 return;
1395 }
1396 let key = KeyDescriptor {
1397 domain: Domain::APP,
1398 nspace: -1,
1399 alias: Some(format!("test_alias_{}", count)),
1400 blob: None,
1401 };
1402 db.unbind_key(&key, KeyType::Client, 1, |_, _| Ok(())).expect("Unbind Failed.");
1403 }
1404 });
1405
1406 // While a lot of inserting and deleting is going on we have to open database connections
1407 // successfully and use them.
1408 // This clone is not redundant, because temp_dir needs to be kept alive until db goes
1409 // out of scope.
1410 #[allow(clippy::redundant_clone)]
1411 let temp_dir4 = temp_dir.clone();
1412 let handle4 = thread::spawn(move || {
1413 for count in 0..OPEN_DB_COUNT {
1414 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
1415 return;
1416 }
1417 let mut db = new_test_db_with_gc(temp_dir4.path(), |_, _| Ok(()))
1418 .expect("Failed to open database.");
1419
1420 let alias = format!("test_alias_{}", count);
1421 make_test_key_entry(&mut db, Domain::APP, 3, &alias, None)
1422 .expect("Failed to make key entry.");
1423 let key =
1424 KeyDescriptor { domain: Domain::APP, nspace: -1, alias: Some(alias), blob: None };
1425 db.unbind_key(&key, KeyType::Client, 3, |_, _| Ok(())).expect("Unbind Failed.");
1426 }
1427 });
1428
1429 handle1.join().expect("Thread 1 panicked.");
1430 handle2.join().expect("Thread 2 panicked.");
1431 handle4.join().expect("Thread 4 panicked.");
1432
1433 Ok(())
1434}
1435
1436#[test]
1437fn list() -> Result<()> {
1438 let temp_dir = TempDir::new("list_test")?;
1439 let mut db = KeystoreDB::new(temp_dir.path(), None)?;
1440 static LIST_O_ENTRIES: &[(Domain, i64, &str)] = &[
1441 (Domain::APP, 1, "test1"),
1442 (Domain::APP, 1, "test2"),
1443 (Domain::APP, 1, "test3"),
1444 (Domain::APP, 1, "test4"),
1445 (Domain::APP, 1, "test5"),
1446 (Domain::APP, 1, "test6"),
1447 (Domain::APP, 1, "test7"),
1448 (Domain::APP, 2, "test1"),
1449 (Domain::APP, 2, "test2"),
1450 (Domain::APP, 2, "test3"),
1451 (Domain::APP, 2, "test4"),
1452 (Domain::APP, 2, "test5"),
1453 (Domain::APP, 2, "test6"),
1454 (Domain::APP, 2, "test8"),
1455 (Domain::SELINUX, 100, "test1"),
1456 (Domain::SELINUX, 100, "test2"),
1457 (Domain::SELINUX, 100, "test3"),
1458 (Domain::SELINUX, 100, "test4"),
1459 (Domain::SELINUX, 100, "test5"),
1460 (Domain::SELINUX, 100, "test6"),
1461 (Domain::SELINUX, 100, "test9"),
1462 ];
1463
1464 let list_o_keys: Vec<(i64, i64)> = LIST_O_ENTRIES
1465 .iter()
1466 .map(|(domain, ns, alias)| {
1467 let entry =
1468 make_test_key_entry(&mut db, *domain, *ns, alias, None).unwrap_or_else(|e| {
1469 panic!("Failed to insert {:?} {} {}. Error {:?}", domain, ns, alias, e)
1470 });
1471 (entry.id(), *ns)
1472 })
1473 .collect();
1474
1475 for (domain, namespace) in
1476 &[(Domain::APP, 1i64), (Domain::APP, 2i64), (Domain::SELINUX, 100i64)]
1477 {
1478 let mut list_o_descriptors: Vec<KeyDescriptor> = LIST_O_ENTRIES
1479 .iter()
1480 .filter_map(|(domain, ns, alias)| match ns {
1481 ns if *ns == *namespace => Some(KeyDescriptor {
1482 domain: *domain,
1483 nspace: *ns,
1484 alias: Some(alias.to_string()),
1485 blob: None,
1486 }),
1487 _ => None,
1488 })
1489 .collect();
1490 list_o_descriptors.sort();
1491 let mut list_result = db.list_past_alias(*domain, *namespace, KeyType::Client, None)?;
1492 list_result.sort();
1493 assert_eq!(list_o_descriptors, list_result);
1494
1495 let mut list_o_ids: Vec<i64> = list_o_descriptors
1496 .into_iter()
1497 .map(|d| {
1498 let (_, entry) = db
1499 .load_key_entry(
1500 &d,
1501 KeyType::Client,
1502 KeyEntryLoadBits::NONE,
1503 *namespace as u32,
1504 |_, _| Ok(()),
1505 )
1506 .unwrap();
1507 entry.id()
1508 })
1509 .collect();
1510 list_o_ids.sort_unstable();
1511 let mut loaded_entries: Vec<i64> = list_o_keys
1512 .iter()
1513 .filter_map(|(id, ns)| match ns {
1514 ns if *ns == *namespace => Some(*id),
1515 _ => None,
1516 })
1517 .collect();
1518 loaded_entries.sort_unstable();
1519 assert_eq!(list_o_ids, loaded_entries);
1520 }
1521 assert_eq!(
1522 Vec::<KeyDescriptor>::new(),
1523 db.list_past_alias(Domain::SELINUX, 101, KeyType::Client, None)?
1524 );
1525
1526 Ok(())
1527}
1528
1529// Helpers
1530
1531// Checks that the given result is an error containing the given string.
1532fn check_result_is_error_containing_string<T>(result: Result<T>, target: &str) {
1533 let error_str =
1534 format!("{:#?}", result.err().unwrap_or_else(|| panic!("Expected the error: {}", target)));
1535 assert!(
1536 error_str.contains(target),
1537 "The string \"{}\" should contain \"{}\"",
1538 error_str,
1539 target
1540 );
1541}
1542
1543#[derive(Debug, PartialEq)]
1544struct KeyEntryRow {
1545 id: i64,
1546 key_type: KeyType,
1547 domain: Option<Domain>,
1548 namespace: Option<i64>,
1549 alias: Option<String>,
1550 state: KeyLifeCycle,
1551 km_uuid: Option<Uuid>,
1552}
1553
1554fn get_keyentry(db: &KeystoreDB) -> Result<Vec<KeyEntryRow>> {
1555 db.conn
1556 .prepare("SELECT * FROM persistent.keyentry;")?
1557 .query_map([], |row| {
1558 Ok(KeyEntryRow {
1559 id: row.get(0)?,
1560 key_type: row.get(1)?,
1561 domain: row.get::<_, Option<_>>(2)?.map(Domain),
1562 namespace: row.get(3)?,
1563 alias: row.get(4)?,
1564 state: row.get(5)?,
1565 km_uuid: row.get(6)?,
1566 })
1567 })?
1568 .map(|r| r.context("Could not read keyentry row."))
1569 .collect::<Result<Vec<_>>>()
1570}
1571
1572fn make_test_params(max_usage_count: Option<i32>) -> Vec<KeyParameter> {
1573 make_test_params_with_sids(max_usage_count, &[42])
1574}
1575
1576// Note: The parameters and SecurityLevel associations are nonsensical. This
1577// collection is only used to check if the parameters are preserved as expected by the
1578// database.
1579fn make_test_params_with_sids(
1580 max_usage_count: Option<i32>,
1581 user_secure_ids: &[i64],
1582) -> Vec<KeyParameter> {
1583 let mut params = vec![
1584 KeyParameter::new(KeyParameterValue::Invalid, SecurityLevel::TRUSTED_ENVIRONMENT),
1585 KeyParameter::new(
1586 KeyParameterValue::KeyPurpose(KeyPurpose::SIGN),
1587 SecurityLevel::TRUSTED_ENVIRONMENT,
1588 ),
1589 KeyParameter::new(
1590 KeyParameterValue::KeyPurpose(KeyPurpose::DECRYPT),
1591 SecurityLevel::TRUSTED_ENVIRONMENT,
1592 ),
1593 KeyParameter::new(
1594 KeyParameterValue::Algorithm(Algorithm::RSA),
1595 SecurityLevel::TRUSTED_ENVIRONMENT,
1596 ),
1597 KeyParameter::new(KeyParameterValue::KeySize(1024), SecurityLevel::TRUSTED_ENVIRONMENT),
1598 KeyParameter::new(
1599 KeyParameterValue::BlockMode(BlockMode::ECB),
1600 SecurityLevel::TRUSTED_ENVIRONMENT,
1601 ),
1602 KeyParameter::new(
1603 KeyParameterValue::BlockMode(BlockMode::GCM),
1604 SecurityLevel::TRUSTED_ENVIRONMENT,
1605 ),
1606 KeyParameter::new(KeyParameterValue::Digest(Digest::NONE), SecurityLevel::STRONGBOX),
1607 KeyParameter::new(
1608 KeyParameterValue::Digest(Digest::MD5),
1609 SecurityLevel::TRUSTED_ENVIRONMENT,
1610 ),
1611 KeyParameter::new(
1612 KeyParameterValue::Digest(Digest::SHA_2_224),
1613 SecurityLevel::TRUSTED_ENVIRONMENT,
1614 ),
1615 KeyParameter::new(KeyParameterValue::Digest(Digest::SHA_2_256), SecurityLevel::STRONGBOX),
1616 KeyParameter::new(
1617 KeyParameterValue::PaddingMode(PaddingMode::NONE),
1618 SecurityLevel::TRUSTED_ENVIRONMENT,
1619 ),
1620 KeyParameter::new(
1621 KeyParameterValue::PaddingMode(PaddingMode::RSA_OAEP),
1622 SecurityLevel::TRUSTED_ENVIRONMENT,
1623 ),
1624 KeyParameter::new(
1625 KeyParameterValue::PaddingMode(PaddingMode::RSA_PSS),
1626 SecurityLevel::STRONGBOX,
1627 ),
1628 KeyParameter::new(
1629 KeyParameterValue::PaddingMode(PaddingMode::RSA_PKCS1_1_5_SIGN),
1630 SecurityLevel::TRUSTED_ENVIRONMENT,
1631 ),
1632 KeyParameter::new(KeyParameterValue::CallerNonce, SecurityLevel::TRUSTED_ENVIRONMENT),
1633 KeyParameter::new(KeyParameterValue::MinMacLength(256), SecurityLevel::STRONGBOX),
1634 KeyParameter::new(
1635 KeyParameterValue::EcCurve(EcCurve::P_224),
1636 SecurityLevel::TRUSTED_ENVIRONMENT,
1637 ),
1638 KeyParameter::new(KeyParameterValue::EcCurve(EcCurve::P_256), SecurityLevel::STRONGBOX),
1639 KeyParameter::new(
1640 KeyParameterValue::EcCurve(EcCurve::P_384),
1641 SecurityLevel::TRUSTED_ENVIRONMENT,
1642 ),
1643 KeyParameter::new(
1644 KeyParameterValue::EcCurve(EcCurve::P_521),
1645 SecurityLevel::TRUSTED_ENVIRONMENT,
1646 ),
1647 KeyParameter::new(
1648 KeyParameterValue::RSAPublicExponent(3),
1649 SecurityLevel::TRUSTED_ENVIRONMENT,
1650 ),
1651 KeyParameter::new(KeyParameterValue::IncludeUniqueID, SecurityLevel::TRUSTED_ENVIRONMENT),
1652 KeyParameter::new(KeyParameterValue::BootLoaderOnly, SecurityLevel::STRONGBOX),
1653 KeyParameter::new(KeyParameterValue::RollbackResistance, SecurityLevel::STRONGBOX),
1654 KeyParameter::new(KeyParameterValue::ActiveDateTime(1234567890), SecurityLevel::STRONGBOX),
1655 KeyParameter::new(
1656 KeyParameterValue::OriginationExpireDateTime(1234567890),
1657 SecurityLevel::TRUSTED_ENVIRONMENT,
1658 ),
1659 KeyParameter::new(
1660 KeyParameterValue::UsageExpireDateTime(1234567890),
1661 SecurityLevel::TRUSTED_ENVIRONMENT,
1662 ),
1663 KeyParameter::new(
1664 KeyParameterValue::MinSecondsBetweenOps(1234567890),
1665 SecurityLevel::TRUSTED_ENVIRONMENT,
1666 ),
1667 KeyParameter::new(
1668 KeyParameterValue::MaxUsesPerBoot(1234567890),
1669 SecurityLevel::TRUSTED_ENVIRONMENT,
1670 ),
1671 KeyParameter::new(KeyParameterValue::UserID(1), SecurityLevel::STRONGBOX),
1672 KeyParameter::new(KeyParameterValue::NoAuthRequired, SecurityLevel::TRUSTED_ENVIRONMENT),
1673 KeyParameter::new(
1674 KeyParameterValue::HardwareAuthenticatorType(HardwareAuthenticatorType::PASSWORD),
1675 SecurityLevel::TRUSTED_ENVIRONMENT,
1676 ),
1677 KeyParameter::new(KeyParameterValue::AuthTimeout(1234567890), SecurityLevel::SOFTWARE),
1678 KeyParameter::new(KeyParameterValue::AllowWhileOnBody, SecurityLevel::SOFTWARE),
1679 KeyParameter::new(
1680 KeyParameterValue::TrustedUserPresenceRequired,
1681 SecurityLevel::TRUSTED_ENVIRONMENT,
1682 ),
1683 KeyParameter::new(
1684 KeyParameterValue::TrustedConfirmationRequired,
1685 SecurityLevel::TRUSTED_ENVIRONMENT,
1686 ),
1687 KeyParameter::new(
1688 KeyParameterValue::UnlockedDeviceRequired,
1689 SecurityLevel::TRUSTED_ENVIRONMENT,
1690 ),
1691 KeyParameter::new(
1692 KeyParameterValue::ApplicationID(vec![1u8, 2u8, 3u8, 4u8]),
1693 SecurityLevel::SOFTWARE,
1694 ),
1695 KeyParameter::new(
1696 KeyParameterValue::ApplicationData(vec![4u8, 3u8, 2u8, 1u8]),
1697 SecurityLevel::SOFTWARE,
1698 ),
1699 KeyParameter::new(
1700 KeyParameterValue::CreationDateTime(12345677890),
1701 SecurityLevel::SOFTWARE,
1702 ),
1703 KeyParameter::new(
1704 KeyParameterValue::KeyOrigin(KeyOrigin::GENERATED),
1705 SecurityLevel::TRUSTED_ENVIRONMENT,
1706 ),
1707 KeyParameter::new(
1708 KeyParameterValue::RootOfTrust(vec![3u8, 2u8, 1u8, 4u8]),
1709 SecurityLevel::TRUSTED_ENVIRONMENT,
1710 ),
1711 KeyParameter::new(KeyParameterValue::OSVersion(1), SecurityLevel::TRUSTED_ENVIRONMENT),
1712 KeyParameter::new(KeyParameterValue::OSPatchLevel(2), SecurityLevel::SOFTWARE),
1713 KeyParameter::new(
1714 KeyParameterValue::UniqueID(vec![4u8, 3u8, 1u8, 2u8]),
1715 SecurityLevel::SOFTWARE,
1716 ),
1717 KeyParameter::new(
1718 KeyParameterValue::AttestationChallenge(vec![4u8, 3u8, 1u8, 2u8]),
1719 SecurityLevel::TRUSTED_ENVIRONMENT,
1720 ),
1721 KeyParameter::new(
1722 KeyParameterValue::AttestationApplicationID(vec![4u8, 3u8, 1u8, 2u8]),
1723 SecurityLevel::TRUSTED_ENVIRONMENT,
1724 ),
1725 KeyParameter::new(
1726 KeyParameterValue::AttestationIdBrand(vec![4u8, 3u8, 1u8, 2u8]),
1727 SecurityLevel::TRUSTED_ENVIRONMENT,
1728 ),
1729 KeyParameter::new(
1730 KeyParameterValue::AttestationIdDevice(vec![4u8, 3u8, 1u8, 2u8]),
1731 SecurityLevel::TRUSTED_ENVIRONMENT,
1732 ),
1733 KeyParameter::new(
1734 KeyParameterValue::AttestationIdProduct(vec![4u8, 3u8, 1u8, 2u8]),
1735 SecurityLevel::TRUSTED_ENVIRONMENT,
1736 ),
1737 KeyParameter::new(
1738 KeyParameterValue::AttestationIdSerial(vec![4u8, 3u8, 1u8, 2u8]),
1739 SecurityLevel::TRUSTED_ENVIRONMENT,
1740 ),
1741 KeyParameter::new(
1742 KeyParameterValue::AttestationIdIMEI(vec![4u8, 3u8, 1u8, 2u8]),
1743 SecurityLevel::TRUSTED_ENVIRONMENT,
1744 ),
1745 KeyParameter::new(
1746 KeyParameterValue::AttestationIdSecondIMEI(vec![4u8, 3u8, 1u8, 2u8]),
1747 SecurityLevel::TRUSTED_ENVIRONMENT,
1748 ),
1749 KeyParameter::new(
1750 KeyParameterValue::AttestationIdMEID(vec![4u8, 3u8, 1u8, 2u8]),
1751 SecurityLevel::TRUSTED_ENVIRONMENT,
1752 ),
1753 KeyParameter::new(
1754 KeyParameterValue::AttestationIdManufacturer(vec![4u8, 3u8, 1u8, 2u8]),
1755 SecurityLevel::TRUSTED_ENVIRONMENT,
1756 ),
1757 KeyParameter::new(
1758 KeyParameterValue::AttestationIdModel(vec![4u8, 3u8, 1u8, 2u8]),
1759 SecurityLevel::TRUSTED_ENVIRONMENT,
1760 ),
1761 KeyParameter::new(
1762 KeyParameterValue::VendorPatchLevel(3),
1763 SecurityLevel::TRUSTED_ENVIRONMENT,
1764 ),
1765 KeyParameter::new(KeyParameterValue::BootPatchLevel(4), SecurityLevel::TRUSTED_ENVIRONMENT),
1766 KeyParameter::new(
1767 KeyParameterValue::AssociatedData(vec![4u8, 3u8, 1u8, 2u8]),
1768 SecurityLevel::TRUSTED_ENVIRONMENT,
1769 ),
1770 KeyParameter::new(
1771 KeyParameterValue::Nonce(vec![4u8, 3u8, 1u8, 2u8]),
1772 SecurityLevel::TRUSTED_ENVIRONMENT,
1773 ),
1774 KeyParameter::new(KeyParameterValue::MacLength(256), SecurityLevel::TRUSTED_ENVIRONMENT),
1775 KeyParameter::new(
1776 KeyParameterValue::ResetSinceIdRotation,
1777 SecurityLevel::TRUSTED_ENVIRONMENT,
1778 ),
1779 KeyParameter::new(
1780 KeyParameterValue::ConfirmationToken(vec![5u8, 5u8, 5u8, 5u8]),
1781 SecurityLevel::TRUSTED_ENVIRONMENT,
1782 ),
1783 ];
1784 if let Some(value) = max_usage_count {
1785 params.push(KeyParameter::new(
1786 KeyParameterValue::UsageCountLimit(value),
1787 SecurityLevel::SOFTWARE,
1788 ));
1789 }
1790
1791 for sid in user_secure_ids.iter() {
1792 params.push(KeyParameter::new(
1793 KeyParameterValue::UserSecureID(*sid),
1794 SecurityLevel::STRONGBOX,
1795 ));
1796 }
1797 params
1798}
1799
1800pub fn make_test_key_entry(
1801 db: &mut KeystoreDB,
1802 domain: Domain,
1803 namespace: i64,
1804 alias: &str,
1805 max_usage_count: Option<i32>,
1806) -> Result<KeyIdGuard> {
1807 make_test_key_entry_with_sids(db, domain, namespace, alias, max_usage_count, &[42])
1808}
1809
1810pub fn make_test_key_entry_with_sids(
1811 db: &mut KeystoreDB,
1812 domain: Domain,
1813 namespace: i64,
1814 alias: &str,
1815 max_usage_count: Option<i32>,
1816 sids: &[i64],
1817) -> Result<KeyIdGuard> {
1818 let key_id = create_key_entry(db, &domain, &namespace, KeyType::Client, &KEYSTORE_UUID)?;
1819 let mut blob_metadata = BlobMetaData::new();
1820 blob_metadata.add(BlobMetaEntry::EncryptedBy(EncryptedBy::Password));
1821 blob_metadata.add(BlobMetaEntry::Salt(vec![1, 2, 3]));
1822 blob_metadata.add(BlobMetaEntry::Iv(vec![2, 3, 1]));
1823 blob_metadata.add(BlobMetaEntry::AeadTag(vec![3, 1, 2]));
1824 blob_metadata.add(BlobMetaEntry::KmUuid(KEYSTORE_UUID));
1825
1826 db.set_blob(&key_id, SubComponentType::KEY_BLOB, Some(TEST_KEY_BLOB), Some(&blob_metadata))?;
1827 db.set_blob(&key_id, SubComponentType::CERT, Some(TEST_CERT_BLOB), None)?;
1828 db.set_blob(&key_id, SubComponentType::CERT_CHAIN, Some(TEST_CERT_CHAIN_BLOB), None)?;
1829
1830 let params = make_test_params_with_sids(max_usage_count, sids);
1831 db.insert_keyparameter(&key_id, &params)?;
1832
1833 let mut metadata = KeyMetaData::new();
1834 metadata.add(KeyMetaEntry::CreationDate(DateTime::from_millis_epoch(123456789)));
1835 db.insert_key_metadata(&key_id, &metadata)?;
1836 rebind_alias(db, &key_id, alias, domain, namespace)?;
1837 Ok(key_id)
1838}
1839
1840fn make_test_key_entry_test_vector(key_id: i64, max_usage_count: Option<i32>) -> KeyEntry {
1841 let params = make_test_params(max_usage_count);
1842
1843 let mut blob_metadata = BlobMetaData::new();
1844 blob_metadata.add(BlobMetaEntry::EncryptedBy(EncryptedBy::Password));
1845 blob_metadata.add(BlobMetaEntry::Salt(vec![1, 2, 3]));
1846 blob_metadata.add(BlobMetaEntry::Iv(vec![2, 3, 1]));
1847 blob_metadata.add(BlobMetaEntry::AeadTag(vec![3, 1, 2]));
1848 blob_metadata.add(BlobMetaEntry::KmUuid(KEYSTORE_UUID));
1849
1850 let mut metadata = KeyMetaData::new();
1851 metadata.add(KeyMetaEntry::CreationDate(DateTime::from_millis_epoch(123456789)));
1852
1853 KeyEntry {
1854 id: key_id,
1855 key_blob_info: Some((TEST_KEY_BLOB.to_vec(), blob_metadata)),
1856 cert: Some(TEST_CERT_BLOB.to_vec()),
1857 cert_chain: Some(TEST_CERT_CHAIN_BLOB.to_vec()),
1858 km_uuid: KEYSTORE_UUID,
1859 parameters: params,
1860 metadata,
1861 pure_cert: false,
1862 }
1863}
1864
1865pub fn make_bootlevel_key_entry(
1866 db: &mut KeystoreDB,
1867 domain: Domain,
1868 namespace: i64,
1869 alias: &str,
1870 logical_only: bool,
1871) -> Result<KeyIdGuard> {
1872 let key_id = create_key_entry(db, &domain, &namespace, KeyType::Client, &KEYSTORE_UUID)?;
1873 let mut blob_metadata = BlobMetaData::new();
1874 if !logical_only {
1875 blob_metadata.add(BlobMetaEntry::MaxBootLevel(3));
1876 }
1877 blob_metadata.add(BlobMetaEntry::KmUuid(KEYSTORE_UUID));
1878
1879 db.set_blob(&key_id, SubComponentType::KEY_BLOB, Some(TEST_KEY_BLOB), Some(&blob_metadata))?;
1880 db.set_blob(&key_id, SubComponentType::CERT, Some(TEST_CERT_BLOB), None)?;
1881 db.set_blob(&key_id, SubComponentType::CERT_CHAIN, Some(TEST_CERT_CHAIN_BLOB), None)?;
1882
1883 let mut params = make_test_params(None);
1884 params.push(KeyParameter::new(KeyParameterValue::MaxBootLevel(3), SecurityLevel::KEYSTORE));
1885
1886 db.insert_keyparameter(&key_id, &params)?;
1887
1888 let mut metadata = KeyMetaData::new();
1889 metadata.add(KeyMetaEntry::CreationDate(DateTime::from_millis_epoch(123456789)));
1890 db.insert_key_metadata(&key_id, &metadata)?;
1891 rebind_alias(db, &key_id, alias, domain, namespace)?;
1892 Ok(key_id)
1893}
1894
1895// Creates an app key that is marked as being superencrypted by the given
1896// super key ID and that has the given authentication and unlocked device
1897// parameters. This does not actually superencrypt the key blob.
1898fn make_superencrypted_key_entry(
1899 db: &mut KeystoreDB,
1900 namespace: i64,
1901 alias: &str,
1902 requires_authentication: bool,
1903 requires_unlocked_device: bool,
1904 super_key_id: i64,
1905) -> Result<KeyIdGuard> {
1906 let domain = Domain::APP;
1907 let key_id = create_key_entry(db, &domain, &namespace, KeyType::Client, &KEYSTORE_UUID)?;
1908
1909 let mut blob_metadata = BlobMetaData::new();
1910 blob_metadata.add(BlobMetaEntry::KmUuid(KEYSTORE_UUID));
1911 blob_metadata.add(BlobMetaEntry::EncryptedBy(EncryptedBy::KeyId(super_key_id)));
1912 db.set_blob(&key_id, SubComponentType::KEY_BLOB, Some(TEST_KEY_BLOB), Some(&blob_metadata))?;
1913
1914 let mut params = vec![];
1915 if requires_unlocked_device {
1916 params.push(KeyParameter::new(
1917 KeyParameterValue::UnlockedDeviceRequired,
1918 SecurityLevel::TRUSTED_ENVIRONMENT,
1919 ));
1920 }
1921 if requires_authentication {
1922 params.push(KeyParameter::new(
1923 KeyParameterValue::UserSecureID(42),
1924 SecurityLevel::TRUSTED_ENVIRONMENT,
1925 ));
1926 }
1927 db.insert_keyparameter(&key_id, &params)?;
1928
1929 let mut metadata = KeyMetaData::new();
1930 metadata.add(KeyMetaEntry::CreationDate(DateTime::from_millis_epoch(123456789)));
1931 db.insert_key_metadata(&key_id, &metadata)?;
1932
1933 rebind_alias(db, &key_id, alias, domain, namespace)?;
1934 Ok(key_id)
1935}
1936
1937fn make_bootlevel_test_key_entry_test_vector(key_id: i64, logical_only: bool) -> KeyEntry {
1938 let mut params = make_test_params(None);
1939 params.push(KeyParameter::new(KeyParameterValue::MaxBootLevel(3), SecurityLevel::KEYSTORE));
1940
1941 let mut blob_metadata = BlobMetaData::new();
1942 if !logical_only {
1943 blob_metadata.add(BlobMetaEntry::MaxBootLevel(3));
1944 }
1945 blob_metadata.add(BlobMetaEntry::KmUuid(KEYSTORE_UUID));
1946
1947 let mut metadata = KeyMetaData::new();
1948 metadata.add(KeyMetaEntry::CreationDate(DateTime::from_millis_epoch(123456789)));
1949
1950 KeyEntry {
1951 id: key_id,
1952 key_blob_info: Some((TEST_KEY_BLOB.to_vec(), blob_metadata)),
1953 cert: Some(TEST_CERT_BLOB.to_vec()),
1954 cert_chain: Some(TEST_CERT_CHAIN_BLOB.to_vec()),
1955 km_uuid: KEYSTORE_UUID,
1956 parameters: params,
1957 metadata,
1958 pure_cert: false,
1959 }
1960}
1961
1962fn debug_dump_keyentry_table(db: &mut KeystoreDB) -> Result<()> {
1963 let mut stmt = db.conn.prepare(
1964 "SELECT id, key_type, domain, namespace, alias, state, km_uuid FROM persistent.keyentry;",
1965 )?;
1966 let rows =
1967 stmt.query_map::<(i64, KeyType, i32, i64, String, KeyLifeCycle, Uuid), _, _>([], |row| {
1968 Ok((
1969 row.get(0)?,
1970 row.get(1)?,
1971 row.get(2)?,
1972 row.get(3)?,
1973 row.get(4)?,
1974 row.get(5)?,
1975 row.get(6)?,
1976 ))
1977 })?;
1978
1979 println!("Key entry table rows:");
1980 for r in rows {
1981 let (id, key_type, domain, namespace, alias, state, km_uuid) = r.unwrap();
1982 println!(
1983 " id: {} KeyType: {:?} Domain: {} Namespace: {} Alias: {} State: {:?} KmUuid: {:?}",
1984 id, key_type, domain, namespace, alias, state, km_uuid
1985 );
1986 }
1987 Ok(())
1988}
1989
1990fn debug_dump_grant_table(db: &mut KeystoreDB) -> Result<()> {
1991 let mut stmt =
1992 db.conn.prepare("SELECT id, grantee, keyentryid, access_vector FROM persistent.grant;")?;
1993 let rows = stmt.query_map::<(i64, i64, i64, i64), _, _>([], |row| {
1994 Ok((row.get(0)?, row.get(1)?, row.get(2)?, row.get(3)?))
1995 })?;
1996
1997 println!("Grant table rows:");
1998 for r in rows {
1999 let (id, gt, ki, av) = r.unwrap();
2000 println!(" id: {} grantee: {} key_id: {} access_vector: {}", id, gt, ki, av);
2001 }
2002 Ok(())
2003}
2004
2005// Use a custom random number generator that repeats each number once.
2006// This allows us to test repeated elements.
2007
2008thread_local! {
2009 static RANDOM_COUNTER: RefCell<i64> = const { RefCell::new(0) };
2010}
2011
2012fn reset_random() {
2013 RANDOM_COUNTER.with(|counter| {
2014 *counter.borrow_mut() = 0;
2015 })
2016}
2017
2018pub fn random() -> i64 {
2019 RANDOM_COUNTER.with(|counter| {
2020 let result = *counter.borrow() / 2;
2021 *counter.borrow_mut() += 1;
2022 result
2023 })
2024}
2025
2026#[test]
2027fn test_unbind_keys_for_user() -> Result<()> {
2028 let mut db = new_test_db()?;
2029 db.unbind_keys_for_user(1)?;
2030
2031 make_test_key_entry(&mut db, Domain::APP, 210000, TEST_ALIAS, None)?;
2032 make_test_key_entry(&mut db, Domain::APP, 110000, TEST_ALIAS, None)?;
2033 db.unbind_keys_for_user(2)?;
2034
2035 assert_eq!(1, db.list_past_alias(Domain::APP, 110000, KeyType::Client, None)?.len());
2036 assert_eq!(0, db.list_past_alias(Domain::APP, 210000, KeyType::Client, None)?.len());
2037
2038 db.unbind_keys_for_user(1)?;
2039 assert_eq!(0, db.list_past_alias(Domain::APP, 110000, KeyType::Client, None)?.len());
2040
2041 Ok(())
2042}
2043
2044#[test]
2045fn test_unbind_keys_for_user_removes_superkeys() -> Result<()> {
2046 let mut db = new_test_db()?;
2047 let super_key = keystore2_crypto::generate_aes256_key()?;
2048 let pw: keystore2_crypto::Password = (&b"xyzabc"[..]).into();
2049 let (encrypted_super_key, metadata) = SuperKeyManager::encrypt_with_password(&super_key, &pw)?;
2050
2051 let key_name_enc = SuperKeyType {
2052 alias: "test_super_key_1",
2053 algorithm: SuperEncryptionAlgorithm::Aes256Gcm,
2054 name: "test_super_key_1",
2055 };
2056
2057 let key_name_nonenc = SuperKeyType {
2058 alias: "test_super_key_2",
2059 algorithm: SuperEncryptionAlgorithm::Aes256Gcm,
2060 name: "test_super_key_2",
2061 };
2062
2063 // Install two super keys.
2064 db.store_super_key(1, &key_name_nonenc, &super_key, &BlobMetaData::new(), &KeyMetaData::new())?;
2065 db.store_super_key(1, &key_name_enc, &encrypted_super_key, &metadata, &KeyMetaData::new())?;
2066
2067 // Check that both can be found in the database.
2068 assert!(db.load_super_key(&key_name_enc, 1)?.is_some());
2069 assert!(db.load_super_key(&key_name_nonenc, 1)?.is_some());
2070
2071 // Install the same keys for a different user.
2072 db.store_super_key(2, &key_name_nonenc, &super_key, &BlobMetaData::new(), &KeyMetaData::new())?;
2073 db.store_super_key(2, &key_name_enc, &encrypted_super_key, &metadata, &KeyMetaData::new())?;
2074
2075 // Check that the second pair of keys can be found in the database.
2076 assert!(db.load_super_key(&key_name_enc, 2)?.is_some());
2077 assert!(db.load_super_key(&key_name_nonenc, 2)?.is_some());
2078
2079 // Delete all keys for user 1.
2080 db.unbind_keys_for_user(1)?;
2081
2082 // All of user 1's keys should be gone.
2083 assert!(db.load_super_key(&key_name_enc, 1)?.is_none());
2084 assert!(db.load_super_key(&key_name_nonenc, 1)?.is_none());
2085
2086 // User 2's keys should not have been touched.
2087 assert!(db.load_super_key(&key_name_enc, 2)?.is_some());
2088 assert!(db.load_super_key(&key_name_nonenc, 2)?.is_some());
2089
2090 Ok(())
2091}
2092
Catherine Vlasov4b3e7262025-02-06 10:21:42 +00002093#[test]
2094fn test_unbind_keys_for_user_removes_received_grants() -> Result<()> {
2095 let mut db = new_test_db()?;
2096 const USER_ID_1: u32 = 1;
2097 const USER_ID_2: u32 = 2;
2098 const APPLICATION_ID_1: u32 = 11;
2099 const APPLICATION_ID_2: u32 = 22;
2100 const UID_1_FOR_USER_ID_1: u32 = USER_ID_1 * AID_USER_OFFSET + APPLICATION_ID_1;
2101 const UID_2_FOR_USER_ID_1: u32 = USER_ID_1 * AID_USER_OFFSET + APPLICATION_ID_2;
2102 const UID_1_FOR_USER_ID_2: u32 = USER_ID_2 * AID_USER_OFFSET + APPLICATION_ID_1;
2103
2104 // Pretend two application IDs for user ID 1 were granted access to 1 key each and one
2105 // application ID for user ID 2 was granted access to 1 key.
2106 db.conn.execute(
2107 &format!(
2108 "INSERT INTO persistent.grant (id, grantee, keyentryid, access_vector)
2109 VALUES (1, {UID_1_FOR_USER_ID_1}, 111, 222),
2110 (2, {UID_1_FOR_USER_ID_2}, 333, 444),
2111 (3, {UID_2_FOR_USER_ID_1}, 555, 666);"
2112 ),
2113 [],
2114 )?;
2115 db.unbind_keys_for_user(USER_ID_1)?;
2116
2117 let mut stmt = db.conn.prepare("SELECT id, grantee FROM persistent.grant")?;
2118 let mut rows = stmt.query_map::<(i64, u32), _, _>([], |row| Ok((row.get(0)?, row.get(1)?)))?;
2119
2120 // The rows for the user ID 1 grantees (UID_1_FOR_USER_ID_1 and UID_2_FOR_USER_ID_1) should be
2121 // deleted and the row for the user ID 2 grantee (UID_1_FOR_USER_ID_2) should be untouched.
2122 let r = rows.next().unwrap().unwrap();
2123 assert_eq!(r, (2, UID_1_FOR_USER_ID_2));
2124 assert!(rows.next().is_none());
2125
2126 Ok(())
2127}
2128
Catherine Vlasovff4ed322025-03-06 16:27:56 +00002129#[test]
2130fn test_unbind_keys_for_namespace_removes_received_grants() -> Result<()> {
2131 const USER_ID_1: u32 = 1;
2132 const APPLICATION_ID_1: u32 = 11;
2133 const APPLICATION_ID_2: u32 = 22;
2134 const UID_1_FOR_USER_ID_1: u32 = USER_ID_1 * AID_USER_OFFSET + APPLICATION_ID_1;
2135 const UID_2_FOR_USER_ID_1: u32 = USER_ID_1 * AID_USER_OFFSET + APPLICATION_ID_2;
2136
2137 // Check that grants are removed for Domain::APP.
2138 {
2139 let mut db = new_test_db()?;
2140
2141 // Pretend two application IDs for user ID 1 were granted access to 1 key each.
2142 db.conn.execute(
2143 &format!(
2144 "INSERT INTO persistent.grant (id, grantee, keyentryid, access_vector)
2145 VALUES (1, {UID_1_FOR_USER_ID_1}, 111, 222), (2, {UID_2_FOR_USER_ID_1}, 333, 444);"
2146 ),
2147 [],
2148 )?;
2149 // Keystore uses the UID as the namespace for Domain::APP keys.
2150 db.unbind_keys_for_namespace(Domain::APP, UID_1_FOR_USER_ID_1.into())?;
2151
2152 let mut stmt = db.conn.prepare("SELECT id, grantee FROM persistent.grant")?;
2153 let mut rows =
2154 stmt.query_map::<(i64, u32), _, _>([], |row| Ok((row.get(0)?, row.get(1)?)))?;
2155
2156 // The row for the grant to the namespace that was cleared (UID_1_FOR_USER_ID_1) should be
2157 // deleted. The other row should be untouched.
2158 let r = rows.next().unwrap().unwrap();
2159 assert_eq!(r, (2, UID_2_FOR_USER_ID_1));
2160 assert!(rows.next().is_none());
2161 }
2162
2163 // Check that grants aren't removed for Domain::SELINUX.
2164 {
2165 let mut db = new_test_db()?;
2166
2167 // Pretend two application IDs for user ID 1 were granted access to 1 key each.
2168 db.conn.execute(
2169 &format!(
2170 "INSERT INTO persistent.grant (id, grantee, keyentryid, access_vector)
2171 VALUES (1, {UID_1_FOR_USER_ID_1}, 111, 222), (2, {UID_2_FOR_USER_ID_1}, 333, 444);"
2172 ),
2173 [],
2174 )?;
2175 // Keystore uses the UID as the namespace for Domain::APP keys. Here we're passing in
2176 // Domain::SELINUX, but still pass the UID as the "namespace" argument to make sure the
2177 // code's logic is correct.
2178 db.unbind_keys_for_namespace(Domain::SELINUX, UID_1_FOR_USER_ID_1.into())?;
2179
2180 let mut stmt = db.conn.prepare("SELECT id, grantee FROM persistent.grant")?;
2181 let mut rows =
2182 stmt.query_map::<(i64, u32), _, _>([], |row| Ok((row.get(0)?, row.get(1)?)))?;
2183
2184 // Both rows should still be present.
2185 let r = rows.next().unwrap().unwrap();
2186 assert_eq!(r, (1, UID_1_FOR_USER_ID_1));
2187 let r = rows.next().unwrap().unwrap();
2188 assert_eq!(r, (2, UID_2_FOR_USER_ID_1));
2189 assert!(rows.next().is_none());
2190 }
2191
2192 Ok(())
2193}
2194
David Drysdale2566fb32024-07-09 14:46:37 +01002195fn app_key_exists(db: &mut KeystoreDB, nspace: i64, alias: &str) -> Result<bool> {
2196 db.key_exists(Domain::APP, nspace, alias, KeyType::Client)
2197}
2198
2199// Tests the unbind_auth_bound_keys_for_user() function.
2200#[test]
2201fn test_unbind_auth_bound_keys_for_user() -> Result<()> {
2202 let mut db = new_test_db()?;
2203 let user_id = 1;
2204 let nspace: i64 = (user_id * AID_USER_OFFSET).into();
2205 let other_user_id = 2;
2206 let other_user_nspace: i64 = (other_user_id * AID_USER_OFFSET).into();
2207 let super_key_type = &USER_AFTER_FIRST_UNLOCK_SUPER_KEY;
2208
2209 // Create a superencryption key.
2210 let super_key = keystore2_crypto::generate_aes256_key()?;
2211 let pw: keystore2_crypto::Password = (&b"xyzabc"[..]).into();
2212 let (encrypted_super_key, blob_metadata) =
2213 SuperKeyManager::encrypt_with_password(&super_key, &pw)?;
2214 db.store_super_key(
2215 user_id,
2216 super_key_type,
2217 &encrypted_super_key,
2218 &blob_metadata,
2219 &KeyMetaData::new(),
2220 )?;
2221 let super_key_id = db.load_super_key(super_key_type, user_id)?.unwrap().0 .0;
2222
2223 // Store 4 superencrypted app keys, one for each possible combination of
2224 // (authentication required, unlocked device required).
2225 make_superencrypted_key_entry(&mut db, nspace, "noauth_noud", false, false, super_key_id)?;
2226 make_superencrypted_key_entry(&mut db, nspace, "noauth_ud", false, true, super_key_id)?;
2227 make_superencrypted_key_entry(&mut db, nspace, "auth_noud", true, false, super_key_id)?;
2228 make_superencrypted_key_entry(&mut db, nspace, "auth_ud", true, true, super_key_id)?;
2229 assert!(app_key_exists(&mut db, nspace, "noauth_noud")?);
2230 assert!(app_key_exists(&mut db, nspace, "noauth_ud")?);
2231 assert!(app_key_exists(&mut db, nspace, "auth_noud")?);
2232 assert!(app_key_exists(&mut db, nspace, "auth_ud")?);
2233
2234 // Also store a key for a different user that requires authentication.
2235 make_superencrypted_key_entry(&mut db, other_user_nspace, "auth_ud", true, true, super_key_id)?;
2236
2237 db.unbind_auth_bound_keys_for_user(user_id)?;
2238
2239 // Verify that only the user's app keys that require authentication were
2240 // deleted. Keys that require an unlocked device but not authentication
2241 // should *not* have been deleted, nor should the super key have been
2242 // deleted, nor should other users' keys have been deleted.
2243 assert!(db.load_super_key(super_key_type, user_id)?.is_some());
2244 assert!(app_key_exists(&mut db, nspace, "noauth_noud")?);
2245 assert!(app_key_exists(&mut db, nspace, "noauth_ud")?);
2246 assert!(!app_key_exists(&mut db, nspace, "auth_noud")?);
2247 assert!(!app_key_exists(&mut db, nspace, "auth_ud")?);
2248 assert!(app_key_exists(&mut db, other_user_nspace, "auth_ud")?);
2249
2250 Ok(())
2251}
2252
2253#[test]
2254fn test_store_super_key() -> Result<()> {
2255 let mut db = new_test_db()?;
2256 let pw: keystore2_crypto::Password = (&b"xyzabc"[..]).into();
2257 let super_key = keystore2_crypto::generate_aes256_key()?;
2258 let secret_bytes = b"keystore2 is great.";
2259 let (encrypted_secret, iv, tag) = keystore2_crypto::aes_gcm_encrypt(secret_bytes, &super_key)?;
2260
2261 let (encrypted_super_key, metadata) = SuperKeyManager::encrypt_with_password(&super_key, &pw)?;
2262 db.store_super_key(
2263 1,
2264 &USER_AFTER_FIRST_UNLOCK_SUPER_KEY,
2265 &encrypted_super_key,
2266 &metadata,
2267 &KeyMetaData::new(),
2268 )?;
2269
2270 // Check if super key exists.
2271 assert!(db.key_exists(
2272 Domain::APP,
2273 1,
2274 USER_AFTER_FIRST_UNLOCK_SUPER_KEY.alias,
2275 KeyType::Super
2276 )?);
2277
2278 let (_, key_entry) = db.load_super_key(&USER_AFTER_FIRST_UNLOCK_SUPER_KEY, 1)?.unwrap();
2279 let loaded_super_key = SuperKeyManager::extract_super_key_from_key_entry(
2280 USER_AFTER_FIRST_UNLOCK_SUPER_KEY.algorithm,
2281 key_entry,
2282 &pw,
2283 None,
2284 )?;
2285
2286 let decrypted_secret_bytes = loaded_super_key.decrypt(&encrypted_secret, &iv, &tag)?;
2287 assert_eq!(secret_bytes, &*decrypted_secret_bytes);
2288
2289 Ok(())
2290}
2291
2292fn get_valid_statsd_storage_types() -> Vec<MetricsStorage> {
2293 vec![
2294 MetricsStorage::KEY_ENTRY,
2295 MetricsStorage::KEY_ENTRY_ID_INDEX,
2296 MetricsStorage::KEY_ENTRY_DOMAIN_NAMESPACE_INDEX,
2297 MetricsStorage::BLOB_ENTRY,
2298 MetricsStorage::BLOB_ENTRY_KEY_ENTRY_ID_INDEX,
2299 MetricsStorage::KEY_PARAMETER,
2300 MetricsStorage::KEY_PARAMETER_KEY_ENTRY_ID_INDEX,
2301 MetricsStorage::KEY_METADATA,
2302 MetricsStorage::KEY_METADATA_KEY_ENTRY_ID_INDEX,
2303 MetricsStorage::GRANT,
2304 MetricsStorage::AUTH_TOKEN,
2305 MetricsStorage::BLOB_METADATA,
2306 MetricsStorage::BLOB_METADATA_BLOB_ENTRY_ID_INDEX,
2307 ]
2308}
2309
2310/// Perform a simple check to ensure that we can query all the storage types
2311/// that are supported by the DB. Check for reasonable values.
2312#[test]
2313fn test_query_all_valid_table_sizes() -> Result<()> {
2314 const PAGE_SIZE: i32 = 4096;
2315
2316 let mut db = new_test_db()?;
2317
2318 for t in get_valid_statsd_storage_types() {
2319 let stat = db.get_storage_stat(t)?;
2320 // AuthToken can be less than a page since it's in a btree, not sqlite
2321 // TODO(b/187474736) stop using if-let here
2322 if let MetricsStorage::AUTH_TOKEN = t {
2323 } else {
2324 assert!(stat.size >= PAGE_SIZE);
2325 }
2326 assert!(stat.size >= stat.unused_size);
2327 }
2328
2329 Ok(())
2330}
2331
2332fn get_storage_stats_map(db: &mut KeystoreDB) -> BTreeMap<i32, StorageStats> {
2333 get_valid_statsd_storage_types()
2334 .into_iter()
2335 .map(|t| (t.0, db.get_storage_stat(t).unwrap()))
2336 .collect()
2337}
2338
2339fn assert_storage_increased(
2340 db: &mut KeystoreDB,
2341 increased_storage_types: Vec<MetricsStorage>,
2342 baseline: &mut BTreeMap<i32, StorageStats>,
2343) {
2344 for storage in increased_storage_types {
2345 // Verify the expected storage increased.
2346 let new = db.get_storage_stat(storage).unwrap();
2347 let old = &baseline[&storage.0];
2348 assert!(new.size >= old.size, "{}: {} >= {}", storage.0, new.size, old.size);
2349 assert!(
2350 new.unused_size <= old.unused_size,
2351 "{}: {} <= {}",
2352 storage.0,
2353 new.unused_size,
2354 old.unused_size
2355 );
2356
2357 // Update the baseline with the new value so that it succeeds in the
2358 // later comparison.
2359 baseline.insert(storage.0, new);
2360 }
2361
2362 // Get an updated map of the storage and verify there were no unexpected changes.
2363 let updated_stats = get_storage_stats_map(db);
2364 assert_eq!(updated_stats.len(), baseline.len());
2365
2366 for &k in baseline.keys() {
2367 let stringify = |map: &BTreeMap<i32, StorageStats>| -> String {
2368 let mut s = String::new();
2369 for &k in map.keys() {
2370 writeln!(&mut s, " {}: {}, {}", &k, map[&k].size, map[&k].unused_size)
2371 .expect("string concat failed");
2372 }
2373 s
2374 };
2375
2376 assert!(
2377 updated_stats[&k].size == baseline[&k].size
2378 && updated_stats[&k].unused_size == baseline[&k].unused_size,
2379 "updated_stats:\n{}\nbaseline:\n{}",
2380 stringify(&updated_stats),
2381 stringify(baseline)
2382 );
2383 }
2384}
2385
2386#[test]
2387fn test_verify_key_table_size_reporting() -> Result<()> {
2388 let mut db = new_test_db()?;
2389 let mut working_stats = get_storage_stats_map(&mut db);
2390
2391 let key_id = create_key_entry(&mut db, &Domain::APP, &42, KeyType::Client, &KEYSTORE_UUID)?;
2392 assert_storage_increased(
2393 &mut db,
2394 vec![
2395 MetricsStorage::KEY_ENTRY,
2396 MetricsStorage::KEY_ENTRY_ID_INDEX,
2397 MetricsStorage::KEY_ENTRY_DOMAIN_NAMESPACE_INDEX,
2398 ],
2399 &mut working_stats,
2400 );
2401
2402 let mut blob_metadata = BlobMetaData::new();
2403 blob_metadata.add(BlobMetaEntry::EncryptedBy(EncryptedBy::Password));
2404 db.set_blob(&key_id, SubComponentType::KEY_BLOB, Some(TEST_KEY_BLOB), None)?;
2405 assert_storage_increased(
2406 &mut db,
2407 vec![
2408 MetricsStorage::BLOB_ENTRY,
2409 MetricsStorage::BLOB_ENTRY_KEY_ENTRY_ID_INDEX,
2410 MetricsStorage::BLOB_METADATA,
2411 MetricsStorage::BLOB_METADATA_BLOB_ENTRY_ID_INDEX,
2412 ],
2413 &mut working_stats,
2414 );
2415
2416 let params = make_test_params(None);
2417 db.insert_keyparameter(&key_id, &params)?;
2418 assert_storage_increased(
2419 &mut db,
2420 vec![MetricsStorage::KEY_PARAMETER, MetricsStorage::KEY_PARAMETER_KEY_ENTRY_ID_INDEX],
2421 &mut working_stats,
2422 );
2423
2424 let mut metadata = KeyMetaData::new();
2425 metadata.add(KeyMetaEntry::CreationDate(DateTime::from_millis_epoch(123456789)));
2426 db.insert_key_metadata(&key_id, &metadata)?;
2427 assert_storage_increased(
2428 &mut db,
2429 vec![MetricsStorage::KEY_METADATA, MetricsStorage::KEY_METADATA_KEY_ENTRY_ID_INDEX],
2430 &mut working_stats,
2431 );
2432
2433 let mut sum = 0;
2434 for stat in working_stats.values() {
2435 sum += stat.size;
2436 }
2437 let total = db.get_storage_stat(MetricsStorage::DATABASE)?.size;
2438 assert!(sum <= total, "Expected sum <= total. sum: {}, total: {}", sum, total);
2439
2440 Ok(())
2441}
2442
2443#[test]
2444fn test_verify_auth_table_size_reporting() -> Result<()> {
2445 let mut db = new_test_db()?;
2446 let mut working_stats = get_storage_stats_map(&mut db);
2447 db.insert_auth_token(&HardwareAuthToken {
2448 challenge: 123,
2449 userId: 456,
2450 authenticatorId: 789,
2451 authenticatorType: kmhw_authenticator_type::ANY,
2452 timestamp: Timestamp { milliSeconds: 10 },
2453 mac: b"mac".to_vec(),
2454 });
2455 assert_storage_increased(&mut db, vec![MetricsStorage::AUTH_TOKEN], &mut working_stats);
2456 Ok(())
2457}
2458
2459#[test]
2460fn test_verify_grant_table_size_reporting() -> Result<()> {
2461 const OWNER: i64 = 1;
2462 let mut db = new_test_db()?;
2463 make_test_key_entry(&mut db, Domain::APP, OWNER, TEST_ALIAS, None)?;
2464
2465 let mut working_stats = get_storage_stats_map(&mut db);
2466 db.grant(
2467 &KeyDescriptor {
2468 domain: Domain::APP,
2469 nspace: 0,
2470 alias: Some(TEST_ALIAS.to_string()),
2471 blob: None,
2472 },
2473 OWNER as u32,
2474 123,
2475 key_perm_set![KeyPerm::Use],
2476 |_, _| Ok(()),
2477 )?;
2478
2479 assert_storage_increased(&mut db, vec![MetricsStorage::GRANT], &mut working_stats);
2480
2481 Ok(())
2482}
2483
2484#[test]
2485fn find_auth_token_entry_returns_latest() -> Result<()> {
2486 let mut db = new_test_db()?;
2487 db.insert_auth_token(&HardwareAuthToken {
2488 challenge: 123,
2489 userId: 456,
2490 authenticatorId: 789,
2491 authenticatorType: kmhw_authenticator_type::ANY,
2492 timestamp: Timestamp { milliSeconds: 10 },
2493 mac: b"mac0".to_vec(),
2494 });
2495 std::thread::sleep(std::time::Duration::from_millis(1));
2496 db.insert_auth_token(&HardwareAuthToken {
2497 challenge: 123,
2498 userId: 457,
2499 authenticatorId: 789,
2500 authenticatorType: kmhw_authenticator_type::ANY,
2501 timestamp: Timestamp { milliSeconds: 12 },
2502 mac: b"mac1".to_vec(),
2503 });
2504 std::thread::sleep(std::time::Duration::from_millis(1));
2505 db.insert_auth_token(&HardwareAuthToken {
2506 challenge: 123,
2507 userId: 458,
2508 authenticatorId: 789,
2509 authenticatorType: kmhw_authenticator_type::ANY,
2510 timestamp: Timestamp { milliSeconds: 3 },
2511 mac: b"mac2".to_vec(),
2512 });
2513 // All three entries are in the database
2514 assert_eq!(db.perboot.auth_tokens_len(), 3);
2515 // It selected the most recent timestamp
2516 assert_eq!(db.find_auth_token_entry(|_| true).unwrap().auth_token.mac, b"mac2".to_vec());
2517 Ok(())
2518}
2519
David Drysdalee85c1b72024-09-10 10:37:12 +01002520fn blob_count(db: &mut KeystoreDB, sc_type: SubComponentType) -> usize {
2521 db.with_transaction(TransactionBehavior::Deferred, |tx| {
2522 tx.query_row(
2523 "SELECT COUNT(*) FROM persistent.blobentry
2524 WHERE subcomponent_type = ?;",
2525 params![sc_type],
2526 |row| row.get(0),
2527 )
2528 .context(ks_err!("Failed to count number of {sc_type:?} blobs"))
2529 .no_gc()
2530 })
2531 .unwrap()
2532}
2533
David Drysdale8da288c2024-07-29 15:57:01 +01002534fn blob_count_in_state(db: &mut KeystoreDB, sc_type: SubComponentType, state: BlobState) -> usize {
2535 db.with_transaction(TransactionBehavior::Deferred, |tx| {
2536 tx.query_row(
2537 "SELECT COUNT(*) FROM persistent.blobentry
2538 WHERE subcomponent_type = ? AND state = ?;",
2539 params![sc_type, state],
2540 |row| row.get(0),
2541 )
2542 .context(ks_err!("Failed to count number of {sc_type:?} blobs"))
2543 .no_gc()
2544 })
2545 .unwrap()
2546}
2547
David Drysdalee85c1b72024-09-10 10:37:12 +01002548#[test]
2549fn test_blobentry_gc() -> Result<()> {
2550 let mut db = new_test_db()?;
2551 let _key_id1 = make_test_key_entry(&mut db, Domain::APP, 1, "key1", None)?.0;
2552 let key_guard2 = make_test_key_entry(&mut db, Domain::APP, 2, "key2", None)?;
2553 let key_guard3 = make_test_key_entry(&mut db, Domain::APP, 3, "key3", None)?;
2554 let key_id4 = make_test_key_entry(&mut db, Domain::APP, 4, "key4", None)?.0;
2555 let key_id5 = make_test_key_entry(&mut db, Domain::APP, 5, "key5", None)?.0;
2556
2557 assert_eq!(5, blob_count(&mut db, SubComponentType::KEY_BLOB));
David Drysdale8da288c2024-07-29 15:57:01 +01002558 assert_eq!(5, blob_count_in_state(&mut db, SubComponentType::KEY_BLOB, BlobState::Current));
2559 assert_eq!(0, blob_count_in_state(&mut db, SubComponentType::KEY_BLOB, BlobState::Superseded));
2560 assert_eq!(0, blob_count_in_state(&mut db, SubComponentType::KEY_BLOB, BlobState::Orphaned));
David Drysdalee85c1b72024-09-10 10:37:12 +01002561 assert_eq!(5, blob_count(&mut db, SubComponentType::CERT));
2562 assert_eq!(5, blob_count(&mut db, SubComponentType::CERT_CHAIN));
2563
2564 // Replace the keyblobs for keys 2 and 3. The previous blobs will still exist.
2565 db.set_blob(&key_guard2, SubComponentType::KEY_BLOB, Some(&[1, 2, 3]), None)?;
2566 db.set_blob(&key_guard3, SubComponentType::KEY_BLOB, Some(&[1, 2, 3]), None)?;
2567
2568 assert_eq!(7, blob_count(&mut db, SubComponentType::KEY_BLOB));
David Drysdale8da288c2024-07-29 15:57:01 +01002569 assert_eq!(5, blob_count_in_state(&mut db, SubComponentType::KEY_BLOB, BlobState::Current));
2570 assert_eq!(2, blob_count_in_state(&mut db, SubComponentType::KEY_BLOB, BlobState::Superseded));
2571 assert_eq!(0, blob_count_in_state(&mut db, SubComponentType::KEY_BLOB, BlobState::Orphaned));
David Drysdalee85c1b72024-09-10 10:37:12 +01002572 assert_eq!(5, blob_count(&mut db, SubComponentType::CERT));
2573 assert_eq!(5, blob_count(&mut db, SubComponentType::CERT_CHAIN));
2574
2575 // Delete keys 4 and 5. The keyblobs aren't removed yet.
2576 db.with_transaction(Immediate("TX_delete_test_keys"), |tx| {
2577 KeystoreDB::mark_unreferenced(tx, key_id4)?;
2578 KeystoreDB::mark_unreferenced(tx, key_id5)?;
2579 Ok(()).no_gc()
2580 })
2581 .unwrap();
2582
2583 assert_eq!(7, blob_count(&mut db, SubComponentType::KEY_BLOB));
David Drysdale8da288c2024-07-29 15:57:01 +01002584 assert_eq!(3, blob_count_in_state(&mut db, SubComponentType::KEY_BLOB, BlobState::Current));
2585 assert_eq!(2, blob_count_in_state(&mut db, SubComponentType::KEY_BLOB, BlobState::Superseded));
2586 assert_eq!(2, blob_count_in_state(&mut db, SubComponentType::KEY_BLOB, BlobState::Orphaned));
David Drysdalee85c1b72024-09-10 10:37:12 +01002587 assert_eq!(5, blob_count(&mut db, SubComponentType::CERT));
2588 assert_eq!(5, blob_count(&mut db, SubComponentType::CERT_CHAIN));
2589
2590 // First garbage collection should return all 4 blobentry rows that are no longer current for
2591 // their key.
2592 let superseded = db.handle_next_superseded_blobs(&[], 20).unwrap();
2593 let superseded_ids: Vec<i64> = superseded.iter().map(|v| v.blob_id).collect();
2594 assert_eq!(4, superseded.len());
2595 assert_eq!(7, blob_count(&mut db, SubComponentType::KEY_BLOB));
David Drysdale8da288c2024-07-29 15:57:01 +01002596 assert_eq!(3, blob_count_in_state(&mut db, SubComponentType::KEY_BLOB, BlobState::Current));
2597 assert_eq!(2, blob_count_in_state(&mut db, SubComponentType::KEY_BLOB, BlobState::Superseded));
2598 assert_eq!(2, blob_count_in_state(&mut db, SubComponentType::KEY_BLOB, BlobState::Orphaned));
David Drysdalee85c1b72024-09-10 10:37:12 +01002599 assert_eq!(5, blob_count(&mut db, SubComponentType::CERT));
2600 assert_eq!(5, blob_count(&mut db, SubComponentType::CERT_CHAIN));
2601
2602 // Feed the superseded blob IDs back in, to trigger removal of the old KEY_BLOB entries. As no
2603 // new superseded KEY_BLOBs are found, the unreferenced CERT/CERT_CHAIN blobs are removed.
2604 let superseded = db.handle_next_superseded_blobs(&superseded_ids, 20).unwrap();
2605 let superseded_ids: Vec<i64> = superseded.iter().map(|v| v.blob_id).collect();
2606 assert_eq!(0, superseded.len());
2607 assert_eq!(3, blob_count(&mut db, SubComponentType::KEY_BLOB));
David Drysdale8da288c2024-07-29 15:57:01 +01002608 assert_eq!(3, blob_count_in_state(&mut db, SubComponentType::KEY_BLOB, BlobState::Current));
2609 assert_eq!(0, blob_count_in_state(&mut db, SubComponentType::KEY_BLOB, BlobState::Superseded));
2610 assert_eq!(0, blob_count_in_state(&mut db, SubComponentType::KEY_BLOB, BlobState::Orphaned));
David Drysdalee85c1b72024-09-10 10:37:12 +01002611 assert_eq!(3, blob_count(&mut db, SubComponentType::CERT));
2612 assert_eq!(3, blob_count(&mut db, SubComponentType::CERT_CHAIN));
2613
2614 // Nothing left to garbage collect.
2615 let superseded = db.handle_next_superseded_blobs(&superseded_ids, 20).unwrap();
2616 assert_eq!(0, superseded.len());
2617 assert_eq!(3, blob_count(&mut db, SubComponentType::KEY_BLOB));
David Drysdale8da288c2024-07-29 15:57:01 +01002618 assert_eq!(3, blob_count_in_state(&mut db, SubComponentType::KEY_BLOB, BlobState::Current));
2619 assert_eq!(0, blob_count_in_state(&mut db, SubComponentType::KEY_BLOB, BlobState::Superseded));
2620 assert_eq!(0, blob_count_in_state(&mut db, SubComponentType::KEY_BLOB, BlobState::Orphaned));
David Drysdalee85c1b72024-09-10 10:37:12 +01002621 assert_eq!(3, blob_count(&mut db, SubComponentType::CERT));
2622 assert_eq!(3, blob_count(&mut db, SubComponentType::CERT_CHAIN));
2623
2624 Ok(())
2625}
2626
David Drysdale2566fb32024-07-09 14:46:37 +01002627#[test]
David Drysdale8da288c2024-07-29 15:57:01 +01002628fn test_upgrade_1_to_2() -> Result<()> {
2629 let mut db = new_test_db()?;
2630 let _key_id1 = make_test_key_entry(&mut db, Domain::APP, 1, "key1", None)?.0;
2631 let key_guard2 = make_test_key_entry(&mut db, Domain::APP, 2, "key2", None)?;
2632 let key_guard3 = make_test_key_entry(&mut db, Domain::APP, 3, "key3", None)?;
2633 let key_id4 = make_test_key_entry(&mut db, Domain::APP, 4, "key4", None)?.0;
2634 let key_id5 = make_test_key_entry(&mut db, Domain::APP, 5, "key5", None)?.0;
2635
2636 // Replace the keyblobs for keys 2 and 3. The previous blobs will still exist.
2637 db.set_blob(&key_guard2, SubComponentType::KEY_BLOB, Some(&[1, 2, 3]), None)?;
2638 db.set_blob(&key_guard3, SubComponentType::KEY_BLOB, Some(&[1, 2, 3]), None)?;
2639
2640 // Delete keys 4 and 5. The keyblobs aren't removed yet.
2641 db.with_transaction(Immediate("TX_delete_test_keys"), |tx| {
2642 KeystoreDB::mark_unreferenced(tx, key_id4)?;
2643 KeystoreDB::mark_unreferenced(tx, key_id5)?;
2644 Ok(()).no_gc()
2645 })
2646 .unwrap();
2647 assert_eq!(7, blob_count(&mut db, SubComponentType::KEY_BLOB));
2648 assert_eq!(5, blob_count(&mut db, SubComponentType::CERT));
2649 assert_eq!(5, blob_count(&mut db, SubComponentType::CERT_CHAIN));
2650
2651 // Manually downgrade the database to the v1 schema.
2652 db.with_transaction(Immediate("TX_downgrade_2_to_1"), |tx| {
2653 tx.execute("DROP INDEX persistent.keyentry_state_index;", params!())?;
2654 tx.execute("DROP INDEX persistent.blobentry_state_index;", params!())?;
2655 tx.execute("ALTER TABLE persistent.blobentry DROP COLUMN state;", params!())?;
2656 Ok(()).no_gc()
2657 })?;
2658
2659 // Run the upgrade process.
2660 let version = db.with_transaction(Immediate("TX_upgrade_1_to_2"), |tx| {
2661 KeystoreDB::from_1_to_2(tx).no_gc()
2662 })?;
2663 assert_eq!(version, 2);
2664
2665 // Check blobs have acquired the right `state` values.
2666 assert_eq!(7, blob_count(&mut db, SubComponentType::KEY_BLOB));
2667 assert_eq!(3, blob_count_in_state(&mut db, SubComponentType::KEY_BLOB, BlobState::Current));
2668 assert_eq!(2, blob_count_in_state(&mut db, SubComponentType::KEY_BLOB, BlobState::Superseded));
2669 assert_eq!(2, blob_count_in_state(&mut db, SubComponentType::KEY_BLOB, BlobState::Orphaned));
2670 assert_eq!(5, blob_count(&mut db, SubComponentType::CERT));
2671 assert_eq!(5, blob_count(&mut db, SubComponentType::CERT_CHAIN));
2672
2673 Ok(())
2674}
2675
2676#[test]
David Drysdale2566fb32024-07-09 14:46:37 +01002677fn test_load_key_descriptor() -> Result<()> {
2678 let mut db = new_test_db()?;
2679 let key_id = make_test_key_entry(&mut db, Domain::APP, 1, TEST_ALIAS, None)?.0;
2680
2681 let key = db.load_key_descriptor(key_id)?.unwrap();
2682
2683 assert_eq!(key.domain, Domain::APP);
2684 assert_eq!(key.nspace, 1);
2685 assert_eq!(key.alias, Some(TEST_ALIAS.to_string()));
2686
2687 // No such id
2688 assert_eq!(db.load_key_descriptor(key_id + 1)?, None);
2689 Ok(())
2690}
2691
2692#[test]
2693fn test_get_list_app_uids_for_sid() -> Result<()> {
2694 let uid: i32 = 1;
2695 let uid_offset: i64 = (uid as i64) * (AID_USER_OFFSET as i64);
2696 let first_sid = 667;
2697 let second_sid = 669;
2698 let first_app_id: i64 = 123 + uid_offset;
2699 let second_app_id: i64 = 456 + uid_offset;
2700 let third_app_id: i64 = 789 + uid_offset;
2701 let unrelated_app_id: i64 = 1011 + uid_offset;
2702 let mut db = new_test_db()?;
2703 make_test_key_entry_with_sids(
2704 &mut db,
2705 Domain::APP,
2706 first_app_id,
2707 TEST_ALIAS,
2708 None,
2709 &[first_sid],
2710 )
2711 .context("test_get_list_app_uids_for_sid")?;
2712 make_test_key_entry_with_sids(
2713 &mut db,
2714 Domain::APP,
2715 second_app_id,
2716 "alias2",
2717 None,
2718 &[first_sid],
2719 )
2720 .context("test_get_list_app_uids_for_sid")?;
2721 make_test_key_entry_with_sids(
2722 &mut db,
2723 Domain::APP,
2724 second_app_id,
2725 TEST_ALIAS,
2726 None,
2727 &[second_sid],
2728 )
2729 .context("test_get_list_app_uids_for_sid")?;
2730 make_test_key_entry_with_sids(
2731 &mut db,
2732 Domain::APP,
2733 third_app_id,
2734 "alias3",
2735 None,
2736 &[second_sid],
2737 )
2738 .context("test_get_list_app_uids_for_sid")?;
2739 make_test_key_entry_with_sids(&mut db, Domain::APP, unrelated_app_id, TEST_ALIAS, None, &[])
2740 .context("test_get_list_app_uids_for_sid")?;
2741
2742 let mut first_sid_apps = db.get_app_uids_affected_by_sid(uid, first_sid)?;
2743 first_sid_apps.sort();
2744 assert_eq!(first_sid_apps, vec![first_app_id, second_app_id]);
2745 let mut second_sid_apps = db.get_app_uids_affected_by_sid(uid, second_sid)?;
2746 second_sid_apps.sort();
2747 assert_eq!(second_sid_apps, vec![second_app_id, third_app_id]);
2748 Ok(())
2749}
2750
2751#[test]
2752fn test_get_list_app_uids_with_multiple_sids() -> Result<()> {
2753 let uid: i32 = 1;
2754 let uid_offset: i64 = (uid as i64) * (AID_USER_OFFSET as i64);
2755 let first_sid = 667;
2756 let second_sid = 669;
2757 let third_sid = 772;
2758 let first_app_id: i64 = 123 + uid_offset;
2759 let second_app_id: i64 = 456 + uid_offset;
2760 let mut db = new_test_db()?;
2761 make_test_key_entry_with_sids(
2762 &mut db,
2763 Domain::APP,
2764 first_app_id,
2765 TEST_ALIAS,
2766 None,
2767 &[first_sid, second_sid],
2768 )
2769 .context("test_get_list_app_uids_for_sid")?;
2770 make_test_key_entry_with_sids(
2771 &mut db,
2772 Domain::APP,
2773 second_app_id,
2774 "alias2",
2775 None,
2776 &[second_sid, third_sid],
2777 )
2778 .context("test_get_list_app_uids_for_sid")?;
2779
2780 let first_sid_apps = db.get_app_uids_affected_by_sid(uid, first_sid)?;
2781 assert_eq!(first_sid_apps, vec![first_app_id]);
2782
2783 let mut second_sid_apps = db.get_app_uids_affected_by_sid(uid, second_sid)?;
2784 second_sid_apps.sort();
2785 assert_eq!(second_sid_apps, vec![first_app_id, second_app_id]);
2786
2787 let third_sid_apps = db.get_app_uids_affected_by_sid(uid, third_sid)?;
2788 assert_eq!(third_sid_apps, vec![second_app_id]);
2789 Ok(())
2790}
David Drysdaleda897432024-06-24 15:57:35 +01002791
2792// Starting from `next_keyid`, add keys to the database until the count reaches
2793// `key_count`. (`next_keyid` is assumed to indicate how many rows already exist.)
2794fn db_populate_keys(db: &mut KeystoreDB, next_keyid: usize, key_count: usize) {
2795 db.with_transaction(Immediate("test_keyentry"), |tx| {
2796 for next_keyid in next_keyid..key_count {
2797 tx.execute(
2798 "INSERT into persistent.keyentry
2799 (id, key_type, domain, namespace, alias, state, km_uuid)
2800 VALUES(?, ?, ?, ?, ?, ?, ?);",
2801 params![
2802 next_keyid,
2803 KeyType::Client,
2804 Domain::APP.0 as u32,
2805 10001,
2806 &format!("alias-{next_keyid}"),
2807 KeyLifeCycle::Live,
2808 KEYSTORE_UUID,
2809 ],
2810 )?;
2811 tx.execute(
2812 "INSERT INTO persistent.blobentry
2813 (subcomponent_type, keyentryid, blob) VALUES (?, ?, ?);",
2814 params![SubComponentType::KEY_BLOB, next_keyid, TEST_KEY_BLOB],
2815 )?;
2816 tx.execute(
2817 "INSERT INTO persistent.blobentry
2818 (subcomponent_type, keyentryid, blob) VALUES (?, ?, ?);",
2819 params![SubComponentType::CERT, next_keyid, TEST_CERT_BLOB],
2820 )?;
2821 tx.execute(
2822 "INSERT INTO persistent.blobentry
2823 (subcomponent_type, keyentryid, blob) VALUES (?, ?, ?);",
2824 params![SubComponentType::CERT_CHAIN, next_keyid, TEST_CERT_CHAIN_BLOB],
2825 )?;
2826 }
2827 Ok(()).no_gc()
2828 })
2829 .unwrap()
2830}
2831
2832/// Run the provided `test_fn` against the database at various increasing stages of
2833/// database population.
2834fn run_with_many_keys<F, T>(max_count: usize, test_fn: F) -> Result<()>
2835where
2836 F: Fn(&mut KeystoreDB) -> T,
2837{
David Drysdale8da288c2024-07-29 15:57:01 +01002838 prep_and_run_with_many_keys(max_count, |_db| (), test_fn)
2839}
2840
2841/// Run the provided `test_fn` against the database at various increasing stages of
2842/// database population.
2843fn prep_and_run_with_many_keys<F, T, P>(max_count: usize, prep_fn: P, test_fn: F) -> Result<()>
2844where
2845 F: Fn(&mut KeystoreDB) -> T,
2846 P: Fn(&mut KeystoreDB),
2847{
David Drysdaleda897432024-06-24 15:57:35 +01002848 android_logger::init_once(
2849 android_logger::Config::default()
2850 .with_tag("keystore2_test")
2851 .with_max_level(log::LevelFilter::Debug),
2852 );
2853 // Put the test database on disk for a more realistic result.
2854 let db_root = tempfile::Builder::new().prefix("ks2db-test-").tempdir().unwrap();
2855 let mut db_path = db_root.path().to_owned();
2856 db_path.push("ks2-test.sqlite");
2857 let mut db = new_test_db_at(&db_path.to_string_lossy())?;
2858
2859 println!("\nNumber_of_keys,time_in_s");
2860 let mut key_count = 10;
2861 let mut next_keyid = 0;
2862 while key_count < max_count {
2863 db_populate_keys(&mut db, next_keyid, key_count);
2864 assert_eq!(db_key_count(&mut db), key_count);
2865
David Drysdale8da288c2024-07-29 15:57:01 +01002866 // Perform any test-specific preparation
2867 prep_fn(&mut db);
2868
2869 // Time execution of the test function.
David Drysdaleda897432024-06-24 15:57:35 +01002870 let start = std::time::Instant::now();
2871 let _result = test_fn(&mut db);
2872 println!("{key_count}, {}", start.elapsed().as_secs_f64());
2873
2874 next_keyid = key_count;
2875 key_count *= 2;
2876 }
2877
2878 Ok(())
2879}
2880
2881fn db_key_count(db: &mut KeystoreDB) -> usize {
2882 db.with_transaction(TransactionBehavior::Deferred, |tx| {
2883 tx.query_row(
2884 "SELECT COUNT(*) FROM persistent.keyentry
2885 WHERE domain = ? AND state = ? AND key_type = ?;",
2886 params![Domain::APP.0 as u32, KeyLifeCycle::Live, KeyType::Client],
2887 |row| row.get::<usize, usize>(0),
2888 )
2889 .context(ks_err!("Failed to count number of keys."))
2890 .no_gc()
2891 })
2892 .unwrap()
2893}
2894
2895#[test]
2896fn test_handle_superseded_with_many_keys() -> Result<()> {
2897 run_with_many_keys(1_000_000, |db| db.handle_next_superseded_blobs(&[], 20))
2898}
2899
2900#[test]
2901fn test_get_storage_stats_with_many_keys() -> Result<()> {
2902 use android_security_metrics::aidl::android::security::metrics::Storage::Storage as MetricsStorage;
2903 run_with_many_keys(1_000_000, |db| {
2904 db.get_storage_stat(MetricsStorage::DATABASE).unwrap();
2905 db.get_storage_stat(MetricsStorage::KEY_ENTRY).unwrap();
2906 db.get_storage_stat(MetricsStorage::KEY_ENTRY_ID_INDEX).unwrap();
2907 db.get_storage_stat(MetricsStorage::KEY_ENTRY_DOMAIN_NAMESPACE_INDEX).unwrap();
2908 db.get_storage_stat(MetricsStorage::BLOB_ENTRY).unwrap();
2909 db.get_storage_stat(MetricsStorage::BLOB_ENTRY_KEY_ENTRY_ID_INDEX).unwrap();
2910 db.get_storage_stat(MetricsStorage::KEY_PARAMETER).unwrap();
2911 db.get_storage_stat(MetricsStorage::KEY_PARAMETER_KEY_ENTRY_ID_INDEX).unwrap();
2912 db.get_storage_stat(MetricsStorage::KEY_METADATA).unwrap();
2913 db.get_storage_stat(MetricsStorage::KEY_METADATA_KEY_ENTRY_ID_INDEX).unwrap();
2914 db.get_storage_stat(MetricsStorage::GRANT).unwrap();
2915 db.get_storage_stat(MetricsStorage::AUTH_TOKEN).unwrap();
2916 db.get_storage_stat(MetricsStorage::BLOB_METADATA).unwrap();
2917 db.get_storage_stat(MetricsStorage::BLOB_METADATA_BLOB_ENTRY_ID_INDEX).unwrap();
2918 })
2919}
2920
2921#[test]
2922fn test_list_keys_with_many_keys() -> Result<()> {
2923 run_with_many_keys(1_000_000, |db: &mut KeystoreDB| -> Result<()> {
2924 // Behave equivalently to how clients list aliases.
2925 let domain = Domain::APP;
2926 let namespace = 10001;
2927 let mut start_past: Option<String> = None;
2928 let mut count = 0;
2929 let mut batches = 0;
2930 loop {
2931 let keys = db
2932 .list_past_alias(domain, namespace, KeyType::Client, start_past.as_deref())
2933 .unwrap();
2934 let batch_size = crate::utils::estimate_safe_amount_to_return(
2935 domain,
2936 namespace,
David Drysdale703bcc12024-11-26 14:15:03 +00002937 None,
David Drysdaleda897432024-06-24 15:57:35 +01002938 &keys,
2939 crate::utils::RESPONSE_SIZE_LIMIT,
2940 );
2941 let batch = &keys[..batch_size];
2942 count += batch.len();
2943 match batch.last() {
2944 Some(key) => start_past.clone_from(&key.alias),
2945 None => {
2946 log::info!("got {count} keys in {batches} non-empty batches");
2947 return Ok(());
2948 }
2949 }
2950 batches += 1;
2951 }
2952 })
2953}
David Drysdale8da288c2024-07-29 15:57:01 +01002954
2955#[test]
2956fn test_upgrade_1_to_2_with_many_keys() -> Result<()> {
2957 prep_and_run_with_many_keys(
2958 1_000_000,
2959 |db: &mut KeystoreDB| {
2960 // Manually downgrade the database to the v1 schema.
2961 db.with_transaction(Immediate("TX_downgrade_2_to_1"), |tx| {
2962 tx.execute("DROP INDEX persistent.keyentry_state_index;", params!())?;
2963 tx.execute("DROP INDEX persistent.blobentry_state_index;", params!())?;
2964 tx.execute("ALTER TABLE persistent.blobentry DROP COLUMN state;", params!())?;
2965 Ok(()).no_gc()
2966 })
2967 .unwrap();
2968 },
2969 |db: &mut KeystoreDB| -> Result<()> {
2970 // Run the upgrade process.
2971 db.with_transaction(Immediate("TX_upgrade_1_to_2"), |tx| {
2972 KeystoreDB::from_1_to_2(tx).no_gc()
2973 })?;
2974 Ok(())
2975 },
2976 )
2977}