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