blob: 3c26827b25c1799bbc42b3235f76c1fcef12490c [file] [log] [blame]
Joel Galenson26f4d012020-07-17 14:57:21 -07001// 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
Janis Danisevskis63f7bc82020-09-03 10:12:56 -070015//! This is the Keystore 2.0 database module.
16//! The database module provides a connection to the backing SQLite store.
17//! We have two databases one for persistent key blob storage and one for
18//! items that have a per boot life cycle.
19//!
20//! ## Persistent database
21//! The persistent database has tables for key blobs. They are organized
22//! as follows:
23//! The `keyentry` table is the primary table for key entries. It is
24//! accompanied by two tables for blobs and parameters.
25//! Each key entry occupies exactly one row in the `keyentry` table and
26//! zero or more rows in the tables `blobentry` and `keyparameter`.
27//!
28//! ## Per boot database
29//! The per boot database stores items with a per boot lifecycle.
30//! Currently, there is only the `grant` table in this database.
31//! Grants are references to a key that can be used to access a key by
32//! clients that don't own that key. Grants can only be created by the
33//! owner of a key. And only certain components can create grants.
34//! This is governed by SEPolicy.
35//!
36//! ## Access control
37//! Some database functions that load keys or create grants perform
38//! access control. This is because in some cases access control
39//! can only be performed after some information about the designated
40//! key was loaded from the database. To decouple the permission checks
41//! from the database module these functions take permission check
42//! callbacks.
Joel Galenson26f4d012020-07-17 14:57:21 -070043
Qi Wub9433b52020-12-01 14:52:46 +080044use crate::error::{Error as KsError, ErrorCode, ResponseCode};
Janis Danisevskisb42fc182020-12-15 08:41:27 -080045use crate::impl_metadata; // This is in db_utils.rs
Janis Danisevskis4522c2b2020-11-27 18:04:58 -080046use crate::key_parameter::{KeyParameter, Tag};
Janis Danisevskisc5b210b2020-09-11 13:27:37 -070047use crate::permission::KeyPermSet;
Hasini Gunasinghe557b1032020-11-10 01:35:30 +000048use crate::utils::get_current_time_in_seconds;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -080049use crate::{
50 db_utils::{self, SqlField},
51 gc::Gc,
52};
Janis Danisevskisb42fc182020-12-15 08:41:27 -080053use anyhow::{anyhow, Context, Result};
Max Bires8e93d2b2021-01-14 13:17:59 -080054use std::{convert::TryFrom, convert::TryInto, ops::Deref, time::SystemTimeError};
Janis Danisevskis60400fe2020-08-26 15:24:42 -070055
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +000056use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
Janis Danisevskis5ed8c532021-01-11 14:19:42 -080057 HardwareAuthToken::HardwareAuthToken,
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +000058 HardwareAuthenticatorType::HardwareAuthenticatorType, SecurityLevel::SecurityLevel,
Janis Danisevskisc3a496b2021-01-05 10:37:22 -080059};
60use android_hardware_security_secureclock::aidl::android::hardware::security::secureclock::{
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +000061 Timestamp::Timestamp,
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +000062};
Janis Danisevskisc5b210b2020-09-11 13:27:37 -070063use android_system_keystore2::aidl::android::system::keystore2::{
Janis Danisevskis04b02832020-10-26 09:21:40 -070064 Domain::Domain, KeyDescriptor::KeyDescriptor,
Janis Danisevskis60400fe2020-08-26 15:24:42 -070065};
Max Bires2b2e6562020-09-22 11:22:36 -070066use android_security_remoteprovisioning::aidl::android::security::remoteprovisioning::{
67 AttestationPoolStatus::AttestationPoolStatus,
68};
69
70use keystore2_crypto::ZVec;
Janis Danisevskisaec14592020-11-12 09:41:49 -080071use lazy_static::lazy_static;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +000072use log::error;
Joel Galenson0891bc12020-07-20 10:37:03 -070073#[cfg(not(test))]
74use rand::prelude::random;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -070075use rusqlite::{
Janis Danisevskisb42fc182020-12-15 08:41:27 -080076 params,
77 types::FromSql,
78 types::FromSqlResult,
79 types::ToSqlOutput,
80 types::{FromSqlError, Value, ValueRef},
Janis Danisevskis5ed8c532021-01-11 14:19:42 -080081 Connection, OptionalExtension, ToSql, Transaction, TransactionBehavior, NO_PARAMS,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -070082};
Max Bires2b2e6562020-09-22 11:22:36 -070083
Janis Danisevskisaec14592020-11-12 09:41:49 -080084use std::{
Janis Danisevskisb42fc182020-12-15 08:41:27 -080085 collections::{HashMap, HashSet},
Janis Danisevskisbf15d732020-12-08 10:35:26 -080086 path::Path,
87 sync::{Condvar, Mutex},
Janis Danisevskisb42fc182020-12-15 08:41:27 -080088 time::{Duration, SystemTime},
Janis Danisevskisaec14592020-11-12 09:41:49 -080089};
Max Bires2b2e6562020-09-22 11:22:36 -070090
Joel Galenson0891bc12020-07-20 10:37:03 -070091#[cfg(test)]
92use tests::random;
Joel Galenson26f4d012020-07-17 14:57:21 -070093
Janis Danisevskisb42fc182020-12-15 08:41:27 -080094impl_metadata!(
95 /// A set of metadata for key entries.
96 #[derive(Debug, Default, Eq, PartialEq)]
97 pub struct KeyMetaData;
98 /// A metadata entry for key entries.
99 #[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
100 pub enum KeyMetaEntry {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800101 /// Date of the creation of the key entry.
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800102 CreationDate(DateTime) with accessor creation_date,
103 /// Expiration date for attestation keys.
104 AttestationExpirationDate(DateTime) with accessor attestation_expiration_date,
Max Bires2b2e6562020-09-22 11:22:36 -0700105 /// CBOR Blob that represents a COSE_Key and associated metadata needed for remote
106 /// provisioning
107 AttestationMacedPublicKey(Vec<u8>) with accessor attestation_maced_public_key,
108 /// Vector representing the raw public key so results from the server can be matched
109 /// to the right entry
110 AttestationRawPubKey(Vec<u8>) with accessor attestation_raw_pub_key,
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800111 // --- ADD NEW META DATA FIELDS HERE ---
112 // For backwards compatibility add new entries only to
113 // end of this list and above this comment.
114 };
115);
116
117impl KeyMetaData {
118 fn load_from_db(key_id: i64, tx: &Transaction) -> Result<Self> {
119 let mut stmt = tx
120 .prepare(
121 "SELECT tag, data from persistent.keymetadata
122 WHERE keyentryid = ?;",
123 )
124 .context("In KeyMetaData::load_from_db: prepare statement failed.")?;
125
126 let mut metadata: HashMap<i64, KeyMetaEntry> = Default::default();
127
128 let mut rows =
129 stmt.query(params![key_id]).context("In KeyMetaData::load_from_db: query failed.")?;
130 db_utils::with_rows_extract_all(&mut rows, |row| {
131 let db_tag: i64 = row.get(0).context("Failed to read tag.")?;
132 metadata.insert(
133 db_tag,
134 KeyMetaEntry::new_from_sql(db_tag, &SqlField::new(1, &row))
135 .context("Failed to read KeyMetaEntry.")?,
136 );
137 Ok(())
138 })
139 .context("In KeyMetaData::load_from_db.")?;
140
141 Ok(Self { data: metadata })
142 }
143
144 fn store_in_db(&self, key_id: i64, tx: &Transaction) -> Result<()> {
145 let mut stmt = tx
146 .prepare(
147 "INSERT into persistent.keymetadata (keyentryid, tag, data)
148 VALUES (?, ?, ?);",
149 )
150 .context("In KeyMetaData::store_in_db: Failed to prepare statement.")?;
151
152 let iter = self.data.iter();
153 for (tag, entry) in iter {
154 stmt.insert(params![key_id, tag, entry,]).with_context(|| {
155 format!("In KeyMetaData::store_in_db: Failed to insert {:?}", entry)
156 })?;
157 }
158 Ok(())
159 }
160}
161
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800162impl_metadata!(
163 /// A set of metadata for key blobs.
164 #[derive(Debug, Default, Eq, PartialEq)]
165 pub struct BlobMetaData;
166 /// A metadata entry for key blobs.
167 #[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
168 pub enum BlobMetaEntry {
169 /// If present, indicates that the blob is encrypted with another key or a key derived
170 /// from a password.
171 EncryptedBy(EncryptedBy) with accessor encrypted_by,
172 /// If the blob is password encrypted this field is set to the
173 /// salt used for the key derivation.
174 Salt(Vec<u8>) with accessor salt,
175 /// If the blob is encrypted, this field is set to the initialization vector.
176 Iv(Vec<u8>) with accessor iv,
177 /// If the blob is encrypted, this field holds the AEAD TAG.
178 AeadTag(Vec<u8>) with accessor aead_tag,
179 /// The uuid of the owning KeyMint instance.
180 KmUuid(Uuid) with accessor km_uuid,
181 // --- ADD NEW META DATA FIELDS HERE ---
182 // For backwards compatibility add new entries only to
183 // end of this list and above this comment.
184 };
185);
186
187impl BlobMetaData {
188 fn load_from_db(blob_id: i64, tx: &Transaction) -> Result<Self> {
189 let mut stmt = tx
190 .prepare(
191 "SELECT tag, data from persistent.blobmetadata
192 WHERE blobentryid = ?;",
193 )
194 .context("In BlobMetaData::load_from_db: prepare statement failed.")?;
195
196 let mut metadata: HashMap<i64, BlobMetaEntry> = Default::default();
197
198 let mut rows =
199 stmt.query(params![blob_id]).context("In BlobMetaData::load_from_db: query failed.")?;
200 db_utils::with_rows_extract_all(&mut rows, |row| {
201 let db_tag: i64 = row.get(0).context("Failed to read tag.")?;
202 metadata.insert(
203 db_tag,
204 BlobMetaEntry::new_from_sql(db_tag, &SqlField::new(1, &row))
205 .context("Failed to read BlobMetaEntry.")?,
206 );
207 Ok(())
208 })
209 .context("In BlobMetaData::load_from_db.")?;
210
211 Ok(Self { data: metadata })
212 }
213
214 fn store_in_db(&self, blob_id: i64, tx: &Transaction) -> Result<()> {
215 let mut stmt = tx
216 .prepare(
217 "INSERT or REPLACE INTO persistent.blobmetadata (blobentryid, tag, data)
218 VALUES (?, ?, ?);",
219 )
220 .context("In BlobMetaData::store_in_db: Failed to prepare statement.")?;
221
222 let iter = self.data.iter();
223 for (tag, entry) in iter {
224 stmt.insert(params![blob_id, tag, entry,]).with_context(|| {
225 format!("In BlobMetaData::store_in_db: Failed to insert {:?}", entry)
226 })?;
227 }
228 Ok(())
229 }
230}
231
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800232/// Indicates the type of the keyentry.
233#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
234pub enum KeyType {
235 /// This is a client key type. These keys are created or imported through the Keystore 2.0
236 /// AIDL interface android.system.keystore2.
237 Client,
238 /// This is a super key type. These keys are created by keystore itself and used to encrypt
239 /// other key blobs to provide LSKF binding.
240 Super,
241 /// This is an attestation key. These keys are created by the remote provisioning mechanism.
242 Attestation,
243}
244
245impl ToSql for KeyType {
246 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
247 Ok(ToSqlOutput::Owned(Value::Integer(match self {
248 KeyType::Client => 0,
249 KeyType::Super => 1,
250 KeyType::Attestation => 2,
251 })))
252 }
253}
254
255impl FromSql for KeyType {
256 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
257 match i64::column_result(value)? {
258 0 => Ok(KeyType::Client),
259 1 => Ok(KeyType::Super),
260 2 => Ok(KeyType::Attestation),
261 v => Err(FromSqlError::OutOfRange(v)),
262 }
263 }
264}
265
Max Bires8e93d2b2021-01-14 13:17:59 -0800266/// Uuid representation that can be stored in the database.
267/// Right now it can only be initialized from SecurityLevel.
268/// Once KeyMint provides a UUID type a corresponding From impl shall be added.
269#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
270pub struct Uuid([u8; 16]);
271
272impl Deref for Uuid {
273 type Target = [u8; 16];
274
275 fn deref(&self) -> &Self::Target {
276 &self.0
277 }
278}
279
280impl From<SecurityLevel> for Uuid {
281 fn from(sec_level: SecurityLevel) -> Self {
282 Self((sec_level.0 as u128).to_be_bytes())
283 }
284}
285
286impl ToSql for Uuid {
287 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
288 self.0.to_sql()
289 }
290}
291
292impl FromSql for Uuid {
293 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
294 let blob = Vec::<u8>::column_result(value)?;
295 if blob.len() != 16 {
296 return Err(FromSqlError::OutOfRange(blob.len() as i64));
297 }
298 let mut arr = [0u8; 16];
299 arr.copy_from_slice(&blob);
300 Ok(Self(arr))
301 }
302}
303
304/// Key entries that are not associated with any KeyMint instance, such as pure certificate
305/// entries are associated with this UUID.
306pub static KEYSTORE_UUID: Uuid = Uuid([
307 0x41, 0xe3, 0xb9, 0xce, 0x27, 0x58, 0x4e, 0x91, 0xbc, 0xfd, 0xa5, 0x5d, 0x91, 0x85, 0xab, 0x11,
308]);
309
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800310/// Indicates how the sensitive part of this key blob is encrypted.
311#[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
312pub enum EncryptedBy {
313 /// The keyblob is encrypted by a user password.
314 /// In the database this variant is represented as NULL.
315 Password,
316 /// The keyblob is encrypted by another key with wrapped key id.
317 /// In the database this variant is represented as non NULL value
318 /// that is convertible to i64, typically NUMERIC.
319 KeyId(i64),
320}
321
322impl ToSql for EncryptedBy {
323 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
324 match self {
325 Self::Password => Ok(ToSqlOutput::Owned(Value::Null)),
326 Self::KeyId(id) => id.to_sql(),
327 }
328 }
329}
330
331impl FromSql for EncryptedBy {
332 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
333 match value {
334 ValueRef::Null => Ok(Self::Password),
335 _ => Ok(Self::KeyId(i64::column_result(value)?)),
336 }
337 }
338}
339
340/// A database representation of wall clock time. DateTime stores unix epoch time as
341/// i64 in milliseconds.
342#[derive(Debug, Copy, Clone, Default, Eq, PartialEq, Ord, PartialOrd)]
343pub struct DateTime(i64);
344
345/// Error type returned when creating DateTime or converting it from and to
346/// SystemTime.
347#[derive(thiserror::Error, Debug)]
348pub enum DateTimeError {
349 /// This is returned when SystemTime and Duration computations fail.
350 #[error(transparent)]
351 SystemTimeError(#[from] SystemTimeError),
352
353 /// This is returned when type conversions fail.
354 #[error(transparent)]
355 TypeConversion(#[from] std::num::TryFromIntError),
356
357 /// This is returned when checked time arithmetic failed.
358 #[error("Time arithmetic failed.")]
359 TimeArithmetic,
360}
361
362impl DateTime {
363 /// Constructs a new DateTime object denoting the current time. This may fail during
364 /// conversion to unix epoch time and during conversion to the internal i64 representation.
365 pub fn now() -> Result<Self, DateTimeError> {
366 Ok(Self(SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_millis().try_into()?))
367 }
368
369 /// Constructs a new DateTime object from milliseconds.
370 pub fn from_millis_epoch(millis: i64) -> Self {
371 Self(millis)
372 }
373
374 /// Returns unix epoch time in milliseconds.
375 pub fn to_millis_epoch(&self) -> i64 {
376 self.0
377 }
378
379 /// Returns unix epoch time in seconds.
380 pub fn to_secs_epoch(&self) -> i64 {
381 self.0 / 1000
382 }
383}
384
385impl ToSql for DateTime {
386 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
387 Ok(ToSqlOutput::Owned(Value::Integer(self.0)))
388 }
389}
390
391impl FromSql for DateTime {
392 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
393 Ok(Self(i64::column_result(value)?))
394 }
395}
396
397impl TryInto<SystemTime> for DateTime {
398 type Error = DateTimeError;
399
400 fn try_into(self) -> Result<SystemTime, Self::Error> {
401 // We want to construct a SystemTime representation equivalent to self, denoting
402 // a point in time THEN, but we cannot set the time directly. We can only construct
403 // a SystemTime denoting NOW, and we can get the duration between EPOCH and NOW,
404 // and between EPOCH and THEN. With this common reference we can construct the
405 // duration between NOW and THEN which we can add to our SystemTime representation
406 // of NOW to get a SystemTime representation of THEN.
407 // Durations can only be positive, thus the if statement below.
408 let now = SystemTime::now();
409 let now_epoch = now.duration_since(SystemTime::UNIX_EPOCH)?;
410 let then_epoch = Duration::from_millis(self.0.try_into()?);
411 Ok(if now_epoch > then_epoch {
412 // then = now - (now_epoch - then_epoch)
413 now_epoch
414 .checked_sub(then_epoch)
415 .and_then(|d| now.checked_sub(d))
416 .ok_or(DateTimeError::TimeArithmetic)?
417 } else {
418 // then = now + (then_epoch - now_epoch)
419 then_epoch
420 .checked_sub(now_epoch)
421 .and_then(|d| now.checked_add(d))
422 .ok_or(DateTimeError::TimeArithmetic)?
423 })
424 }
425}
426
427impl TryFrom<SystemTime> for DateTime {
428 type Error = DateTimeError;
429
430 fn try_from(t: SystemTime) -> Result<Self, Self::Error> {
431 Ok(Self(t.duration_since(SystemTime::UNIX_EPOCH)?.as_millis().try_into()?))
432 }
433}
434
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800435#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone)]
436enum KeyLifeCycle {
437 /// Existing keys have a key ID but are not fully populated yet.
438 /// This is a transient state. If Keystore finds any such keys when it starts up, it must move
439 /// them to Unreferenced for garbage collection.
440 Existing,
441 /// A live key is fully populated and usable by clients.
442 Live,
443 /// An unreferenced key is scheduled for garbage collection.
444 Unreferenced,
445}
446
447impl ToSql for KeyLifeCycle {
448 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
449 match self {
450 Self::Existing => Ok(ToSqlOutput::Owned(Value::Integer(0))),
451 Self::Live => Ok(ToSqlOutput::Owned(Value::Integer(1))),
452 Self::Unreferenced => Ok(ToSqlOutput::Owned(Value::Integer(2))),
453 }
454 }
455}
456
457impl FromSql for KeyLifeCycle {
458 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
459 match i64::column_result(value)? {
460 0 => Ok(KeyLifeCycle::Existing),
461 1 => Ok(KeyLifeCycle::Live),
462 2 => Ok(KeyLifeCycle::Unreferenced),
463 v => Err(FromSqlError::OutOfRange(v)),
464 }
465 }
466}
467
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700468/// Keys have a KeyMint blob component and optional public certificate and
469/// certificate chain components.
470/// KeyEntryLoadBits is a bitmap that indicates to `KeystoreDB::load_key_entry`
471/// which components shall be loaded from the database if present.
Janis Danisevskis66784c42021-01-27 08:40:25 -0800472#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700473pub struct KeyEntryLoadBits(u32);
474
475impl KeyEntryLoadBits {
476 /// Indicate to `KeystoreDB::load_key_entry` that no component shall be loaded.
477 pub const NONE: KeyEntryLoadBits = Self(0);
478 /// Indicate to `KeystoreDB::load_key_entry` that the KeyMint component shall be loaded.
479 pub const KM: KeyEntryLoadBits = Self(1);
480 /// Indicate to `KeystoreDB::load_key_entry` that the Public components shall be loaded.
481 pub const PUBLIC: KeyEntryLoadBits = Self(2);
482 /// Indicate to `KeystoreDB::load_key_entry` that both components shall be loaded.
483 pub const BOTH: KeyEntryLoadBits = Self(3);
484
485 /// Returns true if this object indicates that the public components shall be loaded.
486 pub const fn load_public(&self) -> bool {
487 self.0 & Self::PUBLIC.0 != 0
488 }
489
490 /// Returns true if the object indicates that the KeyMint component shall be loaded.
491 pub const fn load_km(&self) -> bool {
492 self.0 & Self::KM.0 != 0
493 }
494}
495
Janis Danisevskisaec14592020-11-12 09:41:49 -0800496lazy_static! {
497 static ref KEY_ID_LOCK: KeyIdLockDb = KeyIdLockDb::new();
498}
499
500struct KeyIdLockDb {
501 locked_keys: Mutex<HashSet<i64>>,
502 cond_var: Condvar,
503}
504
505/// A locked key. While a guard exists for a given key id, the same key cannot be loaded
506/// from the database a second time. Most functions manipulating the key blob database
507/// require a KeyIdGuard.
508#[derive(Debug)]
509pub struct KeyIdGuard(i64);
510
511impl KeyIdLockDb {
512 fn new() -> Self {
513 Self { locked_keys: Mutex::new(HashSet::new()), cond_var: Condvar::new() }
514 }
515
516 /// This function blocks until an exclusive lock for the given key entry id can
517 /// be acquired. It returns a guard object, that represents the lifecycle of the
518 /// acquired lock.
519 pub fn get(&self, key_id: i64) -> KeyIdGuard {
520 let mut locked_keys = self.locked_keys.lock().unwrap();
521 while locked_keys.contains(&key_id) {
522 locked_keys = self.cond_var.wait(locked_keys).unwrap();
523 }
524 locked_keys.insert(key_id);
525 KeyIdGuard(key_id)
526 }
527
528 /// This function attempts to acquire an exclusive lock on a given key id. If the
529 /// given key id is already taken the function returns None immediately. If a lock
530 /// can be acquired this function returns a guard object, that represents the
531 /// lifecycle of the acquired lock.
532 pub fn try_get(&self, key_id: i64) -> Option<KeyIdGuard> {
533 let mut locked_keys = self.locked_keys.lock().unwrap();
534 if locked_keys.insert(key_id) {
535 Some(KeyIdGuard(key_id))
536 } else {
537 None
538 }
539 }
540}
541
542impl KeyIdGuard {
543 /// Get the numeric key id of the locked key.
544 pub fn id(&self) -> i64 {
545 self.0
546 }
547}
548
549impl Drop for KeyIdGuard {
550 fn drop(&mut self) {
551 let mut locked_keys = KEY_ID_LOCK.locked_keys.lock().unwrap();
552 locked_keys.remove(&self.0);
Janis Danisevskis7fd53582020-11-23 13:40:34 -0800553 drop(locked_keys);
Janis Danisevskisaec14592020-11-12 09:41:49 -0800554 KEY_ID_LOCK.cond_var.notify_all();
555 }
556}
557
Max Bires8e93d2b2021-01-14 13:17:59 -0800558/// This type represents a certificate and certificate chain entry for a key.
Max Bires2b2e6562020-09-22 11:22:36 -0700559#[derive(Debug, Default)]
Max Bires8e93d2b2021-01-14 13:17:59 -0800560pub struct CertificateInfo {
561 cert: Option<Vec<u8>>,
562 cert_chain: Option<Vec<u8>>,
563}
564
565impl CertificateInfo {
566 /// Constructs a new CertificateInfo object from `cert` and `cert_chain`
567 pub fn new(cert: Option<Vec<u8>>, cert_chain: Option<Vec<u8>>) -> Self {
568 Self { cert, cert_chain }
569 }
570
571 /// Take the cert
572 pub fn take_cert(&mut self) -> Option<Vec<u8>> {
573 self.cert.take()
574 }
575
576 /// Take the cert chain
577 pub fn take_cert_chain(&mut self) -> Option<Vec<u8>> {
578 self.cert_chain.take()
579 }
580}
581
Max Bires2b2e6562020-09-22 11:22:36 -0700582/// This type represents a certificate chain with a private key corresponding to the leaf
583/// certificate. TODO(jbires): This will be used in a follow-on CL, for now it's used in the tests.
584#[allow(dead_code)]
585pub struct CertificateChain {
586 private_key: ZVec,
587 cert_chain: ZVec,
588}
589
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700590/// This type represents a Keystore 2.0 key entry.
591/// An entry has a unique `id` by which it can be found in the database.
592/// It has a security level field, key parameters, and three optional fields
593/// for the KeyMint blob, public certificate and a public certificate chain.
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800594#[derive(Debug, Default, Eq, PartialEq)]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700595pub struct KeyEntry {
596 id: i64,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800597 key_blob_info: Option<(Vec<u8>, BlobMetaData)>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700598 cert: Option<Vec<u8>>,
599 cert_chain: Option<Vec<u8>>,
Max Bires8e93d2b2021-01-14 13:17:59 -0800600 km_uuid: Uuid,
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700601 parameters: Vec<KeyParameter>,
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800602 metadata: KeyMetaData,
Janis Danisevskis377d1002021-01-27 19:07:48 -0800603 pure_cert: bool,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700604}
605
606impl KeyEntry {
607 /// Returns the unique id of the Key entry.
608 pub fn id(&self) -> i64 {
609 self.id
610 }
611 /// Exposes the optional KeyMint blob.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800612 pub fn key_blob_info(&self) -> &Option<(Vec<u8>, BlobMetaData)> {
613 &self.key_blob_info
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700614 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800615 /// Extracts the Optional KeyMint blob including its metadata.
616 pub fn take_key_blob_info(&mut self) -> Option<(Vec<u8>, BlobMetaData)> {
617 self.key_blob_info.take()
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700618 }
619 /// Exposes the optional public certificate.
620 pub fn cert(&self) -> &Option<Vec<u8>> {
621 &self.cert
622 }
623 /// Extracts the optional public certificate.
624 pub fn take_cert(&mut self) -> Option<Vec<u8>> {
625 self.cert.take()
626 }
627 /// Exposes the optional public certificate chain.
628 pub fn cert_chain(&self) -> &Option<Vec<u8>> {
629 &self.cert_chain
630 }
631 /// Extracts the optional public certificate_chain.
632 pub fn take_cert_chain(&mut self) -> Option<Vec<u8>> {
633 self.cert_chain.take()
634 }
Max Bires8e93d2b2021-01-14 13:17:59 -0800635 /// Returns the uuid of the owning KeyMint instance.
636 pub fn km_uuid(&self) -> &Uuid {
637 &self.km_uuid
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700638 }
Janis Danisevskis04b02832020-10-26 09:21:40 -0700639 /// Exposes the key parameters of this key entry.
640 pub fn key_parameters(&self) -> &Vec<KeyParameter> {
641 &self.parameters
642 }
643 /// Consumes this key entry and extracts the keyparameters from it.
644 pub fn into_key_parameters(self) -> Vec<KeyParameter> {
645 self.parameters
646 }
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800647 /// Exposes the key metadata of this key entry.
648 pub fn metadata(&self) -> &KeyMetaData {
649 &self.metadata
650 }
Janis Danisevskis377d1002021-01-27 19:07:48 -0800651 /// This returns true if the entry is a pure certificate entry with no
652 /// private key component.
653 pub fn pure_cert(&self) -> bool {
654 self.pure_cert
655 }
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700656}
657
658/// Indicates the sub component of a key entry for persistent storage.
Janis Danisevskis377d1002021-01-27 19:07:48 -0800659#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700660pub struct SubComponentType(u32);
661impl SubComponentType {
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800662 /// Persistent identifier for a key blob.
663 pub const KEY_BLOB: SubComponentType = Self(0);
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700664 /// Persistent identifier for a certificate blob.
665 pub const CERT: SubComponentType = Self(1);
666 /// Persistent identifier for a certificate chain blob.
667 pub const CERT_CHAIN: SubComponentType = Self(2);
668}
669
670impl ToSql for SubComponentType {
671 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
672 self.0.to_sql()
673 }
674}
675
676impl FromSql for SubComponentType {
677 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
678 Ok(Self(u32::column_result(value)?))
679 }
680}
681
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800682/// This trait is private to the database module. It is used to convey whether or not the garbage
683/// collector shall be invoked after a database access. All closures passed to
684/// `KeystoreDB::with_transaction` return a tuple (bool, T) where the bool indicates if the
685/// gc needs to be triggered. This convenience function allows to turn any anyhow::Result<T>
686/// into anyhow::Result<(bool, T)> by simply appending one of `.do_gc(bool)`, `.no_gc()`, or
687/// `.need_gc()`.
688trait DoGc<T> {
689 fn do_gc(self, need_gc: bool) -> Result<(bool, T)>;
690
691 fn no_gc(self) -> Result<(bool, T)>;
692
693 fn need_gc(self) -> Result<(bool, T)>;
694}
695
696impl<T> DoGc<T> for Result<T> {
697 fn do_gc(self, need_gc: bool) -> Result<(bool, T)> {
698 self.map(|r| (need_gc, r))
699 }
700
701 fn no_gc(self) -> Result<(bool, T)> {
702 self.do_gc(false)
703 }
704
705 fn need_gc(self) -> Result<(bool, T)> {
706 self.do_gc(true)
707 }
708}
709
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700710/// KeystoreDB wraps a connection to an SQLite database and tracks its
711/// ownership. It also implements all of Keystore 2.0's database functionality.
Joel Galenson26f4d012020-07-17 14:57:21 -0700712pub struct KeystoreDB {
Joel Galenson26f4d012020-07-17 14:57:21 -0700713 conn: Connection,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800714 gc: Option<Gc>,
Joel Galenson26f4d012020-07-17 14:57:21 -0700715}
716
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000717/// Database representation of the monotonic time retrieved from the system call clock_gettime with
718/// CLOCK_MONOTONIC_RAW. Stores monotonic time as i64 in seconds.
719#[derive(Debug, Copy, Clone, Default, Eq, PartialEq, Ord, PartialOrd)]
720pub struct MonotonicRawTime(i64);
721
722impl MonotonicRawTime {
723 /// Constructs a new MonotonicRawTime
724 pub fn now() -> Self {
725 Self(get_current_time_in_seconds())
726 }
727
728 /// Returns the integer value of MonotonicRawTime as i64
729 pub fn seconds(&self) -> i64 {
730 self.0
731 }
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800732
733 /// Like i64::checked_sub.
734 pub fn checked_sub(&self, other: &Self) -> Option<Self> {
735 self.0.checked_sub(other.0).map(Self)
736 }
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000737}
738
739impl ToSql for MonotonicRawTime {
740 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
741 Ok(ToSqlOutput::Owned(Value::Integer(self.0)))
742 }
743}
744
745impl FromSql for MonotonicRawTime {
746 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
747 Ok(Self(i64::column_result(value)?))
748 }
749}
750
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000751/// This struct encapsulates the information to be stored in the database about the auth tokens
752/// received by keystore.
753pub struct AuthTokenEntry {
754 auth_token: HardwareAuthToken,
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000755 time_received: MonotonicRawTime,
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000756}
757
758impl AuthTokenEntry {
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000759 fn new(auth_token: HardwareAuthToken, time_received: MonotonicRawTime) -> Self {
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000760 AuthTokenEntry { auth_token, time_received }
761 }
762
763 /// Checks if this auth token satisfies the given authentication information.
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800764 pub fn satisfies(&self, user_secure_ids: &[i64], auth_type: HardwareAuthenticatorType) -> bool {
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000765 user_secure_ids.iter().any(|&sid| {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800766 (sid == self.auth_token.userId || sid == self.auth_token.authenticatorId)
767 && (((auth_type.0 as i32) & (self.auth_token.authenticatorType.0 as i32)) != 0)
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000768 })
769 }
770
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000771 /// Returns the auth token wrapped by the AuthTokenEntry
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800772 pub fn auth_token(&self) -> &HardwareAuthToken {
773 &self.auth_token
774 }
775
776 /// Returns the auth token wrapped by the AuthTokenEntry
777 pub fn take_auth_token(self) -> HardwareAuthToken {
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000778 self.auth_token
779 }
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800780
781 /// Returns the time that this auth token was received.
782 pub fn time_received(&self) -> MonotonicRawTime {
783 self.time_received
784 }
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000785}
786
Janis Danisevskisb00ebd02021-02-02 21:52:24 -0800787/// Shared in-memory databases get destroyed as soon as the last connection to them gets closed.
788/// This object does not allow access to the database connection. But it keeps a database
789/// connection alive in order to keep the in memory per boot database alive.
790pub struct PerBootDbKeepAlive(Connection);
791
Joel Galenson26f4d012020-07-17 14:57:21 -0700792impl KeystoreDB {
Janis Danisevskisb00ebd02021-02-02 21:52:24 -0800793 const PERBOOT_DB_FILE_NAME: &'static str = &"file:perboot.sqlite?mode=memory&cache=shared";
794
Hasini Gunasinghe0e161452021-01-27 19:34:37 +0000795 /// The alias of the user super key.
796 pub const USER_SUPER_KEY_ALIAS: &'static str = &"USER_SUPER_KEY";
797
Janis Danisevskisb00ebd02021-02-02 21:52:24 -0800798 /// This creates a PerBootDbKeepAlive object to keep the per boot database alive.
799 pub fn keep_perboot_db_alive() -> Result<PerBootDbKeepAlive> {
800 let conn = Connection::open_in_memory()
801 .context("In keep_perboot_db_alive: Failed to initialize SQLite connection.")?;
802
803 conn.execute("ATTACH DATABASE ? as perboot;", params![Self::PERBOOT_DB_FILE_NAME])
804 .context("In keep_perboot_db_alive: Failed to attach database perboot.")?;
805 Ok(PerBootDbKeepAlive(conn))
806 }
807
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700808 /// This will create a new database connection connecting the two
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800809 /// files persistent.sqlite and perboot.sqlite in the given directory.
810 /// It also attempts to initialize all of the tables.
811 /// KeystoreDB cannot be used by multiple threads.
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700812 /// Each thread should open their own connection using `thread_local!`.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800813 pub fn new(db_root: &Path, gc: Option<Gc>) -> Result<Self> {
Janis Danisevskisb00ebd02021-02-02 21:52:24 -0800814 // Build the path to the sqlite file.
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800815 let mut persistent_path = db_root.to_path_buf();
816 persistent_path.push("persistent.sqlite");
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700817
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800818 // Now convert them to strings prefixed with "file:"
819 let mut persistent_path_str = "file:".to_owned();
820 persistent_path_str.push_str(&persistent_path.to_string_lossy());
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800821
Janis Danisevskisb00ebd02021-02-02 21:52:24 -0800822 let conn = Self::make_connection(&persistent_path_str, &Self::PERBOOT_DB_FILE_NAME)?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800823
Janis Danisevskis66784c42021-01-27 08:40:25 -0800824 // On busy fail Immediately. It is unlikely to succeed given a bug in sqlite.
825 conn.busy_handler(None).context("In KeystoreDB::new: Failed to set busy handler.")?;
826
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800827 let mut db = Self { conn, gc };
Janis Danisevskis66784c42021-01-27 08:40:25 -0800828 db.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800829 Self::init_tables(tx).context("Trying to initialize tables.").no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -0800830 })?;
831 Ok(db)
Joel Galenson2aab4432020-07-22 15:27:57 -0700832 }
833
Janis Danisevskis66784c42021-01-27 08:40:25 -0800834 fn init_tables(tx: &Transaction) -> Result<()> {
835 tx.execute(
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700836 "CREATE TABLE IF NOT EXISTS persistent.keyentry (
Joel Galenson0891bc12020-07-20 10:37:03 -0700837 id INTEGER UNIQUE,
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800838 key_type INTEGER,
Joel Galenson0891bc12020-07-20 10:37:03 -0700839 domain INTEGER,
840 namespace INTEGER,
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800841 alias BLOB,
Max Bires8e93d2b2021-01-14 13:17:59 -0800842 state INTEGER,
843 km_uuid BLOB);",
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700844 NO_PARAMS,
845 )
846 .context("Failed to initialize \"keyentry\" table.")?;
847
Janis Danisevskis66784c42021-01-27 08:40:25 -0800848 tx.execute(
Janis Danisevskisa5438182021-02-02 14:22:59 -0800849 "CREATE INDEX IF NOT EXISTS persistent.keyentry_id_index
850 ON keyentry(id);",
851 NO_PARAMS,
852 )
853 .context("Failed to create index keyentry_id_index.")?;
854
855 tx.execute(
856 "CREATE INDEX IF NOT EXISTS persistent.keyentry_domain_namespace_index
857 ON keyentry(domain, namespace, alias);",
858 NO_PARAMS,
859 )
860 .context("Failed to create index keyentry_domain_namespace_index.")?;
861
862 tx.execute(
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700863 "CREATE TABLE IF NOT EXISTS persistent.blobentry (
864 id INTEGER PRIMARY KEY,
865 subcomponent_type INTEGER,
866 keyentryid INTEGER,
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800867 blob BLOB);",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700868 NO_PARAMS,
869 )
870 .context("Failed to initialize \"blobentry\" table.")?;
871
Janis Danisevskis66784c42021-01-27 08:40:25 -0800872 tx.execute(
Janis Danisevskisa5438182021-02-02 14:22:59 -0800873 "CREATE INDEX IF NOT EXISTS persistent.blobentry_keyentryid_index
874 ON blobentry(keyentryid);",
875 NO_PARAMS,
876 )
877 .context("Failed to create index blobentry_keyentryid_index.")?;
878
879 tx.execute(
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800880 "CREATE TABLE IF NOT EXISTS persistent.blobmetadata (
881 id INTEGER PRIMARY KEY,
882 blobentryid INTEGER,
883 tag INTEGER,
884 data ANY,
885 UNIQUE (blobentryid, tag));",
886 NO_PARAMS,
887 )
888 .context("Failed to initialize \"blobmetadata\" table.")?;
889
890 tx.execute(
891 "CREATE INDEX IF NOT EXISTS persistent.blobmetadata_blobentryid_index
892 ON blobmetadata(blobentryid);",
893 NO_PARAMS,
894 )
895 .context("Failed to create index blobmetadata_blobentryid_index.")?;
896
897 tx.execute(
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700898 "CREATE TABLE IF NOT EXISTS persistent.keyparameter (
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000899 keyentryid INTEGER,
900 tag INTEGER,
901 data ANY,
902 security_level INTEGER);",
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700903 NO_PARAMS,
904 )
905 .context("Failed to initialize \"keyparameter\" table.")?;
906
Janis Danisevskis66784c42021-01-27 08:40:25 -0800907 tx.execute(
Janis Danisevskisa5438182021-02-02 14:22:59 -0800908 "CREATE INDEX IF NOT EXISTS persistent.keyparameter_keyentryid_index
909 ON keyparameter(keyentryid);",
910 NO_PARAMS,
911 )
912 .context("Failed to create index keyparameter_keyentryid_index.")?;
913
914 tx.execute(
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800915 "CREATE TABLE IF NOT EXISTS persistent.keymetadata (
916 keyentryid INTEGER,
917 tag INTEGER,
918 data ANY);",
919 NO_PARAMS,
920 )
921 .context("Failed to initialize \"keymetadata\" table.")?;
922
Janis Danisevskis66784c42021-01-27 08:40:25 -0800923 tx.execute(
Janis Danisevskisa5438182021-02-02 14:22:59 -0800924 "CREATE INDEX IF NOT EXISTS persistent.keymetadata_keyentryid_index
925 ON keymetadata(keyentryid);",
926 NO_PARAMS,
927 )
928 .context("Failed to create index keymetadata_keyentryid_index.")?;
929
930 tx.execute(
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800931 "CREATE TABLE IF NOT EXISTS persistent.grant (
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700932 id INTEGER UNIQUE,
933 grantee INTEGER,
934 keyentryid INTEGER,
935 access_vector INTEGER);",
936 NO_PARAMS,
937 )
938 .context("Failed to initialize \"grant\" table.")?;
939
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000940 //TODO: only drop the following two perboot tables if this is the first start up
941 //during the boot (b/175716626).
Janis Danisevskis66784c42021-01-27 08:40:25 -0800942 // tx.execute("DROP TABLE IF EXISTS perboot.authtoken;", NO_PARAMS)
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000943 // .context("Failed to drop perboot.authtoken table")?;
Janis Danisevskis66784c42021-01-27 08:40:25 -0800944 tx.execute(
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000945 "CREATE TABLE IF NOT EXISTS perboot.authtoken (
946 id INTEGER PRIMARY KEY,
947 challenge INTEGER,
948 user_id INTEGER,
949 auth_id INTEGER,
950 authenticator_type INTEGER,
951 timestamp INTEGER,
952 mac BLOB,
953 time_received INTEGER,
954 UNIQUE(user_id, auth_id, authenticator_type));",
955 NO_PARAMS,
956 )
957 .context("Failed to initialize \"authtoken\" table.")?;
958
Janis Danisevskis66784c42021-01-27 08:40:25 -0800959 // tx.execute("DROP TABLE IF EXISTS perboot.metadata;", NO_PARAMS)
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000960 // .context("Failed to drop perboot.metadata table")?;
961 // metadata table stores certain miscellaneous information required for keystore functioning
962 // during a boot cycle, as key-value pairs.
Janis Danisevskis66784c42021-01-27 08:40:25 -0800963 tx.execute(
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000964 "CREATE TABLE IF NOT EXISTS perboot.metadata (
965 key TEXT,
966 value BLOB,
967 UNIQUE(key));",
968 NO_PARAMS,
969 )
970 .context("Failed to initialize \"metadata\" table.")?;
Joel Galenson0891bc12020-07-20 10:37:03 -0700971 Ok(())
972 }
973
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700974 fn make_connection(persistent_file: &str, perboot_file: &str) -> Result<Connection> {
975 let conn =
976 Connection::open_in_memory().context("Failed to initialize SQLite connection.")?;
977
Janis Danisevskis66784c42021-01-27 08:40:25 -0800978 loop {
979 if let Err(e) = conn
980 .execute("ATTACH DATABASE ? as persistent;", params![persistent_file])
981 .context("Failed to attach database persistent.")
982 {
983 if Self::is_locked_error(&e) {
984 std::thread::sleep(std::time::Duration::from_micros(500));
985 continue;
986 } else {
987 return Err(e);
988 }
989 }
990 break;
991 }
992 loop {
993 if let Err(e) = conn
994 .execute("ATTACH DATABASE ? as perboot;", params![perboot_file])
995 .context("Failed to attach database perboot.")
996 {
997 if Self::is_locked_error(&e) {
998 std::thread::sleep(std::time::Duration::from_micros(500));
999 continue;
1000 } else {
1001 return Err(e);
1002 }
1003 }
1004 break;
1005 }
Janis Danisevskis4df44f42020-08-26 14:40:03 -07001006
1007 Ok(conn)
1008 }
1009
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001010 /// This function is intended to be used by the garbage collector.
1011 /// It deletes the blob given by `blob_id_to_delete`. It then tries to find a superseded
1012 /// key blob that might need special handling by the garbage collector.
1013 /// If no further superseded blobs can be found it deletes all other superseded blobs that don't
1014 /// need special handling and returns None.
1015 pub fn handle_next_superseded_blob(
1016 &mut self,
1017 blob_id_to_delete: Option<i64>,
1018 ) -> Result<Option<(i64, Vec<u8>, BlobMetaData)>> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001019 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001020 // Delete the given blob if one was given.
1021 if let Some(blob_id_to_delete) = blob_id_to_delete {
1022 tx.execute(
1023 "DELETE FROM persistent.blobmetadata WHERE blobentryid = ?;",
1024 params![blob_id_to_delete],
1025 )
1026 .context("Trying to delete blob metadata.")?;
1027 tx.execute(
1028 "DELETE FROM persistent.blobentry WHERE id = ?;",
1029 params![blob_id_to_delete],
1030 )
1031 .context("Trying to blob.")?;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001032 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001033
1034 // Find another superseded keyblob load its metadata and return it.
1035 if let Some((blob_id, blob)) = tx
1036 .query_row(
1037 "SELECT id, blob FROM persistent.blobentry
1038 WHERE subcomponent_type = ?
1039 AND (
1040 id NOT IN (
1041 SELECT MAX(id) FROM persistent.blobentry
1042 WHERE subcomponent_type = ?
1043 GROUP BY keyentryid, subcomponent_type
1044 )
1045 OR keyentryid NOT IN (SELECT id FROM persistent.keyentry)
1046 );",
1047 params![SubComponentType::KEY_BLOB, SubComponentType::KEY_BLOB],
1048 |row| Ok((row.get(0)?, row.get(1)?)),
1049 )
1050 .optional()
1051 .context("Trying to query superseded blob.")?
1052 {
1053 let blob_metadata = BlobMetaData::load_from_db(blob_id, tx)
1054 .context("Trying to load blob metadata.")?;
1055 return Ok(Some((blob_id, blob, blob_metadata))).no_gc();
1056 }
1057
1058 // We did not find any superseded key blob, so let's remove other superseded blob in
1059 // one transaction.
1060 tx.execute(
1061 "DELETE FROM persistent.blobentry
1062 WHERE NOT subcomponent_type = ?
1063 AND (
1064 id NOT IN (
1065 SELECT MAX(id) FROM persistent.blobentry
1066 WHERE NOT subcomponent_type = ?
1067 GROUP BY keyentryid, subcomponent_type
1068 ) OR keyentryid NOT IN (SELECT id FROM persistent.keyentry)
1069 );",
1070 params![SubComponentType::KEY_BLOB, SubComponentType::KEY_BLOB],
1071 )
1072 .context("Trying to purge superseded blobs.")?;
1073
1074 Ok(None).no_gc()
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001075 })
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001076 .context("In handle_next_superseded_blob.")
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001077 }
1078
1079 /// This maintenance function should be called only once before the database is used for the
1080 /// first time. It restores the invariant that `KeyLifeCycle::Existing` is a transient state.
1081 /// The function transitions all key entries from Existing to Unreferenced unconditionally and
1082 /// returns the number of rows affected. If this returns a value greater than 0, it means that
1083 /// Keystore crashed at some point during key generation. Callers may want to log such
1084 /// occurrences.
1085 /// Unlike with `mark_unreferenced`, we don't need to purge grants, because only keys that made
1086 /// it to `KeyLifeCycle::Live` may have grants.
1087 pub fn cleanup_leftovers(&mut self) -> Result<usize> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001088 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1089 tx.execute(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001090 "UPDATE persistent.keyentry SET state = ? WHERE state = ?;",
1091 params![KeyLifeCycle::Unreferenced, KeyLifeCycle::Existing],
1092 )
Janis Danisevskis66784c42021-01-27 08:40:25 -08001093 .context("Failed to execute query.")
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001094 .need_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08001095 })
1096 .context("In cleanup_leftovers.")
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001097 }
1098
Hasini Gunasinghe0e161452021-01-27 19:34:37 +00001099 /// Checks if a key exists with given key type and key descriptor properties.
1100 pub fn key_exists(
1101 &mut self,
1102 domain: Domain,
1103 nspace: i64,
1104 alias: &str,
1105 key_type: KeyType,
1106 ) -> Result<bool> {
1107 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1108 let key_descriptor =
1109 KeyDescriptor { domain, nspace, alias: Some(alias.to_string()), blob: None };
1110 let result = Self::load_key_entry_id(&tx, &key_descriptor, key_type);
1111 match result {
1112 Ok(_) => Ok(true),
1113 Err(error) => match error.root_cause().downcast_ref::<KsError>() {
1114 Some(KsError::Rc(ResponseCode::KEY_NOT_FOUND)) => Ok(false),
1115 _ => Err(error).context("In key_exists: Failed to find if the key exists."),
1116 },
1117 }
1118 .no_gc()
1119 })
1120 .context("In key_exists.")
1121 }
1122
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001123 /// Atomically loads a key entry and associated metadata or creates it using the
1124 /// callback create_new_key callback. The callback is called during a database
1125 /// transaction. This means that implementers should be mindful about using
1126 /// blocking operations such as IPC or grabbing mutexes.
1127 pub fn get_or_create_key_with<F>(
1128 &mut self,
1129 domain: Domain,
1130 namespace: i64,
1131 alias: &str,
Max Bires8e93d2b2021-01-14 13:17:59 -08001132 km_uuid: Uuid,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001133 create_new_key: F,
1134 ) -> Result<(KeyIdGuard, KeyEntry)>
1135 where
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001136 F: Fn() -> Result<(Vec<u8>, BlobMetaData)>,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001137 {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001138 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1139 let id = {
1140 let mut stmt = tx
1141 .prepare(
1142 "SELECT id FROM persistent.keyentry
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001143 WHERE
1144 key_type = ?
1145 AND domain = ?
1146 AND namespace = ?
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001147 AND alias = ?
1148 AND state = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08001149 )
1150 .context("In get_or_create_key_with: Failed to select from keyentry table.")?;
1151 let mut rows = stmt
1152 .query(params![KeyType::Super, domain.0, namespace, alias, KeyLifeCycle::Live])
1153 .context("In get_or_create_key_with: Failed to query from keyentry table.")?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001154
Janis Danisevskis66784c42021-01-27 08:40:25 -08001155 db_utils::with_rows_extract_one(&mut rows, |row| {
1156 Ok(match row {
1157 Some(r) => r.get(0).context("Failed to unpack id.")?,
1158 None => None,
1159 })
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001160 })
Janis Danisevskis66784c42021-01-27 08:40:25 -08001161 .context("In get_or_create_key_with.")?
1162 };
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001163
Janis Danisevskis66784c42021-01-27 08:40:25 -08001164 let (id, entry) = match id {
1165 Some(id) => (
1166 id,
1167 Self::load_key_components(&tx, KeyEntryLoadBits::KM, id)
1168 .context("In get_or_create_key_with.")?,
1169 ),
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001170
Janis Danisevskis66784c42021-01-27 08:40:25 -08001171 None => {
1172 let id = Self::insert_with_retry(|id| {
1173 tx.execute(
1174 "INSERT into persistent.keyentry
Max Bires8e93d2b2021-01-14 13:17:59 -08001175 (id, key_type, domain, namespace, alias, state, km_uuid)
1176 VALUES(?, ?, ?, ?, ?, ?, ?);",
Janis Danisevskis66784c42021-01-27 08:40:25 -08001177 params![
1178 id,
1179 KeyType::Super,
1180 domain.0,
1181 namespace,
1182 alias,
1183 KeyLifeCycle::Live,
1184 km_uuid,
1185 ],
1186 )
1187 })
1188 .context("In get_or_create_key_with.")?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001189
Janis Danisevskis66784c42021-01-27 08:40:25 -08001190 let (blob, metadata) =
1191 create_new_key().context("In get_or_create_key_with.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001192 Self::set_blob_internal(
1193 &tx,
1194 id,
1195 SubComponentType::KEY_BLOB,
1196 Some(&blob),
1197 Some(&metadata),
1198 )
1199 .context("In get_of_create_key_with.")?;
Janis Danisevskis66784c42021-01-27 08:40:25 -08001200 (
Janis Danisevskis377d1002021-01-27 19:07:48 -08001201 id,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001202 KeyEntry {
1203 id,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001204 key_blob_info: Some((blob, metadata)),
Janis Danisevskis66784c42021-01-27 08:40:25 -08001205 pure_cert: false,
1206 ..Default::default()
1207 },
1208 )
1209 }
1210 };
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001211 Ok((KEY_ID_LOCK.get(id), entry)).no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08001212 })
1213 .context("In get_or_create_key_with.")
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001214 }
1215
Janis Danisevskis66784c42021-01-27 08:40:25 -08001216 /// SQLite3 seems to hold a shared mutex while running the busy handler when
1217 /// waiting for the database file to become available. This makes it
1218 /// impossible to successfully recover from a locked database when the
1219 /// transaction holding the device busy is in the same process on a
1220 /// different connection. As a result the busy handler has to time out and
1221 /// fail in order to make progress.
1222 ///
1223 /// Instead, we set the busy handler to None (return immediately). And catch
1224 /// Busy and Locked errors (the latter occur on in memory databases with
1225 /// shared cache, e.g., the per-boot database.) and restart the transaction
1226 /// after a grace period of half a millisecond.
1227 ///
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001228 /// Creates a transaction with the given behavior and executes f with the new transaction.
Janis Danisevskis66784c42021-01-27 08:40:25 -08001229 /// The transaction is committed only if f returns Ok and retried if DatabaseBusy
1230 /// or DatabaseLocked is encountered.
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001231 fn with_transaction<T, F>(&mut self, behavior: TransactionBehavior, f: F) -> Result<T>
1232 where
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001233 F: Fn(&Transaction) -> Result<(bool, T)>,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001234 {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001235 loop {
1236 match self
1237 .conn
1238 .transaction_with_behavior(behavior)
1239 .context("In with_transaction.")
1240 .and_then(|tx| f(&tx).map(|result| (result, tx)))
1241 .and_then(|(result, tx)| {
1242 tx.commit().context("In with_transaction: Failed to commit transaction.")?;
1243 Ok(result)
1244 }) {
1245 Ok(result) => break Ok(result),
1246 Err(e) => {
1247 if Self::is_locked_error(&e) {
1248 std::thread::sleep(std::time::Duration::from_micros(500));
1249 continue;
1250 } else {
1251 return Err(e).context("In with_transaction.");
1252 }
1253 }
1254 }
1255 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001256 .map(|(need_gc, result)| {
1257 if need_gc {
1258 if let Some(ref gc) = self.gc {
1259 gc.notify_gc();
1260 }
1261 }
1262 result
1263 })
Janis Danisevskis66784c42021-01-27 08:40:25 -08001264 }
1265
1266 fn is_locked_error(e: &anyhow::Error) -> bool {
1267 matches!(e.root_cause().downcast_ref::<rusqlite::ffi::Error>(),
1268 Some(rusqlite::ffi::Error {
1269 code: rusqlite::ErrorCode::DatabaseBusy,
1270 ..
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001271 })
Janis Danisevskis66784c42021-01-27 08:40:25 -08001272 | Some(rusqlite::ffi::Error {
1273 code: rusqlite::ErrorCode::DatabaseLocked,
1274 ..
1275 }))
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001276 }
1277
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001278 /// Creates a new key entry and allocates a new randomized id for the new key.
1279 /// The key id gets associated with a domain and namespace but not with an alias.
1280 /// To complete key generation `rebind_alias` should be called after all of the
1281 /// key artifacts, i.e., blobs and parameters have been associated with the new
1282 /// key id. Finalizing with `rebind_alias` makes the creation of a new key entry
1283 /// atomic even if key generation is not.
Max Bires8e93d2b2021-01-14 13:17:59 -08001284 pub fn create_key_entry(
1285 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001286 domain: &Domain,
1287 namespace: &i64,
Max Bires8e93d2b2021-01-14 13:17:59 -08001288 km_uuid: &Uuid,
1289 ) -> Result<KeyIdGuard> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001290 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001291 Self::create_key_entry_internal(tx, domain, namespace, km_uuid).no_gc()
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001292 })
1293 .context("In create_key_entry.")
1294 }
1295
1296 fn create_key_entry_internal(
1297 tx: &Transaction,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001298 domain: &Domain,
1299 namespace: &i64,
Max Bires8e93d2b2021-01-14 13:17:59 -08001300 km_uuid: &Uuid,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001301 ) -> Result<KeyIdGuard> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001302 match *domain {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001303 Domain::APP | Domain::SELINUX => {}
Joel Galenson0891bc12020-07-20 10:37:03 -07001304 _ => {
1305 return Err(KsError::sys())
1306 .context(format!("Domain {:?} must be either App or SELinux.", domain));
1307 }
1308 }
Janis Danisevskisaec14592020-11-12 09:41:49 -08001309 Ok(KEY_ID_LOCK.get(
1310 Self::insert_with_retry(|id| {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001311 tx.execute(
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001312 "INSERT into persistent.keyentry
Max Bires8e93d2b2021-01-14 13:17:59 -08001313 (id, key_type, domain, namespace, alias, state, km_uuid)
1314 VALUES(?, ?, ?, ?, NULL, ?, ?);",
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001315 params![
1316 id,
1317 KeyType::Client,
1318 domain.0 as u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001319 *namespace,
Max Bires8e93d2b2021-01-14 13:17:59 -08001320 KeyLifeCycle::Existing,
1321 km_uuid,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001322 ],
Janis Danisevskisaec14592020-11-12 09:41:49 -08001323 )
1324 })
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001325 .context("In create_key_entry_internal")?,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001326 ))
Joel Galenson26f4d012020-07-17 14:57:21 -07001327 }
Joel Galenson33c04ad2020-08-03 11:04:38 -07001328
Max Bires2b2e6562020-09-22 11:22:36 -07001329 /// Creates a new attestation key entry and allocates a new randomized id for the new key.
1330 /// The key id gets associated with a domain and namespace later but not with an alias. The
1331 /// alias will be used to denote if a key has been signed as each key can only be bound to one
1332 /// domain and namespace pairing so there is no need to use them as a value for indexing into
1333 /// a key.
1334 pub fn create_attestation_key_entry(
1335 &mut self,
1336 maced_public_key: &[u8],
1337 raw_public_key: &[u8],
1338 private_key: &[u8],
1339 km_uuid: &Uuid,
1340 ) -> Result<()> {
1341 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1342 let key_id = KEY_ID_LOCK.get(
1343 Self::insert_with_retry(|id| {
1344 tx.execute(
1345 "INSERT into persistent.keyentry
1346 (id, key_type, domain, namespace, alias, state, km_uuid)
1347 VALUES(?, ?, NULL, NULL, NULL, ?, ?);",
1348 params![id, KeyType::Attestation, KeyLifeCycle::Live, km_uuid],
1349 )
1350 })
1351 .context("In create_key_entry")?,
1352 );
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001353 Self::set_blob_internal(
1354 &tx,
1355 key_id.0,
1356 SubComponentType::KEY_BLOB,
1357 Some(private_key),
1358 None,
1359 )?;
Max Bires2b2e6562020-09-22 11:22:36 -07001360 let mut metadata = KeyMetaData::new();
1361 metadata.add(KeyMetaEntry::AttestationMacedPublicKey(maced_public_key.to_vec()));
1362 metadata.add(KeyMetaEntry::AttestationRawPubKey(raw_public_key.to_vec()));
1363 metadata.store_in_db(key_id.0, &tx)?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001364 Ok(()).no_gc()
Max Bires2b2e6562020-09-22 11:22:36 -07001365 })
1366 .context("In create_attestation_key_entry")
1367 }
1368
Janis Danisevskis377d1002021-01-27 19:07:48 -08001369 /// Set a new blob and associates it with the given key id. Each blob
1370 /// has a sub component type.
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001371 /// Each key can have one of each sub component type associated. If more
1372 /// are added only the most recent can be retrieved, and superseded blobs
Janis Danisevskis377d1002021-01-27 19:07:48 -08001373 /// will get garbage collected.
1374 /// Components SubComponentType::CERT and SubComponentType::CERT_CHAIN can be
1375 /// removed by setting blob to None.
1376 pub fn set_blob(
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001377 &mut self,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001378 key_id: &KeyIdGuard,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001379 sc_type: SubComponentType,
Janis Danisevskis377d1002021-01-27 19:07:48 -08001380 blob: Option<&[u8]>,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001381 blob_metadata: Option<&BlobMetaData>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001382 ) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001383 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001384 Self::set_blob_internal(&tx, key_id.0, sc_type, blob, blob_metadata).need_gc()
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001385 })
Janis Danisevskis377d1002021-01-27 19:07:48 -08001386 .context("In set_blob.")
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001387 }
1388
Janis Danisevskis377d1002021-01-27 19:07:48 -08001389 fn set_blob_internal(
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001390 tx: &Transaction,
1391 key_id: i64,
1392 sc_type: SubComponentType,
Janis Danisevskis377d1002021-01-27 19:07:48 -08001393 blob: Option<&[u8]>,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001394 blob_metadata: Option<&BlobMetaData>,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001395 ) -> Result<()> {
Janis Danisevskis377d1002021-01-27 19:07:48 -08001396 match (blob, sc_type) {
1397 (Some(blob), _) => {
1398 tx.execute(
1399 "INSERT INTO persistent.blobentry
1400 (subcomponent_type, keyentryid, blob) VALUES (?, ?, ?);",
1401 params![sc_type, key_id, blob],
1402 )
1403 .context("In set_blob_internal: Failed to insert blob.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001404 if let Some(blob_metadata) = blob_metadata {
1405 let blob_id = tx
1406 .query_row("SELECT MAX(id) FROM persistent.blobentry;", NO_PARAMS, |row| {
1407 row.get(0)
1408 })
1409 .context("In set_blob_internal: Failed to get new blob id.")?;
1410 blob_metadata
1411 .store_in_db(blob_id, tx)
1412 .context("In set_blob_internal: Trying to store blob metadata.")?;
1413 }
Janis Danisevskis377d1002021-01-27 19:07:48 -08001414 }
1415 (None, SubComponentType::CERT) | (None, SubComponentType::CERT_CHAIN) => {
1416 tx.execute(
1417 "DELETE FROM persistent.blobentry
1418 WHERE subcomponent_type = ? AND keyentryid = ?;",
1419 params![sc_type, key_id],
1420 )
1421 .context("In set_blob_internal: Failed to delete blob.")?;
1422 }
1423 (None, _) => {
1424 return Err(KsError::sys())
1425 .context("In set_blob_internal: Other blobs cannot be deleted in this way.");
1426 }
1427 }
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001428 Ok(())
1429 }
1430
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001431 /// Inserts a collection of key parameters into the `persistent.keyparameter` table
1432 /// and associates them with the given `key_id`.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001433 #[cfg(test)]
1434 fn insert_keyparameter(&mut self, key_id: &KeyIdGuard, params: &[KeyParameter]) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001435 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001436 Self::insert_keyparameter_internal(tx, key_id, params).no_gc()
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001437 })
1438 .context("In insert_keyparameter.")
1439 }
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001440
Janis Danisevskis66784c42021-01-27 08:40:25 -08001441 fn insert_keyparameter_internal(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001442 tx: &Transaction,
1443 key_id: &KeyIdGuard,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001444 params: &[KeyParameter],
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001445 ) -> Result<()> {
1446 let mut stmt = tx
1447 .prepare(
1448 "INSERT into persistent.keyparameter (keyentryid, tag, data, security_level)
1449 VALUES (?, ?, ?, ?);",
1450 )
1451 .context("In insert_keyparameter_internal: Failed to prepare statement.")?;
1452
Janis Danisevskis66784c42021-01-27 08:40:25 -08001453 for p in params.iter() {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001454 stmt.insert(params![
1455 key_id.0,
1456 p.get_tag().0,
1457 p.key_parameter_value(),
1458 p.security_level().0
1459 ])
1460 .with_context(|| {
1461 format!("In insert_keyparameter_internal: Failed to insert {:?}", p)
1462 })?;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001463 }
1464 Ok(())
1465 }
1466
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001467 /// Insert a set of key entry specific metadata into the database.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001468 #[cfg(test)]
1469 fn insert_key_metadata(&mut self, key_id: &KeyIdGuard, metadata: &KeyMetaData) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001470 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001471 metadata.store_in_db(key_id.0, &tx).no_gc()
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001472 })
1473 .context("In insert_key_metadata.")
1474 }
1475
Max Bires2b2e6562020-09-22 11:22:36 -07001476 /// Stores a signed certificate chain signed by a remote provisioning server, keyed
1477 /// on the public key.
1478 pub fn store_signed_attestation_certificate_chain(
1479 &mut self,
1480 raw_public_key: &[u8],
1481 cert_chain: &[u8],
1482 expiration_date: i64,
1483 km_uuid: &Uuid,
1484 ) -> Result<()> {
1485 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1486 let mut stmt = tx
1487 .prepare(
1488 "SELECT keyentryid
1489 FROM persistent.keymetadata
1490 WHERE tag = ? AND data = ? AND keyentryid IN
1491 (SELECT id
1492 FROM persistent.keyentry
1493 WHERE
1494 alias IS NULL AND
1495 domain IS NULL AND
1496 namespace IS NULL AND
1497 key_type = ? AND
1498 km_uuid = ?);",
1499 )
1500 .context("Failed to store attestation certificate chain.")?;
1501 let mut rows = stmt
1502 .query(params![
1503 KeyMetaData::AttestationRawPubKey,
1504 raw_public_key,
1505 KeyType::Attestation,
1506 km_uuid
1507 ])
1508 .context("Failed to fetch keyid")?;
1509 let key_id = db_utils::with_rows_extract_one(&mut rows, |row| {
1510 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?
1511 .get(0)
1512 .context("Failed to unpack id.")
1513 })
1514 .context("Failed to get key_id.")?;
1515 let num_updated = tx
1516 .execute(
1517 "UPDATE persistent.keyentry
1518 SET alias = ?
1519 WHERE id = ?;",
1520 params!["signed", key_id],
1521 )
1522 .context("Failed to update alias.")?;
1523 if num_updated != 1 {
1524 return Err(KsError::sys()).context("Alias not updated for the key.");
1525 }
1526 let mut metadata = KeyMetaData::new();
1527 metadata.add(KeyMetaEntry::AttestationExpirationDate(DateTime::from_millis_epoch(
1528 expiration_date,
1529 )));
1530 metadata.store_in_db(key_id, &tx).context("Failed to insert key metadata.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001531 Self::set_blob_internal(
1532 &tx,
1533 key_id,
1534 SubComponentType::CERT_CHAIN,
1535 Some(cert_chain),
1536 None,
1537 )
1538 .context("Failed to insert cert chain")?;
1539 Ok(()).no_gc()
Max Bires2b2e6562020-09-22 11:22:36 -07001540 })
1541 .context("In store_signed_attestation_certificate_chain: ")
1542 }
1543
1544 /// Assigns the next unassigned attestation key to a domain/namespace combo that does not
1545 /// currently have a key assigned to it.
1546 pub fn assign_attestation_key(
1547 &mut self,
1548 domain: Domain,
1549 namespace: i64,
1550 km_uuid: &Uuid,
1551 ) -> Result<()> {
1552 match domain {
1553 Domain::APP | Domain::SELINUX => {}
1554 _ => {
1555 return Err(KsError::sys()).context(format!(
1556 concat!(
1557 "In assign_attestation_key: Domain {:?} ",
1558 "must be either App or SELinux.",
1559 ),
1560 domain
1561 ));
1562 }
1563 }
1564 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1565 let result = tx
1566 .execute(
1567 "UPDATE persistent.keyentry
1568 SET domain=?1, namespace=?2
1569 WHERE
1570 id =
1571 (SELECT MIN(id)
1572 FROM persistent.keyentry
1573 WHERE ALIAS IS NOT NULL
1574 AND domain IS NULL
1575 AND key_type IS ?3
1576 AND state IS ?4
1577 AND km_uuid IS ?5)
1578 AND
1579 (SELECT COUNT(*)
1580 FROM persistent.keyentry
1581 WHERE domain=?1
1582 AND namespace=?2
1583 AND key_type IS ?3
1584 AND state IS ?4
1585 AND km_uuid IS ?5) = 0;",
1586 params![
1587 domain.0 as u32,
1588 namespace,
1589 KeyType::Attestation,
1590 KeyLifeCycle::Live,
1591 km_uuid,
1592 ],
1593 )
1594 .context("Failed to assign attestation key")?;
1595 if result != 1 {
1596 return Err(KsError::sys()).context(format!(
1597 "Expected to update a single entry but instead updated {}.",
1598 result
1599 ));
1600 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001601 Ok(()).no_gc()
Max Bires2b2e6562020-09-22 11:22:36 -07001602 })
1603 .context("In assign_attestation_key: ")
1604 }
1605
1606 /// Retrieves num_keys number of attestation keys that have not yet been signed by a remote
1607 /// provisioning server, or the maximum number available if there are not num_keys number of
1608 /// entries in the table.
1609 pub fn fetch_unsigned_attestation_keys(
1610 &mut self,
1611 num_keys: i32,
1612 km_uuid: &Uuid,
1613 ) -> Result<Vec<Vec<u8>>> {
1614 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1615 let mut stmt = tx
1616 .prepare(
1617 "SELECT data
1618 FROM persistent.keymetadata
1619 WHERE tag = ? AND keyentryid IN
1620 (SELECT id
1621 FROM persistent.keyentry
1622 WHERE
1623 alias IS NULL AND
1624 domain IS NULL AND
1625 namespace IS NULL AND
1626 key_type = ? AND
1627 km_uuid = ?
1628 LIMIT ?);",
1629 )
1630 .context("Failed to prepare statement")?;
1631 let rows = stmt
1632 .query_map(
1633 params![
1634 KeyMetaData::AttestationMacedPublicKey,
1635 KeyType::Attestation,
1636 km_uuid,
1637 num_keys
1638 ],
1639 |row| Ok(row.get(0)?),
1640 )?
1641 .collect::<rusqlite::Result<Vec<Vec<u8>>>>()
1642 .context("Failed to execute statement")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001643 Ok(rows).no_gc()
Max Bires2b2e6562020-09-22 11:22:36 -07001644 })
1645 .context("In fetch_unsigned_attestation_keys")
1646 }
1647
1648 /// Removes any keys that have expired as of the current time. Returns the number of keys
1649 /// marked unreferenced that are bound to be garbage collected.
1650 pub fn delete_expired_attestation_keys(&mut self) -> Result<i32> {
1651 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1652 let mut stmt = tx
1653 .prepare(
1654 "SELECT keyentryid, data
1655 FROM persistent.keymetadata
1656 WHERE tag = ? AND keyentryid IN
1657 (SELECT id
1658 FROM persistent.keyentry
1659 WHERE key_type = ?);",
1660 )
1661 .context("Failed to prepare query")?;
1662 let key_ids_to_check = stmt
1663 .query_map(
1664 params![KeyMetaData::AttestationExpirationDate, KeyType::Attestation],
1665 |row| Ok((row.get(0)?, row.get(1)?)),
1666 )?
1667 .collect::<rusqlite::Result<Vec<(i64, DateTime)>>>()
1668 .context("Failed to get date metadata")?;
1669 let curr_time = DateTime::from_millis_epoch(
1670 SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_millis() as i64,
1671 );
1672 let mut num_deleted = 0;
1673 for id in key_ids_to_check.iter().filter(|kt| kt.1 < curr_time).map(|kt| kt.0) {
1674 if Self::mark_unreferenced(&tx, id)? {
1675 num_deleted += 1;
1676 }
1677 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001678 Ok(num_deleted).do_gc(num_deleted != 0)
Max Bires2b2e6562020-09-22 11:22:36 -07001679 })
1680 .context("In delete_expired_attestation_keys: ")
1681 }
1682
1683 /// Counts the number of keys that will expire by the provided epoch date and the number of
1684 /// keys not currently assigned to a domain.
1685 pub fn get_attestation_pool_status(
1686 &mut self,
1687 date: i64,
1688 km_uuid: &Uuid,
1689 ) -> Result<AttestationPoolStatus> {
1690 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1691 let mut stmt = tx.prepare(
1692 "SELECT data
1693 FROM persistent.keymetadata
1694 WHERE tag = ? AND keyentryid IN
1695 (SELECT id
1696 FROM persistent.keyentry
1697 WHERE alias IS NOT NULL
1698 AND key_type = ?
1699 AND km_uuid = ?
1700 AND state = ?);",
1701 )?;
1702 let times = stmt
1703 .query_map(
1704 params![
1705 KeyMetaData::AttestationExpirationDate,
1706 KeyType::Attestation,
1707 km_uuid,
1708 KeyLifeCycle::Live
1709 ],
1710 |row| Ok(row.get(0)?),
1711 )?
1712 .collect::<rusqlite::Result<Vec<DateTime>>>()
1713 .context("Failed to execute metadata statement")?;
1714 let expiring =
1715 times.iter().filter(|time| time < &&DateTime::from_millis_epoch(date)).count()
1716 as i32;
1717 stmt = tx.prepare(
1718 "SELECT alias, domain
1719 FROM persistent.keyentry
1720 WHERE key_type = ? AND km_uuid = ? AND state = ?;",
1721 )?;
1722 let rows = stmt
1723 .query_map(params![KeyType::Attestation, km_uuid, KeyLifeCycle::Live], |row| {
1724 Ok((row.get(0)?, row.get(1)?))
1725 })?
1726 .collect::<rusqlite::Result<Vec<(Option<String>, Option<u32>)>>>()
1727 .context("Failed to execute keyentry statement")?;
1728 let mut unassigned = 0i32;
1729 let mut attested = 0i32;
1730 let total = rows.len() as i32;
1731 for (alias, domain) in rows {
1732 match (alias, domain) {
1733 (Some(_alias), None) => {
1734 attested += 1;
1735 unassigned += 1;
1736 }
1737 (Some(_alias), Some(_domain)) => {
1738 attested += 1;
1739 }
1740 _ => {}
1741 }
1742 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001743 Ok(AttestationPoolStatus { expiring, unassigned, attested, total }).no_gc()
Max Bires2b2e6562020-09-22 11:22:36 -07001744 })
1745 .context("In get_attestation_pool_status: ")
1746 }
1747
1748 /// Fetches the private key and corresponding certificate chain assigned to a
1749 /// domain/namespace pair. Will either return nothing if the domain/namespace is
1750 /// not assigned, or one CertificateChain.
1751 pub fn retrieve_attestation_key_and_cert_chain(
1752 &mut self,
1753 domain: Domain,
1754 namespace: i64,
1755 km_uuid: &Uuid,
1756 ) -> Result<Option<CertificateChain>> {
1757 match domain {
1758 Domain::APP | Domain::SELINUX => {}
1759 _ => {
1760 return Err(KsError::sys())
1761 .context(format!("Domain {:?} must be either App or SELinux.", domain));
1762 }
1763 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001764 self.with_transaction(TransactionBehavior::Deferred, |tx| {
1765 let mut stmt = tx.prepare(
1766 "SELECT subcomponent_type, blob
Max Bires2b2e6562020-09-22 11:22:36 -07001767 FROM persistent.blobentry
1768 WHERE keyentryid IN
1769 (SELECT id
1770 FROM persistent.keyentry
1771 WHERE key_type = ?
1772 AND domain = ?
1773 AND namespace = ?
1774 AND state = ?
1775 AND km_uuid = ?);",
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001776 )?;
1777 let rows = stmt
1778 .query_map(
1779 params![
1780 KeyType::Attestation,
1781 domain.0 as u32,
1782 namespace,
1783 KeyLifeCycle::Live,
1784 km_uuid
1785 ],
1786 |row| Ok((row.get(0)?, row.get(1)?)),
1787 )?
1788 .collect::<rusqlite::Result<Vec<(SubComponentType, Vec<u8>)>>>()
1789 .context("In retrieve_attestation_key_and_cert_chain: query failed.")?;
1790 if rows.is_empty() {
1791 return Ok(None).no_gc();
1792 } else if rows.len() != 2 {
1793 return Err(KsError::sys()).context(format!(
1794 concat!(
Max Bires2b2e6562020-09-22 11:22:36 -07001795 "In retrieve_attestation_key_and_cert_chain: Expected to get a single attestation",
1796 "key chain but instead got {}."),
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001797 rows.len()
1798 ));
Max Bires2b2e6562020-09-22 11:22:36 -07001799 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001800 let mut km_blob: Vec<u8> = Vec::new();
1801 let mut cert_chain_blob: Vec<u8> = Vec::new();
1802 for row in rows {
1803 let sub_type: SubComponentType = row.0;
1804 match sub_type {
1805 SubComponentType::KEY_BLOB => {
1806 km_blob = row.1;
1807 }
1808 SubComponentType::CERT_CHAIN => {
1809 cert_chain_blob = row.1;
1810 }
1811 _ => Err(KsError::sys()).context("Unknown or incorrect subcomponent type.")?,
1812 }
1813 }
1814 Ok(Some(CertificateChain {
1815 private_key: ZVec::try_from(km_blob)?,
1816 cert_chain: ZVec::try_from(cert_chain_blob)?,
1817 }))
1818 .no_gc()
1819 })
Max Bires2b2e6562020-09-22 11:22:36 -07001820 }
1821
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001822 /// Updates the alias column of the given key id `newid` with the given alias,
1823 /// and atomically, removes the alias, domain, and namespace from another row
1824 /// with the same alias-domain-namespace tuple if such row exits.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001825 /// Returns Ok(true) if an old key was marked unreferenced as a hint to the garbage
1826 /// collector.
1827 fn rebind_alias(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001828 tx: &Transaction,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001829 newid: &KeyIdGuard,
Joel Galenson33c04ad2020-08-03 11:04:38 -07001830 alias: &str,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001831 domain: &Domain,
1832 namespace: &i64,
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001833 ) -> Result<bool> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001834 match *domain {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001835 Domain::APP | Domain::SELINUX => {}
Joel Galenson33c04ad2020-08-03 11:04:38 -07001836 _ => {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001837 return Err(KsError::sys()).context(format!(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001838 "In rebind_alias: Domain {:?} must be either App or SELinux.",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001839 domain
1840 ));
Joel Galenson33c04ad2020-08-03 11:04:38 -07001841 }
1842 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001843 let updated = tx
1844 .execute(
1845 "UPDATE persistent.keyentry
1846 SET alias = NULL, domain = NULL, namespace = NULL, state = ?
Joel Galenson33c04ad2020-08-03 11:04:38 -07001847 WHERE alias = ? AND domain = ? AND namespace = ?;",
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001848 params![KeyLifeCycle::Unreferenced, alias, domain.0 as u32, namespace],
1849 )
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001850 .context("In rebind_alias: Failed to rebind existing entry.")?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07001851 let result = tx
1852 .execute(
1853 "UPDATE persistent.keyentry
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001854 SET alias = ?, state = ?
1855 WHERE id = ? AND domain = ? AND namespace = ? AND state = ?;",
1856 params![
1857 alias,
1858 KeyLifeCycle::Live,
1859 newid.0,
1860 domain.0 as u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001861 *namespace,
Max Bires8e93d2b2021-01-14 13:17:59 -08001862 KeyLifeCycle::Existing,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001863 ],
Joel Galenson33c04ad2020-08-03 11:04:38 -07001864 )
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001865 .context("In rebind_alias: Failed to set alias.")?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07001866 if result != 1 {
Joel Galenson33c04ad2020-08-03 11:04:38 -07001867 return Err(KsError::sys()).context(format!(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001868 "In rebind_alias: Expected to update a single entry but instead updated {}.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07001869 result
1870 ));
1871 }
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001872 Ok(updated != 0)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001873 }
1874
1875 /// Store a new key in a single transaction.
1876 /// The function creates a new key entry, populates the blob, key parameter, and metadata
1877 /// fields, and rebinds the given alias to the new key.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001878 /// The boolean returned is a hint for the garbage collector. If true, a key was replaced,
1879 /// is now unreferenced and needs to be collected.
Janis Danisevskis66784c42021-01-27 08:40:25 -08001880 pub fn store_new_key(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001881 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001882 key: &KeyDescriptor,
1883 params: &[KeyParameter],
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001884 blob_info: &(&[u8], &BlobMetaData),
Max Bires8e93d2b2021-01-14 13:17:59 -08001885 cert_info: &CertificateInfo,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001886 metadata: &KeyMetaData,
Max Bires8e93d2b2021-01-14 13:17:59 -08001887 km_uuid: &Uuid,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001888 ) -> Result<KeyIdGuard> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001889 let (alias, domain, namespace) = match key {
1890 KeyDescriptor { alias: Some(alias), domain: Domain::APP, nspace, blob: None }
1891 | KeyDescriptor { alias: Some(alias), domain: Domain::SELINUX, nspace, blob: None } => {
1892 (alias, key.domain, nspace)
1893 }
1894 _ => {
1895 return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT))
1896 .context("In store_new_key: Need alias and domain must be APP or SELINUX.")
1897 }
1898 };
1899 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001900 let key_id = Self::create_key_entry_internal(tx, &domain, namespace, km_uuid)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001901 .context("Trying to create new key entry.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001902 let (blob, blob_metadata) = *blob_info;
1903 Self::set_blob_internal(
1904 tx,
1905 key_id.id(),
1906 SubComponentType::KEY_BLOB,
1907 Some(blob),
1908 Some(&blob_metadata),
1909 )
1910 .context("Trying to insert the key blob.")?;
Max Bires8e93d2b2021-01-14 13:17:59 -08001911 if let Some(cert) = &cert_info.cert {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001912 Self::set_blob_internal(tx, key_id.id(), SubComponentType::CERT, Some(&cert), None)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001913 .context("Trying to insert the certificate.")?;
1914 }
Max Bires8e93d2b2021-01-14 13:17:59 -08001915 if let Some(cert_chain) = &cert_info.cert_chain {
Janis Danisevskis377d1002021-01-27 19:07:48 -08001916 Self::set_blob_internal(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001917 tx,
1918 key_id.id(),
1919 SubComponentType::CERT_CHAIN,
Janis Danisevskis377d1002021-01-27 19:07:48 -08001920 Some(&cert_chain),
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001921 None,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001922 )
1923 .context("Trying to insert the certificate chain.")?;
1924 }
1925 Self::insert_keyparameter_internal(tx, &key_id, params)
1926 .context("Trying to insert key parameters.")?;
Janis Danisevskis377d1002021-01-27 19:07:48 -08001927 metadata.store_in_db(key_id.id(), tx).context("Trying to insert key metadata.")?;
Janis Danisevskis66784c42021-01-27 08:40:25 -08001928 let need_gc = Self::rebind_alias(tx, &key_id, &alias, &domain, namespace)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001929 .context("Trying to rebind alias.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001930 Ok(key_id).do_gc(need_gc)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001931 })
1932 .context("In store_new_key.")
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001933 }
1934
Janis Danisevskis377d1002021-01-27 19:07:48 -08001935 /// Store a new certificate
1936 /// The function creates a new key entry, populates the blob field and metadata, and rebinds
1937 /// the given alias to the new cert.
Max Bires8e93d2b2021-01-14 13:17:59 -08001938 pub fn store_new_certificate(
1939 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001940 key: &KeyDescriptor,
Max Bires8e93d2b2021-01-14 13:17:59 -08001941 cert: &[u8],
1942 km_uuid: &Uuid,
1943 ) -> Result<KeyIdGuard> {
Janis Danisevskis377d1002021-01-27 19:07:48 -08001944 let (alias, domain, namespace) = match key {
1945 KeyDescriptor { alias: Some(alias), domain: Domain::APP, nspace, blob: None }
1946 | KeyDescriptor { alias: Some(alias), domain: Domain::SELINUX, nspace, blob: None } => {
1947 (alias, key.domain, nspace)
1948 }
1949 _ => {
1950 return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT)).context(
1951 "In store_new_certificate: Need alias and domain must be APP or SELINUX.",
1952 )
1953 }
1954 };
1955 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001956 let key_id = Self::create_key_entry_internal(tx, &domain, namespace, km_uuid)
Janis Danisevskis377d1002021-01-27 19:07:48 -08001957 .context("Trying to create new key entry.")?;
1958
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001959 Self::set_blob_internal(
1960 tx,
1961 key_id.id(),
1962 SubComponentType::CERT_CHAIN,
1963 Some(cert),
1964 None,
1965 )
1966 .context("Trying to insert certificate.")?;
Janis Danisevskis377d1002021-01-27 19:07:48 -08001967
1968 let mut metadata = KeyMetaData::new();
1969 metadata.add(KeyMetaEntry::CreationDate(
1970 DateTime::now().context("Trying to make creation time.")?,
1971 ));
1972
1973 metadata.store_in_db(key_id.id(), tx).context("Trying to insert key metadata.")?;
1974
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001975 let need_gc = Self::rebind_alias(tx, &key_id, &alias, &domain, namespace)
Janis Danisevskis377d1002021-01-27 19:07:48 -08001976 .context("Trying to rebind alias.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001977 Ok(key_id).do_gc(need_gc)
Janis Danisevskis377d1002021-01-27 19:07:48 -08001978 })
1979 .context("In store_new_certificate.")
1980 }
1981
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001982 // Helper function loading the key_id given the key descriptor
1983 // tuple comprising domain, namespace, and alias.
1984 // Requires a valid transaction.
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001985 fn load_key_entry_id(tx: &Transaction, key: &KeyDescriptor, key_type: KeyType) -> Result<i64> {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001986 let alias = key
1987 .alias
1988 .as_ref()
1989 .map_or_else(|| Err(KsError::sys()), Ok)
1990 .context("In load_key_entry_id: Alias must be specified.")?;
1991 let mut stmt = tx
1992 .prepare(
1993 "SELECT id FROM persistent.keyentry
1994 WHERE
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001995 key_type = ?
1996 AND domain = ?
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001997 AND namespace = ?
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001998 AND alias = ?
1999 AND state = ?;",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002000 )
2001 .context("In load_key_entry_id: Failed to select from keyentry table.")?;
2002 let mut rows = stmt
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002003 .query(params![key_type, key.domain.0 as u32, key.nspace, alias, KeyLifeCycle::Live])
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002004 .context("In load_key_entry_id: Failed to read from keyentry table.")?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002005 db_utils::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002006 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002007 .get(0)
2008 .context("Failed to unpack id.")
2009 })
2010 .context("In load_key_entry_id.")
2011 }
2012
2013 /// This helper function completes the access tuple of a key, which is required
2014 /// to perform access control. The strategy depends on the `domain` field in the
2015 /// key descriptor.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002016 /// * Domain::SELINUX: The access tuple is complete and this function only loads
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002017 /// the key_id for further processing.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002018 /// * Domain::APP: Like Domain::SELINUX, but the tuple is completed by `caller_uid`
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002019 /// which serves as the namespace.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002020 /// * Domain::GRANT: The grant table is queried for the `key_id` and the
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002021 /// `access_vector`.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002022 /// * Domain::KEY_ID: The keyentry table is queried for the owning `domain` and
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002023 /// `namespace`.
2024 /// In each case the information returned is sufficient to perform the access
2025 /// check and the key id can be used to load further key artifacts.
2026 fn load_access_tuple(
2027 tx: &Transaction,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002028 key: &KeyDescriptor,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002029 key_type: KeyType,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002030 caller_uid: u32,
2031 ) -> Result<(i64, KeyDescriptor, Option<KeyPermSet>)> {
2032 match key.domain {
2033 // Domain App or SELinux. In this case we load the key_id from
2034 // the keyentry database for further loading of key components.
2035 // We already have the full access tuple to perform access control.
2036 // The only distinction is that we use the caller_uid instead
2037 // of the caller supplied namespace if the domain field is
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002038 // Domain::APP.
2039 Domain::APP | Domain::SELINUX => {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002040 let mut access_key = key.clone();
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002041 if access_key.domain == Domain::APP {
2042 access_key.nspace = caller_uid as i64;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002043 }
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002044 let key_id = Self::load_key_entry_id(&tx, &access_key, key_type)
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002045 .with_context(|| format!("With key.domain = {:?}.", access_key.domain))?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002046
2047 Ok((key_id, access_key, None))
2048 }
2049
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002050 // Domain::GRANT. In this case we load the key_id and the access_vector
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002051 // from the grant table.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002052 Domain::GRANT => {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002053 let mut stmt = tx
2054 .prepare(
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002055 "SELECT keyentryid, access_vector FROM persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002056 WHERE grantee = ? AND id = ?;",
2057 )
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002058 .context("Domain::GRANT prepare statement failed")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002059 let mut rows = stmt
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002060 .query(params![caller_uid as i64, key.nspace])
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002061 .context("Domain:Grant: query failed.")?;
2062 let (key_id, access_vector): (i64, i32) =
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002063 db_utils::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002064 let r =
2065 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002066 Ok((
2067 r.get(0).context("Failed to unpack key_id.")?,
2068 r.get(1).context("Failed to unpack access_vector.")?,
2069 ))
2070 })
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002071 .context("Domain::GRANT.")?;
Janis Danisevskis66784c42021-01-27 08:40:25 -08002072 Ok((key_id, key.clone(), Some(access_vector.into())))
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002073 }
2074
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002075 // Domain::KEY_ID. In this case we load the domain and namespace from the
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002076 // keyentry database because we need them for access control.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002077 Domain::KEY_ID => {
Janis Danisevskis45760022021-01-19 16:34:10 -08002078 let (domain, namespace): (Domain, i64) = {
2079 let mut stmt = tx
2080 .prepare(
2081 "SELECT domain, namespace FROM persistent.keyentry
2082 WHERE
2083 id = ?
2084 AND state = ?;",
2085 )
2086 .context("Domain::KEY_ID: prepare statement failed")?;
2087 let mut rows = stmt
2088 .query(params![key.nspace, KeyLifeCycle::Live])
2089 .context("Domain::KEY_ID: query failed.")?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002090 db_utils::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002091 let r =
2092 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002093 Ok((
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002094 Domain(r.get(0).context("Failed to unpack domain.")?),
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002095 r.get(1).context("Failed to unpack namespace.")?,
2096 ))
2097 })
Janis Danisevskis45760022021-01-19 16:34:10 -08002098 .context("Domain::KEY_ID.")?
2099 };
2100
2101 // We may use a key by id after loading it by grant.
2102 // In this case we have to check if the caller has a grant for this particular
2103 // key. We can skip this if we already know that the caller is the owner.
2104 // But we cannot know this if domain is anything but App. E.g. in the case
2105 // of Domain::SELINUX we have to speculatively check for grants because we have to
2106 // consult the SEPolicy before we know if the caller is the owner.
2107 let access_vector: Option<KeyPermSet> =
2108 if domain != Domain::APP || namespace != caller_uid as i64 {
2109 let access_vector: Option<i32> = tx
2110 .query_row(
2111 "SELECT access_vector FROM persistent.grant
2112 WHERE grantee = ? AND keyentryid = ?;",
2113 params![caller_uid as i64, key.nspace],
2114 |row| row.get(0),
2115 )
2116 .optional()
2117 .context("Domain::KEY_ID: query grant failed.")?;
2118 access_vector.map(|p| p.into())
2119 } else {
2120 None
2121 };
2122
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002123 let key_id = key.nspace;
Janis Danisevskis66784c42021-01-27 08:40:25 -08002124 let mut access_key: KeyDescriptor = key.clone();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002125 access_key.domain = domain;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002126 access_key.nspace = namespace;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002127
Janis Danisevskis45760022021-01-19 16:34:10 -08002128 Ok((key_id, access_key, access_vector))
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002129 }
2130 _ => Err(anyhow!(KsError::sys())),
2131 }
2132 }
2133
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002134 fn load_blob_components(
2135 key_id: i64,
2136 load_bits: KeyEntryLoadBits,
2137 tx: &Transaction,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002138 ) -> Result<(bool, Option<(Vec<u8>, BlobMetaData)>, Option<Vec<u8>>, Option<Vec<u8>>)> {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002139 let mut stmt = tx
2140 .prepare(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002141 "SELECT MAX(id), subcomponent_type, blob FROM persistent.blobentry
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002142 WHERE keyentryid = ? GROUP BY subcomponent_type;",
2143 )
2144 .context("In load_blob_components: prepare statement failed.")?;
2145
2146 let mut rows =
2147 stmt.query(params![key_id]).context("In load_blob_components: query failed.")?;
2148
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002149 let mut key_blob: Option<(i64, Vec<u8>)> = None;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002150 let mut cert_blob: Option<Vec<u8>> = None;
2151 let mut cert_chain_blob: Option<Vec<u8>> = None;
Janis Danisevskis377d1002021-01-27 19:07:48 -08002152 let mut has_km_blob: bool = false;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002153 db_utils::with_rows_extract_all(&mut rows, |row| {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002154 let sub_type: SubComponentType =
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002155 row.get(1).context("Failed to extract subcomponent_type.")?;
Janis Danisevskis377d1002021-01-27 19:07:48 -08002156 has_km_blob = has_km_blob || sub_type == SubComponentType::KEY_BLOB;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002157 match (sub_type, load_bits.load_public(), load_bits.load_km()) {
2158 (SubComponentType::KEY_BLOB, _, true) => {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002159 key_blob = Some((
2160 row.get(0).context("Failed to extract key blob id.")?,
2161 row.get(2).context("Failed to extract key blob.")?,
2162 ));
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002163 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002164 (SubComponentType::CERT, true, _) => {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002165 cert_blob =
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002166 Some(row.get(2).context("Failed to extract public certificate blob.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002167 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002168 (SubComponentType::CERT_CHAIN, true, _) => {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002169 cert_chain_blob =
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002170 Some(row.get(2).context("Failed to extract certificate chain blob.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002171 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002172 (SubComponentType::CERT, _, _)
2173 | (SubComponentType::CERT_CHAIN, _, _)
2174 | (SubComponentType::KEY_BLOB, _, _) => {}
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002175 _ => Err(KsError::sys()).context("Unknown subcomponent type.")?,
2176 }
2177 Ok(())
2178 })
2179 .context("In load_blob_components.")?;
2180
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002181 let blob_info = key_blob.map_or::<Result<_>, _>(Ok(None), |(blob_id, blob)| {
2182 Ok(Some((
2183 blob,
2184 BlobMetaData::load_from_db(blob_id, tx)
2185 .context("In load_blob_components: Trying to load blob_metadata.")?,
2186 )))
2187 })?;
2188
2189 Ok((has_km_blob, blob_info, cert_blob, cert_chain_blob))
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002190 }
2191
2192 fn load_key_parameters(key_id: i64, tx: &Transaction) -> Result<Vec<KeyParameter>> {
2193 let mut stmt = tx
2194 .prepare(
2195 "SELECT tag, data, security_level from persistent.keyparameter
2196 WHERE keyentryid = ?;",
2197 )
2198 .context("In load_key_parameters: prepare statement failed.")?;
2199
2200 let mut parameters: Vec<KeyParameter> = Vec::new();
2201
2202 let mut rows =
2203 stmt.query(params![key_id]).context("In load_key_parameters: query failed.")?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002204 db_utils::with_rows_extract_all(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002205 let tag = Tag(row.get(0).context("Failed to read tag.")?);
2206 let sec_level = SecurityLevel(row.get(2).context("Failed to read sec_level.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002207 parameters.push(
2208 KeyParameter::new_from_sql(tag, &SqlField::new(1, &row), sec_level)
2209 .context("Failed to read KeyParameter.")?,
2210 );
2211 Ok(())
2212 })
2213 .context("In load_key_parameters.")?;
2214
2215 Ok(parameters)
2216 }
2217
Qi Wub9433b52020-12-01 14:52:46 +08002218 /// Decrements the usage count of a limited use key. This function first checks whether the
2219 /// usage has been exhausted, if not, decreases the usage count. If the usage count reaches
2220 /// zero, the key also gets marked unreferenced and scheduled for deletion.
2221 /// Returns Ok(true) if the key was marked unreferenced as a hint to the garbage collector.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002222 pub fn check_and_update_key_usage_count(&mut self, key_id: i64) -> Result<()> {
Qi Wub9433b52020-12-01 14:52:46 +08002223 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2224 let limit: Option<i32> = tx
2225 .query_row(
2226 "SELECT data FROM persistent.keyparameter WHERE keyentryid = ? AND tag = ?;",
2227 params![key_id, Tag::USAGE_COUNT_LIMIT.0],
2228 |row| row.get(0),
2229 )
2230 .optional()
2231 .context("Trying to load usage count")?;
2232
2233 let limit = limit
2234 .ok_or(KsError::Km(ErrorCode::INVALID_KEY_BLOB))
2235 .context("The Key no longer exists. Key is exhausted.")?;
2236
2237 tx.execute(
2238 "UPDATE persistent.keyparameter
2239 SET data = data - 1
2240 WHERE keyentryid = ? AND tag = ? AND data > 0;",
2241 params![key_id, Tag::USAGE_COUNT_LIMIT.0],
2242 )
2243 .context("Failed to update key usage count.")?;
2244
2245 match limit {
2246 1 => Self::mark_unreferenced(tx, key_id)
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002247 .map(|need_gc| (need_gc, ()))
Qi Wub9433b52020-12-01 14:52:46 +08002248 .context("Trying to mark limited use key for deletion."),
2249 0 => Err(KsError::Km(ErrorCode::INVALID_KEY_BLOB)).context("Key is exhausted."),
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002250 _ => Ok(()).no_gc(),
Qi Wub9433b52020-12-01 14:52:46 +08002251 }
2252 })
2253 .context("In check_and_update_key_usage_count.")
2254 }
2255
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002256 /// Load a key entry by the given key descriptor.
2257 /// It uses the `check_permission` callback to verify if the access is allowed
2258 /// given the key access tuple read from the database using `load_access_tuple`.
2259 /// With `load_bits` the caller may specify which blobs shall be loaded from
2260 /// the blob database.
2261 pub fn load_key_entry(
2262 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002263 key: &KeyDescriptor,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002264 key_type: KeyType,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002265 load_bits: KeyEntryLoadBits,
2266 caller_uid: u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002267 check_permission: impl Fn(&KeyDescriptor, Option<KeyPermSet>) -> Result<()>,
2268 ) -> Result<(KeyIdGuard, KeyEntry)> {
2269 loop {
2270 match self.load_key_entry_internal(
2271 key,
2272 key_type,
2273 load_bits,
2274 caller_uid,
2275 &check_permission,
2276 ) {
2277 Ok(result) => break Ok(result),
2278 Err(e) => {
2279 if Self::is_locked_error(&e) {
2280 std::thread::sleep(std::time::Duration::from_micros(500));
2281 continue;
2282 } else {
2283 return Err(e).context("In load_key_entry.");
2284 }
2285 }
2286 }
2287 }
2288 }
2289
2290 fn load_key_entry_internal(
2291 &mut self,
2292 key: &KeyDescriptor,
2293 key_type: KeyType,
2294 load_bits: KeyEntryLoadBits,
2295 caller_uid: u32,
2296 check_permission: &impl Fn(&KeyDescriptor, Option<KeyPermSet>) -> Result<()>,
Janis Danisevskisaec14592020-11-12 09:41:49 -08002297 ) -> Result<(KeyIdGuard, KeyEntry)> {
2298 // KEY ID LOCK 1/2
2299 // If we got a key descriptor with a key id we can get the lock right away.
2300 // Otherwise we have to defer it until we know the key id.
2301 let key_id_guard = match key.domain {
2302 Domain::KEY_ID => Some(KEY_ID_LOCK.get(key.nspace)),
2303 _ => None,
2304 };
2305
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002306 let tx = self
2307 .conn
Janis Danisevskisaec14592020-11-12 09:41:49 -08002308 .unchecked_transaction()
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002309 .context("In load_key_entry: Failed to initialize transaction.")?;
2310
2311 // Load the key_id and complete the access control tuple.
2312 let (key_id, access_key_descriptor, access_vector) =
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002313 Self::load_access_tuple(&tx, key, key_type, caller_uid)
2314 .context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002315
2316 // Perform access control. It is vital that we return here if the permission is denied.
2317 // So do not touch that '?' at the end.
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002318 check_permission(&access_key_descriptor, access_vector).context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002319
Janis Danisevskisaec14592020-11-12 09:41:49 -08002320 // KEY ID LOCK 2/2
2321 // If we did not get a key id lock by now, it was because we got a key descriptor
2322 // without a key id. At this point we got the key id, so we can try and get a lock.
2323 // However, we cannot block here, because we are in the middle of the transaction.
2324 // So first we try to get the lock non blocking. If that fails, we roll back the
2325 // transaction and block until we get the lock. After we successfully got the lock,
2326 // we start a new transaction and load the access tuple again.
2327 //
2328 // We don't need to perform access control again, because we already established
2329 // that the caller had access to the given key. But we need to make sure that the
2330 // key id still exists. So we have to load the key entry by key id this time.
2331 let (key_id_guard, tx) = match key_id_guard {
2332 None => match KEY_ID_LOCK.try_get(key_id) {
2333 None => {
2334 // Roll back the transaction.
2335 tx.rollback().context("In load_key_entry: Failed to roll back transaction.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002336
Janis Danisevskisaec14592020-11-12 09:41:49 -08002337 // Block until we have a key id lock.
2338 let key_id_guard = KEY_ID_LOCK.get(key_id);
2339
2340 // Create a new transaction.
Janis Danisevskis66784c42021-01-27 08:40:25 -08002341 let tx = self
2342 .conn
2343 .unchecked_transaction()
2344 .context("In load_key_entry: Failed to initialize transaction.")?;
Janis Danisevskisaec14592020-11-12 09:41:49 -08002345
2346 Self::load_access_tuple(
2347 &tx,
2348 // This time we have to load the key by the retrieved key id, because the
2349 // alias may have been rebound after we rolled back the transaction.
Janis Danisevskis66784c42021-01-27 08:40:25 -08002350 &KeyDescriptor {
Janis Danisevskisaec14592020-11-12 09:41:49 -08002351 domain: Domain::KEY_ID,
2352 nspace: key_id,
2353 ..Default::default()
2354 },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002355 key_type,
Janis Danisevskisaec14592020-11-12 09:41:49 -08002356 caller_uid,
2357 )
2358 .context("In load_key_entry. (deferred key lock)")?;
2359 (key_id_guard, tx)
2360 }
2361 Some(l) => (l, tx),
2362 },
2363 Some(key_id_guard) => (key_id_guard, tx),
2364 };
2365
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002366 let key_entry = Self::load_key_components(&tx, load_bits, key_id_guard.id())
2367 .context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002368
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002369 tx.commit().context("In load_key_entry: Failed to commit transaction.")?;
2370
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002371 Ok((key_id_guard, key_entry))
2372 }
2373
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002374 fn mark_unreferenced(tx: &Transaction, key_id: i64) -> Result<bool> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002375 let updated = tx
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002376 .execute("DELETE FROM persistent.keyentry WHERE id = ?;", params![key_id])
2377 .context("Trying to delete keyentry.")?;
2378 tx.execute("DELETE FROM persistent.keymetadata WHERE keyentryid = ?;", params![key_id])
2379 .context("Trying to delete keymetadata.")?;
2380 tx.execute("DELETE FROM persistent.keyparameter WHERE keyentryid = ?;", params![key_id])
2381 .context("Trying to delete keyparameters.")?;
2382 tx.execute("DELETE FROM persistent.grant WHERE keyentryid = ?;", params![key_id])
2383 .context("Trying to delete grants.")?;
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002384 Ok(updated != 0)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002385 }
2386
2387 /// Marks the given key as unreferenced and removes all of the grants to this key.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002388 /// Returns Ok(true) if a key was marked unreferenced as a hint for the garbage collector.
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002389 pub fn unbind_key(
2390 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002391 key: &KeyDescriptor,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002392 key_type: KeyType,
2393 caller_uid: u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002394 check_permission: impl Fn(&KeyDescriptor, Option<KeyPermSet>) -> Result<()>,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002395 ) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002396 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2397 let (key_id, access_key_descriptor, access_vector) =
2398 Self::load_access_tuple(tx, key, key_type, caller_uid)
2399 .context("Trying to get access tuple.")?;
2400
2401 // Perform access control. It is vital that we return here if the permission is denied.
2402 // So do not touch that '?' at the end.
2403 check_permission(&access_key_descriptor, access_vector)
2404 .context("While checking permission.")?;
2405
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002406 Self::mark_unreferenced(tx, key_id)
2407 .map(|need_gc| (need_gc, ()))
2408 .context("Trying to mark the key unreferenced.")
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002409 })
2410 .context("In unbind_key.")
2411 }
2412
Max Bires8e93d2b2021-01-14 13:17:59 -08002413 fn get_key_km_uuid(tx: &Transaction, key_id: i64) -> Result<Uuid> {
2414 tx.query_row(
2415 "SELECT km_uuid FROM persistent.keyentry WHERE id = ?",
2416 params![key_id],
2417 |row| row.get(0),
2418 )
2419 .context("In get_key_km_uuid.")
2420 }
2421
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002422 fn load_key_components(
2423 tx: &Transaction,
2424 load_bits: KeyEntryLoadBits,
2425 key_id: i64,
2426 ) -> Result<KeyEntry> {
2427 let metadata = KeyMetaData::load_from_db(key_id, &tx).context("In load_key_components.")?;
2428
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002429 let (has_km_blob, key_blob_info, cert_blob, cert_chain_blob) =
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002430 Self::load_blob_components(key_id, load_bits, &tx)
2431 .context("In load_key_components.")?;
2432
Max Bires8e93d2b2021-01-14 13:17:59 -08002433 let parameters = Self::load_key_parameters(key_id, &tx)
2434 .context("In load_key_components: Trying to load key parameters.")?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002435
Max Bires8e93d2b2021-01-14 13:17:59 -08002436 let km_uuid = Self::get_key_km_uuid(&tx, key_id)
2437 .context("In load_key_components: Trying to get KM uuid.")?;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002438
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002439 Ok(KeyEntry {
2440 id: key_id,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002441 key_blob_info,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002442 cert: cert_blob,
2443 cert_chain: cert_chain_blob,
Max Bires8e93d2b2021-01-14 13:17:59 -08002444 km_uuid,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002445 parameters,
2446 metadata,
Janis Danisevskis377d1002021-01-27 19:07:48 -08002447 pure_cert: !has_km_blob,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002448 })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002449 }
2450
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002451 /// Returns a list of KeyDescriptors in the selected domain/namespace.
2452 /// The key descriptors will have the domain, nspace, and alias field set.
2453 /// Domain must be APP or SELINUX, the caller must make sure of that.
2454 pub fn list(&mut self, domain: Domain, namespace: i64) -> Result<Vec<KeyDescriptor>> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002455 self.with_transaction(TransactionBehavior::Deferred, |tx| {
2456 let mut stmt = tx
2457 .prepare(
2458 "SELECT alias FROM persistent.keyentry
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002459 WHERE domain = ? AND namespace = ? AND alias IS NOT NULL AND state = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08002460 )
2461 .context("In list: Failed to prepare.")?;
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002462
Janis Danisevskis66784c42021-01-27 08:40:25 -08002463 let mut rows = stmt
2464 .query(params![domain.0 as u32, namespace, KeyLifeCycle::Live])
2465 .context("In list: Failed to query.")?;
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002466
Janis Danisevskis66784c42021-01-27 08:40:25 -08002467 let mut descriptors: Vec<KeyDescriptor> = Vec::new();
2468 db_utils::with_rows_extract_all(&mut rows, |row| {
2469 descriptors.push(KeyDescriptor {
2470 domain,
2471 nspace: namespace,
2472 alias: Some(row.get(0).context("Trying to extract alias.")?),
2473 blob: None,
2474 });
2475 Ok(())
2476 })
2477 .context("In list: Failed to extract rows.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002478 Ok(descriptors).no_gc()
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002479 })
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002480 }
2481
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002482 /// Adds a grant to the grant table.
2483 /// Like `load_key_entry` this function loads the access tuple before
2484 /// it uses the callback for a permission check. Upon success,
2485 /// it inserts the `grantee_uid`, `key_id`, and `access_vector` into the
2486 /// grant table. The new row will have a randomized id, which is used as
2487 /// grant id in the namespace field of the resulting KeyDescriptor.
2488 pub fn grant(
2489 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002490 key: &KeyDescriptor,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002491 caller_uid: u32,
2492 grantee_uid: u32,
2493 access_vector: KeyPermSet,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002494 check_permission: impl Fn(&KeyDescriptor, &KeyPermSet) -> Result<()>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002495 ) -> Result<KeyDescriptor> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002496 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2497 // Load the key_id and complete the access control tuple.
2498 // We ignore the access vector here because grants cannot be granted.
2499 // The access vector returned here expresses the permissions the
2500 // grantee has if key.domain == Domain::GRANT. But this vector
2501 // cannot include the grant permission by design, so there is no way the
2502 // subsequent permission check can pass.
2503 // We could check key.domain == Domain::GRANT and fail early.
2504 // But even if we load the access tuple by grant here, the permission
2505 // check denies the attempt to create a grant by grant descriptor.
2506 let (key_id, access_key_descriptor, _) =
2507 Self::load_access_tuple(&tx, key, KeyType::Client, caller_uid)
2508 .context("In grant")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002509
Janis Danisevskis66784c42021-01-27 08:40:25 -08002510 // Perform access control. It is vital that we return here if the permission
2511 // was denied. So do not touch that '?' at the end of the line.
2512 // This permission check checks if the caller has the grant permission
2513 // for the given key and in addition to all of the permissions
2514 // expressed in `access_vector`.
2515 check_permission(&access_key_descriptor, &access_vector)
2516 .context("In grant: check_permission failed.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002517
Janis Danisevskis66784c42021-01-27 08:40:25 -08002518 let grant_id = if let Some(grant_id) = tx
2519 .query_row(
2520 "SELECT id FROM persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002521 WHERE keyentryid = ? AND grantee = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08002522 params![key_id, grantee_uid],
2523 |row| row.get(0),
2524 )
2525 .optional()
2526 .context("In grant: Failed get optional existing grant id.")?
2527 {
2528 tx.execute(
2529 "UPDATE persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002530 SET access_vector = ?
2531 WHERE id = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08002532 params![i32::from(access_vector), grant_id],
Joel Galenson845f74b2020-09-09 14:11:55 -07002533 )
Janis Danisevskis66784c42021-01-27 08:40:25 -08002534 .context("In grant: Failed to update existing grant.")?;
2535 grant_id
2536 } else {
2537 Self::insert_with_retry(|id| {
2538 tx.execute(
2539 "INSERT INTO persistent.grant (id, grantee, keyentryid, access_vector)
2540 VALUES (?, ?, ?, ?);",
2541 params![id, grantee_uid, key_id, i32::from(access_vector)],
2542 )
2543 })
2544 .context("In grant")?
2545 };
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002546
Janis Danisevskis66784c42021-01-27 08:40:25 -08002547 Ok(KeyDescriptor { domain: Domain::GRANT, nspace: grant_id, alias: None, blob: None })
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002548 .no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08002549 })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002550 }
2551
2552 /// This function checks permissions like `grant` and `load_key_entry`
2553 /// before removing a grant from the grant table.
2554 pub fn ungrant(
2555 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002556 key: &KeyDescriptor,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002557 caller_uid: u32,
2558 grantee_uid: u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002559 check_permission: impl Fn(&KeyDescriptor) -> Result<()>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002560 ) -> Result<()> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002561 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2562 // Load the key_id and complete the access control tuple.
2563 // We ignore the access vector here because grants cannot be granted.
2564 let (key_id, access_key_descriptor, _) =
2565 Self::load_access_tuple(&tx, key, KeyType::Client, caller_uid)
2566 .context("In ungrant.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002567
Janis Danisevskis66784c42021-01-27 08:40:25 -08002568 // Perform access control. We must return here if the permission
2569 // was denied. So do not touch the '?' at the end of this line.
2570 check_permission(&access_key_descriptor)
2571 .context("In grant: check_permission failed.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002572
Janis Danisevskis66784c42021-01-27 08:40:25 -08002573 tx.execute(
2574 "DELETE FROM persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002575 WHERE keyentryid = ? AND grantee = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08002576 params![key_id, grantee_uid],
2577 )
2578 .context("Failed to delete grant.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002579
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002580 Ok(()).no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08002581 })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002582 }
2583
Joel Galenson845f74b2020-09-09 14:11:55 -07002584 // Generates a random id and passes it to the given function, which will
2585 // try to insert it into a database. If that insertion fails, retry;
2586 // otherwise return the id.
2587 fn insert_with_retry(inserter: impl Fn(i64) -> rusqlite::Result<usize>) -> Result<i64> {
2588 loop {
2589 let newid: i64 = random();
2590 match inserter(newid) {
2591 // If the id already existed, try again.
2592 Err(rusqlite::Error::SqliteFailure(
2593 libsqlite3_sys::Error {
2594 code: libsqlite3_sys::ErrorCode::ConstraintViolation,
2595 extended_code: libsqlite3_sys::SQLITE_CONSTRAINT_UNIQUE,
2596 },
2597 _,
2598 )) => (),
2599 Err(e) => {
2600 return Err(e).context("In insert_with_retry: failed to insert into database.")
2601 }
2602 _ => return Ok(newid),
2603 }
2604 }
2605 }
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002606
2607 /// Insert or replace the auth token based on the UNIQUE constraint of the auth token table
2608 pub fn insert_auth_token(&mut self, auth_token: &HardwareAuthToken) -> Result<()> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002609 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2610 tx.execute(
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002611 "INSERT OR REPLACE INTO perboot.authtoken (challenge, user_id, auth_id,
2612 authenticator_type, timestamp, mac, time_received) VALUES(?, ?, ?, ?, ?, ?, ?);",
2613 params![
2614 auth_token.challenge,
2615 auth_token.userId,
2616 auth_token.authenticatorId,
2617 auth_token.authenticatorType.0 as i32,
2618 auth_token.timestamp.milliSeconds as i64,
2619 auth_token.mac,
2620 MonotonicRawTime::now(),
2621 ],
2622 )
2623 .context("In insert_auth_token: failed to insert auth token into the database")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002624 Ok(()).no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08002625 })
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002626 }
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002627
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002628 /// Find the newest auth token matching the given predicate.
2629 pub fn find_auth_token_entry<F>(
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002630 &mut self,
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002631 p: F,
2632 ) -> Result<Option<(AuthTokenEntry, MonotonicRawTime)>>
2633 where
2634 F: Fn(&AuthTokenEntry) -> bool,
2635 {
2636 self.with_transaction(TransactionBehavior::Deferred, |tx| {
2637 let mut stmt = tx
2638 .prepare("SELECT * from perboot.authtoken ORDER BY time_received DESC;")
2639 .context("Prepare statement failed.")?;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002640
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002641 let mut rows = stmt.query(NO_PARAMS).context("Failed to query.")?;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002642
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002643 while let Some(row) = rows.next().context("Failed to get next row.")? {
2644 let entry = AuthTokenEntry::new(
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002645 HardwareAuthToken {
2646 challenge: row.get(1)?,
2647 userId: row.get(2)?,
2648 authenticatorId: row.get(3)?,
2649 authenticatorType: HardwareAuthenticatorType(row.get(4)?),
2650 timestamp: Timestamp { milliSeconds: row.get(5)? },
2651 mac: row.get(6)?,
2652 },
2653 row.get(7)?,
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002654 );
2655 if p(&entry) {
2656 return Ok(Some((
2657 entry,
2658 Self::get_last_off_body(tx)
2659 .context("In find_auth_token_entry: Trying to get last off body")?,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002660 )))
2661 .no_gc();
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002662 }
2663 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002664 Ok(None).no_gc()
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002665 })
2666 .context("In find_auth_token_entry.")
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002667 }
2668
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002669 /// Insert last_off_body into the metadata table at the initialization of auth token table
Janis Danisevskis66784c42021-01-27 08:40:25 -08002670 pub fn insert_last_off_body(&mut self, last_off_body: MonotonicRawTime) -> Result<()> {
2671 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2672 tx.execute(
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002673 "INSERT OR REPLACE INTO perboot.metadata (key, value) VALUES (?, ?);",
2674 params!["last_off_body", last_off_body],
2675 )
2676 .context("In insert_last_off_body: failed to insert.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002677 Ok(()).no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08002678 })
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002679 }
2680
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002681 /// Update last_off_body when on_device_off_body is called
Janis Danisevskis66784c42021-01-27 08:40:25 -08002682 pub fn update_last_off_body(&mut self, last_off_body: MonotonicRawTime) -> Result<()> {
2683 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2684 tx.execute(
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002685 "UPDATE perboot.metadata SET value = ? WHERE key = ?;",
2686 params![last_off_body, "last_off_body"],
2687 )
2688 .context("In update_last_off_body: failed to update.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002689 Ok(()).no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08002690 })
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002691 }
2692
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002693 /// Get last_off_body time when finding auth tokens
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002694 fn get_last_off_body(tx: &Transaction) -> Result<MonotonicRawTime> {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002695 tx.query_row(
2696 "SELECT value from perboot.metadata WHERE key = ?;",
2697 params!["last_off_body"],
2698 |row| Ok(row.get(0)?),
2699 )
2700 .context("In get_last_off_body: query_row failed.")
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002701 }
Joel Galenson26f4d012020-07-17 14:57:21 -07002702}
2703
2704#[cfg(test)]
2705mod tests {
2706
2707 use super::*;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002708 use crate::key_parameter::{
2709 Algorithm, BlockMode, Digest, EcCurve, HardwareAuthenticatorType, KeyOrigin, KeyParameter,
2710 KeyParameterValue, KeyPurpose, PaddingMode, SecurityLevel,
2711 };
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002712 use crate::key_perm_set;
2713 use crate::permission::{KeyPerm, KeyPermSet};
Janis Danisevskis2a8330a2021-01-20 15:34:26 -08002714 use keystore2_test_utils::TempDir;
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002715 use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
2716 HardwareAuthToken::HardwareAuthToken,
2717 HardwareAuthenticatorType::HardwareAuthenticatorType as kmhw_authenticator_type,
Janis Danisevskisc3a496b2021-01-05 10:37:22 -08002718 };
2719 use android_hardware_security_secureclock::aidl::android::hardware::security::secureclock::{
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002720 Timestamp::Timestamp,
2721 };
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002722 use rusqlite::NO_PARAMS;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002723 use rusqlite::{Error, TransactionBehavior};
Joel Galenson0891bc12020-07-20 10:37:03 -07002724 use std::cell::RefCell;
Janis Danisevskisaec14592020-11-12 09:41:49 -08002725 use std::sync::atomic::{AtomicU8, Ordering};
2726 use std::sync::Arc;
2727 use std::thread;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002728 use std::time::{Duration, SystemTime};
Janis Danisevskis66784c42021-01-27 08:40:25 -08002729 #[cfg(disabled)]
2730 use std::time::Instant;
Joel Galenson0891bc12020-07-20 10:37:03 -07002731
Janis Danisevskis4df44f42020-08-26 14:40:03 -07002732 fn new_test_db() -> Result<KeystoreDB> {
2733 let conn = KeystoreDB::make_connection("file::memory:", "file::memory:")?;
2734
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002735 let mut db = KeystoreDB { conn, gc: None };
Janis Danisevskis66784c42021-01-27 08:40:25 -08002736 db.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002737 KeystoreDB::init_tables(tx).context("Failed to initialize tables.").no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08002738 })?;
2739 Ok(db)
Janis Danisevskis4df44f42020-08-26 14:40:03 -07002740 }
2741
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002742 fn new_test_db_with_gc<F>(path: &Path, cb: F) -> Result<KeystoreDB>
2743 where
2744 F: Fn(&Uuid, &[u8]) -> Result<()> + Send + 'static,
2745 {
2746 let gc_db = KeystoreDB::new(path, None).expect("Failed to open test gc db_connection.");
2747 let gc = Gc::new_init_with(Default::default(), move || (Box::new(cb), gc_db));
2748
2749 KeystoreDB::new(path, Some(gc))
2750 }
2751
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002752 fn rebind_alias(
2753 db: &mut KeystoreDB,
2754 newid: &KeyIdGuard,
2755 alias: &str,
2756 domain: Domain,
2757 namespace: i64,
2758 ) -> Result<bool> {
2759 db.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002760 KeystoreDB::rebind_alias(tx, newid, alias, &domain, &namespace).no_gc()
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002761 })
2762 .context("In rebind_alias.")
2763 }
2764
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002765 #[test]
2766 fn datetime() -> Result<()> {
2767 let conn = Connection::open_in_memory()?;
2768 conn.execute("CREATE TABLE test (ts DATETIME);", NO_PARAMS)?;
2769 let now = SystemTime::now();
2770 let duration = Duration::from_secs(1000);
2771 let then = now.checked_sub(duration).unwrap();
2772 let soon = now.checked_add(duration).unwrap();
2773 conn.execute(
2774 "INSERT INTO test (ts) VALUES (?), (?), (?);",
2775 params![DateTime::try_from(now)?, DateTime::try_from(then)?, DateTime::try_from(soon)?],
2776 )?;
2777 let mut stmt = conn.prepare("SELECT ts FROM test ORDER BY ts ASC;")?;
2778 let mut rows = stmt.query(NO_PARAMS)?;
2779 assert_eq!(DateTime::try_from(then)?, rows.next()?.unwrap().get(0)?);
2780 assert_eq!(DateTime::try_from(now)?, rows.next()?.unwrap().get(0)?);
2781 assert_eq!(DateTime::try_from(soon)?, rows.next()?.unwrap().get(0)?);
2782 assert!(rows.next()?.is_none());
2783 assert!(DateTime::try_from(then)? < DateTime::try_from(now)?);
2784 assert!(DateTime::try_from(then)? < DateTime::try_from(soon)?);
2785 assert!(DateTime::try_from(now)? < DateTime::try_from(soon)?);
2786 Ok(())
2787 }
2788
Joel Galenson0891bc12020-07-20 10:37:03 -07002789 // Ensure that we're using the "injected" random function, not the real one.
2790 #[test]
2791 fn test_mocked_random() {
2792 let rand1 = random();
2793 let rand2 = random();
2794 let rand3 = random();
2795 if rand1 == rand2 {
2796 assert_eq!(rand2 + 1, rand3);
2797 } else {
2798 assert_eq!(rand1 + 1, rand2);
2799 assert_eq!(rand2, rand3);
2800 }
2801 }
Joel Galenson26f4d012020-07-17 14:57:21 -07002802
Joel Galenson26f4d012020-07-17 14:57:21 -07002803 // Test that we have the correct tables.
2804 #[test]
2805 fn test_tables() -> Result<()> {
Janis Danisevskis4df44f42020-08-26 14:40:03 -07002806 let db = new_test_db()?;
Joel Galenson26f4d012020-07-17 14:57:21 -07002807 let tables = db
2808 .conn
Joel Galenson2aab4432020-07-22 15:27:57 -07002809 .prepare("SELECT name from persistent.sqlite_master WHERE type='table' ORDER BY name;")?
Joel Galenson26f4d012020-07-17 14:57:21 -07002810 .query_map(params![], |row| row.get(0))?
2811 .collect::<rusqlite::Result<Vec<String>>>()?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002812 assert_eq!(tables.len(), 6);
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002813 assert_eq!(tables[0], "blobentry");
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002814 assert_eq!(tables[1], "blobmetadata");
2815 assert_eq!(tables[2], "grant");
2816 assert_eq!(tables[3], "keyentry");
2817 assert_eq!(tables[4], "keymetadata");
2818 assert_eq!(tables[5], "keyparameter");
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002819 let tables = db
2820 .conn
2821 .prepare("SELECT name from perboot.sqlite_master WHERE type='table' ORDER BY name;")?
2822 .query_map(params![], |row| row.get(0))?
2823 .collect::<rusqlite::Result<Vec<String>>>()?;
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002824
2825 assert_eq!(tables.len(), 2);
2826 assert_eq!(tables[0], "authtoken");
2827 assert_eq!(tables[1], "metadata");
Joel Galenson2aab4432020-07-22 15:27:57 -07002828 Ok(())
2829 }
2830
2831 #[test]
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002832 fn test_auth_token_table_invariant() -> Result<()> {
2833 let mut db = new_test_db()?;
2834 let auth_token1 = HardwareAuthToken {
2835 challenge: i64::MAX,
2836 userId: 200,
2837 authenticatorId: 200,
2838 authenticatorType: kmhw_authenticator_type(kmhw_authenticator_type::PASSWORD.0),
2839 timestamp: Timestamp { milliSeconds: 500 },
2840 mac: String::from("mac").into_bytes(),
2841 };
2842 db.insert_auth_token(&auth_token1)?;
2843 let auth_tokens_returned = get_auth_tokens(&mut db)?;
2844 assert_eq!(auth_tokens_returned.len(), 1);
2845
2846 // insert another auth token with the same values for the columns in the UNIQUE constraint
2847 // of the auth token table and different value for timestamp
2848 let auth_token2 = HardwareAuthToken {
2849 challenge: i64::MAX,
2850 userId: 200,
2851 authenticatorId: 200,
2852 authenticatorType: kmhw_authenticator_type(kmhw_authenticator_type::PASSWORD.0),
2853 timestamp: Timestamp { milliSeconds: 600 },
2854 mac: String::from("mac").into_bytes(),
2855 };
2856
2857 db.insert_auth_token(&auth_token2)?;
2858 let mut auth_tokens_returned = get_auth_tokens(&mut db)?;
2859 assert_eq!(auth_tokens_returned.len(), 1);
2860
2861 if let Some(auth_token) = auth_tokens_returned.pop() {
2862 assert_eq!(auth_token.auth_token.timestamp.milliSeconds, 600);
2863 }
2864
2865 // insert another auth token with the different values for the columns in the UNIQUE
2866 // constraint of the auth token table
2867 let auth_token3 = HardwareAuthToken {
2868 challenge: i64::MAX,
2869 userId: 201,
2870 authenticatorId: 200,
2871 authenticatorType: kmhw_authenticator_type(kmhw_authenticator_type::PASSWORD.0),
2872 timestamp: Timestamp { milliSeconds: 600 },
2873 mac: String::from("mac").into_bytes(),
2874 };
2875
2876 db.insert_auth_token(&auth_token3)?;
2877 let auth_tokens_returned = get_auth_tokens(&mut db)?;
2878 assert_eq!(auth_tokens_returned.len(), 2);
2879
2880 Ok(())
2881 }
2882
2883 // utility function for test_auth_token_table_invariant()
2884 fn get_auth_tokens(db: &mut KeystoreDB) -> Result<Vec<AuthTokenEntry>> {
2885 let mut stmt = db.conn.prepare("SELECT * from perboot.authtoken;")?;
2886
2887 let auth_token_entries: Vec<AuthTokenEntry> = stmt
2888 .query_map(NO_PARAMS, |row| {
2889 Ok(AuthTokenEntry::new(
2890 HardwareAuthToken {
2891 challenge: row.get(1)?,
2892 userId: row.get(2)?,
2893 authenticatorId: row.get(3)?,
2894 authenticatorType: HardwareAuthenticatorType(row.get(4)?),
2895 timestamp: Timestamp { milliSeconds: row.get(5)? },
2896 mac: row.get(6)?,
2897 },
2898 row.get(7)?,
2899 ))
2900 })?
2901 .collect::<Result<Vec<AuthTokenEntry>, Error>>()?;
2902 Ok(auth_token_entries)
2903 }
2904
2905 #[test]
Joel Galenson2aab4432020-07-22 15:27:57 -07002906 fn test_persistence_for_files() -> Result<()> {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002907 let temp_dir = TempDir::new("persistent_db_test")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002908 let mut db = KeystoreDB::new(temp_dir.path(), None)?;
Joel Galenson2aab4432020-07-22 15:27:57 -07002909
Janis Danisevskis66784c42021-01-27 08:40:25 -08002910 db.create_key_entry(&Domain::APP, &100, &KEYSTORE_UUID)?;
Joel Galenson2aab4432020-07-22 15:27:57 -07002911 let entries = get_keyentry(&db)?;
2912 assert_eq!(entries.len(), 1);
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002913
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002914 let db = KeystoreDB::new(temp_dir.path(), None)?;
Joel Galenson2aab4432020-07-22 15:27:57 -07002915
2916 let entries_new = get_keyentry(&db)?;
2917 assert_eq!(entries, entries_new);
2918 Ok(())
2919 }
2920
2921 #[test]
Joel Galenson0891bc12020-07-20 10:37:03 -07002922 fn test_create_key_entry() -> Result<()> {
Max Bires8e93d2b2021-01-14 13:17:59 -08002923 fn extractor(ke: &KeyEntryRow) -> (Domain, i64, Option<&str>, Uuid) {
2924 (ke.domain.unwrap(), ke.namespace.unwrap(), ke.alias.as_deref(), ke.km_uuid.unwrap())
Joel Galenson0891bc12020-07-20 10:37:03 -07002925 }
2926
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002927 let mut db = new_test_db()?;
Joel Galenson0891bc12020-07-20 10:37:03 -07002928
Janis Danisevskis66784c42021-01-27 08:40:25 -08002929 db.create_key_entry(&Domain::APP, &100, &KEYSTORE_UUID)?;
2930 db.create_key_entry(&Domain::SELINUX, &101, &KEYSTORE_UUID)?;
Joel Galenson0891bc12020-07-20 10:37:03 -07002931
2932 let entries = get_keyentry(&db)?;
2933 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08002934 assert_eq!(extractor(&entries[0]), (Domain::APP, 100, None, KEYSTORE_UUID));
2935 assert_eq!(extractor(&entries[1]), (Domain::SELINUX, 101, None, KEYSTORE_UUID));
Joel Galenson0891bc12020-07-20 10:37:03 -07002936
2937 // Test that we must pass in a valid Domain.
2938 check_result_is_error_containing_string(
Janis Danisevskis66784c42021-01-27 08:40:25 -08002939 db.create_key_entry(&Domain::GRANT, &102, &KEYSTORE_UUID),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002940 "Domain Domain(1) must be either App or SELinux.",
Joel Galenson0891bc12020-07-20 10:37:03 -07002941 );
2942 check_result_is_error_containing_string(
Janis Danisevskis66784c42021-01-27 08:40:25 -08002943 db.create_key_entry(&Domain::BLOB, &103, &KEYSTORE_UUID),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002944 "Domain Domain(3) must be either App or SELinux.",
Joel Galenson0891bc12020-07-20 10:37:03 -07002945 );
2946 check_result_is_error_containing_string(
Janis Danisevskis66784c42021-01-27 08:40:25 -08002947 db.create_key_entry(&Domain::KEY_ID, &104, &KEYSTORE_UUID),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002948 "Domain Domain(4) must be either App or SELinux.",
Joel Galenson0891bc12020-07-20 10:37:03 -07002949 );
2950
2951 Ok(())
2952 }
2953
Joel Galenson33c04ad2020-08-03 11:04:38 -07002954 #[test]
Max Bires2b2e6562020-09-22 11:22:36 -07002955 fn test_add_unsigned_key() -> Result<()> {
2956 let mut db = new_test_db()?;
2957 let public_key: Vec<u8> = vec![0x01, 0x02, 0x03];
2958 let private_key: Vec<u8> = vec![0x04, 0x05, 0x06];
2959 let raw_public_key: Vec<u8> = vec![0x07, 0x08, 0x09];
2960 db.create_attestation_key_entry(
2961 &public_key,
2962 &raw_public_key,
2963 &private_key,
2964 &KEYSTORE_UUID,
2965 )?;
2966 let keys = db.fetch_unsigned_attestation_keys(5, &KEYSTORE_UUID)?;
2967 assert_eq!(keys.len(), 1);
2968 assert_eq!(keys[0], public_key);
2969 Ok(())
2970 }
2971
2972 #[test]
2973 fn test_store_signed_attestation_certificate_chain() -> Result<()> {
2974 let mut db = new_test_db()?;
2975 let expiration_date: i64 = 20;
2976 let namespace: i64 = 30;
2977 let base_byte: u8 = 1;
2978 let loaded_values =
2979 load_attestation_key_pool(&mut db, expiration_date, namespace, base_byte)?;
2980 let chain =
2981 db.retrieve_attestation_key_and_cert_chain(Domain::APP, namespace, &KEYSTORE_UUID)?;
2982 assert_eq!(true, chain.is_some());
2983 let cert_chain = chain.unwrap();
2984 assert_eq!(cert_chain.private_key.to_vec(), loaded_values[2]);
2985 assert_eq!(cert_chain.cert_chain.to_vec(), loaded_values[1]);
2986 Ok(())
2987 }
2988
2989 #[test]
2990 fn test_get_attestation_pool_status() -> Result<()> {
2991 let mut db = new_test_db()?;
2992 let namespace: i64 = 30;
2993 load_attestation_key_pool(
2994 &mut db, 10, /* expiration */
2995 namespace, 0x01, /* base_byte */
2996 )?;
2997 load_attestation_key_pool(&mut db, 20 /* expiration */, namespace + 1, 0x02)?;
2998 load_attestation_key_pool(&mut db, 40 /* expiration */, namespace + 2, 0x03)?;
2999 let mut status = db.get_attestation_pool_status(9 /* expiration */, &KEYSTORE_UUID)?;
3000 assert_eq!(status.expiring, 0);
3001 assert_eq!(status.attested, 3);
3002 assert_eq!(status.unassigned, 0);
3003 assert_eq!(status.total, 3);
3004 assert_eq!(
3005 db.get_attestation_pool_status(15 /* expiration */, &KEYSTORE_UUID)?.expiring,
3006 1
3007 );
3008 assert_eq!(
3009 db.get_attestation_pool_status(25 /* expiration */, &KEYSTORE_UUID)?.expiring,
3010 2
3011 );
3012 assert_eq!(
3013 db.get_attestation_pool_status(60 /* expiration */, &KEYSTORE_UUID)?.expiring,
3014 3
3015 );
3016 let public_key: Vec<u8> = vec![0x01, 0x02, 0x03];
3017 let private_key: Vec<u8> = vec![0x04, 0x05, 0x06];
3018 let raw_public_key: Vec<u8> = vec![0x07, 0x08, 0x09];
3019 let cert_chain: Vec<u8> = vec![0x0a, 0x0b, 0x0c];
3020 db.create_attestation_key_entry(
3021 &public_key,
3022 &raw_public_key,
3023 &private_key,
3024 &KEYSTORE_UUID,
3025 )?;
3026 status = db.get_attestation_pool_status(0 /* expiration */, &KEYSTORE_UUID)?;
3027 assert_eq!(status.attested, 3);
3028 assert_eq!(status.unassigned, 0);
3029 assert_eq!(status.total, 4);
3030 db.store_signed_attestation_certificate_chain(
3031 &raw_public_key,
3032 &cert_chain,
3033 20,
3034 &KEYSTORE_UUID,
3035 )?;
3036 status = db.get_attestation_pool_status(0 /* expiration */, &KEYSTORE_UUID)?;
3037 assert_eq!(status.attested, 4);
3038 assert_eq!(status.unassigned, 1);
3039 assert_eq!(status.total, 4);
3040 Ok(())
3041 }
3042
3043 #[test]
3044 fn test_remove_expired_certs() -> Result<()> {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003045 let temp_dir =
3046 TempDir::new("test_remove_expired_certs_").expect("Failed to create temp dir.");
3047 let mut db = new_test_db_with_gc(temp_dir.path(), |_, _| Ok(()))?;
Max Bires2b2e6562020-09-22 11:22:36 -07003048 let expiration_date: i64 =
3049 SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_millis() as i64 + 10000;
3050 let namespace: i64 = 30;
3051 let namespace_del1: i64 = 45;
3052 let namespace_del2: i64 = 60;
3053 let entry_values = load_attestation_key_pool(
3054 &mut db,
3055 expiration_date,
3056 namespace,
3057 0x01, /* base_byte */
3058 )?;
3059 load_attestation_key_pool(&mut db, 45, namespace_del1, 0x02)?;
3060 load_attestation_key_pool(&mut db, 60, namespace_del2, 0x03)?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003061
3062 let blob_entry_row_count: u32 = db
3063 .conn
3064 .query_row("SELECT COUNT(id) FROM persistent.blobentry;", NO_PARAMS, |row| row.get(0))
3065 .expect("Failed to get blob entry row count.");
3066 // We expect 6 rows here because there are two blobs per attestation key, i.e.,
3067 // One key and one certificate.
3068 assert_eq!(blob_entry_row_count, 6);
3069
Max Bires2b2e6562020-09-22 11:22:36 -07003070 assert_eq!(db.delete_expired_attestation_keys()?, 2);
3071
3072 let mut cert_chain =
3073 db.retrieve_attestation_key_and_cert_chain(Domain::APP, namespace, &KEYSTORE_UUID)?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003074 assert!(cert_chain.is_some());
Max Bires2b2e6562020-09-22 11:22:36 -07003075 let value = cert_chain.unwrap();
3076 assert_eq!(entry_values[1], value.cert_chain.to_vec());
3077 assert_eq!(entry_values[2], value.private_key.to_vec());
3078
3079 cert_chain = db.retrieve_attestation_key_and_cert_chain(
3080 Domain::APP,
3081 namespace_del1,
3082 &KEYSTORE_UUID,
3083 )?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003084 assert!(!cert_chain.is_some());
Max Bires2b2e6562020-09-22 11:22:36 -07003085 cert_chain = db.retrieve_attestation_key_and_cert_chain(
3086 Domain::APP,
3087 namespace_del2,
3088 &KEYSTORE_UUID,
3089 )?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003090 assert!(!cert_chain.is_some());
Max Bires2b2e6562020-09-22 11:22:36 -07003091
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003092 // Give the garbage collector half a second to catch up.
3093 std::thread::sleep(Duration::from_millis(500));
Max Bires2b2e6562020-09-22 11:22:36 -07003094
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003095 let blob_entry_row_count: u32 = db
3096 .conn
3097 .query_row("SELECT COUNT(id) FROM persistent.blobentry;", NO_PARAMS, |row| row.get(0))
3098 .expect("Failed to get blob entry row count.");
3099 // There shound be 2 blob entries left, because we deleted two of the attestation
3100 // key entries with two blobs each.
3101 assert_eq!(blob_entry_row_count, 2);
Max Bires2b2e6562020-09-22 11:22:36 -07003102
Max Bires2b2e6562020-09-22 11:22:36 -07003103 Ok(())
3104 }
3105
3106 #[test]
Joel Galenson33c04ad2020-08-03 11:04:38 -07003107 fn test_rebind_alias() -> Result<()> {
Max Bires8e93d2b2021-01-14 13:17:59 -08003108 fn extractor(
3109 ke: &KeyEntryRow,
3110 ) -> (Option<Domain>, Option<i64>, Option<&str>, Option<Uuid>) {
3111 (ke.domain, ke.namespace, ke.alias.as_deref(), ke.km_uuid)
Joel Galenson33c04ad2020-08-03 11:04:38 -07003112 }
3113
Janis Danisevskis4df44f42020-08-26 14:40:03 -07003114 let mut db = new_test_db()?;
Janis Danisevskis66784c42021-01-27 08:40:25 -08003115 db.create_key_entry(&Domain::APP, &42, &KEYSTORE_UUID)?;
3116 db.create_key_entry(&Domain::APP, &42, &KEYSTORE_UUID)?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07003117 let entries = get_keyentry(&db)?;
3118 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08003119 assert_eq!(
3120 extractor(&entries[0]),
3121 (Some(Domain::APP), Some(42), None, Some(KEYSTORE_UUID))
3122 );
3123 assert_eq!(
3124 extractor(&entries[1]),
3125 (Some(Domain::APP), Some(42), None, Some(KEYSTORE_UUID))
3126 );
Joel Galenson33c04ad2020-08-03 11:04:38 -07003127
3128 // Test that the first call to rebind_alias sets the alias.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003129 rebind_alias(&mut db, &KEY_ID_LOCK.get(entries[0].id), "foo", Domain::APP, 42)?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07003130 let entries = get_keyentry(&db)?;
3131 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08003132 assert_eq!(
3133 extractor(&entries[0]),
3134 (Some(Domain::APP), Some(42), Some("foo"), Some(KEYSTORE_UUID))
3135 );
3136 assert_eq!(
3137 extractor(&entries[1]),
3138 (Some(Domain::APP), Some(42), None, Some(KEYSTORE_UUID))
3139 );
Joel Galenson33c04ad2020-08-03 11:04:38 -07003140
3141 // Test that the second call to rebind_alias also empties the old one.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003142 rebind_alias(&mut db, &KEY_ID_LOCK.get(entries[1].id), "foo", Domain::APP, 42)?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07003143 let entries = get_keyentry(&db)?;
3144 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08003145 assert_eq!(extractor(&entries[0]), (None, None, None, Some(KEYSTORE_UUID)));
3146 assert_eq!(
3147 extractor(&entries[1]),
3148 (Some(Domain::APP), Some(42), Some("foo"), Some(KEYSTORE_UUID))
3149 );
Joel Galenson33c04ad2020-08-03 11:04:38 -07003150
3151 // Test that we must pass in a valid Domain.
3152 check_result_is_error_containing_string(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003153 rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::GRANT, 42),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003154 "Domain Domain(1) must be either App or SELinux.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07003155 );
3156 check_result_is_error_containing_string(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003157 rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::BLOB, 42),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003158 "Domain Domain(3) must be either App or SELinux.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07003159 );
3160 check_result_is_error_containing_string(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003161 rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::KEY_ID, 42),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003162 "Domain Domain(4) must be either App or SELinux.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07003163 );
3164
3165 // Test that we correctly handle setting an alias for something that does not exist.
3166 check_result_is_error_containing_string(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003167 rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::SELINUX, 42),
Joel Galenson33c04ad2020-08-03 11:04:38 -07003168 "Expected to update a single entry but instead updated 0",
3169 );
3170 // Test that we correctly abort the transaction in this case.
3171 let entries = get_keyentry(&db)?;
3172 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08003173 assert_eq!(extractor(&entries[0]), (None, None, None, Some(KEYSTORE_UUID)));
3174 assert_eq!(
3175 extractor(&entries[1]),
3176 (Some(Domain::APP), Some(42), Some("foo"), Some(KEYSTORE_UUID))
3177 );
Joel Galenson33c04ad2020-08-03 11:04:38 -07003178
3179 Ok(())
3180 }
3181
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003182 #[test]
3183 fn test_grant_ungrant() -> Result<()> {
3184 const CALLER_UID: u32 = 15;
3185 const GRANTEE_UID: u32 = 12;
3186 const SELINUX_NAMESPACE: i64 = 7;
3187
3188 let mut db = new_test_db()?;
3189 db.conn.execute(
Max Bires8e93d2b2021-01-14 13:17:59 -08003190 "INSERT INTO persistent.keyentry (id, key_type, domain, namespace, alias, state, km_uuid)
3191 VALUES (1, 0, 0, 15, 'key', 1, ?), (2, 0, 2, 7, 'yek', 1, ?);",
3192 params![KEYSTORE_UUID, KEYSTORE_UUID],
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003193 )?;
3194 let app_key = KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003195 domain: super::Domain::APP,
3196 nspace: 0,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003197 alias: Some("key".to_string()),
3198 blob: None,
3199 };
3200 const PVEC1: KeyPermSet = key_perm_set![KeyPerm::use_(), KeyPerm::get_info()];
3201 const PVEC2: KeyPermSet = key_perm_set![KeyPerm::use_()];
3202
3203 // Reset totally predictable random number generator in case we
3204 // are not the first test running on this thread.
3205 reset_random();
3206 let next_random = 0i64;
3207
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003208 let app_granted_key = db
Janis Danisevskis66784c42021-01-27 08:40:25 -08003209 .grant(&app_key, CALLER_UID, GRANTEE_UID, PVEC1, |k, a| {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003210 assert_eq!(*a, PVEC1);
3211 assert_eq!(
3212 *k,
3213 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003214 domain: super::Domain::APP,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003215 // namespace must be set to the caller_uid.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003216 nspace: CALLER_UID as i64,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003217 alias: Some("key".to_string()),
3218 blob: None,
3219 }
3220 );
3221 Ok(())
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003222 })
3223 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003224
3225 assert_eq!(
3226 app_granted_key,
3227 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003228 domain: super::Domain::GRANT,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003229 // The grantid is next_random due to the mock random number generator.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003230 nspace: next_random,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003231 alias: None,
3232 blob: None,
3233 }
3234 );
3235
3236 let selinux_key = KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003237 domain: super::Domain::SELINUX,
3238 nspace: SELINUX_NAMESPACE,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003239 alias: Some("yek".to_string()),
3240 blob: None,
3241 };
3242
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003243 let selinux_granted_key = db
Janis Danisevskis66784c42021-01-27 08:40:25 -08003244 .grant(&selinux_key, CALLER_UID, 12, PVEC1, |k, a| {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003245 assert_eq!(*a, PVEC1);
3246 assert_eq!(
3247 *k,
3248 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003249 domain: super::Domain::SELINUX,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003250 // namespace must be the supplied SELinux
3251 // namespace.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003252 nspace: SELINUX_NAMESPACE,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003253 alias: Some("yek".to_string()),
3254 blob: None,
3255 }
3256 );
3257 Ok(())
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003258 })
3259 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003260
3261 assert_eq!(
3262 selinux_granted_key,
3263 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003264 domain: super::Domain::GRANT,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003265 // The grantid is next_random + 1 due to the mock random number generator.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003266 nspace: next_random + 1,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003267 alias: None,
3268 blob: None,
3269 }
3270 );
3271
3272 // This should update the existing grant with PVEC2.
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003273 let selinux_granted_key = db
Janis Danisevskis66784c42021-01-27 08:40:25 -08003274 .grant(&selinux_key, CALLER_UID, 12, PVEC2, |k, a| {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003275 assert_eq!(*a, PVEC2);
3276 assert_eq!(
3277 *k,
3278 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003279 domain: super::Domain::SELINUX,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003280 // namespace must be the supplied SELinux
3281 // namespace.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003282 nspace: SELINUX_NAMESPACE,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003283 alias: Some("yek".to_string()),
3284 blob: None,
3285 }
3286 );
3287 Ok(())
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003288 })
3289 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003290
3291 assert_eq!(
3292 selinux_granted_key,
3293 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003294 domain: super::Domain::GRANT,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003295 // Same grant id as before. The entry was only updated.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003296 nspace: next_random + 1,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003297 alias: None,
3298 blob: None,
3299 }
3300 );
3301
3302 {
3303 // Limiting scope of stmt, because it borrows db.
3304 let mut stmt = db
3305 .conn
Janis Danisevskisbf15d732020-12-08 10:35:26 -08003306 .prepare("SELECT id, grantee, keyentryid, access_vector FROM persistent.grant;")?;
Janis Danisevskisee10b5f2020-09-22 16:42:35 -07003307 let mut rows =
3308 stmt.query_map::<(i64, u32, i64, KeyPermSet), _, _>(NO_PARAMS, |row| {
3309 Ok((
3310 row.get(0)?,
3311 row.get(1)?,
3312 row.get(2)?,
3313 KeyPermSet::from(row.get::<_, i32>(3)?),
3314 ))
3315 })?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003316
3317 let r = rows.next().unwrap().unwrap();
Janis Danisevskisee10b5f2020-09-22 16:42:35 -07003318 assert_eq!(r, (next_random, GRANTEE_UID, 1, PVEC1));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003319 let r = rows.next().unwrap().unwrap();
Janis Danisevskisee10b5f2020-09-22 16:42:35 -07003320 assert_eq!(r, (next_random + 1, GRANTEE_UID, 2, PVEC2));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003321 assert!(rows.next().is_none());
3322 }
3323
3324 debug_dump_keyentry_table(&mut db)?;
3325 println!("app_key {:?}", app_key);
3326 println!("selinux_key {:?}", selinux_key);
3327
Janis Danisevskis66784c42021-01-27 08:40:25 -08003328 db.ungrant(&app_key, CALLER_UID, GRANTEE_UID, |_| Ok(()))?;
3329 db.ungrant(&selinux_key, CALLER_UID, GRANTEE_UID, |_| Ok(()))?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003330
3331 Ok(())
3332 }
3333
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003334 static TEST_KEY_BLOB: &[u8] = b"my test blob";
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003335 static TEST_CERT_BLOB: &[u8] = b"my test cert";
3336 static TEST_CERT_CHAIN_BLOB: &[u8] = b"my test cert_chain";
3337
3338 #[test]
Janis Danisevskis377d1002021-01-27 19:07:48 -08003339 fn test_set_blob() -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003340 let key_id = KEY_ID_LOCK.get(3000);
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003341 let mut db = new_test_db()?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003342 let mut blob_metadata = BlobMetaData::new();
3343 blob_metadata.add(BlobMetaEntry::KmUuid(KEYSTORE_UUID));
3344 db.set_blob(
3345 &key_id,
3346 SubComponentType::KEY_BLOB,
3347 Some(TEST_KEY_BLOB),
3348 Some(&blob_metadata),
3349 )?;
3350 db.set_blob(&key_id, SubComponentType::CERT, Some(TEST_CERT_BLOB), None)?;
3351 db.set_blob(&key_id, SubComponentType::CERT_CHAIN, Some(TEST_CERT_CHAIN_BLOB), None)?;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003352 drop(key_id);
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003353
3354 let mut stmt = db.conn.prepare(
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003355 "SELECT subcomponent_type, keyentryid, blob, id FROM persistent.blobentry
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003356 ORDER BY subcomponent_type ASC;",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003357 )?;
3358 let mut rows = stmt
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003359 .query_map::<((SubComponentType, i64, Vec<u8>), i64), _, _>(NO_PARAMS, |row| {
3360 Ok(((row.get(0)?, row.get(1)?, row.get(2)?), row.get(3)?))
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003361 })?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003362 let (r, id) = rows.next().unwrap().unwrap();
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003363 assert_eq!(r, (SubComponentType::KEY_BLOB, 3000, TEST_KEY_BLOB.to_vec()));
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003364 let (r, _) = rows.next().unwrap().unwrap();
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003365 assert_eq!(r, (SubComponentType::CERT, 3000, TEST_CERT_BLOB.to_vec()));
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003366 let (r, _) = rows.next().unwrap().unwrap();
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003367 assert_eq!(r, (SubComponentType::CERT_CHAIN, 3000, TEST_CERT_CHAIN_BLOB.to_vec()));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003368
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003369 drop(rows);
3370 drop(stmt);
3371
3372 assert_eq!(
3373 db.with_transaction(TransactionBehavior::Immediate, |tx| {
3374 BlobMetaData::load_from_db(id, tx).no_gc()
3375 })
3376 .expect("Should find blob metadata."),
3377 blob_metadata
3378 );
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003379 Ok(())
3380 }
3381
3382 static TEST_ALIAS: &str = "my super duper key";
3383
3384 #[test]
3385 fn test_insert_and_load_full_keyentry_domain_app() -> Result<()> {
3386 let mut db = new_test_db()?;
Qi Wub9433b52020-12-01 14:52:46 +08003387 let key_id = make_test_key_entry(&mut db, Domain::APP, 1, TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08003388 .context("test_insert_and_load_full_keyentry_domain_app")?
3389 .0;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003390 let (_key_guard, key_entry) = db
3391 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003392 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003393 domain: Domain::APP,
3394 nspace: 0,
3395 alias: Some(TEST_ALIAS.to_string()),
3396 blob: None,
3397 },
3398 KeyType::Client,
3399 KeyEntryLoadBits::BOTH,
3400 1,
3401 |_k, _av| Ok(()),
3402 )
3403 .unwrap();
Qi Wub9433b52020-12-01 14:52:46 +08003404 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003405
3406 db.unbind_key(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003407 &KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003408 domain: Domain::APP,
3409 nspace: 0,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003410 alias: Some(TEST_ALIAS.to_string()),
3411 blob: None,
3412 },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003413 KeyType::Client,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003414 1,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003415 |_, _| Ok(()),
3416 )
3417 .unwrap();
3418
3419 assert_eq!(
3420 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
3421 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003422 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003423 domain: Domain::APP,
3424 nspace: 0,
3425 alias: Some(TEST_ALIAS.to_string()),
3426 blob: None,
3427 },
3428 KeyType::Client,
3429 KeyEntryLoadBits::NONE,
3430 1,
3431 |_k, _av| Ok(()),
3432 )
3433 .unwrap_err()
3434 .root_cause()
3435 .downcast_ref::<KsError>()
3436 );
3437
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003438 Ok(())
3439 }
3440
3441 #[test]
Janis Danisevskis377d1002021-01-27 19:07:48 -08003442 fn test_insert_and_load_certificate_entry_domain_app() -> Result<()> {
3443 let mut db = new_test_db()?;
3444
3445 db.store_new_certificate(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003446 &KeyDescriptor {
Janis Danisevskis377d1002021-01-27 19:07:48 -08003447 domain: Domain::APP,
3448 nspace: 1,
3449 alias: Some(TEST_ALIAS.to_string()),
3450 blob: None,
3451 },
3452 TEST_CERT_BLOB,
Max Bires8e93d2b2021-01-14 13:17:59 -08003453 &KEYSTORE_UUID,
Janis Danisevskis377d1002021-01-27 19:07:48 -08003454 )
3455 .expect("Trying to insert cert.");
3456
3457 let (_key_guard, mut key_entry) = db
3458 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003459 &KeyDescriptor {
Janis Danisevskis377d1002021-01-27 19:07:48 -08003460 domain: Domain::APP,
3461 nspace: 1,
3462 alias: Some(TEST_ALIAS.to_string()),
3463 blob: None,
3464 },
3465 KeyType::Client,
3466 KeyEntryLoadBits::PUBLIC,
3467 1,
3468 |_k, _av| Ok(()),
3469 )
3470 .expect("Trying to read certificate entry.");
3471
3472 assert!(key_entry.pure_cert());
3473 assert!(key_entry.cert().is_none());
3474 assert_eq!(key_entry.take_cert_chain(), Some(TEST_CERT_BLOB.to_vec()));
3475
3476 db.unbind_key(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003477 &KeyDescriptor {
Janis Danisevskis377d1002021-01-27 19:07:48 -08003478 domain: Domain::APP,
3479 nspace: 1,
3480 alias: Some(TEST_ALIAS.to_string()),
3481 blob: None,
3482 },
3483 KeyType::Client,
3484 1,
3485 |_, _| Ok(()),
3486 )
3487 .unwrap();
3488
3489 assert_eq!(
3490 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
3491 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003492 &KeyDescriptor {
Janis Danisevskis377d1002021-01-27 19:07:48 -08003493 domain: Domain::APP,
3494 nspace: 1,
3495 alias: Some(TEST_ALIAS.to_string()),
3496 blob: None,
3497 },
3498 KeyType::Client,
3499 KeyEntryLoadBits::NONE,
3500 1,
3501 |_k, _av| Ok(()),
3502 )
3503 .unwrap_err()
3504 .root_cause()
3505 .downcast_ref::<KsError>()
3506 );
3507
3508 Ok(())
3509 }
3510
3511 #[test]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003512 fn test_insert_and_load_full_keyentry_domain_selinux() -> Result<()> {
3513 let mut db = new_test_db()?;
Qi Wub9433b52020-12-01 14:52:46 +08003514 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08003515 .context("test_insert_and_load_full_keyentry_domain_selinux")?
3516 .0;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003517 let (_key_guard, key_entry) = db
3518 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003519 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003520 domain: Domain::SELINUX,
3521 nspace: 1,
3522 alias: Some(TEST_ALIAS.to_string()),
3523 blob: None,
3524 },
3525 KeyType::Client,
3526 KeyEntryLoadBits::BOTH,
3527 1,
3528 |_k, _av| Ok(()),
3529 )
3530 .unwrap();
Qi Wub9433b52020-12-01 14:52:46 +08003531 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003532
3533 db.unbind_key(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003534 &KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003535 domain: Domain::SELINUX,
3536 nspace: 1,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003537 alias: Some(TEST_ALIAS.to_string()),
3538 blob: None,
3539 },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003540 KeyType::Client,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003541 1,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003542 |_, _| Ok(()),
3543 )
3544 .unwrap();
3545
3546 assert_eq!(
3547 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
3548 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003549 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003550 domain: Domain::SELINUX,
3551 nspace: 1,
3552 alias: Some(TEST_ALIAS.to_string()),
3553 blob: None,
3554 },
3555 KeyType::Client,
3556 KeyEntryLoadBits::NONE,
3557 1,
3558 |_k, _av| Ok(()),
3559 )
3560 .unwrap_err()
3561 .root_cause()
3562 .downcast_ref::<KsError>()
3563 );
3564
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003565 Ok(())
3566 }
3567
3568 #[test]
3569 fn test_insert_and_load_full_keyentry_domain_key_id() -> Result<()> {
3570 let mut db = new_test_db()?;
Qi Wub9433b52020-12-01 14:52:46 +08003571 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08003572 .context("test_insert_and_load_full_keyentry_domain_key_id")?
3573 .0;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003574 let (_, key_entry) = db
3575 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003576 &KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003577 KeyType::Client,
3578 KeyEntryLoadBits::BOTH,
3579 1,
3580 |_k, _av| Ok(()),
3581 )
3582 .unwrap();
3583
Qi Wub9433b52020-12-01 14:52:46 +08003584 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003585
3586 db.unbind_key(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003587 &KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003588 KeyType::Client,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003589 1,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003590 |_, _| Ok(()),
3591 )
3592 .unwrap();
3593
3594 assert_eq!(
3595 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
3596 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003597 &KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003598 KeyType::Client,
3599 KeyEntryLoadBits::NONE,
3600 1,
3601 |_k, _av| Ok(()),
3602 )
3603 .unwrap_err()
3604 .root_cause()
3605 .downcast_ref::<KsError>()
3606 );
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003607
3608 Ok(())
3609 }
3610
3611 #[test]
Qi Wub9433b52020-12-01 14:52:46 +08003612 fn test_check_and_update_key_usage_count_with_limited_use_key() -> Result<()> {
3613 let mut db = new_test_db()?;
3614 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, Some(123))
3615 .context("test_check_and_update_key_usage_count_with_limited_use_key")?
3616 .0;
3617 // Update the usage count of the limited use key.
3618 db.check_and_update_key_usage_count(key_id)?;
3619
3620 let (_key_guard, key_entry) = db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003621 &KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
Qi Wub9433b52020-12-01 14:52:46 +08003622 KeyType::Client,
3623 KeyEntryLoadBits::BOTH,
3624 1,
3625 |_k, _av| Ok(()),
3626 )?;
3627
3628 // The usage count is decremented now.
3629 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, Some(122)));
3630
3631 Ok(())
3632 }
3633
3634 #[test]
3635 fn test_check_and_update_key_usage_count_with_exhausted_limited_use_key() -> Result<()> {
3636 let mut db = new_test_db()?;
3637 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, Some(1))
3638 .context("test_check_and_update_key_usage_count_with_exhausted_limited_use_key")?
3639 .0;
3640 // Update the usage count of the limited use key.
3641 db.check_and_update_key_usage_count(key_id).expect(concat!(
3642 "In test_check_and_update_key_usage_count_with_exhausted_limited_use_key: ",
3643 "This should succeed."
3644 ));
3645
3646 // Try to update the exhausted limited use key.
3647 let e = db.check_and_update_key_usage_count(key_id).expect_err(concat!(
3648 "In test_check_and_update_key_usage_count_with_exhausted_limited_use_key: ",
3649 "This should fail."
3650 ));
3651 assert_eq!(
3652 &KsError::Km(ErrorCode::INVALID_KEY_BLOB),
3653 e.root_cause().downcast_ref::<KsError>().unwrap()
3654 );
3655
3656 Ok(())
3657 }
3658
3659 #[test]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003660 fn test_insert_and_load_full_keyentry_from_grant() -> Result<()> {
3661 let mut db = new_test_db()?;
Qi Wub9433b52020-12-01 14:52:46 +08003662 let key_id = make_test_key_entry(&mut db, Domain::APP, 1, TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08003663 .context("test_insert_and_load_full_keyentry_from_grant")?
3664 .0;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003665
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003666 let granted_key = db
3667 .grant(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003668 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003669 domain: Domain::APP,
3670 nspace: 0,
3671 alias: Some(TEST_ALIAS.to_string()),
3672 blob: None,
3673 },
3674 1,
3675 2,
3676 key_perm_set![KeyPerm::use_()],
3677 |_k, _av| Ok(()),
3678 )
3679 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003680
3681 debug_dump_grant_table(&mut db)?;
3682
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003683 let (_key_guard, key_entry) = db
Janis Danisevskis66784c42021-01-27 08:40:25 -08003684 .load_key_entry(&granted_key, KeyType::Client, KeyEntryLoadBits::BOTH, 2, |k, av| {
3685 assert_eq!(Domain::GRANT, k.domain);
3686 assert!(av.unwrap().includes(KeyPerm::use_()));
3687 Ok(())
3688 })
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003689 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003690
Qi Wub9433b52020-12-01 14:52:46 +08003691 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003692
Janis Danisevskis66784c42021-01-27 08:40:25 -08003693 db.unbind_key(&granted_key, KeyType::Client, 2, |_, _| Ok(())).unwrap();
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003694
3695 assert_eq!(
3696 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
3697 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003698 &granted_key,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003699 KeyType::Client,
3700 KeyEntryLoadBits::NONE,
3701 2,
3702 |_k, _av| Ok(()),
3703 )
3704 .unwrap_err()
3705 .root_cause()
3706 .downcast_ref::<KsError>()
3707 );
3708
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003709 Ok(())
3710 }
3711
Janis Danisevskis45760022021-01-19 16:34:10 -08003712 // This test attempts to load a key by key id while the caller is not the owner
3713 // but a grant exists for the given key and the caller.
3714 #[test]
3715 fn test_insert_and_load_full_keyentry_from_grant_by_key_id() -> Result<()> {
3716 let mut db = new_test_db()?;
3717 const OWNER_UID: u32 = 1u32;
3718 const GRANTEE_UID: u32 = 2u32;
3719 const SOMEONE_ELSE_UID: u32 = 3u32;
3720 let key_id = make_test_key_entry(&mut db, Domain::APP, OWNER_UID as i64, TEST_ALIAS, None)
3721 .context("test_insert_and_load_full_keyentry_from_grant_by_key_id")?
3722 .0;
3723
3724 db.grant(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003725 &KeyDescriptor {
Janis Danisevskis45760022021-01-19 16:34:10 -08003726 domain: Domain::APP,
3727 nspace: 0,
3728 alias: Some(TEST_ALIAS.to_string()),
3729 blob: None,
3730 },
3731 OWNER_UID,
3732 GRANTEE_UID,
3733 key_perm_set![KeyPerm::use_()],
3734 |_k, _av| Ok(()),
3735 )
3736 .unwrap();
3737
3738 debug_dump_grant_table(&mut db)?;
3739
3740 let id_descriptor =
3741 KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, ..Default::default() };
3742
3743 let (_, key_entry) = db
3744 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003745 &id_descriptor,
Janis Danisevskis45760022021-01-19 16:34:10 -08003746 KeyType::Client,
3747 KeyEntryLoadBits::BOTH,
3748 GRANTEE_UID,
3749 |k, av| {
3750 assert_eq!(Domain::APP, k.domain);
3751 assert_eq!(OWNER_UID as i64, k.nspace);
3752 assert!(av.unwrap().includes(KeyPerm::use_()));
3753 Ok(())
3754 },
3755 )
3756 .unwrap();
3757
3758 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
3759
3760 let (_, key_entry) = db
3761 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003762 &id_descriptor,
Janis Danisevskis45760022021-01-19 16:34:10 -08003763 KeyType::Client,
3764 KeyEntryLoadBits::BOTH,
3765 SOMEONE_ELSE_UID,
3766 |k, av| {
3767 assert_eq!(Domain::APP, k.domain);
3768 assert_eq!(OWNER_UID as i64, k.nspace);
3769 assert!(av.is_none());
3770 Ok(())
3771 },
3772 )
3773 .unwrap();
3774
3775 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
3776
Janis Danisevskis66784c42021-01-27 08:40:25 -08003777 db.unbind_key(&id_descriptor, KeyType::Client, OWNER_UID, |_, _| Ok(())).unwrap();
Janis Danisevskis45760022021-01-19 16:34:10 -08003778
3779 assert_eq!(
3780 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
3781 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003782 &id_descriptor,
Janis Danisevskis45760022021-01-19 16:34:10 -08003783 KeyType::Client,
3784 KeyEntryLoadBits::NONE,
3785 GRANTEE_UID,
3786 |_k, _av| Ok(()),
3787 )
3788 .unwrap_err()
3789 .root_cause()
3790 .downcast_ref::<KsError>()
3791 );
3792
3793 Ok(())
3794 }
3795
Janis Danisevskisaec14592020-11-12 09:41:49 -08003796 static KEY_LOCK_TEST_ALIAS: &str = "my super duper locked key";
3797
Janis Danisevskisaec14592020-11-12 09:41:49 -08003798 #[test]
3799 fn test_insert_and_load_full_keyentry_domain_app_concurrently() -> Result<()> {
3800 let handle = {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08003801 let temp_dir = Arc::new(TempDir::new("id_lock_test")?);
3802 let temp_dir_clone = temp_dir.clone();
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003803 let mut db = KeystoreDB::new(temp_dir.path(), None)?;
Qi Wub9433b52020-12-01 14:52:46 +08003804 let key_id = make_test_key_entry(&mut db, Domain::APP, 33, KEY_LOCK_TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08003805 .context("test_insert_and_load_full_keyentry_domain_app")?
3806 .0;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003807 let (_key_guard, key_entry) = db
3808 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003809 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003810 domain: Domain::APP,
3811 nspace: 0,
3812 alias: Some(KEY_LOCK_TEST_ALIAS.to_string()),
3813 blob: None,
3814 },
3815 KeyType::Client,
3816 KeyEntryLoadBits::BOTH,
3817 33,
3818 |_k, _av| Ok(()),
3819 )
3820 .unwrap();
Qi Wub9433b52020-12-01 14:52:46 +08003821 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskisaec14592020-11-12 09:41:49 -08003822 let state = Arc::new(AtomicU8::new(1));
3823 let state2 = state.clone();
3824
3825 // Spawning a second thread that attempts to acquire the key id lock
3826 // for the same key as the primary thread. The primary thread then
3827 // waits, thereby forcing the secondary thread into the second stage
3828 // of acquiring the lock (see KEY ID LOCK 2/2 above).
3829 // The test succeeds if the secondary thread observes the transition
3830 // of `state` from 1 to 2, despite having a whole second to overtake
3831 // the primary thread.
3832 let handle = thread::spawn(move || {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08003833 let temp_dir = temp_dir_clone;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003834 let mut db = KeystoreDB::new(temp_dir.path(), None).unwrap();
Janis Danisevskisaec14592020-11-12 09:41:49 -08003835 assert!(db
3836 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003837 &KeyDescriptor {
Janis Danisevskisaec14592020-11-12 09:41:49 -08003838 domain: Domain::APP,
3839 nspace: 0,
3840 alias: Some(KEY_LOCK_TEST_ALIAS.to_string()),
3841 blob: None,
3842 },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003843 KeyType::Client,
Janis Danisevskisaec14592020-11-12 09:41:49 -08003844 KeyEntryLoadBits::BOTH,
3845 33,
3846 |_k, _av| Ok(()),
3847 )
3848 .is_ok());
3849 // We should only see a 2 here because we can only return
3850 // from load_key_entry when the `_key_guard` expires,
3851 // which happens at the end of the scope.
3852 assert_eq!(2, state2.load(Ordering::Relaxed));
3853 });
3854
3855 thread::sleep(std::time::Duration::from_millis(1000));
3856
3857 assert_eq!(Ok(1), state.compare_exchange(1, 2, Ordering::Relaxed, Ordering::Relaxed));
3858
3859 // Return the handle from this scope so we can join with the
3860 // secondary thread after the key id lock has expired.
3861 handle
3862 // This is where the `_key_guard` goes out of scope,
3863 // which is the reason for concurrent load_key_entry on the same key
3864 // to unblock.
3865 };
3866 // Join with the secondary thread and unwrap, to propagate failing asserts to the
3867 // main test thread. We will not see failing asserts in secondary threads otherwise.
3868 handle.join().unwrap();
3869 Ok(())
3870 }
3871
Janis Danisevskise92a5e62020-12-02 12:57:41 -08003872 #[test]
Janis Danisevskis66784c42021-01-27 08:40:25 -08003873 fn teset_database_busy_error_code() {
3874 let temp_dir =
3875 TempDir::new("test_database_busy_error_code_").expect("Failed to create temp dir.");
3876
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003877 let mut db1 = KeystoreDB::new(temp_dir.path(), None).expect("Failed to open database1.");
3878 let mut db2 = KeystoreDB::new(temp_dir.path(), None).expect("Failed to open database2.");
Janis Danisevskis66784c42021-01-27 08:40:25 -08003879
3880 let _tx1 = db1
3881 .conn
3882 .transaction_with_behavior(TransactionBehavior::Immediate)
3883 .expect("Failed to create first transaction.");
3884
3885 let error = db2
3886 .conn
3887 .transaction_with_behavior(TransactionBehavior::Immediate)
3888 .context("Transaction begin failed.")
3889 .expect_err("This should fail.");
3890 let root_cause = error.root_cause();
3891 if let Some(rusqlite::ffi::Error { code: rusqlite::ErrorCode::DatabaseBusy, .. }) =
3892 root_cause.downcast_ref::<rusqlite::ffi::Error>()
3893 {
3894 return;
3895 }
3896 panic!(
3897 "Unexpected error {:?} \n{:?} \n{:?}",
3898 error,
3899 root_cause,
3900 root_cause.downcast_ref::<rusqlite::ffi::Error>()
3901 )
3902 }
3903
3904 #[cfg(disabled)]
3905 #[test]
3906 fn test_large_number_of_concurrent_db_manipulations() -> Result<()> {
3907 let temp_dir = Arc::new(
3908 TempDir::new("test_large_number_of_concurrent_db_manipulations_")
3909 .expect("Failed to create temp dir."),
3910 );
3911
3912 let test_begin = Instant::now();
3913
3914 let mut db = KeystoreDB::new(temp_dir.path()).expect("Failed to open database.");
3915 const KEY_COUNT: u32 = 500u32;
3916 const OPEN_DB_COUNT: u32 = 50u32;
3917
3918 let mut actual_key_count = KEY_COUNT;
3919 // First insert KEY_COUNT keys.
3920 for count in 0..KEY_COUNT {
3921 if Instant::now().duration_since(test_begin) >= Duration::from_secs(15) {
3922 actual_key_count = count;
3923 break;
3924 }
3925 let alias = format!("test_alias_{}", count);
3926 make_test_key_entry(&mut db, Domain::APP, 1, &alias, None)
3927 .expect("Failed to make key entry.");
3928 }
3929
3930 // Insert more keys from a different thread and into a different namespace.
3931 let temp_dir1 = temp_dir.clone();
3932 let handle1 = thread::spawn(move || {
3933 let mut db = KeystoreDB::new(temp_dir1.path()).expect("Failed to open database.");
3934
3935 for count in 0..actual_key_count {
3936 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
3937 return;
3938 }
3939 let alias = format!("test_alias_{}", count);
3940 make_test_key_entry(&mut db, Domain::APP, 2, &alias, None)
3941 .expect("Failed to make key entry.");
3942 }
3943
3944 // then unbind them again.
3945 for count in 0..actual_key_count {
3946 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
3947 return;
3948 }
3949 let key = KeyDescriptor {
3950 domain: Domain::APP,
3951 nspace: -1,
3952 alias: Some(format!("test_alias_{}", count)),
3953 blob: None,
3954 };
3955 db.unbind_key(&key, KeyType::Client, 2, |_, _| Ok(())).expect("Unbind Failed.");
3956 }
3957 });
3958
3959 // And start unbinding the first set of keys.
3960 let temp_dir2 = temp_dir.clone();
3961 let handle2 = thread::spawn(move || {
3962 let mut db = KeystoreDB::new(temp_dir2.path()).expect("Failed to open database.");
3963
3964 for count in 0..actual_key_count {
3965 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
3966 return;
3967 }
3968 let key = KeyDescriptor {
3969 domain: Domain::APP,
3970 nspace: -1,
3971 alias: Some(format!("test_alias_{}", count)),
3972 blob: None,
3973 };
3974 db.unbind_key(&key, KeyType::Client, 1, |_, _| Ok(())).expect("Unbind Failed.");
3975 }
3976 });
3977
3978 let stop_deleting = Arc::new(AtomicU8::new(0));
3979 let stop_deleting2 = stop_deleting.clone();
3980
3981 // And delete anything that is unreferenced keys.
3982 let temp_dir3 = temp_dir.clone();
3983 let handle3 = thread::spawn(move || {
3984 let mut db = KeystoreDB::new(temp_dir3.path()).expect("Failed to open database.");
3985
3986 while stop_deleting2.load(Ordering::Relaxed) != 1 {
3987 while let Some((key_guard, _key)) =
3988 db.get_unreferenced_key().expect("Failed to get unreferenced Key.")
3989 {
3990 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
3991 return;
3992 }
3993 db.purge_key_entry(key_guard).expect("Failed to purge key.");
3994 }
3995 std::thread::sleep(std::time::Duration::from_millis(100));
3996 }
3997 });
3998
3999 // While a lot of inserting and deleting is going on we have to open database connections
4000 // successfully and use them.
4001 // This clone is not redundant, because temp_dir needs to be kept alive until db goes
4002 // out of scope.
4003 #[allow(clippy::redundant_clone)]
4004 let temp_dir4 = temp_dir.clone();
4005 let handle4 = thread::spawn(move || {
4006 for count in 0..OPEN_DB_COUNT {
4007 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
4008 return;
4009 }
4010 let mut db = KeystoreDB::new(temp_dir4.path()).expect("Failed to open database.");
4011
4012 let alias = format!("test_alias_{}", count);
4013 make_test_key_entry(&mut db, Domain::APP, 3, &alias, None)
4014 .expect("Failed to make key entry.");
4015 let key = KeyDescriptor {
4016 domain: Domain::APP,
4017 nspace: -1,
4018 alias: Some(alias),
4019 blob: None,
4020 };
4021 db.unbind_key(&key, KeyType::Client, 3, |_, _| Ok(())).expect("Unbind Failed.");
4022 }
4023 });
4024
4025 handle1.join().expect("Thread 1 panicked.");
4026 handle2.join().expect("Thread 2 panicked.");
4027 handle4.join().expect("Thread 4 panicked.");
4028
4029 stop_deleting.store(1, Ordering::Relaxed);
4030 handle3.join().expect("Thread 3 panicked.");
4031
4032 Ok(())
4033 }
4034
4035 #[test]
Janis Danisevskise92a5e62020-12-02 12:57:41 -08004036 fn list() -> Result<()> {
4037 let temp_dir = TempDir::new("list_test")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004038 let mut db = KeystoreDB::new(temp_dir.path(), None)?;
Janis Danisevskise92a5e62020-12-02 12:57:41 -08004039 static LIST_O_ENTRIES: &[(Domain, i64, &str)] = &[
4040 (Domain::APP, 1, "test1"),
4041 (Domain::APP, 1, "test2"),
4042 (Domain::APP, 1, "test3"),
4043 (Domain::APP, 1, "test4"),
4044 (Domain::APP, 1, "test5"),
4045 (Domain::APP, 1, "test6"),
4046 (Domain::APP, 1, "test7"),
4047 (Domain::APP, 2, "test1"),
4048 (Domain::APP, 2, "test2"),
4049 (Domain::APP, 2, "test3"),
4050 (Domain::APP, 2, "test4"),
4051 (Domain::APP, 2, "test5"),
4052 (Domain::APP, 2, "test6"),
4053 (Domain::APP, 2, "test8"),
4054 (Domain::SELINUX, 100, "test1"),
4055 (Domain::SELINUX, 100, "test2"),
4056 (Domain::SELINUX, 100, "test3"),
4057 (Domain::SELINUX, 100, "test4"),
4058 (Domain::SELINUX, 100, "test5"),
4059 (Domain::SELINUX, 100, "test6"),
4060 (Domain::SELINUX, 100, "test9"),
4061 ];
4062
4063 let list_o_keys: Vec<(i64, i64)> = LIST_O_ENTRIES
4064 .iter()
4065 .map(|(domain, ns, alias)| {
Qi Wub9433b52020-12-01 14:52:46 +08004066 let entry = make_test_key_entry(&mut db, *domain, *ns, *alias, None)
4067 .unwrap_or_else(|e| {
Janis Danisevskise92a5e62020-12-02 12:57:41 -08004068 panic!("Failed to insert {:?} {} {}. Error {:?}", domain, ns, alias, e)
4069 });
4070 (entry.id(), *ns)
4071 })
4072 .collect();
4073
4074 for (domain, namespace) in
4075 &[(Domain::APP, 1i64), (Domain::APP, 2i64), (Domain::SELINUX, 100i64)]
4076 {
4077 let mut list_o_descriptors: Vec<KeyDescriptor> = LIST_O_ENTRIES
4078 .iter()
4079 .filter_map(|(domain, ns, alias)| match ns {
4080 ns if *ns == *namespace => Some(KeyDescriptor {
4081 domain: *domain,
4082 nspace: *ns,
4083 alias: Some(alias.to_string()),
4084 blob: None,
4085 }),
4086 _ => None,
4087 })
4088 .collect();
4089 list_o_descriptors.sort();
4090 let mut list_result = db.list(*domain, *namespace)?;
4091 list_result.sort();
4092 assert_eq!(list_o_descriptors, list_result);
4093
4094 let mut list_o_ids: Vec<i64> = list_o_descriptors
4095 .into_iter()
4096 .map(|d| {
4097 let (_, entry) = db
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004098 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004099 &d,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004100 KeyType::Client,
4101 KeyEntryLoadBits::NONE,
4102 *namespace as u32,
4103 |_, _| Ok(()),
4104 )
Janis Danisevskise92a5e62020-12-02 12:57:41 -08004105 .unwrap();
4106 entry.id()
4107 })
4108 .collect();
4109 list_o_ids.sort_unstable();
4110 let mut loaded_entries: Vec<i64> = list_o_keys
4111 .iter()
4112 .filter_map(|(id, ns)| match ns {
4113 ns if *ns == *namespace => Some(*id),
4114 _ => None,
4115 })
4116 .collect();
4117 loaded_entries.sort_unstable();
4118 assert_eq!(list_o_ids, loaded_entries);
4119 }
4120 assert_eq!(Vec::<KeyDescriptor>::new(), db.list(Domain::SELINUX, 101)?);
4121
4122 Ok(())
4123 }
4124
Joel Galenson0891bc12020-07-20 10:37:03 -07004125 // Helpers
4126
4127 // Checks that the given result is an error containing the given string.
4128 fn check_result_is_error_containing_string<T>(result: Result<T>, target: &str) {
4129 let error_str = format!(
4130 "{:#?}",
4131 result.err().unwrap_or_else(|| panic!("Expected the error: {}", target))
4132 );
4133 assert!(
4134 error_str.contains(target),
4135 "The string \"{}\" should contain \"{}\"",
4136 error_str,
4137 target
4138 );
4139 }
4140
Joel Galenson2aab4432020-07-22 15:27:57 -07004141 #[derive(Debug, PartialEq)]
Joel Galenson0891bc12020-07-20 10:37:03 -07004142 #[allow(dead_code)]
4143 struct KeyEntryRow {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004144 id: i64,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004145 key_type: KeyType,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07004146 domain: Option<Domain>,
Joel Galenson0891bc12020-07-20 10:37:03 -07004147 namespace: Option<i64>,
4148 alias: Option<String>,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004149 state: KeyLifeCycle,
Max Bires8e93d2b2021-01-14 13:17:59 -08004150 km_uuid: Option<Uuid>,
Joel Galenson0891bc12020-07-20 10:37:03 -07004151 }
4152
4153 fn get_keyentry(db: &KeystoreDB) -> Result<Vec<KeyEntryRow>> {
4154 db.conn
Joel Galenson2aab4432020-07-22 15:27:57 -07004155 .prepare("SELECT * FROM persistent.keyentry;")?
Joel Galenson0891bc12020-07-20 10:37:03 -07004156 .query_map(NO_PARAMS, |row| {
Joel Galenson0891bc12020-07-20 10:37:03 -07004157 Ok(KeyEntryRow {
4158 id: row.get(0)?,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004159 key_type: row.get(1)?,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07004160 domain: match row.get(2)? {
4161 Some(i) => Some(Domain(i)),
4162 None => None,
4163 },
Joel Galenson0891bc12020-07-20 10:37:03 -07004164 namespace: row.get(3)?,
4165 alias: row.get(4)?,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004166 state: row.get(5)?,
Max Bires8e93d2b2021-01-14 13:17:59 -08004167 km_uuid: row.get(6)?,
Joel Galenson0891bc12020-07-20 10:37:03 -07004168 })
4169 })?
4170 .map(|r| r.context("Could not read keyentry row."))
4171 .collect::<Result<Vec<_>>>()
4172 }
4173
Max Bires2b2e6562020-09-22 11:22:36 -07004174 fn load_attestation_key_pool(
4175 db: &mut KeystoreDB,
4176 expiration_date: i64,
4177 namespace: i64,
4178 base_byte: u8,
4179 ) -> Result<Vec<Vec<u8>>> {
4180 let mut chain: Vec<Vec<u8>> = Vec::new();
4181 let public_key: Vec<u8> = vec![base_byte, 0x02 * base_byte];
4182 let cert_chain: Vec<u8> = vec![0x03 * base_byte, 0x04 * base_byte];
4183 let priv_key: Vec<u8> = vec![0x05 * base_byte, 0x06 * base_byte];
4184 let raw_public_key: Vec<u8> = vec![0x0b * base_byte, 0x0c * base_byte];
4185 db.create_attestation_key_entry(&public_key, &raw_public_key, &priv_key, &KEYSTORE_UUID)?;
4186 db.store_signed_attestation_certificate_chain(
4187 &raw_public_key,
4188 &cert_chain,
4189 expiration_date,
4190 &KEYSTORE_UUID,
4191 )?;
4192 db.assign_attestation_key(Domain::APP, namespace, &KEYSTORE_UUID)?;
4193 chain.push(public_key);
4194 chain.push(cert_chain);
4195 chain.push(priv_key);
4196 chain.push(raw_public_key);
4197 Ok(chain)
4198 }
4199
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07004200 // Note: The parameters and SecurityLevel associations are nonsensical. This
4201 // collection is only used to check if the parameters are preserved as expected by the
4202 // database.
Qi Wub9433b52020-12-01 14:52:46 +08004203 fn make_test_params(max_usage_count: Option<i32>) -> Vec<KeyParameter> {
4204 let mut params = vec![
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07004205 KeyParameter::new(KeyParameterValue::Invalid, SecurityLevel::TRUSTED_ENVIRONMENT),
4206 KeyParameter::new(
4207 KeyParameterValue::KeyPurpose(KeyPurpose::SIGN),
4208 SecurityLevel::TRUSTED_ENVIRONMENT,
4209 ),
4210 KeyParameter::new(
4211 KeyParameterValue::KeyPurpose(KeyPurpose::DECRYPT),
4212 SecurityLevel::TRUSTED_ENVIRONMENT,
4213 ),
4214 KeyParameter::new(
4215 KeyParameterValue::Algorithm(Algorithm::RSA),
4216 SecurityLevel::TRUSTED_ENVIRONMENT,
4217 ),
4218 KeyParameter::new(KeyParameterValue::KeySize(1024), SecurityLevel::TRUSTED_ENVIRONMENT),
4219 KeyParameter::new(
4220 KeyParameterValue::BlockMode(BlockMode::ECB),
4221 SecurityLevel::TRUSTED_ENVIRONMENT,
4222 ),
4223 KeyParameter::new(
4224 KeyParameterValue::BlockMode(BlockMode::GCM),
4225 SecurityLevel::TRUSTED_ENVIRONMENT,
4226 ),
4227 KeyParameter::new(KeyParameterValue::Digest(Digest::NONE), SecurityLevel::STRONGBOX),
4228 KeyParameter::new(
4229 KeyParameterValue::Digest(Digest::MD5),
4230 SecurityLevel::TRUSTED_ENVIRONMENT,
4231 ),
4232 KeyParameter::new(
4233 KeyParameterValue::Digest(Digest::SHA_2_224),
4234 SecurityLevel::TRUSTED_ENVIRONMENT,
4235 ),
4236 KeyParameter::new(
4237 KeyParameterValue::Digest(Digest::SHA_2_256),
4238 SecurityLevel::STRONGBOX,
4239 ),
4240 KeyParameter::new(
4241 KeyParameterValue::PaddingMode(PaddingMode::NONE),
4242 SecurityLevel::TRUSTED_ENVIRONMENT,
4243 ),
4244 KeyParameter::new(
4245 KeyParameterValue::PaddingMode(PaddingMode::RSA_OAEP),
4246 SecurityLevel::TRUSTED_ENVIRONMENT,
4247 ),
4248 KeyParameter::new(
4249 KeyParameterValue::PaddingMode(PaddingMode::RSA_PSS),
4250 SecurityLevel::STRONGBOX,
4251 ),
4252 KeyParameter::new(
4253 KeyParameterValue::PaddingMode(PaddingMode::RSA_PKCS1_1_5_SIGN),
4254 SecurityLevel::TRUSTED_ENVIRONMENT,
4255 ),
4256 KeyParameter::new(KeyParameterValue::CallerNonce, SecurityLevel::TRUSTED_ENVIRONMENT),
4257 KeyParameter::new(KeyParameterValue::MinMacLength(256), SecurityLevel::STRONGBOX),
4258 KeyParameter::new(
4259 KeyParameterValue::EcCurve(EcCurve::P_224),
4260 SecurityLevel::TRUSTED_ENVIRONMENT,
4261 ),
4262 KeyParameter::new(KeyParameterValue::EcCurve(EcCurve::P_256), SecurityLevel::STRONGBOX),
4263 KeyParameter::new(
4264 KeyParameterValue::EcCurve(EcCurve::P_384),
4265 SecurityLevel::TRUSTED_ENVIRONMENT,
4266 ),
4267 KeyParameter::new(
4268 KeyParameterValue::EcCurve(EcCurve::P_521),
4269 SecurityLevel::TRUSTED_ENVIRONMENT,
4270 ),
4271 KeyParameter::new(
4272 KeyParameterValue::RSAPublicExponent(3),
4273 SecurityLevel::TRUSTED_ENVIRONMENT,
4274 ),
4275 KeyParameter::new(
4276 KeyParameterValue::IncludeUniqueID,
4277 SecurityLevel::TRUSTED_ENVIRONMENT,
4278 ),
4279 KeyParameter::new(KeyParameterValue::BootLoaderOnly, SecurityLevel::STRONGBOX),
4280 KeyParameter::new(KeyParameterValue::RollbackResistance, SecurityLevel::STRONGBOX),
4281 KeyParameter::new(
4282 KeyParameterValue::ActiveDateTime(1234567890),
4283 SecurityLevel::STRONGBOX,
4284 ),
4285 KeyParameter::new(
4286 KeyParameterValue::OriginationExpireDateTime(1234567890),
4287 SecurityLevel::TRUSTED_ENVIRONMENT,
4288 ),
4289 KeyParameter::new(
4290 KeyParameterValue::UsageExpireDateTime(1234567890),
4291 SecurityLevel::TRUSTED_ENVIRONMENT,
4292 ),
4293 KeyParameter::new(
4294 KeyParameterValue::MinSecondsBetweenOps(1234567890),
4295 SecurityLevel::TRUSTED_ENVIRONMENT,
4296 ),
4297 KeyParameter::new(
4298 KeyParameterValue::MaxUsesPerBoot(1234567890),
4299 SecurityLevel::TRUSTED_ENVIRONMENT,
4300 ),
4301 KeyParameter::new(KeyParameterValue::UserID(1), SecurityLevel::STRONGBOX),
4302 KeyParameter::new(KeyParameterValue::UserSecureID(42), SecurityLevel::STRONGBOX),
4303 KeyParameter::new(
4304 KeyParameterValue::NoAuthRequired,
4305 SecurityLevel::TRUSTED_ENVIRONMENT,
4306 ),
4307 KeyParameter::new(
4308 KeyParameterValue::HardwareAuthenticatorType(HardwareAuthenticatorType::PASSWORD),
4309 SecurityLevel::TRUSTED_ENVIRONMENT,
4310 ),
4311 KeyParameter::new(KeyParameterValue::AuthTimeout(1234567890), SecurityLevel::SOFTWARE),
4312 KeyParameter::new(KeyParameterValue::AllowWhileOnBody, SecurityLevel::SOFTWARE),
4313 KeyParameter::new(
4314 KeyParameterValue::TrustedUserPresenceRequired,
4315 SecurityLevel::TRUSTED_ENVIRONMENT,
4316 ),
4317 KeyParameter::new(
4318 KeyParameterValue::TrustedConfirmationRequired,
4319 SecurityLevel::TRUSTED_ENVIRONMENT,
4320 ),
4321 KeyParameter::new(
4322 KeyParameterValue::UnlockedDeviceRequired,
4323 SecurityLevel::TRUSTED_ENVIRONMENT,
4324 ),
4325 KeyParameter::new(
4326 KeyParameterValue::ApplicationID(vec![1u8, 2u8, 3u8, 4u8]),
4327 SecurityLevel::SOFTWARE,
4328 ),
4329 KeyParameter::new(
4330 KeyParameterValue::ApplicationData(vec![4u8, 3u8, 2u8, 1u8]),
4331 SecurityLevel::SOFTWARE,
4332 ),
4333 KeyParameter::new(
4334 KeyParameterValue::CreationDateTime(12345677890),
4335 SecurityLevel::SOFTWARE,
4336 ),
4337 KeyParameter::new(
4338 KeyParameterValue::KeyOrigin(KeyOrigin::GENERATED),
4339 SecurityLevel::TRUSTED_ENVIRONMENT,
4340 ),
4341 KeyParameter::new(
4342 KeyParameterValue::RootOfTrust(vec![3u8, 2u8, 1u8, 4u8]),
4343 SecurityLevel::TRUSTED_ENVIRONMENT,
4344 ),
4345 KeyParameter::new(KeyParameterValue::OSVersion(1), SecurityLevel::TRUSTED_ENVIRONMENT),
4346 KeyParameter::new(KeyParameterValue::OSPatchLevel(2), SecurityLevel::SOFTWARE),
4347 KeyParameter::new(
4348 KeyParameterValue::UniqueID(vec![4u8, 3u8, 1u8, 2u8]),
4349 SecurityLevel::SOFTWARE,
4350 ),
4351 KeyParameter::new(
4352 KeyParameterValue::AttestationChallenge(vec![4u8, 3u8, 1u8, 2u8]),
4353 SecurityLevel::TRUSTED_ENVIRONMENT,
4354 ),
4355 KeyParameter::new(
4356 KeyParameterValue::AttestationApplicationID(vec![4u8, 3u8, 1u8, 2u8]),
4357 SecurityLevel::TRUSTED_ENVIRONMENT,
4358 ),
4359 KeyParameter::new(
4360 KeyParameterValue::AttestationIdBrand(vec![4u8, 3u8, 1u8, 2u8]),
4361 SecurityLevel::TRUSTED_ENVIRONMENT,
4362 ),
4363 KeyParameter::new(
4364 KeyParameterValue::AttestationIdDevice(vec![4u8, 3u8, 1u8, 2u8]),
4365 SecurityLevel::TRUSTED_ENVIRONMENT,
4366 ),
4367 KeyParameter::new(
4368 KeyParameterValue::AttestationIdProduct(vec![4u8, 3u8, 1u8, 2u8]),
4369 SecurityLevel::TRUSTED_ENVIRONMENT,
4370 ),
4371 KeyParameter::new(
4372 KeyParameterValue::AttestationIdSerial(vec![4u8, 3u8, 1u8, 2u8]),
4373 SecurityLevel::TRUSTED_ENVIRONMENT,
4374 ),
4375 KeyParameter::new(
4376 KeyParameterValue::AttestationIdIMEI(vec![4u8, 3u8, 1u8, 2u8]),
4377 SecurityLevel::TRUSTED_ENVIRONMENT,
4378 ),
4379 KeyParameter::new(
4380 KeyParameterValue::AttestationIdMEID(vec![4u8, 3u8, 1u8, 2u8]),
4381 SecurityLevel::TRUSTED_ENVIRONMENT,
4382 ),
4383 KeyParameter::new(
4384 KeyParameterValue::AttestationIdManufacturer(vec![4u8, 3u8, 1u8, 2u8]),
4385 SecurityLevel::TRUSTED_ENVIRONMENT,
4386 ),
4387 KeyParameter::new(
4388 KeyParameterValue::AttestationIdModel(vec![4u8, 3u8, 1u8, 2u8]),
4389 SecurityLevel::TRUSTED_ENVIRONMENT,
4390 ),
4391 KeyParameter::new(
4392 KeyParameterValue::VendorPatchLevel(3),
4393 SecurityLevel::TRUSTED_ENVIRONMENT,
4394 ),
4395 KeyParameter::new(
4396 KeyParameterValue::BootPatchLevel(4),
4397 SecurityLevel::TRUSTED_ENVIRONMENT,
4398 ),
4399 KeyParameter::new(
4400 KeyParameterValue::AssociatedData(vec![4u8, 3u8, 1u8, 2u8]),
4401 SecurityLevel::TRUSTED_ENVIRONMENT,
4402 ),
4403 KeyParameter::new(
4404 KeyParameterValue::Nonce(vec![4u8, 3u8, 1u8, 2u8]),
4405 SecurityLevel::TRUSTED_ENVIRONMENT,
4406 ),
4407 KeyParameter::new(
4408 KeyParameterValue::MacLength(256),
4409 SecurityLevel::TRUSTED_ENVIRONMENT,
4410 ),
4411 KeyParameter::new(
4412 KeyParameterValue::ResetSinceIdRotation,
4413 SecurityLevel::TRUSTED_ENVIRONMENT,
4414 ),
4415 KeyParameter::new(
4416 KeyParameterValue::ConfirmationToken(vec![5u8, 5u8, 5u8, 5u8]),
4417 SecurityLevel::TRUSTED_ENVIRONMENT,
4418 ),
Qi Wub9433b52020-12-01 14:52:46 +08004419 ];
4420 if let Some(value) = max_usage_count {
4421 params.push(KeyParameter::new(
4422 KeyParameterValue::UsageCountLimit(value),
4423 SecurityLevel::SOFTWARE,
4424 ));
4425 }
4426 params
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07004427 }
4428
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004429 fn make_test_key_entry(
4430 db: &mut KeystoreDB,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07004431 domain: Domain,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004432 namespace: i64,
4433 alias: &str,
Qi Wub9433b52020-12-01 14:52:46 +08004434 max_usage_count: Option<i32>,
Janis Danisevskisaec14592020-11-12 09:41:49 -08004435 ) -> Result<KeyIdGuard> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08004436 let key_id = db.create_key_entry(&domain, &namespace, &KEYSTORE_UUID)?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004437 let mut blob_metadata = BlobMetaData::new();
4438 blob_metadata.add(BlobMetaEntry::EncryptedBy(EncryptedBy::Password));
4439 blob_metadata.add(BlobMetaEntry::Salt(vec![1, 2, 3]));
4440 blob_metadata.add(BlobMetaEntry::Iv(vec![2, 3, 1]));
4441 blob_metadata.add(BlobMetaEntry::AeadTag(vec![3, 1, 2]));
4442 blob_metadata.add(BlobMetaEntry::KmUuid(KEYSTORE_UUID));
4443
4444 db.set_blob(
4445 &key_id,
4446 SubComponentType::KEY_BLOB,
4447 Some(TEST_KEY_BLOB),
4448 Some(&blob_metadata),
4449 )?;
4450 db.set_blob(&key_id, SubComponentType::CERT, Some(TEST_CERT_BLOB), None)?;
4451 db.set_blob(&key_id, SubComponentType::CERT_CHAIN, Some(TEST_CERT_CHAIN_BLOB), None)?;
Qi Wub9433b52020-12-01 14:52:46 +08004452
4453 let params = make_test_params(max_usage_count);
4454 db.insert_keyparameter(&key_id, &params)?;
4455
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004456 let mut metadata = KeyMetaData::new();
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004457 metadata.add(KeyMetaEntry::CreationDate(DateTime::from_millis_epoch(123456789)));
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004458 db.insert_key_metadata(&key_id, &metadata)?;
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08004459 rebind_alias(db, &key_id, alias, domain, namespace)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004460 Ok(key_id)
4461 }
4462
Qi Wub9433b52020-12-01 14:52:46 +08004463 fn make_test_key_entry_test_vector(key_id: i64, max_usage_count: Option<i32>) -> KeyEntry {
4464 let params = make_test_params(max_usage_count);
4465
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004466 let mut blob_metadata = BlobMetaData::new();
4467 blob_metadata.add(BlobMetaEntry::EncryptedBy(EncryptedBy::Password));
4468 blob_metadata.add(BlobMetaEntry::Salt(vec![1, 2, 3]));
4469 blob_metadata.add(BlobMetaEntry::Iv(vec![2, 3, 1]));
4470 blob_metadata.add(BlobMetaEntry::AeadTag(vec![3, 1, 2]));
4471 blob_metadata.add(BlobMetaEntry::KmUuid(KEYSTORE_UUID));
4472
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004473 let mut metadata = KeyMetaData::new();
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004474 metadata.add(KeyMetaEntry::CreationDate(DateTime::from_millis_epoch(123456789)));
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004475
4476 KeyEntry {
4477 id: key_id,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004478 key_blob_info: Some((TEST_KEY_BLOB.to_vec(), blob_metadata)),
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004479 cert: Some(TEST_CERT_BLOB.to_vec()),
4480 cert_chain: Some(TEST_CERT_CHAIN_BLOB.to_vec()),
Max Bires8e93d2b2021-01-14 13:17:59 -08004481 km_uuid: KEYSTORE_UUID,
Qi Wub9433b52020-12-01 14:52:46 +08004482 parameters: params,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004483 metadata,
Janis Danisevskis377d1002021-01-27 19:07:48 -08004484 pure_cert: false,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004485 }
4486 }
4487
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004488 fn debug_dump_keyentry_table(db: &mut KeystoreDB) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004489 let mut stmt = db.conn.prepare(
Max Bires8e93d2b2021-01-14 13:17:59 -08004490 "SELECT id, key_type, domain, namespace, alias, state, km_uuid FROM persistent.keyentry;",
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004491 )?;
Max Bires8e93d2b2021-01-14 13:17:59 -08004492 let rows = stmt.query_map::<(i64, KeyType, i32, i64, String, KeyLifeCycle, Uuid), _, _>(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004493 NO_PARAMS,
4494 |row| {
Max Bires8e93d2b2021-01-14 13:17:59 -08004495 Ok((
4496 row.get(0)?,
4497 row.get(1)?,
4498 row.get(2)?,
4499 row.get(3)?,
4500 row.get(4)?,
4501 row.get(5)?,
4502 row.get(6)?,
4503 ))
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004504 },
4505 )?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004506
4507 println!("Key entry table rows:");
4508 for r in rows {
Max Bires8e93d2b2021-01-14 13:17:59 -08004509 let (id, key_type, domain, namespace, alias, state, km_uuid) = r.unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004510 println!(
Max Bires8e93d2b2021-01-14 13:17:59 -08004511 " id: {} KeyType: {:?} Domain: {} Namespace: {} Alias: {} State: {:?} KmUuid: {:?}",
4512 id, key_type, domain, namespace, alias, state, km_uuid
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004513 );
4514 }
4515 Ok(())
4516 }
4517
4518 fn debug_dump_grant_table(db: &mut KeystoreDB) -> Result<()> {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08004519 let mut stmt = db
4520 .conn
4521 .prepare("SELECT id, grantee, keyentryid, access_vector FROM persistent.grant;")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004522 let rows = stmt.query_map::<(i64, i64, i64, i64), _, _>(NO_PARAMS, |row| {
4523 Ok((row.get(0)?, row.get(1)?, row.get(2)?, row.get(3)?))
4524 })?;
4525
4526 println!("Grant table rows:");
4527 for r in rows {
4528 let (id, gt, ki, av) = r.unwrap();
4529 println!(" id: {} grantee: {} key_id: {} access_vector: {}", id, gt, ki, av);
4530 }
4531 Ok(())
4532 }
4533
Joel Galenson0891bc12020-07-20 10:37:03 -07004534 // Use a custom random number generator that repeats each number once.
4535 // This allows us to test repeated elements.
4536
4537 thread_local! {
4538 static RANDOM_COUNTER: RefCell<i64> = RefCell::new(0);
4539 }
4540
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004541 fn reset_random() {
4542 RANDOM_COUNTER.with(|counter| {
4543 *counter.borrow_mut() = 0;
4544 })
4545 }
4546
Joel Galenson0891bc12020-07-20 10:37:03 -07004547 pub fn random() -> i64 {
4548 RANDOM_COUNTER.with(|counter| {
4549 let result = *counter.borrow() / 2;
4550 *counter.borrow_mut() += 1;
4551 result
4552 })
4553 }
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00004554
4555 #[test]
4556 fn test_last_off_body() -> Result<()> {
4557 let mut db = new_test_db()?;
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08004558 db.insert_last_off_body(MonotonicRawTime::now())?;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00004559 let tx = db.conn.transaction_with_behavior(TransactionBehavior::Immediate)?;
4560 let last_off_body_1 = KeystoreDB::get_last_off_body(&tx)?;
4561 tx.commit()?;
4562 let one_second = Duration::from_secs(1);
4563 thread::sleep(one_second);
4564 db.update_last_off_body(MonotonicRawTime::now())?;
4565 let tx2 = db.conn.transaction_with_behavior(TransactionBehavior::Immediate)?;
4566 let last_off_body_2 = KeystoreDB::get_last_off_body(&tx2)?;
4567 tx2.commit()?;
4568 assert!(last_off_body_1.seconds() < last_off_body_2.seconds());
4569 Ok(())
4570 }
Joel Galenson26f4d012020-07-17 14:57:21 -07004571}