blob: d18223e5129bd880a58269bcf6cf1136fe4ca4eb [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
Matthew Maurerd7815ca2021-05-06 21:58:45 -070044mod perboot;
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 Gunasinghe66a24602021-05-12 19:03:12 +000049use crate::utils::{get_current_time_in_milliseconds, watchdog as wd, 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};
Janis Danisevskisc5b210b2020-09-11 13:27:37 -070066use android_system_keystore2::aidl::android::system::keystore2::{
Janis Danisevskis04b02832020-10-26 09:21:40 -070067 Domain::Domain, KeyDescriptor::KeyDescriptor,
Janis Danisevskis60400fe2020-08-26 15:24:42 -070068};
Max Bires2b2e6562020-09-22 11:22:36 -070069use android_security_remoteprovisioning::aidl::android::security::remoteprovisioning::{
70 AttestationPoolStatus::AttestationPoolStatus,
71};
Seth Moore78c091f2021-04-09 21:38:30 +000072use statslog_rust::keystore2_storage_stats::{
73 Keystore2StorageStats, StorageType as StatsdStorageType,
74};
Max Bires2b2e6562020-09-22 11:22:36 -070075
76use keystore2_crypto::ZVec;
Janis Danisevskisaec14592020-11-12 09:41:49 -080077use lazy_static::lazy_static;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +000078use log::error;
Joel Galenson0891bc12020-07-20 10:37:03 -070079#[cfg(not(test))]
80use rand::prelude::random;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -070081use rusqlite::{
Janis Danisevskisb42fc182020-12-15 08:41:27 -080082 params,
83 types::FromSql,
84 types::FromSqlResult,
85 types::ToSqlOutput,
86 types::{FromSqlError, Value, ValueRef},
Janis Danisevskis5ed8c532021-01-11 14:19:42 -080087 Connection, OptionalExtension, ToSql, Transaction, TransactionBehavior, NO_PARAMS,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -070088};
Max Bires2b2e6562020-09-22 11:22:36 -070089
Janis Danisevskisaec14592020-11-12 09:41:49 -080090use std::{
Janis Danisevskisb42fc182020-12-15 08:41:27 -080091 collections::{HashMap, HashSet},
Janis Danisevskisbf15d732020-12-08 10:35:26 -080092 path::Path,
Janis Danisevskis3395f862021-05-06 10:54:17 -070093 sync::{Arc, Condvar, Mutex},
Janis Danisevskisb42fc182020-12-15 08:41:27 -080094 time::{Duration, SystemTime},
Janis Danisevskisaec14592020-11-12 09:41:49 -080095};
Max Bires2b2e6562020-09-22 11:22:36 -070096
Joel Galenson0891bc12020-07-20 10:37:03 -070097#[cfg(test)]
98use tests::random;
Joel Galenson26f4d012020-07-17 14:57:21 -070099
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800100impl_metadata!(
101 /// A set of metadata for key entries.
102 #[derive(Debug, Default, Eq, PartialEq)]
103 pub struct KeyMetaData;
104 /// A metadata entry for key entries.
105 #[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
106 pub enum KeyMetaEntry {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800107 /// Date of the creation of the key entry.
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800108 CreationDate(DateTime) with accessor creation_date,
109 /// Expiration date for attestation keys.
110 AttestationExpirationDate(DateTime) with accessor attestation_expiration_date,
Max Bires2b2e6562020-09-22 11:22:36 -0700111 /// CBOR Blob that represents a COSE_Key and associated metadata needed for remote
112 /// provisioning
113 AttestationMacedPublicKey(Vec<u8>) with accessor attestation_maced_public_key,
114 /// Vector representing the raw public key so results from the server can be matched
115 /// to the right entry
116 AttestationRawPubKey(Vec<u8>) with accessor attestation_raw_pub_key,
Paul Crowley8d5b2532021-03-19 10:53:07 -0700117 /// SEC1 public key for ECDH encryption
118 Sec1PublicKey(Vec<u8>) with accessor sec1_public_key,
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800119 // --- ADD NEW META DATA FIELDS HERE ---
120 // For backwards compatibility add new entries only to
121 // end of this list and above this comment.
122 };
123);
124
125impl KeyMetaData {
126 fn load_from_db(key_id: i64, tx: &Transaction) -> Result<Self> {
127 let mut stmt = tx
128 .prepare(
129 "SELECT tag, data from persistent.keymetadata
130 WHERE keyentryid = ?;",
131 )
132 .context("In KeyMetaData::load_from_db: prepare statement failed.")?;
133
134 let mut metadata: HashMap<i64, KeyMetaEntry> = Default::default();
135
136 let mut rows =
137 stmt.query(params![key_id]).context("In KeyMetaData::load_from_db: query failed.")?;
138 db_utils::with_rows_extract_all(&mut rows, |row| {
139 let db_tag: i64 = row.get(0).context("Failed to read tag.")?;
140 metadata.insert(
141 db_tag,
142 KeyMetaEntry::new_from_sql(db_tag, &SqlField::new(1, &row))
143 .context("Failed to read KeyMetaEntry.")?,
144 );
145 Ok(())
146 })
147 .context("In KeyMetaData::load_from_db.")?;
148
149 Ok(Self { data: metadata })
150 }
151
152 fn store_in_db(&self, key_id: i64, tx: &Transaction) -> Result<()> {
153 let mut stmt = tx
154 .prepare(
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000155 "INSERT or REPLACE INTO persistent.keymetadata (keyentryid, tag, data)
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800156 VALUES (?, ?, ?);",
157 )
158 .context("In KeyMetaData::store_in_db: Failed to prepare statement.")?;
159
160 let iter = self.data.iter();
161 for (tag, entry) in iter {
162 stmt.insert(params![key_id, tag, entry,]).with_context(|| {
163 format!("In KeyMetaData::store_in_db: Failed to insert {:?}", entry)
164 })?;
165 }
166 Ok(())
167 }
168}
169
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800170impl_metadata!(
171 /// A set of metadata for key blobs.
172 #[derive(Debug, Default, Eq, PartialEq)]
173 pub struct BlobMetaData;
174 /// A metadata entry for key blobs.
175 #[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
176 pub enum BlobMetaEntry {
177 /// If present, indicates that the blob is encrypted with another key or a key derived
178 /// from a password.
179 EncryptedBy(EncryptedBy) with accessor encrypted_by,
180 /// If the blob is password encrypted this field is set to the
181 /// salt used for the key derivation.
182 Salt(Vec<u8>) with accessor salt,
183 /// If the blob is encrypted, this field is set to the initialization vector.
184 Iv(Vec<u8>) with accessor iv,
185 /// If the blob is encrypted, this field holds the AEAD TAG.
186 AeadTag(Vec<u8>) with accessor aead_tag,
187 /// The uuid of the owning KeyMint instance.
188 KmUuid(Uuid) with accessor km_uuid,
Paul Crowley8d5b2532021-03-19 10:53:07 -0700189 /// If the key is ECDH encrypted, this is the ephemeral public key
190 PublicKey(Vec<u8>) with accessor public_key,
Paul Crowley44c02da2021-04-08 17:04:43 +0000191 /// If the key is encrypted with a MaxBootLevel key, this is the boot level
192 /// of that key
193 MaxBootLevel(i32) with accessor max_boot_level,
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 Danisevskis3395f862021-05-06 10:54:17 -0700735 gc: Option<Arc<Gc>>,
Matthew Maurerd7815ca2021-05-06 21:58:45 -0700736 perboot: Arc<perboot::PerbootDB>,
Joel Galenson26f4d012020-07-17 14:57:21 -0700737}
738
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000739/// Database representation of the monotonic time retrieved from the system call clock_gettime with
Hasini Gunasinghe66a24602021-05-12 19:03:12 +0000740/// CLOCK_MONOTONIC_RAW. Stores monotonic time as i64 in milliseconds.
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000741#[derive(Debug, Copy, Clone, Default, Eq, PartialEq, Ord, PartialOrd)]
742pub struct MonotonicRawTime(i64);
743
744impl MonotonicRawTime {
745 /// Constructs a new MonotonicRawTime
746 pub fn now() -> Self {
Hasini Gunasinghe66a24602021-05-12 19:03:12 +0000747 Self(get_current_time_in_milliseconds())
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000748 }
749
Hasini Gunasinghe66a24602021-05-12 19:03:12 +0000750 /// Returns the value of MonotonicRawTime in milliseconds as i64
751 pub fn milliseconds(&self) -> i64 {
752 self.0
David Drysdale0e45a612021-02-25 17:24:36 +0000753 }
754
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000755 /// Returns the integer value of MonotonicRawTime as i64
756 pub fn seconds(&self) -> i64 {
Hasini Gunasinghe66a24602021-05-12 19:03:12 +0000757 self.0 / 1000
Hasini Gunasingheb3715fb2021-02-26 20:34:45 +0000758 }
759
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800760 /// Like i64::checked_sub.
761 pub fn checked_sub(&self, other: &Self) -> Option<Self> {
762 self.0.checked_sub(other.0).map(Self)
763 }
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000764}
765
766impl ToSql for MonotonicRawTime {
767 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
768 Ok(ToSqlOutput::Owned(Value::Integer(self.0)))
769 }
770}
771
772impl FromSql for MonotonicRawTime {
773 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
774 Ok(Self(i64::column_result(value)?))
775 }
776}
777
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000778/// This struct encapsulates the information to be stored in the database about the auth tokens
779/// received by keystore.
Matthew Maurerd7815ca2021-05-06 21:58:45 -0700780#[derive(Clone)]
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000781pub struct AuthTokenEntry {
782 auth_token: HardwareAuthToken,
Hasini Gunasinghe66a24602021-05-12 19:03:12 +0000783 // Time received in milliseconds
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000784 time_received: MonotonicRawTime,
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000785}
786
787impl AuthTokenEntry {
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000788 fn new(auth_token: HardwareAuthToken, time_received: MonotonicRawTime) -> Self {
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000789 AuthTokenEntry { auth_token, time_received }
790 }
791
792 /// Checks if this auth token satisfies the given authentication information.
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800793 pub fn satisfies(&self, user_secure_ids: &[i64], auth_type: HardwareAuthenticatorType) -> bool {
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000794 user_secure_ids.iter().any(|&sid| {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800795 (sid == self.auth_token.userId || sid == self.auth_token.authenticatorId)
796 && (((auth_type.0 as i32) & (self.auth_token.authenticatorType.0 as i32)) != 0)
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000797 })
798 }
799
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000800 /// Returns the auth token wrapped by the AuthTokenEntry
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800801 pub fn auth_token(&self) -> &HardwareAuthToken {
802 &self.auth_token
803 }
804
805 /// Returns the auth token wrapped by the AuthTokenEntry
806 pub fn take_auth_token(self) -> HardwareAuthToken {
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000807 self.auth_token
808 }
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800809
810 /// Returns the time that this auth token was received.
811 pub fn time_received(&self) -> MonotonicRawTime {
812 self.time_received
813 }
Hasini Gunasingheb3715fb2021-02-26 20:34:45 +0000814
815 /// Returns the challenge value of the auth token.
816 pub fn challenge(&self) -> i64 {
817 self.auth_token.challenge
818 }
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000819}
820
Janis Danisevskisb00ebd02021-02-02 21:52:24 -0800821/// Shared in-memory databases get destroyed as soon as the last connection to them gets closed.
822/// This object does not allow access to the database connection. But it keeps a database
823/// connection alive in order to keep the in memory per boot database alive.
824pub struct PerBootDbKeepAlive(Connection);
825
Joel Galenson26f4d012020-07-17 14:57:21 -0700826impl KeystoreDB {
Janis Danisevskiseed69842021-02-18 20:04:10 -0800827 const UNASSIGNED_KEY_ID: i64 = -1i64;
Janis Danisevskisb00ebd02021-02-02 21:52:24 -0800828
Seth Moore78c091f2021-04-09 21:38:30 +0000829 /// Name of the file that holds the cross-boot persistent database.
830 pub const PERSISTENT_DB_FILENAME: &'static str = &"persistent.sqlite";
831
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700832 /// This will create a new database connection connecting the two
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800833 /// files persistent.sqlite and perboot.sqlite in the given directory.
834 /// It also attempts to initialize all of the tables.
835 /// KeystoreDB cannot be used by multiple threads.
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700836 /// Each thread should open their own connection using `thread_local!`.
Janis Danisevskis3395f862021-05-06 10:54:17 -0700837 pub fn new(db_root: &Path, gc: Option<Arc<Gc>>) -> Result<Self> {
Janis Danisevskis850d4862021-05-05 08:41:14 -0700838 let _wp = wd::watch_millis("KeystoreDB::new", 500);
839
Janis Danisevskisb00ebd02021-02-02 21:52:24 -0800840 // Build the path to the sqlite file.
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800841 let mut persistent_path = db_root.to_path_buf();
Seth Moore78c091f2021-04-09 21:38:30 +0000842 persistent_path.push(Self::PERSISTENT_DB_FILENAME);
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700843
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800844 // Now convert them to strings prefixed with "file:"
845 let mut persistent_path_str = "file:".to_owned();
846 persistent_path_str.push_str(&persistent_path.to_string_lossy());
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800847
Matthew Maurerd7815ca2021-05-06 21:58:45 -0700848 let conn = Self::make_connection(&persistent_path_str)?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800849
Janis Danisevskis66784c42021-01-27 08:40:25 -0800850 // On busy fail Immediately. It is unlikely to succeed given a bug in sqlite.
851 conn.busy_handler(None).context("In KeystoreDB::new: Failed to set busy handler.")?;
852
Matthew Maurerd7815ca2021-05-06 21:58:45 -0700853 let mut db = Self { conn, gc, perboot: perboot::PERBOOT_DB.clone() };
Janis Danisevskis66784c42021-01-27 08:40:25 -0800854 db.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800855 Self::init_tables(tx).context("Trying to initialize tables.").no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -0800856 })?;
857 Ok(db)
Joel Galenson2aab4432020-07-22 15:27:57 -0700858 }
859
Janis Danisevskis66784c42021-01-27 08:40:25 -0800860 fn init_tables(tx: &Transaction) -> Result<()> {
861 tx.execute(
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700862 "CREATE TABLE IF NOT EXISTS persistent.keyentry (
Joel Galenson0891bc12020-07-20 10:37:03 -0700863 id INTEGER UNIQUE,
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800864 key_type INTEGER,
Joel Galenson0891bc12020-07-20 10:37:03 -0700865 domain INTEGER,
866 namespace INTEGER,
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800867 alias BLOB,
Max Bires8e93d2b2021-01-14 13:17:59 -0800868 state INTEGER,
869 km_uuid BLOB);",
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700870 NO_PARAMS,
871 )
872 .context("Failed to initialize \"keyentry\" table.")?;
873
Janis Danisevskis66784c42021-01-27 08:40:25 -0800874 tx.execute(
Janis Danisevskisa5438182021-02-02 14:22:59 -0800875 "CREATE INDEX IF NOT EXISTS persistent.keyentry_id_index
876 ON keyentry(id);",
877 NO_PARAMS,
878 )
879 .context("Failed to create index keyentry_id_index.")?;
880
881 tx.execute(
882 "CREATE INDEX IF NOT EXISTS persistent.keyentry_domain_namespace_index
883 ON keyentry(domain, namespace, alias);",
884 NO_PARAMS,
885 )
886 .context("Failed to create index keyentry_domain_namespace_index.")?;
887
888 tx.execute(
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700889 "CREATE TABLE IF NOT EXISTS persistent.blobentry (
890 id INTEGER PRIMARY KEY,
891 subcomponent_type INTEGER,
892 keyentryid INTEGER,
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800893 blob BLOB);",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700894 NO_PARAMS,
895 )
896 .context("Failed to initialize \"blobentry\" table.")?;
897
Janis Danisevskis66784c42021-01-27 08:40:25 -0800898 tx.execute(
Janis Danisevskisa5438182021-02-02 14:22:59 -0800899 "CREATE INDEX IF NOT EXISTS persistent.blobentry_keyentryid_index
900 ON blobentry(keyentryid);",
901 NO_PARAMS,
902 )
903 .context("Failed to create index blobentry_keyentryid_index.")?;
904
905 tx.execute(
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800906 "CREATE TABLE IF NOT EXISTS persistent.blobmetadata (
907 id INTEGER PRIMARY KEY,
908 blobentryid INTEGER,
909 tag INTEGER,
910 data ANY,
911 UNIQUE (blobentryid, tag));",
912 NO_PARAMS,
913 )
914 .context("Failed to initialize \"blobmetadata\" table.")?;
915
916 tx.execute(
917 "CREATE INDEX IF NOT EXISTS persistent.blobmetadata_blobentryid_index
918 ON blobmetadata(blobentryid);",
919 NO_PARAMS,
920 )
921 .context("Failed to create index blobmetadata_blobentryid_index.")?;
922
923 tx.execute(
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700924 "CREATE TABLE IF NOT EXISTS persistent.keyparameter (
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000925 keyentryid INTEGER,
926 tag INTEGER,
927 data ANY,
928 security_level INTEGER);",
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700929 NO_PARAMS,
930 )
931 .context("Failed to initialize \"keyparameter\" table.")?;
932
Janis Danisevskis66784c42021-01-27 08:40:25 -0800933 tx.execute(
Janis Danisevskisa5438182021-02-02 14:22:59 -0800934 "CREATE INDEX IF NOT EXISTS persistent.keyparameter_keyentryid_index
935 ON keyparameter(keyentryid);",
936 NO_PARAMS,
937 )
938 .context("Failed to create index keyparameter_keyentryid_index.")?;
939
940 tx.execute(
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800941 "CREATE TABLE IF NOT EXISTS persistent.keymetadata (
942 keyentryid INTEGER,
943 tag INTEGER,
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000944 data ANY,
945 UNIQUE (keyentryid, tag));",
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800946 NO_PARAMS,
947 )
948 .context("Failed to initialize \"keymetadata\" table.")?;
949
Janis Danisevskis66784c42021-01-27 08:40:25 -0800950 tx.execute(
Janis Danisevskisa5438182021-02-02 14:22:59 -0800951 "CREATE INDEX IF NOT EXISTS persistent.keymetadata_keyentryid_index
952 ON keymetadata(keyentryid);",
953 NO_PARAMS,
954 )
955 .context("Failed to create index keymetadata_keyentryid_index.")?;
956
957 tx.execute(
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800958 "CREATE TABLE IF NOT EXISTS persistent.grant (
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700959 id INTEGER UNIQUE,
960 grantee INTEGER,
961 keyentryid INTEGER,
962 access_vector INTEGER);",
963 NO_PARAMS,
964 )
965 .context("Failed to initialize \"grant\" table.")?;
966
Joel Galenson0891bc12020-07-20 10:37:03 -0700967 Ok(())
968 }
969
Matthew Maurerd7815ca2021-05-06 21:58:45 -0700970 fn make_connection(persistent_file: &str) -> Result<Connection> {
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700971 let conn =
972 Connection::open_in_memory().context("Failed to initialize SQLite connection.")?;
973
Janis Danisevskis66784c42021-01-27 08:40:25 -0800974 loop {
975 if let Err(e) = conn
976 .execute("ATTACH DATABASE ? as persistent;", params![persistent_file])
977 .context("Failed to attach database persistent.")
978 {
979 if Self::is_locked_error(&e) {
980 std::thread::sleep(std::time::Duration::from_micros(500));
981 continue;
982 } else {
983 return Err(e);
984 }
985 }
986 break;
987 }
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700988
Matthew Maurer4fb19112021-05-06 15:40:44 -0700989 // Drop the cache size from default (2M) to 0.5M
990 conn.execute("PRAGMA persistent.cache_size = -500;", params![])
991 .context("Failed to decrease cache size for persistent db")?;
Matthew Maurer4fb19112021-05-06 15:40:44 -0700992
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700993 Ok(conn)
994 }
995
Seth Moore78c091f2021-04-09 21:38:30 +0000996 fn do_table_size_query(
997 &mut self,
998 storage_type: StatsdStorageType,
999 query: &str,
1000 params: &[&str],
1001 ) -> Result<Keystore2StorageStats> {
1002 let (total, unused) = self.with_transaction(TransactionBehavior::Deferred, |tx| {
1003 tx.query_row(query, params, |row| Ok((row.get(0)?, row.get(1)?)))
1004 .with_context(|| {
1005 format!("get_storage_stat: Error size of storage type {}", storage_type as i32)
1006 })
1007 .no_gc()
1008 })?;
1009 Ok(Keystore2StorageStats { storage_type, size: total, unused_size: unused })
1010 }
1011
1012 fn get_total_size(&mut self) -> Result<Keystore2StorageStats> {
1013 self.do_table_size_query(
1014 StatsdStorageType::Database,
1015 "SELECT page_count * page_size, freelist_count * page_size
1016 FROM pragma_page_count('persistent'),
1017 pragma_page_size('persistent'),
1018 persistent.pragma_freelist_count();",
1019 &[],
1020 )
1021 }
1022
1023 fn get_table_size(
1024 &mut self,
1025 storage_type: StatsdStorageType,
1026 schema: &str,
1027 table: &str,
1028 ) -> Result<Keystore2StorageStats> {
1029 self.do_table_size_query(
1030 storage_type,
1031 "SELECT pgsize,unused FROM dbstat(?1)
1032 WHERE name=?2 AND aggregate=TRUE;",
1033 &[schema, table],
1034 )
1035 }
1036
1037 /// Fetches a storage statisitics atom for a given storage type. For storage
1038 /// types that map to a table, information about the table's storage is
1039 /// returned. Requests for storage types that are not DB tables return None.
1040 pub fn get_storage_stat(
1041 &mut self,
1042 storage_type: StatsdStorageType,
1043 ) -> Result<Keystore2StorageStats> {
Janis Danisevskis850d4862021-05-05 08:41:14 -07001044 let _wp = wd::watch_millis("KeystoreDB::get_storage_stat", 500);
1045
Seth Moore78c091f2021-04-09 21:38:30 +00001046 match storage_type {
1047 StatsdStorageType::Database => self.get_total_size(),
1048 StatsdStorageType::KeyEntry => {
1049 self.get_table_size(storage_type, "persistent", "keyentry")
1050 }
1051 StatsdStorageType::KeyEntryIdIndex => {
1052 self.get_table_size(storage_type, "persistent", "keyentry_id_index")
1053 }
1054 StatsdStorageType::KeyEntryDomainNamespaceIndex => {
1055 self.get_table_size(storage_type, "persistent", "keyentry_domain_namespace_index")
1056 }
1057 StatsdStorageType::BlobEntry => {
1058 self.get_table_size(storage_type, "persistent", "blobentry")
1059 }
1060 StatsdStorageType::BlobEntryKeyEntryIdIndex => {
1061 self.get_table_size(storage_type, "persistent", "blobentry_keyentryid_index")
1062 }
1063 StatsdStorageType::KeyParameter => {
1064 self.get_table_size(storage_type, "persistent", "keyparameter")
1065 }
1066 StatsdStorageType::KeyParameterKeyEntryIdIndex => {
1067 self.get_table_size(storage_type, "persistent", "keyparameter_keyentryid_index")
1068 }
1069 StatsdStorageType::KeyMetadata => {
1070 self.get_table_size(storage_type, "persistent", "keymetadata")
1071 }
1072 StatsdStorageType::KeyMetadataKeyEntryIdIndex => {
1073 self.get_table_size(storage_type, "persistent", "keymetadata_keyentryid_index")
1074 }
1075 StatsdStorageType::Grant => self.get_table_size(storage_type, "persistent", "grant"),
1076 StatsdStorageType::AuthToken => {
Matthew Maurerd7815ca2021-05-06 21:58:45 -07001077 // Since the table is actually a BTreeMap now, unused_size is not meaningfully
1078 // reportable
1079 // Size provided is only an approximation
1080 Ok(Keystore2StorageStats {
1081 storage_type,
1082 size: (self.perboot.auth_tokens_len() * std::mem::size_of::<AuthTokenEntry>())
1083 as i64,
1084 unused_size: 0,
1085 })
Seth Moore78c091f2021-04-09 21:38:30 +00001086 }
1087 StatsdStorageType::BlobMetadata => {
1088 self.get_table_size(storage_type, "persistent", "blobmetadata")
1089 }
1090 StatsdStorageType::BlobMetadataBlobEntryIdIndex => {
1091 self.get_table_size(storage_type, "persistent", "blobmetadata_blobentryid_index")
1092 }
1093 _ => Err(anyhow::Error::msg(format!(
1094 "Unsupported storage type: {}",
1095 storage_type as i32
1096 ))),
1097 }
1098 }
1099
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001100 /// This function is intended to be used by the garbage collector.
Janis Danisevskis3395f862021-05-06 10:54:17 -07001101 /// It deletes the blobs given by `blob_ids_to_delete`. It then tries to find up to `max_blobs`
1102 /// superseded key blobs that might need special handling by the garbage collector.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001103 /// If no further superseded blobs can be found it deletes all other superseded blobs that don't
1104 /// need special handling and returns None.
Janis Danisevskis3395f862021-05-06 10:54:17 -07001105 pub fn handle_next_superseded_blobs(
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001106 &mut self,
Janis Danisevskis3395f862021-05-06 10:54:17 -07001107 blob_ids_to_delete: &[i64],
1108 max_blobs: usize,
1109 ) -> Result<Vec<(i64, Vec<u8>, BlobMetaData)>> {
Janis Danisevskis850d4862021-05-05 08:41:14 -07001110 let _wp = wd::watch_millis("KeystoreDB::handle_next_superseded_blob", 500);
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001111 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis3395f862021-05-06 10:54:17 -07001112 // Delete the given blobs.
1113 for blob_id in blob_ids_to_delete {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001114 tx.execute(
1115 "DELETE FROM persistent.blobmetadata WHERE blobentryid = ?;",
Janis Danisevskis3395f862021-05-06 10:54:17 -07001116 params![blob_id],
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001117 )
1118 .context("Trying to delete blob metadata.")?;
Janis Danisevskis3395f862021-05-06 10:54:17 -07001119 tx.execute("DELETE FROM persistent.blobentry WHERE id = ?;", params![blob_id])
1120 .context("Trying to blob.")?;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001121 }
Janis Danisevskis3cba10d2021-05-06 17:02:19 -07001122
1123 Self::cleanup_unreferenced(tx).context("Trying to cleanup unreferenced.")?;
1124
Janis Danisevskis3395f862021-05-06 10:54:17 -07001125 // Find up to max_blobx more superseded key blobs, load their metadata and return it.
1126 let result: Vec<(i64, Vec<u8>)> = {
1127 let mut stmt = tx
1128 .prepare(
1129 "SELECT id, blob FROM persistent.blobentry
1130 WHERE subcomponent_type = ?
1131 AND (
1132 id NOT IN (
1133 SELECT MAX(id) FROM persistent.blobentry
1134 WHERE subcomponent_type = ?
1135 GROUP BY keyentryid, subcomponent_type
1136 )
1137 OR keyentryid NOT IN (SELECT id FROM persistent.keyentry)
1138 ) LIMIT ?;",
1139 )
1140 .context("Trying to prepare query for superseded blobs.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001141
Janis Danisevskis3395f862021-05-06 10:54:17 -07001142 let rows = stmt
1143 .query_map(
1144 params![
1145 SubComponentType::KEY_BLOB,
1146 SubComponentType::KEY_BLOB,
1147 max_blobs as i64,
1148 ],
1149 |row| Ok((row.get(0)?, row.get(1)?)),
1150 )
1151 .context("Trying to query superseded blob.")?;
1152
1153 rows.collect::<Result<Vec<(i64, Vec<u8>)>, rusqlite::Error>>()
1154 .context("Trying to extract superseded blobs.")?
1155 };
1156
1157 let result = result
1158 .into_iter()
1159 .map(|(blob_id, blob)| {
1160 Ok((blob_id, blob, BlobMetaData::load_from_db(blob_id, tx)?))
1161 })
1162 .collect::<Result<Vec<(i64, Vec<u8>, BlobMetaData)>>>()
1163 .context("Trying to load blob metadata.")?;
1164 if !result.is_empty() {
1165 return Ok(result).no_gc();
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001166 }
1167
1168 // We did not find any superseded key blob, so let's remove other superseded blob in
1169 // one transaction.
1170 tx.execute(
1171 "DELETE FROM persistent.blobentry
1172 WHERE NOT subcomponent_type = ?
1173 AND (
1174 id NOT IN (
1175 SELECT MAX(id) FROM persistent.blobentry
1176 WHERE NOT subcomponent_type = ?
1177 GROUP BY keyentryid, subcomponent_type
1178 ) OR keyentryid NOT IN (SELECT id FROM persistent.keyentry)
1179 );",
1180 params![SubComponentType::KEY_BLOB, SubComponentType::KEY_BLOB],
1181 )
1182 .context("Trying to purge superseded blobs.")?;
1183
Janis Danisevskis3395f862021-05-06 10:54:17 -07001184 Ok(vec![]).no_gc()
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001185 })
Janis Danisevskis3395f862021-05-06 10:54:17 -07001186 .context("In handle_next_superseded_blobs.")
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001187 }
1188
1189 /// This maintenance function should be called only once before the database is used for the
1190 /// first time. It restores the invariant that `KeyLifeCycle::Existing` is a transient state.
1191 /// The function transitions all key entries from Existing to Unreferenced unconditionally and
1192 /// returns the number of rows affected. If this returns a value greater than 0, it means that
1193 /// Keystore crashed at some point during key generation. Callers may want to log such
1194 /// occurrences.
1195 /// Unlike with `mark_unreferenced`, we don't need to purge grants, because only keys that made
1196 /// it to `KeyLifeCycle::Live` may have grants.
1197 pub fn cleanup_leftovers(&mut self) -> Result<usize> {
Janis Danisevskis850d4862021-05-05 08:41:14 -07001198 let _wp = wd::watch_millis("KeystoreDB::cleanup_leftovers", 500);
1199
Janis Danisevskis66784c42021-01-27 08:40:25 -08001200 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1201 tx.execute(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001202 "UPDATE persistent.keyentry SET state = ? WHERE state = ?;",
1203 params![KeyLifeCycle::Unreferenced, KeyLifeCycle::Existing],
1204 )
Janis Danisevskis66784c42021-01-27 08:40:25 -08001205 .context("Failed to execute query.")
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001206 .need_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08001207 })
1208 .context("In cleanup_leftovers.")
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001209 }
1210
Hasini Gunasinghe0e161452021-01-27 19:34:37 +00001211 /// Checks if a key exists with given key type and key descriptor properties.
1212 pub fn key_exists(
1213 &mut self,
1214 domain: Domain,
1215 nspace: i64,
1216 alias: &str,
1217 key_type: KeyType,
1218 ) -> Result<bool> {
Janis Danisevskis850d4862021-05-05 08:41:14 -07001219 let _wp = wd::watch_millis("KeystoreDB::key_exists", 500);
1220
Hasini Gunasinghe0e161452021-01-27 19:34:37 +00001221 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1222 let key_descriptor =
1223 KeyDescriptor { domain, nspace, alias: Some(alias.to_string()), blob: None };
1224 let result = Self::load_key_entry_id(&tx, &key_descriptor, key_type);
1225 match result {
1226 Ok(_) => Ok(true),
1227 Err(error) => match error.root_cause().downcast_ref::<KsError>() {
1228 Some(KsError::Rc(ResponseCode::KEY_NOT_FOUND)) => Ok(false),
1229 _ => Err(error).context("In key_exists: Failed to find if the key exists."),
1230 },
1231 }
1232 .no_gc()
1233 })
1234 .context("In key_exists.")
1235 }
1236
Hasini Gunasingheda895552021-01-27 19:34:37 +00001237 /// Stores a super key in the database.
1238 pub fn store_super_key(
1239 &mut self,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +00001240 user_id: u32,
Paul Crowley7a658392021-03-18 17:08:20 -07001241 key_type: &SuperKeyType,
1242 blob: &[u8],
1243 blob_metadata: &BlobMetaData,
Paul Crowley8d5b2532021-03-19 10:53:07 -07001244 key_metadata: &KeyMetaData,
Hasini Gunasingheda895552021-01-27 19:34:37 +00001245 ) -> Result<KeyEntry> {
Janis Danisevskis850d4862021-05-05 08:41:14 -07001246 let _wp = wd::watch_millis("KeystoreDB::store_super_key", 500);
1247
Hasini Gunasingheda895552021-01-27 19:34:37 +00001248 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1249 let key_id = Self::insert_with_retry(|id| {
1250 tx.execute(
1251 "INSERT into persistent.keyentry
1252 (id, key_type, domain, namespace, alias, state, km_uuid)
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00001253 VALUES(?, ?, ?, ?, ?, ?, ?);",
Hasini Gunasingheda895552021-01-27 19:34:37 +00001254 params![
1255 id,
1256 KeyType::Super,
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00001257 Domain::APP.0,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +00001258 user_id as i64,
Paul Crowley7a658392021-03-18 17:08:20 -07001259 key_type.alias,
Hasini Gunasingheda895552021-01-27 19:34:37 +00001260 KeyLifeCycle::Live,
1261 &KEYSTORE_UUID,
1262 ],
1263 )
1264 })
1265 .context("Failed to insert into keyentry table.")?;
1266
Paul Crowley8d5b2532021-03-19 10:53:07 -07001267 key_metadata.store_in_db(key_id, tx).context("KeyMetaData::store_in_db failed")?;
1268
Hasini Gunasingheda895552021-01-27 19:34:37 +00001269 Self::set_blob_internal(
1270 &tx,
1271 key_id,
1272 SubComponentType::KEY_BLOB,
1273 Some(blob),
1274 Some(blob_metadata),
1275 )
1276 .context("Failed to store key blob.")?;
1277
1278 Self::load_key_components(tx, KeyEntryLoadBits::KM, key_id)
1279 .context("Trying to load key components.")
1280 .no_gc()
1281 })
1282 .context("In store_super_key.")
1283 }
1284
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +00001285 /// Loads super key of a given user, if exists
Paul Crowley7a658392021-03-18 17:08:20 -07001286 pub fn load_super_key(
1287 &mut self,
1288 key_type: &SuperKeyType,
1289 user_id: u32,
1290 ) -> Result<Option<(KeyIdGuard, KeyEntry)>> {
Janis Danisevskis850d4862021-05-05 08:41:14 -07001291 let _wp = wd::watch_millis("KeystoreDB::load_super_key", 500);
1292
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +00001293 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1294 let key_descriptor = KeyDescriptor {
1295 domain: Domain::APP,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +00001296 nspace: user_id as i64,
Paul Crowley7a658392021-03-18 17:08:20 -07001297 alias: Some(key_type.alias.into()),
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +00001298 blob: None,
1299 };
1300 let id = Self::load_key_entry_id(&tx, &key_descriptor, KeyType::Super);
1301 match id {
1302 Ok(id) => {
1303 let key_entry = Self::load_key_components(&tx, KeyEntryLoadBits::KM, id)
1304 .context("In load_super_key. Failed to load key entry.")?;
1305 Ok(Some((KEY_ID_LOCK.get(id), key_entry)))
1306 }
1307 Err(error) => match error.root_cause().downcast_ref::<KsError>() {
1308 Some(KsError::Rc(ResponseCode::KEY_NOT_FOUND)) => Ok(None),
1309 _ => Err(error).context("In load_super_key."),
1310 },
1311 }
1312 .no_gc()
1313 })
1314 .context("In load_super_key.")
1315 }
1316
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001317 /// Atomically loads a key entry and associated metadata or creates it using the
1318 /// callback create_new_key callback. The callback is called during a database
1319 /// transaction. This means that implementers should be mindful about using
1320 /// blocking operations such as IPC or grabbing mutexes.
1321 pub fn get_or_create_key_with<F>(
1322 &mut self,
1323 domain: Domain,
1324 namespace: i64,
1325 alias: &str,
Max Bires8e93d2b2021-01-14 13:17:59 -08001326 km_uuid: Uuid,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001327 create_new_key: F,
1328 ) -> Result<(KeyIdGuard, KeyEntry)>
1329 where
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001330 F: Fn() -> Result<(Vec<u8>, BlobMetaData)>,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001331 {
Janis Danisevskis850d4862021-05-05 08:41:14 -07001332 let _wp = wd::watch_millis("KeystoreDB::get_or_create_key_with", 500);
1333
Janis Danisevskis66784c42021-01-27 08:40:25 -08001334 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1335 let id = {
1336 let mut stmt = tx
1337 .prepare(
1338 "SELECT id FROM persistent.keyentry
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001339 WHERE
1340 key_type = ?
1341 AND domain = ?
1342 AND namespace = ?
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001343 AND alias = ?
1344 AND state = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08001345 )
1346 .context("In get_or_create_key_with: Failed to select from keyentry table.")?;
1347 let mut rows = stmt
1348 .query(params![KeyType::Super, domain.0, namespace, alias, KeyLifeCycle::Live])
1349 .context("In get_or_create_key_with: Failed to query from keyentry table.")?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001350
Janis Danisevskis66784c42021-01-27 08:40:25 -08001351 db_utils::with_rows_extract_one(&mut rows, |row| {
1352 Ok(match row {
1353 Some(r) => r.get(0).context("Failed to unpack id.")?,
1354 None => None,
1355 })
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001356 })
Janis Danisevskis66784c42021-01-27 08:40:25 -08001357 .context("In get_or_create_key_with.")?
1358 };
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001359
Janis Danisevskis66784c42021-01-27 08:40:25 -08001360 let (id, entry) = match id {
1361 Some(id) => (
1362 id,
1363 Self::load_key_components(&tx, KeyEntryLoadBits::KM, id)
1364 .context("In get_or_create_key_with.")?,
1365 ),
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001366
Janis Danisevskis66784c42021-01-27 08:40:25 -08001367 None => {
1368 let id = Self::insert_with_retry(|id| {
1369 tx.execute(
1370 "INSERT into persistent.keyentry
Max Bires8e93d2b2021-01-14 13:17:59 -08001371 (id, key_type, domain, namespace, alias, state, km_uuid)
1372 VALUES(?, ?, ?, ?, ?, ?, ?);",
Janis Danisevskis66784c42021-01-27 08:40:25 -08001373 params![
1374 id,
1375 KeyType::Super,
1376 domain.0,
1377 namespace,
1378 alias,
1379 KeyLifeCycle::Live,
1380 km_uuid,
1381 ],
1382 )
1383 })
1384 .context("In get_or_create_key_with.")?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001385
Janis Danisevskis66784c42021-01-27 08:40:25 -08001386 let (blob, metadata) =
1387 create_new_key().context("In get_or_create_key_with.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001388 Self::set_blob_internal(
1389 &tx,
1390 id,
1391 SubComponentType::KEY_BLOB,
1392 Some(&blob),
1393 Some(&metadata),
1394 )
Paul Crowley7a658392021-03-18 17:08:20 -07001395 .context("In get_or_create_key_with.")?;
Janis Danisevskis66784c42021-01-27 08:40:25 -08001396 (
Janis Danisevskis377d1002021-01-27 19:07:48 -08001397 id,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001398 KeyEntry {
1399 id,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001400 key_blob_info: Some((blob, metadata)),
Janis Danisevskis66784c42021-01-27 08:40:25 -08001401 pure_cert: false,
1402 ..Default::default()
1403 },
1404 )
1405 }
1406 };
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001407 Ok((KEY_ID_LOCK.get(id), entry)).no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08001408 })
1409 .context("In get_or_create_key_with.")
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001410 }
1411
Janis Danisevskis66784c42021-01-27 08:40:25 -08001412 /// SQLite3 seems to hold a shared mutex while running the busy handler when
1413 /// waiting for the database file to become available. This makes it
1414 /// impossible to successfully recover from a locked database when the
1415 /// transaction holding the device busy is in the same process on a
1416 /// different connection. As a result the busy handler has to time out and
1417 /// fail in order to make progress.
1418 ///
1419 /// Instead, we set the busy handler to None (return immediately). And catch
1420 /// Busy and Locked errors (the latter occur on in memory databases with
1421 /// shared cache, e.g., the per-boot database.) and restart the transaction
1422 /// after a grace period of half a millisecond.
1423 ///
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001424 /// Creates a transaction with the given behavior and executes f with the new transaction.
Janis Danisevskis66784c42021-01-27 08:40:25 -08001425 /// The transaction is committed only if f returns Ok and retried if DatabaseBusy
1426 /// or DatabaseLocked is encountered.
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001427 fn with_transaction<T, F>(&mut self, behavior: TransactionBehavior, f: F) -> Result<T>
1428 where
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001429 F: Fn(&Transaction) -> Result<(bool, T)>,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001430 {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001431 loop {
1432 match self
1433 .conn
1434 .transaction_with_behavior(behavior)
1435 .context("In with_transaction.")
1436 .and_then(|tx| f(&tx).map(|result| (result, tx)))
1437 .and_then(|(result, tx)| {
1438 tx.commit().context("In with_transaction: Failed to commit transaction.")?;
1439 Ok(result)
1440 }) {
1441 Ok(result) => break Ok(result),
1442 Err(e) => {
1443 if Self::is_locked_error(&e) {
1444 std::thread::sleep(std::time::Duration::from_micros(500));
1445 continue;
1446 } else {
1447 return Err(e).context("In with_transaction.");
1448 }
1449 }
1450 }
1451 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001452 .map(|(need_gc, result)| {
1453 if need_gc {
1454 if let Some(ref gc) = self.gc {
1455 gc.notify_gc();
1456 }
1457 }
1458 result
1459 })
Janis Danisevskis66784c42021-01-27 08:40:25 -08001460 }
1461
1462 fn is_locked_error(e: &anyhow::Error) -> bool {
Paul Crowleyf61fee72021-03-17 14:38:44 -07001463 matches!(
1464 e.root_cause().downcast_ref::<rusqlite::ffi::Error>(),
1465 Some(rusqlite::ffi::Error { code: rusqlite::ErrorCode::DatabaseBusy, .. })
1466 | Some(rusqlite::ffi::Error { code: rusqlite::ErrorCode::DatabaseLocked, .. })
1467 )
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001468 }
1469
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001470 /// Creates a new key entry and allocates a new randomized id for the new key.
1471 /// The key id gets associated with a domain and namespace but not with an alias.
1472 /// To complete key generation `rebind_alias` should be called after all of the
1473 /// key artifacts, i.e., blobs and parameters have been associated with the new
1474 /// key id. Finalizing with `rebind_alias` makes the creation of a new key entry
1475 /// atomic even if key generation is not.
Max Bires8e93d2b2021-01-14 13:17:59 -08001476 pub fn create_key_entry(
1477 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001478 domain: &Domain,
1479 namespace: &i64,
Max Bires8e93d2b2021-01-14 13:17:59 -08001480 km_uuid: &Uuid,
1481 ) -> Result<KeyIdGuard> {
Janis Danisevskis850d4862021-05-05 08:41:14 -07001482 let _wp = wd::watch_millis("KeystoreDB::create_key_entry", 500);
1483
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001484 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001485 Self::create_key_entry_internal(tx, domain, namespace, km_uuid).no_gc()
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001486 })
1487 .context("In create_key_entry.")
1488 }
1489
1490 fn create_key_entry_internal(
1491 tx: &Transaction,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001492 domain: &Domain,
1493 namespace: &i64,
Max Bires8e93d2b2021-01-14 13:17:59 -08001494 km_uuid: &Uuid,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001495 ) -> Result<KeyIdGuard> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001496 match *domain {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001497 Domain::APP | Domain::SELINUX => {}
Joel Galenson0891bc12020-07-20 10:37:03 -07001498 _ => {
1499 return Err(KsError::sys())
1500 .context(format!("Domain {:?} must be either App or SELinux.", domain));
1501 }
1502 }
Janis Danisevskisaec14592020-11-12 09:41:49 -08001503 Ok(KEY_ID_LOCK.get(
1504 Self::insert_with_retry(|id| {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001505 tx.execute(
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001506 "INSERT into persistent.keyentry
Max Bires8e93d2b2021-01-14 13:17:59 -08001507 (id, key_type, domain, namespace, alias, state, km_uuid)
1508 VALUES(?, ?, ?, ?, NULL, ?, ?);",
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001509 params![
1510 id,
1511 KeyType::Client,
1512 domain.0 as u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001513 *namespace,
Max Bires8e93d2b2021-01-14 13:17:59 -08001514 KeyLifeCycle::Existing,
1515 km_uuid,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001516 ],
Janis Danisevskisaec14592020-11-12 09:41:49 -08001517 )
1518 })
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001519 .context("In create_key_entry_internal")?,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001520 ))
Joel Galenson26f4d012020-07-17 14:57:21 -07001521 }
Joel Galenson33c04ad2020-08-03 11:04:38 -07001522
Max Bires2b2e6562020-09-22 11:22:36 -07001523 /// Creates a new attestation key entry and allocates a new randomized id for the new key.
1524 /// The key id gets associated with a domain and namespace later but not with an alias. The
1525 /// alias will be used to denote if a key has been signed as each key can only be bound to one
1526 /// domain and namespace pairing so there is no need to use them as a value for indexing into
1527 /// a key.
1528 pub fn create_attestation_key_entry(
1529 &mut self,
1530 maced_public_key: &[u8],
1531 raw_public_key: &[u8],
1532 private_key: &[u8],
1533 km_uuid: &Uuid,
1534 ) -> Result<()> {
Janis Danisevskis850d4862021-05-05 08:41:14 -07001535 let _wp = wd::watch_millis("KeystoreDB::create_attestation_key_entry", 500);
1536
Max Bires2b2e6562020-09-22 11:22:36 -07001537 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1538 let key_id = KEY_ID_LOCK.get(
1539 Self::insert_with_retry(|id| {
1540 tx.execute(
1541 "INSERT into persistent.keyentry
1542 (id, key_type, domain, namespace, alias, state, km_uuid)
1543 VALUES(?, ?, NULL, NULL, NULL, ?, ?);",
1544 params![id, KeyType::Attestation, KeyLifeCycle::Live, km_uuid],
1545 )
1546 })
1547 .context("In create_key_entry")?,
1548 );
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001549 Self::set_blob_internal(
1550 &tx,
1551 key_id.0,
1552 SubComponentType::KEY_BLOB,
1553 Some(private_key),
1554 None,
1555 )?;
Max Bires2b2e6562020-09-22 11:22:36 -07001556 let mut metadata = KeyMetaData::new();
1557 metadata.add(KeyMetaEntry::AttestationMacedPublicKey(maced_public_key.to_vec()));
1558 metadata.add(KeyMetaEntry::AttestationRawPubKey(raw_public_key.to_vec()));
1559 metadata.store_in_db(key_id.0, &tx)?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001560 Ok(()).no_gc()
Max Bires2b2e6562020-09-22 11:22:36 -07001561 })
1562 .context("In create_attestation_key_entry")
1563 }
1564
Janis Danisevskis377d1002021-01-27 19:07:48 -08001565 /// Set a new blob and associates it with the given key id. Each blob
1566 /// has a sub component type.
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001567 /// Each key can have one of each sub component type associated. If more
1568 /// are added only the most recent can be retrieved, and superseded blobs
Janis Danisevskis377d1002021-01-27 19:07:48 -08001569 /// will get garbage collected.
1570 /// Components SubComponentType::CERT and SubComponentType::CERT_CHAIN can be
1571 /// removed by setting blob to None.
1572 pub fn set_blob(
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001573 &mut self,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001574 key_id: &KeyIdGuard,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001575 sc_type: SubComponentType,
Janis Danisevskis377d1002021-01-27 19:07:48 -08001576 blob: Option<&[u8]>,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001577 blob_metadata: Option<&BlobMetaData>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001578 ) -> Result<()> {
Janis Danisevskis850d4862021-05-05 08:41:14 -07001579 let _wp = wd::watch_millis("KeystoreDB::set_blob", 500);
1580
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001581 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001582 Self::set_blob_internal(&tx, key_id.0, sc_type, blob, blob_metadata).need_gc()
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001583 })
Janis Danisevskis377d1002021-01-27 19:07:48 -08001584 .context("In set_blob.")
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001585 }
1586
Janis Danisevskiseed69842021-02-18 20:04:10 -08001587 /// Why would we insert a deleted blob? This weird function is for the purpose of legacy
1588 /// key migration in the case where we bulk delete all the keys of an app or even a user.
1589 /// We use this to insert key blobs into the database which can then be garbage collected
1590 /// lazily by the key garbage collector.
1591 pub fn set_deleted_blob(&mut self, blob: &[u8], blob_metadata: &BlobMetaData) -> Result<()> {
Janis Danisevskis850d4862021-05-05 08:41:14 -07001592 let _wp = wd::watch_millis("KeystoreDB::set_deleted_blob", 500);
1593
Janis Danisevskiseed69842021-02-18 20:04:10 -08001594 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1595 Self::set_blob_internal(
1596 &tx,
1597 Self::UNASSIGNED_KEY_ID,
1598 SubComponentType::KEY_BLOB,
1599 Some(blob),
1600 Some(blob_metadata),
1601 )
1602 .need_gc()
1603 })
1604 .context("In set_deleted_blob.")
1605 }
1606
Janis Danisevskis377d1002021-01-27 19:07:48 -08001607 fn set_blob_internal(
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001608 tx: &Transaction,
1609 key_id: i64,
1610 sc_type: SubComponentType,
Janis Danisevskis377d1002021-01-27 19:07:48 -08001611 blob: Option<&[u8]>,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001612 blob_metadata: Option<&BlobMetaData>,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001613 ) -> Result<()> {
Janis Danisevskis377d1002021-01-27 19:07:48 -08001614 match (blob, sc_type) {
1615 (Some(blob), _) => {
1616 tx.execute(
1617 "INSERT INTO persistent.blobentry
1618 (subcomponent_type, keyentryid, blob) VALUES (?, ?, ?);",
1619 params![sc_type, key_id, blob],
1620 )
1621 .context("In set_blob_internal: Failed to insert blob.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001622 if let Some(blob_metadata) = blob_metadata {
1623 let blob_id = tx
1624 .query_row("SELECT MAX(id) FROM persistent.blobentry;", NO_PARAMS, |row| {
1625 row.get(0)
1626 })
1627 .context("In set_blob_internal: Failed to get new blob id.")?;
1628 blob_metadata
1629 .store_in_db(blob_id, tx)
1630 .context("In set_blob_internal: Trying to store blob metadata.")?;
1631 }
Janis Danisevskis377d1002021-01-27 19:07:48 -08001632 }
1633 (None, SubComponentType::CERT) | (None, SubComponentType::CERT_CHAIN) => {
1634 tx.execute(
1635 "DELETE FROM persistent.blobentry
1636 WHERE subcomponent_type = ? AND keyentryid = ?;",
1637 params![sc_type, key_id],
1638 )
1639 .context("In set_blob_internal: Failed to delete blob.")?;
1640 }
1641 (None, _) => {
1642 return Err(KsError::sys())
1643 .context("In set_blob_internal: Other blobs cannot be deleted in this way.");
1644 }
1645 }
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001646 Ok(())
1647 }
1648
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001649 /// Inserts a collection of key parameters into the `persistent.keyparameter` table
1650 /// and associates them with the given `key_id`.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001651 #[cfg(test)]
1652 fn insert_keyparameter(&mut self, key_id: &KeyIdGuard, params: &[KeyParameter]) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001653 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001654 Self::insert_keyparameter_internal(tx, key_id, params).no_gc()
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001655 })
1656 .context("In insert_keyparameter.")
1657 }
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001658
Janis Danisevskis66784c42021-01-27 08:40:25 -08001659 fn insert_keyparameter_internal(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001660 tx: &Transaction,
1661 key_id: &KeyIdGuard,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001662 params: &[KeyParameter],
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001663 ) -> Result<()> {
1664 let mut stmt = tx
1665 .prepare(
1666 "INSERT into persistent.keyparameter (keyentryid, tag, data, security_level)
1667 VALUES (?, ?, ?, ?);",
1668 )
1669 .context("In insert_keyparameter_internal: Failed to prepare statement.")?;
1670
Janis Danisevskis66784c42021-01-27 08:40:25 -08001671 for p in params.iter() {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001672 stmt.insert(params![
1673 key_id.0,
1674 p.get_tag().0,
1675 p.key_parameter_value(),
1676 p.security_level().0
1677 ])
1678 .with_context(|| {
1679 format!("In insert_keyparameter_internal: Failed to insert {:?}", p)
1680 })?;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001681 }
1682 Ok(())
1683 }
1684
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001685 /// Insert a set of key entry specific metadata into the database.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001686 #[cfg(test)]
1687 fn insert_key_metadata(&mut self, key_id: &KeyIdGuard, metadata: &KeyMetaData) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001688 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001689 metadata.store_in_db(key_id.0, &tx).no_gc()
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001690 })
1691 .context("In insert_key_metadata.")
1692 }
1693
Max Bires2b2e6562020-09-22 11:22:36 -07001694 /// Stores a signed certificate chain signed by a remote provisioning server, keyed
1695 /// on the public key.
1696 pub fn store_signed_attestation_certificate_chain(
1697 &mut self,
1698 raw_public_key: &[u8],
Max Biresb2e1d032021-02-08 21:35:05 -08001699 batch_cert: &[u8],
Max Bires2b2e6562020-09-22 11:22:36 -07001700 cert_chain: &[u8],
1701 expiration_date: i64,
1702 km_uuid: &Uuid,
1703 ) -> Result<()> {
Janis Danisevskis850d4862021-05-05 08:41:14 -07001704 let _wp = wd::watch_millis("KeystoreDB::store_signed_attestation_certificate_chain", 500);
1705
Max Bires2b2e6562020-09-22 11:22:36 -07001706 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1707 let mut stmt = tx
1708 .prepare(
1709 "SELECT keyentryid
1710 FROM persistent.keymetadata
1711 WHERE tag = ? AND data = ? AND keyentryid IN
1712 (SELECT id
1713 FROM persistent.keyentry
1714 WHERE
1715 alias IS NULL AND
1716 domain IS NULL AND
1717 namespace IS NULL AND
1718 key_type = ? AND
1719 km_uuid = ?);",
1720 )
1721 .context("Failed to store attestation certificate chain.")?;
1722 let mut rows = stmt
1723 .query(params![
1724 KeyMetaData::AttestationRawPubKey,
1725 raw_public_key,
1726 KeyType::Attestation,
1727 km_uuid
1728 ])
1729 .context("Failed to fetch keyid")?;
1730 let key_id = db_utils::with_rows_extract_one(&mut rows, |row| {
1731 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?
1732 .get(0)
1733 .context("Failed to unpack id.")
1734 })
1735 .context("Failed to get key_id.")?;
1736 let num_updated = tx
1737 .execute(
1738 "UPDATE persistent.keyentry
1739 SET alias = ?
1740 WHERE id = ?;",
1741 params!["signed", key_id],
1742 )
1743 .context("Failed to update alias.")?;
1744 if num_updated != 1 {
1745 return Err(KsError::sys()).context("Alias not updated for the key.");
1746 }
1747 let mut metadata = KeyMetaData::new();
1748 metadata.add(KeyMetaEntry::AttestationExpirationDate(DateTime::from_millis_epoch(
1749 expiration_date,
1750 )));
1751 metadata.store_in_db(key_id, &tx).context("Failed to insert key metadata.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001752 Self::set_blob_internal(
1753 &tx,
1754 key_id,
1755 SubComponentType::CERT_CHAIN,
1756 Some(cert_chain),
1757 None,
1758 )
1759 .context("Failed to insert cert chain")?;
Max Biresb2e1d032021-02-08 21:35:05 -08001760 Self::set_blob_internal(&tx, key_id, SubComponentType::CERT, Some(batch_cert), None)
1761 .context("Failed to insert cert")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001762 Ok(()).no_gc()
Max Bires2b2e6562020-09-22 11:22:36 -07001763 })
1764 .context("In store_signed_attestation_certificate_chain: ")
1765 }
1766
1767 /// Assigns the next unassigned attestation key to a domain/namespace combo that does not
1768 /// currently have a key assigned to it.
1769 pub fn assign_attestation_key(
1770 &mut self,
1771 domain: Domain,
1772 namespace: i64,
1773 km_uuid: &Uuid,
1774 ) -> Result<()> {
Janis Danisevskis850d4862021-05-05 08:41:14 -07001775 let _wp = wd::watch_millis("KeystoreDB::assign_attestation_key", 500);
1776
Max Bires2b2e6562020-09-22 11:22:36 -07001777 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>>> {
Janis Danisevskis850d4862021-05-05 08:41:14 -07001839 let _wp = wd::watch_millis("KeystoreDB::fetch_unsigned_attestation_keys", 500);
1840
Max Bires2b2e6562020-09-22 11:22:36 -07001841 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1842 let mut stmt = tx
1843 .prepare(
1844 "SELECT data
1845 FROM persistent.keymetadata
1846 WHERE tag = ? AND keyentryid IN
1847 (SELECT id
1848 FROM persistent.keyentry
1849 WHERE
1850 alias IS NULL AND
1851 domain IS NULL AND
1852 namespace IS NULL AND
1853 key_type = ? AND
1854 km_uuid = ?
1855 LIMIT ?);",
1856 )
1857 .context("Failed to prepare statement")?;
1858 let rows = stmt
1859 .query_map(
1860 params![
1861 KeyMetaData::AttestationMacedPublicKey,
1862 KeyType::Attestation,
1863 km_uuid,
1864 num_keys
1865 ],
Janis Danisevskis82e55f92021-05-06 14:55:48 -07001866 |row| row.get(0),
Max Bires2b2e6562020-09-22 11:22:36 -07001867 )?
1868 .collect::<rusqlite::Result<Vec<Vec<u8>>>>()
1869 .context("Failed to execute statement")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001870 Ok(rows).no_gc()
Max Bires2b2e6562020-09-22 11:22:36 -07001871 })
1872 .context("In fetch_unsigned_attestation_keys")
1873 }
1874
1875 /// Removes any keys that have expired as of the current time. Returns the number of keys
1876 /// marked unreferenced that are bound to be garbage collected.
1877 pub fn delete_expired_attestation_keys(&mut self) -> Result<i32> {
Janis Danisevskis850d4862021-05-05 08:41:14 -07001878 let _wp = wd::watch_millis("KeystoreDB::delete_expired_attestation_keys", 500);
1879
Max Bires2b2e6562020-09-22 11:22:36 -07001880 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1881 let mut stmt = tx
1882 .prepare(
1883 "SELECT keyentryid, data
1884 FROM persistent.keymetadata
1885 WHERE tag = ? AND keyentryid IN
1886 (SELECT id
1887 FROM persistent.keyentry
1888 WHERE key_type = ?);",
1889 )
1890 .context("Failed to prepare query")?;
1891 let key_ids_to_check = stmt
1892 .query_map(
1893 params![KeyMetaData::AttestationExpirationDate, KeyType::Attestation],
1894 |row| Ok((row.get(0)?, row.get(1)?)),
1895 )?
1896 .collect::<rusqlite::Result<Vec<(i64, DateTime)>>>()
1897 .context("Failed to get date metadata")?;
1898 let curr_time = DateTime::from_millis_epoch(
1899 SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_millis() as i64,
1900 );
1901 let mut num_deleted = 0;
1902 for id in key_ids_to_check.iter().filter(|kt| kt.1 < curr_time).map(|kt| kt.0) {
1903 if Self::mark_unreferenced(&tx, id)? {
1904 num_deleted += 1;
1905 }
1906 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001907 Ok(num_deleted).do_gc(num_deleted != 0)
Max Bires2b2e6562020-09-22 11:22:36 -07001908 })
1909 .context("In delete_expired_attestation_keys: ")
1910 }
1911
Max Bires60d7ed12021-03-05 15:59:22 -08001912 /// Deletes all remotely provisioned attestation keys in the system, regardless of the state
1913 /// they are in. This is useful primarily as a testing mechanism.
1914 pub fn delete_all_attestation_keys(&mut self) -> Result<i64> {
Janis Danisevskis850d4862021-05-05 08:41:14 -07001915 let _wp = wd::watch_millis("KeystoreDB::delete_all_attestation_keys", 500);
1916
Max Bires60d7ed12021-03-05 15:59:22 -08001917 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1918 let mut stmt = tx
1919 .prepare(
1920 "SELECT id FROM persistent.keyentry
1921 WHERE key_type IS ?;",
1922 )
1923 .context("Failed to prepare statement")?;
1924 let keys_to_delete = stmt
Janis Danisevskis82e55f92021-05-06 14:55:48 -07001925 .query_map(params![KeyType::Attestation], |row| row.get(0))?
Max Bires60d7ed12021-03-05 15:59:22 -08001926 .collect::<rusqlite::Result<Vec<i64>>>()
1927 .context("Failed to execute statement")?;
1928 let num_deleted = keys_to_delete
1929 .iter()
1930 .map(|id| Self::mark_unreferenced(&tx, *id))
1931 .collect::<Result<Vec<bool>>>()
1932 .context("Failed to execute mark_unreferenced on a keyid")?
1933 .into_iter()
1934 .filter(|result| *result)
1935 .count() as i64;
1936 Ok(num_deleted).do_gc(num_deleted != 0)
1937 })
1938 .context("In delete_all_attestation_keys: ")
1939 }
1940
Max Bires2b2e6562020-09-22 11:22:36 -07001941 /// Counts the number of keys that will expire by the provided epoch date and the number of
1942 /// keys not currently assigned to a domain.
1943 pub fn get_attestation_pool_status(
1944 &mut self,
1945 date: i64,
1946 km_uuid: &Uuid,
1947 ) -> Result<AttestationPoolStatus> {
Janis Danisevskis850d4862021-05-05 08:41:14 -07001948 let _wp = wd::watch_millis("KeystoreDB::get_attestation_pool_status", 500);
1949
Max Bires2b2e6562020-09-22 11:22:36 -07001950 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1951 let mut stmt = tx.prepare(
1952 "SELECT data
1953 FROM persistent.keymetadata
1954 WHERE tag = ? AND keyentryid IN
1955 (SELECT id
1956 FROM persistent.keyentry
1957 WHERE alias IS NOT NULL
1958 AND key_type = ?
1959 AND km_uuid = ?
1960 AND state = ?);",
1961 )?;
1962 let times = stmt
1963 .query_map(
1964 params![
1965 KeyMetaData::AttestationExpirationDate,
1966 KeyType::Attestation,
1967 km_uuid,
1968 KeyLifeCycle::Live
1969 ],
Janis Danisevskis82e55f92021-05-06 14:55:48 -07001970 |row| row.get(0),
Max Bires2b2e6562020-09-22 11:22:36 -07001971 )?
1972 .collect::<rusqlite::Result<Vec<DateTime>>>()
1973 .context("Failed to execute metadata statement")?;
1974 let expiring =
1975 times.iter().filter(|time| time < &&DateTime::from_millis_epoch(date)).count()
1976 as i32;
1977 stmt = tx.prepare(
1978 "SELECT alias, domain
1979 FROM persistent.keyentry
1980 WHERE key_type = ? AND km_uuid = ? AND state = ?;",
1981 )?;
1982 let rows = stmt
1983 .query_map(params![KeyType::Attestation, km_uuid, KeyLifeCycle::Live], |row| {
1984 Ok((row.get(0)?, row.get(1)?))
1985 })?
1986 .collect::<rusqlite::Result<Vec<(Option<String>, Option<u32>)>>>()
1987 .context("Failed to execute keyentry statement")?;
1988 let mut unassigned = 0i32;
1989 let mut attested = 0i32;
1990 let total = rows.len() as i32;
1991 for (alias, domain) in rows {
1992 match (alias, domain) {
1993 (Some(_alias), None) => {
1994 attested += 1;
1995 unassigned += 1;
1996 }
1997 (Some(_alias), Some(_domain)) => {
1998 attested += 1;
1999 }
2000 _ => {}
2001 }
2002 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002003 Ok(AttestationPoolStatus { expiring, unassigned, attested, total }).no_gc()
Max Bires2b2e6562020-09-22 11:22:36 -07002004 })
2005 .context("In get_attestation_pool_status: ")
2006 }
2007
2008 /// Fetches the private key and corresponding certificate chain assigned to a
2009 /// domain/namespace pair. Will either return nothing if the domain/namespace is
2010 /// not assigned, or one CertificateChain.
2011 pub fn retrieve_attestation_key_and_cert_chain(
2012 &mut self,
2013 domain: Domain,
2014 namespace: i64,
2015 km_uuid: &Uuid,
2016 ) -> Result<Option<CertificateChain>> {
Janis Danisevskis850d4862021-05-05 08:41:14 -07002017 let _wp = wd::watch_millis("KeystoreDB::retrieve_attestation_key_and_cert_chain", 500);
2018
Max Bires2b2e6562020-09-22 11:22:36 -07002019 match domain {
2020 Domain::APP | Domain::SELINUX => {}
2021 _ => {
2022 return Err(KsError::sys())
2023 .context(format!("Domain {:?} must be either App or SELinux.", domain));
2024 }
2025 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002026 self.with_transaction(TransactionBehavior::Deferred, |tx| {
2027 let mut stmt = tx.prepare(
2028 "SELECT subcomponent_type, blob
Max Bires2b2e6562020-09-22 11:22:36 -07002029 FROM persistent.blobentry
2030 WHERE keyentryid IN
2031 (SELECT id
2032 FROM persistent.keyentry
2033 WHERE key_type = ?
2034 AND domain = ?
2035 AND namespace = ?
2036 AND state = ?
2037 AND km_uuid = ?);",
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002038 )?;
2039 let rows = stmt
2040 .query_map(
2041 params![
2042 KeyType::Attestation,
2043 domain.0 as u32,
2044 namespace,
2045 KeyLifeCycle::Live,
2046 km_uuid
2047 ],
2048 |row| Ok((row.get(0)?, row.get(1)?)),
2049 )?
2050 .collect::<rusqlite::Result<Vec<(SubComponentType, Vec<u8>)>>>()
Max Biresb2e1d032021-02-08 21:35:05 -08002051 .context("query failed.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002052 if rows.is_empty() {
2053 return Ok(None).no_gc();
Max Biresb2e1d032021-02-08 21:35:05 -08002054 } else if rows.len() != 3 {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002055 return Err(KsError::sys()).context(format!(
2056 concat!(
Max Biresb2e1d032021-02-08 21:35:05 -08002057 "Expected to get a single attestation",
2058 "key, cert, and cert chain for a total of 3 entries, but instead got {}."
2059 ),
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002060 rows.len()
2061 ));
Max Bires2b2e6562020-09-22 11:22:36 -07002062 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002063 let mut km_blob: Vec<u8> = Vec::new();
2064 let mut cert_chain_blob: Vec<u8> = Vec::new();
Max Biresb2e1d032021-02-08 21:35:05 -08002065 let mut batch_cert_blob: Vec<u8> = Vec::new();
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002066 for row in rows {
2067 let sub_type: SubComponentType = row.0;
2068 match sub_type {
2069 SubComponentType::KEY_BLOB => {
2070 km_blob = row.1;
2071 }
2072 SubComponentType::CERT_CHAIN => {
2073 cert_chain_blob = row.1;
2074 }
Max Biresb2e1d032021-02-08 21:35:05 -08002075 SubComponentType::CERT => {
2076 batch_cert_blob = row.1;
2077 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002078 _ => Err(KsError::sys()).context("Unknown or incorrect subcomponent type.")?,
2079 }
2080 }
2081 Ok(Some(CertificateChain {
2082 private_key: ZVec::try_from(km_blob)?,
Max Bires97f96812021-02-23 23:44:57 -08002083 batch_cert: batch_cert_blob,
2084 cert_chain: cert_chain_blob,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002085 }))
2086 .no_gc()
2087 })
Max Biresb2e1d032021-02-08 21:35:05 -08002088 .context("In retrieve_attestation_key_and_cert_chain:")
Max Bires2b2e6562020-09-22 11:22:36 -07002089 }
2090
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002091 /// Updates the alias column of the given key id `newid` with the given alias,
2092 /// and atomically, removes the alias, domain, and namespace from another row
2093 /// with the same alias-domain-namespace tuple if such row exits.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002094 /// Returns Ok(true) if an old key was marked unreferenced as a hint to the garbage
2095 /// collector.
2096 fn rebind_alias(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002097 tx: &Transaction,
Janis Danisevskisaec14592020-11-12 09:41:49 -08002098 newid: &KeyIdGuard,
Joel Galenson33c04ad2020-08-03 11:04:38 -07002099 alias: &str,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002100 domain: &Domain,
2101 namespace: &i64,
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002102 ) -> Result<bool> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002103 match *domain {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002104 Domain::APP | Domain::SELINUX => {}
Joel Galenson33c04ad2020-08-03 11:04:38 -07002105 _ => {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002106 return Err(KsError::sys()).context(format!(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002107 "In rebind_alias: Domain {:?} must be either App or SELinux.",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002108 domain
2109 ));
Joel Galenson33c04ad2020-08-03 11:04:38 -07002110 }
2111 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002112 let updated = tx
2113 .execute(
2114 "UPDATE persistent.keyentry
2115 SET alias = NULL, domain = NULL, namespace = NULL, state = ?
Joel Galenson33c04ad2020-08-03 11:04:38 -07002116 WHERE alias = ? AND domain = ? AND namespace = ?;",
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002117 params![KeyLifeCycle::Unreferenced, alias, domain.0 as u32, namespace],
2118 )
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002119 .context("In rebind_alias: Failed to rebind existing entry.")?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07002120 let result = tx
2121 .execute(
2122 "UPDATE persistent.keyentry
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002123 SET alias = ?, state = ?
2124 WHERE id = ? AND domain = ? AND namespace = ? AND state = ?;",
2125 params![
2126 alias,
2127 KeyLifeCycle::Live,
2128 newid.0,
2129 domain.0 as u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002130 *namespace,
Max Bires8e93d2b2021-01-14 13:17:59 -08002131 KeyLifeCycle::Existing,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002132 ],
Joel Galenson33c04ad2020-08-03 11:04:38 -07002133 )
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002134 .context("In rebind_alias: Failed to set alias.")?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07002135 if result != 1 {
Joel Galenson33c04ad2020-08-03 11:04:38 -07002136 return Err(KsError::sys()).context(format!(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002137 "In rebind_alias: Expected to update a single entry but instead updated {}.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07002138 result
2139 ));
2140 }
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002141 Ok(updated != 0)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002142 }
2143
Janis Danisevskiscdcf4e52021-04-14 15:44:36 -07002144 /// Moves the key given by KeyIdGuard to the new location at `destination`. If the destination
2145 /// is already occupied by a key, this function fails with `ResponseCode::INVALID_ARGUMENT`.
2146 pub fn migrate_key_namespace(
2147 &mut self,
2148 key_id_guard: KeyIdGuard,
2149 destination: &KeyDescriptor,
2150 caller_uid: u32,
2151 check_permission: impl Fn(&KeyDescriptor) -> Result<()>,
2152 ) -> Result<()> {
Janis Danisevskis850d4862021-05-05 08:41:14 -07002153 let _wp = wd::watch_millis("KeystoreDB::migrate_key_namespace", 500);
2154
Janis Danisevskiscdcf4e52021-04-14 15:44:36 -07002155 let destination = match destination.domain {
2156 Domain::APP => KeyDescriptor { nspace: caller_uid as i64, ..(*destination).clone() },
2157 Domain::SELINUX => (*destination).clone(),
2158 domain => {
2159 return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT))
2160 .context(format!("Domain {:?} must be either APP or SELINUX.", domain));
2161 }
2162 };
2163
2164 // Security critical: Must return immediately on failure. Do not remove the '?';
2165 check_permission(&destination)
2166 .context("In migrate_key_namespace: Trying to check permission.")?;
2167
2168 let alias = destination
2169 .alias
2170 .as_ref()
2171 .ok_or(KsError::Rc(ResponseCode::INVALID_ARGUMENT))
2172 .context("In migrate_key_namespace: Alias must be specified.")?;
2173
2174 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2175 // Query the destination location. If there is a key, the migration request fails.
2176 if tx
2177 .query_row(
2178 "SELECT id FROM persistent.keyentry
2179 WHERE alias = ? AND domain = ? AND namespace = ?;",
2180 params![alias, destination.domain.0, destination.nspace],
2181 |_| Ok(()),
2182 )
2183 .optional()
2184 .context("Failed to query destination.")?
2185 .is_some()
2186 {
2187 return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT))
2188 .context("Target already exists.");
2189 }
2190
2191 let updated = tx
2192 .execute(
2193 "UPDATE persistent.keyentry
2194 SET alias = ?, domain = ?, namespace = ?
2195 WHERE id = ?;",
2196 params![alias, destination.domain.0, destination.nspace, key_id_guard.id()],
2197 )
2198 .context("Failed to update key entry.")?;
2199
2200 if updated != 1 {
2201 return Err(KsError::sys())
2202 .context(format!("Update succeeded, but {} rows were updated.", updated));
2203 }
2204 Ok(()).no_gc()
2205 })
2206 .context("In migrate_key_namespace:")
2207 }
2208
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002209 /// Store a new key in a single transaction.
2210 /// The function creates a new key entry, populates the blob, key parameter, and metadata
2211 /// fields, and rebinds the given alias to the new key.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002212 /// The boolean returned is a hint for the garbage collector. If true, a key was replaced,
2213 /// is now unreferenced and needs to be collected.
Janis Danisevskis66784c42021-01-27 08:40:25 -08002214 pub fn store_new_key(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002215 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002216 key: &KeyDescriptor,
2217 params: &[KeyParameter],
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002218 blob_info: &(&[u8], &BlobMetaData),
Max Bires8e93d2b2021-01-14 13:17:59 -08002219 cert_info: &CertificateInfo,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002220 metadata: &KeyMetaData,
Max Bires8e93d2b2021-01-14 13:17:59 -08002221 km_uuid: &Uuid,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002222 ) -> Result<KeyIdGuard> {
Janis Danisevskis850d4862021-05-05 08:41:14 -07002223 let _wp = wd::watch_millis("KeystoreDB::store_new_key", 500);
2224
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002225 let (alias, domain, namespace) = match key {
2226 KeyDescriptor { alias: Some(alias), domain: Domain::APP, nspace, blob: None }
2227 | KeyDescriptor { alias: Some(alias), domain: Domain::SELINUX, nspace, blob: None } => {
2228 (alias, key.domain, nspace)
2229 }
2230 _ => {
2231 return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT))
2232 .context("In store_new_key: Need alias and domain must be APP or SELINUX.")
2233 }
2234 };
2235 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002236 let key_id = Self::create_key_entry_internal(tx, &domain, namespace, km_uuid)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002237 .context("Trying to create new key entry.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002238 let (blob, blob_metadata) = *blob_info;
2239 Self::set_blob_internal(
2240 tx,
2241 key_id.id(),
2242 SubComponentType::KEY_BLOB,
2243 Some(blob),
2244 Some(&blob_metadata),
2245 )
2246 .context("Trying to insert the key blob.")?;
Max Bires8e93d2b2021-01-14 13:17:59 -08002247 if let Some(cert) = &cert_info.cert {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002248 Self::set_blob_internal(tx, key_id.id(), SubComponentType::CERT, Some(&cert), None)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002249 .context("Trying to insert the certificate.")?;
2250 }
Max Bires8e93d2b2021-01-14 13:17:59 -08002251 if let Some(cert_chain) = &cert_info.cert_chain {
Janis Danisevskis377d1002021-01-27 19:07:48 -08002252 Self::set_blob_internal(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002253 tx,
2254 key_id.id(),
2255 SubComponentType::CERT_CHAIN,
Janis Danisevskis377d1002021-01-27 19:07:48 -08002256 Some(&cert_chain),
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002257 None,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002258 )
2259 .context("Trying to insert the certificate chain.")?;
2260 }
2261 Self::insert_keyparameter_internal(tx, &key_id, params)
2262 .context("Trying to insert key parameters.")?;
Janis Danisevskis377d1002021-01-27 19:07:48 -08002263 metadata.store_in_db(key_id.id(), tx).context("Trying to insert key metadata.")?;
Janis Danisevskis66784c42021-01-27 08:40:25 -08002264 let need_gc = Self::rebind_alias(tx, &key_id, &alias, &domain, namespace)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002265 .context("Trying to rebind alias.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002266 Ok(key_id).do_gc(need_gc)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002267 })
2268 .context("In store_new_key.")
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002269 }
2270
Janis Danisevskis377d1002021-01-27 19:07:48 -08002271 /// Store a new certificate
2272 /// The function creates a new key entry, populates the blob field and metadata, and rebinds
2273 /// the given alias to the new cert.
Max Bires8e93d2b2021-01-14 13:17:59 -08002274 pub fn store_new_certificate(
2275 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002276 key: &KeyDescriptor,
Max Bires8e93d2b2021-01-14 13:17:59 -08002277 cert: &[u8],
2278 km_uuid: &Uuid,
2279 ) -> Result<KeyIdGuard> {
Janis Danisevskis850d4862021-05-05 08:41:14 -07002280 let _wp = wd::watch_millis("KeystoreDB::store_new_certificate", 500);
2281
Janis Danisevskis377d1002021-01-27 19:07:48 -08002282 let (alias, domain, namespace) = match key {
2283 KeyDescriptor { alias: Some(alias), domain: Domain::APP, nspace, blob: None }
2284 | KeyDescriptor { alias: Some(alias), domain: Domain::SELINUX, nspace, blob: None } => {
2285 (alias, key.domain, nspace)
2286 }
2287 _ => {
2288 return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT)).context(
2289 "In store_new_certificate: Need alias and domain must be APP or SELINUX.",
2290 )
2291 }
2292 };
2293 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002294 let key_id = Self::create_key_entry_internal(tx, &domain, namespace, km_uuid)
Janis Danisevskis377d1002021-01-27 19:07:48 -08002295 .context("Trying to create new key entry.")?;
2296
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002297 Self::set_blob_internal(
2298 tx,
2299 key_id.id(),
2300 SubComponentType::CERT_CHAIN,
2301 Some(cert),
2302 None,
2303 )
2304 .context("Trying to insert certificate.")?;
Janis Danisevskis377d1002021-01-27 19:07:48 -08002305
2306 let mut metadata = KeyMetaData::new();
2307 metadata.add(KeyMetaEntry::CreationDate(
2308 DateTime::now().context("Trying to make creation time.")?,
2309 ));
2310
2311 metadata.store_in_db(key_id.id(), tx).context("Trying to insert key metadata.")?;
2312
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002313 let need_gc = Self::rebind_alias(tx, &key_id, &alias, &domain, namespace)
Janis Danisevskis377d1002021-01-27 19:07:48 -08002314 .context("Trying to rebind alias.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002315 Ok(key_id).do_gc(need_gc)
Janis Danisevskis377d1002021-01-27 19:07:48 -08002316 })
2317 .context("In store_new_certificate.")
2318 }
2319
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002320 // Helper function loading the key_id given the key descriptor
2321 // tuple comprising domain, namespace, and alias.
2322 // Requires a valid transaction.
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002323 fn load_key_entry_id(tx: &Transaction, key: &KeyDescriptor, key_type: KeyType) -> Result<i64> {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002324 let alias = key
2325 .alias
2326 .as_ref()
2327 .map_or_else(|| Err(KsError::sys()), Ok)
2328 .context("In load_key_entry_id: Alias must be specified.")?;
2329 let mut stmt = tx
2330 .prepare(
2331 "SELECT id FROM persistent.keyentry
2332 WHERE
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00002333 key_type = ?
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002334 AND domain = ?
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002335 AND namespace = ?
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002336 AND alias = ?
2337 AND state = ?;",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002338 )
2339 .context("In load_key_entry_id: Failed to select from keyentry table.")?;
2340 let mut rows = stmt
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002341 .query(params![key_type, key.domain.0 as u32, key.nspace, alias, KeyLifeCycle::Live])
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002342 .context("In load_key_entry_id: Failed to read from keyentry table.")?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002343 db_utils::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002344 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002345 .get(0)
2346 .context("Failed to unpack id.")
2347 })
2348 .context("In load_key_entry_id.")
2349 }
2350
2351 /// This helper function completes the access tuple of a key, which is required
2352 /// to perform access control. The strategy depends on the `domain` field in the
2353 /// key descriptor.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002354 /// * Domain::SELINUX: The access tuple is complete and this function only loads
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002355 /// the key_id for further processing.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002356 /// * Domain::APP: Like Domain::SELINUX, but the tuple is completed by `caller_uid`
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002357 /// which serves as the namespace.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002358 /// * Domain::GRANT: The grant table is queried for the `key_id` and the
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002359 /// `access_vector`.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002360 /// * Domain::KEY_ID: The keyentry table is queried for the owning `domain` and
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002361 /// `namespace`.
2362 /// In each case the information returned is sufficient to perform the access
2363 /// check and the key id can be used to load further key artifacts.
2364 fn load_access_tuple(
2365 tx: &Transaction,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002366 key: &KeyDescriptor,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002367 key_type: KeyType,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002368 caller_uid: u32,
2369 ) -> Result<(i64, KeyDescriptor, Option<KeyPermSet>)> {
2370 match key.domain {
2371 // Domain App or SELinux. In this case we load the key_id from
2372 // the keyentry database for further loading of key components.
2373 // We already have the full access tuple to perform access control.
2374 // The only distinction is that we use the caller_uid instead
2375 // of the caller supplied namespace if the domain field is
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002376 // Domain::APP.
2377 Domain::APP | Domain::SELINUX => {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002378 let mut access_key = key.clone();
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002379 if access_key.domain == Domain::APP {
2380 access_key.nspace = caller_uid as i64;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002381 }
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002382 let key_id = Self::load_key_entry_id(&tx, &access_key, key_type)
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002383 .with_context(|| format!("With key.domain = {:?}.", access_key.domain))?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002384
2385 Ok((key_id, access_key, None))
2386 }
2387
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002388 // Domain::GRANT. In this case we load the key_id and the access_vector
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002389 // from the grant table.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002390 Domain::GRANT => {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002391 let mut stmt = tx
2392 .prepare(
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002393 "SELECT keyentryid, access_vector FROM persistent.grant
Hasini Gunasinghee70a0ec2021-05-10 21:12:34 +00002394 WHERE grantee = ? AND id = ? AND
2395 (SELECT state FROM persistent.keyentry WHERE id = keyentryid) = ?;",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002396 )
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002397 .context("Domain::GRANT prepare statement failed")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002398 let mut rows = stmt
Hasini Gunasinghee70a0ec2021-05-10 21:12:34 +00002399 .query(params![caller_uid as i64, key.nspace, KeyLifeCycle::Live])
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002400 .context("Domain:Grant: query failed.")?;
2401 let (key_id, access_vector): (i64, i32) =
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002402 db_utils::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002403 let r =
2404 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002405 Ok((
2406 r.get(0).context("Failed to unpack key_id.")?,
2407 r.get(1).context("Failed to unpack access_vector.")?,
2408 ))
2409 })
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002410 .context("Domain::GRANT.")?;
Janis Danisevskis66784c42021-01-27 08:40:25 -08002411 Ok((key_id, key.clone(), Some(access_vector.into())))
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002412 }
2413
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002414 // Domain::KEY_ID. In this case we load the domain and namespace from the
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002415 // keyentry database because we need them for access control.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002416 Domain::KEY_ID => {
Janis Danisevskis45760022021-01-19 16:34:10 -08002417 let (domain, namespace): (Domain, i64) = {
2418 let mut stmt = tx
2419 .prepare(
2420 "SELECT domain, namespace FROM persistent.keyentry
2421 WHERE
2422 id = ?
2423 AND state = ?;",
2424 )
2425 .context("Domain::KEY_ID: prepare statement failed")?;
2426 let mut rows = stmt
2427 .query(params![key.nspace, KeyLifeCycle::Live])
2428 .context("Domain::KEY_ID: query failed.")?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002429 db_utils::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002430 let r =
2431 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002432 Ok((
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002433 Domain(r.get(0).context("Failed to unpack domain.")?),
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002434 r.get(1).context("Failed to unpack namespace.")?,
2435 ))
2436 })
Janis Danisevskis45760022021-01-19 16:34:10 -08002437 .context("Domain::KEY_ID.")?
2438 };
2439
2440 // We may use a key by id after loading it by grant.
2441 // In this case we have to check if the caller has a grant for this particular
2442 // key. We can skip this if we already know that the caller is the owner.
2443 // But we cannot know this if domain is anything but App. E.g. in the case
2444 // of Domain::SELINUX we have to speculatively check for grants because we have to
2445 // consult the SEPolicy before we know if the caller is the owner.
2446 let access_vector: Option<KeyPermSet> =
2447 if domain != Domain::APP || namespace != caller_uid as i64 {
2448 let access_vector: Option<i32> = tx
2449 .query_row(
2450 "SELECT access_vector FROM persistent.grant
2451 WHERE grantee = ? AND keyentryid = ?;",
2452 params![caller_uid as i64, key.nspace],
2453 |row| row.get(0),
2454 )
2455 .optional()
2456 .context("Domain::KEY_ID: query grant failed.")?;
2457 access_vector.map(|p| p.into())
2458 } else {
2459 None
2460 };
2461
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002462 let key_id = key.nspace;
Janis Danisevskis66784c42021-01-27 08:40:25 -08002463 let mut access_key: KeyDescriptor = key.clone();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002464 access_key.domain = domain;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002465 access_key.nspace = namespace;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002466
Janis Danisevskis45760022021-01-19 16:34:10 -08002467 Ok((key_id, access_key, access_vector))
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002468 }
2469 _ => Err(anyhow!(KsError::sys())),
2470 }
2471 }
2472
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002473 fn load_blob_components(
2474 key_id: i64,
2475 load_bits: KeyEntryLoadBits,
2476 tx: &Transaction,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002477 ) -> Result<(bool, Option<(Vec<u8>, BlobMetaData)>, Option<Vec<u8>>, Option<Vec<u8>>)> {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002478 let mut stmt = tx
2479 .prepare(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002480 "SELECT MAX(id), subcomponent_type, blob FROM persistent.blobentry
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002481 WHERE keyentryid = ? GROUP BY subcomponent_type;",
2482 )
2483 .context("In load_blob_components: prepare statement failed.")?;
2484
2485 let mut rows =
2486 stmt.query(params![key_id]).context("In load_blob_components: query failed.")?;
2487
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002488 let mut key_blob: Option<(i64, Vec<u8>)> = None;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002489 let mut cert_blob: Option<Vec<u8>> = None;
2490 let mut cert_chain_blob: Option<Vec<u8>> = None;
Janis Danisevskis377d1002021-01-27 19:07:48 -08002491 let mut has_km_blob: bool = false;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002492 db_utils::with_rows_extract_all(&mut rows, |row| {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002493 let sub_type: SubComponentType =
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002494 row.get(1).context("Failed to extract subcomponent_type.")?;
Janis Danisevskis377d1002021-01-27 19:07:48 -08002495 has_km_blob = has_km_blob || sub_type == SubComponentType::KEY_BLOB;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002496 match (sub_type, load_bits.load_public(), load_bits.load_km()) {
2497 (SubComponentType::KEY_BLOB, _, true) => {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002498 key_blob = Some((
2499 row.get(0).context("Failed to extract key blob id.")?,
2500 row.get(2).context("Failed to extract key blob.")?,
2501 ));
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002502 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002503 (SubComponentType::CERT, true, _) => {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002504 cert_blob =
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002505 Some(row.get(2).context("Failed to extract public certificate blob.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002506 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002507 (SubComponentType::CERT_CHAIN, true, _) => {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002508 cert_chain_blob =
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002509 Some(row.get(2).context("Failed to extract certificate chain blob.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002510 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002511 (SubComponentType::CERT, _, _)
2512 | (SubComponentType::CERT_CHAIN, _, _)
2513 | (SubComponentType::KEY_BLOB, _, _) => {}
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002514 _ => Err(KsError::sys()).context("Unknown subcomponent type.")?,
2515 }
2516 Ok(())
2517 })
2518 .context("In load_blob_components.")?;
2519
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002520 let blob_info = key_blob.map_or::<Result<_>, _>(Ok(None), |(blob_id, blob)| {
2521 Ok(Some((
2522 blob,
2523 BlobMetaData::load_from_db(blob_id, tx)
2524 .context("In load_blob_components: Trying to load blob_metadata.")?,
2525 )))
2526 })?;
2527
2528 Ok((has_km_blob, blob_info, cert_blob, cert_chain_blob))
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002529 }
2530
2531 fn load_key_parameters(key_id: i64, tx: &Transaction) -> Result<Vec<KeyParameter>> {
2532 let mut stmt = tx
2533 .prepare(
2534 "SELECT tag, data, security_level from persistent.keyparameter
2535 WHERE keyentryid = ?;",
2536 )
2537 .context("In load_key_parameters: prepare statement failed.")?;
2538
2539 let mut parameters: Vec<KeyParameter> = Vec::new();
2540
2541 let mut rows =
2542 stmt.query(params![key_id]).context("In load_key_parameters: query failed.")?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002543 db_utils::with_rows_extract_all(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002544 let tag = Tag(row.get(0).context("Failed to read tag.")?);
2545 let sec_level = SecurityLevel(row.get(2).context("Failed to read sec_level.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002546 parameters.push(
2547 KeyParameter::new_from_sql(tag, &SqlField::new(1, &row), sec_level)
2548 .context("Failed to read KeyParameter.")?,
2549 );
2550 Ok(())
2551 })
2552 .context("In load_key_parameters.")?;
2553
2554 Ok(parameters)
2555 }
2556
Qi Wub9433b52020-12-01 14:52:46 +08002557 /// Decrements the usage count of a limited use key. This function first checks whether the
2558 /// usage has been exhausted, if not, decreases the usage count. If the usage count reaches
2559 /// zero, the key also gets marked unreferenced and scheduled for deletion.
2560 /// Returns Ok(true) if the key was marked unreferenced as a hint to the garbage collector.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002561 pub fn check_and_update_key_usage_count(&mut self, key_id: i64) -> Result<()> {
Janis Danisevskis850d4862021-05-05 08:41:14 -07002562 let _wp = wd::watch_millis("KeystoreDB::check_and_update_key_usage_count", 500);
2563
Qi Wub9433b52020-12-01 14:52:46 +08002564 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2565 let limit: Option<i32> = tx
2566 .query_row(
2567 "SELECT data FROM persistent.keyparameter WHERE keyentryid = ? AND tag = ?;",
2568 params![key_id, Tag::USAGE_COUNT_LIMIT.0],
2569 |row| row.get(0),
2570 )
2571 .optional()
2572 .context("Trying to load usage count")?;
2573
2574 let limit = limit
2575 .ok_or(KsError::Km(ErrorCode::INVALID_KEY_BLOB))
2576 .context("The Key no longer exists. Key is exhausted.")?;
2577
2578 tx.execute(
2579 "UPDATE persistent.keyparameter
2580 SET data = data - 1
2581 WHERE keyentryid = ? AND tag = ? AND data > 0;",
2582 params![key_id, Tag::USAGE_COUNT_LIMIT.0],
2583 )
2584 .context("Failed to update key usage count.")?;
2585
2586 match limit {
2587 1 => Self::mark_unreferenced(tx, key_id)
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002588 .map(|need_gc| (need_gc, ()))
Qi Wub9433b52020-12-01 14:52:46 +08002589 .context("Trying to mark limited use key for deletion."),
2590 0 => Err(KsError::Km(ErrorCode::INVALID_KEY_BLOB)).context("Key is exhausted."),
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002591 _ => Ok(()).no_gc(),
Qi Wub9433b52020-12-01 14:52:46 +08002592 }
2593 })
2594 .context("In check_and_update_key_usage_count.")
2595 }
2596
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002597 /// Load a key entry by the given key descriptor.
2598 /// It uses the `check_permission` callback to verify if the access is allowed
2599 /// given the key access tuple read from the database using `load_access_tuple`.
2600 /// With `load_bits` the caller may specify which blobs shall be loaded from
2601 /// the blob database.
2602 pub fn load_key_entry(
2603 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002604 key: &KeyDescriptor,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002605 key_type: KeyType,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002606 load_bits: KeyEntryLoadBits,
2607 caller_uid: u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002608 check_permission: impl Fn(&KeyDescriptor, Option<KeyPermSet>) -> Result<()>,
2609 ) -> Result<(KeyIdGuard, KeyEntry)> {
Janis Danisevskis850d4862021-05-05 08:41:14 -07002610 let _wp = wd::watch_millis("KeystoreDB::load_key_entry", 500);
2611
Janis Danisevskis66784c42021-01-27 08:40:25 -08002612 loop {
2613 match self.load_key_entry_internal(
2614 key,
2615 key_type,
2616 load_bits,
2617 caller_uid,
2618 &check_permission,
2619 ) {
2620 Ok(result) => break Ok(result),
2621 Err(e) => {
2622 if Self::is_locked_error(&e) {
2623 std::thread::sleep(std::time::Duration::from_micros(500));
2624 continue;
2625 } else {
2626 return Err(e).context("In load_key_entry.");
2627 }
2628 }
2629 }
2630 }
2631 }
2632
2633 fn load_key_entry_internal(
2634 &mut self,
2635 key: &KeyDescriptor,
2636 key_type: KeyType,
2637 load_bits: KeyEntryLoadBits,
2638 caller_uid: u32,
2639 check_permission: &impl Fn(&KeyDescriptor, Option<KeyPermSet>) -> Result<()>,
Janis Danisevskisaec14592020-11-12 09:41:49 -08002640 ) -> Result<(KeyIdGuard, KeyEntry)> {
2641 // KEY ID LOCK 1/2
2642 // If we got a key descriptor with a key id we can get the lock right away.
2643 // Otherwise we have to defer it until we know the key id.
2644 let key_id_guard = match key.domain {
2645 Domain::KEY_ID => Some(KEY_ID_LOCK.get(key.nspace)),
2646 _ => None,
2647 };
2648
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002649 let tx = self
2650 .conn
Janis Danisevskisaec14592020-11-12 09:41:49 -08002651 .unchecked_transaction()
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002652 .context("In load_key_entry: Failed to initialize transaction.")?;
2653
2654 // Load the key_id and complete the access control tuple.
2655 let (key_id, access_key_descriptor, access_vector) =
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002656 Self::load_access_tuple(&tx, key, key_type, caller_uid)
2657 .context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002658
2659 // Perform access control. It is vital that we return here if the permission is denied.
2660 // So do not touch that '?' at the end.
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002661 check_permission(&access_key_descriptor, access_vector).context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002662
Janis Danisevskisaec14592020-11-12 09:41:49 -08002663 // KEY ID LOCK 2/2
2664 // If we did not get a key id lock by now, it was because we got a key descriptor
2665 // without a key id. At this point we got the key id, so we can try and get a lock.
2666 // However, we cannot block here, because we are in the middle of the transaction.
2667 // So first we try to get the lock non blocking. If that fails, we roll back the
2668 // transaction and block until we get the lock. After we successfully got the lock,
2669 // we start a new transaction and load the access tuple again.
2670 //
2671 // We don't need to perform access control again, because we already established
2672 // that the caller had access to the given key. But we need to make sure that the
2673 // key id still exists. So we have to load the key entry by key id this time.
2674 let (key_id_guard, tx) = match key_id_guard {
2675 None => match KEY_ID_LOCK.try_get(key_id) {
2676 None => {
2677 // Roll back the transaction.
2678 tx.rollback().context("In load_key_entry: Failed to roll back transaction.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002679
Janis Danisevskisaec14592020-11-12 09:41:49 -08002680 // Block until we have a key id lock.
2681 let key_id_guard = KEY_ID_LOCK.get(key_id);
2682
2683 // Create a new transaction.
Janis Danisevskis66784c42021-01-27 08:40:25 -08002684 let tx = self
2685 .conn
2686 .unchecked_transaction()
2687 .context("In load_key_entry: Failed to initialize transaction.")?;
Janis Danisevskisaec14592020-11-12 09:41:49 -08002688
2689 Self::load_access_tuple(
2690 &tx,
2691 // This time we have to load the key by the retrieved key id, because the
2692 // alias may have been rebound after we rolled back the transaction.
Janis Danisevskis66784c42021-01-27 08:40:25 -08002693 &KeyDescriptor {
Janis Danisevskisaec14592020-11-12 09:41:49 -08002694 domain: Domain::KEY_ID,
2695 nspace: key_id,
2696 ..Default::default()
2697 },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002698 key_type,
Janis Danisevskisaec14592020-11-12 09:41:49 -08002699 caller_uid,
2700 )
2701 .context("In load_key_entry. (deferred key lock)")?;
2702 (key_id_guard, tx)
2703 }
2704 Some(l) => (l, tx),
2705 },
2706 Some(key_id_guard) => (key_id_guard, tx),
2707 };
2708
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002709 let key_entry = Self::load_key_components(&tx, load_bits, key_id_guard.id())
2710 .context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002711
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002712 tx.commit().context("In load_key_entry: Failed to commit transaction.")?;
2713
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002714 Ok((key_id_guard, key_entry))
2715 }
2716
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002717 fn mark_unreferenced(tx: &Transaction, key_id: i64) -> Result<bool> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002718 let updated = tx
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002719 .execute("DELETE FROM persistent.keyentry WHERE id = ?;", params![key_id])
2720 .context("Trying to delete keyentry.")?;
2721 tx.execute("DELETE FROM persistent.keymetadata WHERE keyentryid = ?;", params![key_id])
2722 .context("Trying to delete keymetadata.")?;
2723 tx.execute("DELETE FROM persistent.keyparameter WHERE keyentryid = ?;", params![key_id])
2724 .context("Trying to delete keyparameters.")?;
2725 tx.execute("DELETE FROM persistent.grant WHERE keyentryid = ?;", params![key_id])
2726 .context("Trying to delete grants.")?;
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002727 Ok(updated != 0)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002728 }
2729
2730 /// Marks the given key as unreferenced and removes all of the grants to this key.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002731 /// Returns Ok(true) if a key was marked unreferenced as a hint for the garbage collector.
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002732 pub fn unbind_key(
2733 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002734 key: &KeyDescriptor,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002735 key_type: KeyType,
2736 caller_uid: u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002737 check_permission: impl Fn(&KeyDescriptor, Option<KeyPermSet>) -> Result<()>,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002738 ) -> Result<()> {
Janis Danisevskis850d4862021-05-05 08:41:14 -07002739 let _wp = wd::watch_millis("KeystoreDB::unbind_key", 500);
2740
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002741 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2742 let (key_id, access_key_descriptor, access_vector) =
2743 Self::load_access_tuple(tx, key, key_type, caller_uid)
2744 .context("Trying to get access tuple.")?;
2745
2746 // Perform access control. It is vital that we return here if the permission is denied.
2747 // So do not touch that '?' at the end.
2748 check_permission(&access_key_descriptor, access_vector)
2749 .context("While checking permission.")?;
2750
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002751 Self::mark_unreferenced(tx, key_id)
2752 .map(|need_gc| (need_gc, ()))
2753 .context("Trying to mark the key unreferenced.")
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002754 })
2755 .context("In unbind_key.")
2756 }
2757
Max Bires8e93d2b2021-01-14 13:17:59 -08002758 fn get_key_km_uuid(tx: &Transaction, key_id: i64) -> Result<Uuid> {
2759 tx.query_row(
2760 "SELECT km_uuid FROM persistent.keyentry WHERE id = ?",
2761 params![key_id],
2762 |row| row.get(0),
2763 )
2764 .context("In get_key_km_uuid.")
2765 }
2766
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002767 /// Delete all artifacts belonging to the namespace given by the domain-namespace tuple.
2768 /// This leaves all of the blob entries orphaned for subsequent garbage collection.
2769 pub fn unbind_keys_for_namespace(&mut self, domain: Domain, namespace: i64) -> Result<()> {
Janis Danisevskis850d4862021-05-05 08:41:14 -07002770 let _wp = wd::watch_millis("KeystoreDB::unbind_keys_for_namespace", 500);
2771
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002772 if !(domain == Domain::APP || domain == Domain::SELINUX) {
2773 return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT))
2774 .context("In unbind_keys_for_namespace.");
2775 }
2776 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2777 tx.execute(
2778 "DELETE FROM persistent.keymetadata
2779 WHERE keyentryid IN (
2780 SELECT id FROM persistent.keyentry
Janis Danisevskisb146f312021-05-06 15:05:45 -07002781 WHERE domain = ? AND namespace = ? AND key_type = ?
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002782 );",
Janis Danisevskisb146f312021-05-06 15:05:45 -07002783 params![domain.0, namespace, KeyType::Client],
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002784 )
2785 .context("Trying to delete keymetadata.")?;
2786 tx.execute(
2787 "DELETE FROM persistent.keyparameter
2788 WHERE keyentryid IN (
2789 SELECT id FROM persistent.keyentry
Janis Danisevskisb146f312021-05-06 15:05:45 -07002790 WHERE domain = ? AND namespace = ? AND key_type = ?
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002791 );",
Janis Danisevskisb146f312021-05-06 15:05:45 -07002792 params![domain.0, namespace, KeyType::Client],
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002793 )
2794 .context("Trying to delete keyparameters.")?;
2795 tx.execute(
2796 "DELETE FROM persistent.grant
2797 WHERE keyentryid IN (
2798 SELECT id FROM persistent.keyentry
Janis Danisevskisb146f312021-05-06 15:05:45 -07002799 WHERE domain = ? AND namespace = ? AND key_type = ?
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002800 );",
Janis Danisevskisb146f312021-05-06 15:05:45 -07002801 params![domain.0, namespace, KeyType::Client],
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002802 )
2803 .context("Trying to delete grants.")?;
2804 tx.execute(
Janis Danisevskisb146f312021-05-06 15:05:45 -07002805 "DELETE FROM persistent.keyentry
2806 WHERE domain = ? AND namespace = ? AND key_type = ?;",
2807 params![domain.0, namespace, KeyType::Client],
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002808 )
2809 .context("Trying to delete keyentry.")?;
2810 Ok(()).need_gc()
2811 })
2812 .context("In unbind_keys_for_namespace")
2813 }
2814
Janis Danisevskis3cba10d2021-05-06 17:02:19 -07002815 fn cleanup_unreferenced(tx: &Transaction) -> Result<()> {
2816 let _wp = wd::watch_millis("KeystoreDB::cleanup_unreferenced", 500);
2817 {
2818 tx.execute(
2819 "DELETE FROM persistent.keymetadata
2820 WHERE keyentryid IN (
2821 SELECT id FROM persistent.keyentry
2822 WHERE state = ?
2823 );",
2824 params![KeyLifeCycle::Unreferenced],
2825 )
2826 .context("Trying to delete keymetadata.")?;
2827 tx.execute(
2828 "DELETE FROM persistent.keyparameter
2829 WHERE keyentryid IN (
2830 SELECT id FROM persistent.keyentry
2831 WHERE state = ?
2832 );",
2833 params![KeyLifeCycle::Unreferenced],
2834 )
2835 .context("Trying to delete keyparameters.")?;
2836 tx.execute(
2837 "DELETE FROM persistent.grant
2838 WHERE keyentryid IN (
2839 SELECT id FROM persistent.keyentry
2840 WHERE state = ?
2841 );",
2842 params![KeyLifeCycle::Unreferenced],
2843 )
2844 .context("Trying to delete grants.")?;
2845 tx.execute(
2846 "DELETE FROM persistent.keyentry
2847 WHERE state = ?;",
2848 params![KeyLifeCycle::Unreferenced],
2849 )
2850 .context("Trying to delete keyentry.")?;
2851 Result::<()>::Ok(())
2852 }
2853 .context("In cleanup_unreferenced")
2854 }
2855
Hasini Gunasingheda895552021-01-27 19:34:37 +00002856 /// Delete the keys created on behalf of the user, denoted by the user id.
2857 /// Delete all the keys unless 'keep_non_super_encrypted_keys' set to true.
2858 /// Returned boolean is to hint the garbage collector to delete the unbound keys.
2859 /// The caller of this function should notify the gc if the returned value is true.
2860 pub fn unbind_keys_for_user(
2861 &mut self,
2862 user_id: u32,
2863 keep_non_super_encrypted_keys: bool,
2864 ) -> Result<()> {
Janis Danisevskis850d4862021-05-05 08:41:14 -07002865 let _wp = wd::watch_millis("KeystoreDB::unbind_keys_for_user", 500);
2866
Hasini Gunasingheda895552021-01-27 19:34:37 +00002867 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2868 let mut stmt = tx
2869 .prepare(&format!(
2870 "SELECT id from persistent.keyentry
2871 WHERE (
2872 key_type = ?
2873 AND domain = ?
2874 AND cast ( (namespace/{aid_user_offset}) as int) = ?
2875 AND state = ?
2876 ) OR (
2877 key_type = ?
2878 AND namespace = ?
2879 AND alias = ?
2880 AND state = ?
2881 );",
2882 aid_user_offset = AID_USER_OFFSET
2883 ))
2884 .context(concat!(
2885 "In unbind_keys_for_user. ",
2886 "Failed to prepare the query to find the keys created by apps."
2887 ))?;
2888
2889 let mut rows = stmt
2890 .query(params![
2891 // WHERE client key:
2892 KeyType::Client,
2893 Domain::APP.0 as u32,
2894 user_id,
2895 KeyLifeCycle::Live,
2896 // OR super key:
2897 KeyType::Super,
2898 user_id,
Paul Crowley7a658392021-03-18 17:08:20 -07002899 USER_SUPER_KEY.alias,
Hasini Gunasingheda895552021-01-27 19:34:37 +00002900 KeyLifeCycle::Live
2901 ])
2902 .context("In unbind_keys_for_user. Failed to query the keys created by apps.")?;
2903
2904 let mut key_ids: Vec<i64> = Vec::new();
2905 db_utils::with_rows_extract_all(&mut rows, |row| {
2906 key_ids
2907 .push(row.get(0).context("Failed to read key id of a key created by an app.")?);
2908 Ok(())
2909 })
2910 .context("In unbind_keys_for_user.")?;
2911
2912 let mut notify_gc = false;
2913 for key_id in key_ids {
2914 if keep_non_super_encrypted_keys {
2915 // Load metadata and filter out non-super-encrypted keys.
2916 if let (_, Some((_, blob_metadata)), _, _) =
2917 Self::load_blob_components(key_id, KeyEntryLoadBits::KM, tx)
2918 .context("In unbind_keys_for_user: Trying to load blob info.")?
2919 {
2920 if blob_metadata.encrypted_by().is_none() {
2921 continue;
2922 }
2923 }
2924 }
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +00002925 notify_gc = Self::mark_unreferenced(&tx, key_id)
Hasini Gunasingheda895552021-01-27 19:34:37 +00002926 .context("In unbind_keys_for_user.")?
2927 || notify_gc;
2928 }
2929 Ok(()).do_gc(notify_gc)
2930 })
2931 .context("In unbind_keys_for_user.")
2932 }
2933
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002934 fn load_key_components(
2935 tx: &Transaction,
2936 load_bits: KeyEntryLoadBits,
2937 key_id: i64,
2938 ) -> Result<KeyEntry> {
2939 let metadata = KeyMetaData::load_from_db(key_id, &tx).context("In load_key_components.")?;
2940
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002941 let (has_km_blob, key_blob_info, cert_blob, cert_chain_blob) =
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002942 Self::load_blob_components(key_id, load_bits, &tx)
2943 .context("In load_key_components.")?;
2944
Max Bires8e93d2b2021-01-14 13:17:59 -08002945 let parameters = Self::load_key_parameters(key_id, &tx)
2946 .context("In load_key_components: Trying to load key parameters.")?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002947
Max Bires8e93d2b2021-01-14 13:17:59 -08002948 let km_uuid = Self::get_key_km_uuid(&tx, key_id)
2949 .context("In load_key_components: Trying to get KM uuid.")?;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002950
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002951 Ok(KeyEntry {
2952 id: key_id,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002953 key_blob_info,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002954 cert: cert_blob,
2955 cert_chain: cert_chain_blob,
Max Bires8e93d2b2021-01-14 13:17:59 -08002956 km_uuid,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002957 parameters,
2958 metadata,
Janis Danisevskis377d1002021-01-27 19:07:48 -08002959 pure_cert: !has_km_blob,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002960 })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002961 }
2962
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002963 /// Returns a list of KeyDescriptors in the selected domain/namespace.
2964 /// The key descriptors will have the domain, nspace, and alias field set.
2965 /// Domain must be APP or SELINUX, the caller must make sure of that.
2966 pub fn list(&mut self, domain: Domain, namespace: i64) -> Result<Vec<KeyDescriptor>> {
Janis Danisevskis850d4862021-05-05 08:41:14 -07002967 let _wp = wd::watch_millis("KeystoreDB::list", 500);
2968
Janis Danisevskis66784c42021-01-27 08:40:25 -08002969 self.with_transaction(TransactionBehavior::Deferred, |tx| {
2970 let mut stmt = tx
2971 .prepare(
2972 "SELECT alias FROM persistent.keyentry
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002973 WHERE domain = ? AND namespace = ? AND alias IS NOT NULL AND state = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08002974 )
2975 .context("In list: Failed to prepare.")?;
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002976
Janis Danisevskis66784c42021-01-27 08:40:25 -08002977 let mut rows = stmt
2978 .query(params![domain.0 as u32, namespace, KeyLifeCycle::Live])
2979 .context("In list: Failed to query.")?;
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002980
Janis Danisevskis66784c42021-01-27 08:40:25 -08002981 let mut descriptors: Vec<KeyDescriptor> = Vec::new();
2982 db_utils::with_rows_extract_all(&mut rows, |row| {
2983 descriptors.push(KeyDescriptor {
2984 domain,
2985 nspace: namespace,
2986 alias: Some(row.get(0).context("Trying to extract alias.")?),
2987 blob: None,
2988 });
2989 Ok(())
2990 })
2991 .context("In list: Failed to extract rows.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002992 Ok(descriptors).no_gc()
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002993 })
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002994 }
2995
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002996 /// Adds a grant to the grant table.
2997 /// Like `load_key_entry` this function loads the access tuple before
2998 /// it uses the callback for a permission check. Upon success,
2999 /// it inserts the `grantee_uid`, `key_id`, and `access_vector` into the
3000 /// grant table. The new row will have a randomized id, which is used as
3001 /// grant id in the namespace field of the resulting KeyDescriptor.
3002 pub fn grant(
3003 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08003004 key: &KeyDescriptor,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003005 caller_uid: u32,
3006 grantee_uid: u32,
3007 access_vector: KeyPermSet,
Janis Danisevskis66784c42021-01-27 08:40:25 -08003008 check_permission: impl Fn(&KeyDescriptor, &KeyPermSet) -> Result<()>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003009 ) -> Result<KeyDescriptor> {
Janis Danisevskis850d4862021-05-05 08:41:14 -07003010 let _wp = wd::watch_millis("KeystoreDB::grant", 500);
3011
Janis Danisevskis66784c42021-01-27 08:40:25 -08003012 self.with_transaction(TransactionBehavior::Immediate, |tx| {
3013 // Load the key_id and complete the access control tuple.
3014 // We ignore the access vector here because grants cannot be granted.
3015 // The access vector returned here expresses the permissions the
3016 // grantee has if key.domain == Domain::GRANT. But this vector
3017 // cannot include the grant permission by design, so there is no way the
3018 // subsequent permission check can pass.
3019 // We could check key.domain == Domain::GRANT and fail early.
3020 // But even if we load the access tuple by grant here, the permission
3021 // check denies the attempt to create a grant by grant descriptor.
3022 let (key_id, access_key_descriptor, _) =
3023 Self::load_access_tuple(&tx, key, KeyType::Client, caller_uid)
3024 .context("In grant")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003025
Janis Danisevskis66784c42021-01-27 08:40:25 -08003026 // Perform access control. It is vital that we return here if the permission
3027 // was denied. So do not touch that '?' at the end of the line.
3028 // This permission check checks if the caller has the grant permission
3029 // for the given key and in addition to all of the permissions
3030 // expressed in `access_vector`.
3031 check_permission(&access_key_descriptor, &access_vector)
3032 .context("In grant: check_permission failed.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003033
Janis Danisevskis66784c42021-01-27 08:40:25 -08003034 let grant_id = if let Some(grant_id) = tx
3035 .query_row(
3036 "SELECT id FROM persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003037 WHERE keyentryid = ? AND grantee = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08003038 params![key_id, grantee_uid],
3039 |row| row.get(0),
3040 )
3041 .optional()
3042 .context("In grant: Failed get optional existing grant id.")?
3043 {
3044 tx.execute(
3045 "UPDATE persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003046 SET access_vector = ?
3047 WHERE id = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08003048 params![i32::from(access_vector), grant_id],
Joel Galenson845f74b2020-09-09 14:11:55 -07003049 )
Janis Danisevskis66784c42021-01-27 08:40:25 -08003050 .context("In grant: Failed to update existing grant.")?;
3051 grant_id
3052 } else {
3053 Self::insert_with_retry(|id| {
3054 tx.execute(
3055 "INSERT INTO persistent.grant (id, grantee, keyentryid, access_vector)
3056 VALUES (?, ?, ?, ?);",
3057 params![id, grantee_uid, key_id, i32::from(access_vector)],
3058 )
3059 })
3060 .context("In grant")?
3061 };
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003062
Janis Danisevskis66784c42021-01-27 08:40:25 -08003063 Ok(KeyDescriptor { domain: Domain::GRANT, nspace: grant_id, alias: None, blob: None })
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003064 .no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08003065 })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003066 }
3067
3068 /// This function checks permissions like `grant` and `load_key_entry`
3069 /// before removing a grant from the grant table.
3070 pub fn ungrant(
3071 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08003072 key: &KeyDescriptor,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003073 caller_uid: u32,
3074 grantee_uid: u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08003075 check_permission: impl Fn(&KeyDescriptor) -> Result<()>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003076 ) -> Result<()> {
Janis Danisevskis850d4862021-05-05 08:41:14 -07003077 let _wp = wd::watch_millis("KeystoreDB::ungrant", 500);
3078
Janis Danisevskis66784c42021-01-27 08:40:25 -08003079 self.with_transaction(TransactionBehavior::Immediate, |tx| {
3080 // Load the key_id and complete the access control tuple.
3081 // We ignore the access vector here because grants cannot be granted.
3082 let (key_id, access_key_descriptor, _) =
3083 Self::load_access_tuple(&tx, key, KeyType::Client, caller_uid)
3084 .context("In ungrant.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003085
Janis Danisevskis66784c42021-01-27 08:40:25 -08003086 // Perform access control. We must return here if the permission
3087 // was denied. So do not touch the '?' at the end of this line.
3088 check_permission(&access_key_descriptor)
3089 .context("In grant: check_permission failed.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003090
Janis Danisevskis66784c42021-01-27 08:40:25 -08003091 tx.execute(
3092 "DELETE FROM persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003093 WHERE keyentryid = ? AND grantee = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08003094 params![key_id, grantee_uid],
3095 )
3096 .context("Failed to delete grant.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003097
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003098 Ok(()).no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08003099 })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003100 }
3101
Joel Galenson845f74b2020-09-09 14:11:55 -07003102 // Generates a random id and passes it to the given function, which will
3103 // try to insert it into a database. If that insertion fails, retry;
3104 // otherwise return the id.
3105 fn insert_with_retry(inserter: impl Fn(i64) -> rusqlite::Result<usize>) -> Result<i64> {
3106 loop {
Janis Danisevskiseed69842021-02-18 20:04:10 -08003107 let newid: i64 = match random() {
3108 Self::UNASSIGNED_KEY_ID => continue, // UNASSIGNED_KEY_ID cannot be assigned.
3109 i => i,
3110 };
Joel Galenson845f74b2020-09-09 14:11:55 -07003111 match inserter(newid) {
3112 // If the id already existed, try again.
3113 Err(rusqlite::Error::SqliteFailure(
3114 libsqlite3_sys::Error {
3115 code: libsqlite3_sys::ErrorCode::ConstraintViolation,
3116 extended_code: libsqlite3_sys::SQLITE_CONSTRAINT_UNIQUE,
3117 },
3118 _,
3119 )) => (),
3120 Err(e) => {
3121 return Err(e).context("In insert_with_retry: failed to insert into database.")
3122 }
3123 _ => return Ok(newid),
3124 }
3125 }
3126 }
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00003127
Matthew Maurerd7815ca2021-05-06 21:58:45 -07003128 /// Insert or replace the auth token based on (user_id, auth_id, auth_type)
3129 pub fn insert_auth_token(&mut self, auth_token: &HardwareAuthToken) {
3130 self.perboot.insert_auth_token_entry(AuthTokenEntry::new(
3131 auth_token.clone(),
3132 MonotonicRawTime::now(),
3133 ))
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00003134 }
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00003135
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08003136 /// Find the newest auth token matching the given predicate.
Matthew Maurerd7815ca2021-05-06 21:58:45 -07003137 pub fn find_auth_token_entry<F>(&self, p: F) -> Option<(AuthTokenEntry, MonotonicRawTime)>
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08003138 where
3139 F: Fn(&AuthTokenEntry) -> bool,
3140 {
Matthew Maurerd7815ca2021-05-06 21:58:45 -07003141 self.perboot.find_auth_token_entry(p).map(|entry| (entry, self.get_last_off_body()))
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00003142 }
3143
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08003144 /// Insert last_off_body into the metadata table at the initialization of auth token table
Matthew Maurerd7815ca2021-05-06 21:58:45 -07003145 pub fn insert_last_off_body(&self, last_off_body: MonotonicRawTime) {
3146 self.perboot.set_last_off_body(last_off_body)
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00003147 }
3148
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08003149 /// Update last_off_body when on_device_off_body is called
Matthew Maurerd7815ca2021-05-06 21:58:45 -07003150 pub fn update_last_off_body(&self, last_off_body: MonotonicRawTime) {
3151 self.perboot.set_last_off_body(last_off_body)
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00003152 }
3153
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08003154 /// Get last_off_body time when finding auth tokens
Matthew Maurerd7815ca2021-05-06 21:58:45 -07003155 fn get_last_off_body(&self) -> MonotonicRawTime {
3156 self.perboot.get_last_off_body()
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00003157 }
Joel Galenson26f4d012020-07-17 14:57:21 -07003158}
3159
3160#[cfg(test)]
3161mod tests {
3162
3163 use super::*;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07003164 use crate::key_parameter::{
3165 Algorithm, BlockMode, Digest, EcCurve, HardwareAuthenticatorType, KeyOrigin, KeyParameter,
3166 KeyParameterValue, KeyPurpose, PaddingMode, SecurityLevel,
3167 };
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003168 use crate::key_perm_set;
3169 use crate::permission::{KeyPerm, KeyPermSet};
Hasini Gunasingheda895552021-01-27 19:34:37 +00003170 use crate::super_key::SuperKeyManager;
Janis Danisevskis2a8330a2021-01-20 15:34:26 -08003171 use keystore2_test_utils::TempDir;
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00003172 use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
3173 HardwareAuthToken::HardwareAuthToken,
3174 HardwareAuthenticatorType::HardwareAuthenticatorType as kmhw_authenticator_type,
Janis Danisevskisc3a496b2021-01-05 10:37:22 -08003175 };
3176 use android_hardware_security_secureclock::aidl::android::hardware::security::secureclock::{
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00003177 Timestamp::Timestamp,
3178 };
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003179 use rusqlite::NO_PARAMS;
Matthew Maurerd7815ca2021-05-06 21:58:45 -07003180 use rusqlite::TransactionBehavior;
Joel Galenson0891bc12020-07-20 10:37:03 -07003181 use std::cell::RefCell;
Seth Moore78c091f2021-04-09 21:38:30 +00003182 use std::collections::BTreeMap;
3183 use std::fmt::Write;
Janis Danisevskisaec14592020-11-12 09:41:49 -08003184 use std::sync::atomic::{AtomicU8, Ordering};
3185 use std::sync::Arc;
3186 use std::thread;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00003187 use std::time::{Duration, SystemTime};
Janis Danisevskis66784c42021-01-27 08:40:25 -08003188 #[cfg(disabled)]
3189 use std::time::Instant;
Joel Galenson0891bc12020-07-20 10:37:03 -07003190
Janis Danisevskis4df44f42020-08-26 14:40:03 -07003191 fn new_test_db() -> Result<KeystoreDB> {
Matthew Maurerd7815ca2021-05-06 21:58:45 -07003192 let conn = KeystoreDB::make_connection("file::memory:")?;
Janis Danisevskis4df44f42020-08-26 14:40:03 -07003193
Matthew Maurerd7815ca2021-05-06 21:58:45 -07003194 let mut db = KeystoreDB { conn, gc: None, perboot: Arc::new(perboot::PerbootDB::new()) };
Janis Danisevskis66784c42021-01-27 08:40:25 -08003195 db.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003196 KeystoreDB::init_tables(tx).context("Failed to initialize tables.").no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08003197 })?;
3198 Ok(db)
Janis Danisevskis4df44f42020-08-26 14:40:03 -07003199 }
3200
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003201 fn new_test_db_with_gc<F>(path: &Path, cb: F) -> Result<KeystoreDB>
3202 where
3203 F: Fn(&Uuid, &[u8]) -> Result<()> + Send + 'static,
3204 {
Paul Crowleye8826e52021-03-31 08:33:53 -07003205 let super_key: Arc<SuperKeyManager> = Default::default();
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00003206
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003207 let gc_db = KeystoreDB::new(path, None).expect("Failed to open test gc db_connection.");
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00003208 let gc = Gc::new_init_with(Default::default(), move || (Box::new(cb), gc_db, super_key));
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003209
Janis Danisevskis3395f862021-05-06 10:54:17 -07003210 KeystoreDB::new(path, Some(Arc::new(gc)))
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003211 }
3212
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003213 fn rebind_alias(
3214 db: &mut KeystoreDB,
3215 newid: &KeyIdGuard,
3216 alias: &str,
3217 domain: Domain,
3218 namespace: i64,
3219 ) -> Result<bool> {
3220 db.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003221 KeystoreDB::rebind_alias(tx, newid, alias, &domain, &namespace).no_gc()
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003222 })
3223 .context("In rebind_alias.")
3224 }
3225
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003226 #[test]
3227 fn datetime() -> Result<()> {
3228 let conn = Connection::open_in_memory()?;
3229 conn.execute("CREATE TABLE test (ts DATETIME);", NO_PARAMS)?;
3230 let now = SystemTime::now();
3231 let duration = Duration::from_secs(1000);
3232 let then = now.checked_sub(duration).unwrap();
3233 let soon = now.checked_add(duration).unwrap();
3234 conn.execute(
3235 "INSERT INTO test (ts) VALUES (?), (?), (?);",
3236 params![DateTime::try_from(now)?, DateTime::try_from(then)?, DateTime::try_from(soon)?],
3237 )?;
3238 let mut stmt = conn.prepare("SELECT ts FROM test ORDER BY ts ASC;")?;
3239 let mut rows = stmt.query(NO_PARAMS)?;
3240 assert_eq!(DateTime::try_from(then)?, rows.next()?.unwrap().get(0)?);
3241 assert_eq!(DateTime::try_from(now)?, rows.next()?.unwrap().get(0)?);
3242 assert_eq!(DateTime::try_from(soon)?, rows.next()?.unwrap().get(0)?);
3243 assert!(rows.next()?.is_none());
3244 assert!(DateTime::try_from(then)? < DateTime::try_from(now)?);
3245 assert!(DateTime::try_from(then)? < DateTime::try_from(soon)?);
3246 assert!(DateTime::try_from(now)? < DateTime::try_from(soon)?);
3247 Ok(())
3248 }
3249
Joel Galenson0891bc12020-07-20 10:37:03 -07003250 // Ensure that we're using the "injected" random function, not the real one.
3251 #[test]
3252 fn test_mocked_random() {
3253 let rand1 = random();
3254 let rand2 = random();
3255 let rand3 = random();
3256 if rand1 == rand2 {
3257 assert_eq!(rand2 + 1, rand3);
3258 } else {
3259 assert_eq!(rand1 + 1, rand2);
3260 assert_eq!(rand2, rand3);
3261 }
3262 }
Joel Galenson26f4d012020-07-17 14:57:21 -07003263
Joel Galenson26f4d012020-07-17 14:57:21 -07003264 // Test that we have the correct tables.
3265 #[test]
3266 fn test_tables() -> Result<()> {
Janis Danisevskis4df44f42020-08-26 14:40:03 -07003267 let db = new_test_db()?;
Joel Galenson26f4d012020-07-17 14:57:21 -07003268 let tables = db
3269 .conn
Joel Galenson2aab4432020-07-22 15:27:57 -07003270 .prepare("SELECT name from persistent.sqlite_master WHERE type='table' ORDER BY name;")?
Joel Galenson26f4d012020-07-17 14:57:21 -07003271 .query_map(params![], |row| row.get(0))?
3272 .collect::<rusqlite::Result<Vec<String>>>()?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003273 assert_eq!(tables.len(), 6);
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003274 assert_eq!(tables[0], "blobentry");
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003275 assert_eq!(tables[1], "blobmetadata");
3276 assert_eq!(tables[2], "grant");
3277 assert_eq!(tables[3], "keyentry");
3278 assert_eq!(tables[4], "keymetadata");
3279 assert_eq!(tables[5], "keyparameter");
Joel Galenson2aab4432020-07-22 15:27:57 -07003280 Ok(())
3281 }
3282
3283 #[test]
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00003284 fn test_auth_token_table_invariant() -> Result<()> {
3285 let mut db = new_test_db()?;
3286 let auth_token1 = HardwareAuthToken {
3287 challenge: i64::MAX,
3288 userId: 200,
3289 authenticatorId: 200,
3290 authenticatorType: kmhw_authenticator_type(kmhw_authenticator_type::PASSWORD.0),
3291 timestamp: Timestamp { milliSeconds: 500 },
3292 mac: String::from("mac").into_bytes(),
3293 };
Matthew Maurerd7815ca2021-05-06 21:58:45 -07003294 db.insert_auth_token(&auth_token1);
3295 let auth_tokens_returned = get_auth_tokens(&db);
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00003296 assert_eq!(auth_tokens_returned.len(), 1);
3297
3298 // insert another auth token with the same values for the columns in the UNIQUE constraint
3299 // of the auth token table and different value for timestamp
3300 let auth_token2 = HardwareAuthToken {
3301 challenge: i64::MAX,
3302 userId: 200,
3303 authenticatorId: 200,
3304 authenticatorType: kmhw_authenticator_type(kmhw_authenticator_type::PASSWORD.0),
3305 timestamp: Timestamp { milliSeconds: 600 },
3306 mac: String::from("mac").into_bytes(),
3307 };
3308
Matthew Maurerd7815ca2021-05-06 21:58:45 -07003309 db.insert_auth_token(&auth_token2);
3310 let mut auth_tokens_returned = get_auth_tokens(&db);
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00003311 assert_eq!(auth_tokens_returned.len(), 1);
3312
3313 if let Some(auth_token) = auth_tokens_returned.pop() {
3314 assert_eq!(auth_token.auth_token.timestamp.milliSeconds, 600);
3315 }
3316
3317 // insert another auth token with the different values for the columns in the UNIQUE
3318 // constraint of the auth token table
3319 let auth_token3 = HardwareAuthToken {
3320 challenge: i64::MAX,
3321 userId: 201,
3322 authenticatorId: 200,
3323 authenticatorType: kmhw_authenticator_type(kmhw_authenticator_type::PASSWORD.0),
3324 timestamp: Timestamp { milliSeconds: 600 },
3325 mac: String::from("mac").into_bytes(),
3326 };
3327
Matthew Maurerd7815ca2021-05-06 21:58:45 -07003328 db.insert_auth_token(&auth_token3);
3329 let auth_tokens_returned = get_auth_tokens(&db);
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00003330 assert_eq!(auth_tokens_returned.len(), 2);
3331
3332 Ok(())
3333 }
3334
3335 // utility function for test_auth_token_table_invariant()
Matthew Maurerd7815ca2021-05-06 21:58:45 -07003336 fn get_auth_tokens(db: &KeystoreDB) -> Vec<AuthTokenEntry> {
3337 db.perboot.get_all_auth_token_entries()
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00003338 }
3339
3340 #[test]
Joel Galenson2aab4432020-07-22 15:27:57 -07003341 fn test_persistence_for_files() -> Result<()> {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08003342 let temp_dir = TempDir::new("persistent_db_test")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003343 let mut db = KeystoreDB::new(temp_dir.path(), None)?;
Joel Galenson2aab4432020-07-22 15:27:57 -07003344
Janis Danisevskis66784c42021-01-27 08:40:25 -08003345 db.create_key_entry(&Domain::APP, &100, &KEYSTORE_UUID)?;
Joel Galenson2aab4432020-07-22 15:27:57 -07003346 let entries = get_keyentry(&db)?;
3347 assert_eq!(entries.len(), 1);
Janis Danisevskisbf15d732020-12-08 10:35:26 -08003348
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003349 let db = KeystoreDB::new(temp_dir.path(), None)?;
Joel Galenson2aab4432020-07-22 15:27:57 -07003350
3351 let entries_new = get_keyentry(&db)?;
3352 assert_eq!(entries, entries_new);
3353 Ok(())
3354 }
3355
3356 #[test]
Joel Galenson0891bc12020-07-20 10:37:03 -07003357 fn test_create_key_entry() -> Result<()> {
Max Bires8e93d2b2021-01-14 13:17:59 -08003358 fn extractor(ke: &KeyEntryRow) -> (Domain, i64, Option<&str>, Uuid) {
3359 (ke.domain.unwrap(), ke.namespace.unwrap(), ke.alias.as_deref(), ke.km_uuid.unwrap())
Joel Galenson0891bc12020-07-20 10:37:03 -07003360 }
3361
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003362 let mut db = new_test_db()?;
Joel Galenson0891bc12020-07-20 10:37:03 -07003363
Janis Danisevskis66784c42021-01-27 08:40:25 -08003364 db.create_key_entry(&Domain::APP, &100, &KEYSTORE_UUID)?;
3365 db.create_key_entry(&Domain::SELINUX, &101, &KEYSTORE_UUID)?;
Joel Galenson0891bc12020-07-20 10:37:03 -07003366
3367 let entries = get_keyentry(&db)?;
3368 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08003369 assert_eq!(extractor(&entries[0]), (Domain::APP, 100, None, KEYSTORE_UUID));
3370 assert_eq!(extractor(&entries[1]), (Domain::SELINUX, 101, None, KEYSTORE_UUID));
Joel Galenson0891bc12020-07-20 10:37:03 -07003371
3372 // Test that we must pass in a valid Domain.
3373 check_result_is_error_containing_string(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003374 db.create_key_entry(&Domain::GRANT, &102, &KEYSTORE_UUID),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003375 "Domain Domain(1) must be either App or SELinux.",
Joel Galenson0891bc12020-07-20 10:37:03 -07003376 );
3377 check_result_is_error_containing_string(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003378 db.create_key_entry(&Domain::BLOB, &103, &KEYSTORE_UUID),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003379 "Domain Domain(3) must be either App or SELinux.",
Joel Galenson0891bc12020-07-20 10:37:03 -07003380 );
3381 check_result_is_error_containing_string(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003382 db.create_key_entry(&Domain::KEY_ID, &104, &KEYSTORE_UUID),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003383 "Domain Domain(4) must be either App or SELinux.",
Joel Galenson0891bc12020-07-20 10:37:03 -07003384 );
3385
3386 Ok(())
3387 }
3388
Joel Galenson33c04ad2020-08-03 11:04:38 -07003389 #[test]
Max Bires2b2e6562020-09-22 11:22:36 -07003390 fn test_add_unsigned_key() -> Result<()> {
3391 let mut db = new_test_db()?;
3392 let public_key: Vec<u8> = vec![0x01, 0x02, 0x03];
3393 let private_key: Vec<u8> = vec![0x04, 0x05, 0x06];
3394 let raw_public_key: Vec<u8> = vec![0x07, 0x08, 0x09];
3395 db.create_attestation_key_entry(
3396 &public_key,
3397 &raw_public_key,
3398 &private_key,
3399 &KEYSTORE_UUID,
3400 )?;
3401 let keys = db.fetch_unsigned_attestation_keys(5, &KEYSTORE_UUID)?;
3402 assert_eq!(keys.len(), 1);
3403 assert_eq!(keys[0], public_key);
3404 Ok(())
3405 }
3406
3407 #[test]
3408 fn test_store_signed_attestation_certificate_chain() -> Result<()> {
3409 let mut db = new_test_db()?;
3410 let expiration_date: i64 = 20;
3411 let namespace: i64 = 30;
3412 let base_byte: u8 = 1;
3413 let loaded_values =
3414 load_attestation_key_pool(&mut db, expiration_date, namespace, base_byte)?;
3415 let chain =
3416 db.retrieve_attestation_key_and_cert_chain(Domain::APP, namespace, &KEYSTORE_UUID)?;
3417 assert_eq!(true, chain.is_some());
3418 let cert_chain = chain.unwrap();
Max Biresb2e1d032021-02-08 21:35:05 -08003419 assert_eq!(cert_chain.private_key.to_vec(), loaded_values.priv_key);
Max Bires97f96812021-02-23 23:44:57 -08003420 assert_eq!(cert_chain.batch_cert, loaded_values.batch_cert);
3421 assert_eq!(cert_chain.cert_chain, loaded_values.cert_chain);
Max Bires2b2e6562020-09-22 11:22:36 -07003422 Ok(())
3423 }
3424
3425 #[test]
3426 fn test_get_attestation_pool_status() -> Result<()> {
3427 let mut db = new_test_db()?;
3428 let namespace: i64 = 30;
3429 load_attestation_key_pool(
3430 &mut db, 10, /* expiration */
3431 namespace, 0x01, /* base_byte */
3432 )?;
3433 load_attestation_key_pool(&mut db, 20 /* expiration */, namespace + 1, 0x02)?;
3434 load_attestation_key_pool(&mut db, 40 /* expiration */, namespace + 2, 0x03)?;
3435 let mut status = db.get_attestation_pool_status(9 /* expiration */, &KEYSTORE_UUID)?;
3436 assert_eq!(status.expiring, 0);
3437 assert_eq!(status.attested, 3);
3438 assert_eq!(status.unassigned, 0);
3439 assert_eq!(status.total, 3);
3440 assert_eq!(
3441 db.get_attestation_pool_status(15 /* expiration */, &KEYSTORE_UUID)?.expiring,
3442 1
3443 );
3444 assert_eq!(
3445 db.get_attestation_pool_status(25 /* expiration */, &KEYSTORE_UUID)?.expiring,
3446 2
3447 );
3448 assert_eq!(
3449 db.get_attestation_pool_status(60 /* expiration */, &KEYSTORE_UUID)?.expiring,
3450 3
3451 );
3452 let public_key: Vec<u8> = vec![0x01, 0x02, 0x03];
3453 let private_key: Vec<u8> = vec![0x04, 0x05, 0x06];
3454 let raw_public_key: Vec<u8> = vec![0x07, 0x08, 0x09];
3455 let cert_chain: Vec<u8> = vec![0x0a, 0x0b, 0x0c];
Max Biresb2e1d032021-02-08 21:35:05 -08003456 let batch_cert: Vec<u8> = vec![0x0d, 0x0e, 0x0f];
Max Bires2b2e6562020-09-22 11:22:36 -07003457 db.create_attestation_key_entry(
3458 &public_key,
3459 &raw_public_key,
3460 &private_key,
3461 &KEYSTORE_UUID,
3462 )?;
3463 status = db.get_attestation_pool_status(0 /* expiration */, &KEYSTORE_UUID)?;
3464 assert_eq!(status.attested, 3);
3465 assert_eq!(status.unassigned, 0);
3466 assert_eq!(status.total, 4);
3467 db.store_signed_attestation_certificate_chain(
3468 &raw_public_key,
Max Biresb2e1d032021-02-08 21:35:05 -08003469 &batch_cert,
Max Bires2b2e6562020-09-22 11:22:36 -07003470 &cert_chain,
3471 20,
3472 &KEYSTORE_UUID,
3473 )?;
3474 status = db.get_attestation_pool_status(0 /* expiration */, &KEYSTORE_UUID)?;
3475 assert_eq!(status.attested, 4);
3476 assert_eq!(status.unassigned, 1);
3477 assert_eq!(status.total, 4);
3478 Ok(())
3479 }
3480
3481 #[test]
3482 fn test_remove_expired_certs() -> Result<()> {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003483 let temp_dir =
3484 TempDir::new("test_remove_expired_certs_").expect("Failed to create temp dir.");
3485 let mut db = new_test_db_with_gc(temp_dir.path(), |_, _| Ok(()))?;
Max Bires2b2e6562020-09-22 11:22:36 -07003486 let expiration_date: i64 =
3487 SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_millis() as i64 + 10000;
3488 let namespace: i64 = 30;
3489 let namespace_del1: i64 = 45;
3490 let namespace_del2: i64 = 60;
3491 let entry_values = load_attestation_key_pool(
3492 &mut db,
3493 expiration_date,
3494 namespace,
3495 0x01, /* base_byte */
3496 )?;
3497 load_attestation_key_pool(&mut db, 45, namespace_del1, 0x02)?;
3498 load_attestation_key_pool(&mut db, 60, namespace_del2, 0x03)?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003499
3500 let blob_entry_row_count: u32 = db
3501 .conn
3502 .query_row("SELECT COUNT(id) FROM persistent.blobentry;", NO_PARAMS, |row| row.get(0))
3503 .expect("Failed to get blob entry row count.");
Max Biresb2e1d032021-02-08 21:35:05 -08003504 // We expect 9 rows here because there are three blobs per attestation key, i.e.,
3505 // one key, one certificate chain, and one certificate.
3506 assert_eq!(blob_entry_row_count, 9);
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003507
Max Bires2b2e6562020-09-22 11:22:36 -07003508 assert_eq!(db.delete_expired_attestation_keys()?, 2);
3509
3510 let mut cert_chain =
3511 db.retrieve_attestation_key_and_cert_chain(Domain::APP, namespace, &KEYSTORE_UUID)?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003512 assert!(cert_chain.is_some());
Max Bires2b2e6562020-09-22 11:22:36 -07003513 let value = cert_chain.unwrap();
Max Bires97f96812021-02-23 23:44:57 -08003514 assert_eq!(entry_values.batch_cert, value.batch_cert);
3515 assert_eq!(entry_values.cert_chain, value.cert_chain);
Max Biresb2e1d032021-02-08 21:35:05 -08003516 assert_eq!(entry_values.priv_key, value.private_key.to_vec());
Max Bires2b2e6562020-09-22 11:22:36 -07003517
3518 cert_chain = db.retrieve_attestation_key_and_cert_chain(
3519 Domain::APP,
3520 namespace_del1,
3521 &KEYSTORE_UUID,
3522 )?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003523 assert!(!cert_chain.is_some());
Max Bires2b2e6562020-09-22 11:22:36 -07003524 cert_chain = db.retrieve_attestation_key_and_cert_chain(
3525 Domain::APP,
3526 namespace_del2,
3527 &KEYSTORE_UUID,
3528 )?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003529 assert!(!cert_chain.is_some());
Max Bires2b2e6562020-09-22 11:22:36 -07003530
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003531 // Give the garbage collector half a second to catch up.
3532 std::thread::sleep(Duration::from_millis(500));
Max Bires2b2e6562020-09-22 11:22:36 -07003533
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003534 let blob_entry_row_count: u32 = db
3535 .conn
3536 .query_row("SELECT COUNT(id) FROM persistent.blobentry;", NO_PARAMS, |row| row.get(0))
3537 .expect("Failed to get blob entry row count.");
Max Biresb2e1d032021-02-08 21:35:05 -08003538 // There shound be 3 blob entries left, because we deleted two of the attestation
3539 // key entries with three blobs each.
3540 assert_eq!(blob_entry_row_count, 3);
Max Bires2b2e6562020-09-22 11:22:36 -07003541
Max Bires2b2e6562020-09-22 11:22:36 -07003542 Ok(())
3543 }
3544
3545 #[test]
Max Bires60d7ed12021-03-05 15:59:22 -08003546 fn test_delete_all_attestation_keys() -> Result<()> {
3547 let mut db = new_test_db()?;
3548 load_attestation_key_pool(&mut db, 45 /* expiration */, 1 /* namespace */, 0x02)?;
3549 load_attestation_key_pool(&mut db, 80 /* expiration */, 2 /* namespace */, 0x03)?;
3550 db.create_key_entry(&Domain::APP, &42, &KEYSTORE_UUID)?;
3551 let result = db.delete_all_attestation_keys()?;
3552
3553 // Give the garbage collector half a second to catch up.
3554 std::thread::sleep(Duration::from_millis(500));
3555
3556 // Attestation keys should be deleted, and the regular key should remain.
3557 assert_eq!(result, 2);
3558
3559 Ok(())
3560 }
3561
3562 #[test]
Joel Galenson33c04ad2020-08-03 11:04:38 -07003563 fn test_rebind_alias() -> Result<()> {
Max Bires8e93d2b2021-01-14 13:17:59 -08003564 fn extractor(
3565 ke: &KeyEntryRow,
3566 ) -> (Option<Domain>, Option<i64>, Option<&str>, Option<Uuid>) {
3567 (ke.domain, ke.namespace, ke.alias.as_deref(), ke.km_uuid)
Joel Galenson33c04ad2020-08-03 11:04:38 -07003568 }
3569
Janis Danisevskis4df44f42020-08-26 14:40:03 -07003570 let mut db = new_test_db()?;
Janis Danisevskis66784c42021-01-27 08:40:25 -08003571 db.create_key_entry(&Domain::APP, &42, &KEYSTORE_UUID)?;
3572 db.create_key_entry(&Domain::APP, &42, &KEYSTORE_UUID)?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07003573 let entries = get_keyentry(&db)?;
3574 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08003575 assert_eq!(
3576 extractor(&entries[0]),
3577 (Some(Domain::APP), Some(42), None, Some(KEYSTORE_UUID))
3578 );
3579 assert_eq!(
3580 extractor(&entries[1]),
3581 (Some(Domain::APP), Some(42), None, Some(KEYSTORE_UUID))
3582 );
Joel Galenson33c04ad2020-08-03 11:04:38 -07003583
3584 // Test that the first call to rebind_alias sets the alias.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003585 rebind_alias(&mut db, &KEY_ID_LOCK.get(entries[0].id), "foo", Domain::APP, 42)?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07003586 let entries = get_keyentry(&db)?;
3587 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08003588 assert_eq!(
3589 extractor(&entries[0]),
3590 (Some(Domain::APP), Some(42), Some("foo"), Some(KEYSTORE_UUID))
3591 );
3592 assert_eq!(
3593 extractor(&entries[1]),
3594 (Some(Domain::APP), Some(42), None, Some(KEYSTORE_UUID))
3595 );
Joel Galenson33c04ad2020-08-03 11:04:38 -07003596
3597 // Test that the second call to rebind_alias also empties the old one.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003598 rebind_alias(&mut db, &KEY_ID_LOCK.get(entries[1].id), "foo", Domain::APP, 42)?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07003599 let entries = get_keyentry(&db)?;
3600 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08003601 assert_eq!(extractor(&entries[0]), (None, None, None, Some(KEYSTORE_UUID)));
3602 assert_eq!(
3603 extractor(&entries[1]),
3604 (Some(Domain::APP), Some(42), Some("foo"), Some(KEYSTORE_UUID))
3605 );
Joel Galenson33c04ad2020-08-03 11:04:38 -07003606
3607 // Test that we must pass in a valid Domain.
3608 check_result_is_error_containing_string(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003609 rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::GRANT, 42),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003610 "Domain Domain(1) must be either App or SELinux.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07003611 );
3612 check_result_is_error_containing_string(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003613 rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::BLOB, 42),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003614 "Domain Domain(3) must be either App or SELinux.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07003615 );
3616 check_result_is_error_containing_string(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003617 rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::KEY_ID, 42),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003618 "Domain Domain(4) must be either App or SELinux.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07003619 );
3620
3621 // Test that we correctly handle setting an alias for something that does not exist.
3622 check_result_is_error_containing_string(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003623 rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::SELINUX, 42),
Joel Galenson33c04ad2020-08-03 11:04:38 -07003624 "Expected to update a single entry but instead updated 0",
3625 );
3626 // Test that we correctly abort the transaction in this case.
3627 let entries = get_keyentry(&db)?;
3628 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08003629 assert_eq!(extractor(&entries[0]), (None, None, None, Some(KEYSTORE_UUID)));
3630 assert_eq!(
3631 extractor(&entries[1]),
3632 (Some(Domain::APP), Some(42), Some("foo"), Some(KEYSTORE_UUID))
3633 );
Joel Galenson33c04ad2020-08-03 11:04:38 -07003634
3635 Ok(())
3636 }
3637
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003638 #[test]
3639 fn test_grant_ungrant() -> Result<()> {
3640 const CALLER_UID: u32 = 15;
3641 const GRANTEE_UID: u32 = 12;
3642 const SELINUX_NAMESPACE: i64 = 7;
3643
3644 let mut db = new_test_db()?;
3645 db.conn.execute(
Max Bires8e93d2b2021-01-14 13:17:59 -08003646 "INSERT INTO persistent.keyentry (id, key_type, domain, namespace, alias, state, km_uuid)
3647 VALUES (1, 0, 0, 15, 'key', 1, ?), (2, 0, 2, 7, 'yek', 1, ?);",
3648 params![KEYSTORE_UUID, KEYSTORE_UUID],
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003649 )?;
3650 let app_key = KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003651 domain: super::Domain::APP,
3652 nspace: 0,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003653 alias: Some("key".to_string()),
3654 blob: None,
3655 };
3656 const PVEC1: KeyPermSet = key_perm_set![KeyPerm::use_(), KeyPerm::get_info()];
3657 const PVEC2: KeyPermSet = key_perm_set![KeyPerm::use_()];
3658
3659 // Reset totally predictable random number generator in case we
3660 // are not the first test running on this thread.
3661 reset_random();
3662 let next_random = 0i64;
3663
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003664 let app_granted_key = db
Janis Danisevskis66784c42021-01-27 08:40:25 -08003665 .grant(&app_key, CALLER_UID, GRANTEE_UID, PVEC1, |k, a| {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003666 assert_eq!(*a, PVEC1);
3667 assert_eq!(
3668 *k,
3669 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003670 domain: super::Domain::APP,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003671 // namespace must be set to the caller_uid.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003672 nspace: CALLER_UID as i64,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003673 alias: Some("key".to_string()),
3674 blob: None,
3675 }
3676 );
3677 Ok(())
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003678 })
3679 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003680
3681 assert_eq!(
3682 app_granted_key,
3683 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003684 domain: super::Domain::GRANT,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003685 // The grantid is next_random due to the mock random number generator.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003686 nspace: next_random,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003687 alias: None,
3688 blob: None,
3689 }
3690 );
3691
3692 let selinux_key = KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003693 domain: super::Domain::SELINUX,
3694 nspace: SELINUX_NAMESPACE,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003695 alias: Some("yek".to_string()),
3696 blob: None,
3697 };
3698
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003699 let selinux_granted_key = db
Janis Danisevskis66784c42021-01-27 08:40:25 -08003700 .grant(&selinux_key, CALLER_UID, 12, PVEC1, |k, a| {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003701 assert_eq!(*a, PVEC1);
3702 assert_eq!(
3703 *k,
3704 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003705 domain: super::Domain::SELINUX,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003706 // namespace must be the supplied SELinux
3707 // namespace.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003708 nspace: SELINUX_NAMESPACE,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003709 alias: Some("yek".to_string()),
3710 blob: None,
3711 }
3712 );
3713 Ok(())
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003714 })
3715 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003716
3717 assert_eq!(
3718 selinux_granted_key,
3719 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003720 domain: super::Domain::GRANT,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003721 // The grantid is next_random + 1 due to the mock random number generator.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003722 nspace: next_random + 1,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003723 alias: None,
3724 blob: None,
3725 }
3726 );
3727
3728 // This should update the existing grant with PVEC2.
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003729 let selinux_granted_key = db
Janis Danisevskis66784c42021-01-27 08:40:25 -08003730 .grant(&selinux_key, CALLER_UID, 12, PVEC2, |k, a| {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003731 assert_eq!(*a, PVEC2);
3732 assert_eq!(
3733 *k,
3734 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003735 domain: super::Domain::SELINUX,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003736 // namespace must be the supplied SELinux
3737 // namespace.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003738 nspace: SELINUX_NAMESPACE,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003739 alias: Some("yek".to_string()),
3740 blob: None,
3741 }
3742 );
3743 Ok(())
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003744 })
3745 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003746
3747 assert_eq!(
3748 selinux_granted_key,
3749 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003750 domain: super::Domain::GRANT,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003751 // Same grant id as before. The entry was only updated.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003752 nspace: next_random + 1,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003753 alias: None,
3754 blob: None,
3755 }
3756 );
3757
3758 {
3759 // Limiting scope of stmt, because it borrows db.
3760 let mut stmt = db
3761 .conn
Janis Danisevskisbf15d732020-12-08 10:35:26 -08003762 .prepare("SELECT id, grantee, keyentryid, access_vector FROM persistent.grant;")?;
Janis Danisevskisee10b5f2020-09-22 16:42:35 -07003763 let mut rows =
3764 stmt.query_map::<(i64, u32, i64, KeyPermSet), _, _>(NO_PARAMS, |row| {
3765 Ok((
3766 row.get(0)?,
3767 row.get(1)?,
3768 row.get(2)?,
3769 KeyPermSet::from(row.get::<_, i32>(3)?),
3770 ))
3771 })?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003772
3773 let r = rows.next().unwrap().unwrap();
Janis Danisevskisee10b5f2020-09-22 16:42:35 -07003774 assert_eq!(r, (next_random, GRANTEE_UID, 1, PVEC1));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003775 let r = rows.next().unwrap().unwrap();
Janis Danisevskisee10b5f2020-09-22 16:42:35 -07003776 assert_eq!(r, (next_random + 1, GRANTEE_UID, 2, PVEC2));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003777 assert!(rows.next().is_none());
3778 }
3779
3780 debug_dump_keyentry_table(&mut db)?;
3781 println!("app_key {:?}", app_key);
3782 println!("selinux_key {:?}", selinux_key);
3783
Janis Danisevskis66784c42021-01-27 08:40:25 -08003784 db.ungrant(&app_key, CALLER_UID, GRANTEE_UID, |_| Ok(()))?;
3785 db.ungrant(&selinux_key, CALLER_UID, GRANTEE_UID, |_| Ok(()))?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003786
3787 Ok(())
3788 }
3789
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003790 static TEST_KEY_BLOB: &[u8] = b"my test blob";
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003791 static TEST_CERT_BLOB: &[u8] = b"my test cert";
3792 static TEST_CERT_CHAIN_BLOB: &[u8] = b"my test cert_chain";
3793
3794 #[test]
Janis Danisevskis377d1002021-01-27 19:07:48 -08003795 fn test_set_blob() -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003796 let key_id = KEY_ID_LOCK.get(3000);
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003797 let mut db = new_test_db()?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003798 let mut blob_metadata = BlobMetaData::new();
3799 blob_metadata.add(BlobMetaEntry::KmUuid(KEYSTORE_UUID));
3800 db.set_blob(
3801 &key_id,
3802 SubComponentType::KEY_BLOB,
3803 Some(TEST_KEY_BLOB),
3804 Some(&blob_metadata),
3805 )?;
3806 db.set_blob(&key_id, SubComponentType::CERT, Some(TEST_CERT_BLOB), None)?;
3807 db.set_blob(&key_id, SubComponentType::CERT_CHAIN, Some(TEST_CERT_CHAIN_BLOB), None)?;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003808 drop(key_id);
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003809
3810 let mut stmt = db.conn.prepare(
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003811 "SELECT subcomponent_type, keyentryid, blob, id FROM persistent.blobentry
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003812 ORDER BY subcomponent_type ASC;",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003813 )?;
3814 let mut rows = stmt
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003815 .query_map::<((SubComponentType, i64, Vec<u8>), i64), _, _>(NO_PARAMS, |row| {
3816 Ok(((row.get(0)?, row.get(1)?, row.get(2)?), row.get(3)?))
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003817 })?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003818 let (r, id) = rows.next().unwrap().unwrap();
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003819 assert_eq!(r, (SubComponentType::KEY_BLOB, 3000, TEST_KEY_BLOB.to_vec()));
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003820 let (r, _) = rows.next().unwrap().unwrap();
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003821 assert_eq!(r, (SubComponentType::CERT, 3000, TEST_CERT_BLOB.to_vec()));
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003822 let (r, _) = rows.next().unwrap().unwrap();
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003823 assert_eq!(r, (SubComponentType::CERT_CHAIN, 3000, TEST_CERT_CHAIN_BLOB.to_vec()));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003824
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003825 drop(rows);
3826 drop(stmt);
3827
3828 assert_eq!(
3829 db.with_transaction(TransactionBehavior::Immediate, |tx| {
3830 BlobMetaData::load_from_db(id, tx).no_gc()
3831 })
3832 .expect("Should find blob metadata."),
3833 blob_metadata
3834 );
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003835 Ok(())
3836 }
3837
3838 static TEST_ALIAS: &str = "my super duper key";
3839
3840 #[test]
3841 fn test_insert_and_load_full_keyentry_domain_app() -> Result<()> {
3842 let mut db = new_test_db()?;
Qi Wub9433b52020-12-01 14:52:46 +08003843 let key_id = make_test_key_entry(&mut db, Domain::APP, 1, TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08003844 .context("test_insert_and_load_full_keyentry_domain_app")?
3845 .0;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003846 let (_key_guard, key_entry) = db
3847 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003848 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003849 domain: Domain::APP,
3850 nspace: 0,
3851 alias: Some(TEST_ALIAS.to_string()),
3852 blob: None,
3853 },
3854 KeyType::Client,
3855 KeyEntryLoadBits::BOTH,
3856 1,
3857 |_k, _av| Ok(()),
3858 )
3859 .unwrap();
Qi Wub9433b52020-12-01 14:52:46 +08003860 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003861
3862 db.unbind_key(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003863 &KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003864 domain: Domain::APP,
3865 nspace: 0,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003866 alias: Some(TEST_ALIAS.to_string()),
3867 blob: None,
3868 },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003869 KeyType::Client,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003870 1,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003871 |_, _| Ok(()),
3872 )
3873 .unwrap();
3874
3875 assert_eq!(
3876 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
3877 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003878 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003879 domain: Domain::APP,
3880 nspace: 0,
3881 alias: Some(TEST_ALIAS.to_string()),
3882 blob: None,
3883 },
3884 KeyType::Client,
3885 KeyEntryLoadBits::NONE,
3886 1,
3887 |_k, _av| Ok(()),
3888 )
3889 .unwrap_err()
3890 .root_cause()
3891 .downcast_ref::<KsError>()
3892 );
3893
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003894 Ok(())
3895 }
3896
3897 #[test]
Janis Danisevskis377d1002021-01-27 19:07:48 -08003898 fn test_insert_and_load_certificate_entry_domain_app() -> Result<()> {
3899 let mut db = new_test_db()?;
3900
3901 db.store_new_certificate(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003902 &KeyDescriptor {
Janis Danisevskis377d1002021-01-27 19:07:48 -08003903 domain: Domain::APP,
3904 nspace: 1,
3905 alias: Some(TEST_ALIAS.to_string()),
3906 blob: None,
3907 },
3908 TEST_CERT_BLOB,
Max Bires8e93d2b2021-01-14 13:17:59 -08003909 &KEYSTORE_UUID,
Janis Danisevskis377d1002021-01-27 19:07:48 -08003910 )
3911 .expect("Trying to insert cert.");
3912
3913 let (_key_guard, mut key_entry) = db
3914 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003915 &KeyDescriptor {
Janis Danisevskis377d1002021-01-27 19:07:48 -08003916 domain: Domain::APP,
3917 nspace: 1,
3918 alias: Some(TEST_ALIAS.to_string()),
3919 blob: None,
3920 },
3921 KeyType::Client,
3922 KeyEntryLoadBits::PUBLIC,
3923 1,
3924 |_k, _av| Ok(()),
3925 )
3926 .expect("Trying to read certificate entry.");
3927
3928 assert!(key_entry.pure_cert());
3929 assert!(key_entry.cert().is_none());
3930 assert_eq!(key_entry.take_cert_chain(), Some(TEST_CERT_BLOB.to_vec()));
3931
3932 db.unbind_key(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003933 &KeyDescriptor {
Janis Danisevskis377d1002021-01-27 19:07:48 -08003934 domain: Domain::APP,
3935 nspace: 1,
3936 alias: Some(TEST_ALIAS.to_string()),
3937 blob: None,
3938 },
3939 KeyType::Client,
3940 1,
3941 |_, _| Ok(()),
3942 )
3943 .unwrap();
3944
3945 assert_eq!(
3946 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
3947 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003948 &KeyDescriptor {
Janis Danisevskis377d1002021-01-27 19:07:48 -08003949 domain: Domain::APP,
3950 nspace: 1,
3951 alias: Some(TEST_ALIAS.to_string()),
3952 blob: None,
3953 },
3954 KeyType::Client,
3955 KeyEntryLoadBits::NONE,
3956 1,
3957 |_k, _av| Ok(()),
3958 )
3959 .unwrap_err()
3960 .root_cause()
3961 .downcast_ref::<KsError>()
3962 );
3963
3964 Ok(())
3965 }
3966
3967 #[test]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003968 fn test_insert_and_load_full_keyentry_domain_selinux() -> Result<()> {
3969 let mut db = new_test_db()?;
Qi Wub9433b52020-12-01 14:52:46 +08003970 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08003971 .context("test_insert_and_load_full_keyentry_domain_selinux")?
3972 .0;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003973 let (_key_guard, key_entry) = db
3974 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003975 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003976 domain: Domain::SELINUX,
3977 nspace: 1,
3978 alias: Some(TEST_ALIAS.to_string()),
3979 blob: None,
3980 },
3981 KeyType::Client,
3982 KeyEntryLoadBits::BOTH,
3983 1,
3984 |_k, _av| Ok(()),
3985 )
3986 .unwrap();
Qi Wub9433b52020-12-01 14:52:46 +08003987 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003988
3989 db.unbind_key(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003990 &KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003991 domain: Domain::SELINUX,
3992 nspace: 1,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003993 alias: Some(TEST_ALIAS.to_string()),
3994 blob: None,
3995 },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003996 KeyType::Client,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003997 1,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003998 |_, _| Ok(()),
3999 )
4000 .unwrap();
4001
4002 assert_eq!(
4003 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
4004 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004005 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004006 domain: Domain::SELINUX,
4007 nspace: 1,
4008 alias: Some(TEST_ALIAS.to_string()),
4009 blob: None,
4010 },
4011 KeyType::Client,
4012 KeyEntryLoadBits::NONE,
4013 1,
4014 |_k, _av| Ok(()),
4015 )
4016 .unwrap_err()
4017 .root_cause()
4018 .downcast_ref::<KsError>()
4019 );
4020
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004021 Ok(())
4022 }
4023
4024 #[test]
4025 fn test_insert_and_load_full_keyentry_domain_key_id() -> Result<()> {
4026 let mut db = new_test_db()?;
Qi Wub9433b52020-12-01 14:52:46 +08004027 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08004028 .context("test_insert_and_load_full_keyentry_domain_key_id")?
4029 .0;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004030 let (_, key_entry) = db
4031 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004032 &KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004033 KeyType::Client,
4034 KeyEntryLoadBits::BOTH,
4035 1,
4036 |_k, _av| Ok(()),
4037 )
4038 .unwrap();
4039
Qi Wub9433b52020-12-01 14:52:46 +08004040 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004041
4042 db.unbind_key(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004043 &KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004044 KeyType::Client,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004045 1,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004046 |_, _| Ok(()),
4047 )
4048 .unwrap();
4049
4050 assert_eq!(
4051 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
4052 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004053 &KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004054 KeyType::Client,
4055 KeyEntryLoadBits::NONE,
4056 1,
4057 |_k, _av| Ok(()),
4058 )
4059 .unwrap_err()
4060 .root_cause()
4061 .downcast_ref::<KsError>()
4062 );
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004063
4064 Ok(())
4065 }
4066
4067 #[test]
Qi Wub9433b52020-12-01 14:52:46 +08004068 fn test_check_and_update_key_usage_count_with_limited_use_key() -> Result<()> {
4069 let mut db = new_test_db()?;
4070 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, Some(123))
4071 .context("test_check_and_update_key_usage_count_with_limited_use_key")?
4072 .0;
4073 // Update the usage count of the limited use key.
4074 db.check_and_update_key_usage_count(key_id)?;
4075
4076 let (_key_guard, key_entry) = db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004077 &KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
Qi Wub9433b52020-12-01 14:52:46 +08004078 KeyType::Client,
4079 KeyEntryLoadBits::BOTH,
4080 1,
4081 |_k, _av| Ok(()),
4082 )?;
4083
4084 // The usage count is decremented now.
4085 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, Some(122)));
4086
4087 Ok(())
4088 }
4089
4090 #[test]
4091 fn test_check_and_update_key_usage_count_with_exhausted_limited_use_key() -> Result<()> {
4092 let mut db = new_test_db()?;
4093 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, Some(1))
4094 .context("test_check_and_update_key_usage_count_with_exhausted_limited_use_key")?
4095 .0;
4096 // Update the usage count of the limited use key.
4097 db.check_and_update_key_usage_count(key_id).expect(concat!(
4098 "In test_check_and_update_key_usage_count_with_exhausted_limited_use_key: ",
4099 "This should succeed."
4100 ));
4101
4102 // Try to update the exhausted limited use key.
4103 let e = db.check_and_update_key_usage_count(key_id).expect_err(concat!(
4104 "In test_check_and_update_key_usage_count_with_exhausted_limited_use_key: ",
4105 "This should fail."
4106 ));
4107 assert_eq!(
4108 &KsError::Km(ErrorCode::INVALID_KEY_BLOB),
4109 e.root_cause().downcast_ref::<KsError>().unwrap()
4110 );
4111
4112 Ok(())
4113 }
4114
4115 #[test]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004116 fn test_insert_and_load_full_keyentry_from_grant() -> Result<()> {
4117 let mut db = new_test_db()?;
Qi Wub9433b52020-12-01 14:52:46 +08004118 let key_id = make_test_key_entry(&mut db, Domain::APP, 1, TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08004119 .context("test_insert_and_load_full_keyentry_from_grant")?
4120 .0;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004121
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004122 let granted_key = db
4123 .grant(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004124 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004125 domain: Domain::APP,
4126 nspace: 0,
4127 alias: Some(TEST_ALIAS.to_string()),
4128 blob: None,
4129 },
4130 1,
4131 2,
4132 key_perm_set![KeyPerm::use_()],
4133 |_k, _av| Ok(()),
4134 )
4135 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004136
4137 debug_dump_grant_table(&mut db)?;
4138
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004139 let (_key_guard, key_entry) = db
Janis Danisevskis66784c42021-01-27 08:40:25 -08004140 .load_key_entry(&granted_key, KeyType::Client, KeyEntryLoadBits::BOTH, 2, |k, av| {
4141 assert_eq!(Domain::GRANT, k.domain);
4142 assert!(av.unwrap().includes(KeyPerm::use_()));
4143 Ok(())
4144 })
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004145 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004146
Qi Wub9433b52020-12-01 14:52:46 +08004147 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004148
Janis Danisevskis66784c42021-01-27 08:40:25 -08004149 db.unbind_key(&granted_key, KeyType::Client, 2, |_, _| Ok(())).unwrap();
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004150
4151 assert_eq!(
4152 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
4153 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004154 &granted_key,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004155 KeyType::Client,
4156 KeyEntryLoadBits::NONE,
4157 2,
4158 |_k, _av| Ok(()),
4159 )
4160 .unwrap_err()
4161 .root_cause()
4162 .downcast_ref::<KsError>()
4163 );
4164
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004165 Ok(())
4166 }
4167
Janis Danisevskis45760022021-01-19 16:34:10 -08004168 // This test attempts to load a key by key id while the caller is not the owner
4169 // but a grant exists for the given key and the caller.
4170 #[test]
4171 fn test_insert_and_load_full_keyentry_from_grant_by_key_id() -> Result<()> {
4172 let mut db = new_test_db()?;
4173 const OWNER_UID: u32 = 1u32;
4174 const GRANTEE_UID: u32 = 2u32;
4175 const SOMEONE_ELSE_UID: u32 = 3u32;
4176 let key_id = make_test_key_entry(&mut db, Domain::APP, OWNER_UID as i64, TEST_ALIAS, None)
4177 .context("test_insert_and_load_full_keyentry_from_grant_by_key_id")?
4178 .0;
4179
4180 db.grant(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004181 &KeyDescriptor {
Janis Danisevskis45760022021-01-19 16:34:10 -08004182 domain: Domain::APP,
4183 nspace: 0,
4184 alias: Some(TEST_ALIAS.to_string()),
4185 blob: None,
4186 },
4187 OWNER_UID,
4188 GRANTEE_UID,
4189 key_perm_set![KeyPerm::use_()],
4190 |_k, _av| Ok(()),
4191 )
4192 .unwrap();
4193
4194 debug_dump_grant_table(&mut db)?;
4195
4196 let id_descriptor =
4197 KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, ..Default::default() };
4198
4199 let (_, key_entry) = db
4200 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004201 &id_descriptor,
Janis Danisevskis45760022021-01-19 16:34:10 -08004202 KeyType::Client,
4203 KeyEntryLoadBits::BOTH,
4204 GRANTEE_UID,
4205 |k, av| {
4206 assert_eq!(Domain::APP, k.domain);
4207 assert_eq!(OWNER_UID as i64, k.nspace);
4208 assert!(av.unwrap().includes(KeyPerm::use_()));
4209 Ok(())
4210 },
4211 )
4212 .unwrap();
4213
4214 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
4215
4216 let (_, key_entry) = db
4217 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004218 &id_descriptor,
Janis Danisevskis45760022021-01-19 16:34:10 -08004219 KeyType::Client,
4220 KeyEntryLoadBits::BOTH,
4221 SOMEONE_ELSE_UID,
4222 |k, av| {
4223 assert_eq!(Domain::APP, k.domain);
4224 assert_eq!(OWNER_UID as i64, k.nspace);
4225 assert!(av.is_none());
4226 Ok(())
4227 },
4228 )
4229 .unwrap();
4230
4231 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
4232
Janis Danisevskis66784c42021-01-27 08:40:25 -08004233 db.unbind_key(&id_descriptor, KeyType::Client, OWNER_UID, |_, _| Ok(())).unwrap();
Janis Danisevskis45760022021-01-19 16:34:10 -08004234
4235 assert_eq!(
4236 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
4237 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004238 &id_descriptor,
Janis Danisevskis45760022021-01-19 16:34:10 -08004239 KeyType::Client,
4240 KeyEntryLoadBits::NONE,
4241 GRANTEE_UID,
4242 |_k, _av| Ok(()),
4243 )
4244 .unwrap_err()
4245 .root_cause()
4246 .downcast_ref::<KsError>()
4247 );
4248
4249 Ok(())
4250 }
4251
Janis Danisevskiscdcf4e52021-04-14 15:44:36 -07004252 // Creates a key migrates it to a different location and then tries to access it by the old
4253 // and new location.
4254 #[test]
4255 fn test_migrate_key_app_to_app() -> Result<()> {
4256 let mut db = new_test_db()?;
4257 const SOURCE_UID: u32 = 1u32;
4258 const DESTINATION_UID: u32 = 2u32;
4259 static SOURCE_ALIAS: &str = &"SOURCE_ALIAS";
4260 static DESTINATION_ALIAS: &str = &"DESTINATION_ALIAS";
4261 let key_id_guard =
4262 make_test_key_entry(&mut db, Domain::APP, SOURCE_UID as i64, SOURCE_ALIAS, None)
4263 .context("test_insert_and_load_full_keyentry_from_grant_by_key_id")?;
4264
4265 let source_descriptor: KeyDescriptor = KeyDescriptor {
4266 domain: Domain::APP,
4267 nspace: -1,
4268 alias: Some(SOURCE_ALIAS.to_string()),
4269 blob: None,
4270 };
4271
4272 let destination_descriptor: KeyDescriptor = KeyDescriptor {
4273 domain: Domain::APP,
4274 nspace: -1,
4275 alias: Some(DESTINATION_ALIAS.to_string()),
4276 blob: None,
4277 };
4278
4279 let key_id = key_id_guard.id();
4280
4281 db.migrate_key_namespace(key_id_guard, &destination_descriptor, DESTINATION_UID, |_k| {
4282 Ok(())
4283 })
4284 .unwrap();
4285
4286 let (_, key_entry) = db
4287 .load_key_entry(
4288 &destination_descriptor,
4289 KeyType::Client,
4290 KeyEntryLoadBits::BOTH,
4291 DESTINATION_UID,
4292 |k, av| {
4293 assert_eq!(Domain::APP, k.domain);
4294 assert_eq!(DESTINATION_UID as i64, k.nspace);
4295 assert!(av.is_none());
4296 Ok(())
4297 },
4298 )
4299 .unwrap();
4300
4301 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
4302
4303 assert_eq!(
4304 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
4305 db.load_key_entry(
4306 &source_descriptor,
4307 KeyType::Client,
4308 KeyEntryLoadBits::NONE,
4309 SOURCE_UID,
4310 |_k, _av| Ok(()),
4311 )
4312 .unwrap_err()
4313 .root_cause()
4314 .downcast_ref::<KsError>()
4315 );
4316
4317 Ok(())
4318 }
4319
4320 // Creates a key migrates it to a different location and then tries to access it by the old
4321 // and new location.
4322 #[test]
4323 fn test_migrate_key_app_to_selinux() -> Result<()> {
4324 let mut db = new_test_db()?;
4325 const SOURCE_UID: u32 = 1u32;
4326 const DESTINATION_UID: u32 = 2u32;
4327 const DESTINATION_NAMESPACE: i64 = 1000i64;
4328 static SOURCE_ALIAS: &str = &"SOURCE_ALIAS";
4329 static DESTINATION_ALIAS: &str = &"DESTINATION_ALIAS";
4330 let key_id_guard =
4331 make_test_key_entry(&mut db, Domain::APP, SOURCE_UID as i64, SOURCE_ALIAS, None)
4332 .context("test_insert_and_load_full_keyentry_from_grant_by_key_id")?;
4333
4334 let source_descriptor: KeyDescriptor = KeyDescriptor {
4335 domain: Domain::APP,
4336 nspace: -1,
4337 alias: Some(SOURCE_ALIAS.to_string()),
4338 blob: None,
4339 };
4340
4341 let destination_descriptor: KeyDescriptor = KeyDescriptor {
4342 domain: Domain::SELINUX,
4343 nspace: DESTINATION_NAMESPACE,
4344 alias: Some(DESTINATION_ALIAS.to_string()),
4345 blob: None,
4346 };
4347
4348 let key_id = key_id_guard.id();
4349
4350 db.migrate_key_namespace(key_id_guard, &destination_descriptor, DESTINATION_UID, |_k| {
4351 Ok(())
4352 })
4353 .unwrap();
4354
4355 let (_, key_entry) = db
4356 .load_key_entry(
4357 &destination_descriptor,
4358 KeyType::Client,
4359 KeyEntryLoadBits::BOTH,
4360 DESTINATION_UID,
4361 |k, av| {
4362 assert_eq!(Domain::SELINUX, k.domain);
4363 assert_eq!(DESTINATION_NAMESPACE as i64, k.nspace);
4364 assert!(av.is_none());
4365 Ok(())
4366 },
4367 )
4368 .unwrap();
4369
4370 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
4371
4372 assert_eq!(
4373 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
4374 db.load_key_entry(
4375 &source_descriptor,
4376 KeyType::Client,
4377 KeyEntryLoadBits::NONE,
4378 SOURCE_UID,
4379 |_k, _av| Ok(()),
4380 )
4381 .unwrap_err()
4382 .root_cause()
4383 .downcast_ref::<KsError>()
4384 );
4385
4386 Ok(())
4387 }
4388
4389 // Creates two keys and tries to migrate the first to the location of the second which
4390 // is expected to fail.
4391 #[test]
4392 fn test_migrate_key_destination_occupied() -> Result<()> {
4393 let mut db = new_test_db()?;
4394 const SOURCE_UID: u32 = 1u32;
4395 const DESTINATION_UID: u32 = 2u32;
4396 static SOURCE_ALIAS: &str = &"SOURCE_ALIAS";
4397 static DESTINATION_ALIAS: &str = &"DESTINATION_ALIAS";
4398 let key_id_guard =
4399 make_test_key_entry(&mut db, Domain::APP, SOURCE_UID as i64, SOURCE_ALIAS, None)
4400 .context("test_insert_and_load_full_keyentry_from_grant_by_key_id")?;
4401 make_test_key_entry(&mut db, Domain::APP, DESTINATION_UID as i64, DESTINATION_ALIAS, None)
4402 .context("test_insert_and_load_full_keyentry_from_grant_by_key_id")?;
4403
4404 let destination_descriptor: KeyDescriptor = KeyDescriptor {
4405 domain: Domain::APP,
4406 nspace: -1,
4407 alias: Some(DESTINATION_ALIAS.to_string()),
4408 blob: None,
4409 };
4410
4411 assert_eq!(
4412 Some(&KsError::Rc(ResponseCode::INVALID_ARGUMENT)),
4413 db.migrate_key_namespace(
4414 key_id_guard,
4415 &destination_descriptor,
4416 DESTINATION_UID,
4417 |_k| Ok(())
4418 )
4419 .unwrap_err()
4420 .root_cause()
4421 .downcast_ref::<KsError>()
4422 );
4423
4424 Ok(())
4425 }
4426
Janis Danisevskisaec14592020-11-12 09:41:49 -08004427 static KEY_LOCK_TEST_ALIAS: &str = "my super duper locked key";
4428
Janis Danisevskisaec14592020-11-12 09:41:49 -08004429 #[test]
4430 fn test_insert_and_load_full_keyentry_domain_app_concurrently() -> Result<()> {
4431 let handle = {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08004432 let temp_dir = Arc::new(TempDir::new("id_lock_test")?);
4433 let temp_dir_clone = temp_dir.clone();
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004434 let mut db = KeystoreDB::new(temp_dir.path(), None)?;
Qi Wub9433b52020-12-01 14:52:46 +08004435 let key_id = make_test_key_entry(&mut db, Domain::APP, 33, KEY_LOCK_TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08004436 .context("test_insert_and_load_full_keyentry_domain_app")?
4437 .0;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004438 let (_key_guard, key_entry) = db
4439 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004440 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004441 domain: Domain::APP,
4442 nspace: 0,
4443 alias: Some(KEY_LOCK_TEST_ALIAS.to_string()),
4444 blob: None,
4445 },
4446 KeyType::Client,
4447 KeyEntryLoadBits::BOTH,
4448 33,
4449 |_k, _av| Ok(()),
4450 )
4451 .unwrap();
Qi Wub9433b52020-12-01 14:52:46 +08004452 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskisaec14592020-11-12 09:41:49 -08004453 let state = Arc::new(AtomicU8::new(1));
4454 let state2 = state.clone();
4455
4456 // Spawning a second thread that attempts to acquire the key id lock
4457 // for the same key as the primary thread. The primary thread then
4458 // waits, thereby forcing the secondary thread into the second stage
4459 // of acquiring the lock (see KEY ID LOCK 2/2 above).
4460 // The test succeeds if the secondary thread observes the transition
4461 // of `state` from 1 to 2, despite having a whole second to overtake
4462 // the primary thread.
4463 let handle = thread::spawn(move || {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08004464 let temp_dir = temp_dir_clone;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004465 let mut db = KeystoreDB::new(temp_dir.path(), None).unwrap();
Janis Danisevskisaec14592020-11-12 09:41:49 -08004466 assert!(db
4467 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004468 &KeyDescriptor {
Janis Danisevskisaec14592020-11-12 09:41:49 -08004469 domain: Domain::APP,
4470 nspace: 0,
4471 alias: Some(KEY_LOCK_TEST_ALIAS.to_string()),
4472 blob: None,
4473 },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004474 KeyType::Client,
Janis Danisevskisaec14592020-11-12 09:41:49 -08004475 KeyEntryLoadBits::BOTH,
4476 33,
4477 |_k, _av| Ok(()),
4478 )
4479 .is_ok());
4480 // We should only see a 2 here because we can only return
4481 // from load_key_entry when the `_key_guard` expires,
4482 // which happens at the end of the scope.
4483 assert_eq!(2, state2.load(Ordering::Relaxed));
4484 });
4485
4486 thread::sleep(std::time::Duration::from_millis(1000));
4487
4488 assert_eq!(Ok(1), state.compare_exchange(1, 2, Ordering::Relaxed, Ordering::Relaxed));
4489
4490 // Return the handle from this scope so we can join with the
4491 // secondary thread after the key id lock has expired.
4492 handle
4493 // This is where the `_key_guard` goes out of scope,
4494 // which is the reason for concurrent load_key_entry on the same key
4495 // to unblock.
4496 };
4497 // Join with the secondary thread and unwrap, to propagate failing asserts to the
4498 // main test thread. We will not see failing asserts in secondary threads otherwise.
4499 handle.join().unwrap();
4500 Ok(())
4501 }
4502
Janis Danisevskise92a5e62020-12-02 12:57:41 -08004503 #[test]
Janis Danisevskiscdcf4e52021-04-14 15:44:36 -07004504 fn test_database_busy_error_code() {
Janis Danisevskis66784c42021-01-27 08:40:25 -08004505 let temp_dir =
4506 TempDir::new("test_database_busy_error_code_").expect("Failed to create temp dir.");
4507
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004508 let mut db1 = KeystoreDB::new(temp_dir.path(), None).expect("Failed to open database1.");
4509 let mut db2 = KeystoreDB::new(temp_dir.path(), None).expect("Failed to open database2.");
Janis Danisevskis66784c42021-01-27 08:40:25 -08004510
4511 let _tx1 = db1
4512 .conn
4513 .transaction_with_behavior(TransactionBehavior::Immediate)
4514 .expect("Failed to create first transaction.");
4515
4516 let error = db2
4517 .conn
4518 .transaction_with_behavior(TransactionBehavior::Immediate)
4519 .context("Transaction begin failed.")
4520 .expect_err("This should fail.");
4521 let root_cause = error.root_cause();
4522 if let Some(rusqlite::ffi::Error { code: rusqlite::ErrorCode::DatabaseBusy, .. }) =
4523 root_cause.downcast_ref::<rusqlite::ffi::Error>()
4524 {
4525 return;
4526 }
4527 panic!(
4528 "Unexpected error {:?} \n{:?} \n{:?}",
4529 error,
4530 root_cause,
4531 root_cause.downcast_ref::<rusqlite::ffi::Error>()
4532 )
4533 }
4534
4535 #[cfg(disabled)]
4536 #[test]
4537 fn test_large_number_of_concurrent_db_manipulations() -> Result<()> {
4538 let temp_dir = Arc::new(
4539 TempDir::new("test_large_number_of_concurrent_db_manipulations_")
4540 .expect("Failed to create temp dir."),
4541 );
4542
4543 let test_begin = Instant::now();
4544
4545 let mut db = KeystoreDB::new(temp_dir.path()).expect("Failed to open database.");
4546 const KEY_COUNT: u32 = 500u32;
4547 const OPEN_DB_COUNT: u32 = 50u32;
4548
4549 let mut actual_key_count = KEY_COUNT;
4550 // First insert KEY_COUNT keys.
4551 for count in 0..KEY_COUNT {
4552 if Instant::now().duration_since(test_begin) >= Duration::from_secs(15) {
4553 actual_key_count = count;
4554 break;
4555 }
4556 let alias = format!("test_alias_{}", count);
4557 make_test_key_entry(&mut db, Domain::APP, 1, &alias, None)
4558 .expect("Failed to make key entry.");
4559 }
4560
4561 // Insert more keys from a different thread and into a different namespace.
4562 let temp_dir1 = temp_dir.clone();
4563 let handle1 = thread::spawn(move || {
4564 let mut db = KeystoreDB::new(temp_dir1.path()).expect("Failed to open database.");
4565
4566 for count in 0..actual_key_count {
4567 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
4568 return;
4569 }
4570 let alias = format!("test_alias_{}", count);
4571 make_test_key_entry(&mut db, Domain::APP, 2, &alias, None)
4572 .expect("Failed to make key entry.");
4573 }
4574
4575 // then unbind them again.
4576 for count in 0..actual_key_count {
4577 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
4578 return;
4579 }
4580 let key = KeyDescriptor {
4581 domain: Domain::APP,
4582 nspace: -1,
4583 alias: Some(format!("test_alias_{}", count)),
4584 blob: None,
4585 };
4586 db.unbind_key(&key, KeyType::Client, 2, |_, _| Ok(())).expect("Unbind Failed.");
4587 }
4588 });
4589
4590 // And start unbinding the first set of keys.
4591 let temp_dir2 = temp_dir.clone();
4592 let handle2 = thread::spawn(move || {
4593 let mut db = KeystoreDB::new(temp_dir2.path()).expect("Failed to open database.");
4594
4595 for count in 0..actual_key_count {
4596 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
4597 return;
4598 }
4599 let key = KeyDescriptor {
4600 domain: Domain::APP,
4601 nspace: -1,
4602 alias: Some(format!("test_alias_{}", count)),
4603 blob: None,
4604 };
4605 db.unbind_key(&key, KeyType::Client, 1, |_, _| Ok(())).expect("Unbind Failed.");
4606 }
4607 });
4608
4609 let stop_deleting = Arc::new(AtomicU8::new(0));
4610 let stop_deleting2 = stop_deleting.clone();
4611
4612 // And delete anything that is unreferenced keys.
4613 let temp_dir3 = temp_dir.clone();
4614 let handle3 = thread::spawn(move || {
4615 let mut db = KeystoreDB::new(temp_dir3.path()).expect("Failed to open database.");
4616
4617 while stop_deleting2.load(Ordering::Relaxed) != 1 {
4618 while let Some((key_guard, _key)) =
4619 db.get_unreferenced_key().expect("Failed to get unreferenced Key.")
4620 {
4621 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
4622 return;
4623 }
4624 db.purge_key_entry(key_guard).expect("Failed to purge key.");
4625 }
4626 std::thread::sleep(std::time::Duration::from_millis(100));
4627 }
4628 });
4629
4630 // While a lot of inserting and deleting is going on we have to open database connections
4631 // successfully and use them.
4632 // This clone is not redundant, because temp_dir needs to be kept alive until db goes
4633 // out of scope.
4634 #[allow(clippy::redundant_clone)]
4635 let temp_dir4 = temp_dir.clone();
4636 let handle4 = thread::spawn(move || {
4637 for count in 0..OPEN_DB_COUNT {
4638 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
4639 return;
4640 }
4641 let mut db = KeystoreDB::new(temp_dir4.path()).expect("Failed to open database.");
4642
4643 let alias = format!("test_alias_{}", count);
4644 make_test_key_entry(&mut db, Domain::APP, 3, &alias, None)
4645 .expect("Failed to make key entry.");
4646 let key = KeyDescriptor {
4647 domain: Domain::APP,
4648 nspace: -1,
4649 alias: Some(alias),
4650 blob: None,
4651 };
4652 db.unbind_key(&key, KeyType::Client, 3, |_, _| Ok(())).expect("Unbind Failed.");
4653 }
4654 });
4655
4656 handle1.join().expect("Thread 1 panicked.");
4657 handle2.join().expect("Thread 2 panicked.");
4658 handle4.join().expect("Thread 4 panicked.");
4659
4660 stop_deleting.store(1, Ordering::Relaxed);
4661 handle3.join().expect("Thread 3 panicked.");
4662
4663 Ok(())
4664 }
4665
4666 #[test]
Janis Danisevskise92a5e62020-12-02 12:57:41 -08004667 fn list() -> Result<()> {
4668 let temp_dir = TempDir::new("list_test")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004669 let mut db = KeystoreDB::new(temp_dir.path(), None)?;
Janis Danisevskise92a5e62020-12-02 12:57:41 -08004670 static LIST_O_ENTRIES: &[(Domain, i64, &str)] = &[
4671 (Domain::APP, 1, "test1"),
4672 (Domain::APP, 1, "test2"),
4673 (Domain::APP, 1, "test3"),
4674 (Domain::APP, 1, "test4"),
4675 (Domain::APP, 1, "test5"),
4676 (Domain::APP, 1, "test6"),
4677 (Domain::APP, 1, "test7"),
4678 (Domain::APP, 2, "test1"),
4679 (Domain::APP, 2, "test2"),
4680 (Domain::APP, 2, "test3"),
4681 (Domain::APP, 2, "test4"),
4682 (Domain::APP, 2, "test5"),
4683 (Domain::APP, 2, "test6"),
4684 (Domain::APP, 2, "test8"),
4685 (Domain::SELINUX, 100, "test1"),
4686 (Domain::SELINUX, 100, "test2"),
4687 (Domain::SELINUX, 100, "test3"),
4688 (Domain::SELINUX, 100, "test4"),
4689 (Domain::SELINUX, 100, "test5"),
4690 (Domain::SELINUX, 100, "test6"),
4691 (Domain::SELINUX, 100, "test9"),
4692 ];
4693
4694 let list_o_keys: Vec<(i64, i64)> = LIST_O_ENTRIES
4695 .iter()
4696 .map(|(domain, ns, alias)| {
Qi Wub9433b52020-12-01 14:52:46 +08004697 let entry = make_test_key_entry(&mut db, *domain, *ns, *alias, None)
4698 .unwrap_or_else(|e| {
Janis Danisevskise92a5e62020-12-02 12:57:41 -08004699 panic!("Failed to insert {:?} {} {}. Error {:?}", domain, ns, alias, e)
4700 });
4701 (entry.id(), *ns)
4702 })
4703 .collect();
4704
4705 for (domain, namespace) in
4706 &[(Domain::APP, 1i64), (Domain::APP, 2i64), (Domain::SELINUX, 100i64)]
4707 {
4708 let mut list_o_descriptors: Vec<KeyDescriptor> = LIST_O_ENTRIES
4709 .iter()
4710 .filter_map(|(domain, ns, alias)| match ns {
4711 ns if *ns == *namespace => Some(KeyDescriptor {
4712 domain: *domain,
4713 nspace: *ns,
4714 alias: Some(alias.to_string()),
4715 blob: None,
4716 }),
4717 _ => None,
4718 })
4719 .collect();
4720 list_o_descriptors.sort();
4721 let mut list_result = db.list(*domain, *namespace)?;
4722 list_result.sort();
4723 assert_eq!(list_o_descriptors, list_result);
4724
4725 let mut list_o_ids: Vec<i64> = list_o_descriptors
4726 .into_iter()
4727 .map(|d| {
4728 let (_, entry) = db
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004729 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004730 &d,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004731 KeyType::Client,
4732 KeyEntryLoadBits::NONE,
4733 *namespace as u32,
4734 |_, _| Ok(()),
4735 )
Janis Danisevskise92a5e62020-12-02 12:57:41 -08004736 .unwrap();
4737 entry.id()
4738 })
4739 .collect();
4740 list_o_ids.sort_unstable();
4741 let mut loaded_entries: Vec<i64> = list_o_keys
4742 .iter()
4743 .filter_map(|(id, ns)| match ns {
4744 ns if *ns == *namespace => Some(*id),
4745 _ => None,
4746 })
4747 .collect();
4748 loaded_entries.sort_unstable();
4749 assert_eq!(list_o_ids, loaded_entries);
4750 }
4751 assert_eq!(Vec::<KeyDescriptor>::new(), db.list(Domain::SELINUX, 101)?);
4752
4753 Ok(())
4754 }
4755
Joel Galenson0891bc12020-07-20 10:37:03 -07004756 // Helpers
4757
4758 // Checks that the given result is an error containing the given string.
4759 fn check_result_is_error_containing_string<T>(result: Result<T>, target: &str) {
4760 let error_str = format!(
4761 "{:#?}",
4762 result.err().unwrap_or_else(|| panic!("Expected the error: {}", target))
4763 );
4764 assert!(
4765 error_str.contains(target),
4766 "The string \"{}\" should contain \"{}\"",
4767 error_str,
4768 target
4769 );
4770 }
4771
Joel Galenson2aab4432020-07-22 15:27:57 -07004772 #[derive(Debug, PartialEq)]
Joel Galenson0891bc12020-07-20 10:37:03 -07004773 struct KeyEntryRow {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004774 id: i64,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004775 key_type: KeyType,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07004776 domain: Option<Domain>,
Joel Galenson0891bc12020-07-20 10:37:03 -07004777 namespace: Option<i64>,
4778 alias: Option<String>,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004779 state: KeyLifeCycle,
Max Bires8e93d2b2021-01-14 13:17:59 -08004780 km_uuid: Option<Uuid>,
Joel Galenson0891bc12020-07-20 10:37:03 -07004781 }
4782
4783 fn get_keyentry(db: &KeystoreDB) -> Result<Vec<KeyEntryRow>> {
4784 db.conn
Joel Galenson2aab4432020-07-22 15:27:57 -07004785 .prepare("SELECT * FROM persistent.keyentry;")?
Joel Galenson0891bc12020-07-20 10:37:03 -07004786 .query_map(NO_PARAMS, |row| {
Joel Galenson0891bc12020-07-20 10:37:03 -07004787 Ok(KeyEntryRow {
4788 id: row.get(0)?,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004789 key_type: row.get(1)?,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07004790 domain: match row.get(2)? {
4791 Some(i) => Some(Domain(i)),
4792 None => None,
4793 },
Joel Galenson0891bc12020-07-20 10:37:03 -07004794 namespace: row.get(3)?,
4795 alias: row.get(4)?,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004796 state: row.get(5)?,
Max Bires8e93d2b2021-01-14 13:17:59 -08004797 km_uuid: row.get(6)?,
Joel Galenson0891bc12020-07-20 10:37:03 -07004798 })
4799 })?
4800 .map(|r| r.context("Could not read keyentry row."))
4801 .collect::<Result<Vec<_>>>()
4802 }
4803
Max Biresb2e1d032021-02-08 21:35:05 -08004804 struct RemoteProvValues {
4805 cert_chain: Vec<u8>,
4806 priv_key: Vec<u8>,
4807 batch_cert: Vec<u8>,
4808 }
4809
Max Bires2b2e6562020-09-22 11:22:36 -07004810 fn load_attestation_key_pool(
4811 db: &mut KeystoreDB,
4812 expiration_date: i64,
4813 namespace: i64,
4814 base_byte: u8,
Max Biresb2e1d032021-02-08 21:35:05 -08004815 ) -> Result<RemoteProvValues> {
Max Bires2b2e6562020-09-22 11:22:36 -07004816 let public_key: Vec<u8> = vec![base_byte, 0x02 * base_byte];
4817 let cert_chain: Vec<u8> = vec![0x03 * base_byte, 0x04 * base_byte];
4818 let priv_key: Vec<u8> = vec![0x05 * base_byte, 0x06 * base_byte];
4819 let raw_public_key: Vec<u8> = vec![0x0b * base_byte, 0x0c * base_byte];
Max Biresb2e1d032021-02-08 21:35:05 -08004820 let batch_cert: Vec<u8> = vec![base_byte * 0x0d, base_byte * 0x0e];
Max Bires2b2e6562020-09-22 11:22:36 -07004821 db.create_attestation_key_entry(&public_key, &raw_public_key, &priv_key, &KEYSTORE_UUID)?;
4822 db.store_signed_attestation_certificate_chain(
4823 &raw_public_key,
Max Biresb2e1d032021-02-08 21:35:05 -08004824 &batch_cert,
Max Bires2b2e6562020-09-22 11:22:36 -07004825 &cert_chain,
4826 expiration_date,
4827 &KEYSTORE_UUID,
4828 )?;
4829 db.assign_attestation_key(Domain::APP, namespace, &KEYSTORE_UUID)?;
Max Biresb2e1d032021-02-08 21:35:05 -08004830 Ok(RemoteProvValues { cert_chain, priv_key, batch_cert })
Max Bires2b2e6562020-09-22 11:22:36 -07004831 }
4832
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07004833 // Note: The parameters and SecurityLevel associations are nonsensical. This
4834 // collection is only used to check if the parameters are preserved as expected by the
4835 // database.
Qi Wub9433b52020-12-01 14:52:46 +08004836 fn make_test_params(max_usage_count: Option<i32>) -> Vec<KeyParameter> {
4837 let mut params = vec![
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07004838 KeyParameter::new(KeyParameterValue::Invalid, SecurityLevel::TRUSTED_ENVIRONMENT),
4839 KeyParameter::new(
4840 KeyParameterValue::KeyPurpose(KeyPurpose::SIGN),
4841 SecurityLevel::TRUSTED_ENVIRONMENT,
4842 ),
4843 KeyParameter::new(
4844 KeyParameterValue::KeyPurpose(KeyPurpose::DECRYPT),
4845 SecurityLevel::TRUSTED_ENVIRONMENT,
4846 ),
4847 KeyParameter::new(
4848 KeyParameterValue::Algorithm(Algorithm::RSA),
4849 SecurityLevel::TRUSTED_ENVIRONMENT,
4850 ),
4851 KeyParameter::new(KeyParameterValue::KeySize(1024), SecurityLevel::TRUSTED_ENVIRONMENT),
4852 KeyParameter::new(
4853 KeyParameterValue::BlockMode(BlockMode::ECB),
4854 SecurityLevel::TRUSTED_ENVIRONMENT,
4855 ),
4856 KeyParameter::new(
4857 KeyParameterValue::BlockMode(BlockMode::GCM),
4858 SecurityLevel::TRUSTED_ENVIRONMENT,
4859 ),
4860 KeyParameter::new(KeyParameterValue::Digest(Digest::NONE), SecurityLevel::STRONGBOX),
4861 KeyParameter::new(
4862 KeyParameterValue::Digest(Digest::MD5),
4863 SecurityLevel::TRUSTED_ENVIRONMENT,
4864 ),
4865 KeyParameter::new(
4866 KeyParameterValue::Digest(Digest::SHA_2_224),
4867 SecurityLevel::TRUSTED_ENVIRONMENT,
4868 ),
4869 KeyParameter::new(
4870 KeyParameterValue::Digest(Digest::SHA_2_256),
4871 SecurityLevel::STRONGBOX,
4872 ),
4873 KeyParameter::new(
4874 KeyParameterValue::PaddingMode(PaddingMode::NONE),
4875 SecurityLevel::TRUSTED_ENVIRONMENT,
4876 ),
4877 KeyParameter::new(
4878 KeyParameterValue::PaddingMode(PaddingMode::RSA_OAEP),
4879 SecurityLevel::TRUSTED_ENVIRONMENT,
4880 ),
4881 KeyParameter::new(
4882 KeyParameterValue::PaddingMode(PaddingMode::RSA_PSS),
4883 SecurityLevel::STRONGBOX,
4884 ),
4885 KeyParameter::new(
4886 KeyParameterValue::PaddingMode(PaddingMode::RSA_PKCS1_1_5_SIGN),
4887 SecurityLevel::TRUSTED_ENVIRONMENT,
4888 ),
4889 KeyParameter::new(KeyParameterValue::CallerNonce, SecurityLevel::TRUSTED_ENVIRONMENT),
4890 KeyParameter::new(KeyParameterValue::MinMacLength(256), SecurityLevel::STRONGBOX),
4891 KeyParameter::new(
4892 KeyParameterValue::EcCurve(EcCurve::P_224),
4893 SecurityLevel::TRUSTED_ENVIRONMENT,
4894 ),
4895 KeyParameter::new(KeyParameterValue::EcCurve(EcCurve::P_256), SecurityLevel::STRONGBOX),
4896 KeyParameter::new(
4897 KeyParameterValue::EcCurve(EcCurve::P_384),
4898 SecurityLevel::TRUSTED_ENVIRONMENT,
4899 ),
4900 KeyParameter::new(
4901 KeyParameterValue::EcCurve(EcCurve::P_521),
4902 SecurityLevel::TRUSTED_ENVIRONMENT,
4903 ),
4904 KeyParameter::new(
4905 KeyParameterValue::RSAPublicExponent(3),
4906 SecurityLevel::TRUSTED_ENVIRONMENT,
4907 ),
4908 KeyParameter::new(
4909 KeyParameterValue::IncludeUniqueID,
4910 SecurityLevel::TRUSTED_ENVIRONMENT,
4911 ),
4912 KeyParameter::new(KeyParameterValue::BootLoaderOnly, SecurityLevel::STRONGBOX),
4913 KeyParameter::new(KeyParameterValue::RollbackResistance, SecurityLevel::STRONGBOX),
4914 KeyParameter::new(
4915 KeyParameterValue::ActiveDateTime(1234567890),
4916 SecurityLevel::STRONGBOX,
4917 ),
4918 KeyParameter::new(
4919 KeyParameterValue::OriginationExpireDateTime(1234567890),
4920 SecurityLevel::TRUSTED_ENVIRONMENT,
4921 ),
4922 KeyParameter::new(
4923 KeyParameterValue::UsageExpireDateTime(1234567890),
4924 SecurityLevel::TRUSTED_ENVIRONMENT,
4925 ),
4926 KeyParameter::new(
4927 KeyParameterValue::MinSecondsBetweenOps(1234567890),
4928 SecurityLevel::TRUSTED_ENVIRONMENT,
4929 ),
4930 KeyParameter::new(
4931 KeyParameterValue::MaxUsesPerBoot(1234567890),
4932 SecurityLevel::TRUSTED_ENVIRONMENT,
4933 ),
4934 KeyParameter::new(KeyParameterValue::UserID(1), SecurityLevel::STRONGBOX),
4935 KeyParameter::new(KeyParameterValue::UserSecureID(42), SecurityLevel::STRONGBOX),
4936 KeyParameter::new(
4937 KeyParameterValue::NoAuthRequired,
4938 SecurityLevel::TRUSTED_ENVIRONMENT,
4939 ),
4940 KeyParameter::new(
4941 KeyParameterValue::HardwareAuthenticatorType(HardwareAuthenticatorType::PASSWORD),
4942 SecurityLevel::TRUSTED_ENVIRONMENT,
4943 ),
4944 KeyParameter::new(KeyParameterValue::AuthTimeout(1234567890), SecurityLevel::SOFTWARE),
4945 KeyParameter::new(KeyParameterValue::AllowWhileOnBody, SecurityLevel::SOFTWARE),
4946 KeyParameter::new(
4947 KeyParameterValue::TrustedUserPresenceRequired,
4948 SecurityLevel::TRUSTED_ENVIRONMENT,
4949 ),
4950 KeyParameter::new(
4951 KeyParameterValue::TrustedConfirmationRequired,
4952 SecurityLevel::TRUSTED_ENVIRONMENT,
4953 ),
4954 KeyParameter::new(
4955 KeyParameterValue::UnlockedDeviceRequired,
4956 SecurityLevel::TRUSTED_ENVIRONMENT,
4957 ),
4958 KeyParameter::new(
4959 KeyParameterValue::ApplicationID(vec![1u8, 2u8, 3u8, 4u8]),
4960 SecurityLevel::SOFTWARE,
4961 ),
4962 KeyParameter::new(
4963 KeyParameterValue::ApplicationData(vec![4u8, 3u8, 2u8, 1u8]),
4964 SecurityLevel::SOFTWARE,
4965 ),
4966 KeyParameter::new(
4967 KeyParameterValue::CreationDateTime(12345677890),
4968 SecurityLevel::SOFTWARE,
4969 ),
4970 KeyParameter::new(
4971 KeyParameterValue::KeyOrigin(KeyOrigin::GENERATED),
4972 SecurityLevel::TRUSTED_ENVIRONMENT,
4973 ),
4974 KeyParameter::new(
4975 KeyParameterValue::RootOfTrust(vec![3u8, 2u8, 1u8, 4u8]),
4976 SecurityLevel::TRUSTED_ENVIRONMENT,
4977 ),
4978 KeyParameter::new(KeyParameterValue::OSVersion(1), SecurityLevel::TRUSTED_ENVIRONMENT),
4979 KeyParameter::new(KeyParameterValue::OSPatchLevel(2), SecurityLevel::SOFTWARE),
4980 KeyParameter::new(
4981 KeyParameterValue::UniqueID(vec![4u8, 3u8, 1u8, 2u8]),
4982 SecurityLevel::SOFTWARE,
4983 ),
4984 KeyParameter::new(
4985 KeyParameterValue::AttestationChallenge(vec![4u8, 3u8, 1u8, 2u8]),
4986 SecurityLevel::TRUSTED_ENVIRONMENT,
4987 ),
4988 KeyParameter::new(
4989 KeyParameterValue::AttestationApplicationID(vec![4u8, 3u8, 1u8, 2u8]),
4990 SecurityLevel::TRUSTED_ENVIRONMENT,
4991 ),
4992 KeyParameter::new(
4993 KeyParameterValue::AttestationIdBrand(vec![4u8, 3u8, 1u8, 2u8]),
4994 SecurityLevel::TRUSTED_ENVIRONMENT,
4995 ),
4996 KeyParameter::new(
4997 KeyParameterValue::AttestationIdDevice(vec![4u8, 3u8, 1u8, 2u8]),
4998 SecurityLevel::TRUSTED_ENVIRONMENT,
4999 ),
5000 KeyParameter::new(
5001 KeyParameterValue::AttestationIdProduct(vec![4u8, 3u8, 1u8, 2u8]),
5002 SecurityLevel::TRUSTED_ENVIRONMENT,
5003 ),
5004 KeyParameter::new(
5005 KeyParameterValue::AttestationIdSerial(vec![4u8, 3u8, 1u8, 2u8]),
5006 SecurityLevel::TRUSTED_ENVIRONMENT,
5007 ),
5008 KeyParameter::new(
5009 KeyParameterValue::AttestationIdIMEI(vec![4u8, 3u8, 1u8, 2u8]),
5010 SecurityLevel::TRUSTED_ENVIRONMENT,
5011 ),
5012 KeyParameter::new(
5013 KeyParameterValue::AttestationIdMEID(vec![4u8, 3u8, 1u8, 2u8]),
5014 SecurityLevel::TRUSTED_ENVIRONMENT,
5015 ),
5016 KeyParameter::new(
5017 KeyParameterValue::AttestationIdManufacturer(vec![4u8, 3u8, 1u8, 2u8]),
5018 SecurityLevel::TRUSTED_ENVIRONMENT,
5019 ),
5020 KeyParameter::new(
5021 KeyParameterValue::AttestationIdModel(vec![4u8, 3u8, 1u8, 2u8]),
5022 SecurityLevel::TRUSTED_ENVIRONMENT,
5023 ),
5024 KeyParameter::new(
5025 KeyParameterValue::VendorPatchLevel(3),
5026 SecurityLevel::TRUSTED_ENVIRONMENT,
5027 ),
5028 KeyParameter::new(
5029 KeyParameterValue::BootPatchLevel(4),
5030 SecurityLevel::TRUSTED_ENVIRONMENT,
5031 ),
5032 KeyParameter::new(
5033 KeyParameterValue::AssociatedData(vec![4u8, 3u8, 1u8, 2u8]),
5034 SecurityLevel::TRUSTED_ENVIRONMENT,
5035 ),
5036 KeyParameter::new(
5037 KeyParameterValue::Nonce(vec![4u8, 3u8, 1u8, 2u8]),
5038 SecurityLevel::TRUSTED_ENVIRONMENT,
5039 ),
5040 KeyParameter::new(
5041 KeyParameterValue::MacLength(256),
5042 SecurityLevel::TRUSTED_ENVIRONMENT,
5043 ),
5044 KeyParameter::new(
5045 KeyParameterValue::ResetSinceIdRotation,
5046 SecurityLevel::TRUSTED_ENVIRONMENT,
5047 ),
5048 KeyParameter::new(
5049 KeyParameterValue::ConfirmationToken(vec![5u8, 5u8, 5u8, 5u8]),
5050 SecurityLevel::TRUSTED_ENVIRONMENT,
5051 ),
Qi Wub9433b52020-12-01 14:52:46 +08005052 ];
5053 if let Some(value) = max_usage_count {
5054 params.push(KeyParameter::new(
5055 KeyParameterValue::UsageCountLimit(value),
5056 SecurityLevel::SOFTWARE,
5057 ));
5058 }
5059 params
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07005060 }
5061
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07005062 fn make_test_key_entry(
5063 db: &mut KeystoreDB,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07005064 domain: Domain,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07005065 namespace: i64,
5066 alias: &str,
Qi Wub9433b52020-12-01 14:52:46 +08005067 max_usage_count: Option<i32>,
Janis Danisevskisaec14592020-11-12 09:41:49 -08005068 ) -> Result<KeyIdGuard> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08005069 let key_id = db.create_key_entry(&domain, &namespace, &KEYSTORE_UUID)?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08005070 let mut blob_metadata = BlobMetaData::new();
5071 blob_metadata.add(BlobMetaEntry::EncryptedBy(EncryptedBy::Password));
5072 blob_metadata.add(BlobMetaEntry::Salt(vec![1, 2, 3]));
5073 blob_metadata.add(BlobMetaEntry::Iv(vec![2, 3, 1]));
5074 blob_metadata.add(BlobMetaEntry::AeadTag(vec![3, 1, 2]));
5075 blob_metadata.add(BlobMetaEntry::KmUuid(KEYSTORE_UUID));
5076
5077 db.set_blob(
5078 &key_id,
5079 SubComponentType::KEY_BLOB,
5080 Some(TEST_KEY_BLOB),
5081 Some(&blob_metadata),
5082 )?;
5083 db.set_blob(&key_id, SubComponentType::CERT, Some(TEST_CERT_BLOB), None)?;
5084 db.set_blob(&key_id, SubComponentType::CERT_CHAIN, Some(TEST_CERT_CHAIN_BLOB), None)?;
Qi Wub9433b52020-12-01 14:52:46 +08005085
5086 let params = make_test_params(max_usage_count);
5087 db.insert_keyparameter(&key_id, &params)?;
5088
Janis Danisevskisb42fc182020-12-15 08:41:27 -08005089 let mut metadata = KeyMetaData::new();
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08005090 metadata.add(KeyMetaEntry::CreationDate(DateTime::from_millis_epoch(123456789)));
Janis Danisevskisb42fc182020-12-15 08:41:27 -08005091 db.insert_key_metadata(&key_id, &metadata)?;
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08005092 rebind_alias(db, &key_id, alias, domain, namespace)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07005093 Ok(key_id)
5094 }
5095
Qi Wub9433b52020-12-01 14:52:46 +08005096 fn make_test_key_entry_test_vector(key_id: i64, max_usage_count: Option<i32>) -> KeyEntry {
5097 let params = make_test_params(max_usage_count);
5098
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08005099 let mut blob_metadata = BlobMetaData::new();
5100 blob_metadata.add(BlobMetaEntry::EncryptedBy(EncryptedBy::Password));
5101 blob_metadata.add(BlobMetaEntry::Salt(vec![1, 2, 3]));
5102 blob_metadata.add(BlobMetaEntry::Iv(vec![2, 3, 1]));
5103 blob_metadata.add(BlobMetaEntry::AeadTag(vec![3, 1, 2]));
5104 blob_metadata.add(BlobMetaEntry::KmUuid(KEYSTORE_UUID));
5105
Janis Danisevskisb42fc182020-12-15 08:41:27 -08005106 let mut metadata = KeyMetaData::new();
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08005107 metadata.add(KeyMetaEntry::CreationDate(DateTime::from_millis_epoch(123456789)));
Janis Danisevskisb42fc182020-12-15 08:41:27 -08005108
5109 KeyEntry {
5110 id: key_id,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08005111 key_blob_info: Some((TEST_KEY_BLOB.to_vec(), blob_metadata)),
Janis Danisevskisb42fc182020-12-15 08:41:27 -08005112 cert: Some(TEST_CERT_BLOB.to_vec()),
5113 cert_chain: Some(TEST_CERT_CHAIN_BLOB.to_vec()),
Max Bires8e93d2b2021-01-14 13:17:59 -08005114 km_uuid: KEYSTORE_UUID,
Qi Wub9433b52020-12-01 14:52:46 +08005115 parameters: params,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08005116 metadata,
Janis Danisevskis377d1002021-01-27 19:07:48 -08005117 pure_cert: false,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08005118 }
5119 }
5120
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07005121 fn debug_dump_keyentry_table(db: &mut KeystoreDB) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08005122 let mut stmt = db.conn.prepare(
Max Bires8e93d2b2021-01-14 13:17:59 -08005123 "SELECT id, key_type, domain, namespace, alias, state, km_uuid FROM persistent.keyentry;",
Janis Danisevskis93927dd2020-12-23 12:23:08 -08005124 )?;
Max Bires8e93d2b2021-01-14 13:17:59 -08005125 let rows = stmt.query_map::<(i64, KeyType, i32, i64, String, KeyLifeCycle, Uuid), _, _>(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08005126 NO_PARAMS,
5127 |row| {
Max Bires8e93d2b2021-01-14 13:17:59 -08005128 Ok((
5129 row.get(0)?,
5130 row.get(1)?,
5131 row.get(2)?,
5132 row.get(3)?,
5133 row.get(4)?,
5134 row.get(5)?,
5135 row.get(6)?,
5136 ))
Janis Danisevskis93927dd2020-12-23 12:23:08 -08005137 },
5138 )?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07005139
5140 println!("Key entry table rows:");
5141 for r in rows {
Max Bires8e93d2b2021-01-14 13:17:59 -08005142 let (id, key_type, domain, namespace, alias, state, km_uuid) = r.unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07005143 println!(
Max Bires8e93d2b2021-01-14 13:17:59 -08005144 " id: {} KeyType: {:?} Domain: {} Namespace: {} Alias: {} State: {:?} KmUuid: {:?}",
5145 id, key_type, domain, namespace, alias, state, km_uuid
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07005146 );
5147 }
5148 Ok(())
5149 }
5150
5151 fn debug_dump_grant_table(db: &mut KeystoreDB) -> Result<()> {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08005152 let mut stmt = db
5153 .conn
5154 .prepare("SELECT id, grantee, keyentryid, access_vector FROM persistent.grant;")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07005155 let rows = stmt.query_map::<(i64, i64, i64, i64), _, _>(NO_PARAMS, |row| {
5156 Ok((row.get(0)?, row.get(1)?, row.get(2)?, row.get(3)?))
5157 })?;
5158
5159 println!("Grant table rows:");
5160 for r in rows {
5161 let (id, gt, ki, av) = r.unwrap();
5162 println!(" id: {} grantee: {} key_id: {} access_vector: {}", id, gt, ki, av);
5163 }
5164 Ok(())
5165 }
5166
Joel Galenson0891bc12020-07-20 10:37:03 -07005167 // Use a custom random number generator that repeats each number once.
5168 // This allows us to test repeated elements.
5169
5170 thread_local! {
5171 static RANDOM_COUNTER: RefCell<i64> = RefCell::new(0);
5172 }
5173
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07005174 fn reset_random() {
5175 RANDOM_COUNTER.with(|counter| {
5176 *counter.borrow_mut() = 0;
5177 })
5178 }
5179
Joel Galenson0891bc12020-07-20 10:37:03 -07005180 pub fn random() -> i64 {
5181 RANDOM_COUNTER.with(|counter| {
5182 let result = *counter.borrow() / 2;
5183 *counter.borrow_mut() += 1;
5184 result
5185 })
5186 }
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00005187
5188 #[test]
5189 fn test_last_off_body() -> Result<()> {
5190 let mut db = new_test_db()?;
Matthew Maurerd7815ca2021-05-06 21:58:45 -07005191 db.insert_last_off_body(MonotonicRawTime::now());
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00005192 let tx = db.conn.transaction_with_behavior(TransactionBehavior::Immediate)?;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00005193 tx.commit()?;
Matthew Maurerd7815ca2021-05-06 21:58:45 -07005194 let last_off_body_1 = db.get_last_off_body();
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00005195 let one_second = Duration::from_secs(1);
5196 thread::sleep(one_second);
Matthew Maurerd7815ca2021-05-06 21:58:45 -07005197 db.update_last_off_body(MonotonicRawTime::now());
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00005198 let tx2 = db.conn.transaction_with_behavior(TransactionBehavior::Immediate)?;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00005199 tx2.commit()?;
Matthew Maurerd7815ca2021-05-06 21:58:45 -07005200 let last_off_body_2 = db.get_last_off_body();
Hasini Gunasinghe66a24602021-05-12 19:03:12 +00005201 assert!(last_off_body_1 < last_off_body_2);
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00005202 Ok(())
5203 }
Hasini Gunasingheda895552021-01-27 19:34:37 +00005204
5205 #[test]
5206 fn test_unbind_keys_for_user() -> Result<()> {
5207 let mut db = new_test_db()?;
5208 db.unbind_keys_for_user(1, false)?;
5209
5210 make_test_key_entry(&mut db, Domain::APP, 210000, TEST_ALIAS, None)?;
5211 make_test_key_entry(&mut db, Domain::APP, 110000, TEST_ALIAS, None)?;
5212 db.unbind_keys_for_user(2, false)?;
5213
5214 assert_eq!(1, db.list(Domain::APP, 110000)?.len());
5215 assert_eq!(0, db.list(Domain::APP, 210000)?.len());
5216
5217 db.unbind_keys_for_user(1, true)?;
5218 assert_eq!(0, db.list(Domain::APP, 110000)?.len());
5219
5220 Ok(())
5221 }
5222
5223 #[test]
5224 fn test_store_super_key() -> Result<()> {
5225 let mut db = new_test_db()?;
Paul Crowleyf61fee72021-03-17 14:38:44 -07005226 let pw: keystore2_crypto::Password = (&b"xyzabc"[..]).into();
Hasini Gunasingheda895552021-01-27 19:34:37 +00005227 let super_key = keystore2_crypto::generate_aes256_key()?;
Paul Crowley7a658392021-03-18 17:08:20 -07005228 let secret_bytes = b"keystore2 is great.";
Hasini Gunasingheda895552021-01-27 19:34:37 +00005229 let (encrypted_secret, iv, tag) =
Paul Crowley7a658392021-03-18 17:08:20 -07005230 keystore2_crypto::aes_gcm_encrypt(secret_bytes, &super_key)?;
Hasini Gunasingheda895552021-01-27 19:34:37 +00005231
5232 let (encrypted_super_key, metadata) =
5233 SuperKeyManager::encrypt_with_password(&super_key, &pw)?;
Paul Crowley8d5b2532021-03-19 10:53:07 -07005234 db.store_super_key(
5235 1,
5236 &USER_SUPER_KEY,
5237 &encrypted_super_key,
5238 &metadata,
5239 &KeyMetaData::new(),
5240 )?;
Hasini Gunasingheda895552021-01-27 19:34:37 +00005241
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00005242 //check if super key exists
Paul Crowley7a658392021-03-18 17:08:20 -07005243 assert!(db.key_exists(Domain::APP, 1, &USER_SUPER_KEY.alias, KeyType::Super)?);
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00005244
Paul Crowley7a658392021-03-18 17:08:20 -07005245 let (_, key_entry) = db.load_super_key(&USER_SUPER_KEY, 1)?.unwrap();
Paul Crowley8d5b2532021-03-19 10:53:07 -07005246 let loaded_super_key = SuperKeyManager::extract_super_key_from_key_entry(
5247 USER_SUPER_KEY.algorithm,
5248 key_entry,
5249 &pw,
5250 None,
5251 )?;
Hasini Gunasingheda895552021-01-27 19:34:37 +00005252
Paul Crowley7a658392021-03-18 17:08:20 -07005253 let decrypted_secret_bytes =
5254 loaded_super_key.aes_gcm_decrypt(&encrypted_secret, &iv, &tag)?;
5255 assert_eq!(secret_bytes, &*decrypted_secret_bytes);
Hasini Gunasingheda895552021-01-27 19:34:37 +00005256 Ok(())
5257 }
Seth Moore78c091f2021-04-09 21:38:30 +00005258
5259 fn get_valid_statsd_storage_types() -> Vec<StatsdStorageType> {
5260 vec![
5261 StatsdStorageType::KeyEntry,
5262 StatsdStorageType::KeyEntryIdIndex,
5263 StatsdStorageType::KeyEntryDomainNamespaceIndex,
5264 StatsdStorageType::BlobEntry,
5265 StatsdStorageType::BlobEntryKeyEntryIdIndex,
5266 StatsdStorageType::KeyParameter,
5267 StatsdStorageType::KeyParameterKeyEntryIdIndex,
5268 StatsdStorageType::KeyMetadata,
5269 StatsdStorageType::KeyMetadataKeyEntryIdIndex,
5270 StatsdStorageType::Grant,
5271 StatsdStorageType::AuthToken,
5272 StatsdStorageType::BlobMetadata,
5273 StatsdStorageType::BlobMetadataBlobEntryIdIndex,
5274 ]
5275 }
5276
5277 /// Perform a simple check to ensure that we can query all the storage types
5278 /// that are supported by the DB. Check for reasonable values.
5279 #[test]
5280 fn test_query_all_valid_table_sizes() -> Result<()> {
5281 const PAGE_SIZE: i64 = 4096;
5282
5283 let mut db = new_test_db()?;
5284
5285 for t in get_valid_statsd_storage_types() {
5286 let stat = db.get_storage_stat(t)?;
Matthew Maurerd7815ca2021-05-06 21:58:45 -07005287 // AuthToken can be less than a page since it's in a btree, not sqlite
5288 // TODO(b/187474736) stop using if-let here
5289 if let StatsdStorageType::AuthToken = t {
5290 } else {
5291 assert!(stat.size >= PAGE_SIZE);
5292 }
Seth Moore78c091f2021-04-09 21:38:30 +00005293 assert!(stat.size >= stat.unused_size);
5294 }
5295
5296 Ok(())
5297 }
5298
5299 fn get_storage_stats_map(db: &mut KeystoreDB) -> BTreeMap<i32, Keystore2StorageStats> {
5300 get_valid_statsd_storage_types()
5301 .into_iter()
5302 .map(|t| (t as i32, db.get_storage_stat(t).unwrap()))
5303 .collect()
5304 }
5305
5306 fn assert_storage_increased(
5307 db: &mut KeystoreDB,
5308 increased_storage_types: Vec<StatsdStorageType>,
5309 baseline: &mut BTreeMap<i32, Keystore2StorageStats>,
5310 ) {
5311 for storage in increased_storage_types {
5312 // Verify the expected storage increased.
5313 let new = db.get_storage_stat(storage).unwrap();
5314 let storage = storage as i32;
5315 let old = &baseline[&storage];
5316 assert!(new.size >= old.size, "{}: {} >= {}", storage, new.size, old.size);
5317 assert!(
5318 new.unused_size <= old.unused_size,
5319 "{}: {} <= {}",
5320 storage,
5321 new.unused_size,
5322 old.unused_size
5323 );
5324
5325 // Update the baseline with the new value so that it succeeds in the
5326 // later comparison.
5327 baseline.insert(storage, new);
5328 }
5329
5330 // Get an updated map of the storage and verify there were no unexpected changes.
5331 let updated_stats = get_storage_stats_map(db);
5332 assert_eq!(updated_stats.len(), baseline.len());
5333
5334 for &k in baseline.keys() {
5335 let stringify = |map: &BTreeMap<i32, Keystore2StorageStats>| -> String {
5336 let mut s = String::new();
5337 for &k in map.keys() {
5338 writeln!(&mut s, " {}: {}, {}", &k, map[&k].size, map[&k].unused_size)
5339 .expect("string concat failed");
5340 }
5341 s
5342 };
5343
5344 assert!(
5345 updated_stats[&k].size == baseline[&k].size
5346 && updated_stats[&k].unused_size == baseline[&k].unused_size,
5347 "updated_stats:\n{}\nbaseline:\n{}",
5348 stringify(&updated_stats),
5349 stringify(&baseline)
5350 );
5351 }
5352 }
5353
5354 #[test]
5355 fn test_verify_key_table_size_reporting() -> Result<()> {
5356 let mut db = new_test_db()?;
5357 let mut working_stats = get_storage_stats_map(&mut db);
5358
5359 let key_id = db.create_key_entry(&Domain::APP, &42, &KEYSTORE_UUID)?;
5360 assert_storage_increased(
5361 &mut db,
5362 vec![
5363 StatsdStorageType::KeyEntry,
5364 StatsdStorageType::KeyEntryIdIndex,
5365 StatsdStorageType::KeyEntryDomainNamespaceIndex,
5366 ],
5367 &mut working_stats,
5368 );
5369
5370 let mut blob_metadata = BlobMetaData::new();
5371 blob_metadata.add(BlobMetaEntry::EncryptedBy(EncryptedBy::Password));
5372 db.set_blob(&key_id, SubComponentType::KEY_BLOB, Some(TEST_KEY_BLOB), None)?;
5373 assert_storage_increased(
5374 &mut db,
5375 vec![
5376 StatsdStorageType::BlobEntry,
5377 StatsdStorageType::BlobEntryKeyEntryIdIndex,
5378 StatsdStorageType::BlobMetadata,
5379 StatsdStorageType::BlobMetadataBlobEntryIdIndex,
5380 ],
5381 &mut working_stats,
5382 );
5383
5384 let params = make_test_params(None);
5385 db.insert_keyparameter(&key_id, &params)?;
5386 assert_storage_increased(
5387 &mut db,
5388 vec![StatsdStorageType::KeyParameter, StatsdStorageType::KeyParameterKeyEntryIdIndex],
5389 &mut working_stats,
5390 );
5391
5392 let mut metadata = KeyMetaData::new();
5393 metadata.add(KeyMetaEntry::CreationDate(DateTime::from_millis_epoch(123456789)));
5394 db.insert_key_metadata(&key_id, &metadata)?;
5395 assert_storage_increased(
5396 &mut db,
5397 vec![StatsdStorageType::KeyMetadata, StatsdStorageType::KeyMetadataKeyEntryIdIndex],
5398 &mut working_stats,
5399 );
5400
5401 let mut sum = 0;
5402 for stat in working_stats.values() {
5403 sum += stat.size;
5404 }
5405 let total = db.get_storage_stat(StatsdStorageType::Database)?.size;
5406 assert!(sum <= total, "Expected sum <= total. sum: {}, total: {}", sum, total);
5407
5408 Ok(())
5409 }
5410
5411 #[test]
5412 fn test_verify_auth_table_size_reporting() -> Result<()> {
5413 let mut db = new_test_db()?;
5414 let mut working_stats = get_storage_stats_map(&mut db);
5415 db.insert_auth_token(&HardwareAuthToken {
5416 challenge: 123,
5417 userId: 456,
5418 authenticatorId: 789,
5419 authenticatorType: kmhw_authenticator_type::ANY,
5420 timestamp: Timestamp { milliSeconds: 10 },
5421 mac: b"mac".to_vec(),
Matthew Maurerd7815ca2021-05-06 21:58:45 -07005422 });
Seth Moore78c091f2021-04-09 21:38:30 +00005423 assert_storage_increased(&mut db, vec![StatsdStorageType::AuthToken], &mut working_stats);
5424 Ok(())
5425 }
5426
5427 #[test]
5428 fn test_verify_grant_table_size_reporting() -> Result<()> {
5429 const OWNER: i64 = 1;
5430 let mut db = new_test_db()?;
5431 make_test_key_entry(&mut db, Domain::APP, OWNER, TEST_ALIAS, None)?;
5432
5433 let mut working_stats = get_storage_stats_map(&mut db);
5434 db.grant(
5435 &KeyDescriptor {
5436 domain: Domain::APP,
5437 nspace: 0,
5438 alias: Some(TEST_ALIAS.to_string()),
5439 blob: None,
5440 },
5441 OWNER as u32,
5442 123,
5443 key_perm_set![KeyPerm::use_()],
5444 |_, _| Ok(()),
5445 )?;
5446
5447 assert_storage_increased(&mut db, vec![StatsdStorageType::Grant], &mut working_stats);
5448
5449 Ok(())
5450 }
Matthew Maurerd7815ca2021-05-06 21:58:45 -07005451
5452 #[test]
5453 fn find_auth_token_entry_returns_latest() -> Result<()> {
5454 let mut db = new_test_db()?;
5455 db.insert_auth_token(&HardwareAuthToken {
5456 challenge: 123,
5457 userId: 456,
5458 authenticatorId: 789,
5459 authenticatorType: kmhw_authenticator_type::ANY,
5460 timestamp: Timestamp { milliSeconds: 10 },
5461 mac: b"mac0".to_vec(),
5462 });
5463 std::thread::sleep(std::time::Duration::from_millis(1));
5464 db.insert_auth_token(&HardwareAuthToken {
5465 challenge: 123,
5466 userId: 457,
5467 authenticatorId: 789,
5468 authenticatorType: kmhw_authenticator_type::ANY,
5469 timestamp: Timestamp { milliSeconds: 12 },
5470 mac: b"mac1".to_vec(),
5471 });
5472 std::thread::sleep(std::time::Duration::from_millis(1));
5473 db.insert_auth_token(&HardwareAuthToken {
5474 challenge: 123,
5475 userId: 458,
5476 authenticatorId: 789,
5477 authenticatorType: kmhw_authenticator_type::ANY,
5478 timestamp: Timestamp { milliSeconds: 3 },
5479 mac: b"mac2".to_vec(),
5480 });
5481 // All three entries are in the database
5482 assert_eq!(db.perboot.auth_tokens_len(), 3);
5483 // It selected the most recent timestamp
5484 assert_eq!(db.find_auth_token_entry(|_| true).unwrap().0.auth_token.mac, b"mac2".to_vec());
5485 Ok(())
5486 }
Joel Galenson26f4d012020-07-17 14:57:21 -07005487}