blob: f645069e7305a1c6d0e48d62cb59a3490defa066 [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
Jeff Vander Stoep46bbc612021-04-09 08:55:21 +020044#![allow(clippy::needless_question_mark)]
45
Janis Danisevskisb42fc182020-12-15 08:41:27 -080046use crate::impl_metadata; // This is in db_utils.rs
Janis Danisevskis4522c2b2020-11-27 18:04:58 -080047use crate::key_parameter::{KeyParameter, Tag};
Janis Danisevskisc5b210b2020-09-11 13:27:37 -070048use crate::permission::KeyPermSet;
Hasini Gunasingheda895552021-01-27 19:34:37 +000049use crate::utils::{get_current_time_in_seconds, AID_USER_OFFSET};
Janis Danisevskis7e8b4622021-02-13 10:01:59 -080050use crate::{
51 db_utils::{self, SqlField},
52 gc::Gc,
Paul Crowley7a658392021-03-18 17:08:20 -070053 super_key::USER_SUPER_KEY,
54};
55use crate::{
56 error::{Error as KsError, ErrorCode, ResponseCode},
57 super_key::SuperKeyType,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -080058};
Janis Danisevskisb42fc182020-12-15 08:41:27 -080059use anyhow::{anyhow, Context, Result};
Max Bires8e93d2b2021-01-14 13:17:59 -080060use std::{convert::TryFrom, convert::TryInto, ops::Deref, time::SystemTimeError};
Janis Danisevskis60400fe2020-08-26 15:24:42 -070061
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +000062use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
Janis Danisevskis5ed8c532021-01-11 14:19:42 -080063 HardwareAuthToken::HardwareAuthToken,
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +000064 HardwareAuthenticatorType::HardwareAuthenticatorType, SecurityLevel::SecurityLevel,
Janis Danisevskisc3a496b2021-01-05 10:37:22 -080065};
66use android_hardware_security_secureclock::aidl::android::hardware::security::secureclock::{
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +000067 Timestamp::Timestamp,
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +000068};
Janis Danisevskisc5b210b2020-09-11 13:27:37 -070069use android_system_keystore2::aidl::android::system::keystore2::{
Janis Danisevskis04b02832020-10-26 09:21:40 -070070 Domain::Domain, KeyDescriptor::KeyDescriptor,
Janis Danisevskis60400fe2020-08-26 15:24:42 -070071};
Max Bires2b2e6562020-09-22 11:22:36 -070072use android_security_remoteprovisioning::aidl::android::security::remoteprovisioning::{
73 AttestationPoolStatus::AttestationPoolStatus,
74};
Seth Moore78c091f2021-04-09 21:38:30 +000075use statslog_rust::keystore2_storage_stats::{
76 Keystore2StorageStats, StorageType as StatsdStorageType,
77};
Max Bires2b2e6562020-09-22 11:22:36 -070078
79use keystore2_crypto::ZVec;
Janis Danisevskisaec14592020-11-12 09:41:49 -080080use lazy_static::lazy_static;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +000081use log::error;
Joel Galenson0891bc12020-07-20 10:37:03 -070082#[cfg(not(test))]
83use rand::prelude::random;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -070084use rusqlite::{
Janis Danisevskisb42fc182020-12-15 08:41:27 -080085 params,
86 types::FromSql,
87 types::FromSqlResult,
88 types::ToSqlOutput,
89 types::{FromSqlError, Value, ValueRef},
Janis Danisevskis5ed8c532021-01-11 14:19:42 -080090 Connection, OptionalExtension, ToSql, Transaction, TransactionBehavior, NO_PARAMS,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -070091};
Max Bires2b2e6562020-09-22 11:22:36 -070092
Janis Danisevskisaec14592020-11-12 09:41:49 -080093use std::{
Janis Danisevskisb42fc182020-12-15 08:41:27 -080094 collections::{HashMap, HashSet},
Janis Danisevskisbf15d732020-12-08 10:35:26 -080095 path::Path,
96 sync::{Condvar, Mutex},
Janis Danisevskisb42fc182020-12-15 08:41:27 -080097 time::{Duration, SystemTime},
Janis Danisevskisaec14592020-11-12 09:41:49 -080098};
Max Bires2b2e6562020-09-22 11:22:36 -070099
Joel Galenson0891bc12020-07-20 10:37:03 -0700100#[cfg(test)]
101use tests::random;
Joel Galenson26f4d012020-07-17 14:57:21 -0700102
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800103impl_metadata!(
104 /// A set of metadata for key entries.
105 #[derive(Debug, Default, Eq, PartialEq)]
106 pub struct KeyMetaData;
107 /// A metadata entry for key entries.
108 #[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
109 pub enum KeyMetaEntry {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800110 /// Date of the creation of the key entry.
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800111 CreationDate(DateTime) with accessor creation_date,
112 /// Expiration date for attestation keys.
113 AttestationExpirationDate(DateTime) with accessor attestation_expiration_date,
Max Bires2b2e6562020-09-22 11:22:36 -0700114 /// CBOR Blob that represents a COSE_Key and associated metadata needed for remote
115 /// provisioning
116 AttestationMacedPublicKey(Vec<u8>) with accessor attestation_maced_public_key,
117 /// Vector representing the raw public key so results from the server can be matched
118 /// to the right entry
119 AttestationRawPubKey(Vec<u8>) with accessor attestation_raw_pub_key,
Paul Crowley8d5b2532021-03-19 10:53:07 -0700120 /// SEC1 public key for ECDH encryption
121 Sec1PublicKey(Vec<u8>) with accessor sec1_public_key,
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800122 // --- ADD NEW META DATA FIELDS HERE ---
123 // For backwards compatibility add new entries only to
124 // end of this list and above this comment.
125 };
126);
127
128impl KeyMetaData {
129 fn load_from_db(key_id: i64, tx: &Transaction) -> Result<Self> {
130 let mut stmt = tx
131 .prepare(
132 "SELECT tag, data from persistent.keymetadata
133 WHERE keyentryid = ?;",
134 )
135 .context("In KeyMetaData::load_from_db: prepare statement failed.")?;
136
137 let mut metadata: HashMap<i64, KeyMetaEntry> = Default::default();
138
139 let mut rows =
140 stmt.query(params![key_id]).context("In KeyMetaData::load_from_db: query failed.")?;
141 db_utils::with_rows_extract_all(&mut rows, |row| {
142 let db_tag: i64 = row.get(0).context("Failed to read tag.")?;
143 metadata.insert(
144 db_tag,
145 KeyMetaEntry::new_from_sql(db_tag, &SqlField::new(1, &row))
146 .context("Failed to read KeyMetaEntry.")?,
147 );
148 Ok(())
149 })
150 .context("In KeyMetaData::load_from_db.")?;
151
152 Ok(Self { data: metadata })
153 }
154
155 fn store_in_db(&self, key_id: i64, tx: &Transaction) -> Result<()> {
156 let mut stmt = tx
157 .prepare(
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000158 "INSERT or REPLACE INTO persistent.keymetadata (keyentryid, tag, data)
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800159 VALUES (?, ?, ?);",
160 )
161 .context("In KeyMetaData::store_in_db: Failed to prepare statement.")?;
162
163 let iter = self.data.iter();
164 for (tag, entry) in iter {
165 stmt.insert(params![key_id, tag, entry,]).with_context(|| {
166 format!("In KeyMetaData::store_in_db: Failed to insert {:?}", entry)
167 })?;
168 }
169 Ok(())
170 }
171}
172
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800173impl_metadata!(
174 /// A set of metadata for key blobs.
175 #[derive(Debug, Default, Eq, PartialEq)]
176 pub struct BlobMetaData;
177 /// A metadata entry for key blobs.
178 #[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
179 pub enum BlobMetaEntry {
180 /// If present, indicates that the blob is encrypted with another key or a key derived
181 /// from a password.
182 EncryptedBy(EncryptedBy) with accessor encrypted_by,
183 /// If the blob is password encrypted this field is set to the
184 /// salt used for the key derivation.
185 Salt(Vec<u8>) with accessor salt,
186 /// If the blob is encrypted, this field is set to the initialization vector.
187 Iv(Vec<u8>) with accessor iv,
188 /// If the blob is encrypted, this field holds the AEAD TAG.
189 AeadTag(Vec<u8>) with accessor aead_tag,
190 /// The uuid of the owning KeyMint instance.
191 KmUuid(Uuid) with accessor km_uuid,
Paul Crowley8d5b2532021-03-19 10:53:07 -0700192 /// If the key is ECDH encrypted, this is the ephemeral public key
193 PublicKey(Vec<u8>) with accessor public_key,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800194 // --- ADD NEW META DATA FIELDS HERE ---
195 // For backwards compatibility add new entries only to
196 // end of this list and above this comment.
197 };
198);
199
200impl BlobMetaData {
201 fn load_from_db(blob_id: i64, tx: &Transaction) -> Result<Self> {
202 let mut stmt = tx
203 .prepare(
204 "SELECT tag, data from persistent.blobmetadata
205 WHERE blobentryid = ?;",
206 )
207 .context("In BlobMetaData::load_from_db: prepare statement failed.")?;
208
209 let mut metadata: HashMap<i64, BlobMetaEntry> = Default::default();
210
211 let mut rows =
212 stmt.query(params![blob_id]).context("In BlobMetaData::load_from_db: query failed.")?;
213 db_utils::with_rows_extract_all(&mut rows, |row| {
214 let db_tag: i64 = row.get(0).context("Failed to read tag.")?;
215 metadata.insert(
216 db_tag,
217 BlobMetaEntry::new_from_sql(db_tag, &SqlField::new(1, &row))
218 .context("Failed to read BlobMetaEntry.")?,
219 );
220 Ok(())
221 })
222 .context("In BlobMetaData::load_from_db.")?;
223
224 Ok(Self { data: metadata })
225 }
226
227 fn store_in_db(&self, blob_id: i64, tx: &Transaction) -> Result<()> {
228 let mut stmt = tx
229 .prepare(
230 "INSERT or REPLACE INTO persistent.blobmetadata (blobentryid, tag, data)
231 VALUES (?, ?, ?);",
232 )
233 .context("In BlobMetaData::store_in_db: Failed to prepare statement.")?;
234
235 let iter = self.data.iter();
236 for (tag, entry) in iter {
237 stmt.insert(params![blob_id, tag, entry,]).with_context(|| {
238 format!("In BlobMetaData::store_in_db: Failed to insert {:?}", entry)
239 })?;
240 }
241 Ok(())
242 }
243}
244
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800245/// Indicates the type of the keyentry.
246#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
247pub enum KeyType {
248 /// This is a client key type. These keys are created or imported through the Keystore 2.0
249 /// AIDL interface android.system.keystore2.
250 Client,
251 /// This is a super key type. These keys are created by keystore itself and used to encrypt
252 /// other key blobs to provide LSKF binding.
253 Super,
254 /// This is an attestation key. These keys are created by the remote provisioning mechanism.
255 Attestation,
256}
257
258impl ToSql for KeyType {
259 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
260 Ok(ToSqlOutput::Owned(Value::Integer(match self {
261 KeyType::Client => 0,
262 KeyType::Super => 1,
263 KeyType::Attestation => 2,
264 })))
265 }
266}
267
268impl FromSql for KeyType {
269 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
270 match i64::column_result(value)? {
271 0 => Ok(KeyType::Client),
272 1 => Ok(KeyType::Super),
273 2 => Ok(KeyType::Attestation),
274 v => Err(FromSqlError::OutOfRange(v)),
275 }
276 }
277}
278
Max Bires8e93d2b2021-01-14 13:17:59 -0800279/// Uuid representation that can be stored in the database.
280/// Right now it can only be initialized from SecurityLevel.
281/// Once KeyMint provides a UUID type a corresponding From impl shall be added.
282#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
283pub struct Uuid([u8; 16]);
284
285impl Deref for Uuid {
286 type Target = [u8; 16];
287
288 fn deref(&self) -> &Self::Target {
289 &self.0
290 }
291}
292
293impl From<SecurityLevel> for Uuid {
294 fn from(sec_level: SecurityLevel) -> Self {
295 Self((sec_level.0 as u128).to_be_bytes())
296 }
297}
298
299impl ToSql for Uuid {
300 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
301 self.0.to_sql()
302 }
303}
304
305impl FromSql for Uuid {
306 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
307 let blob = Vec::<u8>::column_result(value)?;
308 if blob.len() != 16 {
309 return Err(FromSqlError::OutOfRange(blob.len() as i64));
310 }
311 let mut arr = [0u8; 16];
312 arr.copy_from_slice(&blob);
313 Ok(Self(arr))
314 }
315}
316
317/// Key entries that are not associated with any KeyMint instance, such as pure certificate
318/// entries are associated with this UUID.
319pub static KEYSTORE_UUID: Uuid = Uuid([
320 0x41, 0xe3, 0xb9, 0xce, 0x27, 0x58, 0x4e, 0x91, 0xbc, 0xfd, 0xa5, 0x5d, 0x91, 0x85, 0xab, 0x11,
321]);
322
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800323/// Indicates how the sensitive part of this key blob is encrypted.
324#[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
325pub enum EncryptedBy {
326 /// The keyblob is encrypted by a user password.
327 /// In the database this variant is represented as NULL.
328 Password,
329 /// The keyblob is encrypted by another key with wrapped key id.
330 /// In the database this variant is represented as non NULL value
331 /// that is convertible to i64, typically NUMERIC.
332 KeyId(i64),
333}
334
335impl ToSql for EncryptedBy {
336 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
337 match self {
338 Self::Password => Ok(ToSqlOutput::Owned(Value::Null)),
339 Self::KeyId(id) => id.to_sql(),
340 }
341 }
342}
343
344impl FromSql for EncryptedBy {
345 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
346 match value {
347 ValueRef::Null => Ok(Self::Password),
348 _ => Ok(Self::KeyId(i64::column_result(value)?)),
349 }
350 }
351}
352
353/// A database representation of wall clock time. DateTime stores unix epoch time as
354/// i64 in milliseconds.
355#[derive(Debug, Copy, Clone, Default, Eq, PartialEq, Ord, PartialOrd)]
356pub struct DateTime(i64);
357
358/// Error type returned when creating DateTime or converting it from and to
359/// SystemTime.
360#[derive(thiserror::Error, Debug)]
361pub enum DateTimeError {
362 /// This is returned when SystemTime and Duration computations fail.
363 #[error(transparent)]
364 SystemTimeError(#[from] SystemTimeError),
365
366 /// This is returned when type conversions fail.
367 #[error(transparent)]
368 TypeConversion(#[from] std::num::TryFromIntError),
369
370 /// This is returned when checked time arithmetic failed.
371 #[error("Time arithmetic failed.")]
372 TimeArithmetic,
373}
374
375impl DateTime {
376 /// Constructs a new DateTime object denoting the current time. This may fail during
377 /// conversion to unix epoch time and during conversion to the internal i64 representation.
378 pub fn now() -> Result<Self, DateTimeError> {
379 Ok(Self(SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_millis().try_into()?))
380 }
381
382 /// Constructs a new DateTime object from milliseconds.
383 pub fn from_millis_epoch(millis: i64) -> Self {
384 Self(millis)
385 }
386
387 /// Returns unix epoch time in milliseconds.
388 pub fn to_millis_epoch(&self) -> i64 {
389 self.0
390 }
391
392 /// Returns unix epoch time in seconds.
393 pub fn to_secs_epoch(&self) -> i64 {
394 self.0 / 1000
395 }
396}
397
398impl ToSql for DateTime {
399 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
400 Ok(ToSqlOutput::Owned(Value::Integer(self.0)))
401 }
402}
403
404impl FromSql for DateTime {
405 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
406 Ok(Self(i64::column_result(value)?))
407 }
408}
409
410impl TryInto<SystemTime> for DateTime {
411 type Error = DateTimeError;
412
413 fn try_into(self) -> Result<SystemTime, Self::Error> {
414 // We want to construct a SystemTime representation equivalent to self, denoting
415 // a point in time THEN, but we cannot set the time directly. We can only construct
416 // a SystemTime denoting NOW, and we can get the duration between EPOCH and NOW,
417 // and between EPOCH and THEN. With this common reference we can construct the
418 // duration between NOW and THEN which we can add to our SystemTime representation
419 // of NOW to get a SystemTime representation of THEN.
420 // Durations can only be positive, thus the if statement below.
421 let now = SystemTime::now();
422 let now_epoch = now.duration_since(SystemTime::UNIX_EPOCH)?;
423 let then_epoch = Duration::from_millis(self.0.try_into()?);
424 Ok(if now_epoch > then_epoch {
425 // then = now - (now_epoch - then_epoch)
426 now_epoch
427 .checked_sub(then_epoch)
428 .and_then(|d| now.checked_sub(d))
429 .ok_or(DateTimeError::TimeArithmetic)?
430 } else {
431 // then = now + (then_epoch - now_epoch)
432 then_epoch
433 .checked_sub(now_epoch)
434 .and_then(|d| now.checked_add(d))
435 .ok_or(DateTimeError::TimeArithmetic)?
436 })
437 }
438}
439
440impl TryFrom<SystemTime> for DateTime {
441 type Error = DateTimeError;
442
443 fn try_from(t: SystemTime) -> Result<Self, Self::Error> {
444 Ok(Self(t.duration_since(SystemTime::UNIX_EPOCH)?.as_millis().try_into()?))
445 }
446}
447
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800448#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone)]
449enum KeyLifeCycle {
450 /// Existing keys have a key ID but are not fully populated yet.
451 /// This is a transient state. If Keystore finds any such keys when it starts up, it must move
452 /// them to Unreferenced for garbage collection.
453 Existing,
454 /// A live key is fully populated and usable by clients.
455 Live,
456 /// An unreferenced key is scheduled for garbage collection.
457 Unreferenced,
458}
459
460impl ToSql for KeyLifeCycle {
461 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
462 match self {
463 Self::Existing => Ok(ToSqlOutput::Owned(Value::Integer(0))),
464 Self::Live => Ok(ToSqlOutput::Owned(Value::Integer(1))),
465 Self::Unreferenced => Ok(ToSqlOutput::Owned(Value::Integer(2))),
466 }
467 }
468}
469
470impl FromSql for KeyLifeCycle {
471 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
472 match i64::column_result(value)? {
473 0 => Ok(KeyLifeCycle::Existing),
474 1 => Ok(KeyLifeCycle::Live),
475 2 => Ok(KeyLifeCycle::Unreferenced),
476 v => Err(FromSqlError::OutOfRange(v)),
477 }
478 }
479}
480
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700481/// Keys have a KeyMint blob component and optional public certificate and
482/// certificate chain components.
483/// KeyEntryLoadBits is a bitmap that indicates to `KeystoreDB::load_key_entry`
484/// which components shall be loaded from the database if present.
Janis Danisevskis66784c42021-01-27 08:40:25 -0800485#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700486pub struct KeyEntryLoadBits(u32);
487
488impl KeyEntryLoadBits {
489 /// Indicate to `KeystoreDB::load_key_entry` that no component shall be loaded.
490 pub const NONE: KeyEntryLoadBits = Self(0);
491 /// Indicate to `KeystoreDB::load_key_entry` that the KeyMint component shall be loaded.
492 pub const KM: KeyEntryLoadBits = Self(1);
493 /// Indicate to `KeystoreDB::load_key_entry` that the Public components shall be loaded.
494 pub const PUBLIC: KeyEntryLoadBits = Self(2);
495 /// Indicate to `KeystoreDB::load_key_entry` that both components shall be loaded.
496 pub const BOTH: KeyEntryLoadBits = Self(3);
497
498 /// Returns true if this object indicates that the public components shall be loaded.
499 pub const fn load_public(&self) -> bool {
500 self.0 & Self::PUBLIC.0 != 0
501 }
502
503 /// Returns true if the object indicates that the KeyMint component shall be loaded.
504 pub const fn load_km(&self) -> bool {
505 self.0 & Self::KM.0 != 0
506 }
507}
508
Janis Danisevskisaec14592020-11-12 09:41:49 -0800509lazy_static! {
510 static ref KEY_ID_LOCK: KeyIdLockDb = KeyIdLockDb::new();
511}
512
513struct KeyIdLockDb {
514 locked_keys: Mutex<HashSet<i64>>,
515 cond_var: Condvar,
516}
517
518/// A locked key. While a guard exists for a given key id, the same key cannot be loaded
519/// from the database a second time. Most functions manipulating the key blob database
520/// require a KeyIdGuard.
521#[derive(Debug)]
522pub struct KeyIdGuard(i64);
523
524impl KeyIdLockDb {
525 fn new() -> Self {
526 Self { locked_keys: Mutex::new(HashSet::new()), cond_var: Condvar::new() }
527 }
528
529 /// This function blocks until an exclusive lock for the given key entry id can
530 /// be acquired. It returns a guard object, that represents the lifecycle of the
531 /// acquired lock.
532 pub fn get(&self, key_id: i64) -> KeyIdGuard {
533 let mut locked_keys = self.locked_keys.lock().unwrap();
534 while locked_keys.contains(&key_id) {
535 locked_keys = self.cond_var.wait(locked_keys).unwrap();
536 }
537 locked_keys.insert(key_id);
538 KeyIdGuard(key_id)
539 }
540
541 /// This function attempts to acquire an exclusive lock on a given key id. If the
542 /// given key id is already taken the function returns None immediately. If a lock
543 /// can be acquired this function returns a guard object, that represents the
544 /// lifecycle of the acquired lock.
545 pub fn try_get(&self, key_id: i64) -> Option<KeyIdGuard> {
546 let mut locked_keys = self.locked_keys.lock().unwrap();
547 if locked_keys.insert(key_id) {
548 Some(KeyIdGuard(key_id))
549 } else {
550 None
551 }
552 }
553}
554
555impl KeyIdGuard {
556 /// Get the numeric key id of the locked key.
557 pub fn id(&self) -> i64 {
558 self.0
559 }
560}
561
562impl Drop for KeyIdGuard {
563 fn drop(&mut self) {
564 let mut locked_keys = KEY_ID_LOCK.locked_keys.lock().unwrap();
565 locked_keys.remove(&self.0);
Janis Danisevskis7fd53582020-11-23 13:40:34 -0800566 drop(locked_keys);
Janis Danisevskisaec14592020-11-12 09:41:49 -0800567 KEY_ID_LOCK.cond_var.notify_all();
568 }
569}
570
Max Bires8e93d2b2021-01-14 13:17:59 -0800571/// This type represents a certificate and certificate chain entry for a key.
Max Bires2b2e6562020-09-22 11:22:36 -0700572#[derive(Debug, Default)]
Max Bires8e93d2b2021-01-14 13:17:59 -0800573pub struct CertificateInfo {
574 cert: Option<Vec<u8>>,
575 cert_chain: Option<Vec<u8>>,
576}
577
578impl CertificateInfo {
579 /// Constructs a new CertificateInfo object from `cert` and `cert_chain`
580 pub fn new(cert: Option<Vec<u8>>, cert_chain: Option<Vec<u8>>) -> Self {
581 Self { cert, cert_chain }
582 }
583
584 /// Take the cert
585 pub fn take_cert(&mut self) -> Option<Vec<u8>> {
586 self.cert.take()
587 }
588
589 /// Take the cert chain
590 pub fn take_cert_chain(&mut self) -> Option<Vec<u8>> {
591 self.cert_chain.take()
592 }
593}
594
Max Bires2b2e6562020-09-22 11:22:36 -0700595/// This type represents a certificate chain with a private key corresponding to the leaf
596/// certificate. TODO(jbires): This will be used in a follow-on CL, for now it's used in the tests.
Max Bires2b2e6562020-09-22 11:22:36 -0700597pub struct CertificateChain {
Max Bires97f96812021-02-23 23:44:57 -0800598 /// A KM key blob
599 pub private_key: ZVec,
600 /// A batch cert for private_key
601 pub batch_cert: Vec<u8>,
602 /// A full certificate chain from root signing authority to private_key, including batch_cert
603 /// for convenience.
604 pub cert_chain: Vec<u8>,
Max Bires2b2e6562020-09-22 11:22:36 -0700605}
606
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700607/// This type represents a Keystore 2.0 key entry.
608/// An entry has a unique `id` by which it can be found in the database.
609/// It has a security level field, key parameters, and three optional fields
610/// for the KeyMint blob, public certificate and a public certificate chain.
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800611#[derive(Debug, Default, Eq, PartialEq)]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700612pub struct KeyEntry {
613 id: i64,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800614 key_blob_info: Option<(Vec<u8>, BlobMetaData)>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700615 cert: Option<Vec<u8>>,
616 cert_chain: Option<Vec<u8>>,
Max Bires8e93d2b2021-01-14 13:17:59 -0800617 km_uuid: Uuid,
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700618 parameters: Vec<KeyParameter>,
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800619 metadata: KeyMetaData,
Janis Danisevskis377d1002021-01-27 19:07:48 -0800620 pure_cert: bool,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700621}
622
623impl KeyEntry {
624 /// Returns the unique id of the Key entry.
625 pub fn id(&self) -> i64 {
626 self.id
627 }
628 /// Exposes the optional KeyMint blob.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800629 pub fn key_blob_info(&self) -> &Option<(Vec<u8>, BlobMetaData)> {
630 &self.key_blob_info
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700631 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800632 /// Extracts the Optional KeyMint blob including its metadata.
633 pub fn take_key_blob_info(&mut self) -> Option<(Vec<u8>, BlobMetaData)> {
634 self.key_blob_info.take()
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700635 }
636 /// Exposes the optional public certificate.
637 pub fn cert(&self) -> &Option<Vec<u8>> {
638 &self.cert
639 }
640 /// Extracts the optional public certificate.
641 pub fn take_cert(&mut self) -> Option<Vec<u8>> {
642 self.cert.take()
643 }
644 /// Exposes the optional public certificate chain.
645 pub fn cert_chain(&self) -> &Option<Vec<u8>> {
646 &self.cert_chain
647 }
648 /// Extracts the optional public certificate_chain.
649 pub fn take_cert_chain(&mut self) -> Option<Vec<u8>> {
650 self.cert_chain.take()
651 }
Max Bires8e93d2b2021-01-14 13:17:59 -0800652 /// Returns the uuid of the owning KeyMint instance.
653 pub fn km_uuid(&self) -> &Uuid {
654 &self.km_uuid
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700655 }
Janis Danisevskis04b02832020-10-26 09:21:40 -0700656 /// Exposes the key parameters of this key entry.
657 pub fn key_parameters(&self) -> &Vec<KeyParameter> {
658 &self.parameters
659 }
660 /// Consumes this key entry and extracts the keyparameters from it.
661 pub fn into_key_parameters(self) -> Vec<KeyParameter> {
662 self.parameters
663 }
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800664 /// Exposes the key metadata of this key entry.
665 pub fn metadata(&self) -> &KeyMetaData {
666 &self.metadata
667 }
Janis Danisevskis377d1002021-01-27 19:07:48 -0800668 /// This returns true if the entry is a pure certificate entry with no
669 /// private key component.
670 pub fn pure_cert(&self) -> bool {
671 self.pure_cert
672 }
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000673 /// Consumes this key entry and extracts the keyparameters and metadata from it.
674 pub fn into_key_parameters_and_metadata(self) -> (Vec<KeyParameter>, KeyMetaData) {
675 (self.parameters, self.metadata)
676 }
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700677}
678
679/// Indicates the sub component of a key entry for persistent storage.
Janis Danisevskis377d1002021-01-27 19:07:48 -0800680#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700681pub struct SubComponentType(u32);
682impl SubComponentType {
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800683 /// Persistent identifier for a key blob.
684 pub const KEY_BLOB: SubComponentType = Self(0);
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700685 /// Persistent identifier for a certificate blob.
686 pub const CERT: SubComponentType = Self(1);
687 /// Persistent identifier for a certificate chain blob.
688 pub const CERT_CHAIN: SubComponentType = Self(2);
689}
690
691impl ToSql for SubComponentType {
692 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
693 self.0.to_sql()
694 }
695}
696
697impl FromSql for SubComponentType {
698 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
699 Ok(Self(u32::column_result(value)?))
700 }
701}
702
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800703/// This trait is private to the database module. It is used to convey whether or not the garbage
704/// collector shall be invoked after a database access. All closures passed to
705/// `KeystoreDB::with_transaction` return a tuple (bool, T) where the bool indicates if the
706/// gc needs to be triggered. This convenience function allows to turn any anyhow::Result<T>
707/// into anyhow::Result<(bool, T)> by simply appending one of `.do_gc(bool)`, `.no_gc()`, or
708/// `.need_gc()`.
709trait DoGc<T> {
710 fn do_gc(self, need_gc: bool) -> Result<(bool, T)>;
711
712 fn no_gc(self) -> Result<(bool, T)>;
713
714 fn need_gc(self) -> Result<(bool, T)>;
715}
716
717impl<T> DoGc<T> for Result<T> {
718 fn do_gc(self, need_gc: bool) -> Result<(bool, T)> {
719 self.map(|r| (need_gc, r))
720 }
721
722 fn no_gc(self) -> Result<(bool, T)> {
723 self.do_gc(false)
724 }
725
726 fn need_gc(self) -> Result<(bool, T)> {
727 self.do_gc(true)
728 }
729}
730
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700731/// KeystoreDB wraps a connection to an SQLite database and tracks its
732/// ownership. It also implements all of Keystore 2.0's database functionality.
Joel Galenson26f4d012020-07-17 14:57:21 -0700733pub struct KeystoreDB {
Joel Galenson26f4d012020-07-17 14:57:21 -0700734 conn: Connection,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800735 gc: Option<Gc>,
Joel Galenson26f4d012020-07-17 14:57:21 -0700736}
737
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000738/// Database representation of the monotonic time retrieved from the system call clock_gettime with
739/// CLOCK_MONOTONIC_RAW. Stores monotonic time as i64 in seconds.
740#[derive(Debug, Copy, Clone, Default, Eq, PartialEq, Ord, PartialOrd)]
741pub struct MonotonicRawTime(i64);
742
743impl MonotonicRawTime {
744 /// Constructs a new MonotonicRawTime
745 pub fn now() -> Self {
746 Self(get_current_time_in_seconds())
747 }
748
David Drysdale0e45a612021-02-25 17:24:36 +0000749 /// Constructs a new MonotonicRawTime from a given number of seconds.
750 pub fn from_secs(val: i64) -> Self {
751 Self(val)
752 }
753
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000754 /// Returns the integer value of MonotonicRawTime as i64
755 pub fn seconds(&self) -> i64 {
756 self.0
757 }
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800758
Hasini Gunasingheb3715fb2021-02-26 20:34:45 +0000759 /// Returns the value of MonotonicRawTime in milli seconds as i64
760 pub fn milli_seconds(&self) -> i64 {
761 self.0 * 1000
762 }
763
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800764 /// Like i64::checked_sub.
765 pub fn checked_sub(&self, other: &Self) -> Option<Self> {
766 self.0.checked_sub(other.0).map(Self)
767 }
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000768}
769
770impl ToSql for MonotonicRawTime {
771 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
772 Ok(ToSqlOutput::Owned(Value::Integer(self.0)))
773 }
774}
775
776impl FromSql for MonotonicRawTime {
777 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
778 Ok(Self(i64::column_result(value)?))
779 }
780}
781
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000782/// This struct encapsulates the information to be stored in the database about the auth tokens
783/// received by keystore.
784pub struct AuthTokenEntry {
785 auth_token: HardwareAuthToken,
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000786 time_received: MonotonicRawTime,
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000787}
788
789impl AuthTokenEntry {
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000790 fn new(auth_token: HardwareAuthToken, time_received: MonotonicRawTime) -> Self {
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000791 AuthTokenEntry { auth_token, time_received }
792 }
793
794 /// Checks if this auth token satisfies the given authentication information.
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800795 pub fn satisfies(&self, user_secure_ids: &[i64], auth_type: HardwareAuthenticatorType) -> bool {
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000796 user_secure_ids.iter().any(|&sid| {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800797 (sid == self.auth_token.userId || sid == self.auth_token.authenticatorId)
798 && (((auth_type.0 as i32) & (self.auth_token.authenticatorType.0 as i32)) != 0)
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000799 })
800 }
801
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000802 /// Returns the auth token wrapped by the AuthTokenEntry
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800803 pub fn auth_token(&self) -> &HardwareAuthToken {
804 &self.auth_token
805 }
806
807 /// Returns the auth token wrapped by the AuthTokenEntry
808 pub fn take_auth_token(self) -> HardwareAuthToken {
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000809 self.auth_token
810 }
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800811
812 /// Returns the time that this auth token was received.
813 pub fn time_received(&self) -> MonotonicRawTime {
814 self.time_received
815 }
Hasini Gunasingheb3715fb2021-02-26 20:34:45 +0000816
817 /// Returns the challenge value of the auth token.
818 pub fn challenge(&self) -> i64 {
819 self.auth_token.challenge
820 }
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000821}
822
Janis Danisevskisb00ebd02021-02-02 21:52:24 -0800823/// Shared in-memory databases get destroyed as soon as the last connection to them gets closed.
824/// This object does not allow access to the database connection. But it keeps a database
825/// connection alive in order to keep the in memory per boot database alive.
826pub struct PerBootDbKeepAlive(Connection);
827
Joel Galenson26f4d012020-07-17 14:57:21 -0700828impl KeystoreDB {
Janis Danisevskiseed69842021-02-18 20:04:10 -0800829 const UNASSIGNED_KEY_ID: i64 = -1i64;
Janis Danisevskisb00ebd02021-02-02 21:52:24 -0800830 const PERBOOT_DB_FILE_NAME: &'static str = &"file:perboot.sqlite?mode=memory&cache=shared";
831
Seth Moore78c091f2021-04-09 21:38:30 +0000832 /// Name of the file that holds the cross-boot persistent database.
833 pub const PERSISTENT_DB_FILENAME: &'static str = &"persistent.sqlite";
834
Janis Danisevskisb00ebd02021-02-02 21:52:24 -0800835 /// This creates a PerBootDbKeepAlive object to keep the per boot database alive.
836 pub fn keep_perboot_db_alive() -> Result<PerBootDbKeepAlive> {
837 let conn = Connection::open_in_memory()
838 .context("In keep_perboot_db_alive: Failed to initialize SQLite connection.")?;
839
840 conn.execute("ATTACH DATABASE ? as perboot;", params![Self::PERBOOT_DB_FILE_NAME])
841 .context("In keep_perboot_db_alive: Failed to attach database perboot.")?;
842 Ok(PerBootDbKeepAlive(conn))
843 }
844
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700845 /// This will create a new database connection connecting the two
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800846 /// files persistent.sqlite and perboot.sqlite in the given directory.
847 /// It also attempts to initialize all of the tables.
848 /// KeystoreDB cannot be used by multiple threads.
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700849 /// Each thread should open their own connection using `thread_local!`.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800850 pub fn new(db_root: &Path, gc: Option<Gc>) -> Result<Self> {
Janis Danisevskisb00ebd02021-02-02 21:52:24 -0800851 // Build the path to the sqlite file.
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800852 let mut persistent_path = db_root.to_path_buf();
Seth Moore78c091f2021-04-09 21:38:30 +0000853 persistent_path.push(Self::PERSISTENT_DB_FILENAME);
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700854
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800855 // Now convert them to strings prefixed with "file:"
856 let mut persistent_path_str = "file:".to_owned();
857 persistent_path_str.push_str(&persistent_path.to_string_lossy());
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800858
Janis Danisevskisb00ebd02021-02-02 21:52:24 -0800859 let conn = Self::make_connection(&persistent_path_str, &Self::PERBOOT_DB_FILE_NAME)?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800860
Janis Danisevskis66784c42021-01-27 08:40:25 -0800861 // On busy fail Immediately. It is unlikely to succeed given a bug in sqlite.
862 conn.busy_handler(None).context("In KeystoreDB::new: Failed to set busy handler.")?;
863
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800864 let mut db = Self { conn, gc };
Janis Danisevskis66784c42021-01-27 08:40:25 -0800865 db.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800866 Self::init_tables(tx).context("Trying to initialize tables.").no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -0800867 })?;
868 Ok(db)
Joel Galenson2aab4432020-07-22 15:27:57 -0700869 }
870
Janis Danisevskis66784c42021-01-27 08:40:25 -0800871 fn init_tables(tx: &Transaction) -> Result<()> {
872 tx.execute(
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700873 "CREATE TABLE IF NOT EXISTS persistent.keyentry (
Joel Galenson0891bc12020-07-20 10:37:03 -0700874 id INTEGER UNIQUE,
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800875 key_type INTEGER,
Joel Galenson0891bc12020-07-20 10:37:03 -0700876 domain INTEGER,
877 namespace INTEGER,
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800878 alias BLOB,
Max Bires8e93d2b2021-01-14 13:17:59 -0800879 state INTEGER,
880 km_uuid BLOB);",
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700881 NO_PARAMS,
882 )
883 .context("Failed to initialize \"keyentry\" table.")?;
884
Janis Danisevskis66784c42021-01-27 08:40:25 -0800885 tx.execute(
Janis Danisevskisa5438182021-02-02 14:22:59 -0800886 "CREATE INDEX IF NOT EXISTS persistent.keyentry_id_index
887 ON keyentry(id);",
888 NO_PARAMS,
889 )
890 .context("Failed to create index keyentry_id_index.")?;
891
892 tx.execute(
893 "CREATE INDEX IF NOT EXISTS persistent.keyentry_domain_namespace_index
894 ON keyentry(domain, namespace, alias);",
895 NO_PARAMS,
896 )
897 .context("Failed to create index keyentry_domain_namespace_index.")?;
898
899 tx.execute(
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700900 "CREATE TABLE IF NOT EXISTS persistent.blobentry (
901 id INTEGER PRIMARY KEY,
902 subcomponent_type INTEGER,
903 keyentryid INTEGER,
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800904 blob BLOB);",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700905 NO_PARAMS,
906 )
907 .context("Failed to initialize \"blobentry\" table.")?;
908
Janis Danisevskis66784c42021-01-27 08:40:25 -0800909 tx.execute(
Janis Danisevskisa5438182021-02-02 14:22:59 -0800910 "CREATE INDEX IF NOT EXISTS persistent.blobentry_keyentryid_index
911 ON blobentry(keyentryid);",
912 NO_PARAMS,
913 )
914 .context("Failed to create index blobentry_keyentryid_index.")?;
915
916 tx.execute(
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800917 "CREATE TABLE IF NOT EXISTS persistent.blobmetadata (
918 id INTEGER PRIMARY KEY,
919 blobentryid INTEGER,
920 tag INTEGER,
921 data ANY,
922 UNIQUE (blobentryid, tag));",
923 NO_PARAMS,
924 )
925 .context("Failed to initialize \"blobmetadata\" table.")?;
926
927 tx.execute(
928 "CREATE INDEX IF NOT EXISTS persistent.blobmetadata_blobentryid_index
929 ON blobmetadata(blobentryid);",
930 NO_PARAMS,
931 )
932 .context("Failed to create index blobmetadata_blobentryid_index.")?;
933
934 tx.execute(
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700935 "CREATE TABLE IF NOT EXISTS persistent.keyparameter (
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000936 keyentryid INTEGER,
937 tag INTEGER,
938 data ANY,
939 security_level INTEGER);",
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700940 NO_PARAMS,
941 )
942 .context("Failed to initialize \"keyparameter\" table.")?;
943
Janis Danisevskis66784c42021-01-27 08:40:25 -0800944 tx.execute(
Janis Danisevskisa5438182021-02-02 14:22:59 -0800945 "CREATE INDEX IF NOT EXISTS persistent.keyparameter_keyentryid_index
946 ON keyparameter(keyentryid);",
947 NO_PARAMS,
948 )
949 .context("Failed to create index keyparameter_keyentryid_index.")?;
950
951 tx.execute(
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800952 "CREATE TABLE IF NOT EXISTS persistent.keymetadata (
953 keyentryid INTEGER,
954 tag INTEGER,
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000955 data ANY,
956 UNIQUE (keyentryid, tag));",
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800957 NO_PARAMS,
958 )
959 .context("Failed to initialize \"keymetadata\" table.")?;
960
Janis Danisevskis66784c42021-01-27 08:40:25 -0800961 tx.execute(
Janis Danisevskisa5438182021-02-02 14:22:59 -0800962 "CREATE INDEX IF NOT EXISTS persistent.keymetadata_keyentryid_index
963 ON keymetadata(keyentryid);",
964 NO_PARAMS,
965 )
966 .context("Failed to create index keymetadata_keyentryid_index.")?;
967
968 tx.execute(
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800969 "CREATE TABLE IF NOT EXISTS persistent.grant (
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700970 id INTEGER UNIQUE,
971 grantee INTEGER,
972 keyentryid INTEGER,
973 access_vector INTEGER);",
974 NO_PARAMS,
975 )
976 .context("Failed to initialize \"grant\" table.")?;
977
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000978 //TODO: only drop the following two perboot tables if this is the first start up
979 //during the boot (b/175716626).
Janis Danisevskis66784c42021-01-27 08:40:25 -0800980 // tx.execute("DROP TABLE IF EXISTS perboot.authtoken;", NO_PARAMS)
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000981 // .context("Failed to drop perboot.authtoken table")?;
Janis Danisevskis66784c42021-01-27 08:40:25 -0800982 tx.execute(
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000983 "CREATE TABLE IF NOT EXISTS perboot.authtoken (
984 id INTEGER PRIMARY KEY,
985 challenge INTEGER,
986 user_id INTEGER,
987 auth_id INTEGER,
988 authenticator_type INTEGER,
989 timestamp INTEGER,
990 mac BLOB,
991 time_received INTEGER,
992 UNIQUE(user_id, auth_id, authenticator_type));",
993 NO_PARAMS,
994 )
995 .context("Failed to initialize \"authtoken\" table.")?;
996
Janis Danisevskis66784c42021-01-27 08:40:25 -0800997 // tx.execute("DROP TABLE IF EXISTS perboot.metadata;", NO_PARAMS)
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000998 // .context("Failed to drop perboot.metadata table")?;
999 // metadata table stores certain miscellaneous information required for keystore functioning
1000 // during a boot cycle, as key-value pairs.
Janis Danisevskis66784c42021-01-27 08:40:25 -08001001 tx.execute(
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00001002 "CREATE TABLE IF NOT EXISTS perboot.metadata (
1003 key TEXT,
1004 value BLOB,
1005 UNIQUE(key));",
1006 NO_PARAMS,
1007 )
1008 .context("Failed to initialize \"metadata\" table.")?;
Joel Galenson0891bc12020-07-20 10:37:03 -07001009 Ok(())
1010 }
1011
Janis Danisevskis4df44f42020-08-26 14:40:03 -07001012 fn make_connection(persistent_file: &str, perboot_file: &str) -> Result<Connection> {
1013 let conn =
1014 Connection::open_in_memory().context("Failed to initialize SQLite connection.")?;
1015
Janis Danisevskis66784c42021-01-27 08:40:25 -08001016 loop {
1017 if let Err(e) = conn
1018 .execute("ATTACH DATABASE ? as persistent;", params![persistent_file])
1019 .context("Failed to attach database persistent.")
1020 {
1021 if Self::is_locked_error(&e) {
1022 std::thread::sleep(std::time::Duration::from_micros(500));
1023 continue;
1024 } else {
1025 return Err(e);
1026 }
1027 }
1028 break;
1029 }
1030 loop {
1031 if let Err(e) = conn
1032 .execute("ATTACH DATABASE ? as perboot;", params![perboot_file])
1033 .context("Failed to attach database perboot.")
1034 {
1035 if Self::is_locked_error(&e) {
1036 std::thread::sleep(std::time::Duration::from_micros(500));
1037 continue;
1038 } else {
1039 return Err(e);
1040 }
1041 }
1042 break;
1043 }
Janis Danisevskis4df44f42020-08-26 14:40:03 -07001044
1045 Ok(conn)
1046 }
1047
Seth Moore78c091f2021-04-09 21:38:30 +00001048 fn do_table_size_query(
1049 &mut self,
1050 storage_type: StatsdStorageType,
1051 query: &str,
1052 params: &[&str],
1053 ) -> Result<Keystore2StorageStats> {
1054 let (total, unused) = self.with_transaction(TransactionBehavior::Deferred, |tx| {
1055 tx.query_row(query, params, |row| Ok((row.get(0)?, row.get(1)?)))
1056 .with_context(|| {
1057 format!("get_storage_stat: Error size of storage type {}", storage_type as i32)
1058 })
1059 .no_gc()
1060 })?;
1061 Ok(Keystore2StorageStats { storage_type, size: total, unused_size: unused })
1062 }
1063
1064 fn get_total_size(&mut self) -> Result<Keystore2StorageStats> {
1065 self.do_table_size_query(
1066 StatsdStorageType::Database,
1067 "SELECT page_count * page_size, freelist_count * page_size
1068 FROM pragma_page_count('persistent'),
1069 pragma_page_size('persistent'),
1070 persistent.pragma_freelist_count();",
1071 &[],
1072 )
1073 }
1074
1075 fn get_table_size(
1076 &mut self,
1077 storage_type: StatsdStorageType,
1078 schema: &str,
1079 table: &str,
1080 ) -> Result<Keystore2StorageStats> {
1081 self.do_table_size_query(
1082 storage_type,
1083 "SELECT pgsize,unused FROM dbstat(?1)
1084 WHERE name=?2 AND aggregate=TRUE;",
1085 &[schema, table],
1086 )
1087 }
1088
1089 /// Fetches a storage statisitics atom for a given storage type. For storage
1090 /// types that map to a table, information about the table's storage is
1091 /// returned. Requests for storage types that are not DB tables return None.
1092 pub fn get_storage_stat(
1093 &mut self,
1094 storage_type: StatsdStorageType,
1095 ) -> Result<Keystore2StorageStats> {
1096 match storage_type {
1097 StatsdStorageType::Database => self.get_total_size(),
1098 StatsdStorageType::KeyEntry => {
1099 self.get_table_size(storage_type, "persistent", "keyentry")
1100 }
1101 StatsdStorageType::KeyEntryIdIndex => {
1102 self.get_table_size(storage_type, "persistent", "keyentry_id_index")
1103 }
1104 StatsdStorageType::KeyEntryDomainNamespaceIndex => {
1105 self.get_table_size(storage_type, "persistent", "keyentry_domain_namespace_index")
1106 }
1107 StatsdStorageType::BlobEntry => {
1108 self.get_table_size(storage_type, "persistent", "blobentry")
1109 }
1110 StatsdStorageType::BlobEntryKeyEntryIdIndex => {
1111 self.get_table_size(storage_type, "persistent", "blobentry_keyentryid_index")
1112 }
1113 StatsdStorageType::KeyParameter => {
1114 self.get_table_size(storage_type, "persistent", "keyparameter")
1115 }
1116 StatsdStorageType::KeyParameterKeyEntryIdIndex => {
1117 self.get_table_size(storage_type, "persistent", "keyparameter_keyentryid_index")
1118 }
1119 StatsdStorageType::KeyMetadata => {
1120 self.get_table_size(storage_type, "persistent", "keymetadata")
1121 }
1122 StatsdStorageType::KeyMetadataKeyEntryIdIndex => {
1123 self.get_table_size(storage_type, "persistent", "keymetadata_keyentryid_index")
1124 }
1125 StatsdStorageType::Grant => self.get_table_size(storage_type, "persistent", "grant"),
1126 StatsdStorageType::AuthToken => {
1127 self.get_table_size(storage_type, "perboot", "authtoken")
1128 }
1129 StatsdStorageType::BlobMetadata => {
1130 self.get_table_size(storage_type, "persistent", "blobmetadata")
1131 }
1132 StatsdStorageType::BlobMetadataBlobEntryIdIndex => {
1133 self.get_table_size(storage_type, "persistent", "blobmetadata_blobentryid_index")
1134 }
1135 _ => Err(anyhow::Error::msg(format!(
1136 "Unsupported storage type: {}",
1137 storage_type as i32
1138 ))),
1139 }
1140 }
1141
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001142 /// This function is intended to be used by the garbage collector.
1143 /// It deletes the blob given by `blob_id_to_delete`. It then tries to find a superseded
1144 /// key blob that might need special handling by the garbage collector.
1145 /// If no further superseded blobs can be found it deletes all other superseded blobs that don't
1146 /// need special handling and returns None.
1147 pub fn handle_next_superseded_blob(
1148 &mut self,
1149 blob_id_to_delete: Option<i64>,
1150 ) -> Result<Option<(i64, Vec<u8>, BlobMetaData)>> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001151 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001152 // Delete the given blob if one was given.
1153 if let Some(blob_id_to_delete) = blob_id_to_delete {
1154 tx.execute(
1155 "DELETE FROM persistent.blobmetadata WHERE blobentryid = ?;",
1156 params![blob_id_to_delete],
1157 )
1158 .context("Trying to delete blob metadata.")?;
1159 tx.execute(
1160 "DELETE FROM persistent.blobentry WHERE id = ?;",
1161 params![blob_id_to_delete],
1162 )
1163 .context("Trying to blob.")?;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001164 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001165
1166 // Find another superseded keyblob load its metadata and return it.
1167 if let Some((blob_id, blob)) = tx
1168 .query_row(
1169 "SELECT id, blob FROM persistent.blobentry
1170 WHERE subcomponent_type = ?
1171 AND (
1172 id NOT IN (
1173 SELECT MAX(id) FROM persistent.blobentry
1174 WHERE subcomponent_type = ?
1175 GROUP BY keyentryid, subcomponent_type
1176 )
1177 OR keyentryid NOT IN (SELECT id FROM persistent.keyentry)
1178 );",
1179 params![SubComponentType::KEY_BLOB, SubComponentType::KEY_BLOB],
1180 |row| Ok((row.get(0)?, row.get(1)?)),
1181 )
1182 .optional()
1183 .context("Trying to query superseded blob.")?
1184 {
1185 let blob_metadata = BlobMetaData::load_from_db(blob_id, tx)
1186 .context("Trying to load blob metadata.")?;
1187 return Ok(Some((blob_id, blob, blob_metadata))).no_gc();
1188 }
1189
1190 // We did not find any superseded key blob, so let's remove other superseded blob in
1191 // one transaction.
1192 tx.execute(
1193 "DELETE FROM persistent.blobentry
1194 WHERE NOT subcomponent_type = ?
1195 AND (
1196 id NOT IN (
1197 SELECT MAX(id) FROM persistent.blobentry
1198 WHERE NOT subcomponent_type = ?
1199 GROUP BY keyentryid, subcomponent_type
1200 ) OR keyentryid NOT IN (SELECT id FROM persistent.keyentry)
1201 );",
1202 params![SubComponentType::KEY_BLOB, SubComponentType::KEY_BLOB],
1203 )
1204 .context("Trying to purge superseded blobs.")?;
1205
1206 Ok(None).no_gc()
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001207 })
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001208 .context("In handle_next_superseded_blob.")
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001209 }
1210
1211 /// This maintenance function should be called only once before the database is used for the
1212 /// first time. It restores the invariant that `KeyLifeCycle::Existing` is a transient state.
1213 /// The function transitions all key entries from Existing to Unreferenced unconditionally and
1214 /// returns the number of rows affected. If this returns a value greater than 0, it means that
1215 /// Keystore crashed at some point during key generation. Callers may want to log such
1216 /// occurrences.
1217 /// Unlike with `mark_unreferenced`, we don't need to purge grants, because only keys that made
1218 /// it to `KeyLifeCycle::Live` may have grants.
1219 pub fn cleanup_leftovers(&mut self) -> Result<usize> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001220 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1221 tx.execute(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001222 "UPDATE persistent.keyentry SET state = ? WHERE state = ?;",
1223 params![KeyLifeCycle::Unreferenced, KeyLifeCycle::Existing],
1224 )
Janis Danisevskis66784c42021-01-27 08:40:25 -08001225 .context("Failed to execute query.")
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001226 .need_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08001227 })
1228 .context("In cleanup_leftovers.")
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001229 }
1230
Hasini Gunasinghe0e161452021-01-27 19:34:37 +00001231 /// Checks if a key exists with given key type and key descriptor properties.
1232 pub fn key_exists(
1233 &mut self,
1234 domain: Domain,
1235 nspace: i64,
1236 alias: &str,
1237 key_type: KeyType,
1238 ) -> Result<bool> {
1239 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1240 let key_descriptor =
1241 KeyDescriptor { domain, nspace, alias: Some(alias.to_string()), blob: None };
1242 let result = Self::load_key_entry_id(&tx, &key_descriptor, key_type);
1243 match result {
1244 Ok(_) => Ok(true),
1245 Err(error) => match error.root_cause().downcast_ref::<KsError>() {
1246 Some(KsError::Rc(ResponseCode::KEY_NOT_FOUND)) => Ok(false),
1247 _ => Err(error).context("In key_exists: Failed to find if the key exists."),
1248 },
1249 }
1250 .no_gc()
1251 })
1252 .context("In key_exists.")
1253 }
1254
Hasini Gunasingheda895552021-01-27 19:34:37 +00001255 /// Stores a super key in the database.
1256 pub fn store_super_key(
1257 &mut self,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +00001258 user_id: u32,
Paul Crowley7a658392021-03-18 17:08:20 -07001259 key_type: &SuperKeyType,
1260 blob: &[u8],
1261 blob_metadata: &BlobMetaData,
Paul Crowley8d5b2532021-03-19 10:53:07 -07001262 key_metadata: &KeyMetaData,
Hasini Gunasingheda895552021-01-27 19:34:37 +00001263 ) -> Result<KeyEntry> {
1264 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1265 let key_id = Self::insert_with_retry(|id| {
1266 tx.execute(
1267 "INSERT into persistent.keyentry
1268 (id, key_type, domain, namespace, alias, state, km_uuid)
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00001269 VALUES(?, ?, ?, ?, ?, ?, ?);",
Hasini Gunasingheda895552021-01-27 19:34:37 +00001270 params![
1271 id,
1272 KeyType::Super,
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00001273 Domain::APP.0,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +00001274 user_id as i64,
Paul Crowley7a658392021-03-18 17:08:20 -07001275 key_type.alias,
Hasini Gunasingheda895552021-01-27 19:34:37 +00001276 KeyLifeCycle::Live,
1277 &KEYSTORE_UUID,
1278 ],
1279 )
1280 })
1281 .context("Failed to insert into keyentry table.")?;
1282
Paul Crowley8d5b2532021-03-19 10:53:07 -07001283 key_metadata.store_in_db(key_id, tx).context("KeyMetaData::store_in_db failed")?;
1284
Hasini Gunasingheda895552021-01-27 19:34:37 +00001285 Self::set_blob_internal(
1286 &tx,
1287 key_id,
1288 SubComponentType::KEY_BLOB,
1289 Some(blob),
1290 Some(blob_metadata),
1291 )
1292 .context("Failed to store key blob.")?;
1293
1294 Self::load_key_components(tx, KeyEntryLoadBits::KM, key_id)
1295 .context("Trying to load key components.")
1296 .no_gc()
1297 })
1298 .context("In store_super_key.")
1299 }
1300
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +00001301 /// Loads super key of a given user, if exists
Paul Crowley7a658392021-03-18 17:08:20 -07001302 pub fn load_super_key(
1303 &mut self,
1304 key_type: &SuperKeyType,
1305 user_id: u32,
1306 ) -> Result<Option<(KeyIdGuard, KeyEntry)>> {
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +00001307 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1308 let key_descriptor = KeyDescriptor {
1309 domain: Domain::APP,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +00001310 nspace: user_id as i64,
Paul Crowley7a658392021-03-18 17:08:20 -07001311 alias: Some(key_type.alias.into()),
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +00001312 blob: None,
1313 };
1314 let id = Self::load_key_entry_id(&tx, &key_descriptor, KeyType::Super);
1315 match id {
1316 Ok(id) => {
1317 let key_entry = Self::load_key_components(&tx, KeyEntryLoadBits::KM, id)
1318 .context("In load_super_key. Failed to load key entry.")?;
1319 Ok(Some((KEY_ID_LOCK.get(id), key_entry)))
1320 }
1321 Err(error) => match error.root_cause().downcast_ref::<KsError>() {
1322 Some(KsError::Rc(ResponseCode::KEY_NOT_FOUND)) => Ok(None),
1323 _ => Err(error).context("In load_super_key."),
1324 },
1325 }
1326 .no_gc()
1327 })
1328 .context("In load_super_key.")
1329 }
1330
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001331 /// Atomically loads a key entry and associated metadata or creates it using the
1332 /// callback create_new_key callback. The callback is called during a database
1333 /// transaction. This means that implementers should be mindful about using
1334 /// blocking operations such as IPC or grabbing mutexes.
1335 pub fn get_or_create_key_with<F>(
1336 &mut self,
1337 domain: Domain,
1338 namespace: i64,
1339 alias: &str,
Max Bires8e93d2b2021-01-14 13:17:59 -08001340 km_uuid: Uuid,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001341 create_new_key: F,
1342 ) -> Result<(KeyIdGuard, KeyEntry)>
1343 where
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001344 F: Fn() -> Result<(Vec<u8>, BlobMetaData)>,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001345 {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001346 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1347 let id = {
1348 let mut stmt = tx
1349 .prepare(
1350 "SELECT id FROM persistent.keyentry
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001351 WHERE
1352 key_type = ?
1353 AND domain = ?
1354 AND namespace = ?
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001355 AND alias = ?
1356 AND state = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08001357 )
1358 .context("In get_or_create_key_with: Failed to select from keyentry table.")?;
1359 let mut rows = stmt
1360 .query(params![KeyType::Super, domain.0, namespace, alias, KeyLifeCycle::Live])
1361 .context("In get_or_create_key_with: Failed to query from keyentry table.")?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001362
Janis Danisevskis66784c42021-01-27 08:40:25 -08001363 db_utils::with_rows_extract_one(&mut rows, |row| {
1364 Ok(match row {
1365 Some(r) => r.get(0).context("Failed to unpack id.")?,
1366 None => None,
1367 })
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001368 })
Janis Danisevskis66784c42021-01-27 08:40:25 -08001369 .context("In get_or_create_key_with.")?
1370 };
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001371
Janis Danisevskis66784c42021-01-27 08:40:25 -08001372 let (id, entry) = match id {
1373 Some(id) => (
1374 id,
1375 Self::load_key_components(&tx, KeyEntryLoadBits::KM, id)
1376 .context("In get_or_create_key_with.")?,
1377 ),
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001378
Janis Danisevskis66784c42021-01-27 08:40:25 -08001379 None => {
1380 let id = Self::insert_with_retry(|id| {
1381 tx.execute(
1382 "INSERT into persistent.keyentry
Max Bires8e93d2b2021-01-14 13:17:59 -08001383 (id, key_type, domain, namespace, alias, state, km_uuid)
1384 VALUES(?, ?, ?, ?, ?, ?, ?);",
Janis Danisevskis66784c42021-01-27 08:40:25 -08001385 params![
1386 id,
1387 KeyType::Super,
1388 domain.0,
1389 namespace,
1390 alias,
1391 KeyLifeCycle::Live,
1392 km_uuid,
1393 ],
1394 )
1395 })
1396 .context("In get_or_create_key_with.")?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001397
Janis Danisevskis66784c42021-01-27 08:40:25 -08001398 let (blob, metadata) =
1399 create_new_key().context("In get_or_create_key_with.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001400 Self::set_blob_internal(
1401 &tx,
1402 id,
1403 SubComponentType::KEY_BLOB,
1404 Some(&blob),
1405 Some(&metadata),
1406 )
Paul Crowley7a658392021-03-18 17:08:20 -07001407 .context("In get_or_create_key_with.")?;
Janis Danisevskis66784c42021-01-27 08:40:25 -08001408 (
Janis Danisevskis377d1002021-01-27 19:07:48 -08001409 id,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001410 KeyEntry {
1411 id,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001412 key_blob_info: Some((blob, metadata)),
Janis Danisevskis66784c42021-01-27 08:40:25 -08001413 pure_cert: false,
1414 ..Default::default()
1415 },
1416 )
1417 }
1418 };
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001419 Ok((KEY_ID_LOCK.get(id), entry)).no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08001420 })
1421 .context("In get_or_create_key_with.")
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001422 }
1423
Janis Danisevskis66784c42021-01-27 08:40:25 -08001424 /// SQLite3 seems to hold a shared mutex while running the busy handler when
1425 /// waiting for the database file to become available. This makes it
1426 /// impossible to successfully recover from a locked database when the
1427 /// transaction holding the device busy is in the same process on a
1428 /// different connection. As a result the busy handler has to time out and
1429 /// fail in order to make progress.
1430 ///
1431 /// Instead, we set the busy handler to None (return immediately). And catch
1432 /// Busy and Locked errors (the latter occur on in memory databases with
1433 /// shared cache, e.g., the per-boot database.) and restart the transaction
1434 /// after a grace period of half a millisecond.
1435 ///
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001436 /// Creates a transaction with the given behavior and executes f with the new transaction.
Janis Danisevskis66784c42021-01-27 08:40:25 -08001437 /// The transaction is committed only if f returns Ok and retried if DatabaseBusy
1438 /// or DatabaseLocked is encountered.
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001439 fn with_transaction<T, F>(&mut self, behavior: TransactionBehavior, f: F) -> Result<T>
1440 where
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001441 F: Fn(&Transaction) -> Result<(bool, T)>,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001442 {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001443 loop {
1444 match self
1445 .conn
1446 .transaction_with_behavior(behavior)
1447 .context("In with_transaction.")
1448 .and_then(|tx| f(&tx).map(|result| (result, tx)))
1449 .and_then(|(result, tx)| {
1450 tx.commit().context("In with_transaction: Failed to commit transaction.")?;
1451 Ok(result)
1452 }) {
1453 Ok(result) => break Ok(result),
1454 Err(e) => {
1455 if Self::is_locked_error(&e) {
1456 std::thread::sleep(std::time::Duration::from_micros(500));
1457 continue;
1458 } else {
1459 return Err(e).context("In with_transaction.");
1460 }
1461 }
1462 }
1463 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001464 .map(|(need_gc, result)| {
1465 if need_gc {
1466 if let Some(ref gc) = self.gc {
1467 gc.notify_gc();
1468 }
1469 }
1470 result
1471 })
Janis Danisevskis66784c42021-01-27 08:40:25 -08001472 }
1473
1474 fn is_locked_error(e: &anyhow::Error) -> bool {
Paul Crowleyf61fee72021-03-17 14:38:44 -07001475 matches!(
1476 e.root_cause().downcast_ref::<rusqlite::ffi::Error>(),
1477 Some(rusqlite::ffi::Error { code: rusqlite::ErrorCode::DatabaseBusy, .. })
1478 | Some(rusqlite::ffi::Error { code: rusqlite::ErrorCode::DatabaseLocked, .. })
1479 )
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001480 }
1481
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001482 /// Creates a new key entry and allocates a new randomized id for the new key.
1483 /// The key id gets associated with a domain and namespace but not with an alias.
1484 /// To complete key generation `rebind_alias` should be called after all of the
1485 /// key artifacts, i.e., blobs and parameters have been associated with the new
1486 /// key id. Finalizing with `rebind_alias` makes the creation of a new key entry
1487 /// atomic even if key generation is not.
Max Bires8e93d2b2021-01-14 13:17:59 -08001488 pub fn create_key_entry(
1489 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001490 domain: &Domain,
1491 namespace: &i64,
Max Bires8e93d2b2021-01-14 13:17:59 -08001492 km_uuid: &Uuid,
1493 ) -> Result<KeyIdGuard> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001494 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001495 Self::create_key_entry_internal(tx, domain, namespace, km_uuid).no_gc()
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001496 })
1497 .context("In create_key_entry.")
1498 }
1499
1500 fn create_key_entry_internal(
1501 tx: &Transaction,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001502 domain: &Domain,
1503 namespace: &i64,
Max Bires8e93d2b2021-01-14 13:17:59 -08001504 km_uuid: &Uuid,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001505 ) -> Result<KeyIdGuard> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001506 match *domain {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001507 Domain::APP | Domain::SELINUX => {}
Joel Galenson0891bc12020-07-20 10:37:03 -07001508 _ => {
1509 return Err(KsError::sys())
1510 .context(format!("Domain {:?} must be either App or SELinux.", domain));
1511 }
1512 }
Janis Danisevskisaec14592020-11-12 09:41:49 -08001513 Ok(KEY_ID_LOCK.get(
1514 Self::insert_with_retry(|id| {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001515 tx.execute(
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001516 "INSERT into persistent.keyentry
Max Bires8e93d2b2021-01-14 13:17:59 -08001517 (id, key_type, domain, namespace, alias, state, km_uuid)
1518 VALUES(?, ?, ?, ?, NULL, ?, ?);",
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001519 params![
1520 id,
1521 KeyType::Client,
1522 domain.0 as u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001523 *namespace,
Max Bires8e93d2b2021-01-14 13:17:59 -08001524 KeyLifeCycle::Existing,
1525 km_uuid,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001526 ],
Janis Danisevskisaec14592020-11-12 09:41:49 -08001527 )
1528 })
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001529 .context("In create_key_entry_internal")?,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001530 ))
Joel Galenson26f4d012020-07-17 14:57:21 -07001531 }
Joel Galenson33c04ad2020-08-03 11:04:38 -07001532
Max Bires2b2e6562020-09-22 11:22:36 -07001533 /// Creates a new attestation key entry and allocates a new randomized id for the new key.
1534 /// The key id gets associated with a domain and namespace later but not with an alias. The
1535 /// alias will be used to denote if a key has been signed as each key can only be bound to one
1536 /// domain and namespace pairing so there is no need to use them as a value for indexing into
1537 /// a key.
1538 pub fn create_attestation_key_entry(
1539 &mut self,
1540 maced_public_key: &[u8],
1541 raw_public_key: &[u8],
1542 private_key: &[u8],
1543 km_uuid: &Uuid,
1544 ) -> Result<()> {
1545 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1546 let key_id = KEY_ID_LOCK.get(
1547 Self::insert_with_retry(|id| {
1548 tx.execute(
1549 "INSERT into persistent.keyentry
1550 (id, key_type, domain, namespace, alias, state, km_uuid)
1551 VALUES(?, ?, NULL, NULL, NULL, ?, ?);",
1552 params![id, KeyType::Attestation, KeyLifeCycle::Live, km_uuid],
1553 )
1554 })
1555 .context("In create_key_entry")?,
1556 );
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001557 Self::set_blob_internal(
1558 &tx,
1559 key_id.0,
1560 SubComponentType::KEY_BLOB,
1561 Some(private_key),
1562 None,
1563 )?;
Max Bires2b2e6562020-09-22 11:22:36 -07001564 let mut metadata = KeyMetaData::new();
1565 metadata.add(KeyMetaEntry::AttestationMacedPublicKey(maced_public_key.to_vec()));
1566 metadata.add(KeyMetaEntry::AttestationRawPubKey(raw_public_key.to_vec()));
1567 metadata.store_in_db(key_id.0, &tx)?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001568 Ok(()).no_gc()
Max Bires2b2e6562020-09-22 11:22:36 -07001569 })
1570 .context("In create_attestation_key_entry")
1571 }
1572
Janis Danisevskis377d1002021-01-27 19:07:48 -08001573 /// Set a new blob and associates it with the given key id. Each blob
1574 /// has a sub component type.
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001575 /// Each key can have one of each sub component type associated. If more
1576 /// are added only the most recent can be retrieved, and superseded blobs
Janis Danisevskis377d1002021-01-27 19:07:48 -08001577 /// will get garbage collected.
1578 /// Components SubComponentType::CERT and SubComponentType::CERT_CHAIN can be
1579 /// removed by setting blob to None.
1580 pub fn set_blob(
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001581 &mut self,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001582 key_id: &KeyIdGuard,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001583 sc_type: SubComponentType,
Janis Danisevskis377d1002021-01-27 19:07:48 -08001584 blob: Option<&[u8]>,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001585 blob_metadata: Option<&BlobMetaData>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001586 ) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001587 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001588 Self::set_blob_internal(&tx, key_id.0, sc_type, blob, blob_metadata).need_gc()
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001589 })
Janis Danisevskis377d1002021-01-27 19:07:48 -08001590 .context("In set_blob.")
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001591 }
1592
Janis Danisevskiseed69842021-02-18 20:04:10 -08001593 /// Why would we insert a deleted blob? This weird function is for the purpose of legacy
1594 /// key migration in the case where we bulk delete all the keys of an app or even a user.
1595 /// We use this to insert key blobs into the database which can then be garbage collected
1596 /// lazily by the key garbage collector.
1597 pub fn set_deleted_blob(&mut self, blob: &[u8], blob_metadata: &BlobMetaData) -> Result<()> {
1598 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1599 Self::set_blob_internal(
1600 &tx,
1601 Self::UNASSIGNED_KEY_ID,
1602 SubComponentType::KEY_BLOB,
1603 Some(blob),
1604 Some(blob_metadata),
1605 )
1606 .need_gc()
1607 })
1608 .context("In set_deleted_blob.")
1609 }
1610
Janis Danisevskis377d1002021-01-27 19:07:48 -08001611 fn set_blob_internal(
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001612 tx: &Transaction,
1613 key_id: i64,
1614 sc_type: SubComponentType,
Janis Danisevskis377d1002021-01-27 19:07:48 -08001615 blob: Option<&[u8]>,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001616 blob_metadata: Option<&BlobMetaData>,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001617 ) -> Result<()> {
Janis Danisevskis377d1002021-01-27 19:07:48 -08001618 match (blob, sc_type) {
1619 (Some(blob), _) => {
1620 tx.execute(
1621 "INSERT INTO persistent.blobentry
1622 (subcomponent_type, keyentryid, blob) VALUES (?, ?, ?);",
1623 params![sc_type, key_id, blob],
1624 )
1625 .context("In set_blob_internal: Failed to insert blob.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001626 if let Some(blob_metadata) = blob_metadata {
1627 let blob_id = tx
1628 .query_row("SELECT MAX(id) FROM persistent.blobentry;", NO_PARAMS, |row| {
1629 row.get(0)
1630 })
1631 .context("In set_blob_internal: Failed to get new blob id.")?;
1632 blob_metadata
1633 .store_in_db(blob_id, tx)
1634 .context("In set_blob_internal: Trying to store blob metadata.")?;
1635 }
Janis Danisevskis377d1002021-01-27 19:07:48 -08001636 }
1637 (None, SubComponentType::CERT) | (None, SubComponentType::CERT_CHAIN) => {
1638 tx.execute(
1639 "DELETE FROM persistent.blobentry
1640 WHERE subcomponent_type = ? AND keyentryid = ?;",
1641 params![sc_type, key_id],
1642 )
1643 .context("In set_blob_internal: Failed to delete blob.")?;
1644 }
1645 (None, _) => {
1646 return Err(KsError::sys())
1647 .context("In set_blob_internal: Other blobs cannot be deleted in this way.");
1648 }
1649 }
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001650 Ok(())
1651 }
1652
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001653 /// Inserts a collection of key parameters into the `persistent.keyparameter` table
1654 /// and associates them with the given `key_id`.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001655 #[cfg(test)]
1656 fn insert_keyparameter(&mut self, key_id: &KeyIdGuard, params: &[KeyParameter]) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001657 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001658 Self::insert_keyparameter_internal(tx, key_id, params).no_gc()
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001659 })
1660 .context("In insert_keyparameter.")
1661 }
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001662
Janis Danisevskis66784c42021-01-27 08:40:25 -08001663 fn insert_keyparameter_internal(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001664 tx: &Transaction,
1665 key_id: &KeyIdGuard,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001666 params: &[KeyParameter],
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001667 ) -> Result<()> {
1668 let mut stmt = tx
1669 .prepare(
1670 "INSERT into persistent.keyparameter (keyentryid, tag, data, security_level)
1671 VALUES (?, ?, ?, ?);",
1672 )
1673 .context("In insert_keyparameter_internal: Failed to prepare statement.")?;
1674
Janis Danisevskis66784c42021-01-27 08:40:25 -08001675 for p in params.iter() {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001676 stmt.insert(params![
1677 key_id.0,
1678 p.get_tag().0,
1679 p.key_parameter_value(),
1680 p.security_level().0
1681 ])
1682 .with_context(|| {
1683 format!("In insert_keyparameter_internal: Failed to insert {:?}", p)
1684 })?;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001685 }
1686 Ok(())
1687 }
1688
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001689 /// Insert a set of key entry specific metadata into the database.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001690 #[cfg(test)]
1691 fn insert_key_metadata(&mut self, key_id: &KeyIdGuard, metadata: &KeyMetaData) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001692 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001693 metadata.store_in_db(key_id.0, &tx).no_gc()
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001694 })
1695 .context("In insert_key_metadata.")
1696 }
1697
Max Bires2b2e6562020-09-22 11:22:36 -07001698 /// Stores a signed certificate chain signed by a remote provisioning server, keyed
1699 /// on the public key.
1700 pub fn store_signed_attestation_certificate_chain(
1701 &mut self,
1702 raw_public_key: &[u8],
Max Biresb2e1d032021-02-08 21:35:05 -08001703 batch_cert: &[u8],
Max Bires2b2e6562020-09-22 11:22:36 -07001704 cert_chain: &[u8],
1705 expiration_date: i64,
1706 km_uuid: &Uuid,
1707 ) -> Result<()> {
1708 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1709 let mut stmt = tx
1710 .prepare(
1711 "SELECT keyentryid
1712 FROM persistent.keymetadata
1713 WHERE tag = ? AND data = ? AND keyentryid IN
1714 (SELECT id
1715 FROM persistent.keyentry
1716 WHERE
1717 alias IS NULL AND
1718 domain IS NULL AND
1719 namespace IS NULL AND
1720 key_type = ? AND
1721 km_uuid = ?);",
1722 )
1723 .context("Failed to store attestation certificate chain.")?;
1724 let mut rows = stmt
1725 .query(params![
1726 KeyMetaData::AttestationRawPubKey,
1727 raw_public_key,
1728 KeyType::Attestation,
1729 km_uuid
1730 ])
1731 .context("Failed to fetch keyid")?;
1732 let key_id = db_utils::with_rows_extract_one(&mut rows, |row| {
1733 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?
1734 .get(0)
1735 .context("Failed to unpack id.")
1736 })
1737 .context("Failed to get key_id.")?;
1738 let num_updated = tx
1739 .execute(
1740 "UPDATE persistent.keyentry
1741 SET alias = ?
1742 WHERE id = ?;",
1743 params!["signed", key_id],
1744 )
1745 .context("Failed to update alias.")?;
1746 if num_updated != 1 {
1747 return Err(KsError::sys()).context("Alias not updated for the key.");
1748 }
1749 let mut metadata = KeyMetaData::new();
1750 metadata.add(KeyMetaEntry::AttestationExpirationDate(DateTime::from_millis_epoch(
1751 expiration_date,
1752 )));
1753 metadata.store_in_db(key_id, &tx).context("Failed to insert key metadata.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001754 Self::set_blob_internal(
1755 &tx,
1756 key_id,
1757 SubComponentType::CERT_CHAIN,
1758 Some(cert_chain),
1759 None,
1760 )
1761 .context("Failed to insert cert chain")?;
Max Biresb2e1d032021-02-08 21:35:05 -08001762 Self::set_blob_internal(&tx, key_id, SubComponentType::CERT, Some(batch_cert), None)
1763 .context("Failed to insert cert")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001764 Ok(()).no_gc()
Max Bires2b2e6562020-09-22 11:22:36 -07001765 })
1766 .context("In store_signed_attestation_certificate_chain: ")
1767 }
1768
1769 /// Assigns the next unassigned attestation key to a domain/namespace combo that does not
1770 /// currently have a key assigned to it.
1771 pub fn assign_attestation_key(
1772 &mut self,
1773 domain: Domain,
1774 namespace: i64,
1775 km_uuid: &Uuid,
1776 ) -> Result<()> {
1777 match domain {
1778 Domain::APP | Domain::SELINUX => {}
1779 _ => {
1780 return Err(KsError::sys()).context(format!(
1781 concat!(
1782 "In assign_attestation_key: Domain {:?} ",
1783 "must be either App or SELinux.",
1784 ),
1785 domain
1786 ));
1787 }
1788 }
1789 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1790 let result = tx
1791 .execute(
1792 "UPDATE persistent.keyentry
1793 SET domain=?1, namespace=?2
1794 WHERE
1795 id =
1796 (SELECT MIN(id)
1797 FROM persistent.keyentry
1798 WHERE ALIAS IS NOT NULL
1799 AND domain IS NULL
1800 AND key_type IS ?3
1801 AND state IS ?4
1802 AND km_uuid IS ?5)
1803 AND
1804 (SELECT COUNT(*)
1805 FROM persistent.keyentry
1806 WHERE domain=?1
1807 AND namespace=?2
1808 AND key_type IS ?3
1809 AND state IS ?4
1810 AND km_uuid IS ?5) = 0;",
1811 params![
1812 domain.0 as u32,
1813 namespace,
1814 KeyType::Attestation,
1815 KeyLifeCycle::Live,
1816 km_uuid,
1817 ],
1818 )
1819 .context("Failed to assign attestation key")?;
Max Bires01f8af22021-03-02 23:24:50 -08001820 if result == 0 {
1821 return Err(KsError::Rc(ResponseCode::OUT_OF_KEYS)).context("Out of keys.");
1822 } else if result > 1 {
1823 return Err(KsError::sys())
1824 .context(format!("Expected to update 1 entry, instead updated {}", result));
Max Bires2b2e6562020-09-22 11:22:36 -07001825 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001826 Ok(()).no_gc()
Max Bires2b2e6562020-09-22 11:22:36 -07001827 })
1828 .context("In assign_attestation_key: ")
1829 }
1830
1831 /// Retrieves num_keys number of attestation keys that have not yet been signed by a remote
1832 /// provisioning server, or the maximum number available if there are not num_keys number of
1833 /// entries in the table.
1834 pub fn fetch_unsigned_attestation_keys(
1835 &mut self,
1836 num_keys: i32,
1837 km_uuid: &Uuid,
1838 ) -> Result<Vec<Vec<u8>>> {
1839 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1840 let mut stmt = tx
1841 .prepare(
1842 "SELECT data
1843 FROM persistent.keymetadata
1844 WHERE tag = ? AND keyentryid IN
1845 (SELECT id
1846 FROM persistent.keyentry
1847 WHERE
1848 alias IS NULL AND
1849 domain IS NULL AND
1850 namespace IS NULL AND
1851 key_type = ? AND
1852 km_uuid = ?
1853 LIMIT ?);",
1854 )
1855 .context("Failed to prepare statement")?;
1856 let rows = stmt
1857 .query_map(
1858 params![
1859 KeyMetaData::AttestationMacedPublicKey,
1860 KeyType::Attestation,
1861 km_uuid,
1862 num_keys
1863 ],
1864 |row| Ok(row.get(0)?),
1865 )?
1866 .collect::<rusqlite::Result<Vec<Vec<u8>>>>()
1867 .context("Failed to execute statement")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001868 Ok(rows).no_gc()
Max Bires2b2e6562020-09-22 11:22:36 -07001869 })
1870 .context("In fetch_unsigned_attestation_keys")
1871 }
1872
1873 /// Removes any keys that have expired as of the current time. Returns the number of keys
1874 /// marked unreferenced that are bound to be garbage collected.
1875 pub fn delete_expired_attestation_keys(&mut self) -> Result<i32> {
1876 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1877 let mut stmt = tx
1878 .prepare(
1879 "SELECT keyentryid, data
1880 FROM persistent.keymetadata
1881 WHERE tag = ? AND keyentryid IN
1882 (SELECT id
1883 FROM persistent.keyentry
1884 WHERE key_type = ?);",
1885 )
1886 .context("Failed to prepare query")?;
1887 let key_ids_to_check = stmt
1888 .query_map(
1889 params![KeyMetaData::AttestationExpirationDate, KeyType::Attestation],
1890 |row| Ok((row.get(0)?, row.get(1)?)),
1891 )?
1892 .collect::<rusqlite::Result<Vec<(i64, DateTime)>>>()
1893 .context("Failed to get date metadata")?;
1894 let curr_time = DateTime::from_millis_epoch(
1895 SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_millis() as i64,
1896 );
1897 let mut num_deleted = 0;
1898 for id in key_ids_to_check.iter().filter(|kt| kt.1 < curr_time).map(|kt| kt.0) {
1899 if Self::mark_unreferenced(&tx, id)? {
1900 num_deleted += 1;
1901 }
1902 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001903 Ok(num_deleted).do_gc(num_deleted != 0)
Max Bires2b2e6562020-09-22 11:22:36 -07001904 })
1905 .context("In delete_expired_attestation_keys: ")
1906 }
1907
Max Bires60d7ed12021-03-05 15:59:22 -08001908 /// Deletes all remotely provisioned attestation keys in the system, regardless of the state
1909 /// they are in. This is useful primarily as a testing mechanism.
1910 pub fn delete_all_attestation_keys(&mut self) -> Result<i64> {
1911 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1912 let mut stmt = tx
1913 .prepare(
1914 "SELECT id FROM persistent.keyentry
1915 WHERE key_type IS ?;",
1916 )
1917 .context("Failed to prepare statement")?;
1918 let keys_to_delete = stmt
1919 .query_map(params![KeyType::Attestation], |row| Ok(row.get(0)?))?
1920 .collect::<rusqlite::Result<Vec<i64>>>()
1921 .context("Failed to execute statement")?;
1922 let num_deleted = keys_to_delete
1923 .iter()
1924 .map(|id| Self::mark_unreferenced(&tx, *id))
1925 .collect::<Result<Vec<bool>>>()
1926 .context("Failed to execute mark_unreferenced on a keyid")?
1927 .into_iter()
1928 .filter(|result| *result)
1929 .count() as i64;
1930 Ok(num_deleted).do_gc(num_deleted != 0)
1931 })
1932 .context("In delete_all_attestation_keys: ")
1933 }
1934
Max Bires2b2e6562020-09-22 11:22:36 -07001935 /// Counts the number of keys that will expire by the provided epoch date and the number of
1936 /// keys not currently assigned to a domain.
1937 pub fn get_attestation_pool_status(
1938 &mut self,
1939 date: i64,
1940 km_uuid: &Uuid,
1941 ) -> Result<AttestationPoolStatus> {
1942 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1943 let mut stmt = tx.prepare(
1944 "SELECT data
1945 FROM persistent.keymetadata
1946 WHERE tag = ? AND keyentryid IN
1947 (SELECT id
1948 FROM persistent.keyentry
1949 WHERE alias IS NOT NULL
1950 AND key_type = ?
1951 AND km_uuid = ?
1952 AND state = ?);",
1953 )?;
1954 let times = stmt
1955 .query_map(
1956 params![
1957 KeyMetaData::AttestationExpirationDate,
1958 KeyType::Attestation,
1959 km_uuid,
1960 KeyLifeCycle::Live
1961 ],
1962 |row| Ok(row.get(0)?),
1963 )?
1964 .collect::<rusqlite::Result<Vec<DateTime>>>()
1965 .context("Failed to execute metadata statement")?;
1966 let expiring =
1967 times.iter().filter(|time| time < &&DateTime::from_millis_epoch(date)).count()
1968 as i32;
1969 stmt = tx.prepare(
1970 "SELECT alias, domain
1971 FROM persistent.keyentry
1972 WHERE key_type = ? AND km_uuid = ? AND state = ?;",
1973 )?;
1974 let rows = stmt
1975 .query_map(params![KeyType::Attestation, km_uuid, KeyLifeCycle::Live], |row| {
1976 Ok((row.get(0)?, row.get(1)?))
1977 })?
1978 .collect::<rusqlite::Result<Vec<(Option<String>, Option<u32>)>>>()
1979 .context("Failed to execute keyentry statement")?;
1980 let mut unassigned = 0i32;
1981 let mut attested = 0i32;
1982 let total = rows.len() as i32;
1983 for (alias, domain) in rows {
1984 match (alias, domain) {
1985 (Some(_alias), None) => {
1986 attested += 1;
1987 unassigned += 1;
1988 }
1989 (Some(_alias), Some(_domain)) => {
1990 attested += 1;
1991 }
1992 _ => {}
1993 }
1994 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001995 Ok(AttestationPoolStatus { expiring, unassigned, attested, total }).no_gc()
Max Bires2b2e6562020-09-22 11:22:36 -07001996 })
1997 .context("In get_attestation_pool_status: ")
1998 }
1999
2000 /// Fetches the private key and corresponding certificate chain assigned to a
2001 /// domain/namespace pair. Will either return nothing if the domain/namespace is
2002 /// not assigned, or one CertificateChain.
2003 pub fn retrieve_attestation_key_and_cert_chain(
2004 &mut self,
2005 domain: Domain,
2006 namespace: i64,
2007 km_uuid: &Uuid,
2008 ) -> Result<Option<CertificateChain>> {
2009 match domain {
2010 Domain::APP | Domain::SELINUX => {}
2011 _ => {
2012 return Err(KsError::sys())
2013 .context(format!("Domain {:?} must be either App or SELinux.", domain));
2014 }
2015 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002016 self.with_transaction(TransactionBehavior::Deferred, |tx| {
2017 let mut stmt = tx.prepare(
2018 "SELECT subcomponent_type, blob
Max Bires2b2e6562020-09-22 11:22:36 -07002019 FROM persistent.blobentry
2020 WHERE keyentryid IN
2021 (SELECT id
2022 FROM persistent.keyentry
2023 WHERE key_type = ?
2024 AND domain = ?
2025 AND namespace = ?
2026 AND state = ?
2027 AND km_uuid = ?);",
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002028 )?;
2029 let rows = stmt
2030 .query_map(
2031 params![
2032 KeyType::Attestation,
2033 domain.0 as u32,
2034 namespace,
2035 KeyLifeCycle::Live,
2036 km_uuid
2037 ],
2038 |row| Ok((row.get(0)?, row.get(1)?)),
2039 )?
2040 .collect::<rusqlite::Result<Vec<(SubComponentType, Vec<u8>)>>>()
Max Biresb2e1d032021-02-08 21:35:05 -08002041 .context("query failed.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002042 if rows.is_empty() {
2043 return Ok(None).no_gc();
Max Biresb2e1d032021-02-08 21:35:05 -08002044 } else if rows.len() != 3 {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002045 return Err(KsError::sys()).context(format!(
2046 concat!(
Max Biresb2e1d032021-02-08 21:35:05 -08002047 "Expected to get a single attestation",
2048 "key, cert, and cert chain for a total of 3 entries, but instead got {}."
2049 ),
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002050 rows.len()
2051 ));
Max Bires2b2e6562020-09-22 11:22:36 -07002052 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002053 let mut km_blob: Vec<u8> = Vec::new();
2054 let mut cert_chain_blob: Vec<u8> = Vec::new();
Max Biresb2e1d032021-02-08 21:35:05 -08002055 let mut batch_cert_blob: Vec<u8> = Vec::new();
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002056 for row in rows {
2057 let sub_type: SubComponentType = row.0;
2058 match sub_type {
2059 SubComponentType::KEY_BLOB => {
2060 km_blob = row.1;
2061 }
2062 SubComponentType::CERT_CHAIN => {
2063 cert_chain_blob = row.1;
2064 }
Max Biresb2e1d032021-02-08 21:35:05 -08002065 SubComponentType::CERT => {
2066 batch_cert_blob = row.1;
2067 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002068 _ => Err(KsError::sys()).context("Unknown or incorrect subcomponent type.")?,
2069 }
2070 }
2071 Ok(Some(CertificateChain {
2072 private_key: ZVec::try_from(km_blob)?,
Max Bires97f96812021-02-23 23:44:57 -08002073 batch_cert: batch_cert_blob,
2074 cert_chain: cert_chain_blob,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002075 }))
2076 .no_gc()
2077 })
Max Biresb2e1d032021-02-08 21:35:05 -08002078 .context("In retrieve_attestation_key_and_cert_chain:")
Max Bires2b2e6562020-09-22 11:22:36 -07002079 }
2080
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002081 /// Updates the alias column of the given key id `newid` with the given alias,
2082 /// and atomically, removes the alias, domain, and namespace from another row
2083 /// with the same alias-domain-namespace tuple if such row exits.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002084 /// Returns Ok(true) if an old key was marked unreferenced as a hint to the garbage
2085 /// collector.
2086 fn rebind_alias(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002087 tx: &Transaction,
Janis Danisevskisaec14592020-11-12 09:41:49 -08002088 newid: &KeyIdGuard,
Joel Galenson33c04ad2020-08-03 11:04:38 -07002089 alias: &str,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002090 domain: &Domain,
2091 namespace: &i64,
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002092 ) -> Result<bool> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002093 match *domain {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002094 Domain::APP | Domain::SELINUX => {}
Joel Galenson33c04ad2020-08-03 11:04:38 -07002095 _ => {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002096 return Err(KsError::sys()).context(format!(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002097 "In rebind_alias: Domain {:?} must be either App or SELinux.",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002098 domain
2099 ));
Joel Galenson33c04ad2020-08-03 11:04:38 -07002100 }
2101 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002102 let updated = tx
2103 .execute(
2104 "UPDATE persistent.keyentry
2105 SET alias = NULL, domain = NULL, namespace = NULL, state = ?
Joel Galenson33c04ad2020-08-03 11:04:38 -07002106 WHERE alias = ? AND domain = ? AND namespace = ?;",
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002107 params![KeyLifeCycle::Unreferenced, alias, domain.0 as u32, namespace],
2108 )
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002109 .context("In rebind_alias: Failed to rebind existing entry.")?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07002110 let result = tx
2111 .execute(
2112 "UPDATE persistent.keyentry
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002113 SET alias = ?, state = ?
2114 WHERE id = ? AND domain = ? AND namespace = ? AND state = ?;",
2115 params![
2116 alias,
2117 KeyLifeCycle::Live,
2118 newid.0,
2119 domain.0 as u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002120 *namespace,
Max Bires8e93d2b2021-01-14 13:17:59 -08002121 KeyLifeCycle::Existing,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002122 ],
Joel Galenson33c04ad2020-08-03 11:04:38 -07002123 )
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002124 .context("In rebind_alias: Failed to set alias.")?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07002125 if result != 1 {
Joel Galenson33c04ad2020-08-03 11:04:38 -07002126 return Err(KsError::sys()).context(format!(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002127 "In rebind_alias: Expected to update a single entry but instead updated {}.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07002128 result
2129 ));
2130 }
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002131 Ok(updated != 0)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002132 }
2133
2134 /// Store a new key in a single transaction.
2135 /// The function creates a new key entry, populates the blob, key parameter, and metadata
2136 /// fields, and rebinds the given alias to the new key.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002137 /// The boolean returned is a hint for the garbage collector. If true, a key was replaced,
2138 /// is now unreferenced and needs to be collected.
Janis Danisevskis66784c42021-01-27 08:40:25 -08002139 pub fn store_new_key(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002140 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002141 key: &KeyDescriptor,
2142 params: &[KeyParameter],
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002143 blob_info: &(&[u8], &BlobMetaData),
Max Bires8e93d2b2021-01-14 13:17:59 -08002144 cert_info: &CertificateInfo,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002145 metadata: &KeyMetaData,
Max Bires8e93d2b2021-01-14 13:17:59 -08002146 km_uuid: &Uuid,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002147 ) -> Result<KeyIdGuard> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002148 let (alias, domain, namespace) = match key {
2149 KeyDescriptor { alias: Some(alias), domain: Domain::APP, nspace, blob: None }
2150 | KeyDescriptor { alias: Some(alias), domain: Domain::SELINUX, nspace, blob: None } => {
2151 (alias, key.domain, nspace)
2152 }
2153 _ => {
2154 return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT))
2155 .context("In store_new_key: Need alias and domain must be APP or SELINUX.")
2156 }
2157 };
2158 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002159 let key_id = Self::create_key_entry_internal(tx, &domain, namespace, km_uuid)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002160 .context("Trying to create new key entry.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002161 let (blob, blob_metadata) = *blob_info;
2162 Self::set_blob_internal(
2163 tx,
2164 key_id.id(),
2165 SubComponentType::KEY_BLOB,
2166 Some(blob),
2167 Some(&blob_metadata),
2168 )
2169 .context("Trying to insert the key blob.")?;
Max Bires8e93d2b2021-01-14 13:17:59 -08002170 if let Some(cert) = &cert_info.cert {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002171 Self::set_blob_internal(tx, key_id.id(), SubComponentType::CERT, Some(&cert), None)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002172 .context("Trying to insert the certificate.")?;
2173 }
Max Bires8e93d2b2021-01-14 13:17:59 -08002174 if let Some(cert_chain) = &cert_info.cert_chain {
Janis Danisevskis377d1002021-01-27 19:07:48 -08002175 Self::set_blob_internal(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002176 tx,
2177 key_id.id(),
2178 SubComponentType::CERT_CHAIN,
Janis Danisevskis377d1002021-01-27 19:07:48 -08002179 Some(&cert_chain),
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002180 None,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002181 )
2182 .context("Trying to insert the certificate chain.")?;
2183 }
2184 Self::insert_keyparameter_internal(tx, &key_id, params)
2185 .context("Trying to insert key parameters.")?;
Janis Danisevskis377d1002021-01-27 19:07:48 -08002186 metadata.store_in_db(key_id.id(), tx).context("Trying to insert key metadata.")?;
Janis Danisevskis66784c42021-01-27 08:40:25 -08002187 let need_gc = Self::rebind_alias(tx, &key_id, &alias, &domain, namespace)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002188 .context("Trying to rebind alias.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002189 Ok(key_id).do_gc(need_gc)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002190 })
2191 .context("In store_new_key.")
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002192 }
2193
Janis Danisevskis377d1002021-01-27 19:07:48 -08002194 /// Store a new certificate
2195 /// The function creates a new key entry, populates the blob field and metadata, and rebinds
2196 /// the given alias to the new cert.
Max Bires8e93d2b2021-01-14 13:17:59 -08002197 pub fn store_new_certificate(
2198 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002199 key: &KeyDescriptor,
Max Bires8e93d2b2021-01-14 13:17:59 -08002200 cert: &[u8],
2201 km_uuid: &Uuid,
2202 ) -> Result<KeyIdGuard> {
Janis Danisevskis377d1002021-01-27 19:07:48 -08002203 let (alias, domain, namespace) = match key {
2204 KeyDescriptor { alias: Some(alias), domain: Domain::APP, nspace, blob: None }
2205 | KeyDescriptor { alias: Some(alias), domain: Domain::SELINUX, nspace, blob: None } => {
2206 (alias, key.domain, nspace)
2207 }
2208 _ => {
2209 return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT)).context(
2210 "In store_new_certificate: Need alias and domain must be APP or SELINUX.",
2211 )
2212 }
2213 };
2214 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002215 let key_id = Self::create_key_entry_internal(tx, &domain, namespace, km_uuid)
Janis Danisevskis377d1002021-01-27 19:07:48 -08002216 .context("Trying to create new key entry.")?;
2217
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002218 Self::set_blob_internal(
2219 tx,
2220 key_id.id(),
2221 SubComponentType::CERT_CHAIN,
2222 Some(cert),
2223 None,
2224 )
2225 .context("Trying to insert certificate.")?;
Janis Danisevskis377d1002021-01-27 19:07:48 -08002226
2227 let mut metadata = KeyMetaData::new();
2228 metadata.add(KeyMetaEntry::CreationDate(
2229 DateTime::now().context("Trying to make creation time.")?,
2230 ));
2231
2232 metadata.store_in_db(key_id.id(), tx).context("Trying to insert key metadata.")?;
2233
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002234 let need_gc = Self::rebind_alias(tx, &key_id, &alias, &domain, namespace)
Janis Danisevskis377d1002021-01-27 19:07:48 -08002235 .context("Trying to rebind alias.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002236 Ok(key_id).do_gc(need_gc)
Janis Danisevskis377d1002021-01-27 19:07:48 -08002237 })
2238 .context("In store_new_certificate.")
2239 }
2240
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002241 // Helper function loading the key_id given the key descriptor
2242 // tuple comprising domain, namespace, and alias.
2243 // Requires a valid transaction.
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002244 fn load_key_entry_id(tx: &Transaction, key: &KeyDescriptor, key_type: KeyType) -> Result<i64> {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002245 let alias = key
2246 .alias
2247 .as_ref()
2248 .map_or_else(|| Err(KsError::sys()), Ok)
2249 .context("In load_key_entry_id: Alias must be specified.")?;
2250 let mut stmt = tx
2251 .prepare(
2252 "SELECT id FROM persistent.keyentry
2253 WHERE
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00002254 key_type = ?
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002255 AND domain = ?
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002256 AND namespace = ?
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002257 AND alias = ?
2258 AND state = ?;",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002259 )
2260 .context("In load_key_entry_id: Failed to select from keyentry table.")?;
2261 let mut rows = stmt
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002262 .query(params![key_type, key.domain.0 as u32, key.nspace, alias, KeyLifeCycle::Live])
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002263 .context("In load_key_entry_id: Failed to read from keyentry table.")?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002264 db_utils::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002265 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002266 .get(0)
2267 .context("Failed to unpack id.")
2268 })
2269 .context("In load_key_entry_id.")
2270 }
2271
2272 /// This helper function completes the access tuple of a key, which is required
2273 /// to perform access control. The strategy depends on the `domain` field in the
2274 /// key descriptor.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002275 /// * Domain::SELINUX: The access tuple is complete and this function only loads
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002276 /// the key_id for further processing.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002277 /// * Domain::APP: Like Domain::SELINUX, but the tuple is completed by `caller_uid`
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002278 /// which serves as the namespace.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002279 /// * Domain::GRANT: The grant table is queried for the `key_id` and the
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002280 /// `access_vector`.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002281 /// * Domain::KEY_ID: The keyentry table is queried for the owning `domain` and
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002282 /// `namespace`.
2283 /// In each case the information returned is sufficient to perform the access
2284 /// check and the key id can be used to load further key artifacts.
2285 fn load_access_tuple(
2286 tx: &Transaction,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002287 key: &KeyDescriptor,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002288 key_type: KeyType,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002289 caller_uid: u32,
2290 ) -> Result<(i64, KeyDescriptor, Option<KeyPermSet>)> {
2291 match key.domain {
2292 // Domain App or SELinux. In this case we load the key_id from
2293 // the keyentry database for further loading of key components.
2294 // We already have the full access tuple to perform access control.
2295 // The only distinction is that we use the caller_uid instead
2296 // of the caller supplied namespace if the domain field is
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002297 // Domain::APP.
2298 Domain::APP | Domain::SELINUX => {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002299 let mut access_key = key.clone();
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002300 if access_key.domain == Domain::APP {
2301 access_key.nspace = caller_uid as i64;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002302 }
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002303 let key_id = Self::load_key_entry_id(&tx, &access_key, key_type)
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002304 .with_context(|| format!("With key.domain = {:?}.", access_key.domain))?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002305
2306 Ok((key_id, access_key, None))
2307 }
2308
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002309 // Domain::GRANT. In this case we load the key_id and the access_vector
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002310 // from the grant table.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002311 Domain::GRANT => {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002312 let mut stmt = tx
2313 .prepare(
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002314 "SELECT keyentryid, access_vector FROM persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002315 WHERE grantee = ? AND id = ?;",
2316 )
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002317 .context("Domain::GRANT prepare statement failed")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002318 let mut rows = stmt
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002319 .query(params![caller_uid as i64, key.nspace])
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002320 .context("Domain:Grant: query failed.")?;
2321 let (key_id, access_vector): (i64, i32) =
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002322 db_utils::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002323 let r =
2324 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002325 Ok((
2326 r.get(0).context("Failed to unpack key_id.")?,
2327 r.get(1).context("Failed to unpack access_vector.")?,
2328 ))
2329 })
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002330 .context("Domain::GRANT.")?;
Janis Danisevskis66784c42021-01-27 08:40:25 -08002331 Ok((key_id, key.clone(), Some(access_vector.into())))
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002332 }
2333
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002334 // Domain::KEY_ID. In this case we load the domain and namespace from the
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002335 // keyentry database because we need them for access control.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002336 Domain::KEY_ID => {
Janis Danisevskis45760022021-01-19 16:34:10 -08002337 let (domain, namespace): (Domain, i64) = {
2338 let mut stmt = tx
2339 .prepare(
2340 "SELECT domain, namespace FROM persistent.keyentry
2341 WHERE
2342 id = ?
2343 AND state = ?;",
2344 )
2345 .context("Domain::KEY_ID: prepare statement failed")?;
2346 let mut rows = stmt
2347 .query(params![key.nspace, KeyLifeCycle::Live])
2348 .context("Domain::KEY_ID: query failed.")?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002349 db_utils::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002350 let r =
2351 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002352 Ok((
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002353 Domain(r.get(0).context("Failed to unpack domain.")?),
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002354 r.get(1).context("Failed to unpack namespace.")?,
2355 ))
2356 })
Janis Danisevskis45760022021-01-19 16:34:10 -08002357 .context("Domain::KEY_ID.")?
2358 };
2359
2360 // We may use a key by id after loading it by grant.
2361 // In this case we have to check if the caller has a grant for this particular
2362 // key. We can skip this if we already know that the caller is the owner.
2363 // But we cannot know this if domain is anything but App. E.g. in the case
2364 // of Domain::SELINUX we have to speculatively check for grants because we have to
2365 // consult the SEPolicy before we know if the caller is the owner.
2366 let access_vector: Option<KeyPermSet> =
2367 if domain != Domain::APP || namespace != caller_uid as i64 {
2368 let access_vector: Option<i32> = tx
2369 .query_row(
2370 "SELECT access_vector FROM persistent.grant
2371 WHERE grantee = ? AND keyentryid = ?;",
2372 params![caller_uid as i64, key.nspace],
2373 |row| row.get(0),
2374 )
2375 .optional()
2376 .context("Domain::KEY_ID: query grant failed.")?;
2377 access_vector.map(|p| p.into())
2378 } else {
2379 None
2380 };
2381
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002382 let key_id = key.nspace;
Janis Danisevskis66784c42021-01-27 08:40:25 -08002383 let mut access_key: KeyDescriptor = key.clone();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002384 access_key.domain = domain;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002385 access_key.nspace = namespace;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002386
Janis Danisevskis45760022021-01-19 16:34:10 -08002387 Ok((key_id, access_key, access_vector))
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002388 }
2389 _ => Err(anyhow!(KsError::sys())),
2390 }
2391 }
2392
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002393 fn load_blob_components(
2394 key_id: i64,
2395 load_bits: KeyEntryLoadBits,
2396 tx: &Transaction,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002397 ) -> Result<(bool, Option<(Vec<u8>, BlobMetaData)>, Option<Vec<u8>>, Option<Vec<u8>>)> {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002398 let mut stmt = tx
2399 .prepare(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002400 "SELECT MAX(id), subcomponent_type, blob FROM persistent.blobentry
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002401 WHERE keyentryid = ? GROUP BY subcomponent_type;",
2402 )
2403 .context("In load_blob_components: prepare statement failed.")?;
2404
2405 let mut rows =
2406 stmt.query(params![key_id]).context("In load_blob_components: query failed.")?;
2407
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002408 let mut key_blob: Option<(i64, Vec<u8>)> = None;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002409 let mut cert_blob: Option<Vec<u8>> = None;
2410 let mut cert_chain_blob: Option<Vec<u8>> = None;
Janis Danisevskis377d1002021-01-27 19:07:48 -08002411 let mut has_km_blob: bool = false;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002412 db_utils::with_rows_extract_all(&mut rows, |row| {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002413 let sub_type: SubComponentType =
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002414 row.get(1).context("Failed to extract subcomponent_type.")?;
Janis Danisevskis377d1002021-01-27 19:07:48 -08002415 has_km_blob = has_km_blob || sub_type == SubComponentType::KEY_BLOB;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002416 match (sub_type, load_bits.load_public(), load_bits.load_km()) {
2417 (SubComponentType::KEY_BLOB, _, true) => {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002418 key_blob = Some((
2419 row.get(0).context("Failed to extract key blob id.")?,
2420 row.get(2).context("Failed to extract key blob.")?,
2421 ));
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002422 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002423 (SubComponentType::CERT, true, _) => {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002424 cert_blob =
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002425 Some(row.get(2).context("Failed to extract public certificate blob.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002426 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002427 (SubComponentType::CERT_CHAIN, true, _) => {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002428 cert_chain_blob =
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002429 Some(row.get(2).context("Failed to extract certificate chain blob.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002430 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002431 (SubComponentType::CERT, _, _)
2432 | (SubComponentType::CERT_CHAIN, _, _)
2433 | (SubComponentType::KEY_BLOB, _, _) => {}
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002434 _ => Err(KsError::sys()).context("Unknown subcomponent type.")?,
2435 }
2436 Ok(())
2437 })
2438 .context("In load_blob_components.")?;
2439
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002440 let blob_info = key_blob.map_or::<Result<_>, _>(Ok(None), |(blob_id, blob)| {
2441 Ok(Some((
2442 blob,
2443 BlobMetaData::load_from_db(blob_id, tx)
2444 .context("In load_blob_components: Trying to load blob_metadata.")?,
2445 )))
2446 })?;
2447
2448 Ok((has_km_blob, blob_info, cert_blob, cert_chain_blob))
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002449 }
2450
2451 fn load_key_parameters(key_id: i64, tx: &Transaction) -> Result<Vec<KeyParameter>> {
2452 let mut stmt = tx
2453 .prepare(
2454 "SELECT tag, data, security_level from persistent.keyparameter
2455 WHERE keyentryid = ?;",
2456 )
2457 .context("In load_key_parameters: prepare statement failed.")?;
2458
2459 let mut parameters: Vec<KeyParameter> = Vec::new();
2460
2461 let mut rows =
2462 stmt.query(params![key_id]).context("In load_key_parameters: query failed.")?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002463 db_utils::with_rows_extract_all(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002464 let tag = Tag(row.get(0).context("Failed to read tag.")?);
2465 let sec_level = SecurityLevel(row.get(2).context("Failed to read sec_level.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002466 parameters.push(
2467 KeyParameter::new_from_sql(tag, &SqlField::new(1, &row), sec_level)
2468 .context("Failed to read KeyParameter.")?,
2469 );
2470 Ok(())
2471 })
2472 .context("In load_key_parameters.")?;
2473
2474 Ok(parameters)
2475 }
2476
Qi Wub9433b52020-12-01 14:52:46 +08002477 /// Decrements the usage count of a limited use key. This function first checks whether the
2478 /// usage has been exhausted, if not, decreases the usage count. If the usage count reaches
2479 /// zero, the key also gets marked unreferenced and scheduled for deletion.
2480 /// Returns Ok(true) if the key was marked unreferenced as a hint to the garbage collector.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002481 pub fn check_and_update_key_usage_count(&mut self, key_id: i64) -> Result<()> {
Qi Wub9433b52020-12-01 14:52:46 +08002482 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2483 let limit: Option<i32> = tx
2484 .query_row(
2485 "SELECT data FROM persistent.keyparameter WHERE keyentryid = ? AND tag = ?;",
2486 params![key_id, Tag::USAGE_COUNT_LIMIT.0],
2487 |row| row.get(0),
2488 )
2489 .optional()
2490 .context("Trying to load usage count")?;
2491
2492 let limit = limit
2493 .ok_or(KsError::Km(ErrorCode::INVALID_KEY_BLOB))
2494 .context("The Key no longer exists. Key is exhausted.")?;
2495
2496 tx.execute(
2497 "UPDATE persistent.keyparameter
2498 SET data = data - 1
2499 WHERE keyentryid = ? AND tag = ? AND data > 0;",
2500 params![key_id, Tag::USAGE_COUNT_LIMIT.0],
2501 )
2502 .context("Failed to update key usage count.")?;
2503
2504 match limit {
2505 1 => Self::mark_unreferenced(tx, key_id)
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002506 .map(|need_gc| (need_gc, ()))
Qi Wub9433b52020-12-01 14:52:46 +08002507 .context("Trying to mark limited use key for deletion."),
2508 0 => Err(KsError::Km(ErrorCode::INVALID_KEY_BLOB)).context("Key is exhausted."),
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002509 _ => Ok(()).no_gc(),
Qi Wub9433b52020-12-01 14:52:46 +08002510 }
2511 })
2512 .context("In check_and_update_key_usage_count.")
2513 }
2514
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002515 /// Load a key entry by the given key descriptor.
2516 /// It uses the `check_permission` callback to verify if the access is allowed
2517 /// given the key access tuple read from the database using `load_access_tuple`.
2518 /// With `load_bits` the caller may specify which blobs shall be loaded from
2519 /// the blob database.
2520 pub fn load_key_entry(
2521 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002522 key: &KeyDescriptor,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002523 key_type: KeyType,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002524 load_bits: KeyEntryLoadBits,
2525 caller_uid: u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002526 check_permission: impl Fn(&KeyDescriptor, Option<KeyPermSet>) -> Result<()>,
2527 ) -> Result<(KeyIdGuard, KeyEntry)> {
2528 loop {
2529 match self.load_key_entry_internal(
2530 key,
2531 key_type,
2532 load_bits,
2533 caller_uid,
2534 &check_permission,
2535 ) {
2536 Ok(result) => break Ok(result),
2537 Err(e) => {
2538 if Self::is_locked_error(&e) {
2539 std::thread::sleep(std::time::Duration::from_micros(500));
2540 continue;
2541 } else {
2542 return Err(e).context("In load_key_entry.");
2543 }
2544 }
2545 }
2546 }
2547 }
2548
2549 fn load_key_entry_internal(
2550 &mut self,
2551 key: &KeyDescriptor,
2552 key_type: KeyType,
2553 load_bits: KeyEntryLoadBits,
2554 caller_uid: u32,
2555 check_permission: &impl Fn(&KeyDescriptor, Option<KeyPermSet>) -> Result<()>,
Janis Danisevskisaec14592020-11-12 09:41:49 -08002556 ) -> Result<(KeyIdGuard, KeyEntry)> {
2557 // KEY ID LOCK 1/2
2558 // If we got a key descriptor with a key id we can get the lock right away.
2559 // Otherwise we have to defer it until we know the key id.
2560 let key_id_guard = match key.domain {
2561 Domain::KEY_ID => Some(KEY_ID_LOCK.get(key.nspace)),
2562 _ => None,
2563 };
2564
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002565 let tx = self
2566 .conn
Janis Danisevskisaec14592020-11-12 09:41:49 -08002567 .unchecked_transaction()
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002568 .context("In load_key_entry: Failed to initialize transaction.")?;
2569
2570 // Load the key_id and complete the access control tuple.
2571 let (key_id, access_key_descriptor, access_vector) =
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002572 Self::load_access_tuple(&tx, key, key_type, caller_uid)
2573 .context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002574
2575 // Perform access control. It is vital that we return here if the permission is denied.
2576 // So do not touch that '?' at the end.
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002577 check_permission(&access_key_descriptor, access_vector).context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002578
Janis Danisevskisaec14592020-11-12 09:41:49 -08002579 // KEY ID LOCK 2/2
2580 // If we did not get a key id lock by now, it was because we got a key descriptor
2581 // without a key id. At this point we got the key id, so we can try and get a lock.
2582 // However, we cannot block here, because we are in the middle of the transaction.
2583 // So first we try to get the lock non blocking. If that fails, we roll back the
2584 // transaction and block until we get the lock. After we successfully got the lock,
2585 // we start a new transaction and load the access tuple again.
2586 //
2587 // We don't need to perform access control again, because we already established
2588 // that the caller had access to the given key. But we need to make sure that the
2589 // key id still exists. So we have to load the key entry by key id this time.
2590 let (key_id_guard, tx) = match key_id_guard {
2591 None => match KEY_ID_LOCK.try_get(key_id) {
2592 None => {
2593 // Roll back the transaction.
2594 tx.rollback().context("In load_key_entry: Failed to roll back transaction.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002595
Janis Danisevskisaec14592020-11-12 09:41:49 -08002596 // Block until we have a key id lock.
2597 let key_id_guard = KEY_ID_LOCK.get(key_id);
2598
2599 // Create a new transaction.
Janis Danisevskis66784c42021-01-27 08:40:25 -08002600 let tx = self
2601 .conn
2602 .unchecked_transaction()
2603 .context("In load_key_entry: Failed to initialize transaction.")?;
Janis Danisevskisaec14592020-11-12 09:41:49 -08002604
2605 Self::load_access_tuple(
2606 &tx,
2607 // This time we have to load the key by the retrieved key id, because the
2608 // alias may have been rebound after we rolled back the transaction.
Janis Danisevskis66784c42021-01-27 08:40:25 -08002609 &KeyDescriptor {
Janis Danisevskisaec14592020-11-12 09:41:49 -08002610 domain: Domain::KEY_ID,
2611 nspace: key_id,
2612 ..Default::default()
2613 },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002614 key_type,
Janis Danisevskisaec14592020-11-12 09:41:49 -08002615 caller_uid,
2616 )
2617 .context("In load_key_entry. (deferred key lock)")?;
2618 (key_id_guard, tx)
2619 }
2620 Some(l) => (l, tx),
2621 },
2622 Some(key_id_guard) => (key_id_guard, tx),
2623 };
2624
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002625 let key_entry = Self::load_key_components(&tx, load_bits, key_id_guard.id())
2626 .context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002627
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002628 tx.commit().context("In load_key_entry: Failed to commit transaction.")?;
2629
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002630 Ok((key_id_guard, key_entry))
2631 }
2632
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002633 fn mark_unreferenced(tx: &Transaction, key_id: i64) -> Result<bool> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002634 let updated = tx
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002635 .execute("DELETE FROM persistent.keyentry WHERE id = ?;", params![key_id])
2636 .context("Trying to delete keyentry.")?;
2637 tx.execute("DELETE FROM persistent.keymetadata WHERE keyentryid = ?;", params![key_id])
2638 .context("Trying to delete keymetadata.")?;
2639 tx.execute("DELETE FROM persistent.keyparameter WHERE keyentryid = ?;", params![key_id])
2640 .context("Trying to delete keyparameters.")?;
2641 tx.execute("DELETE FROM persistent.grant WHERE keyentryid = ?;", params![key_id])
2642 .context("Trying to delete grants.")?;
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002643 Ok(updated != 0)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002644 }
2645
2646 /// Marks the given key as unreferenced and removes all of the grants to this key.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002647 /// Returns Ok(true) if a key was marked unreferenced as a hint for the garbage collector.
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002648 pub fn unbind_key(
2649 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002650 key: &KeyDescriptor,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002651 key_type: KeyType,
2652 caller_uid: u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002653 check_permission: impl Fn(&KeyDescriptor, Option<KeyPermSet>) -> Result<()>,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002654 ) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002655 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2656 let (key_id, access_key_descriptor, access_vector) =
2657 Self::load_access_tuple(tx, key, key_type, caller_uid)
2658 .context("Trying to get access tuple.")?;
2659
2660 // Perform access control. It is vital that we return here if the permission is denied.
2661 // So do not touch that '?' at the end.
2662 check_permission(&access_key_descriptor, access_vector)
2663 .context("While checking permission.")?;
2664
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002665 Self::mark_unreferenced(tx, key_id)
2666 .map(|need_gc| (need_gc, ()))
2667 .context("Trying to mark the key unreferenced.")
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002668 })
2669 .context("In unbind_key.")
2670 }
2671
Max Bires8e93d2b2021-01-14 13:17:59 -08002672 fn get_key_km_uuid(tx: &Transaction, key_id: i64) -> Result<Uuid> {
2673 tx.query_row(
2674 "SELECT km_uuid FROM persistent.keyentry WHERE id = ?",
2675 params![key_id],
2676 |row| row.get(0),
2677 )
2678 .context("In get_key_km_uuid.")
2679 }
2680
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002681 /// Delete all artifacts belonging to the namespace given by the domain-namespace tuple.
2682 /// This leaves all of the blob entries orphaned for subsequent garbage collection.
2683 pub fn unbind_keys_for_namespace(&mut self, domain: Domain, namespace: i64) -> Result<()> {
2684 if !(domain == Domain::APP || domain == Domain::SELINUX) {
2685 return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT))
2686 .context("In unbind_keys_for_namespace.");
2687 }
2688 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2689 tx.execute(
2690 "DELETE FROM persistent.keymetadata
2691 WHERE keyentryid IN (
2692 SELECT id FROM persistent.keyentry
2693 WHERE domain = ? AND namespace = ?
2694 );",
2695 params![domain.0, namespace],
2696 )
2697 .context("Trying to delete keymetadata.")?;
2698 tx.execute(
2699 "DELETE FROM persistent.keyparameter
2700 WHERE keyentryid IN (
2701 SELECT id FROM persistent.keyentry
2702 WHERE domain = ? AND namespace = ?
2703 );",
2704 params![domain.0, namespace],
2705 )
2706 .context("Trying to delete keyparameters.")?;
2707 tx.execute(
2708 "DELETE FROM persistent.grant
2709 WHERE keyentryid IN (
2710 SELECT id FROM persistent.keyentry
2711 WHERE domain = ? AND namespace = ?
2712 );",
2713 params![domain.0, namespace],
2714 )
2715 .context("Trying to delete grants.")?;
2716 tx.execute(
2717 "DELETE FROM persistent.keyentry WHERE domain = ? AND namespace = ?;",
2718 params![domain.0, namespace],
2719 )
2720 .context("Trying to delete keyentry.")?;
2721 Ok(()).need_gc()
2722 })
2723 .context("In unbind_keys_for_namespace")
2724 }
2725
Hasini Gunasingheda895552021-01-27 19:34:37 +00002726 /// Delete the keys created on behalf of the user, denoted by the user id.
2727 /// Delete all the keys unless 'keep_non_super_encrypted_keys' set to true.
2728 /// Returned boolean is to hint the garbage collector to delete the unbound keys.
2729 /// The caller of this function should notify the gc if the returned value is true.
2730 pub fn unbind_keys_for_user(
2731 &mut self,
2732 user_id: u32,
2733 keep_non_super_encrypted_keys: bool,
2734 ) -> Result<()> {
2735 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2736 let mut stmt = tx
2737 .prepare(&format!(
2738 "SELECT id from persistent.keyentry
2739 WHERE (
2740 key_type = ?
2741 AND domain = ?
2742 AND cast ( (namespace/{aid_user_offset}) as int) = ?
2743 AND state = ?
2744 ) OR (
2745 key_type = ?
2746 AND namespace = ?
2747 AND alias = ?
2748 AND state = ?
2749 );",
2750 aid_user_offset = AID_USER_OFFSET
2751 ))
2752 .context(concat!(
2753 "In unbind_keys_for_user. ",
2754 "Failed to prepare the query to find the keys created by apps."
2755 ))?;
2756
2757 let mut rows = stmt
2758 .query(params![
2759 // WHERE client key:
2760 KeyType::Client,
2761 Domain::APP.0 as u32,
2762 user_id,
2763 KeyLifeCycle::Live,
2764 // OR super key:
2765 KeyType::Super,
2766 user_id,
Paul Crowley7a658392021-03-18 17:08:20 -07002767 USER_SUPER_KEY.alias,
Hasini Gunasingheda895552021-01-27 19:34:37 +00002768 KeyLifeCycle::Live
2769 ])
2770 .context("In unbind_keys_for_user. Failed to query the keys created by apps.")?;
2771
2772 let mut key_ids: Vec<i64> = Vec::new();
2773 db_utils::with_rows_extract_all(&mut rows, |row| {
2774 key_ids
2775 .push(row.get(0).context("Failed to read key id of a key created by an app.")?);
2776 Ok(())
2777 })
2778 .context("In unbind_keys_for_user.")?;
2779
2780 let mut notify_gc = false;
2781 for key_id in key_ids {
2782 if keep_non_super_encrypted_keys {
2783 // Load metadata and filter out non-super-encrypted keys.
2784 if let (_, Some((_, blob_metadata)), _, _) =
2785 Self::load_blob_components(key_id, KeyEntryLoadBits::KM, tx)
2786 .context("In unbind_keys_for_user: Trying to load blob info.")?
2787 {
2788 if blob_metadata.encrypted_by().is_none() {
2789 continue;
2790 }
2791 }
2792 }
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +00002793 notify_gc = Self::mark_unreferenced(&tx, key_id)
Hasini Gunasingheda895552021-01-27 19:34:37 +00002794 .context("In unbind_keys_for_user.")?
2795 || notify_gc;
2796 }
2797 Ok(()).do_gc(notify_gc)
2798 })
2799 .context("In unbind_keys_for_user.")
2800 }
2801
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002802 fn load_key_components(
2803 tx: &Transaction,
2804 load_bits: KeyEntryLoadBits,
2805 key_id: i64,
2806 ) -> Result<KeyEntry> {
2807 let metadata = KeyMetaData::load_from_db(key_id, &tx).context("In load_key_components.")?;
2808
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002809 let (has_km_blob, key_blob_info, cert_blob, cert_chain_blob) =
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002810 Self::load_blob_components(key_id, load_bits, &tx)
2811 .context("In load_key_components.")?;
2812
Max Bires8e93d2b2021-01-14 13:17:59 -08002813 let parameters = Self::load_key_parameters(key_id, &tx)
2814 .context("In load_key_components: Trying to load key parameters.")?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002815
Max Bires8e93d2b2021-01-14 13:17:59 -08002816 let km_uuid = Self::get_key_km_uuid(&tx, key_id)
2817 .context("In load_key_components: Trying to get KM uuid.")?;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002818
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002819 Ok(KeyEntry {
2820 id: key_id,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002821 key_blob_info,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002822 cert: cert_blob,
2823 cert_chain: cert_chain_blob,
Max Bires8e93d2b2021-01-14 13:17:59 -08002824 km_uuid,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002825 parameters,
2826 metadata,
Janis Danisevskis377d1002021-01-27 19:07:48 -08002827 pure_cert: !has_km_blob,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002828 })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002829 }
2830
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002831 /// Returns a list of KeyDescriptors in the selected domain/namespace.
2832 /// The key descriptors will have the domain, nspace, and alias field set.
2833 /// Domain must be APP or SELINUX, the caller must make sure of that.
2834 pub fn list(&mut self, domain: Domain, namespace: i64) -> Result<Vec<KeyDescriptor>> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002835 self.with_transaction(TransactionBehavior::Deferred, |tx| {
2836 let mut stmt = tx
2837 .prepare(
2838 "SELECT alias FROM persistent.keyentry
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002839 WHERE domain = ? AND namespace = ? AND alias IS NOT NULL AND state = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08002840 )
2841 .context("In list: Failed to prepare.")?;
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002842
Janis Danisevskis66784c42021-01-27 08:40:25 -08002843 let mut rows = stmt
2844 .query(params![domain.0 as u32, namespace, KeyLifeCycle::Live])
2845 .context("In list: Failed to query.")?;
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002846
Janis Danisevskis66784c42021-01-27 08:40:25 -08002847 let mut descriptors: Vec<KeyDescriptor> = Vec::new();
2848 db_utils::with_rows_extract_all(&mut rows, |row| {
2849 descriptors.push(KeyDescriptor {
2850 domain,
2851 nspace: namespace,
2852 alias: Some(row.get(0).context("Trying to extract alias.")?),
2853 blob: None,
2854 });
2855 Ok(())
2856 })
2857 .context("In list: Failed to extract rows.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002858 Ok(descriptors).no_gc()
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002859 })
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002860 }
2861
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002862 /// Adds a grant to the grant table.
2863 /// Like `load_key_entry` this function loads the access tuple before
2864 /// it uses the callback for a permission check. Upon success,
2865 /// it inserts the `grantee_uid`, `key_id`, and `access_vector` into the
2866 /// grant table. The new row will have a randomized id, which is used as
2867 /// grant id in the namespace field of the resulting KeyDescriptor.
2868 pub fn grant(
2869 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002870 key: &KeyDescriptor,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002871 caller_uid: u32,
2872 grantee_uid: u32,
2873 access_vector: KeyPermSet,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002874 check_permission: impl Fn(&KeyDescriptor, &KeyPermSet) -> Result<()>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002875 ) -> Result<KeyDescriptor> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002876 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2877 // Load the key_id and complete the access control tuple.
2878 // We ignore the access vector here because grants cannot be granted.
2879 // The access vector returned here expresses the permissions the
2880 // grantee has if key.domain == Domain::GRANT. But this vector
2881 // cannot include the grant permission by design, so there is no way the
2882 // subsequent permission check can pass.
2883 // We could check key.domain == Domain::GRANT and fail early.
2884 // But even if we load the access tuple by grant here, the permission
2885 // check denies the attempt to create a grant by grant descriptor.
2886 let (key_id, access_key_descriptor, _) =
2887 Self::load_access_tuple(&tx, key, KeyType::Client, caller_uid)
2888 .context("In grant")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002889
Janis Danisevskis66784c42021-01-27 08:40:25 -08002890 // Perform access control. It is vital that we return here if the permission
2891 // was denied. So do not touch that '?' at the end of the line.
2892 // This permission check checks if the caller has the grant permission
2893 // for the given key and in addition to all of the permissions
2894 // expressed in `access_vector`.
2895 check_permission(&access_key_descriptor, &access_vector)
2896 .context("In grant: check_permission failed.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002897
Janis Danisevskis66784c42021-01-27 08:40:25 -08002898 let grant_id = if let Some(grant_id) = tx
2899 .query_row(
2900 "SELECT id FROM persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002901 WHERE keyentryid = ? AND grantee = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08002902 params![key_id, grantee_uid],
2903 |row| row.get(0),
2904 )
2905 .optional()
2906 .context("In grant: Failed get optional existing grant id.")?
2907 {
2908 tx.execute(
2909 "UPDATE persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002910 SET access_vector = ?
2911 WHERE id = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08002912 params![i32::from(access_vector), grant_id],
Joel Galenson845f74b2020-09-09 14:11:55 -07002913 )
Janis Danisevskis66784c42021-01-27 08:40:25 -08002914 .context("In grant: Failed to update existing grant.")?;
2915 grant_id
2916 } else {
2917 Self::insert_with_retry(|id| {
2918 tx.execute(
2919 "INSERT INTO persistent.grant (id, grantee, keyentryid, access_vector)
2920 VALUES (?, ?, ?, ?);",
2921 params![id, grantee_uid, key_id, i32::from(access_vector)],
2922 )
2923 })
2924 .context("In grant")?
2925 };
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002926
Janis Danisevskis66784c42021-01-27 08:40:25 -08002927 Ok(KeyDescriptor { domain: Domain::GRANT, nspace: grant_id, alias: None, blob: None })
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002928 .no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08002929 })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002930 }
2931
2932 /// This function checks permissions like `grant` and `load_key_entry`
2933 /// before removing a grant from the grant table.
2934 pub fn ungrant(
2935 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002936 key: &KeyDescriptor,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002937 caller_uid: u32,
2938 grantee_uid: u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002939 check_permission: impl Fn(&KeyDescriptor) -> Result<()>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002940 ) -> Result<()> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002941 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2942 // Load the key_id and complete the access control tuple.
2943 // We ignore the access vector here because grants cannot be granted.
2944 let (key_id, access_key_descriptor, _) =
2945 Self::load_access_tuple(&tx, key, KeyType::Client, caller_uid)
2946 .context("In ungrant.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002947
Janis Danisevskis66784c42021-01-27 08:40:25 -08002948 // Perform access control. We must return here if the permission
2949 // was denied. So do not touch the '?' at the end of this line.
2950 check_permission(&access_key_descriptor)
2951 .context("In grant: check_permission failed.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002952
Janis Danisevskis66784c42021-01-27 08:40:25 -08002953 tx.execute(
2954 "DELETE FROM persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002955 WHERE keyentryid = ? AND grantee = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08002956 params![key_id, grantee_uid],
2957 )
2958 .context("Failed to delete grant.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002959
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002960 Ok(()).no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08002961 })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002962 }
2963
Joel Galenson845f74b2020-09-09 14:11:55 -07002964 // Generates a random id and passes it to the given function, which will
2965 // try to insert it into a database. If that insertion fails, retry;
2966 // otherwise return the id.
2967 fn insert_with_retry(inserter: impl Fn(i64) -> rusqlite::Result<usize>) -> Result<i64> {
2968 loop {
Janis Danisevskiseed69842021-02-18 20:04:10 -08002969 let newid: i64 = match random() {
2970 Self::UNASSIGNED_KEY_ID => continue, // UNASSIGNED_KEY_ID cannot be assigned.
2971 i => i,
2972 };
Joel Galenson845f74b2020-09-09 14:11:55 -07002973 match inserter(newid) {
2974 // If the id already existed, try again.
2975 Err(rusqlite::Error::SqliteFailure(
2976 libsqlite3_sys::Error {
2977 code: libsqlite3_sys::ErrorCode::ConstraintViolation,
2978 extended_code: libsqlite3_sys::SQLITE_CONSTRAINT_UNIQUE,
2979 },
2980 _,
2981 )) => (),
2982 Err(e) => {
2983 return Err(e).context("In insert_with_retry: failed to insert into database.")
2984 }
2985 _ => return Ok(newid),
2986 }
2987 }
2988 }
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002989
2990 /// Insert or replace the auth token based on the UNIQUE constraint of the auth token table
2991 pub fn insert_auth_token(&mut self, auth_token: &HardwareAuthToken) -> Result<()> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002992 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2993 tx.execute(
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002994 "INSERT OR REPLACE INTO perboot.authtoken (challenge, user_id, auth_id,
2995 authenticator_type, timestamp, mac, time_received) VALUES(?, ?, ?, ?, ?, ?, ?);",
2996 params![
2997 auth_token.challenge,
2998 auth_token.userId,
2999 auth_token.authenticatorId,
3000 auth_token.authenticatorType.0 as i32,
3001 auth_token.timestamp.milliSeconds as i64,
3002 auth_token.mac,
3003 MonotonicRawTime::now(),
3004 ],
3005 )
3006 .context("In insert_auth_token: failed to insert auth token into the database")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003007 Ok(()).no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08003008 })
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00003009 }
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00003010
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08003011 /// Find the newest auth token matching the given predicate.
3012 pub fn find_auth_token_entry<F>(
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00003013 &mut self,
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08003014 p: F,
3015 ) -> Result<Option<(AuthTokenEntry, MonotonicRawTime)>>
3016 where
3017 F: Fn(&AuthTokenEntry) -> bool,
3018 {
3019 self.with_transaction(TransactionBehavior::Deferred, |tx| {
3020 let mut stmt = tx
3021 .prepare("SELECT * from perboot.authtoken ORDER BY time_received DESC;")
3022 .context("Prepare statement failed.")?;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00003023
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08003024 let mut rows = stmt.query(NO_PARAMS).context("Failed to query.")?;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00003025
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08003026 while let Some(row) = rows.next().context("Failed to get next row.")? {
3027 let entry = AuthTokenEntry::new(
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00003028 HardwareAuthToken {
3029 challenge: row.get(1)?,
3030 userId: row.get(2)?,
3031 authenticatorId: row.get(3)?,
3032 authenticatorType: HardwareAuthenticatorType(row.get(4)?),
3033 timestamp: Timestamp { milliSeconds: row.get(5)? },
3034 mac: row.get(6)?,
3035 },
3036 row.get(7)?,
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08003037 );
3038 if p(&entry) {
3039 return Ok(Some((
3040 entry,
3041 Self::get_last_off_body(tx)
3042 .context("In find_auth_token_entry: Trying to get last off body")?,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003043 )))
3044 .no_gc();
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08003045 }
3046 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003047 Ok(None).no_gc()
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08003048 })
3049 .context("In find_auth_token_entry.")
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00003050 }
3051
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08003052 /// Insert last_off_body into the metadata table at the initialization of auth token table
Janis Danisevskis66784c42021-01-27 08:40:25 -08003053 pub fn insert_last_off_body(&mut self, last_off_body: MonotonicRawTime) -> Result<()> {
3054 self.with_transaction(TransactionBehavior::Immediate, |tx| {
3055 tx.execute(
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08003056 "INSERT OR REPLACE INTO perboot.metadata (key, value) VALUES (?, ?);",
3057 params!["last_off_body", last_off_body],
3058 )
3059 .context("In insert_last_off_body: failed to insert.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003060 Ok(()).no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08003061 })
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00003062 }
3063
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08003064 /// Update last_off_body when on_device_off_body is called
Janis Danisevskis66784c42021-01-27 08:40:25 -08003065 pub fn update_last_off_body(&mut self, last_off_body: MonotonicRawTime) -> Result<()> {
3066 self.with_transaction(TransactionBehavior::Immediate, |tx| {
3067 tx.execute(
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00003068 "UPDATE perboot.metadata SET value = ? WHERE key = ?;",
3069 params![last_off_body, "last_off_body"],
3070 )
3071 .context("In update_last_off_body: failed to update.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003072 Ok(()).no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08003073 })
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00003074 }
3075
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08003076 /// Get last_off_body time when finding auth tokens
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00003077 fn get_last_off_body(tx: &Transaction) -> Result<MonotonicRawTime> {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08003078 tx.query_row(
3079 "SELECT value from perboot.metadata WHERE key = ?;",
3080 params!["last_off_body"],
3081 |row| Ok(row.get(0)?),
3082 )
3083 .context("In get_last_off_body: query_row failed.")
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00003084 }
Joel Galenson26f4d012020-07-17 14:57:21 -07003085}
3086
3087#[cfg(test)]
3088mod tests {
3089
3090 use super::*;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07003091 use crate::key_parameter::{
3092 Algorithm, BlockMode, Digest, EcCurve, HardwareAuthenticatorType, KeyOrigin, KeyParameter,
3093 KeyParameterValue, KeyPurpose, PaddingMode, SecurityLevel,
3094 };
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003095 use crate::key_perm_set;
3096 use crate::permission::{KeyPerm, KeyPermSet};
Hasini Gunasingheda895552021-01-27 19:34:37 +00003097 use crate::super_key::SuperKeyManager;
Janis Danisevskis2a8330a2021-01-20 15:34:26 -08003098 use keystore2_test_utils::TempDir;
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00003099 use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
3100 HardwareAuthToken::HardwareAuthToken,
3101 HardwareAuthenticatorType::HardwareAuthenticatorType as kmhw_authenticator_type,
Janis Danisevskisc3a496b2021-01-05 10:37:22 -08003102 };
3103 use android_hardware_security_secureclock::aidl::android::hardware::security::secureclock::{
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00003104 Timestamp::Timestamp,
3105 };
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003106 use rusqlite::NO_PARAMS;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00003107 use rusqlite::{Error, TransactionBehavior};
Joel Galenson0891bc12020-07-20 10:37:03 -07003108 use std::cell::RefCell;
Seth Moore78c091f2021-04-09 21:38:30 +00003109 use std::collections::BTreeMap;
3110 use std::fmt::Write;
Janis Danisevskisaec14592020-11-12 09:41:49 -08003111 use std::sync::atomic::{AtomicU8, Ordering};
3112 use std::sync::Arc;
3113 use std::thread;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00003114 use std::time::{Duration, SystemTime};
Janis Danisevskis66784c42021-01-27 08:40:25 -08003115 #[cfg(disabled)]
3116 use std::time::Instant;
Joel Galenson0891bc12020-07-20 10:37:03 -07003117
Janis Danisevskis4df44f42020-08-26 14:40:03 -07003118 fn new_test_db() -> Result<KeystoreDB> {
3119 let conn = KeystoreDB::make_connection("file::memory:", "file::memory:")?;
3120
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003121 let mut db = KeystoreDB { conn, gc: None };
Janis Danisevskis66784c42021-01-27 08:40:25 -08003122 db.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003123 KeystoreDB::init_tables(tx).context("Failed to initialize tables.").no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08003124 })?;
3125 Ok(db)
Janis Danisevskis4df44f42020-08-26 14:40:03 -07003126 }
3127
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003128 fn new_test_db_with_gc<F>(path: &Path, cb: F) -> Result<KeystoreDB>
3129 where
3130 F: Fn(&Uuid, &[u8]) -> Result<()> + Send + 'static,
3131 {
Paul Crowleye8826e52021-03-31 08:33:53 -07003132 let super_key: Arc<SuperKeyManager> = Default::default();
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00003133
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003134 let gc_db = KeystoreDB::new(path, None).expect("Failed to open test gc db_connection.");
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00003135 let gc = Gc::new_init_with(Default::default(), move || (Box::new(cb), gc_db, super_key));
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003136
3137 KeystoreDB::new(path, Some(gc))
3138 }
3139
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003140 fn rebind_alias(
3141 db: &mut KeystoreDB,
3142 newid: &KeyIdGuard,
3143 alias: &str,
3144 domain: Domain,
3145 namespace: i64,
3146 ) -> Result<bool> {
3147 db.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003148 KeystoreDB::rebind_alias(tx, newid, alias, &domain, &namespace).no_gc()
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003149 })
3150 .context("In rebind_alias.")
3151 }
3152
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003153 #[test]
3154 fn datetime() -> Result<()> {
3155 let conn = Connection::open_in_memory()?;
3156 conn.execute("CREATE TABLE test (ts DATETIME);", NO_PARAMS)?;
3157 let now = SystemTime::now();
3158 let duration = Duration::from_secs(1000);
3159 let then = now.checked_sub(duration).unwrap();
3160 let soon = now.checked_add(duration).unwrap();
3161 conn.execute(
3162 "INSERT INTO test (ts) VALUES (?), (?), (?);",
3163 params![DateTime::try_from(now)?, DateTime::try_from(then)?, DateTime::try_from(soon)?],
3164 )?;
3165 let mut stmt = conn.prepare("SELECT ts FROM test ORDER BY ts ASC;")?;
3166 let mut rows = stmt.query(NO_PARAMS)?;
3167 assert_eq!(DateTime::try_from(then)?, rows.next()?.unwrap().get(0)?);
3168 assert_eq!(DateTime::try_from(now)?, rows.next()?.unwrap().get(0)?);
3169 assert_eq!(DateTime::try_from(soon)?, rows.next()?.unwrap().get(0)?);
3170 assert!(rows.next()?.is_none());
3171 assert!(DateTime::try_from(then)? < DateTime::try_from(now)?);
3172 assert!(DateTime::try_from(then)? < DateTime::try_from(soon)?);
3173 assert!(DateTime::try_from(now)? < DateTime::try_from(soon)?);
3174 Ok(())
3175 }
3176
Joel Galenson0891bc12020-07-20 10:37:03 -07003177 // Ensure that we're using the "injected" random function, not the real one.
3178 #[test]
3179 fn test_mocked_random() {
3180 let rand1 = random();
3181 let rand2 = random();
3182 let rand3 = random();
3183 if rand1 == rand2 {
3184 assert_eq!(rand2 + 1, rand3);
3185 } else {
3186 assert_eq!(rand1 + 1, rand2);
3187 assert_eq!(rand2, rand3);
3188 }
3189 }
Joel Galenson26f4d012020-07-17 14:57:21 -07003190
Joel Galenson26f4d012020-07-17 14:57:21 -07003191 // Test that we have the correct tables.
3192 #[test]
3193 fn test_tables() -> Result<()> {
Janis Danisevskis4df44f42020-08-26 14:40:03 -07003194 let db = new_test_db()?;
Joel Galenson26f4d012020-07-17 14:57:21 -07003195 let tables = db
3196 .conn
Joel Galenson2aab4432020-07-22 15:27:57 -07003197 .prepare("SELECT name from persistent.sqlite_master WHERE type='table' ORDER BY name;")?
Joel Galenson26f4d012020-07-17 14:57:21 -07003198 .query_map(params![], |row| row.get(0))?
3199 .collect::<rusqlite::Result<Vec<String>>>()?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003200 assert_eq!(tables.len(), 6);
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003201 assert_eq!(tables[0], "blobentry");
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003202 assert_eq!(tables[1], "blobmetadata");
3203 assert_eq!(tables[2], "grant");
3204 assert_eq!(tables[3], "keyentry");
3205 assert_eq!(tables[4], "keymetadata");
3206 assert_eq!(tables[5], "keyparameter");
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003207 let tables = db
3208 .conn
3209 .prepare("SELECT name from perboot.sqlite_master WHERE type='table' ORDER BY name;")?
3210 .query_map(params![], |row| row.get(0))?
3211 .collect::<rusqlite::Result<Vec<String>>>()?;
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00003212
3213 assert_eq!(tables.len(), 2);
3214 assert_eq!(tables[0], "authtoken");
3215 assert_eq!(tables[1], "metadata");
Joel Galenson2aab4432020-07-22 15:27:57 -07003216 Ok(())
3217 }
3218
3219 #[test]
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00003220 fn test_auth_token_table_invariant() -> Result<()> {
3221 let mut db = new_test_db()?;
3222 let auth_token1 = HardwareAuthToken {
3223 challenge: i64::MAX,
3224 userId: 200,
3225 authenticatorId: 200,
3226 authenticatorType: kmhw_authenticator_type(kmhw_authenticator_type::PASSWORD.0),
3227 timestamp: Timestamp { milliSeconds: 500 },
3228 mac: String::from("mac").into_bytes(),
3229 };
3230 db.insert_auth_token(&auth_token1)?;
3231 let auth_tokens_returned = get_auth_tokens(&mut db)?;
3232 assert_eq!(auth_tokens_returned.len(), 1);
3233
3234 // insert another auth token with the same values for the columns in the UNIQUE constraint
3235 // of the auth token table and different value for timestamp
3236 let auth_token2 = HardwareAuthToken {
3237 challenge: i64::MAX,
3238 userId: 200,
3239 authenticatorId: 200,
3240 authenticatorType: kmhw_authenticator_type(kmhw_authenticator_type::PASSWORD.0),
3241 timestamp: Timestamp { milliSeconds: 600 },
3242 mac: String::from("mac").into_bytes(),
3243 };
3244
3245 db.insert_auth_token(&auth_token2)?;
3246 let mut auth_tokens_returned = get_auth_tokens(&mut db)?;
3247 assert_eq!(auth_tokens_returned.len(), 1);
3248
3249 if let Some(auth_token) = auth_tokens_returned.pop() {
3250 assert_eq!(auth_token.auth_token.timestamp.milliSeconds, 600);
3251 }
3252
3253 // insert another auth token with the different values for the columns in the UNIQUE
3254 // constraint of the auth token table
3255 let auth_token3 = HardwareAuthToken {
3256 challenge: i64::MAX,
3257 userId: 201,
3258 authenticatorId: 200,
3259 authenticatorType: kmhw_authenticator_type(kmhw_authenticator_type::PASSWORD.0),
3260 timestamp: Timestamp { milliSeconds: 600 },
3261 mac: String::from("mac").into_bytes(),
3262 };
3263
3264 db.insert_auth_token(&auth_token3)?;
3265 let auth_tokens_returned = get_auth_tokens(&mut db)?;
3266 assert_eq!(auth_tokens_returned.len(), 2);
3267
3268 Ok(())
3269 }
3270
3271 // utility function for test_auth_token_table_invariant()
3272 fn get_auth_tokens(db: &mut KeystoreDB) -> Result<Vec<AuthTokenEntry>> {
3273 let mut stmt = db.conn.prepare("SELECT * from perboot.authtoken;")?;
3274
3275 let auth_token_entries: Vec<AuthTokenEntry> = stmt
3276 .query_map(NO_PARAMS, |row| {
3277 Ok(AuthTokenEntry::new(
3278 HardwareAuthToken {
3279 challenge: row.get(1)?,
3280 userId: row.get(2)?,
3281 authenticatorId: row.get(3)?,
3282 authenticatorType: HardwareAuthenticatorType(row.get(4)?),
3283 timestamp: Timestamp { milliSeconds: row.get(5)? },
3284 mac: row.get(6)?,
3285 },
3286 row.get(7)?,
3287 ))
3288 })?
3289 .collect::<Result<Vec<AuthTokenEntry>, Error>>()?;
3290 Ok(auth_token_entries)
3291 }
3292
3293 #[test]
Joel Galenson2aab4432020-07-22 15:27:57 -07003294 fn test_persistence_for_files() -> Result<()> {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08003295 let temp_dir = TempDir::new("persistent_db_test")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003296 let mut db = KeystoreDB::new(temp_dir.path(), None)?;
Joel Galenson2aab4432020-07-22 15:27:57 -07003297
Janis Danisevskis66784c42021-01-27 08:40:25 -08003298 db.create_key_entry(&Domain::APP, &100, &KEYSTORE_UUID)?;
Joel Galenson2aab4432020-07-22 15:27:57 -07003299 let entries = get_keyentry(&db)?;
3300 assert_eq!(entries.len(), 1);
Janis Danisevskisbf15d732020-12-08 10:35:26 -08003301
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003302 let db = KeystoreDB::new(temp_dir.path(), None)?;
Joel Galenson2aab4432020-07-22 15:27:57 -07003303
3304 let entries_new = get_keyentry(&db)?;
3305 assert_eq!(entries, entries_new);
3306 Ok(())
3307 }
3308
3309 #[test]
Joel Galenson0891bc12020-07-20 10:37:03 -07003310 fn test_create_key_entry() -> Result<()> {
Max Bires8e93d2b2021-01-14 13:17:59 -08003311 fn extractor(ke: &KeyEntryRow) -> (Domain, i64, Option<&str>, Uuid) {
3312 (ke.domain.unwrap(), ke.namespace.unwrap(), ke.alias.as_deref(), ke.km_uuid.unwrap())
Joel Galenson0891bc12020-07-20 10:37:03 -07003313 }
3314
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003315 let mut db = new_test_db()?;
Joel Galenson0891bc12020-07-20 10:37:03 -07003316
Janis Danisevskis66784c42021-01-27 08:40:25 -08003317 db.create_key_entry(&Domain::APP, &100, &KEYSTORE_UUID)?;
3318 db.create_key_entry(&Domain::SELINUX, &101, &KEYSTORE_UUID)?;
Joel Galenson0891bc12020-07-20 10:37:03 -07003319
3320 let entries = get_keyentry(&db)?;
3321 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08003322 assert_eq!(extractor(&entries[0]), (Domain::APP, 100, None, KEYSTORE_UUID));
3323 assert_eq!(extractor(&entries[1]), (Domain::SELINUX, 101, None, KEYSTORE_UUID));
Joel Galenson0891bc12020-07-20 10:37:03 -07003324
3325 // Test that we must pass in a valid Domain.
3326 check_result_is_error_containing_string(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003327 db.create_key_entry(&Domain::GRANT, &102, &KEYSTORE_UUID),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003328 "Domain Domain(1) must be either App or SELinux.",
Joel Galenson0891bc12020-07-20 10:37:03 -07003329 );
3330 check_result_is_error_containing_string(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003331 db.create_key_entry(&Domain::BLOB, &103, &KEYSTORE_UUID),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003332 "Domain Domain(3) must be either App or SELinux.",
Joel Galenson0891bc12020-07-20 10:37:03 -07003333 );
3334 check_result_is_error_containing_string(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003335 db.create_key_entry(&Domain::KEY_ID, &104, &KEYSTORE_UUID),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003336 "Domain Domain(4) must be either App or SELinux.",
Joel Galenson0891bc12020-07-20 10:37:03 -07003337 );
3338
3339 Ok(())
3340 }
3341
Joel Galenson33c04ad2020-08-03 11:04:38 -07003342 #[test]
Max Bires2b2e6562020-09-22 11:22:36 -07003343 fn test_add_unsigned_key() -> Result<()> {
3344 let mut db = new_test_db()?;
3345 let public_key: Vec<u8> = vec![0x01, 0x02, 0x03];
3346 let private_key: Vec<u8> = vec![0x04, 0x05, 0x06];
3347 let raw_public_key: Vec<u8> = vec![0x07, 0x08, 0x09];
3348 db.create_attestation_key_entry(
3349 &public_key,
3350 &raw_public_key,
3351 &private_key,
3352 &KEYSTORE_UUID,
3353 )?;
3354 let keys = db.fetch_unsigned_attestation_keys(5, &KEYSTORE_UUID)?;
3355 assert_eq!(keys.len(), 1);
3356 assert_eq!(keys[0], public_key);
3357 Ok(())
3358 }
3359
3360 #[test]
3361 fn test_store_signed_attestation_certificate_chain() -> Result<()> {
3362 let mut db = new_test_db()?;
3363 let expiration_date: i64 = 20;
3364 let namespace: i64 = 30;
3365 let base_byte: u8 = 1;
3366 let loaded_values =
3367 load_attestation_key_pool(&mut db, expiration_date, namespace, base_byte)?;
3368 let chain =
3369 db.retrieve_attestation_key_and_cert_chain(Domain::APP, namespace, &KEYSTORE_UUID)?;
3370 assert_eq!(true, chain.is_some());
3371 let cert_chain = chain.unwrap();
Max Biresb2e1d032021-02-08 21:35:05 -08003372 assert_eq!(cert_chain.private_key.to_vec(), loaded_values.priv_key);
Max Bires97f96812021-02-23 23:44:57 -08003373 assert_eq!(cert_chain.batch_cert, loaded_values.batch_cert);
3374 assert_eq!(cert_chain.cert_chain, loaded_values.cert_chain);
Max Bires2b2e6562020-09-22 11:22:36 -07003375 Ok(())
3376 }
3377
3378 #[test]
3379 fn test_get_attestation_pool_status() -> Result<()> {
3380 let mut db = new_test_db()?;
3381 let namespace: i64 = 30;
3382 load_attestation_key_pool(
3383 &mut db, 10, /* expiration */
3384 namespace, 0x01, /* base_byte */
3385 )?;
3386 load_attestation_key_pool(&mut db, 20 /* expiration */, namespace + 1, 0x02)?;
3387 load_attestation_key_pool(&mut db, 40 /* expiration */, namespace + 2, 0x03)?;
3388 let mut status = db.get_attestation_pool_status(9 /* expiration */, &KEYSTORE_UUID)?;
3389 assert_eq!(status.expiring, 0);
3390 assert_eq!(status.attested, 3);
3391 assert_eq!(status.unassigned, 0);
3392 assert_eq!(status.total, 3);
3393 assert_eq!(
3394 db.get_attestation_pool_status(15 /* expiration */, &KEYSTORE_UUID)?.expiring,
3395 1
3396 );
3397 assert_eq!(
3398 db.get_attestation_pool_status(25 /* expiration */, &KEYSTORE_UUID)?.expiring,
3399 2
3400 );
3401 assert_eq!(
3402 db.get_attestation_pool_status(60 /* expiration */, &KEYSTORE_UUID)?.expiring,
3403 3
3404 );
3405 let public_key: Vec<u8> = vec![0x01, 0x02, 0x03];
3406 let private_key: Vec<u8> = vec![0x04, 0x05, 0x06];
3407 let raw_public_key: Vec<u8> = vec![0x07, 0x08, 0x09];
3408 let cert_chain: Vec<u8> = vec![0x0a, 0x0b, 0x0c];
Max Biresb2e1d032021-02-08 21:35:05 -08003409 let batch_cert: Vec<u8> = vec![0x0d, 0x0e, 0x0f];
Max Bires2b2e6562020-09-22 11:22:36 -07003410 db.create_attestation_key_entry(
3411 &public_key,
3412 &raw_public_key,
3413 &private_key,
3414 &KEYSTORE_UUID,
3415 )?;
3416 status = db.get_attestation_pool_status(0 /* expiration */, &KEYSTORE_UUID)?;
3417 assert_eq!(status.attested, 3);
3418 assert_eq!(status.unassigned, 0);
3419 assert_eq!(status.total, 4);
3420 db.store_signed_attestation_certificate_chain(
3421 &raw_public_key,
Max Biresb2e1d032021-02-08 21:35:05 -08003422 &batch_cert,
Max Bires2b2e6562020-09-22 11:22:36 -07003423 &cert_chain,
3424 20,
3425 &KEYSTORE_UUID,
3426 )?;
3427 status = db.get_attestation_pool_status(0 /* expiration */, &KEYSTORE_UUID)?;
3428 assert_eq!(status.attested, 4);
3429 assert_eq!(status.unassigned, 1);
3430 assert_eq!(status.total, 4);
3431 Ok(())
3432 }
3433
3434 #[test]
3435 fn test_remove_expired_certs() -> Result<()> {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003436 let temp_dir =
3437 TempDir::new("test_remove_expired_certs_").expect("Failed to create temp dir.");
3438 let mut db = new_test_db_with_gc(temp_dir.path(), |_, _| Ok(()))?;
Max Bires2b2e6562020-09-22 11:22:36 -07003439 let expiration_date: i64 =
3440 SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_millis() as i64 + 10000;
3441 let namespace: i64 = 30;
3442 let namespace_del1: i64 = 45;
3443 let namespace_del2: i64 = 60;
3444 let entry_values = load_attestation_key_pool(
3445 &mut db,
3446 expiration_date,
3447 namespace,
3448 0x01, /* base_byte */
3449 )?;
3450 load_attestation_key_pool(&mut db, 45, namespace_del1, 0x02)?;
3451 load_attestation_key_pool(&mut db, 60, namespace_del2, 0x03)?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003452
3453 let blob_entry_row_count: u32 = db
3454 .conn
3455 .query_row("SELECT COUNT(id) FROM persistent.blobentry;", NO_PARAMS, |row| row.get(0))
3456 .expect("Failed to get blob entry row count.");
Max Biresb2e1d032021-02-08 21:35:05 -08003457 // We expect 9 rows here because there are three blobs per attestation key, i.e.,
3458 // one key, one certificate chain, and one certificate.
3459 assert_eq!(blob_entry_row_count, 9);
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003460
Max Bires2b2e6562020-09-22 11:22:36 -07003461 assert_eq!(db.delete_expired_attestation_keys()?, 2);
3462
3463 let mut cert_chain =
3464 db.retrieve_attestation_key_and_cert_chain(Domain::APP, namespace, &KEYSTORE_UUID)?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003465 assert!(cert_chain.is_some());
Max Bires2b2e6562020-09-22 11:22:36 -07003466 let value = cert_chain.unwrap();
Max Bires97f96812021-02-23 23:44:57 -08003467 assert_eq!(entry_values.batch_cert, value.batch_cert);
3468 assert_eq!(entry_values.cert_chain, value.cert_chain);
Max Biresb2e1d032021-02-08 21:35:05 -08003469 assert_eq!(entry_values.priv_key, value.private_key.to_vec());
Max Bires2b2e6562020-09-22 11:22:36 -07003470
3471 cert_chain = db.retrieve_attestation_key_and_cert_chain(
3472 Domain::APP,
3473 namespace_del1,
3474 &KEYSTORE_UUID,
3475 )?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003476 assert!(!cert_chain.is_some());
Max Bires2b2e6562020-09-22 11:22:36 -07003477 cert_chain = db.retrieve_attestation_key_and_cert_chain(
3478 Domain::APP,
3479 namespace_del2,
3480 &KEYSTORE_UUID,
3481 )?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003482 assert!(!cert_chain.is_some());
Max Bires2b2e6562020-09-22 11:22:36 -07003483
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003484 // Give the garbage collector half a second to catch up.
3485 std::thread::sleep(Duration::from_millis(500));
Max Bires2b2e6562020-09-22 11:22:36 -07003486
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003487 let blob_entry_row_count: u32 = db
3488 .conn
3489 .query_row("SELECT COUNT(id) FROM persistent.blobentry;", NO_PARAMS, |row| row.get(0))
3490 .expect("Failed to get blob entry row count.");
Max Biresb2e1d032021-02-08 21:35:05 -08003491 // There shound be 3 blob entries left, because we deleted two of the attestation
3492 // key entries with three blobs each.
3493 assert_eq!(blob_entry_row_count, 3);
Max Bires2b2e6562020-09-22 11:22:36 -07003494
Max Bires2b2e6562020-09-22 11:22:36 -07003495 Ok(())
3496 }
3497
3498 #[test]
Max Bires60d7ed12021-03-05 15:59:22 -08003499 fn test_delete_all_attestation_keys() -> Result<()> {
3500 let mut db = new_test_db()?;
3501 load_attestation_key_pool(&mut db, 45 /* expiration */, 1 /* namespace */, 0x02)?;
3502 load_attestation_key_pool(&mut db, 80 /* expiration */, 2 /* namespace */, 0x03)?;
3503 db.create_key_entry(&Domain::APP, &42, &KEYSTORE_UUID)?;
3504 let result = db.delete_all_attestation_keys()?;
3505
3506 // Give the garbage collector half a second to catch up.
3507 std::thread::sleep(Duration::from_millis(500));
3508
3509 // Attestation keys should be deleted, and the regular key should remain.
3510 assert_eq!(result, 2);
3511
3512 Ok(())
3513 }
3514
3515 #[test]
Joel Galenson33c04ad2020-08-03 11:04:38 -07003516 fn test_rebind_alias() -> Result<()> {
Max Bires8e93d2b2021-01-14 13:17:59 -08003517 fn extractor(
3518 ke: &KeyEntryRow,
3519 ) -> (Option<Domain>, Option<i64>, Option<&str>, Option<Uuid>) {
3520 (ke.domain, ke.namespace, ke.alias.as_deref(), ke.km_uuid)
Joel Galenson33c04ad2020-08-03 11:04:38 -07003521 }
3522
Janis Danisevskis4df44f42020-08-26 14:40:03 -07003523 let mut db = new_test_db()?;
Janis Danisevskis66784c42021-01-27 08:40:25 -08003524 db.create_key_entry(&Domain::APP, &42, &KEYSTORE_UUID)?;
3525 db.create_key_entry(&Domain::APP, &42, &KEYSTORE_UUID)?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07003526 let entries = get_keyentry(&db)?;
3527 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08003528 assert_eq!(
3529 extractor(&entries[0]),
3530 (Some(Domain::APP), Some(42), None, Some(KEYSTORE_UUID))
3531 );
3532 assert_eq!(
3533 extractor(&entries[1]),
3534 (Some(Domain::APP), Some(42), None, Some(KEYSTORE_UUID))
3535 );
Joel Galenson33c04ad2020-08-03 11:04:38 -07003536
3537 // Test that the first call to rebind_alias sets the alias.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003538 rebind_alias(&mut db, &KEY_ID_LOCK.get(entries[0].id), "foo", Domain::APP, 42)?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07003539 let entries = get_keyentry(&db)?;
3540 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08003541 assert_eq!(
3542 extractor(&entries[0]),
3543 (Some(Domain::APP), Some(42), Some("foo"), Some(KEYSTORE_UUID))
3544 );
3545 assert_eq!(
3546 extractor(&entries[1]),
3547 (Some(Domain::APP), Some(42), None, Some(KEYSTORE_UUID))
3548 );
Joel Galenson33c04ad2020-08-03 11:04:38 -07003549
3550 // Test that the second call to rebind_alias also empties the old one.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003551 rebind_alias(&mut db, &KEY_ID_LOCK.get(entries[1].id), "foo", Domain::APP, 42)?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07003552 let entries = get_keyentry(&db)?;
3553 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08003554 assert_eq!(extractor(&entries[0]), (None, None, None, Some(KEYSTORE_UUID)));
3555 assert_eq!(
3556 extractor(&entries[1]),
3557 (Some(Domain::APP), Some(42), Some("foo"), Some(KEYSTORE_UUID))
3558 );
Joel Galenson33c04ad2020-08-03 11:04:38 -07003559
3560 // Test that we must pass in a valid Domain.
3561 check_result_is_error_containing_string(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003562 rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::GRANT, 42),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003563 "Domain Domain(1) must be either App or SELinux.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07003564 );
3565 check_result_is_error_containing_string(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003566 rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::BLOB, 42),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003567 "Domain Domain(3) must be either App or SELinux.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07003568 );
3569 check_result_is_error_containing_string(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003570 rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::KEY_ID, 42),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003571 "Domain Domain(4) must be either App or SELinux.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07003572 );
3573
3574 // Test that we correctly handle setting an alias for something that does not exist.
3575 check_result_is_error_containing_string(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003576 rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::SELINUX, 42),
Joel Galenson33c04ad2020-08-03 11:04:38 -07003577 "Expected to update a single entry but instead updated 0",
3578 );
3579 // Test that we correctly abort the transaction in this case.
3580 let entries = get_keyentry(&db)?;
3581 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08003582 assert_eq!(extractor(&entries[0]), (None, None, None, Some(KEYSTORE_UUID)));
3583 assert_eq!(
3584 extractor(&entries[1]),
3585 (Some(Domain::APP), Some(42), Some("foo"), Some(KEYSTORE_UUID))
3586 );
Joel Galenson33c04ad2020-08-03 11:04:38 -07003587
3588 Ok(())
3589 }
3590
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003591 #[test]
3592 fn test_grant_ungrant() -> Result<()> {
3593 const CALLER_UID: u32 = 15;
3594 const GRANTEE_UID: u32 = 12;
3595 const SELINUX_NAMESPACE: i64 = 7;
3596
3597 let mut db = new_test_db()?;
3598 db.conn.execute(
Max Bires8e93d2b2021-01-14 13:17:59 -08003599 "INSERT INTO persistent.keyentry (id, key_type, domain, namespace, alias, state, km_uuid)
3600 VALUES (1, 0, 0, 15, 'key', 1, ?), (2, 0, 2, 7, 'yek', 1, ?);",
3601 params![KEYSTORE_UUID, KEYSTORE_UUID],
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003602 )?;
3603 let app_key = KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003604 domain: super::Domain::APP,
3605 nspace: 0,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003606 alias: Some("key".to_string()),
3607 blob: None,
3608 };
3609 const PVEC1: KeyPermSet = key_perm_set![KeyPerm::use_(), KeyPerm::get_info()];
3610 const PVEC2: KeyPermSet = key_perm_set![KeyPerm::use_()];
3611
3612 // Reset totally predictable random number generator in case we
3613 // are not the first test running on this thread.
3614 reset_random();
3615 let next_random = 0i64;
3616
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003617 let app_granted_key = db
Janis Danisevskis66784c42021-01-27 08:40:25 -08003618 .grant(&app_key, CALLER_UID, GRANTEE_UID, PVEC1, |k, a| {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003619 assert_eq!(*a, PVEC1);
3620 assert_eq!(
3621 *k,
3622 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003623 domain: super::Domain::APP,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003624 // namespace must be set to the caller_uid.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003625 nspace: CALLER_UID as i64,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003626 alias: Some("key".to_string()),
3627 blob: None,
3628 }
3629 );
3630 Ok(())
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003631 })
3632 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003633
3634 assert_eq!(
3635 app_granted_key,
3636 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003637 domain: super::Domain::GRANT,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003638 // The grantid is next_random due to the mock random number generator.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003639 nspace: next_random,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003640 alias: None,
3641 blob: None,
3642 }
3643 );
3644
3645 let selinux_key = KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003646 domain: super::Domain::SELINUX,
3647 nspace: SELINUX_NAMESPACE,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003648 alias: Some("yek".to_string()),
3649 blob: None,
3650 };
3651
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003652 let selinux_granted_key = db
Janis Danisevskis66784c42021-01-27 08:40:25 -08003653 .grant(&selinux_key, CALLER_UID, 12, PVEC1, |k, a| {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003654 assert_eq!(*a, PVEC1);
3655 assert_eq!(
3656 *k,
3657 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003658 domain: super::Domain::SELINUX,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003659 // namespace must be the supplied SELinux
3660 // namespace.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003661 nspace: SELINUX_NAMESPACE,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003662 alias: Some("yek".to_string()),
3663 blob: None,
3664 }
3665 );
3666 Ok(())
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003667 })
3668 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003669
3670 assert_eq!(
3671 selinux_granted_key,
3672 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003673 domain: super::Domain::GRANT,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003674 // The grantid is next_random + 1 due to the mock random number generator.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003675 nspace: next_random + 1,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003676 alias: None,
3677 blob: None,
3678 }
3679 );
3680
3681 // This should update the existing grant with PVEC2.
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003682 let selinux_granted_key = db
Janis Danisevskis66784c42021-01-27 08:40:25 -08003683 .grant(&selinux_key, CALLER_UID, 12, PVEC2, |k, a| {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003684 assert_eq!(*a, PVEC2);
3685 assert_eq!(
3686 *k,
3687 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003688 domain: super::Domain::SELINUX,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003689 // namespace must be the supplied SELinux
3690 // namespace.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003691 nspace: SELINUX_NAMESPACE,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003692 alias: Some("yek".to_string()),
3693 blob: None,
3694 }
3695 );
3696 Ok(())
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003697 })
3698 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003699
3700 assert_eq!(
3701 selinux_granted_key,
3702 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003703 domain: super::Domain::GRANT,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003704 // Same grant id as before. The entry was only updated.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003705 nspace: next_random + 1,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003706 alias: None,
3707 blob: None,
3708 }
3709 );
3710
3711 {
3712 // Limiting scope of stmt, because it borrows db.
3713 let mut stmt = db
3714 .conn
Janis Danisevskisbf15d732020-12-08 10:35:26 -08003715 .prepare("SELECT id, grantee, keyentryid, access_vector FROM persistent.grant;")?;
Janis Danisevskisee10b5f2020-09-22 16:42:35 -07003716 let mut rows =
3717 stmt.query_map::<(i64, u32, i64, KeyPermSet), _, _>(NO_PARAMS, |row| {
3718 Ok((
3719 row.get(0)?,
3720 row.get(1)?,
3721 row.get(2)?,
3722 KeyPermSet::from(row.get::<_, i32>(3)?),
3723 ))
3724 })?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003725
3726 let r = rows.next().unwrap().unwrap();
Janis Danisevskisee10b5f2020-09-22 16:42:35 -07003727 assert_eq!(r, (next_random, GRANTEE_UID, 1, PVEC1));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003728 let r = rows.next().unwrap().unwrap();
Janis Danisevskisee10b5f2020-09-22 16:42:35 -07003729 assert_eq!(r, (next_random + 1, GRANTEE_UID, 2, PVEC2));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003730 assert!(rows.next().is_none());
3731 }
3732
3733 debug_dump_keyentry_table(&mut db)?;
3734 println!("app_key {:?}", app_key);
3735 println!("selinux_key {:?}", selinux_key);
3736
Janis Danisevskis66784c42021-01-27 08:40:25 -08003737 db.ungrant(&app_key, CALLER_UID, GRANTEE_UID, |_| Ok(()))?;
3738 db.ungrant(&selinux_key, CALLER_UID, GRANTEE_UID, |_| Ok(()))?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003739
3740 Ok(())
3741 }
3742
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003743 static TEST_KEY_BLOB: &[u8] = b"my test blob";
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003744 static TEST_CERT_BLOB: &[u8] = b"my test cert";
3745 static TEST_CERT_CHAIN_BLOB: &[u8] = b"my test cert_chain";
3746
3747 #[test]
Janis Danisevskis377d1002021-01-27 19:07:48 -08003748 fn test_set_blob() -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003749 let key_id = KEY_ID_LOCK.get(3000);
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003750 let mut db = new_test_db()?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003751 let mut blob_metadata = BlobMetaData::new();
3752 blob_metadata.add(BlobMetaEntry::KmUuid(KEYSTORE_UUID));
3753 db.set_blob(
3754 &key_id,
3755 SubComponentType::KEY_BLOB,
3756 Some(TEST_KEY_BLOB),
3757 Some(&blob_metadata),
3758 )?;
3759 db.set_blob(&key_id, SubComponentType::CERT, Some(TEST_CERT_BLOB), None)?;
3760 db.set_blob(&key_id, SubComponentType::CERT_CHAIN, Some(TEST_CERT_CHAIN_BLOB), None)?;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003761 drop(key_id);
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003762
3763 let mut stmt = db.conn.prepare(
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003764 "SELECT subcomponent_type, keyentryid, blob, id FROM persistent.blobentry
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003765 ORDER BY subcomponent_type ASC;",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003766 )?;
3767 let mut rows = stmt
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003768 .query_map::<((SubComponentType, i64, Vec<u8>), i64), _, _>(NO_PARAMS, |row| {
3769 Ok(((row.get(0)?, row.get(1)?, row.get(2)?), row.get(3)?))
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003770 })?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003771 let (r, id) = rows.next().unwrap().unwrap();
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003772 assert_eq!(r, (SubComponentType::KEY_BLOB, 3000, TEST_KEY_BLOB.to_vec()));
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003773 let (r, _) = rows.next().unwrap().unwrap();
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003774 assert_eq!(r, (SubComponentType::CERT, 3000, TEST_CERT_BLOB.to_vec()));
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003775 let (r, _) = rows.next().unwrap().unwrap();
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003776 assert_eq!(r, (SubComponentType::CERT_CHAIN, 3000, TEST_CERT_CHAIN_BLOB.to_vec()));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003777
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003778 drop(rows);
3779 drop(stmt);
3780
3781 assert_eq!(
3782 db.with_transaction(TransactionBehavior::Immediate, |tx| {
3783 BlobMetaData::load_from_db(id, tx).no_gc()
3784 })
3785 .expect("Should find blob metadata."),
3786 blob_metadata
3787 );
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003788 Ok(())
3789 }
3790
3791 static TEST_ALIAS: &str = "my super duper key";
3792
3793 #[test]
3794 fn test_insert_and_load_full_keyentry_domain_app() -> Result<()> {
3795 let mut db = new_test_db()?;
Qi Wub9433b52020-12-01 14:52:46 +08003796 let key_id = make_test_key_entry(&mut db, Domain::APP, 1, TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08003797 .context("test_insert_and_load_full_keyentry_domain_app")?
3798 .0;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003799 let (_key_guard, key_entry) = db
3800 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003801 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003802 domain: Domain::APP,
3803 nspace: 0,
3804 alias: Some(TEST_ALIAS.to_string()),
3805 blob: None,
3806 },
3807 KeyType::Client,
3808 KeyEntryLoadBits::BOTH,
3809 1,
3810 |_k, _av| Ok(()),
3811 )
3812 .unwrap();
Qi Wub9433b52020-12-01 14:52:46 +08003813 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003814
3815 db.unbind_key(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003816 &KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003817 domain: Domain::APP,
3818 nspace: 0,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003819 alias: Some(TEST_ALIAS.to_string()),
3820 blob: None,
3821 },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003822 KeyType::Client,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003823 1,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003824 |_, _| Ok(()),
3825 )
3826 .unwrap();
3827
3828 assert_eq!(
3829 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
3830 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003831 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003832 domain: Domain::APP,
3833 nspace: 0,
3834 alias: Some(TEST_ALIAS.to_string()),
3835 blob: None,
3836 },
3837 KeyType::Client,
3838 KeyEntryLoadBits::NONE,
3839 1,
3840 |_k, _av| Ok(()),
3841 )
3842 .unwrap_err()
3843 .root_cause()
3844 .downcast_ref::<KsError>()
3845 );
3846
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003847 Ok(())
3848 }
3849
3850 #[test]
Janis Danisevskis377d1002021-01-27 19:07:48 -08003851 fn test_insert_and_load_certificate_entry_domain_app() -> Result<()> {
3852 let mut db = new_test_db()?;
3853
3854 db.store_new_certificate(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003855 &KeyDescriptor {
Janis Danisevskis377d1002021-01-27 19:07:48 -08003856 domain: Domain::APP,
3857 nspace: 1,
3858 alias: Some(TEST_ALIAS.to_string()),
3859 blob: None,
3860 },
3861 TEST_CERT_BLOB,
Max Bires8e93d2b2021-01-14 13:17:59 -08003862 &KEYSTORE_UUID,
Janis Danisevskis377d1002021-01-27 19:07:48 -08003863 )
3864 .expect("Trying to insert cert.");
3865
3866 let (_key_guard, mut key_entry) = db
3867 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003868 &KeyDescriptor {
Janis Danisevskis377d1002021-01-27 19:07:48 -08003869 domain: Domain::APP,
3870 nspace: 1,
3871 alias: Some(TEST_ALIAS.to_string()),
3872 blob: None,
3873 },
3874 KeyType::Client,
3875 KeyEntryLoadBits::PUBLIC,
3876 1,
3877 |_k, _av| Ok(()),
3878 )
3879 .expect("Trying to read certificate entry.");
3880
3881 assert!(key_entry.pure_cert());
3882 assert!(key_entry.cert().is_none());
3883 assert_eq!(key_entry.take_cert_chain(), Some(TEST_CERT_BLOB.to_vec()));
3884
3885 db.unbind_key(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003886 &KeyDescriptor {
Janis Danisevskis377d1002021-01-27 19:07:48 -08003887 domain: Domain::APP,
3888 nspace: 1,
3889 alias: Some(TEST_ALIAS.to_string()),
3890 blob: None,
3891 },
3892 KeyType::Client,
3893 1,
3894 |_, _| Ok(()),
3895 )
3896 .unwrap();
3897
3898 assert_eq!(
3899 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
3900 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003901 &KeyDescriptor {
Janis Danisevskis377d1002021-01-27 19:07:48 -08003902 domain: Domain::APP,
3903 nspace: 1,
3904 alias: Some(TEST_ALIAS.to_string()),
3905 blob: None,
3906 },
3907 KeyType::Client,
3908 KeyEntryLoadBits::NONE,
3909 1,
3910 |_k, _av| Ok(()),
3911 )
3912 .unwrap_err()
3913 .root_cause()
3914 .downcast_ref::<KsError>()
3915 );
3916
3917 Ok(())
3918 }
3919
3920 #[test]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003921 fn test_insert_and_load_full_keyentry_domain_selinux() -> Result<()> {
3922 let mut db = new_test_db()?;
Qi Wub9433b52020-12-01 14:52:46 +08003923 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08003924 .context("test_insert_and_load_full_keyentry_domain_selinux")?
3925 .0;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003926 let (_key_guard, key_entry) = db
3927 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003928 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003929 domain: Domain::SELINUX,
3930 nspace: 1,
3931 alias: Some(TEST_ALIAS.to_string()),
3932 blob: None,
3933 },
3934 KeyType::Client,
3935 KeyEntryLoadBits::BOTH,
3936 1,
3937 |_k, _av| Ok(()),
3938 )
3939 .unwrap();
Qi Wub9433b52020-12-01 14:52:46 +08003940 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003941
3942 db.unbind_key(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003943 &KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003944 domain: Domain::SELINUX,
3945 nspace: 1,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003946 alias: Some(TEST_ALIAS.to_string()),
3947 blob: None,
3948 },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003949 KeyType::Client,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003950 1,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003951 |_, _| Ok(()),
3952 )
3953 .unwrap();
3954
3955 assert_eq!(
3956 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
3957 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003958 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003959 domain: Domain::SELINUX,
3960 nspace: 1,
3961 alias: Some(TEST_ALIAS.to_string()),
3962 blob: None,
3963 },
3964 KeyType::Client,
3965 KeyEntryLoadBits::NONE,
3966 1,
3967 |_k, _av| Ok(()),
3968 )
3969 .unwrap_err()
3970 .root_cause()
3971 .downcast_ref::<KsError>()
3972 );
3973
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003974 Ok(())
3975 }
3976
3977 #[test]
3978 fn test_insert_and_load_full_keyentry_domain_key_id() -> Result<()> {
3979 let mut db = new_test_db()?;
Qi Wub9433b52020-12-01 14:52:46 +08003980 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08003981 .context("test_insert_and_load_full_keyentry_domain_key_id")?
3982 .0;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003983 let (_, key_entry) = db
3984 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003985 &KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003986 KeyType::Client,
3987 KeyEntryLoadBits::BOTH,
3988 1,
3989 |_k, _av| Ok(()),
3990 )
3991 .unwrap();
3992
Qi Wub9433b52020-12-01 14:52:46 +08003993 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003994
3995 db.unbind_key(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003996 &KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003997 KeyType::Client,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003998 1,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003999 |_, _| Ok(()),
4000 )
4001 .unwrap();
4002
4003 assert_eq!(
4004 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
4005 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004006 &KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004007 KeyType::Client,
4008 KeyEntryLoadBits::NONE,
4009 1,
4010 |_k, _av| Ok(()),
4011 )
4012 .unwrap_err()
4013 .root_cause()
4014 .downcast_ref::<KsError>()
4015 );
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004016
4017 Ok(())
4018 }
4019
4020 #[test]
Qi Wub9433b52020-12-01 14:52:46 +08004021 fn test_check_and_update_key_usage_count_with_limited_use_key() -> Result<()> {
4022 let mut db = new_test_db()?;
4023 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, Some(123))
4024 .context("test_check_and_update_key_usage_count_with_limited_use_key")?
4025 .0;
4026 // Update the usage count of the limited use key.
4027 db.check_and_update_key_usage_count(key_id)?;
4028
4029 let (_key_guard, key_entry) = db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004030 &KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
Qi Wub9433b52020-12-01 14:52:46 +08004031 KeyType::Client,
4032 KeyEntryLoadBits::BOTH,
4033 1,
4034 |_k, _av| Ok(()),
4035 )?;
4036
4037 // The usage count is decremented now.
4038 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, Some(122)));
4039
4040 Ok(())
4041 }
4042
4043 #[test]
4044 fn test_check_and_update_key_usage_count_with_exhausted_limited_use_key() -> Result<()> {
4045 let mut db = new_test_db()?;
4046 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, Some(1))
4047 .context("test_check_and_update_key_usage_count_with_exhausted_limited_use_key")?
4048 .0;
4049 // Update the usage count of the limited use key.
4050 db.check_and_update_key_usage_count(key_id).expect(concat!(
4051 "In test_check_and_update_key_usage_count_with_exhausted_limited_use_key: ",
4052 "This should succeed."
4053 ));
4054
4055 // Try to update the exhausted limited use key.
4056 let e = db.check_and_update_key_usage_count(key_id).expect_err(concat!(
4057 "In test_check_and_update_key_usage_count_with_exhausted_limited_use_key: ",
4058 "This should fail."
4059 ));
4060 assert_eq!(
4061 &KsError::Km(ErrorCode::INVALID_KEY_BLOB),
4062 e.root_cause().downcast_ref::<KsError>().unwrap()
4063 );
4064
4065 Ok(())
4066 }
4067
4068 #[test]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004069 fn test_insert_and_load_full_keyentry_from_grant() -> Result<()> {
4070 let mut db = new_test_db()?;
Qi Wub9433b52020-12-01 14:52:46 +08004071 let key_id = make_test_key_entry(&mut db, Domain::APP, 1, TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08004072 .context("test_insert_and_load_full_keyentry_from_grant")?
4073 .0;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004074
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004075 let granted_key = db
4076 .grant(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004077 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004078 domain: Domain::APP,
4079 nspace: 0,
4080 alias: Some(TEST_ALIAS.to_string()),
4081 blob: None,
4082 },
4083 1,
4084 2,
4085 key_perm_set![KeyPerm::use_()],
4086 |_k, _av| Ok(()),
4087 )
4088 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004089
4090 debug_dump_grant_table(&mut db)?;
4091
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004092 let (_key_guard, key_entry) = db
Janis Danisevskis66784c42021-01-27 08:40:25 -08004093 .load_key_entry(&granted_key, KeyType::Client, KeyEntryLoadBits::BOTH, 2, |k, av| {
4094 assert_eq!(Domain::GRANT, k.domain);
4095 assert!(av.unwrap().includes(KeyPerm::use_()));
4096 Ok(())
4097 })
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004098 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004099
Qi Wub9433b52020-12-01 14:52:46 +08004100 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004101
Janis Danisevskis66784c42021-01-27 08:40:25 -08004102 db.unbind_key(&granted_key, KeyType::Client, 2, |_, _| Ok(())).unwrap();
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004103
4104 assert_eq!(
4105 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
4106 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004107 &granted_key,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004108 KeyType::Client,
4109 KeyEntryLoadBits::NONE,
4110 2,
4111 |_k, _av| Ok(()),
4112 )
4113 .unwrap_err()
4114 .root_cause()
4115 .downcast_ref::<KsError>()
4116 );
4117
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004118 Ok(())
4119 }
4120
Janis Danisevskis45760022021-01-19 16:34:10 -08004121 // This test attempts to load a key by key id while the caller is not the owner
4122 // but a grant exists for the given key and the caller.
4123 #[test]
4124 fn test_insert_and_load_full_keyentry_from_grant_by_key_id() -> Result<()> {
4125 let mut db = new_test_db()?;
4126 const OWNER_UID: u32 = 1u32;
4127 const GRANTEE_UID: u32 = 2u32;
4128 const SOMEONE_ELSE_UID: u32 = 3u32;
4129 let key_id = make_test_key_entry(&mut db, Domain::APP, OWNER_UID as i64, TEST_ALIAS, None)
4130 .context("test_insert_and_load_full_keyentry_from_grant_by_key_id")?
4131 .0;
4132
4133 db.grant(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004134 &KeyDescriptor {
Janis Danisevskis45760022021-01-19 16:34:10 -08004135 domain: Domain::APP,
4136 nspace: 0,
4137 alias: Some(TEST_ALIAS.to_string()),
4138 blob: None,
4139 },
4140 OWNER_UID,
4141 GRANTEE_UID,
4142 key_perm_set![KeyPerm::use_()],
4143 |_k, _av| Ok(()),
4144 )
4145 .unwrap();
4146
4147 debug_dump_grant_table(&mut db)?;
4148
4149 let id_descriptor =
4150 KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, ..Default::default() };
4151
4152 let (_, key_entry) = db
4153 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004154 &id_descriptor,
Janis Danisevskis45760022021-01-19 16:34:10 -08004155 KeyType::Client,
4156 KeyEntryLoadBits::BOTH,
4157 GRANTEE_UID,
4158 |k, av| {
4159 assert_eq!(Domain::APP, k.domain);
4160 assert_eq!(OWNER_UID as i64, k.nspace);
4161 assert!(av.unwrap().includes(KeyPerm::use_()));
4162 Ok(())
4163 },
4164 )
4165 .unwrap();
4166
4167 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
4168
4169 let (_, key_entry) = db
4170 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004171 &id_descriptor,
Janis Danisevskis45760022021-01-19 16:34:10 -08004172 KeyType::Client,
4173 KeyEntryLoadBits::BOTH,
4174 SOMEONE_ELSE_UID,
4175 |k, av| {
4176 assert_eq!(Domain::APP, k.domain);
4177 assert_eq!(OWNER_UID as i64, k.nspace);
4178 assert!(av.is_none());
4179 Ok(())
4180 },
4181 )
4182 .unwrap();
4183
4184 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
4185
Janis Danisevskis66784c42021-01-27 08:40:25 -08004186 db.unbind_key(&id_descriptor, KeyType::Client, OWNER_UID, |_, _| Ok(())).unwrap();
Janis Danisevskis45760022021-01-19 16:34:10 -08004187
4188 assert_eq!(
4189 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
4190 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004191 &id_descriptor,
Janis Danisevskis45760022021-01-19 16:34:10 -08004192 KeyType::Client,
4193 KeyEntryLoadBits::NONE,
4194 GRANTEE_UID,
4195 |_k, _av| Ok(()),
4196 )
4197 .unwrap_err()
4198 .root_cause()
4199 .downcast_ref::<KsError>()
4200 );
4201
4202 Ok(())
4203 }
4204
Janis Danisevskisaec14592020-11-12 09:41:49 -08004205 static KEY_LOCK_TEST_ALIAS: &str = "my super duper locked key";
4206
Janis Danisevskisaec14592020-11-12 09:41:49 -08004207 #[test]
4208 fn test_insert_and_load_full_keyentry_domain_app_concurrently() -> Result<()> {
4209 let handle = {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08004210 let temp_dir = Arc::new(TempDir::new("id_lock_test")?);
4211 let temp_dir_clone = temp_dir.clone();
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004212 let mut db = KeystoreDB::new(temp_dir.path(), None)?;
Qi Wub9433b52020-12-01 14:52:46 +08004213 let key_id = make_test_key_entry(&mut db, Domain::APP, 33, KEY_LOCK_TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08004214 .context("test_insert_and_load_full_keyentry_domain_app")?
4215 .0;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004216 let (_key_guard, key_entry) = db
4217 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004218 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004219 domain: Domain::APP,
4220 nspace: 0,
4221 alias: Some(KEY_LOCK_TEST_ALIAS.to_string()),
4222 blob: None,
4223 },
4224 KeyType::Client,
4225 KeyEntryLoadBits::BOTH,
4226 33,
4227 |_k, _av| Ok(()),
4228 )
4229 .unwrap();
Qi Wub9433b52020-12-01 14:52:46 +08004230 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskisaec14592020-11-12 09:41:49 -08004231 let state = Arc::new(AtomicU8::new(1));
4232 let state2 = state.clone();
4233
4234 // Spawning a second thread that attempts to acquire the key id lock
4235 // for the same key as the primary thread. The primary thread then
4236 // waits, thereby forcing the secondary thread into the second stage
4237 // of acquiring the lock (see KEY ID LOCK 2/2 above).
4238 // The test succeeds if the secondary thread observes the transition
4239 // of `state` from 1 to 2, despite having a whole second to overtake
4240 // the primary thread.
4241 let handle = thread::spawn(move || {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08004242 let temp_dir = temp_dir_clone;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004243 let mut db = KeystoreDB::new(temp_dir.path(), None).unwrap();
Janis Danisevskisaec14592020-11-12 09:41:49 -08004244 assert!(db
4245 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004246 &KeyDescriptor {
Janis Danisevskisaec14592020-11-12 09:41:49 -08004247 domain: Domain::APP,
4248 nspace: 0,
4249 alias: Some(KEY_LOCK_TEST_ALIAS.to_string()),
4250 blob: None,
4251 },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004252 KeyType::Client,
Janis Danisevskisaec14592020-11-12 09:41:49 -08004253 KeyEntryLoadBits::BOTH,
4254 33,
4255 |_k, _av| Ok(()),
4256 )
4257 .is_ok());
4258 // We should only see a 2 here because we can only return
4259 // from load_key_entry when the `_key_guard` expires,
4260 // which happens at the end of the scope.
4261 assert_eq!(2, state2.load(Ordering::Relaxed));
4262 });
4263
4264 thread::sleep(std::time::Duration::from_millis(1000));
4265
4266 assert_eq!(Ok(1), state.compare_exchange(1, 2, Ordering::Relaxed, Ordering::Relaxed));
4267
4268 // Return the handle from this scope so we can join with the
4269 // secondary thread after the key id lock has expired.
4270 handle
4271 // This is where the `_key_guard` goes out of scope,
4272 // which is the reason for concurrent load_key_entry on the same key
4273 // to unblock.
4274 };
4275 // Join with the secondary thread and unwrap, to propagate failing asserts to the
4276 // main test thread. We will not see failing asserts in secondary threads otherwise.
4277 handle.join().unwrap();
4278 Ok(())
4279 }
4280
Janis Danisevskise92a5e62020-12-02 12:57:41 -08004281 #[test]
Janis Danisevskis66784c42021-01-27 08:40:25 -08004282 fn teset_database_busy_error_code() {
4283 let temp_dir =
4284 TempDir::new("test_database_busy_error_code_").expect("Failed to create temp dir.");
4285
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004286 let mut db1 = KeystoreDB::new(temp_dir.path(), None).expect("Failed to open database1.");
4287 let mut db2 = KeystoreDB::new(temp_dir.path(), None).expect("Failed to open database2.");
Janis Danisevskis66784c42021-01-27 08:40:25 -08004288
4289 let _tx1 = db1
4290 .conn
4291 .transaction_with_behavior(TransactionBehavior::Immediate)
4292 .expect("Failed to create first transaction.");
4293
4294 let error = db2
4295 .conn
4296 .transaction_with_behavior(TransactionBehavior::Immediate)
4297 .context("Transaction begin failed.")
4298 .expect_err("This should fail.");
4299 let root_cause = error.root_cause();
4300 if let Some(rusqlite::ffi::Error { code: rusqlite::ErrorCode::DatabaseBusy, .. }) =
4301 root_cause.downcast_ref::<rusqlite::ffi::Error>()
4302 {
4303 return;
4304 }
4305 panic!(
4306 "Unexpected error {:?} \n{:?} \n{:?}",
4307 error,
4308 root_cause,
4309 root_cause.downcast_ref::<rusqlite::ffi::Error>()
4310 )
4311 }
4312
4313 #[cfg(disabled)]
4314 #[test]
4315 fn test_large_number_of_concurrent_db_manipulations() -> Result<()> {
4316 let temp_dir = Arc::new(
4317 TempDir::new("test_large_number_of_concurrent_db_manipulations_")
4318 .expect("Failed to create temp dir."),
4319 );
4320
4321 let test_begin = Instant::now();
4322
4323 let mut db = KeystoreDB::new(temp_dir.path()).expect("Failed to open database.");
4324 const KEY_COUNT: u32 = 500u32;
4325 const OPEN_DB_COUNT: u32 = 50u32;
4326
4327 let mut actual_key_count = KEY_COUNT;
4328 // First insert KEY_COUNT keys.
4329 for count in 0..KEY_COUNT {
4330 if Instant::now().duration_since(test_begin) >= Duration::from_secs(15) {
4331 actual_key_count = count;
4332 break;
4333 }
4334 let alias = format!("test_alias_{}", count);
4335 make_test_key_entry(&mut db, Domain::APP, 1, &alias, None)
4336 .expect("Failed to make key entry.");
4337 }
4338
4339 // Insert more keys from a different thread and into a different namespace.
4340 let temp_dir1 = temp_dir.clone();
4341 let handle1 = thread::spawn(move || {
4342 let mut db = KeystoreDB::new(temp_dir1.path()).expect("Failed to open database.");
4343
4344 for count in 0..actual_key_count {
4345 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
4346 return;
4347 }
4348 let alias = format!("test_alias_{}", count);
4349 make_test_key_entry(&mut db, Domain::APP, 2, &alias, None)
4350 .expect("Failed to make key entry.");
4351 }
4352
4353 // then unbind them again.
4354 for count in 0..actual_key_count {
4355 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
4356 return;
4357 }
4358 let key = KeyDescriptor {
4359 domain: Domain::APP,
4360 nspace: -1,
4361 alias: Some(format!("test_alias_{}", count)),
4362 blob: None,
4363 };
4364 db.unbind_key(&key, KeyType::Client, 2, |_, _| Ok(())).expect("Unbind Failed.");
4365 }
4366 });
4367
4368 // And start unbinding the first set of keys.
4369 let temp_dir2 = temp_dir.clone();
4370 let handle2 = thread::spawn(move || {
4371 let mut db = KeystoreDB::new(temp_dir2.path()).expect("Failed to open database.");
4372
4373 for count in 0..actual_key_count {
4374 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
4375 return;
4376 }
4377 let key = KeyDescriptor {
4378 domain: Domain::APP,
4379 nspace: -1,
4380 alias: Some(format!("test_alias_{}", count)),
4381 blob: None,
4382 };
4383 db.unbind_key(&key, KeyType::Client, 1, |_, _| Ok(())).expect("Unbind Failed.");
4384 }
4385 });
4386
4387 let stop_deleting = Arc::new(AtomicU8::new(0));
4388 let stop_deleting2 = stop_deleting.clone();
4389
4390 // And delete anything that is unreferenced keys.
4391 let temp_dir3 = temp_dir.clone();
4392 let handle3 = thread::spawn(move || {
4393 let mut db = KeystoreDB::new(temp_dir3.path()).expect("Failed to open database.");
4394
4395 while stop_deleting2.load(Ordering::Relaxed) != 1 {
4396 while let Some((key_guard, _key)) =
4397 db.get_unreferenced_key().expect("Failed to get unreferenced Key.")
4398 {
4399 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
4400 return;
4401 }
4402 db.purge_key_entry(key_guard).expect("Failed to purge key.");
4403 }
4404 std::thread::sleep(std::time::Duration::from_millis(100));
4405 }
4406 });
4407
4408 // While a lot of inserting and deleting is going on we have to open database connections
4409 // successfully and use them.
4410 // This clone is not redundant, because temp_dir needs to be kept alive until db goes
4411 // out of scope.
4412 #[allow(clippy::redundant_clone)]
4413 let temp_dir4 = temp_dir.clone();
4414 let handle4 = thread::spawn(move || {
4415 for count in 0..OPEN_DB_COUNT {
4416 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
4417 return;
4418 }
4419 let mut db = KeystoreDB::new(temp_dir4.path()).expect("Failed to open database.");
4420
4421 let alias = format!("test_alias_{}", count);
4422 make_test_key_entry(&mut db, Domain::APP, 3, &alias, None)
4423 .expect("Failed to make key entry.");
4424 let key = KeyDescriptor {
4425 domain: Domain::APP,
4426 nspace: -1,
4427 alias: Some(alias),
4428 blob: None,
4429 };
4430 db.unbind_key(&key, KeyType::Client, 3, |_, _| Ok(())).expect("Unbind Failed.");
4431 }
4432 });
4433
4434 handle1.join().expect("Thread 1 panicked.");
4435 handle2.join().expect("Thread 2 panicked.");
4436 handle4.join().expect("Thread 4 panicked.");
4437
4438 stop_deleting.store(1, Ordering::Relaxed);
4439 handle3.join().expect("Thread 3 panicked.");
4440
4441 Ok(())
4442 }
4443
4444 #[test]
Janis Danisevskise92a5e62020-12-02 12:57:41 -08004445 fn list() -> Result<()> {
4446 let temp_dir = TempDir::new("list_test")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004447 let mut db = KeystoreDB::new(temp_dir.path(), None)?;
Janis Danisevskise92a5e62020-12-02 12:57:41 -08004448 static LIST_O_ENTRIES: &[(Domain, i64, &str)] = &[
4449 (Domain::APP, 1, "test1"),
4450 (Domain::APP, 1, "test2"),
4451 (Domain::APP, 1, "test3"),
4452 (Domain::APP, 1, "test4"),
4453 (Domain::APP, 1, "test5"),
4454 (Domain::APP, 1, "test6"),
4455 (Domain::APP, 1, "test7"),
4456 (Domain::APP, 2, "test1"),
4457 (Domain::APP, 2, "test2"),
4458 (Domain::APP, 2, "test3"),
4459 (Domain::APP, 2, "test4"),
4460 (Domain::APP, 2, "test5"),
4461 (Domain::APP, 2, "test6"),
4462 (Domain::APP, 2, "test8"),
4463 (Domain::SELINUX, 100, "test1"),
4464 (Domain::SELINUX, 100, "test2"),
4465 (Domain::SELINUX, 100, "test3"),
4466 (Domain::SELINUX, 100, "test4"),
4467 (Domain::SELINUX, 100, "test5"),
4468 (Domain::SELINUX, 100, "test6"),
4469 (Domain::SELINUX, 100, "test9"),
4470 ];
4471
4472 let list_o_keys: Vec<(i64, i64)> = LIST_O_ENTRIES
4473 .iter()
4474 .map(|(domain, ns, alias)| {
Qi Wub9433b52020-12-01 14:52:46 +08004475 let entry = make_test_key_entry(&mut db, *domain, *ns, *alias, None)
4476 .unwrap_or_else(|e| {
Janis Danisevskise92a5e62020-12-02 12:57:41 -08004477 panic!("Failed to insert {:?} {} {}. Error {:?}", domain, ns, alias, e)
4478 });
4479 (entry.id(), *ns)
4480 })
4481 .collect();
4482
4483 for (domain, namespace) in
4484 &[(Domain::APP, 1i64), (Domain::APP, 2i64), (Domain::SELINUX, 100i64)]
4485 {
4486 let mut list_o_descriptors: Vec<KeyDescriptor> = LIST_O_ENTRIES
4487 .iter()
4488 .filter_map(|(domain, ns, alias)| match ns {
4489 ns if *ns == *namespace => Some(KeyDescriptor {
4490 domain: *domain,
4491 nspace: *ns,
4492 alias: Some(alias.to_string()),
4493 blob: None,
4494 }),
4495 _ => None,
4496 })
4497 .collect();
4498 list_o_descriptors.sort();
4499 let mut list_result = db.list(*domain, *namespace)?;
4500 list_result.sort();
4501 assert_eq!(list_o_descriptors, list_result);
4502
4503 let mut list_o_ids: Vec<i64> = list_o_descriptors
4504 .into_iter()
4505 .map(|d| {
4506 let (_, entry) = db
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004507 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004508 &d,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004509 KeyType::Client,
4510 KeyEntryLoadBits::NONE,
4511 *namespace as u32,
4512 |_, _| Ok(()),
4513 )
Janis Danisevskise92a5e62020-12-02 12:57:41 -08004514 .unwrap();
4515 entry.id()
4516 })
4517 .collect();
4518 list_o_ids.sort_unstable();
4519 let mut loaded_entries: Vec<i64> = list_o_keys
4520 .iter()
4521 .filter_map(|(id, ns)| match ns {
4522 ns if *ns == *namespace => Some(*id),
4523 _ => None,
4524 })
4525 .collect();
4526 loaded_entries.sort_unstable();
4527 assert_eq!(list_o_ids, loaded_entries);
4528 }
4529 assert_eq!(Vec::<KeyDescriptor>::new(), db.list(Domain::SELINUX, 101)?);
4530
4531 Ok(())
4532 }
4533
Joel Galenson0891bc12020-07-20 10:37:03 -07004534 // Helpers
4535
4536 // Checks that the given result is an error containing the given string.
4537 fn check_result_is_error_containing_string<T>(result: Result<T>, target: &str) {
4538 let error_str = format!(
4539 "{:#?}",
4540 result.err().unwrap_or_else(|| panic!("Expected the error: {}", target))
4541 );
4542 assert!(
4543 error_str.contains(target),
4544 "The string \"{}\" should contain \"{}\"",
4545 error_str,
4546 target
4547 );
4548 }
4549
Joel Galenson2aab4432020-07-22 15:27:57 -07004550 #[derive(Debug, PartialEq)]
Joel Galenson0891bc12020-07-20 10:37:03 -07004551 struct KeyEntryRow {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004552 id: i64,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004553 key_type: KeyType,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07004554 domain: Option<Domain>,
Joel Galenson0891bc12020-07-20 10:37:03 -07004555 namespace: Option<i64>,
4556 alias: Option<String>,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004557 state: KeyLifeCycle,
Max Bires8e93d2b2021-01-14 13:17:59 -08004558 km_uuid: Option<Uuid>,
Joel Galenson0891bc12020-07-20 10:37:03 -07004559 }
4560
4561 fn get_keyentry(db: &KeystoreDB) -> Result<Vec<KeyEntryRow>> {
4562 db.conn
Joel Galenson2aab4432020-07-22 15:27:57 -07004563 .prepare("SELECT * FROM persistent.keyentry;")?
Joel Galenson0891bc12020-07-20 10:37:03 -07004564 .query_map(NO_PARAMS, |row| {
Joel Galenson0891bc12020-07-20 10:37:03 -07004565 Ok(KeyEntryRow {
4566 id: row.get(0)?,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004567 key_type: row.get(1)?,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07004568 domain: match row.get(2)? {
4569 Some(i) => Some(Domain(i)),
4570 None => None,
4571 },
Joel Galenson0891bc12020-07-20 10:37:03 -07004572 namespace: row.get(3)?,
4573 alias: row.get(4)?,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004574 state: row.get(5)?,
Max Bires8e93d2b2021-01-14 13:17:59 -08004575 km_uuid: row.get(6)?,
Joel Galenson0891bc12020-07-20 10:37:03 -07004576 })
4577 })?
4578 .map(|r| r.context("Could not read keyentry row."))
4579 .collect::<Result<Vec<_>>>()
4580 }
4581
Max Biresb2e1d032021-02-08 21:35:05 -08004582 struct RemoteProvValues {
4583 cert_chain: Vec<u8>,
4584 priv_key: Vec<u8>,
4585 batch_cert: Vec<u8>,
4586 }
4587
Max Bires2b2e6562020-09-22 11:22:36 -07004588 fn load_attestation_key_pool(
4589 db: &mut KeystoreDB,
4590 expiration_date: i64,
4591 namespace: i64,
4592 base_byte: u8,
Max Biresb2e1d032021-02-08 21:35:05 -08004593 ) -> Result<RemoteProvValues> {
Max Bires2b2e6562020-09-22 11:22:36 -07004594 let public_key: Vec<u8> = vec![base_byte, 0x02 * base_byte];
4595 let cert_chain: Vec<u8> = vec![0x03 * base_byte, 0x04 * base_byte];
4596 let priv_key: Vec<u8> = vec![0x05 * base_byte, 0x06 * base_byte];
4597 let raw_public_key: Vec<u8> = vec![0x0b * base_byte, 0x0c * base_byte];
Max Biresb2e1d032021-02-08 21:35:05 -08004598 let batch_cert: Vec<u8> = vec![base_byte * 0x0d, base_byte * 0x0e];
Max Bires2b2e6562020-09-22 11:22:36 -07004599 db.create_attestation_key_entry(&public_key, &raw_public_key, &priv_key, &KEYSTORE_UUID)?;
4600 db.store_signed_attestation_certificate_chain(
4601 &raw_public_key,
Max Biresb2e1d032021-02-08 21:35:05 -08004602 &batch_cert,
Max Bires2b2e6562020-09-22 11:22:36 -07004603 &cert_chain,
4604 expiration_date,
4605 &KEYSTORE_UUID,
4606 )?;
4607 db.assign_attestation_key(Domain::APP, namespace, &KEYSTORE_UUID)?;
Max Biresb2e1d032021-02-08 21:35:05 -08004608 Ok(RemoteProvValues { cert_chain, priv_key, batch_cert })
Max Bires2b2e6562020-09-22 11:22:36 -07004609 }
4610
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07004611 // Note: The parameters and SecurityLevel associations are nonsensical. This
4612 // collection is only used to check if the parameters are preserved as expected by the
4613 // database.
Qi Wub9433b52020-12-01 14:52:46 +08004614 fn make_test_params(max_usage_count: Option<i32>) -> Vec<KeyParameter> {
4615 let mut params = vec![
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07004616 KeyParameter::new(KeyParameterValue::Invalid, SecurityLevel::TRUSTED_ENVIRONMENT),
4617 KeyParameter::new(
4618 KeyParameterValue::KeyPurpose(KeyPurpose::SIGN),
4619 SecurityLevel::TRUSTED_ENVIRONMENT,
4620 ),
4621 KeyParameter::new(
4622 KeyParameterValue::KeyPurpose(KeyPurpose::DECRYPT),
4623 SecurityLevel::TRUSTED_ENVIRONMENT,
4624 ),
4625 KeyParameter::new(
4626 KeyParameterValue::Algorithm(Algorithm::RSA),
4627 SecurityLevel::TRUSTED_ENVIRONMENT,
4628 ),
4629 KeyParameter::new(KeyParameterValue::KeySize(1024), SecurityLevel::TRUSTED_ENVIRONMENT),
4630 KeyParameter::new(
4631 KeyParameterValue::BlockMode(BlockMode::ECB),
4632 SecurityLevel::TRUSTED_ENVIRONMENT,
4633 ),
4634 KeyParameter::new(
4635 KeyParameterValue::BlockMode(BlockMode::GCM),
4636 SecurityLevel::TRUSTED_ENVIRONMENT,
4637 ),
4638 KeyParameter::new(KeyParameterValue::Digest(Digest::NONE), SecurityLevel::STRONGBOX),
4639 KeyParameter::new(
4640 KeyParameterValue::Digest(Digest::MD5),
4641 SecurityLevel::TRUSTED_ENVIRONMENT,
4642 ),
4643 KeyParameter::new(
4644 KeyParameterValue::Digest(Digest::SHA_2_224),
4645 SecurityLevel::TRUSTED_ENVIRONMENT,
4646 ),
4647 KeyParameter::new(
4648 KeyParameterValue::Digest(Digest::SHA_2_256),
4649 SecurityLevel::STRONGBOX,
4650 ),
4651 KeyParameter::new(
4652 KeyParameterValue::PaddingMode(PaddingMode::NONE),
4653 SecurityLevel::TRUSTED_ENVIRONMENT,
4654 ),
4655 KeyParameter::new(
4656 KeyParameterValue::PaddingMode(PaddingMode::RSA_OAEP),
4657 SecurityLevel::TRUSTED_ENVIRONMENT,
4658 ),
4659 KeyParameter::new(
4660 KeyParameterValue::PaddingMode(PaddingMode::RSA_PSS),
4661 SecurityLevel::STRONGBOX,
4662 ),
4663 KeyParameter::new(
4664 KeyParameterValue::PaddingMode(PaddingMode::RSA_PKCS1_1_5_SIGN),
4665 SecurityLevel::TRUSTED_ENVIRONMENT,
4666 ),
4667 KeyParameter::new(KeyParameterValue::CallerNonce, SecurityLevel::TRUSTED_ENVIRONMENT),
4668 KeyParameter::new(KeyParameterValue::MinMacLength(256), SecurityLevel::STRONGBOX),
4669 KeyParameter::new(
4670 KeyParameterValue::EcCurve(EcCurve::P_224),
4671 SecurityLevel::TRUSTED_ENVIRONMENT,
4672 ),
4673 KeyParameter::new(KeyParameterValue::EcCurve(EcCurve::P_256), SecurityLevel::STRONGBOX),
4674 KeyParameter::new(
4675 KeyParameterValue::EcCurve(EcCurve::P_384),
4676 SecurityLevel::TRUSTED_ENVIRONMENT,
4677 ),
4678 KeyParameter::new(
4679 KeyParameterValue::EcCurve(EcCurve::P_521),
4680 SecurityLevel::TRUSTED_ENVIRONMENT,
4681 ),
4682 KeyParameter::new(
4683 KeyParameterValue::RSAPublicExponent(3),
4684 SecurityLevel::TRUSTED_ENVIRONMENT,
4685 ),
4686 KeyParameter::new(
4687 KeyParameterValue::IncludeUniqueID,
4688 SecurityLevel::TRUSTED_ENVIRONMENT,
4689 ),
4690 KeyParameter::new(KeyParameterValue::BootLoaderOnly, SecurityLevel::STRONGBOX),
4691 KeyParameter::new(KeyParameterValue::RollbackResistance, SecurityLevel::STRONGBOX),
4692 KeyParameter::new(
4693 KeyParameterValue::ActiveDateTime(1234567890),
4694 SecurityLevel::STRONGBOX,
4695 ),
4696 KeyParameter::new(
4697 KeyParameterValue::OriginationExpireDateTime(1234567890),
4698 SecurityLevel::TRUSTED_ENVIRONMENT,
4699 ),
4700 KeyParameter::new(
4701 KeyParameterValue::UsageExpireDateTime(1234567890),
4702 SecurityLevel::TRUSTED_ENVIRONMENT,
4703 ),
4704 KeyParameter::new(
4705 KeyParameterValue::MinSecondsBetweenOps(1234567890),
4706 SecurityLevel::TRUSTED_ENVIRONMENT,
4707 ),
4708 KeyParameter::new(
4709 KeyParameterValue::MaxUsesPerBoot(1234567890),
4710 SecurityLevel::TRUSTED_ENVIRONMENT,
4711 ),
4712 KeyParameter::new(KeyParameterValue::UserID(1), SecurityLevel::STRONGBOX),
4713 KeyParameter::new(KeyParameterValue::UserSecureID(42), SecurityLevel::STRONGBOX),
4714 KeyParameter::new(
4715 KeyParameterValue::NoAuthRequired,
4716 SecurityLevel::TRUSTED_ENVIRONMENT,
4717 ),
4718 KeyParameter::new(
4719 KeyParameterValue::HardwareAuthenticatorType(HardwareAuthenticatorType::PASSWORD),
4720 SecurityLevel::TRUSTED_ENVIRONMENT,
4721 ),
4722 KeyParameter::new(KeyParameterValue::AuthTimeout(1234567890), SecurityLevel::SOFTWARE),
4723 KeyParameter::new(KeyParameterValue::AllowWhileOnBody, SecurityLevel::SOFTWARE),
4724 KeyParameter::new(
4725 KeyParameterValue::TrustedUserPresenceRequired,
4726 SecurityLevel::TRUSTED_ENVIRONMENT,
4727 ),
4728 KeyParameter::new(
4729 KeyParameterValue::TrustedConfirmationRequired,
4730 SecurityLevel::TRUSTED_ENVIRONMENT,
4731 ),
4732 KeyParameter::new(
4733 KeyParameterValue::UnlockedDeviceRequired,
4734 SecurityLevel::TRUSTED_ENVIRONMENT,
4735 ),
4736 KeyParameter::new(
4737 KeyParameterValue::ApplicationID(vec![1u8, 2u8, 3u8, 4u8]),
4738 SecurityLevel::SOFTWARE,
4739 ),
4740 KeyParameter::new(
4741 KeyParameterValue::ApplicationData(vec![4u8, 3u8, 2u8, 1u8]),
4742 SecurityLevel::SOFTWARE,
4743 ),
4744 KeyParameter::new(
4745 KeyParameterValue::CreationDateTime(12345677890),
4746 SecurityLevel::SOFTWARE,
4747 ),
4748 KeyParameter::new(
4749 KeyParameterValue::KeyOrigin(KeyOrigin::GENERATED),
4750 SecurityLevel::TRUSTED_ENVIRONMENT,
4751 ),
4752 KeyParameter::new(
4753 KeyParameterValue::RootOfTrust(vec![3u8, 2u8, 1u8, 4u8]),
4754 SecurityLevel::TRUSTED_ENVIRONMENT,
4755 ),
4756 KeyParameter::new(KeyParameterValue::OSVersion(1), SecurityLevel::TRUSTED_ENVIRONMENT),
4757 KeyParameter::new(KeyParameterValue::OSPatchLevel(2), SecurityLevel::SOFTWARE),
4758 KeyParameter::new(
4759 KeyParameterValue::UniqueID(vec![4u8, 3u8, 1u8, 2u8]),
4760 SecurityLevel::SOFTWARE,
4761 ),
4762 KeyParameter::new(
4763 KeyParameterValue::AttestationChallenge(vec![4u8, 3u8, 1u8, 2u8]),
4764 SecurityLevel::TRUSTED_ENVIRONMENT,
4765 ),
4766 KeyParameter::new(
4767 KeyParameterValue::AttestationApplicationID(vec![4u8, 3u8, 1u8, 2u8]),
4768 SecurityLevel::TRUSTED_ENVIRONMENT,
4769 ),
4770 KeyParameter::new(
4771 KeyParameterValue::AttestationIdBrand(vec![4u8, 3u8, 1u8, 2u8]),
4772 SecurityLevel::TRUSTED_ENVIRONMENT,
4773 ),
4774 KeyParameter::new(
4775 KeyParameterValue::AttestationIdDevice(vec![4u8, 3u8, 1u8, 2u8]),
4776 SecurityLevel::TRUSTED_ENVIRONMENT,
4777 ),
4778 KeyParameter::new(
4779 KeyParameterValue::AttestationIdProduct(vec![4u8, 3u8, 1u8, 2u8]),
4780 SecurityLevel::TRUSTED_ENVIRONMENT,
4781 ),
4782 KeyParameter::new(
4783 KeyParameterValue::AttestationIdSerial(vec![4u8, 3u8, 1u8, 2u8]),
4784 SecurityLevel::TRUSTED_ENVIRONMENT,
4785 ),
4786 KeyParameter::new(
4787 KeyParameterValue::AttestationIdIMEI(vec![4u8, 3u8, 1u8, 2u8]),
4788 SecurityLevel::TRUSTED_ENVIRONMENT,
4789 ),
4790 KeyParameter::new(
4791 KeyParameterValue::AttestationIdMEID(vec![4u8, 3u8, 1u8, 2u8]),
4792 SecurityLevel::TRUSTED_ENVIRONMENT,
4793 ),
4794 KeyParameter::new(
4795 KeyParameterValue::AttestationIdManufacturer(vec![4u8, 3u8, 1u8, 2u8]),
4796 SecurityLevel::TRUSTED_ENVIRONMENT,
4797 ),
4798 KeyParameter::new(
4799 KeyParameterValue::AttestationIdModel(vec![4u8, 3u8, 1u8, 2u8]),
4800 SecurityLevel::TRUSTED_ENVIRONMENT,
4801 ),
4802 KeyParameter::new(
4803 KeyParameterValue::VendorPatchLevel(3),
4804 SecurityLevel::TRUSTED_ENVIRONMENT,
4805 ),
4806 KeyParameter::new(
4807 KeyParameterValue::BootPatchLevel(4),
4808 SecurityLevel::TRUSTED_ENVIRONMENT,
4809 ),
4810 KeyParameter::new(
4811 KeyParameterValue::AssociatedData(vec![4u8, 3u8, 1u8, 2u8]),
4812 SecurityLevel::TRUSTED_ENVIRONMENT,
4813 ),
4814 KeyParameter::new(
4815 KeyParameterValue::Nonce(vec![4u8, 3u8, 1u8, 2u8]),
4816 SecurityLevel::TRUSTED_ENVIRONMENT,
4817 ),
4818 KeyParameter::new(
4819 KeyParameterValue::MacLength(256),
4820 SecurityLevel::TRUSTED_ENVIRONMENT,
4821 ),
4822 KeyParameter::new(
4823 KeyParameterValue::ResetSinceIdRotation,
4824 SecurityLevel::TRUSTED_ENVIRONMENT,
4825 ),
4826 KeyParameter::new(
4827 KeyParameterValue::ConfirmationToken(vec![5u8, 5u8, 5u8, 5u8]),
4828 SecurityLevel::TRUSTED_ENVIRONMENT,
4829 ),
Qi Wub9433b52020-12-01 14:52:46 +08004830 ];
4831 if let Some(value) = max_usage_count {
4832 params.push(KeyParameter::new(
4833 KeyParameterValue::UsageCountLimit(value),
4834 SecurityLevel::SOFTWARE,
4835 ));
4836 }
4837 params
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07004838 }
4839
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004840 fn make_test_key_entry(
4841 db: &mut KeystoreDB,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07004842 domain: Domain,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004843 namespace: i64,
4844 alias: &str,
Qi Wub9433b52020-12-01 14:52:46 +08004845 max_usage_count: Option<i32>,
Janis Danisevskisaec14592020-11-12 09:41:49 -08004846 ) -> Result<KeyIdGuard> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08004847 let key_id = db.create_key_entry(&domain, &namespace, &KEYSTORE_UUID)?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004848 let mut blob_metadata = BlobMetaData::new();
4849 blob_metadata.add(BlobMetaEntry::EncryptedBy(EncryptedBy::Password));
4850 blob_metadata.add(BlobMetaEntry::Salt(vec![1, 2, 3]));
4851 blob_metadata.add(BlobMetaEntry::Iv(vec![2, 3, 1]));
4852 blob_metadata.add(BlobMetaEntry::AeadTag(vec![3, 1, 2]));
4853 blob_metadata.add(BlobMetaEntry::KmUuid(KEYSTORE_UUID));
4854
4855 db.set_blob(
4856 &key_id,
4857 SubComponentType::KEY_BLOB,
4858 Some(TEST_KEY_BLOB),
4859 Some(&blob_metadata),
4860 )?;
4861 db.set_blob(&key_id, SubComponentType::CERT, Some(TEST_CERT_BLOB), None)?;
4862 db.set_blob(&key_id, SubComponentType::CERT_CHAIN, Some(TEST_CERT_CHAIN_BLOB), None)?;
Qi Wub9433b52020-12-01 14:52:46 +08004863
4864 let params = make_test_params(max_usage_count);
4865 db.insert_keyparameter(&key_id, &params)?;
4866
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004867 let mut metadata = KeyMetaData::new();
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004868 metadata.add(KeyMetaEntry::CreationDate(DateTime::from_millis_epoch(123456789)));
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004869 db.insert_key_metadata(&key_id, &metadata)?;
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08004870 rebind_alias(db, &key_id, alias, domain, namespace)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004871 Ok(key_id)
4872 }
4873
Qi Wub9433b52020-12-01 14:52:46 +08004874 fn make_test_key_entry_test_vector(key_id: i64, max_usage_count: Option<i32>) -> KeyEntry {
4875 let params = make_test_params(max_usage_count);
4876
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004877 let mut blob_metadata = BlobMetaData::new();
4878 blob_metadata.add(BlobMetaEntry::EncryptedBy(EncryptedBy::Password));
4879 blob_metadata.add(BlobMetaEntry::Salt(vec![1, 2, 3]));
4880 blob_metadata.add(BlobMetaEntry::Iv(vec![2, 3, 1]));
4881 blob_metadata.add(BlobMetaEntry::AeadTag(vec![3, 1, 2]));
4882 blob_metadata.add(BlobMetaEntry::KmUuid(KEYSTORE_UUID));
4883
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004884 let mut metadata = KeyMetaData::new();
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004885 metadata.add(KeyMetaEntry::CreationDate(DateTime::from_millis_epoch(123456789)));
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004886
4887 KeyEntry {
4888 id: key_id,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004889 key_blob_info: Some((TEST_KEY_BLOB.to_vec(), blob_metadata)),
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004890 cert: Some(TEST_CERT_BLOB.to_vec()),
4891 cert_chain: Some(TEST_CERT_CHAIN_BLOB.to_vec()),
Max Bires8e93d2b2021-01-14 13:17:59 -08004892 km_uuid: KEYSTORE_UUID,
Qi Wub9433b52020-12-01 14:52:46 +08004893 parameters: params,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004894 metadata,
Janis Danisevskis377d1002021-01-27 19:07:48 -08004895 pure_cert: false,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004896 }
4897 }
4898
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004899 fn debug_dump_keyentry_table(db: &mut KeystoreDB) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004900 let mut stmt = db.conn.prepare(
Max Bires8e93d2b2021-01-14 13:17:59 -08004901 "SELECT id, key_type, domain, namespace, alias, state, km_uuid FROM persistent.keyentry;",
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004902 )?;
Max Bires8e93d2b2021-01-14 13:17:59 -08004903 let rows = stmt.query_map::<(i64, KeyType, i32, i64, String, KeyLifeCycle, Uuid), _, _>(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004904 NO_PARAMS,
4905 |row| {
Max Bires8e93d2b2021-01-14 13:17:59 -08004906 Ok((
4907 row.get(0)?,
4908 row.get(1)?,
4909 row.get(2)?,
4910 row.get(3)?,
4911 row.get(4)?,
4912 row.get(5)?,
4913 row.get(6)?,
4914 ))
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004915 },
4916 )?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004917
4918 println!("Key entry table rows:");
4919 for r in rows {
Max Bires8e93d2b2021-01-14 13:17:59 -08004920 let (id, key_type, domain, namespace, alias, state, km_uuid) = r.unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004921 println!(
Max Bires8e93d2b2021-01-14 13:17:59 -08004922 " id: {} KeyType: {:?} Domain: {} Namespace: {} Alias: {} State: {:?} KmUuid: {:?}",
4923 id, key_type, domain, namespace, alias, state, km_uuid
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004924 );
4925 }
4926 Ok(())
4927 }
4928
4929 fn debug_dump_grant_table(db: &mut KeystoreDB) -> Result<()> {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08004930 let mut stmt = db
4931 .conn
4932 .prepare("SELECT id, grantee, keyentryid, access_vector FROM persistent.grant;")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004933 let rows = stmt.query_map::<(i64, i64, i64, i64), _, _>(NO_PARAMS, |row| {
4934 Ok((row.get(0)?, row.get(1)?, row.get(2)?, row.get(3)?))
4935 })?;
4936
4937 println!("Grant table rows:");
4938 for r in rows {
4939 let (id, gt, ki, av) = r.unwrap();
4940 println!(" id: {} grantee: {} key_id: {} access_vector: {}", id, gt, ki, av);
4941 }
4942 Ok(())
4943 }
4944
Joel Galenson0891bc12020-07-20 10:37:03 -07004945 // Use a custom random number generator that repeats each number once.
4946 // This allows us to test repeated elements.
4947
4948 thread_local! {
4949 static RANDOM_COUNTER: RefCell<i64> = RefCell::new(0);
4950 }
4951
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004952 fn reset_random() {
4953 RANDOM_COUNTER.with(|counter| {
4954 *counter.borrow_mut() = 0;
4955 })
4956 }
4957
Joel Galenson0891bc12020-07-20 10:37:03 -07004958 pub fn random() -> i64 {
4959 RANDOM_COUNTER.with(|counter| {
4960 let result = *counter.borrow() / 2;
4961 *counter.borrow_mut() += 1;
4962 result
4963 })
4964 }
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00004965
4966 #[test]
4967 fn test_last_off_body() -> Result<()> {
4968 let mut db = new_test_db()?;
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08004969 db.insert_last_off_body(MonotonicRawTime::now())?;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00004970 let tx = db.conn.transaction_with_behavior(TransactionBehavior::Immediate)?;
4971 let last_off_body_1 = KeystoreDB::get_last_off_body(&tx)?;
4972 tx.commit()?;
4973 let one_second = Duration::from_secs(1);
4974 thread::sleep(one_second);
4975 db.update_last_off_body(MonotonicRawTime::now())?;
4976 let tx2 = db.conn.transaction_with_behavior(TransactionBehavior::Immediate)?;
4977 let last_off_body_2 = KeystoreDB::get_last_off_body(&tx2)?;
4978 tx2.commit()?;
4979 assert!(last_off_body_1.seconds() < last_off_body_2.seconds());
4980 Ok(())
4981 }
Hasini Gunasingheda895552021-01-27 19:34:37 +00004982
4983 #[test]
4984 fn test_unbind_keys_for_user() -> Result<()> {
4985 let mut db = new_test_db()?;
4986 db.unbind_keys_for_user(1, false)?;
4987
4988 make_test_key_entry(&mut db, Domain::APP, 210000, TEST_ALIAS, None)?;
4989 make_test_key_entry(&mut db, Domain::APP, 110000, TEST_ALIAS, None)?;
4990 db.unbind_keys_for_user(2, false)?;
4991
4992 assert_eq!(1, db.list(Domain::APP, 110000)?.len());
4993 assert_eq!(0, db.list(Domain::APP, 210000)?.len());
4994
4995 db.unbind_keys_for_user(1, true)?;
4996 assert_eq!(0, db.list(Domain::APP, 110000)?.len());
4997
4998 Ok(())
4999 }
5000
5001 #[test]
5002 fn test_store_super_key() -> Result<()> {
5003 let mut db = new_test_db()?;
Paul Crowleyf61fee72021-03-17 14:38:44 -07005004 let pw: keystore2_crypto::Password = (&b"xyzabc"[..]).into();
Hasini Gunasingheda895552021-01-27 19:34:37 +00005005 let super_key = keystore2_crypto::generate_aes256_key()?;
Paul Crowley7a658392021-03-18 17:08:20 -07005006 let secret_bytes = b"keystore2 is great.";
Hasini Gunasingheda895552021-01-27 19:34:37 +00005007 let (encrypted_secret, iv, tag) =
Paul Crowley7a658392021-03-18 17:08:20 -07005008 keystore2_crypto::aes_gcm_encrypt(secret_bytes, &super_key)?;
Hasini Gunasingheda895552021-01-27 19:34:37 +00005009
5010 let (encrypted_super_key, metadata) =
5011 SuperKeyManager::encrypt_with_password(&super_key, &pw)?;
Paul Crowley8d5b2532021-03-19 10:53:07 -07005012 db.store_super_key(
5013 1,
5014 &USER_SUPER_KEY,
5015 &encrypted_super_key,
5016 &metadata,
5017 &KeyMetaData::new(),
5018 )?;
Hasini Gunasingheda895552021-01-27 19:34:37 +00005019
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00005020 //check if super key exists
Paul Crowley7a658392021-03-18 17:08:20 -07005021 assert!(db.key_exists(Domain::APP, 1, &USER_SUPER_KEY.alias, KeyType::Super)?);
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00005022
Paul Crowley7a658392021-03-18 17:08:20 -07005023 let (_, key_entry) = db.load_super_key(&USER_SUPER_KEY, 1)?.unwrap();
Paul Crowley8d5b2532021-03-19 10:53:07 -07005024 let loaded_super_key = SuperKeyManager::extract_super_key_from_key_entry(
5025 USER_SUPER_KEY.algorithm,
5026 key_entry,
5027 &pw,
5028 None,
5029 )?;
Hasini Gunasingheda895552021-01-27 19:34:37 +00005030
Paul Crowley7a658392021-03-18 17:08:20 -07005031 let decrypted_secret_bytes =
5032 loaded_super_key.aes_gcm_decrypt(&encrypted_secret, &iv, &tag)?;
5033 assert_eq!(secret_bytes, &*decrypted_secret_bytes);
Hasini Gunasingheda895552021-01-27 19:34:37 +00005034 Ok(())
5035 }
Seth Moore78c091f2021-04-09 21:38:30 +00005036
5037 fn get_valid_statsd_storage_types() -> Vec<StatsdStorageType> {
5038 vec![
5039 StatsdStorageType::KeyEntry,
5040 StatsdStorageType::KeyEntryIdIndex,
5041 StatsdStorageType::KeyEntryDomainNamespaceIndex,
5042 StatsdStorageType::BlobEntry,
5043 StatsdStorageType::BlobEntryKeyEntryIdIndex,
5044 StatsdStorageType::KeyParameter,
5045 StatsdStorageType::KeyParameterKeyEntryIdIndex,
5046 StatsdStorageType::KeyMetadata,
5047 StatsdStorageType::KeyMetadataKeyEntryIdIndex,
5048 StatsdStorageType::Grant,
5049 StatsdStorageType::AuthToken,
5050 StatsdStorageType::BlobMetadata,
5051 StatsdStorageType::BlobMetadataBlobEntryIdIndex,
5052 ]
5053 }
5054
5055 /// Perform a simple check to ensure that we can query all the storage types
5056 /// that are supported by the DB. Check for reasonable values.
5057 #[test]
5058 fn test_query_all_valid_table_sizes() -> Result<()> {
5059 const PAGE_SIZE: i64 = 4096;
5060
5061 let mut db = new_test_db()?;
5062
5063 for t in get_valid_statsd_storage_types() {
5064 let stat = db.get_storage_stat(t)?;
5065 assert!(stat.size >= PAGE_SIZE);
5066 assert!(stat.size >= stat.unused_size);
5067 }
5068
5069 Ok(())
5070 }
5071
5072 fn get_storage_stats_map(db: &mut KeystoreDB) -> BTreeMap<i32, Keystore2StorageStats> {
5073 get_valid_statsd_storage_types()
5074 .into_iter()
5075 .map(|t| (t as i32, db.get_storage_stat(t).unwrap()))
5076 .collect()
5077 }
5078
5079 fn assert_storage_increased(
5080 db: &mut KeystoreDB,
5081 increased_storage_types: Vec<StatsdStorageType>,
5082 baseline: &mut BTreeMap<i32, Keystore2StorageStats>,
5083 ) {
5084 for storage in increased_storage_types {
5085 // Verify the expected storage increased.
5086 let new = db.get_storage_stat(storage).unwrap();
5087 let storage = storage as i32;
5088 let old = &baseline[&storage];
5089 assert!(new.size >= old.size, "{}: {} >= {}", storage, new.size, old.size);
5090 assert!(
5091 new.unused_size <= old.unused_size,
5092 "{}: {} <= {}",
5093 storage,
5094 new.unused_size,
5095 old.unused_size
5096 );
5097
5098 // Update the baseline with the new value so that it succeeds in the
5099 // later comparison.
5100 baseline.insert(storage, new);
5101 }
5102
5103 // Get an updated map of the storage and verify there were no unexpected changes.
5104 let updated_stats = get_storage_stats_map(db);
5105 assert_eq!(updated_stats.len(), baseline.len());
5106
5107 for &k in baseline.keys() {
5108 let stringify = |map: &BTreeMap<i32, Keystore2StorageStats>| -> String {
5109 let mut s = String::new();
5110 for &k in map.keys() {
5111 writeln!(&mut s, " {}: {}, {}", &k, map[&k].size, map[&k].unused_size)
5112 .expect("string concat failed");
5113 }
5114 s
5115 };
5116
5117 assert!(
5118 updated_stats[&k].size == baseline[&k].size
5119 && updated_stats[&k].unused_size == baseline[&k].unused_size,
5120 "updated_stats:\n{}\nbaseline:\n{}",
5121 stringify(&updated_stats),
5122 stringify(&baseline)
5123 );
5124 }
5125 }
5126
5127 #[test]
5128 fn test_verify_key_table_size_reporting() -> Result<()> {
5129 let mut db = new_test_db()?;
5130 let mut working_stats = get_storage_stats_map(&mut db);
5131
5132 let key_id = db.create_key_entry(&Domain::APP, &42, &KEYSTORE_UUID)?;
5133 assert_storage_increased(
5134 &mut db,
5135 vec![
5136 StatsdStorageType::KeyEntry,
5137 StatsdStorageType::KeyEntryIdIndex,
5138 StatsdStorageType::KeyEntryDomainNamespaceIndex,
5139 ],
5140 &mut working_stats,
5141 );
5142
5143 let mut blob_metadata = BlobMetaData::new();
5144 blob_metadata.add(BlobMetaEntry::EncryptedBy(EncryptedBy::Password));
5145 db.set_blob(&key_id, SubComponentType::KEY_BLOB, Some(TEST_KEY_BLOB), None)?;
5146 assert_storage_increased(
5147 &mut db,
5148 vec![
5149 StatsdStorageType::BlobEntry,
5150 StatsdStorageType::BlobEntryKeyEntryIdIndex,
5151 StatsdStorageType::BlobMetadata,
5152 StatsdStorageType::BlobMetadataBlobEntryIdIndex,
5153 ],
5154 &mut working_stats,
5155 );
5156
5157 let params = make_test_params(None);
5158 db.insert_keyparameter(&key_id, &params)?;
5159 assert_storage_increased(
5160 &mut db,
5161 vec![StatsdStorageType::KeyParameter, StatsdStorageType::KeyParameterKeyEntryIdIndex],
5162 &mut working_stats,
5163 );
5164
5165 let mut metadata = KeyMetaData::new();
5166 metadata.add(KeyMetaEntry::CreationDate(DateTime::from_millis_epoch(123456789)));
5167 db.insert_key_metadata(&key_id, &metadata)?;
5168 assert_storage_increased(
5169 &mut db,
5170 vec![StatsdStorageType::KeyMetadata, StatsdStorageType::KeyMetadataKeyEntryIdIndex],
5171 &mut working_stats,
5172 );
5173
5174 let mut sum = 0;
5175 for stat in working_stats.values() {
5176 sum += stat.size;
5177 }
5178 let total = db.get_storage_stat(StatsdStorageType::Database)?.size;
5179 assert!(sum <= total, "Expected sum <= total. sum: {}, total: {}", sum, total);
5180
5181 Ok(())
5182 }
5183
5184 #[test]
5185 fn test_verify_auth_table_size_reporting() -> Result<()> {
5186 let mut db = new_test_db()?;
5187 let mut working_stats = get_storage_stats_map(&mut db);
5188 db.insert_auth_token(&HardwareAuthToken {
5189 challenge: 123,
5190 userId: 456,
5191 authenticatorId: 789,
5192 authenticatorType: kmhw_authenticator_type::ANY,
5193 timestamp: Timestamp { milliSeconds: 10 },
5194 mac: b"mac".to_vec(),
5195 })?;
5196 assert_storage_increased(&mut db, vec![StatsdStorageType::AuthToken], &mut working_stats);
5197 Ok(())
5198 }
5199
5200 #[test]
5201 fn test_verify_grant_table_size_reporting() -> Result<()> {
5202 const OWNER: i64 = 1;
5203 let mut db = new_test_db()?;
5204 make_test_key_entry(&mut db, Domain::APP, OWNER, TEST_ALIAS, None)?;
5205
5206 let mut working_stats = get_storage_stats_map(&mut db);
5207 db.grant(
5208 &KeyDescriptor {
5209 domain: Domain::APP,
5210 nspace: 0,
5211 alias: Some(TEST_ALIAS.to_string()),
5212 blob: None,
5213 },
5214 OWNER as u32,
5215 123,
5216 key_perm_set![KeyPerm::use_()],
5217 |_, _| Ok(()),
5218 )?;
5219
5220 assert_storage_increased(&mut db, vec![StatsdStorageType::Grant], &mut working_stats);
5221
5222 Ok(())
5223 }
Joel Galenson26f4d012020-07-17 14:57:21 -07005224}