blob: dc0cefe930c50f7b8ff92874cb9b1d062026dcef [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;
Janis Danisevskis030ba022021-05-26 11:15:30 -070045pub(crate) mod utils;
Matthew Maurerd7815ca2021-05-06 21:58:45 -070046
Janis Danisevskisb42fc182020-12-15 08:41:27 -080047use crate::impl_metadata; // This is in db_utils.rs
Janis Danisevskis4522c2b2020-11-27 18:04:58 -080048use crate::key_parameter::{KeyParameter, Tag};
Janis Danisevskisc5b210b2020-09-11 13:27:37 -070049use crate::permission::KeyPermSet;
Hasini Gunasinghe66a24602021-05-12 19:03:12 +000050use crate::utils::{get_current_time_in_milliseconds, watchdog as wd, AID_USER_OFFSET};
Janis Danisevskis7e8b4622021-02-13 10:01:59 -080051use crate::{
Paul Crowley7a658392021-03-18 17:08:20 -070052 error::{Error as KsError, ErrorCode, ResponseCode},
53 super_key::SuperKeyType,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -080054};
Janis Danisevskis030ba022021-05-26 11:15:30 -070055use crate::{gc::Gc, super_key::USER_SUPER_KEY};
Janis Danisevskisb42fc182020-12-15 08:41:27 -080056use anyhow::{anyhow, Context, Result};
Max Bires8e93d2b2021-01-14 13:17:59 -080057use std::{convert::TryFrom, convert::TryInto, ops::Deref, time::SystemTimeError};
Janis Danisevskis030ba022021-05-26 11:15:30 -070058use utils as db_utils;
59use utils::SqlField;
Janis Danisevskis60400fe2020-08-26 15:24:42 -070060
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +000061use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
Janis Danisevskis5ed8c532021-01-11 14:19:42 -080062 HardwareAuthToken::HardwareAuthToken,
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +000063 HardwareAuthenticatorType::HardwareAuthenticatorType, SecurityLevel::SecurityLevel,
Janis Danisevskisc3a496b2021-01-05 10:37:22 -080064};
Janis Danisevskisc5b210b2020-09-11 13:27:37 -070065use android_system_keystore2::aidl::android::system::keystore2::{
Janis Danisevskis04b02832020-10-26 09:21:40 -070066 Domain::Domain, KeyDescriptor::KeyDescriptor,
Janis Danisevskis60400fe2020-08-26 15:24:42 -070067};
Max Bires2b2e6562020-09-22 11:22:36 -070068use android_security_remoteprovisioning::aidl::android::security::remoteprovisioning::{
69 AttestationPoolStatus::AttestationPoolStatus,
70};
Seth Moore78c091f2021-04-09 21:38:30 +000071use statslog_rust::keystore2_storage_stats::{
72 Keystore2StorageStats, StorageType as StatsdStorageType,
73};
Max Bires2b2e6562020-09-22 11:22:36 -070074
75use keystore2_crypto::ZVec;
Janis Danisevskisaec14592020-11-12 09:41:49 -080076use lazy_static::lazy_static;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +000077use log::error;
Joel Galenson0891bc12020-07-20 10:37:03 -070078#[cfg(not(test))]
79use rand::prelude::random;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -070080use rusqlite::{
Joel Galensonff79e362021-05-25 16:30:17 -070081 params, params_from_iter,
Janis Danisevskisb42fc182020-12-15 08:41:27 -080082 types::FromSql,
83 types::FromSqlResult,
84 types::ToSqlOutput,
85 types::{FromSqlError, Value, ValueRef},
Janis Danisevskis5ed8c532021-01-11 14:19:42 -080086 Connection, OptionalExtension, ToSql, Transaction, TransactionBehavior, NO_PARAMS,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -070087};
Max Bires2b2e6562020-09-22 11:22:36 -070088
Janis Danisevskisaec14592020-11-12 09:41:49 -080089use std::{
Janis Danisevskisb42fc182020-12-15 08:41:27 -080090 collections::{HashMap, HashSet},
Janis Danisevskisbf15d732020-12-08 10:35:26 -080091 path::Path,
Janis Danisevskis3395f862021-05-06 10:54:17 -070092 sync::{Arc, Condvar, Mutex},
Janis Danisevskisb42fc182020-12-15 08:41:27 -080093 time::{Duration, SystemTime},
Janis Danisevskisaec14592020-11-12 09:41:49 -080094};
Max Bires2b2e6562020-09-22 11:22:36 -070095
Joel Galenson0891bc12020-07-20 10:37:03 -070096#[cfg(test)]
97use tests::random;
Joel Galenson26f4d012020-07-17 14:57:21 -070098
Janis Danisevskisb42fc182020-12-15 08:41:27 -080099impl_metadata!(
100 /// A set of metadata for key entries.
101 #[derive(Debug, Default, Eq, PartialEq)]
102 pub struct KeyMetaData;
103 /// A metadata entry for key entries.
104 #[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
105 pub enum KeyMetaEntry {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800106 /// Date of the creation of the key entry.
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800107 CreationDate(DateTime) with accessor creation_date,
108 /// Expiration date for attestation keys.
109 AttestationExpirationDate(DateTime) with accessor attestation_expiration_date,
Max Bires2b2e6562020-09-22 11:22:36 -0700110 /// CBOR Blob that represents a COSE_Key and associated metadata needed for remote
111 /// provisioning
112 AttestationMacedPublicKey(Vec<u8>) with accessor attestation_maced_public_key,
113 /// Vector representing the raw public key so results from the server can be matched
114 /// to the right entry
115 AttestationRawPubKey(Vec<u8>) with accessor attestation_raw_pub_key,
Paul Crowley8d5b2532021-03-19 10:53:07 -0700116 /// SEC1 public key for ECDH encryption
117 Sec1PublicKey(Vec<u8>) with accessor sec1_public_key,
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800118 // --- ADD NEW META DATA FIELDS HERE ---
119 // For backwards compatibility add new entries only to
120 // end of this list and above this comment.
121 };
122);
123
124impl KeyMetaData {
125 fn load_from_db(key_id: i64, tx: &Transaction) -> Result<Self> {
126 let mut stmt = tx
127 .prepare(
128 "SELECT tag, data from persistent.keymetadata
129 WHERE keyentryid = ?;",
130 )
131 .context("In KeyMetaData::load_from_db: prepare statement failed.")?;
132
133 let mut metadata: HashMap<i64, KeyMetaEntry> = Default::default();
134
135 let mut rows =
136 stmt.query(params![key_id]).context("In KeyMetaData::load_from_db: query failed.")?;
137 db_utils::with_rows_extract_all(&mut rows, |row| {
138 let db_tag: i64 = row.get(0).context("Failed to read tag.")?;
139 metadata.insert(
140 db_tag,
141 KeyMetaEntry::new_from_sql(db_tag, &SqlField::new(1, &row))
142 .context("Failed to read KeyMetaEntry.")?,
143 );
144 Ok(())
145 })
146 .context("In KeyMetaData::load_from_db.")?;
147
148 Ok(Self { data: metadata })
149 }
150
151 fn store_in_db(&self, key_id: i64, tx: &Transaction) -> Result<()> {
152 let mut stmt = tx
153 .prepare(
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000154 "INSERT or REPLACE INTO persistent.keymetadata (keyentryid, tag, data)
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800155 VALUES (?, ?, ?);",
156 )
157 .context("In KeyMetaData::store_in_db: Failed to prepare statement.")?;
158
159 let iter = self.data.iter();
160 for (tag, entry) in iter {
161 stmt.insert(params![key_id, tag, entry,]).with_context(|| {
162 format!("In KeyMetaData::store_in_db: Failed to insert {:?}", entry)
163 })?;
164 }
165 Ok(())
166 }
167}
168
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800169impl_metadata!(
170 /// A set of metadata for key blobs.
171 #[derive(Debug, Default, Eq, PartialEq)]
172 pub struct BlobMetaData;
173 /// A metadata entry for key blobs.
174 #[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
175 pub enum BlobMetaEntry {
176 /// If present, indicates that the blob is encrypted with another key or a key derived
177 /// from a password.
178 EncryptedBy(EncryptedBy) with accessor encrypted_by,
179 /// If the blob is password encrypted this field is set to the
180 /// salt used for the key derivation.
181 Salt(Vec<u8>) with accessor salt,
182 /// If the blob is encrypted, this field is set to the initialization vector.
183 Iv(Vec<u8>) with accessor iv,
184 /// If the blob is encrypted, this field holds the AEAD TAG.
185 AeadTag(Vec<u8>) with accessor aead_tag,
186 /// The uuid of the owning KeyMint instance.
187 KmUuid(Uuid) with accessor km_uuid,
Paul Crowley8d5b2532021-03-19 10:53:07 -0700188 /// If the key is ECDH encrypted, this is the ephemeral public key
189 PublicKey(Vec<u8>) with accessor public_key,
Paul Crowley44c02da2021-04-08 17:04:43 +0000190 /// If the key is encrypted with a MaxBootLevel key, this is the boot level
191 /// of that key
192 MaxBootLevel(i32) with accessor max_boot_level,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800193 // --- ADD NEW META DATA FIELDS HERE ---
194 // For backwards compatibility add new entries only to
195 // end of this list and above this comment.
196 };
197);
198
199impl BlobMetaData {
200 fn load_from_db(blob_id: i64, tx: &Transaction) -> Result<Self> {
201 let mut stmt = tx
202 .prepare(
203 "SELECT tag, data from persistent.blobmetadata
204 WHERE blobentryid = ?;",
205 )
206 .context("In BlobMetaData::load_from_db: prepare statement failed.")?;
207
208 let mut metadata: HashMap<i64, BlobMetaEntry> = Default::default();
209
210 let mut rows =
211 stmt.query(params![blob_id]).context("In BlobMetaData::load_from_db: query failed.")?;
212 db_utils::with_rows_extract_all(&mut rows, |row| {
213 let db_tag: i64 = row.get(0).context("Failed to read tag.")?;
214 metadata.insert(
215 db_tag,
216 BlobMetaEntry::new_from_sql(db_tag, &SqlField::new(1, &row))
217 .context("Failed to read BlobMetaEntry.")?,
218 );
219 Ok(())
220 })
221 .context("In BlobMetaData::load_from_db.")?;
222
223 Ok(Self { data: metadata })
224 }
225
226 fn store_in_db(&self, blob_id: i64, tx: &Transaction) -> Result<()> {
227 let mut stmt = tx
228 .prepare(
229 "INSERT or REPLACE INTO persistent.blobmetadata (blobentryid, tag, data)
230 VALUES (?, ?, ?);",
231 )
232 .context("In BlobMetaData::store_in_db: Failed to prepare statement.")?;
233
234 let iter = self.data.iter();
235 for (tag, entry) in iter {
236 stmt.insert(params![blob_id, tag, entry,]).with_context(|| {
237 format!("In BlobMetaData::store_in_db: Failed to insert {:?}", entry)
238 })?;
239 }
240 Ok(())
241 }
242}
243
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800244/// Indicates the type of the keyentry.
245#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
246pub enum KeyType {
247 /// This is a client key type. These keys are created or imported through the Keystore 2.0
248 /// AIDL interface android.system.keystore2.
249 Client,
250 /// This is a super key type. These keys are created by keystore itself and used to encrypt
251 /// other key blobs to provide LSKF binding.
252 Super,
253 /// This is an attestation key. These keys are created by the remote provisioning mechanism.
254 Attestation,
255}
256
257impl ToSql for KeyType {
258 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
259 Ok(ToSqlOutput::Owned(Value::Integer(match self {
260 KeyType::Client => 0,
261 KeyType::Super => 1,
262 KeyType::Attestation => 2,
263 })))
264 }
265}
266
267impl FromSql for KeyType {
268 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
269 match i64::column_result(value)? {
270 0 => Ok(KeyType::Client),
271 1 => Ok(KeyType::Super),
272 2 => Ok(KeyType::Attestation),
273 v => Err(FromSqlError::OutOfRange(v)),
274 }
275 }
276}
277
Max Bires8e93d2b2021-01-14 13:17:59 -0800278/// Uuid representation that can be stored in the database.
279/// Right now it can only be initialized from SecurityLevel.
280/// Once KeyMint provides a UUID type a corresponding From impl shall be added.
281#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
282pub struct Uuid([u8; 16]);
283
284impl Deref for Uuid {
285 type Target = [u8; 16];
286
287 fn deref(&self) -> &Self::Target {
288 &self.0
289 }
290}
291
292impl From<SecurityLevel> for Uuid {
293 fn from(sec_level: SecurityLevel) -> Self {
294 Self((sec_level.0 as u128).to_be_bytes())
295 }
296}
297
298impl ToSql for Uuid {
299 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
300 self.0.to_sql()
301 }
302}
303
304impl FromSql for Uuid {
305 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
306 let blob = Vec::<u8>::column_result(value)?;
307 if blob.len() != 16 {
308 return Err(FromSqlError::OutOfRange(blob.len() as i64));
309 }
310 let mut arr = [0u8; 16];
311 arr.copy_from_slice(&blob);
312 Ok(Self(arr))
313 }
314}
315
316/// Key entries that are not associated with any KeyMint instance, such as pure certificate
317/// entries are associated with this UUID.
318pub static KEYSTORE_UUID: Uuid = Uuid([
319 0x41, 0xe3, 0xb9, 0xce, 0x27, 0x58, 0x4e, 0x91, 0xbc, 0xfd, 0xa5, 0x5d, 0x91, 0x85, 0xab, 0x11,
320]);
321
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800322/// Indicates how the sensitive part of this key blob is encrypted.
323#[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
324pub enum EncryptedBy {
325 /// The keyblob is encrypted by a user password.
326 /// In the database this variant is represented as NULL.
327 Password,
328 /// The keyblob is encrypted by another key with wrapped key id.
329 /// In the database this variant is represented as non NULL value
330 /// that is convertible to i64, typically NUMERIC.
331 KeyId(i64),
332}
333
334impl ToSql for EncryptedBy {
335 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
336 match self {
337 Self::Password => Ok(ToSqlOutput::Owned(Value::Null)),
338 Self::KeyId(id) => id.to_sql(),
339 }
340 }
341}
342
343impl FromSql for EncryptedBy {
344 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
345 match value {
346 ValueRef::Null => Ok(Self::Password),
347 _ => Ok(Self::KeyId(i64::column_result(value)?)),
348 }
349 }
350}
351
352/// A database representation of wall clock time. DateTime stores unix epoch time as
353/// i64 in milliseconds.
354#[derive(Debug, Copy, Clone, Default, Eq, PartialEq, Ord, PartialOrd)]
355pub struct DateTime(i64);
356
357/// Error type returned when creating DateTime or converting it from and to
358/// SystemTime.
359#[derive(thiserror::Error, Debug)]
360pub enum DateTimeError {
361 /// This is returned when SystemTime and Duration computations fail.
362 #[error(transparent)]
363 SystemTimeError(#[from] SystemTimeError),
364
365 /// This is returned when type conversions fail.
366 #[error(transparent)]
367 TypeConversion(#[from] std::num::TryFromIntError),
368
369 /// This is returned when checked time arithmetic failed.
370 #[error("Time arithmetic failed.")]
371 TimeArithmetic,
372}
373
374impl DateTime {
375 /// Constructs a new DateTime object denoting the current time. This may fail during
376 /// conversion to unix epoch time and during conversion to the internal i64 representation.
377 pub fn now() -> Result<Self, DateTimeError> {
378 Ok(Self(SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_millis().try_into()?))
379 }
380
381 /// Constructs a new DateTime object from milliseconds.
382 pub fn from_millis_epoch(millis: i64) -> Self {
383 Self(millis)
384 }
385
386 /// Returns unix epoch time in milliseconds.
387 pub fn to_millis_epoch(&self) -> i64 {
388 self.0
389 }
390
391 /// Returns unix epoch time in seconds.
392 pub fn to_secs_epoch(&self) -> i64 {
393 self.0 / 1000
394 }
395}
396
397impl ToSql for DateTime {
398 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
399 Ok(ToSqlOutput::Owned(Value::Integer(self.0)))
400 }
401}
402
403impl FromSql for DateTime {
404 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
405 Ok(Self(i64::column_result(value)?))
406 }
407}
408
409impl TryInto<SystemTime> for DateTime {
410 type Error = DateTimeError;
411
412 fn try_into(self) -> Result<SystemTime, Self::Error> {
413 // We want to construct a SystemTime representation equivalent to self, denoting
414 // a point in time THEN, but we cannot set the time directly. We can only construct
415 // a SystemTime denoting NOW, and we can get the duration between EPOCH and NOW,
416 // and between EPOCH and THEN. With this common reference we can construct the
417 // duration between NOW and THEN which we can add to our SystemTime representation
418 // of NOW to get a SystemTime representation of THEN.
419 // Durations can only be positive, thus the if statement below.
420 let now = SystemTime::now();
421 let now_epoch = now.duration_since(SystemTime::UNIX_EPOCH)?;
422 let then_epoch = Duration::from_millis(self.0.try_into()?);
423 Ok(if now_epoch > then_epoch {
424 // then = now - (now_epoch - then_epoch)
425 now_epoch
426 .checked_sub(then_epoch)
427 .and_then(|d| now.checked_sub(d))
428 .ok_or(DateTimeError::TimeArithmetic)?
429 } else {
430 // then = now + (then_epoch - now_epoch)
431 then_epoch
432 .checked_sub(now_epoch)
433 .and_then(|d| now.checked_add(d))
434 .ok_or(DateTimeError::TimeArithmetic)?
435 })
436 }
437}
438
439impl TryFrom<SystemTime> for DateTime {
440 type Error = DateTimeError;
441
442 fn try_from(t: SystemTime) -> Result<Self, Self::Error> {
443 Ok(Self(t.duration_since(SystemTime::UNIX_EPOCH)?.as_millis().try_into()?))
444 }
445}
446
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800447#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone)]
448enum KeyLifeCycle {
449 /// Existing keys have a key ID but are not fully populated yet.
450 /// This is a transient state. If Keystore finds any such keys when it starts up, it must move
451 /// them to Unreferenced for garbage collection.
452 Existing,
453 /// A live key is fully populated and usable by clients.
454 Live,
455 /// An unreferenced key is scheduled for garbage collection.
456 Unreferenced,
457}
458
459impl ToSql for KeyLifeCycle {
460 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
461 match self {
462 Self::Existing => Ok(ToSqlOutput::Owned(Value::Integer(0))),
463 Self::Live => Ok(ToSqlOutput::Owned(Value::Integer(1))),
464 Self::Unreferenced => Ok(ToSqlOutput::Owned(Value::Integer(2))),
465 }
466 }
467}
468
469impl FromSql for KeyLifeCycle {
470 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
471 match i64::column_result(value)? {
472 0 => Ok(KeyLifeCycle::Existing),
473 1 => Ok(KeyLifeCycle::Live),
474 2 => Ok(KeyLifeCycle::Unreferenced),
475 v => Err(FromSqlError::OutOfRange(v)),
476 }
477 }
478}
479
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700480/// Keys have a KeyMint blob component and optional public certificate and
481/// certificate chain components.
482/// KeyEntryLoadBits is a bitmap that indicates to `KeystoreDB::load_key_entry`
483/// which components shall be loaded from the database if present.
Janis Danisevskis66784c42021-01-27 08:40:25 -0800484#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700485pub struct KeyEntryLoadBits(u32);
486
487impl KeyEntryLoadBits {
488 /// Indicate to `KeystoreDB::load_key_entry` that no component shall be loaded.
489 pub const NONE: KeyEntryLoadBits = Self(0);
490 /// Indicate to `KeystoreDB::load_key_entry` that the KeyMint component shall be loaded.
491 pub const KM: KeyEntryLoadBits = Self(1);
492 /// Indicate to `KeystoreDB::load_key_entry` that the Public components shall be loaded.
493 pub const PUBLIC: KeyEntryLoadBits = Self(2);
494 /// Indicate to `KeystoreDB::load_key_entry` that both components shall be loaded.
495 pub const BOTH: KeyEntryLoadBits = Self(3);
496
497 /// Returns true if this object indicates that the public components shall be loaded.
498 pub const fn load_public(&self) -> bool {
499 self.0 & Self::PUBLIC.0 != 0
500 }
501
502 /// Returns true if the object indicates that the KeyMint component shall be loaded.
503 pub const fn load_km(&self) -> bool {
504 self.0 & Self::KM.0 != 0
505 }
506}
507
Janis Danisevskisaec14592020-11-12 09:41:49 -0800508lazy_static! {
509 static ref KEY_ID_LOCK: KeyIdLockDb = KeyIdLockDb::new();
510}
511
512struct KeyIdLockDb {
513 locked_keys: Mutex<HashSet<i64>>,
514 cond_var: Condvar,
515}
516
517/// A locked key. While a guard exists for a given key id, the same key cannot be loaded
518/// from the database a second time. Most functions manipulating the key blob database
519/// require a KeyIdGuard.
520#[derive(Debug)]
521pub struct KeyIdGuard(i64);
522
523impl KeyIdLockDb {
524 fn new() -> Self {
525 Self { locked_keys: Mutex::new(HashSet::new()), cond_var: Condvar::new() }
526 }
527
528 /// This function blocks until an exclusive lock for the given key entry id can
529 /// be acquired. It returns a guard object, that represents the lifecycle of the
530 /// acquired lock.
531 pub fn get(&self, key_id: i64) -> KeyIdGuard {
532 let mut locked_keys = self.locked_keys.lock().unwrap();
533 while locked_keys.contains(&key_id) {
534 locked_keys = self.cond_var.wait(locked_keys).unwrap();
535 }
536 locked_keys.insert(key_id);
537 KeyIdGuard(key_id)
538 }
539
540 /// This function attempts to acquire an exclusive lock on a given key id. If the
541 /// given key id is already taken the function returns None immediately. If a lock
542 /// can be acquired this function returns a guard object, that represents the
543 /// lifecycle of the acquired lock.
544 pub fn try_get(&self, key_id: i64) -> Option<KeyIdGuard> {
545 let mut locked_keys = self.locked_keys.lock().unwrap();
546 if locked_keys.insert(key_id) {
547 Some(KeyIdGuard(key_id))
548 } else {
549 None
550 }
551 }
552}
553
554impl KeyIdGuard {
555 /// Get the numeric key id of the locked key.
556 pub fn id(&self) -> i64 {
557 self.0
558 }
559}
560
561impl Drop for KeyIdGuard {
562 fn drop(&mut self) {
563 let mut locked_keys = KEY_ID_LOCK.locked_keys.lock().unwrap();
564 locked_keys.remove(&self.0);
Janis Danisevskis7fd53582020-11-23 13:40:34 -0800565 drop(locked_keys);
Janis Danisevskisaec14592020-11-12 09:41:49 -0800566 KEY_ID_LOCK.cond_var.notify_all();
567 }
568}
569
Max Bires8e93d2b2021-01-14 13:17:59 -0800570/// This type represents a certificate and certificate chain entry for a key.
Max Bires2b2e6562020-09-22 11:22:36 -0700571#[derive(Debug, Default)]
Max Bires8e93d2b2021-01-14 13:17:59 -0800572pub struct CertificateInfo {
573 cert: Option<Vec<u8>>,
574 cert_chain: Option<Vec<u8>>,
575}
576
577impl CertificateInfo {
578 /// Constructs a new CertificateInfo object from `cert` and `cert_chain`
579 pub fn new(cert: Option<Vec<u8>>, cert_chain: Option<Vec<u8>>) -> Self {
580 Self { cert, cert_chain }
581 }
582
583 /// Take the cert
584 pub fn take_cert(&mut self) -> Option<Vec<u8>> {
585 self.cert.take()
586 }
587
588 /// Take the cert chain
589 pub fn take_cert_chain(&mut self) -> Option<Vec<u8>> {
590 self.cert_chain.take()
591 }
592}
593
Max Bires2b2e6562020-09-22 11:22:36 -0700594/// This type represents a certificate chain with a private key corresponding to the leaf
595/// 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 -0700596pub struct CertificateChain {
Max Bires97f96812021-02-23 23:44:57 -0800597 /// A KM key blob
598 pub private_key: ZVec,
599 /// A batch cert for private_key
600 pub batch_cert: Vec<u8>,
601 /// A full certificate chain from root signing authority to private_key, including batch_cert
602 /// for convenience.
603 pub cert_chain: Vec<u8>,
Max Bires2b2e6562020-09-22 11:22:36 -0700604}
605
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700606/// This type represents a Keystore 2.0 key entry.
607/// An entry has a unique `id` by which it can be found in the database.
608/// It has a security level field, key parameters, and three optional fields
609/// for the KeyMint blob, public certificate and a public certificate chain.
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800610#[derive(Debug, Default, Eq, PartialEq)]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700611pub struct KeyEntry {
612 id: i64,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800613 key_blob_info: Option<(Vec<u8>, BlobMetaData)>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700614 cert: Option<Vec<u8>>,
615 cert_chain: Option<Vec<u8>>,
Max Bires8e93d2b2021-01-14 13:17:59 -0800616 km_uuid: Uuid,
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700617 parameters: Vec<KeyParameter>,
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800618 metadata: KeyMetaData,
Janis Danisevskis377d1002021-01-27 19:07:48 -0800619 pure_cert: bool,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700620}
621
622impl KeyEntry {
623 /// Returns the unique id of the Key entry.
624 pub fn id(&self) -> i64 {
625 self.id
626 }
627 /// Exposes the optional KeyMint blob.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800628 pub fn key_blob_info(&self) -> &Option<(Vec<u8>, BlobMetaData)> {
629 &self.key_blob_info
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700630 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800631 /// Extracts the Optional KeyMint blob including its metadata.
632 pub fn take_key_blob_info(&mut self) -> Option<(Vec<u8>, BlobMetaData)> {
633 self.key_blob_info.take()
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700634 }
635 /// Exposes the optional public certificate.
636 pub fn cert(&self) -> &Option<Vec<u8>> {
637 &self.cert
638 }
639 /// Extracts the optional public certificate.
640 pub fn take_cert(&mut self) -> Option<Vec<u8>> {
641 self.cert.take()
642 }
643 /// Exposes the optional public certificate chain.
644 pub fn cert_chain(&self) -> &Option<Vec<u8>> {
645 &self.cert_chain
646 }
647 /// Extracts the optional public certificate_chain.
648 pub fn take_cert_chain(&mut self) -> Option<Vec<u8>> {
649 self.cert_chain.take()
650 }
Max Bires8e93d2b2021-01-14 13:17:59 -0800651 /// Returns the uuid of the owning KeyMint instance.
652 pub fn km_uuid(&self) -> &Uuid {
653 &self.km_uuid
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700654 }
Janis Danisevskis04b02832020-10-26 09:21:40 -0700655 /// Exposes the key parameters of this key entry.
656 pub fn key_parameters(&self) -> &Vec<KeyParameter> {
657 &self.parameters
658 }
659 /// Consumes this key entry and extracts the keyparameters from it.
660 pub fn into_key_parameters(self) -> Vec<KeyParameter> {
661 self.parameters
662 }
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800663 /// Exposes the key metadata of this key entry.
664 pub fn metadata(&self) -> &KeyMetaData {
665 &self.metadata
666 }
Janis Danisevskis377d1002021-01-27 19:07:48 -0800667 /// This returns true if the entry is a pure certificate entry with no
668 /// private key component.
669 pub fn pure_cert(&self) -> bool {
670 self.pure_cert
671 }
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000672 /// Consumes this key entry and extracts the keyparameters and metadata from it.
673 pub fn into_key_parameters_and_metadata(self) -> (Vec<KeyParameter>, KeyMetaData) {
674 (self.parameters, self.metadata)
675 }
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700676}
677
678/// Indicates the sub component of a key entry for persistent storage.
Janis Danisevskis377d1002021-01-27 19:07:48 -0800679#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700680pub struct SubComponentType(u32);
681impl SubComponentType {
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800682 /// Persistent identifier for a key blob.
683 pub const KEY_BLOB: SubComponentType = Self(0);
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700684 /// Persistent identifier for a certificate blob.
685 pub const CERT: SubComponentType = Self(1);
686 /// Persistent identifier for a certificate chain blob.
687 pub const CERT_CHAIN: SubComponentType = Self(2);
688}
689
690impl ToSql for SubComponentType {
691 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
692 self.0.to_sql()
693 }
694}
695
696impl FromSql for SubComponentType {
697 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
698 Ok(Self(u32::column_result(value)?))
699 }
700}
701
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800702/// This trait is private to the database module. It is used to convey whether or not the garbage
703/// collector shall be invoked after a database access. All closures passed to
704/// `KeystoreDB::with_transaction` return a tuple (bool, T) where the bool indicates if the
705/// gc needs to be triggered. This convenience function allows to turn any anyhow::Result<T>
706/// into anyhow::Result<(bool, T)> by simply appending one of `.do_gc(bool)`, `.no_gc()`, or
707/// `.need_gc()`.
708trait DoGc<T> {
709 fn do_gc(self, need_gc: bool) -> Result<(bool, T)>;
710
711 fn no_gc(self) -> Result<(bool, T)>;
712
713 fn need_gc(self) -> Result<(bool, T)>;
714}
715
716impl<T> DoGc<T> for Result<T> {
717 fn do_gc(self, need_gc: bool) -> Result<(bool, T)> {
718 self.map(|r| (need_gc, r))
719 }
720
721 fn no_gc(self) -> Result<(bool, T)> {
722 self.do_gc(false)
723 }
724
725 fn need_gc(self) -> Result<(bool, T)> {
726 self.do_gc(true)
727 }
728}
729
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700730/// KeystoreDB wraps a connection to an SQLite database and tracks its
731/// ownership. It also implements all of Keystore 2.0's database functionality.
Joel Galenson26f4d012020-07-17 14:57:21 -0700732pub struct KeystoreDB {
Joel Galenson26f4d012020-07-17 14:57:21 -0700733 conn: Connection,
Janis Danisevskis3395f862021-05-06 10:54:17 -0700734 gc: Option<Arc<Gc>>,
Matthew Maurerd7815ca2021-05-06 21:58:45 -0700735 perboot: Arc<perboot::PerbootDB>,
Joel Galenson26f4d012020-07-17 14:57:21 -0700736}
737
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000738/// Database representation of the monotonic time retrieved from the system call clock_gettime with
Hasini Gunasinghe66a24602021-05-12 19:03:12 +0000739/// CLOCK_MONOTONIC_RAW. Stores monotonic time as i64 in milliseconds.
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000740#[derive(Debug, Copy, Clone, Default, Eq, PartialEq, Ord, PartialOrd)]
741pub struct MonotonicRawTime(i64);
742
743impl MonotonicRawTime {
744 /// Constructs a new MonotonicRawTime
745 pub fn now() -> Self {
Hasini Gunasinghe66a24602021-05-12 19:03:12 +0000746 Self(get_current_time_in_milliseconds())
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000747 }
748
Hasini Gunasinghe66a24602021-05-12 19:03:12 +0000749 /// Returns the value of MonotonicRawTime in milliseconds as i64
750 pub fn milliseconds(&self) -> i64 {
751 self.0
David Drysdale0e45a612021-02-25 17:24:36 +0000752 }
753
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000754 /// Returns the integer value of MonotonicRawTime as i64
755 pub fn seconds(&self) -> i64 {
Hasini Gunasinghe66a24602021-05-12 19:03:12 +0000756 self.0 / 1000
Hasini Gunasingheb3715fb2021-02-26 20:34:45 +0000757 }
758
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800759 /// Like i64::checked_sub.
760 pub fn checked_sub(&self, other: &Self) -> Option<Self> {
761 self.0.checked_sub(other.0).map(Self)
762 }
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000763}
764
765impl ToSql for MonotonicRawTime {
766 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
767 Ok(ToSqlOutput::Owned(Value::Integer(self.0)))
768 }
769}
770
771impl FromSql for MonotonicRawTime {
772 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
773 Ok(Self(i64::column_result(value)?))
774 }
775}
776
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000777/// This struct encapsulates the information to be stored in the database about the auth tokens
778/// received by keystore.
Matthew Maurerd7815ca2021-05-06 21:58:45 -0700779#[derive(Clone)]
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000780pub struct AuthTokenEntry {
781 auth_token: HardwareAuthToken,
Hasini Gunasinghe66a24602021-05-12 19:03:12 +0000782 // Time received in milliseconds
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000783 time_received: MonotonicRawTime,
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000784}
785
786impl AuthTokenEntry {
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000787 fn new(auth_token: HardwareAuthToken, time_received: MonotonicRawTime) -> Self {
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000788 AuthTokenEntry { auth_token, time_received }
789 }
790
791 /// Checks if this auth token satisfies the given authentication information.
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800792 pub fn satisfies(&self, user_secure_ids: &[i64], auth_type: HardwareAuthenticatorType) -> bool {
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000793 user_secure_ids.iter().any(|&sid| {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800794 (sid == self.auth_token.userId || sid == self.auth_token.authenticatorId)
795 && (((auth_type.0 as i32) & (self.auth_token.authenticatorType.0 as i32)) != 0)
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000796 })
797 }
798
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000799 /// Returns the auth token wrapped by the AuthTokenEntry
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800800 pub fn auth_token(&self) -> &HardwareAuthToken {
801 &self.auth_token
802 }
803
804 /// Returns the auth token wrapped by the AuthTokenEntry
805 pub fn take_auth_token(self) -> HardwareAuthToken {
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000806 self.auth_token
807 }
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800808
809 /// Returns the time that this auth token was received.
810 pub fn time_received(&self) -> MonotonicRawTime {
811 self.time_received
812 }
Hasini Gunasingheb3715fb2021-02-26 20:34:45 +0000813
814 /// Returns the challenge value of the auth token.
815 pub fn challenge(&self) -> i64 {
816 self.auth_token.challenge
817 }
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000818}
819
Janis Danisevskisb00ebd02021-02-02 21:52:24 -0800820/// Shared in-memory databases get destroyed as soon as the last connection to them gets closed.
821/// This object does not allow access to the database connection. But it keeps a database
822/// connection alive in order to keep the in memory per boot database alive.
823pub struct PerBootDbKeepAlive(Connection);
824
Joel Galenson26f4d012020-07-17 14:57:21 -0700825impl KeystoreDB {
Janis Danisevskiseed69842021-02-18 20:04:10 -0800826 const UNASSIGNED_KEY_ID: i64 = -1i64;
Janis Danisevskisb00ebd02021-02-02 21:52:24 -0800827
Seth Moore78c091f2021-04-09 21:38:30 +0000828 /// Name of the file that holds the cross-boot persistent database.
829 pub const PERSISTENT_DB_FILENAME: &'static str = &"persistent.sqlite";
830
Seth Moore472fcbb2021-05-12 10:07:51 -0700831 /// Set write-ahead logging mode on the persistent database found in `db_root`.
832 pub fn set_wal_mode(db_root: &Path) -> Result<()> {
833 let path = Self::make_persistent_path(&db_root)?;
834 let conn =
835 Connection::open(path).context("In KeystoreDB::set_wal_mode: Failed to open DB")?;
836 let mode: String = conn
837 .pragma_update_and_check(None, "journal_mode", &"WAL", |row| row.get(0))
838 .context("In KeystoreDB::set_wal_mode: Failed to set journal_mode")?;
839 match mode.as_str() {
840 "wal" => Ok(()),
841 _ => Err(anyhow!("Unable to set WAL mode, db is still in {} mode.", mode)),
842 }
843 }
844
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700845 /// This will create a new database connection connecting the two
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800846 /// files persistent.sqlite and perboot.sqlite in the given directory.
847 /// It also attempts to initialize all of the tables.
848 /// KeystoreDB cannot be used by multiple threads.
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700849 /// Each thread should open their own connection using `thread_local!`.
Janis Danisevskis3395f862021-05-06 10:54:17 -0700850 pub fn new(db_root: &Path, gc: Option<Arc<Gc>>) -> Result<Self> {
Janis Danisevskis850d4862021-05-05 08:41:14 -0700851 let _wp = wd::watch_millis("KeystoreDB::new", 500);
852
Seth Moore472fcbb2021-05-12 10:07:51 -0700853 let persistent_path = Self::make_persistent_path(&db_root)?;
854 let conn = Self::make_connection(&persistent_path)?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800855
Matthew Maurerd7815ca2021-05-06 21:58:45 -0700856 let mut db = Self { conn, gc, perboot: perboot::PERBOOT_DB.clone() };
Janis Danisevskis66784c42021-01-27 08:40:25 -0800857 db.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800858 Self::init_tables(tx).context("Trying to initialize tables.").no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -0800859 })?;
860 Ok(db)
Joel Galenson2aab4432020-07-22 15:27:57 -0700861 }
862
Janis Danisevskis66784c42021-01-27 08:40:25 -0800863 fn init_tables(tx: &Transaction) -> Result<()> {
864 tx.execute(
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700865 "CREATE TABLE IF NOT EXISTS persistent.keyentry (
Joel Galenson0891bc12020-07-20 10:37:03 -0700866 id INTEGER UNIQUE,
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800867 key_type INTEGER,
Joel Galenson0891bc12020-07-20 10:37:03 -0700868 domain INTEGER,
869 namespace INTEGER,
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800870 alias BLOB,
Max Bires8e93d2b2021-01-14 13:17:59 -0800871 state INTEGER,
872 km_uuid BLOB);",
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700873 NO_PARAMS,
874 )
875 .context("Failed to initialize \"keyentry\" table.")?;
876
Janis Danisevskis66784c42021-01-27 08:40:25 -0800877 tx.execute(
Janis Danisevskisa5438182021-02-02 14:22:59 -0800878 "CREATE INDEX IF NOT EXISTS persistent.keyentry_id_index
879 ON keyentry(id);",
880 NO_PARAMS,
881 )
882 .context("Failed to create index keyentry_id_index.")?;
883
884 tx.execute(
885 "CREATE INDEX IF NOT EXISTS persistent.keyentry_domain_namespace_index
886 ON keyentry(domain, namespace, alias);",
887 NO_PARAMS,
888 )
889 .context("Failed to create index keyentry_domain_namespace_index.")?;
890
891 tx.execute(
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700892 "CREATE TABLE IF NOT EXISTS persistent.blobentry (
893 id INTEGER PRIMARY KEY,
894 subcomponent_type INTEGER,
895 keyentryid INTEGER,
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800896 blob BLOB);",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700897 NO_PARAMS,
898 )
899 .context("Failed to initialize \"blobentry\" table.")?;
900
Janis Danisevskis66784c42021-01-27 08:40:25 -0800901 tx.execute(
Janis Danisevskisa5438182021-02-02 14:22:59 -0800902 "CREATE INDEX IF NOT EXISTS persistent.blobentry_keyentryid_index
903 ON blobentry(keyentryid);",
904 NO_PARAMS,
905 )
906 .context("Failed to create index blobentry_keyentryid_index.")?;
907
908 tx.execute(
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800909 "CREATE TABLE IF NOT EXISTS persistent.blobmetadata (
910 id INTEGER PRIMARY KEY,
911 blobentryid INTEGER,
912 tag INTEGER,
913 data ANY,
914 UNIQUE (blobentryid, tag));",
915 NO_PARAMS,
916 )
917 .context("Failed to initialize \"blobmetadata\" table.")?;
918
919 tx.execute(
920 "CREATE INDEX IF NOT EXISTS persistent.blobmetadata_blobentryid_index
921 ON blobmetadata(blobentryid);",
922 NO_PARAMS,
923 )
924 .context("Failed to create index blobmetadata_blobentryid_index.")?;
925
926 tx.execute(
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700927 "CREATE TABLE IF NOT EXISTS persistent.keyparameter (
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000928 keyentryid INTEGER,
929 tag INTEGER,
930 data ANY,
931 security_level INTEGER);",
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700932 NO_PARAMS,
933 )
934 .context("Failed to initialize \"keyparameter\" table.")?;
935
Janis Danisevskis66784c42021-01-27 08:40:25 -0800936 tx.execute(
Janis Danisevskisa5438182021-02-02 14:22:59 -0800937 "CREATE INDEX IF NOT EXISTS persistent.keyparameter_keyentryid_index
938 ON keyparameter(keyentryid);",
939 NO_PARAMS,
940 )
941 .context("Failed to create index keyparameter_keyentryid_index.")?;
942
943 tx.execute(
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800944 "CREATE TABLE IF NOT EXISTS persistent.keymetadata (
945 keyentryid INTEGER,
946 tag INTEGER,
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000947 data ANY,
948 UNIQUE (keyentryid, tag));",
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800949 NO_PARAMS,
950 )
951 .context("Failed to initialize \"keymetadata\" table.")?;
952
Janis Danisevskis66784c42021-01-27 08:40:25 -0800953 tx.execute(
Janis Danisevskisa5438182021-02-02 14:22:59 -0800954 "CREATE INDEX IF NOT EXISTS persistent.keymetadata_keyentryid_index
955 ON keymetadata(keyentryid);",
956 NO_PARAMS,
957 )
958 .context("Failed to create index keymetadata_keyentryid_index.")?;
959
960 tx.execute(
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800961 "CREATE TABLE IF NOT EXISTS persistent.grant (
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700962 id INTEGER UNIQUE,
963 grantee INTEGER,
964 keyentryid INTEGER,
965 access_vector INTEGER);",
966 NO_PARAMS,
967 )
968 .context("Failed to initialize \"grant\" table.")?;
969
Joel Galenson0891bc12020-07-20 10:37:03 -0700970 Ok(())
971 }
972
Seth Moore472fcbb2021-05-12 10:07:51 -0700973 fn make_persistent_path(db_root: &Path) -> Result<String> {
974 // Build the path to the sqlite file.
975 let mut persistent_path = db_root.to_path_buf();
976 persistent_path.push(Self::PERSISTENT_DB_FILENAME);
977
978 // Now convert them to strings prefixed with "file:"
979 let mut persistent_path_str = "file:".to_owned();
980 persistent_path_str.push_str(&persistent_path.to_string_lossy());
981
982 Ok(persistent_path_str)
983 }
984
Matthew Maurerd7815ca2021-05-06 21:58:45 -0700985 fn make_connection(persistent_file: &str) -> Result<Connection> {
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700986 let conn =
987 Connection::open_in_memory().context("Failed to initialize SQLite connection.")?;
988
Janis Danisevskis66784c42021-01-27 08:40:25 -0800989 loop {
990 if let Err(e) = conn
991 .execute("ATTACH DATABASE ? as persistent;", params![persistent_file])
992 .context("Failed to attach database persistent.")
993 {
994 if Self::is_locked_error(&e) {
995 std::thread::sleep(std::time::Duration::from_micros(500));
996 continue;
997 } else {
998 return Err(e);
999 }
1000 }
1001 break;
1002 }
Janis Danisevskis4df44f42020-08-26 14:40:03 -07001003
Matthew Maurer4fb19112021-05-06 15:40:44 -07001004 // Drop the cache size from default (2M) to 0.5M
1005 conn.execute("PRAGMA persistent.cache_size = -500;", params![])
1006 .context("Failed to decrease cache size for persistent db")?;
Matthew Maurer4fb19112021-05-06 15:40:44 -07001007
Janis Danisevskis4df44f42020-08-26 14:40:03 -07001008 Ok(conn)
1009 }
1010
Seth Moore78c091f2021-04-09 21:38:30 +00001011 fn do_table_size_query(
1012 &mut self,
1013 storage_type: StatsdStorageType,
1014 query: &str,
1015 params: &[&str],
1016 ) -> Result<Keystore2StorageStats> {
1017 let (total, unused) = self.with_transaction(TransactionBehavior::Deferred, |tx| {
Joel Galensonff79e362021-05-25 16:30:17 -07001018 tx.query_row(query, params_from_iter(params), |row| Ok((row.get(0)?, row.get(1)?)))
Seth Moore78c091f2021-04-09 21:38:30 +00001019 .with_context(|| {
1020 format!("get_storage_stat: Error size of storage type {}", storage_type as i32)
1021 })
1022 .no_gc()
1023 })?;
1024 Ok(Keystore2StorageStats { storage_type, size: total, unused_size: unused })
1025 }
1026
1027 fn get_total_size(&mut self) -> Result<Keystore2StorageStats> {
1028 self.do_table_size_query(
1029 StatsdStorageType::Database,
1030 "SELECT page_count * page_size, freelist_count * page_size
1031 FROM pragma_page_count('persistent'),
1032 pragma_page_size('persistent'),
1033 persistent.pragma_freelist_count();",
1034 &[],
1035 )
1036 }
1037
1038 fn get_table_size(
1039 &mut self,
1040 storage_type: StatsdStorageType,
1041 schema: &str,
1042 table: &str,
1043 ) -> Result<Keystore2StorageStats> {
1044 self.do_table_size_query(
1045 storage_type,
1046 "SELECT pgsize,unused FROM dbstat(?1)
1047 WHERE name=?2 AND aggregate=TRUE;",
1048 &[schema, table],
1049 )
1050 }
1051
1052 /// Fetches a storage statisitics atom for a given storage type. For storage
1053 /// types that map to a table, information about the table's storage is
1054 /// returned. Requests for storage types that are not DB tables return None.
1055 pub fn get_storage_stat(
1056 &mut self,
1057 storage_type: StatsdStorageType,
1058 ) -> Result<Keystore2StorageStats> {
Janis Danisevskis850d4862021-05-05 08:41:14 -07001059 let _wp = wd::watch_millis("KeystoreDB::get_storage_stat", 500);
1060
Seth Moore78c091f2021-04-09 21:38:30 +00001061 match storage_type {
1062 StatsdStorageType::Database => self.get_total_size(),
1063 StatsdStorageType::KeyEntry => {
1064 self.get_table_size(storage_type, "persistent", "keyentry")
1065 }
1066 StatsdStorageType::KeyEntryIdIndex => {
1067 self.get_table_size(storage_type, "persistent", "keyentry_id_index")
1068 }
1069 StatsdStorageType::KeyEntryDomainNamespaceIndex => {
1070 self.get_table_size(storage_type, "persistent", "keyentry_domain_namespace_index")
1071 }
1072 StatsdStorageType::BlobEntry => {
1073 self.get_table_size(storage_type, "persistent", "blobentry")
1074 }
1075 StatsdStorageType::BlobEntryKeyEntryIdIndex => {
1076 self.get_table_size(storage_type, "persistent", "blobentry_keyentryid_index")
1077 }
1078 StatsdStorageType::KeyParameter => {
1079 self.get_table_size(storage_type, "persistent", "keyparameter")
1080 }
1081 StatsdStorageType::KeyParameterKeyEntryIdIndex => {
1082 self.get_table_size(storage_type, "persistent", "keyparameter_keyentryid_index")
1083 }
1084 StatsdStorageType::KeyMetadata => {
1085 self.get_table_size(storage_type, "persistent", "keymetadata")
1086 }
1087 StatsdStorageType::KeyMetadataKeyEntryIdIndex => {
1088 self.get_table_size(storage_type, "persistent", "keymetadata_keyentryid_index")
1089 }
1090 StatsdStorageType::Grant => self.get_table_size(storage_type, "persistent", "grant"),
1091 StatsdStorageType::AuthToken => {
Matthew Maurerd7815ca2021-05-06 21:58:45 -07001092 // Since the table is actually a BTreeMap now, unused_size is not meaningfully
1093 // reportable
1094 // Size provided is only an approximation
1095 Ok(Keystore2StorageStats {
1096 storage_type,
1097 size: (self.perboot.auth_tokens_len() * std::mem::size_of::<AuthTokenEntry>())
1098 as i64,
1099 unused_size: 0,
1100 })
Seth Moore78c091f2021-04-09 21:38:30 +00001101 }
1102 StatsdStorageType::BlobMetadata => {
1103 self.get_table_size(storage_type, "persistent", "blobmetadata")
1104 }
1105 StatsdStorageType::BlobMetadataBlobEntryIdIndex => {
1106 self.get_table_size(storage_type, "persistent", "blobmetadata_blobentryid_index")
1107 }
1108 _ => Err(anyhow::Error::msg(format!(
1109 "Unsupported storage type: {}",
1110 storage_type as i32
1111 ))),
1112 }
1113 }
1114
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001115 /// This function is intended to be used by the garbage collector.
Janis Danisevskis3395f862021-05-06 10:54:17 -07001116 /// It deletes the blobs given by `blob_ids_to_delete`. It then tries to find up to `max_blobs`
1117 /// superseded key blobs that might need special handling by the garbage collector.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001118 /// If no further superseded blobs can be found it deletes all other superseded blobs that don't
1119 /// need special handling and returns None.
Janis Danisevskis3395f862021-05-06 10:54:17 -07001120 pub fn handle_next_superseded_blobs(
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001121 &mut self,
Janis Danisevskis3395f862021-05-06 10:54:17 -07001122 blob_ids_to_delete: &[i64],
1123 max_blobs: usize,
1124 ) -> Result<Vec<(i64, Vec<u8>, BlobMetaData)>> {
Janis Danisevskis850d4862021-05-05 08:41:14 -07001125 let _wp = wd::watch_millis("KeystoreDB::handle_next_superseded_blob", 500);
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001126 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis3395f862021-05-06 10:54:17 -07001127 // Delete the given blobs.
1128 for blob_id in blob_ids_to_delete {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001129 tx.execute(
1130 "DELETE FROM persistent.blobmetadata WHERE blobentryid = ?;",
Janis Danisevskis3395f862021-05-06 10:54:17 -07001131 params![blob_id],
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001132 )
1133 .context("Trying to delete blob metadata.")?;
Janis Danisevskis3395f862021-05-06 10:54:17 -07001134 tx.execute("DELETE FROM persistent.blobentry WHERE id = ?;", params![blob_id])
1135 .context("Trying to blob.")?;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001136 }
Janis Danisevskis3cba10d2021-05-06 17:02:19 -07001137
1138 Self::cleanup_unreferenced(tx).context("Trying to cleanup unreferenced.")?;
1139
Janis Danisevskis3395f862021-05-06 10:54:17 -07001140 // Find up to max_blobx more superseded key blobs, load their metadata and return it.
1141 let result: Vec<(i64, Vec<u8>)> = {
1142 let mut stmt = tx
1143 .prepare(
1144 "SELECT id, blob FROM persistent.blobentry
1145 WHERE subcomponent_type = ?
1146 AND (
1147 id NOT IN (
1148 SELECT MAX(id) FROM persistent.blobentry
1149 WHERE subcomponent_type = ?
1150 GROUP BY keyentryid, subcomponent_type
1151 )
1152 OR keyentryid NOT IN (SELECT id FROM persistent.keyentry)
1153 ) LIMIT ?;",
1154 )
1155 .context("Trying to prepare query for superseded blobs.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001156
Janis Danisevskis3395f862021-05-06 10:54:17 -07001157 let rows = stmt
1158 .query_map(
1159 params![
1160 SubComponentType::KEY_BLOB,
1161 SubComponentType::KEY_BLOB,
1162 max_blobs as i64,
1163 ],
1164 |row| Ok((row.get(0)?, row.get(1)?)),
1165 )
1166 .context("Trying to query superseded blob.")?;
1167
1168 rows.collect::<Result<Vec<(i64, Vec<u8>)>, rusqlite::Error>>()
1169 .context("Trying to extract superseded blobs.")?
1170 };
1171
1172 let result = result
1173 .into_iter()
1174 .map(|(blob_id, blob)| {
1175 Ok((blob_id, blob, BlobMetaData::load_from_db(blob_id, tx)?))
1176 })
1177 .collect::<Result<Vec<(i64, Vec<u8>, BlobMetaData)>>>()
1178 .context("Trying to load blob metadata.")?;
1179 if !result.is_empty() {
1180 return Ok(result).no_gc();
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001181 }
1182
1183 // We did not find any superseded key blob, so let's remove other superseded blob in
1184 // one transaction.
1185 tx.execute(
1186 "DELETE FROM persistent.blobentry
1187 WHERE NOT subcomponent_type = ?
1188 AND (
1189 id NOT IN (
1190 SELECT MAX(id) FROM persistent.blobentry
1191 WHERE NOT subcomponent_type = ?
1192 GROUP BY keyentryid, subcomponent_type
1193 ) OR keyentryid NOT IN (SELECT id FROM persistent.keyentry)
1194 );",
1195 params![SubComponentType::KEY_BLOB, SubComponentType::KEY_BLOB],
1196 )
1197 .context("Trying to purge superseded blobs.")?;
1198
Janis Danisevskis3395f862021-05-06 10:54:17 -07001199 Ok(vec![]).no_gc()
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001200 })
Janis Danisevskis3395f862021-05-06 10:54:17 -07001201 .context("In handle_next_superseded_blobs.")
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001202 }
1203
1204 /// This maintenance function should be called only once before the database is used for the
1205 /// first time. It restores the invariant that `KeyLifeCycle::Existing` is a transient state.
1206 /// The function transitions all key entries from Existing to Unreferenced unconditionally and
1207 /// returns the number of rows affected. If this returns a value greater than 0, it means that
1208 /// Keystore crashed at some point during key generation. Callers may want to log such
1209 /// occurrences.
1210 /// Unlike with `mark_unreferenced`, we don't need to purge grants, because only keys that made
1211 /// it to `KeyLifeCycle::Live` may have grants.
1212 pub fn cleanup_leftovers(&mut self) -> Result<usize> {
Janis Danisevskis850d4862021-05-05 08:41:14 -07001213 let _wp = wd::watch_millis("KeystoreDB::cleanup_leftovers", 500);
1214
Janis Danisevskis66784c42021-01-27 08:40:25 -08001215 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1216 tx.execute(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001217 "UPDATE persistent.keyentry SET state = ? WHERE state = ?;",
1218 params![KeyLifeCycle::Unreferenced, KeyLifeCycle::Existing],
1219 )
Janis Danisevskis66784c42021-01-27 08:40:25 -08001220 .context("Failed to execute query.")
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001221 .need_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08001222 })
1223 .context("In cleanup_leftovers.")
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001224 }
1225
Hasini Gunasinghe0e161452021-01-27 19:34:37 +00001226 /// Checks if a key exists with given key type and key descriptor properties.
1227 pub fn key_exists(
1228 &mut self,
1229 domain: Domain,
1230 nspace: i64,
1231 alias: &str,
1232 key_type: KeyType,
1233 ) -> Result<bool> {
Janis Danisevskis850d4862021-05-05 08:41:14 -07001234 let _wp = wd::watch_millis("KeystoreDB::key_exists", 500);
1235
Hasini Gunasinghe0e161452021-01-27 19:34:37 +00001236 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1237 let key_descriptor =
1238 KeyDescriptor { domain, nspace, alias: Some(alias.to_string()), blob: None };
1239 let result = Self::load_key_entry_id(&tx, &key_descriptor, key_type);
1240 match result {
1241 Ok(_) => Ok(true),
1242 Err(error) => match error.root_cause().downcast_ref::<KsError>() {
1243 Some(KsError::Rc(ResponseCode::KEY_NOT_FOUND)) => Ok(false),
1244 _ => Err(error).context("In key_exists: Failed to find if the key exists."),
1245 },
1246 }
1247 .no_gc()
1248 })
1249 .context("In key_exists.")
1250 }
1251
Hasini Gunasingheda895552021-01-27 19:34:37 +00001252 /// Stores a super key in the database.
1253 pub fn store_super_key(
1254 &mut self,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +00001255 user_id: u32,
Paul Crowley7a658392021-03-18 17:08:20 -07001256 key_type: &SuperKeyType,
1257 blob: &[u8],
1258 blob_metadata: &BlobMetaData,
Paul Crowley8d5b2532021-03-19 10:53:07 -07001259 key_metadata: &KeyMetaData,
Hasini Gunasingheda895552021-01-27 19:34:37 +00001260 ) -> Result<KeyEntry> {
Janis Danisevskis850d4862021-05-05 08:41:14 -07001261 let _wp = wd::watch_millis("KeystoreDB::store_super_key", 500);
1262
Hasini Gunasingheda895552021-01-27 19:34:37 +00001263 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1264 let key_id = Self::insert_with_retry(|id| {
1265 tx.execute(
1266 "INSERT into persistent.keyentry
1267 (id, key_type, domain, namespace, alias, state, km_uuid)
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00001268 VALUES(?, ?, ?, ?, ?, ?, ?);",
Hasini Gunasingheda895552021-01-27 19:34:37 +00001269 params![
1270 id,
1271 KeyType::Super,
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00001272 Domain::APP.0,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +00001273 user_id as i64,
Paul Crowley7a658392021-03-18 17:08:20 -07001274 key_type.alias,
Hasini Gunasingheda895552021-01-27 19:34:37 +00001275 KeyLifeCycle::Live,
1276 &KEYSTORE_UUID,
1277 ],
1278 )
1279 })
1280 .context("Failed to insert into keyentry table.")?;
1281
Paul Crowley8d5b2532021-03-19 10:53:07 -07001282 key_metadata.store_in_db(key_id, tx).context("KeyMetaData::store_in_db failed")?;
1283
Hasini Gunasingheda895552021-01-27 19:34:37 +00001284 Self::set_blob_internal(
1285 &tx,
1286 key_id,
1287 SubComponentType::KEY_BLOB,
1288 Some(blob),
1289 Some(blob_metadata),
1290 )
1291 .context("Failed to store key blob.")?;
1292
1293 Self::load_key_components(tx, KeyEntryLoadBits::KM, key_id)
1294 .context("Trying to load key components.")
1295 .no_gc()
1296 })
1297 .context("In store_super_key.")
1298 }
1299
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +00001300 /// Loads super key of a given user, if exists
Paul Crowley7a658392021-03-18 17:08:20 -07001301 pub fn load_super_key(
1302 &mut self,
1303 key_type: &SuperKeyType,
1304 user_id: u32,
1305 ) -> Result<Option<(KeyIdGuard, KeyEntry)>> {
Janis Danisevskis850d4862021-05-05 08:41:14 -07001306 let _wp = wd::watch_millis("KeystoreDB::load_super_key", 500);
1307
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +00001308 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1309 let key_descriptor = KeyDescriptor {
1310 domain: Domain::APP,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +00001311 nspace: user_id as i64,
Paul Crowley7a658392021-03-18 17:08:20 -07001312 alias: Some(key_type.alias.into()),
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +00001313 blob: None,
1314 };
1315 let id = Self::load_key_entry_id(&tx, &key_descriptor, KeyType::Super);
1316 match id {
1317 Ok(id) => {
1318 let key_entry = Self::load_key_components(&tx, KeyEntryLoadBits::KM, id)
1319 .context("In load_super_key. Failed to load key entry.")?;
1320 Ok(Some((KEY_ID_LOCK.get(id), key_entry)))
1321 }
1322 Err(error) => match error.root_cause().downcast_ref::<KsError>() {
1323 Some(KsError::Rc(ResponseCode::KEY_NOT_FOUND)) => Ok(None),
1324 _ => Err(error).context("In load_super_key."),
1325 },
1326 }
1327 .no_gc()
1328 })
1329 .context("In load_super_key.")
1330 }
1331
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001332 /// Atomically loads a key entry and associated metadata or creates it using the
1333 /// callback create_new_key callback. The callback is called during a database
1334 /// transaction. This means that implementers should be mindful about using
1335 /// blocking operations such as IPC or grabbing mutexes.
1336 pub fn get_or_create_key_with<F>(
1337 &mut self,
1338 domain: Domain,
1339 namespace: i64,
1340 alias: &str,
Max Bires8e93d2b2021-01-14 13:17:59 -08001341 km_uuid: Uuid,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001342 create_new_key: F,
1343 ) -> Result<(KeyIdGuard, KeyEntry)>
1344 where
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001345 F: Fn() -> Result<(Vec<u8>, BlobMetaData)>,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001346 {
Janis Danisevskis850d4862021-05-05 08:41:14 -07001347 let _wp = wd::watch_millis("KeystoreDB::get_or_create_key_with", 500);
1348
Janis Danisevskis66784c42021-01-27 08:40:25 -08001349 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1350 let id = {
1351 let mut stmt = tx
1352 .prepare(
1353 "SELECT id FROM persistent.keyentry
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001354 WHERE
1355 key_type = ?
1356 AND domain = ?
1357 AND namespace = ?
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001358 AND alias = ?
1359 AND state = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08001360 )
1361 .context("In get_or_create_key_with: Failed to select from keyentry table.")?;
1362 let mut rows = stmt
1363 .query(params![KeyType::Super, domain.0, namespace, alias, KeyLifeCycle::Live])
1364 .context("In get_or_create_key_with: Failed to query from keyentry table.")?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001365
Janis Danisevskis66784c42021-01-27 08:40:25 -08001366 db_utils::with_rows_extract_one(&mut rows, |row| {
1367 Ok(match row {
1368 Some(r) => r.get(0).context("Failed to unpack id.")?,
1369 None => None,
1370 })
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001371 })
Janis Danisevskis66784c42021-01-27 08:40:25 -08001372 .context("In get_or_create_key_with.")?
1373 };
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001374
Janis Danisevskis66784c42021-01-27 08:40:25 -08001375 let (id, entry) = match id {
1376 Some(id) => (
1377 id,
1378 Self::load_key_components(&tx, KeyEntryLoadBits::KM, id)
1379 .context("In get_or_create_key_with.")?,
1380 ),
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001381
Janis Danisevskis66784c42021-01-27 08:40:25 -08001382 None => {
1383 let id = Self::insert_with_retry(|id| {
1384 tx.execute(
1385 "INSERT into persistent.keyentry
Max Bires8e93d2b2021-01-14 13:17:59 -08001386 (id, key_type, domain, namespace, alias, state, km_uuid)
1387 VALUES(?, ?, ?, ?, ?, ?, ?);",
Janis Danisevskis66784c42021-01-27 08:40:25 -08001388 params![
1389 id,
1390 KeyType::Super,
1391 domain.0,
1392 namespace,
1393 alias,
1394 KeyLifeCycle::Live,
1395 km_uuid,
1396 ],
1397 )
1398 })
1399 .context("In get_or_create_key_with.")?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001400
Janis Danisevskis66784c42021-01-27 08:40:25 -08001401 let (blob, metadata) =
1402 create_new_key().context("In get_or_create_key_with.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001403 Self::set_blob_internal(
1404 &tx,
1405 id,
1406 SubComponentType::KEY_BLOB,
1407 Some(&blob),
1408 Some(&metadata),
1409 )
Paul Crowley7a658392021-03-18 17:08:20 -07001410 .context("In get_or_create_key_with.")?;
Janis Danisevskis66784c42021-01-27 08:40:25 -08001411 (
Janis Danisevskis377d1002021-01-27 19:07:48 -08001412 id,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001413 KeyEntry {
1414 id,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001415 key_blob_info: Some((blob, metadata)),
Janis Danisevskis66784c42021-01-27 08:40:25 -08001416 pure_cert: false,
1417 ..Default::default()
1418 },
1419 )
1420 }
1421 };
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001422 Ok((KEY_ID_LOCK.get(id), entry)).no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08001423 })
1424 .context("In get_or_create_key_with.")
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001425 }
1426
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001427 /// Creates a transaction with the given behavior and executes f with the new transaction.
Janis Danisevskis66784c42021-01-27 08:40:25 -08001428 /// The transaction is committed only if f returns Ok and retried if DatabaseBusy
1429 /// or DatabaseLocked is encountered.
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001430 fn with_transaction<T, F>(&mut self, behavior: TransactionBehavior, f: F) -> Result<T>
1431 where
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001432 F: Fn(&Transaction) -> Result<(bool, T)>,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001433 {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001434 loop {
1435 match self
1436 .conn
1437 .transaction_with_behavior(behavior)
1438 .context("In with_transaction.")
1439 .and_then(|tx| f(&tx).map(|result| (result, tx)))
1440 .and_then(|(result, tx)| {
1441 tx.commit().context("In with_transaction: Failed to commit transaction.")?;
1442 Ok(result)
1443 }) {
1444 Ok(result) => break Ok(result),
1445 Err(e) => {
1446 if Self::is_locked_error(&e) {
1447 std::thread::sleep(std::time::Duration::from_micros(500));
1448 continue;
1449 } else {
1450 return Err(e).context("In with_transaction.");
1451 }
1452 }
1453 }
1454 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001455 .map(|(need_gc, result)| {
1456 if need_gc {
1457 if let Some(ref gc) = self.gc {
1458 gc.notify_gc();
1459 }
1460 }
1461 result
1462 })
Janis Danisevskis66784c42021-01-27 08:40:25 -08001463 }
1464
1465 fn is_locked_error(e: &anyhow::Error) -> bool {
Paul Crowleyf61fee72021-03-17 14:38:44 -07001466 matches!(
1467 e.root_cause().downcast_ref::<rusqlite::ffi::Error>(),
1468 Some(rusqlite::ffi::Error { code: rusqlite::ErrorCode::DatabaseBusy, .. })
1469 | Some(rusqlite::ffi::Error { code: rusqlite::ErrorCode::DatabaseLocked, .. })
1470 )
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001471 }
1472
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001473 /// Creates a new key entry and allocates a new randomized id for the new key.
1474 /// The key id gets associated with a domain and namespace but not with an alias.
1475 /// To complete key generation `rebind_alias` should be called after all of the
1476 /// key artifacts, i.e., blobs and parameters have been associated with the new
1477 /// key id. Finalizing with `rebind_alias` makes the creation of a new key entry
1478 /// atomic even if key generation is not.
Max Bires8e93d2b2021-01-14 13:17:59 -08001479 pub fn create_key_entry(
1480 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001481 domain: &Domain,
1482 namespace: &i64,
Janis Danisevskis0cabd712021-05-25 11:07:10 -07001483 key_type: KeyType,
Max Bires8e93d2b2021-01-14 13:17:59 -08001484 km_uuid: &Uuid,
1485 ) -> Result<KeyIdGuard> {
Janis Danisevskis850d4862021-05-05 08:41:14 -07001486 let _wp = wd::watch_millis("KeystoreDB::create_key_entry", 500);
1487
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001488 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis0cabd712021-05-25 11:07:10 -07001489 Self::create_key_entry_internal(tx, domain, namespace, key_type, km_uuid).no_gc()
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001490 })
1491 .context("In create_key_entry.")
1492 }
1493
1494 fn create_key_entry_internal(
1495 tx: &Transaction,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001496 domain: &Domain,
1497 namespace: &i64,
Janis Danisevskis0cabd712021-05-25 11:07:10 -07001498 key_type: KeyType,
Max Bires8e93d2b2021-01-14 13:17:59 -08001499 km_uuid: &Uuid,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001500 ) -> Result<KeyIdGuard> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001501 match *domain {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001502 Domain::APP | Domain::SELINUX => {}
Joel Galenson0891bc12020-07-20 10:37:03 -07001503 _ => {
1504 return Err(KsError::sys())
1505 .context(format!("Domain {:?} must be either App or SELinux.", domain));
1506 }
1507 }
Janis Danisevskisaec14592020-11-12 09:41:49 -08001508 Ok(KEY_ID_LOCK.get(
1509 Self::insert_with_retry(|id| {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001510 tx.execute(
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001511 "INSERT into persistent.keyentry
Max Bires8e93d2b2021-01-14 13:17:59 -08001512 (id, key_type, domain, namespace, alias, state, km_uuid)
1513 VALUES(?, ?, ?, ?, NULL, ?, ?);",
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001514 params![
1515 id,
Janis Danisevskis0cabd712021-05-25 11:07:10 -07001516 key_type,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001517 domain.0 as u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001518 *namespace,
Max Bires8e93d2b2021-01-14 13:17:59 -08001519 KeyLifeCycle::Existing,
1520 km_uuid,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001521 ],
Janis Danisevskisaec14592020-11-12 09:41:49 -08001522 )
1523 })
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001524 .context("In create_key_entry_internal")?,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001525 ))
Joel Galenson26f4d012020-07-17 14:57:21 -07001526 }
Joel Galenson33c04ad2020-08-03 11:04:38 -07001527
Max Bires2b2e6562020-09-22 11:22:36 -07001528 /// Creates a new attestation key entry and allocates a new randomized id for the new key.
1529 /// The key id gets associated with a domain and namespace later but not with an alias. The
1530 /// alias will be used to denote if a key has been signed as each key can only be bound to one
1531 /// domain and namespace pairing so there is no need to use them as a value for indexing into
1532 /// a key.
1533 pub fn create_attestation_key_entry(
1534 &mut self,
1535 maced_public_key: &[u8],
1536 raw_public_key: &[u8],
1537 private_key: &[u8],
1538 km_uuid: &Uuid,
1539 ) -> Result<()> {
Janis Danisevskis850d4862021-05-05 08:41:14 -07001540 let _wp = wd::watch_millis("KeystoreDB::create_attestation_key_entry", 500);
1541
Max Bires2b2e6562020-09-22 11:22:36 -07001542 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1543 let key_id = KEY_ID_LOCK.get(
1544 Self::insert_with_retry(|id| {
1545 tx.execute(
1546 "INSERT into persistent.keyentry
1547 (id, key_type, domain, namespace, alias, state, km_uuid)
1548 VALUES(?, ?, NULL, NULL, NULL, ?, ?);",
1549 params![id, KeyType::Attestation, KeyLifeCycle::Live, km_uuid],
1550 )
1551 })
1552 .context("In create_key_entry")?,
1553 );
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001554 Self::set_blob_internal(
1555 &tx,
1556 key_id.0,
1557 SubComponentType::KEY_BLOB,
1558 Some(private_key),
1559 None,
1560 )?;
Max Bires2b2e6562020-09-22 11:22:36 -07001561 let mut metadata = KeyMetaData::new();
1562 metadata.add(KeyMetaEntry::AttestationMacedPublicKey(maced_public_key.to_vec()));
1563 metadata.add(KeyMetaEntry::AttestationRawPubKey(raw_public_key.to_vec()));
1564 metadata.store_in_db(key_id.0, &tx)?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001565 Ok(()).no_gc()
Max Bires2b2e6562020-09-22 11:22:36 -07001566 })
1567 .context("In create_attestation_key_entry")
1568 }
1569
Janis Danisevskis377d1002021-01-27 19:07:48 -08001570 /// Set a new blob and associates it with the given key id. Each blob
1571 /// has a sub component type.
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001572 /// Each key can have one of each sub component type associated. If more
1573 /// are added only the most recent can be retrieved, and superseded blobs
Janis Danisevskis377d1002021-01-27 19:07:48 -08001574 /// will get garbage collected.
1575 /// Components SubComponentType::CERT and SubComponentType::CERT_CHAIN can be
1576 /// removed by setting blob to None.
1577 pub fn set_blob(
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001578 &mut self,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001579 key_id: &KeyIdGuard,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001580 sc_type: SubComponentType,
Janis Danisevskis377d1002021-01-27 19:07:48 -08001581 blob: Option<&[u8]>,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001582 blob_metadata: Option<&BlobMetaData>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001583 ) -> Result<()> {
Janis Danisevskis850d4862021-05-05 08:41:14 -07001584 let _wp = wd::watch_millis("KeystoreDB::set_blob", 500);
1585
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001586 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001587 Self::set_blob_internal(&tx, key_id.0, sc_type, blob, blob_metadata).need_gc()
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001588 })
Janis Danisevskis377d1002021-01-27 19:07:48 -08001589 .context("In set_blob.")
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001590 }
1591
Janis Danisevskiseed69842021-02-18 20:04:10 -08001592 /// Why would we insert a deleted blob? This weird function is for the purpose of legacy
1593 /// key migration in the case where we bulk delete all the keys of an app or even a user.
1594 /// We use this to insert key blobs into the database which can then be garbage collected
1595 /// lazily by the key garbage collector.
1596 pub fn set_deleted_blob(&mut self, blob: &[u8], blob_metadata: &BlobMetaData) -> Result<()> {
Janis Danisevskis850d4862021-05-05 08:41:14 -07001597 let _wp = wd::watch_millis("KeystoreDB::set_deleted_blob", 500);
1598
Janis Danisevskiseed69842021-02-18 20:04:10 -08001599 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1600 Self::set_blob_internal(
1601 &tx,
1602 Self::UNASSIGNED_KEY_ID,
1603 SubComponentType::KEY_BLOB,
1604 Some(blob),
1605 Some(blob_metadata),
1606 )
1607 .need_gc()
1608 })
1609 .context("In set_deleted_blob.")
1610 }
1611
Janis Danisevskis377d1002021-01-27 19:07:48 -08001612 fn set_blob_internal(
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001613 tx: &Transaction,
1614 key_id: i64,
1615 sc_type: SubComponentType,
Janis Danisevskis377d1002021-01-27 19:07:48 -08001616 blob: Option<&[u8]>,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001617 blob_metadata: Option<&BlobMetaData>,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001618 ) -> Result<()> {
Janis Danisevskis377d1002021-01-27 19:07:48 -08001619 match (blob, sc_type) {
1620 (Some(blob), _) => {
1621 tx.execute(
1622 "INSERT INTO persistent.blobentry
1623 (subcomponent_type, keyentryid, blob) VALUES (?, ?, ?);",
1624 params![sc_type, key_id, blob],
1625 )
1626 .context("In set_blob_internal: Failed to insert blob.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001627 if let Some(blob_metadata) = blob_metadata {
1628 let blob_id = tx
1629 .query_row("SELECT MAX(id) FROM persistent.blobentry;", NO_PARAMS, |row| {
1630 row.get(0)
1631 })
1632 .context("In set_blob_internal: Failed to get new blob id.")?;
1633 blob_metadata
1634 .store_in_db(blob_id, tx)
1635 .context("In set_blob_internal: Trying to store blob metadata.")?;
1636 }
Janis Danisevskis377d1002021-01-27 19:07:48 -08001637 }
1638 (None, SubComponentType::CERT) | (None, SubComponentType::CERT_CHAIN) => {
1639 tx.execute(
1640 "DELETE FROM persistent.blobentry
1641 WHERE subcomponent_type = ? AND keyentryid = ?;",
1642 params![sc_type, key_id],
1643 )
1644 .context("In set_blob_internal: Failed to delete blob.")?;
1645 }
1646 (None, _) => {
1647 return Err(KsError::sys())
1648 .context("In set_blob_internal: Other blobs cannot be deleted in this way.");
1649 }
1650 }
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001651 Ok(())
1652 }
1653
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001654 /// Inserts a collection of key parameters into the `persistent.keyparameter` table
1655 /// and associates them with the given `key_id`.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001656 #[cfg(test)]
1657 fn insert_keyparameter(&mut self, key_id: &KeyIdGuard, params: &[KeyParameter]) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001658 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001659 Self::insert_keyparameter_internal(tx, key_id, params).no_gc()
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001660 })
1661 .context("In insert_keyparameter.")
1662 }
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001663
Janis Danisevskis66784c42021-01-27 08:40:25 -08001664 fn insert_keyparameter_internal(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001665 tx: &Transaction,
1666 key_id: &KeyIdGuard,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001667 params: &[KeyParameter],
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001668 ) -> Result<()> {
1669 let mut stmt = tx
1670 .prepare(
1671 "INSERT into persistent.keyparameter (keyentryid, tag, data, security_level)
1672 VALUES (?, ?, ?, ?);",
1673 )
1674 .context("In insert_keyparameter_internal: Failed to prepare statement.")?;
1675
Janis Danisevskis66784c42021-01-27 08:40:25 -08001676 for p in params.iter() {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001677 stmt.insert(params![
1678 key_id.0,
1679 p.get_tag().0,
1680 p.key_parameter_value(),
1681 p.security_level().0
1682 ])
1683 .with_context(|| {
1684 format!("In insert_keyparameter_internal: Failed to insert {:?}", p)
1685 })?;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001686 }
1687 Ok(())
1688 }
1689
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001690 /// Insert a set of key entry specific metadata into the database.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001691 #[cfg(test)]
1692 fn insert_key_metadata(&mut self, key_id: &KeyIdGuard, metadata: &KeyMetaData) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001693 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001694 metadata.store_in_db(key_id.0, &tx).no_gc()
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001695 })
1696 .context("In insert_key_metadata.")
1697 }
1698
Max Bires2b2e6562020-09-22 11:22:36 -07001699 /// Stores a signed certificate chain signed by a remote provisioning server, keyed
1700 /// on the public key.
1701 pub fn store_signed_attestation_certificate_chain(
1702 &mut self,
1703 raw_public_key: &[u8],
Max Biresb2e1d032021-02-08 21:35:05 -08001704 batch_cert: &[u8],
Max Bires2b2e6562020-09-22 11:22:36 -07001705 cert_chain: &[u8],
1706 expiration_date: i64,
1707 km_uuid: &Uuid,
1708 ) -> Result<()> {
Janis Danisevskis850d4862021-05-05 08:41:14 -07001709 let _wp = wd::watch_millis("KeystoreDB::store_signed_attestation_certificate_chain", 500);
1710
Max Bires2b2e6562020-09-22 11:22:36 -07001711 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1712 let mut stmt = tx
1713 .prepare(
1714 "SELECT keyentryid
1715 FROM persistent.keymetadata
1716 WHERE tag = ? AND data = ? AND keyentryid IN
1717 (SELECT id
1718 FROM persistent.keyentry
1719 WHERE
1720 alias IS NULL AND
1721 domain IS NULL AND
1722 namespace IS NULL AND
1723 key_type = ? AND
1724 km_uuid = ?);",
1725 )
1726 .context("Failed to store attestation certificate chain.")?;
1727 let mut rows = stmt
1728 .query(params![
1729 KeyMetaData::AttestationRawPubKey,
1730 raw_public_key,
1731 KeyType::Attestation,
1732 km_uuid
1733 ])
1734 .context("Failed to fetch keyid")?;
1735 let key_id = db_utils::with_rows_extract_one(&mut rows, |row| {
1736 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?
1737 .get(0)
1738 .context("Failed to unpack id.")
1739 })
1740 .context("Failed to get key_id.")?;
1741 let num_updated = tx
1742 .execute(
1743 "UPDATE persistent.keyentry
1744 SET alias = ?
1745 WHERE id = ?;",
1746 params!["signed", key_id],
1747 )
1748 .context("Failed to update alias.")?;
1749 if num_updated != 1 {
1750 return Err(KsError::sys()).context("Alias not updated for the key.");
1751 }
1752 let mut metadata = KeyMetaData::new();
1753 metadata.add(KeyMetaEntry::AttestationExpirationDate(DateTime::from_millis_epoch(
1754 expiration_date,
1755 )));
1756 metadata.store_in_db(key_id, &tx).context("Failed to insert key metadata.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001757 Self::set_blob_internal(
1758 &tx,
1759 key_id,
1760 SubComponentType::CERT_CHAIN,
1761 Some(cert_chain),
1762 None,
1763 )
1764 .context("Failed to insert cert chain")?;
Max Biresb2e1d032021-02-08 21:35:05 -08001765 Self::set_blob_internal(&tx, key_id, SubComponentType::CERT, Some(batch_cert), None)
1766 .context("Failed to insert cert")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001767 Ok(()).no_gc()
Max Bires2b2e6562020-09-22 11:22:36 -07001768 })
1769 .context("In store_signed_attestation_certificate_chain: ")
1770 }
1771
1772 /// Assigns the next unassigned attestation key to a domain/namespace combo that does not
1773 /// currently have a key assigned to it.
1774 pub fn assign_attestation_key(
1775 &mut self,
1776 domain: Domain,
1777 namespace: i64,
1778 km_uuid: &Uuid,
1779 ) -> Result<()> {
Janis Danisevskis850d4862021-05-05 08:41:14 -07001780 let _wp = wd::watch_millis("KeystoreDB::assign_attestation_key", 500);
1781
Max Bires2b2e6562020-09-22 11:22:36 -07001782 match domain {
1783 Domain::APP | Domain::SELINUX => {}
1784 _ => {
1785 return Err(KsError::sys()).context(format!(
1786 concat!(
1787 "In assign_attestation_key: Domain {:?} ",
1788 "must be either App or SELinux.",
1789 ),
1790 domain
1791 ));
1792 }
1793 }
1794 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1795 let result = tx
1796 .execute(
1797 "UPDATE persistent.keyentry
1798 SET domain=?1, namespace=?2
1799 WHERE
1800 id =
1801 (SELECT MIN(id)
1802 FROM persistent.keyentry
1803 WHERE ALIAS IS NOT NULL
1804 AND domain IS NULL
1805 AND key_type IS ?3
1806 AND state IS ?4
1807 AND km_uuid IS ?5)
1808 AND
1809 (SELECT COUNT(*)
1810 FROM persistent.keyentry
1811 WHERE domain=?1
1812 AND namespace=?2
1813 AND key_type IS ?3
1814 AND state IS ?4
1815 AND km_uuid IS ?5) = 0;",
1816 params![
1817 domain.0 as u32,
1818 namespace,
1819 KeyType::Attestation,
1820 KeyLifeCycle::Live,
1821 km_uuid,
1822 ],
1823 )
1824 .context("Failed to assign attestation key")?;
Max Bires01f8af22021-03-02 23:24:50 -08001825 if result == 0 {
1826 return Err(KsError::Rc(ResponseCode::OUT_OF_KEYS)).context("Out of keys.");
1827 } else if result > 1 {
1828 return Err(KsError::sys())
1829 .context(format!("Expected to update 1 entry, instead updated {}", result));
Max Bires2b2e6562020-09-22 11:22:36 -07001830 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001831 Ok(()).no_gc()
Max Bires2b2e6562020-09-22 11:22:36 -07001832 })
1833 .context("In assign_attestation_key: ")
1834 }
1835
1836 /// Retrieves num_keys number of attestation keys that have not yet been signed by a remote
1837 /// provisioning server, or the maximum number available if there are not num_keys number of
1838 /// entries in the table.
1839 pub fn fetch_unsigned_attestation_keys(
1840 &mut self,
1841 num_keys: i32,
1842 km_uuid: &Uuid,
1843 ) -> Result<Vec<Vec<u8>>> {
Janis Danisevskis850d4862021-05-05 08:41:14 -07001844 let _wp = wd::watch_millis("KeystoreDB::fetch_unsigned_attestation_keys", 500);
1845
Max Bires2b2e6562020-09-22 11:22:36 -07001846 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1847 let mut stmt = tx
1848 .prepare(
1849 "SELECT data
1850 FROM persistent.keymetadata
1851 WHERE tag = ? AND keyentryid IN
1852 (SELECT id
1853 FROM persistent.keyentry
1854 WHERE
1855 alias IS NULL AND
1856 domain IS NULL AND
1857 namespace IS NULL AND
1858 key_type = ? AND
1859 km_uuid = ?
1860 LIMIT ?);",
1861 )
1862 .context("Failed to prepare statement")?;
1863 let rows = stmt
1864 .query_map(
1865 params![
1866 KeyMetaData::AttestationMacedPublicKey,
1867 KeyType::Attestation,
1868 km_uuid,
1869 num_keys
1870 ],
Janis Danisevskis82e55f92021-05-06 14:55:48 -07001871 |row| row.get(0),
Max Bires2b2e6562020-09-22 11:22:36 -07001872 )?
1873 .collect::<rusqlite::Result<Vec<Vec<u8>>>>()
1874 .context("Failed to execute statement")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001875 Ok(rows).no_gc()
Max Bires2b2e6562020-09-22 11:22:36 -07001876 })
1877 .context("In fetch_unsigned_attestation_keys")
1878 }
1879
1880 /// Removes any keys that have expired as of the current time. Returns the number of keys
1881 /// marked unreferenced that are bound to be garbage collected.
1882 pub fn delete_expired_attestation_keys(&mut self) -> Result<i32> {
Janis Danisevskis850d4862021-05-05 08:41:14 -07001883 let _wp = wd::watch_millis("KeystoreDB::delete_expired_attestation_keys", 500);
1884
Max Bires2b2e6562020-09-22 11:22:36 -07001885 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1886 let mut stmt = tx
1887 .prepare(
1888 "SELECT keyentryid, data
1889 FROM persistent.keymetadata
1890 WHERE tag = ? AND keyentryid IN
1891 (SELECT id
1892 FROM persistent.keyentry
1893 WHERE key_type = ?);",
1894 )
1895 .context("Failed to prepare query")?;
1896 let key_ids_to_check = stmt
1897 .query_map(
1898 params![KeyMetaData::AttestationExpirationDate, KeyType::Attestation],
1899 |row| Ok((row.get(0)?, row.get(1)?)),
1900 )?
1901 .collect::<rusqlite::Result<Vec<(i64, DateTime)>>>()
1902 .context("Failed to get date metadata")?;
1903 let curr_time = DateTime::from_millis_epoch(
1904 SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_millis() as i64,
1905 );
1906 let mut num_deleted = 0;
1907 for id in key_ids_to_check.iter().filter(|kt| kt.1 < curr_time).map(|kt| kt.0) {
1908 if Self::mark_unreferenced(&tx, id)? {
1909 num_deleted += 1;
1910 }
1911 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001912 Ok(num_deleted).do_gc(num_deleted != 0)
Max Bires2b2e6562020-09-22 11:22:36 -07001913 })
1914 .context("In delete_expired_attestation_keys: ")
1915 }
1916
Max Bires60d7ed12021-03-05 15:59:22 -08001917 /// Deletes all remotely provisioned attestation keys in the system, regardless of the state
1918 /// they are in. This is useful primarily as a testing mechanism.
1919 pub fn delete_all_attestation_keys(&mut self) -> Result<i64> {
Janis Danisevskis850d4862021-05-05 08:41:14 -07001920 let _wp = wd::watch_millis("KeystoreDB::delete_all_attestation_keys", 500);
1921
Max Bires60d7ed12021-03-05 15:59:22 -08001922 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1923 let mut stmt = tx
1924 .prepare(
1925 "SELECT id FROM persistent.keyentry
1926 WHERE key_type IS ?;",
1927 )
1928 .context("Failed to prepare statement")?;
1929 let keys_to_delete = stmt
Janis Danisevskis82e55f92021-05-06 14:55:48 -07001930 .query_map(params![KeyType::Attestation], |row| row.get(0))?
Max Bires60d7ed12021-03-05 15:59:22 -08001931 .collect::<rusqlite::Result<Vec<i64>>>()
1932 .context("Failed to execute statement")?;
1933 let num_deleted = keys_to_delete
1934 .iter()
1935 .map(|id| Self::mark_unreferenced(&tx, *id))
1936 .collect::<Result<Vec<bool>>>()
1937 .context("Failed to execute mark_unreferenced on a keyid")?
1938 .into_iter()
1939 .filter(|result| *result)
1940 .count() as i64;
1941 Ok(num_deleted).do_gc(num_deleted != 0)
1942 })
1943 .context("In delete_all_attestation_keys: ")
1944 }
1945
Max Bires2b2e6562020-09-22 11:22:36 -07001946 /// Counts the number of keys that will expire by the provided epoch date and the number of
1947 /// keys not currently assigned to a domain.
1948 pub fn get_attestation_pool_status(
1949 &mut self,
1950 date: i64,
1951 km_uuid: &Uuid,
1952 ) -> Result<AttestationPoolStatus> {
Janis Danisevskis850d4862021-05-05 08:41:14 -07001953 let _wp = wd::watch_millis("KeystoreDB::get_attestation_pool_status", 500);
1954
Max Bires2b2e6562020-09-22 11:22:36 -07001955 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1956 let mut stmt = tx.prepare(
1957 "SELECT data
1958 FROM persistent.keymetadata
1959 WHERE tag = ? AND keyentryid IN
1960 (SELECT id
1961 FROM persistent.keyentry
1962 WHERE alias IS NOT NULL
1963 AND key_type = ?
1964 AND km_uuid = ?
1965 AND state = ?);",
1966 )?;
1967 let times = stmt
1968 .query_map(
1969 params![
1970 KeyMetaData::AttestationExpirationDate,
1971 KeyType::Attestation,
1972 km_uuid,
1973 KeyLifeCycle::Live
1974 ],
Janis Danisevskis82e55f92021-05-06 14:55:48 -07001975 |row| row.get(0),
Max Bires2b2e6562020-09-22 11:22:36 -07001976 )?
1977 .collect::<rusqlite::Result<Vec<DateTime>>>()
1978 .context("Failed to execute metadata statement")?;
1979 let expiring =
1980 times.iter().filter(|time| time < &&DateTime::from_millis_epoch(date)).count()
1981 as i32;
1982 stmt = tx.prepare(
1983 "SELECT alias, domain
1984 FROM persistent.keyentry
1985 WHERE key_type = ? AND km_uuid = ? AND state = ?;",
1986 )?;
1987 let rows = stmt
1988 .query_map(params![KeyType::Attestation, km_uuid, KeyLifeCycle::Live], |row| {
1989 Ok((row.get(0)?, row.get(1)?))
1990 })?
1991 .collect::<rusqlite::Result<Vec<(Option<String>, Option<u32>)>>>()
1992 .context("Failed to execute keyentry statement")?;
1993 let mut unassigned = 0i32;
1994 let mut attested = 0i32;
1995 let total = rows.len() as i32;
1996 for (alias, domain) in rows {
1997 match (alias, domain) {
1998 (Some(_alias), None) => {
1999 attested += 1;
2000 unassigned += 1;
2001 }
2002 (Some(_alias), Some(_domain)) => {
2003 attested += 1;
2004 }
2005 _ => {}
2006 }
2007 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002008 Ok(AttestationPoolStatus { expiring, unassigned, attested, total }).no_gc()
Max Bires2b2e6562020-09-22 11:22:36 -07002009 })
2010 .context("In get_attestation_pool_status: ")
2011 }
2012
2013 /// Fetches the private key and corresponding certificate chain assigned to a
2014 /// domain/namespace pair. Will either return nothing if the domain/namespace is
2015 /// not assigned, or one CertificateChain.
2016 pub fn retrieve_attestation_key_and_cert_chain(
2017 &mut self,
2018 domain: Domain,
2019 namespace: i64,
2020 km_uuid: &Uuid,
2021 ) -> Result<Option<CertificateChain>> {
Janis Danisevskis850d4862021-05-05 08:41:14 -07002022 let _wp = wd::watch_millis("KeystoreDB::retrieve_attestation_key_and_cert_chain", 500);
2023
Max Bires2b2e6562020-09-22 11:22:36 -07002024 match domain {
2025 Domain::APP | Domain::SELINUX => {}
2026 _ => {
2027 return Err(KsError::sys())
2028 .context(format!("Domain {:?} must be either App or SELinux.", domain));
2029 }
2030 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002031 self.with_transaction(TransactionBehavior::Deferred, |tx| {
2032 let mut stmt = tx.prepare(
2033 "SELECT subcomponent_type, blob
Max Bires2b2e6562020-09-22 11:22:36 -07002034 FROM persistent.blobentry
2035 WHERE keyentryid IN
2036 (SELECT id
2037 FROM persistent.keyentry
2038 WHERE key_type = ?
2039 AND domain = ?
2040 AND namespace = ?
2041 AND state = ?
2042 AND km_uuid = ?);",
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002043 )?;
2044 let rows = stmt
2045 .query_map(
2046 params![
2047 KeyType::Attestation,
2048 domain.0 as u32,
2049 namespace,
2050 KeyLifeCycle::Live,
2051 km_uuid
2052 ],
2053 |row| Ok((row.get(0)?, row.get(1)?)),
2054 )?
2055 .collect::<rusqlite::Result<Vec<(SubComponentType, Vec<u8>)>>>()
Max Biresb2e1d032021-02-08 21:35:05 -08002056 .context("query failed.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002057 if rows.is_empty() {
2058 return Ok(None).no_gc();
Max Biresb2e1d032021-02-08 21:35:05 -08002059 } else if rows.len() != 3 {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002060 return Err(KsError::sys()).context(format!(
2061 concat!(
Max Biresb2e1d032021-02-08 21:35:05 -08002062 "Expected to get a single attestation",
2063 "key, cert, and cert chain for a total of 3 entries, but instead got {}."
2064 ),
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002065 rows.len()
2066 ));
Max Bires2b2e6562020-09-22 11:22:36 -07002067 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002068 let mut km_blob: Vec<u8> = Vec::new();
2069 let mut cert_chain_blob: Vec<u8> = Vec::new();
Max Biresb2e1d032021-02-08 21:35:05 -08002070 let mut batch_cert_blob: Vec<u8> = Vec::new();
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002071 for row in rows {
2072 let sub_type: SubComponentType = row.0;
2073 match sub_type {
2074 SubComponentType::KEY_BLOB => {
2075 km_blob = row.1;
2076 }
2077 SubComponentType::CERT_CHAIN => {
2078 cert_chain_blob = row.1;
2079 }
Max Biresb2e1d032021-02-08 21:35:05 -08002080 SubComponentType::CERT => {
2081 batch_cert_blob = row.1;
2082 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002083 _ => Err(KsError::sys()).context("Unknown or incorrect subcomponent type.")?,
2084 }
2085 }
2086 Ok(Some(CertificateChain {
2087 private_key: ZVec::try_from(km_blob)?,
Max Bires97f96812021-02-23 23:44:57 -08002088 batch_cert: batch_cert_blob,
2089 cert_chain: cert_chain_blob,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002090 }))
2091 .no_gc()
2092 })
Max Biresb2e1d032021-02-08 21:35:05 -08002093 .context("In retrieve_attestation_key_and_cert_chain:")
Max Bires2b2e6562020-09-22 11:22:36 -07002094 }
2095
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002096 /// Updates the alias column of the given key id `newid` with the given alias,
2097 /// and atomically, removes the alias, domain, and namespace from another row
2098 /// with the same alias-domain-namespace tuple if such row exits.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002099 /// Returns Ok(true) if an old key was marked unreferenced as a hint to the garbage
2100 /// collector.
2101 fn rebind_alias(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002102 tx: &Transaction,
Janis Danisevskisaec14592020-11-12 09:41:49 -08002103 newid: &KeyIdGuard,
Joel Galenson33c04ad2020-08-03 11:04:38 -07002104 alias: &str,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002105 domain: &Domain,
2106 namespace: &i64,
Janis Danisevskis0cabd712021-05-25 11:07:10 -07002107 key_type: KeyType,
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002108 ) -> Result<bool> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002109 match *domain {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002110 Domain::APP | Domain::SELINUX => {}
Joel Galenson33c04ad2020-08-03 11:04:38 -07002111 _ => {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002112 return Err(KsError::sys()).context(format!(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002113 "In rebind_alias: Domain {:?} must be either App or SELinux.",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002114 domain
2115 ));
Joel Galenson33c04ad2020-08-03 11:04:38 -07002116 }
2117 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002118 let updated = tx
2119 .execute(
2120 "UPDATE persistent.keyentry
2121 SET alias = NULL, domain = NULL, namespace = NULL, state = ?
Janis Danisevskis0cabd712021-05-25 11:07:10 -07002122 WHERE alias = ? AND domain = ? AND namespace = ? AND key_type = ?;",
2123 params![KeyLifeCycle::Unreferenced, alias, domain.0 as u32, namespace, key_type],
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002124 )
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002125 .context("In rebind_alias: Failed to rebind existing entry.")?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07002126 let result = tx
2127 .execute(
2128 "UPDATE persistent.keyentry
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002129 SET alias = ?, state = ?
Janis Danisevskis0cabd712021-05-25 11:07:10 -07002130 WHERE id = ? AND domain = ? AND namespace = ? AND state = ? AND key_type = ?;",
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002131 params![
2132 alias,
2133 KeyLifeCycle::Live,
2134 newid.0,
2135 domain.0 as u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002136 *namespace,
Max Bires8e93d2b2021-01-14 13:17:59 -08002137 KeyLifeCycle::Existing,
Janis Danisevskis0cabd712021-05-25 11:07:10 -07002138 key_type,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002139 ],
Joel Galenson33c04ad2020-08-03 11:04:38 -07002140 )
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002141 .context("In rebind_alias: Failed to set alias.")?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07002142 if result != 1 {
Joel Galenson33c04ad2020-08-03 11:04:38 -07002143 return Err(KsError::sys()).context(format!(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002144 "In rebind_alias: Expected to update a single entry but instead updated {}.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07002145 result
2146 ));
2147 }
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002148 Ok(updated != 0)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002149 }
2150
Janis Danisevskiscdcf4e52021-04-14 15:44:36 -07002151 /// Moves the key given by KeyIdGuard to the new location at `destination`. If the destination
2152 /// is already occupied by a key, this function fails with `ResponseCode::INVALID_ARGUMENT`.
2153 pub fn migrate_key_namespace(
2154 &mut self,
2155 key_id_guard: KeyIdGuard,
2156 destination: &KeyDescriptor,
2157 caller_uid: u32,
2158 check_permission: impl Fn(&KeyDescriptor) -> Result<()>,
2159 ) -> Result<()> {
Janis Danisevskis850d4862021-05-05 08:41:14 -07002160 let _wp = wd::watch_millis("KeystoreDB::migrate_key_namespace", 500);
2161
Janis Danisevskiscdcf4e52021-04-14 15:44:36 -07002162 let destination = match destination.domain {
2163 Domain::APP => KeyDescriptor { nspace: caller_uid as i64, ..(*destination).clone() },
2164 Domain::SELINUX => (*destination).clone(),
2165 domain => {
2166 return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT))
2167 .context(format!("Domain {:?} must be either APP or SELINUX.", domain));
2168 }
2169 };
2170
2171 // Security critical: Must return immediately on failure. Do not remove the '?';
2172 check_permission(&destination)
2173 .context("In migrate_key_namespace: Trying to check permission.")?;
2174
2175 let alias = destination
2176 .alias
2177 .as_ref()
2178 .ok_or(KsError::Rc(ResponseCode::INVALID_ARGUMENT))
2179 .context("In migrate_key_namespace: Alias must be specified.")?;
2180
2181 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2182 // Query the destination location. If there is a key, the migration request fails.
2183 if tx
2184 .query_row(
2185 "SELECT id FROM persistent.keyentry
2186 WHERE alias = ? AND domain = ? AND namespace = ?;",
2187 params![alias, destination.domain.0, destination.nspace],
2188 |_| Ok(()),
2189 )
2190 .optional()
2191 .context("Failed to query destination.")?
2192 .is_some()
2193 {
2194 return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT))
2195 .context("Target already exists.");
2196 }
2197
2198 let updated = tx
2199 .execute(
2200 "UPDATE persistent.keyentry
2201 SET alias = ?, domain = ?, namespace = ?
2202 WHERE id = ?;",
2203 params![alias, destination.domain.0, destination.nspace, key_id_guard.id()],
2204 )
2205 .context("Failed to update key entry.")?;
2206
2207 if updated != 1 {
2208 return Err(KsError::sys())
2209 .context(format!("Update succeeded, but {} rows were updated.", updated));
2210 }
2211 Ok(()).no_gc()
2212 })
2213 .context("In migrate_key_namespace:")
2214 }
2215
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002216 /// Store a new key in a single transaction.
2217 /// The function creates a new key entry, populates the blob, key parameter, and metadata
2218 /// fields, and rebinds the given alias to the new key.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002219 /// The boolean returned is a hint for the garbage collector. If true, a key was replaced,
2220 /// is now unreferenced and needs to be collected.
Janis Danisevskis0cabd712021-05-25 11:07:10 -07002221 #[allow(clippy::clippy::too_many_arguments)]
Janis Danisevskis66784c42021-01-27 08:40:25 -08002222 pub fn store_new_key(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002223 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002224 key: &KeyDescriptor,
Janis Danisevskis0cabd712021-05-25 11:07:10 -07002225 key_type: KeyType,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002226 params: &[KeyParameter],
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002227 blob_info: &(&[u8], &BlobMetaData),
Max Bires8e93d2b2021-01-14 13:17:59 -08002228 cert_info: &CertificateInfo,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002229 metadata: &KeyMetaData,
Max Bires8e93d2b2021-01-14 13:17:59 -08002230 km_uuid: &Uuid,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002231 ) -> Result<KeyIdGuard> {
Janis Danisevskis850d4862021-05-05 08:41:14 -07002232 let _wp = wd::watch_millis("KeystoreDB::store_new_key", 500);
2233
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002234 let (alias, domain, namespace) = match key {
2235 KeyDescriptor { alias: Some(alias), domain: Domain::APP, nspace, blob: None }
2236 | KeyDescriptor { alias: Some(alias), domain: Domain::SELINUX, nspace, blob: None } => {
2237 (alias, key.domain, nspace)
2238 }
2239 _ => {
2240 return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT))
2241 .context("In store_new_key: Need alias and domain must be APP or SELINUX.")
2242 }
2243 };
2244 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis0cabd712021-05-25 11:07:10 -07002245 let key_id = Self::create_key_entry_internal(tx, &domain, namespace, key_type, km_uuid)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002246 .context("Trying to create new key entry.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002247 let (blob, blob_metadata) = *blob_info;
2248 Self::set_blob_internal(
2249 tx,
2250 key_id.id(),
2251 SubComponentType::KEY_BLOB,
2252 Some(blob),
2253 Some(&blob_metadata),
2254 )
2255 .context("Trying to insert the key blob.")?;
Max Bires8e93d2b2021-01-14 13:17:59 -08002256 if let Some(cert) = &cert_info.cert {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002257 Self::set_blob_internal(tx, key_id.id(), SubComponentType::CERT, Some(&cert), None)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002258 .context("Trying to insert the certificate.")?;
2259 }
Max Bires8e93d2b2021-01-14 13:17:59 -08002260 if let Some(cert_chain) = &cert_info.cert_chain {
Janis Danisevskis377d1002021-01-27 19:07:48 -08002261 Self::set_blob_internal(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002262 tx,
2263 key_id.id(),
2264 SubComponentType::CERT_CHAIN,
Janis Danisevskis377d1002021-01-27 19:07:48 -08002265 Some(&cert_chain),
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002266 None,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002267 )
2268 .context("Trying to insert the certificate chain.")?;
2269 }
2270 Self::insert_keyparameter_internal(tx, &key_id, params)
2271 .context("Trying to insert key parameters.")?;
Janis Danisevskis377d1002021-01-27 19:07:48 -08002272 metadata.store_in_db(key_id.id(), tx).context("Trying to insert key metadata.")?;
Janis Danisevskis0cabd712021-05-25 11:07:10 -07002273 let need_gc = Self::rebind_alias(tx, &key_id, &alias, &domain, namespace, key_type)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002274 .context("Trying to rebind alias.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002275 Ok(key_id).do_gc(need_gc)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002276 })
2277 .context("In store_new_key.")
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002278 }
2279
Janis Danisevskis377d1002021-01-27 19:07:48 -08002280 /// Store a new certificate
2281 /// The function creates a new key entry, populates the blob field and metadata, and rebinds
2282 /// the given alias to the new cert.
Max Bires8e93d2b2021-01-14 13:17:59 -08002283 pub fn store_new_certificate(
2284 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002285 key: &KeyDescriptor,
Janis Danisevskis0cabd712021-05-25 11:07:10 -07002286 key_type: KeyType,
Max Bires8e93d2b2021-01-14 13:17:59 -08002287 cert: &[u8],
2288 km_uuid: &Uuid,
2289 ) -> Result<KeyIdGuard> {
Janis Danisevskis850d4862021-05-05 08:41:14 -07002290 let _wp = wd::watch_millis("KeystoreDB::store_new_certificate", 500);
2291
Janis Danisevskis377d1002021-01-27 19:07:48 -08002292 let (alias, domain, namespace) = match key {
2293 KeyDescriptor { alias: Some(alias), domain: Domain::APP, nspace, blob: None }
2294 | KeyDescriptor { alias: Some(alias), domain: Domain::SELINUX, nspace, blob: None } => {
2295 (alias, key.domain, nspace)
2296 }
2297 _ => {
2298 return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT)).context(
2299 "In store_new_certificate: Need alias and domain must be APP or SELINUX.",
2300 )
2301 }
2302 };
2303 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis0cabd712021-05-25 11:07:10 -07002304 let key_id = Self::create_key_entry_internal(tx, &domain, namespace, key_type, km_uuid)
Janis Danisevskis377d1002021-01-27 19:07:48 -08002305 .context("Trying to create new key entry.")?;
2306
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002307 Self::set_blob_internal(
2308 tx,
2309 key_id.id(),
2310 SubComponentType::CERT_CHAIN,
2311 Some(cert),
2312 None,
2313 )
2314 .context("Trying to insert certificate.")?;
Janis Danisevskis377d1002021-01-27 19:07:48 -08002315
2316 let mut metadata = KeyMetaData::new();
2317 metadata.add(KeyMetaEntry::CreationDate(
2318 DateTime::now().context("Trying to make creation time.")?,
2319 ));
2320
2321 metadata.store_in_db(key_id.id(), tx).context("Trying to insert key metadata.")?;
2322
Janis Danisevskis0cabd712021-05-25 11:07:10 -07002323 let need_gc = Self::rebind_alias(tx, &key_id, &alias, &domain, namespace, key_type)
Janis Danisevskis377d1002021-01-27 19:07:48 -08002324 .context("Trying to rebind alias.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002325 Ok(key_id).do_gc(need_gc)
Janis Danisevskis377d1002021-01-27 19:07:48 -08002326 })
2327 .context("In store_new_certificate.")
2328 }
2329
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002330 // Helper function loading the key_id given the key descriptor
2331 // tuple comprising domain, namespace, and alias.
2332 // Requires a valid transaction.
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002333 fn load_key_entry_id(tx: &Transaction, key: &KeyDescriptor, key_type: KeyType) -> Result<i64> {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002334 let alias = key
2335 .alias
2336 .as_ref()
2337 .map_or_else(|| Err(KsError::sys()), Ok)
2338 .context("In load_key_entry_id: Alias must be specified.")?;
2339 let mut stmt = tx
2340 .prepare(
2341 "SELECT id FROM persistent.keyentry
2342 WHERE
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00002343 key_type = ?
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002344 AND domain = ?
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002345 AND namespace = ?
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002346 AND alias = ?
2347 AND state = ?;",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002348 )
2349 .context("In load_key_entry_id: Failed to select from keyentry table.")?;
2350 let mut rows = stmt
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002351 .query(params![key_type, key.domain.0 as u32, key.nspace, alias, KeyLifeCycle::Live])
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002352 .context("In load_key_entry_id: Failed to read from keyentry table.")?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002353 db_utils::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002354 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002355 .get(0)
2356 .context("Failed to unpack id.")
2357 })
2358 .context("In load_key_entry_id.")
2359 }
2360
2361 /// This helper function completes the access tuple of a key, which is required
2362 /// to perform access control. The strategy depends on the `domain` field in the
2363 /// key descriptor.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002364 /// * Domain::SELINUX: The access tuple is complete and this function only loads
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002365 /// the key_id for further processing.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002366 /// * Domain::APP: Like Domain::SELINUX, but the tuple is completed by `caller_uid`
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002367 /// which serves as the namespace.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002368 /// * Domain::GRANT: The grant table is queried for the `key_id` and the
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002369 /// `access_vector`.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002370 /// * Domain::KEY_ID: The keyentry table is queried for the owning `domain` and
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002371 /// `namespace`.
2372 /// In each case the information returned is sufficient to perform the access
2373 /// check and the key id can be used to load further key artifacts.
2374 fn load_access_tuple(
2375 tx: &Transaction,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002376 key: &KeyDescriptor,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002377 key_type: KeyType,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002378 caller_uid: u32,
2379 ) -> Result<(i64, KeyDescriptor, Option<KeyPermSet>)> {
2380 match key.domain {
2381 // Domain App or SELinux. In this case we load the key_id from
2382 // the keyentry database for further loading of key components.
2383 // We already have the full access tuple to perform access control.
2384 // The only distinction is that we use the caller_uid instead
2385 // of the caller supplied namespace if the domain field is
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002386 // Domain::APP.
2387 Domain::APP | Domain::SELINUX => {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002388 let mut access_key = key.clone();
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002389 if access_key.domain == Domain::APP {
2390 access_key.nspace = caller_uid as i64;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002391 }
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002392 let key_id = Self::load_key_entry_id(&tx, &access_key, key_type)
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002393 .with_context(|| format!("With key.domain = {:?}.", access_key.domain))?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002394
2395 Ok((key_id, access_key, None))
2396 }
2397
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002398 // Domain::GRANT. In this case we load the key_id and the access_vector
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002399 // from the grant table.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002400 Domain::GRANT => {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002401 let mut stmt = tx
2402 .prepare(
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002403 "SELECT keyentryid, access_vector FROM persistent.grant
Hasini Gunasinghee70a0ec2021-05-10 21:12:34 +00002404 WHERE grantee = ? AND id = ? AND
2405 (SELECT state FROM persistent.keyentry WHERE id = keyentryid) = ?;",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002406 )
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002407 .context("Domain::GRANT prepare statement failed")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002408 let mut rows = stmt
Hasini Gunasinghee70a0ec2021-05-10 21:12:34 +00002409 .query(params![caller_uid as i64, key.nspace, KeyLifeCycle::Live])
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002410 .context("Domain:Grant: query failed.")?;
2411 let (key_id, access_vector): (i64, i32) =
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002412 db_utils::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002413 let r =
2414 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002415 Ok((
2416 r.get(0).context("Failed to unpack key_id.")?,
2417 r.get(1).context("Failed to unpack access_vector.")?,
2418 ))
2419 })
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002420 .context("Domain::GRANT.")?;
Janis Danisevskis66784c42021-01-27 08:40:25 -08002421 Ok((key_id, key.clone(), Some(access_vector.into())))
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002422 }
2423
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002424 // Domain::KEY_ID. In this case we load the domain and namespace from the
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002425 // keyentry database because we need them for access control.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002426 Domain::KEY_ID => {
Janis Danisevskis45760022021-01-19 16:34:10 -08002427 let (domain, namespace): (Domain, i64) = {
2428 let mut stmt = tx
2429 .prepare(
2430 "SELECT domain, namespace FROM persistent.keyentry
2431 WHERE
2432 id = ?
2433 AND state = ?;",
2434 )
2435 .context("Domain::KEY_ID: prepare statement failed")?;
2436 let mut rows = stmt
2437 .query(params![key.nspace, KeyLifeCycle::Live])
2438 .context("Domain::KEY_ID: query failed.")?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002439 db_utils::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002440 let r =
2441 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002442 Ok((
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002443 Domain(r.get(0).context("Failed to unpack domain.")?),
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002444 r.get(1).context("Failed to unpack namespace.")?,
2445 ))
2446 })
Janis Danisevskis45760022021-01-19 16:34:10 -08002447 .context("Domain::KEY_ID.")?
2448 };
2449
2450 // We may use a key by id after loading it by grant.
2451 // In this case we have to check if the caller has a grant for this particular
2452 // key. We can skip this if we already know that the caller is the owner.
2453 // But we cannot know this if domain is anything but App. E.g. in the case
2454 // of Domain::SELINUX we have to speculatively check for grants because we have to
2455 // consult the SEPolicy before we know if the caller is the owner.
2456 let access_vector: Option<KeyPermSet> =
2457 if domain != Domain::APP || namespace != caller_uid as i64 {
2458 let access_vector: Option<i32> = tx
2459 .query_row(
2460 "SELECT access_vector FROM persistent.grant
2461 WHERE grantee = ? AND keyentryid = ?;",
2462 params![caller_uid as i64, key.nspace],
2463 |row| row.get(0),
2464 )
2465 .optional()
2466 .context("Domain::KEY_ID: query grant failed.")?;
2467 access_vector.map(|p| p.into())
2468 } else {
2469 None
2470 };
2471
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002472 let key_id = key.nspace;
Janis Danisevskis66784c42021-01-27 08:40:25 -08002473 let mut access_key: KeyDescriptor = key.clone();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002474 access_key.domain = domain;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002475 access_key.nspace = namespace;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002476
Janis Danisevskis45760022021-01-19 16:34:10 -08002477 Ok((key_id, access_key, access_vector))
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002478 }
2479 _ => Err(anyhow!(KsError::sys())),
2480 }
2481 }
2482
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002483 fn load_blob_components(
2484 key_id: i64,
2485 load_bits: KeyEntryLoadBits,
2486 tx: &Transaction,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002487 ) -> Result<(bool, Option<(Vec<u8>, BlobMetaData)>, Option<Vec<u8>>, Option<Vec<u8>>)> {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002488 let mut stmt = tx
2489 .prepare(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002490 "SELECT MAX(id), subcomponent_type, blob FROM persistent.blobentry
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002491 WHERE keyentryid = ? GROUP BY subcomponent_type;",
2492 )
2493 .context("In load_blob_components: prepare statement failed.")?;
2494
2495 let mut rows =
2496 stmt.query(params![key_id]).context("In load_blob_components: query failed.")?;
2497
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002498 let mut key_blob: Option<(i64, Vec<u8>)> = None;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002499 let mut cert_blob: Option<Vec<u8>> = None;
2500 let mut cert_chain_blob: Option<Vec<u8>> = None;
Janis Danisevskis377d1002021-01-27 19:07:48 -08002501 let mut has_km_blob: bool = false;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002502 db_utils::with_rows_extract_all(&mut rows, |row| {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002503 let sub_type: SubComponentType =
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002504 row.get(1).context("Failed to extract subcomponent_type.")?;
Janis Danisevskis377d1002021-01-27 19:07:48 -08002505 has_km_blob = has_km_blob || sub_type == SubComponentType::KEY_BLOB;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002506 match (sub_type, load_bits.load_public(), load_bits.load_km()) {
2507 (SubComponentType::KEY_BLOB, _, true) => {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002508 key_blob = Some((
2509 row.get(0).context("Failed to extract key blob id.")?,
2510 row.get(2).context("Failed to extract key blob.")?,
2511 ));
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002512 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002513 (SubComponentType::CERT, true, _) => {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002514 cert_blob =
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002515 Some(row.get(2).context("Failed to extract public certificate blob.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002516 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002517 (SubComponentType::CERT_CHAIN, true, _) => {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002518 cert_chain_blob =
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002519 Some(row.get(2).context("Failed to extract certificate chain blob.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002520 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002521 (SubComponentType::CERT, _, _)
2522 | (SubComponentType::CERT_CHAIN, _, _)
2523 | (SubComponentType::KEY_BLOB, _, _) => {}
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002524 _ => Err(KsError::sys()).context("Unknown subcomponent type.")?,
2525 }
2526 Ok(())
2527 })
2528 .context("In load_blob_components.")?;
2529
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002530 let blob_info = key_blob.map_or::<Result<_>, _>(Ok(None), |(blob_id, blob)| {
2531 Ok(Some((
2532 blob,
2533 BlobMetaData::load_from_db(blob_id, tx)
2534 .context("In load_blob_components: Trying to load blob_metadata.")?,
2535 )))
2536 })?;
2537
2538 Ok((has_km_blob, blob_info, cert_blob, cert_chain_blob))
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002539 }
2540
2541 fn load_key_parameters(key_id: i64, tx: &Transaction) -> Result<Vec<KeyParameter>> {
2542 let mut stmt = tx
2543 .prepare(
2544 "SELECT tag, data, security_level from persistent.keyparameter
2545 WHERE keyentryid = ?;",
2546 )
2547 .context("In load_key_parameters: prepare statement failed.")?;
2548
2549 let mut parameters: Vec<KeyParameter> = Vec::new();
2550
2551 let mut rows =
2552 stmt.query(params![key_id]).context("In load_key_parameters: query failed.")?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002553 db_utils::with_rows_extract_all(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002554 let tag = Tag(row.get(0).context("Failed to read tag.")?);
2555 let sec_level = SecurityLevel(row.get(2).context("Failed to read sec_level.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002556 parameters.push(
2557 KeyParameter::new_from_sql(tag, &SqlField::new(1, &row), sec_level)
2558 .context("Failed to read KeyParameter.")?,
2559 );
2560 Ok(())
2561 })
2562 .context("In load_key_parameters.")?;
2563
2564 Ok(parameters)
2565 }
2566
Qi Wub9433b52020-12-01 14:52:46 +08002567 /// Decrements the usage count of a limited use key. This function first checks whether the
2568 /// usage has been exhausted, if not, decreases the usage count. If the usage count reaches
2569 /// zero, the key also gets marked unreferenced and scheduled for deletion.
2570 /// Returns Ok(true) if the key was marked unreferenced as a hint to the garbage collector.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002571 pub fn check_and_update_key_usage_count(&mut self, key_id: i64) -> Result<()> {
Janis Danisevskis850d4862021-05-05 08:41:14 -07002572 let _wp = wd::watch_millis("KeystoreDB::check_and_update_key_usage_count", 500);
2573
Qi Wub9433b52020-12-01 14:52:46 +08002574 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2575 let limit: Option<i32> = tx
2576 .query_row(
2577 "SELECT data FROM persistent.keyparameter WHERE keyentryid = ? AND tag = ?;",
2578 params![key_id, Tag::USAGE_COUNT_LIMIT.0],
2579 |row| row.get(0),
2580 )
2581 .optional()
2582 .context("Trying to load usage count")?;
2583
2584 let limit = limit
2585 .ok_or(KsError::Km(ErrorCode::INVALID_KEY_BLOB))
2586 .context("The Key no longer exists. Key is exhausted.")?;
2587
2588 tx.execute(
2589 "UPDATE persistent.keyparameter
2590 SET data = data - 1
2591 WHERE keyentryid = ? AND tag = ? AND data > 0;",
2592 params![key_id, Tag::USAGE_COUNT_LIMIT.0],
2593 )
2594 .context("Failed to update key usage count.")?;
2595
2596 match limit {
2597 1 => Self::mark_unreferenced(tx, key_id)
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002598 .map(|need_gc| (need_gc, ()))
Qi Wub9433b52020-12-01 14:52:46 +08002599 .context("Trying to mark limited use key for deletion."),
2600 0 => Err(KsError::Km(ErrorCode::INVALID_KEY_BLOB)).context("Key is exhausted."),
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002601 _ => Ok(()).no_gc(),
Qi Wub9433b52020-12-01 14:52:46 +08002602 }
2603 })
2604 .context("In check_and_update_key_usage_count.")
2605 }
2606
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002607 /// Load a key entry by the given key descriptor.
2608 /// It uses the `check_permission` callback to verify if the access is allowed
2609 /// given the key access tuple read from the database using `load_access_tuple`.
2610 /// With `load_bits` the caller may specify which blobs shall be loaded from
2611 /// the blob database.
2612 pub fn load_key_entry(
2613 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002614 key: &KeyDescriptor,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002615 key_type: KeyType,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002616 load_bits: KeyEntryLoadBits,
2617 caller_uid: u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002618 check_permission: impl Fn(&KeyDescriptor, Option<KeyPermSet>) -> Result<()>,
2619 ) -> Result<(KeyIdGuard, KeyEntry)> {
Janis Danisevskis850d4862021-05-05 08:41:14 -07002620 let _wp = wd::watch_millis("KeystoreDB::load_key_entry", 500);
2621
Janis Danisevskis66784c42021-01-27 08:40:25 -08002622 loop {
2623 match self.load_key_entry_internal(
2624 key,
2625 key_type,
2626 load_bits,
2627 caller_uid,
2628 &check_permission,
2629 ) {
2630 Ok(result) => break Ok(result),
2631 Err(e) => {
2632 if Self::is_locked_error(&e) {
2633 std::thread::sleep(std::time::Duration::from_micros(500));
2634 continue;
2635 } else {
2636 return Err(e).context("In load_key_entry.");
2637 }
2638 }
2639 }
2640 }
2641 }
2642
2643 fn load_key_entry_internal(
2644 &mut self,
2645 key: &KeyDescriptor,
2646 key_type: KeyType,
2647 load_bits: KeyEntryLoadBits,
2648 caller_uid: u32,
2649 check_permission: &impl Fn(&KeyDescriptor, Option<KeyPermSet>) -> Result<()>,
Janis Danisevskisaec14592020-11-12 09:41:49 -08002650 ) -> Result<(KeyIdGuard, KeyEntry)> {
2651 // KEY ID LOCK 1/2
2652 // If we got a key descriptor with a key id we can get the lock right away.
2653 // Otherwise we have to defer it until we know the key id.
2654 let key_id_guard = match key.domain {
2655 Domain::KEY_ID => Some(KEY_ID_LOCK.get(key.nspace)),
2656 _ => None,
2657 };
2658
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002659 let tx = self
2660 .conn
Janis Danisevskisaec14592020-11-12 09:41:49 -08002661 .unchecked_transaction()
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002662 .context("In load_key_entry: Failed to initialize transaction.")?;
2663
2664 // Load the key_id and complete the access control tuple.
2665 let (key_id, access_key_descriptor, access_vector) =
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002666 Self::load_access_tuple(&tx, key, key_type, caller_uid)
2667 .context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002668
2669 // Perform access control. It is vital that we return here if the permission is denied.
2670 // So do not touch that '?' at the end.
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002671 check_permission(&access_key_descriptor, access_vector).context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002672
Janis Danisevskisaec14592020-11-12 09:41:49 -08002673 // KEY ID LOCK 2/2
2674 // If we did not get a key id lock by now, it was because we got a key descriptor
2675 // without a key id. At this point we got the key id, so we can try and get a lock.
2676 // However, we cannot block here, because we are in the middle of the transaction.
2677 // So first we try to get the lock non blocking. If that fails, we roll back the
2678 // transaction and block until we get the lock. After we successfully got the lock,
2679 // we start a new transaction and load the access tuple again.
2680 //
2681 // We don't need to perform access control again, because we already established
2682 // that the caller had access to the given key. But we need to make sure that the
2683 // key id still exists. So we have to load the key entry by key id this time.
2684 let (key_id_guard, tx) = match key_id_guard {
2685 None => match KEY_ID_LOCK.try_get(key_id) {
2686 None => {
2687 // Roll back the transaction.
2688 tx.rollback().context("In load_key_entry: Failed to roll back transaction.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002689
Janis Danisevskisaec14592020-11-12 09:41:49 -08002690 // Block until we have a key id lock.
2691 let key_id_guard = KEY_ID_LOCK.get(key_id);
2692
2693 // Create a new transaction.
Janis Danisevskis66784c42021-01-27 08:40:25 -08002694 let tx = self
2695 .conn
2696 .unchecked_transaction()
2697 .context("In load_key_entry: Failed to initialize transaction.")?;
Janis Danisevskisaec14592020-11-12 09:41:49 -08002698
2699 Self::load_access_tuple(
2700 &tx,
2701 // This time we have to load the key by the retrieved key id, because the
2702 // alias may have been rebound after we rolled back the transaction.
Janis Danisevskis66784c42021-01-27 08:40:25 -08002703 &KeyDescriptor {
Janis Danisevskisaec14592020-11-12 09:41:49 -08002704 domain: Domain::KEY_ID,
2705 nspace: key_id,
2706 ..Default::default()
2707 },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002708 key_type,
Janis Danisevskisaec14592020-11-12 09:41:49 -08002709 caller_uid,
2710 )
2711 .context("In load_key_entry. (deferred key lock)")?;
2712 (key_id_guard, tx)
2713 }
2714 Some(l) => (l, tx),
2715 },
2716 Some(key_id_guard) => (key_id_guard, tx),
2717 };
2718
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002719 let key_entry = Self::load_key_components(&tx, load_bits, key_id_guard.id())
2720 .context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002721
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002722 tx.commit().context("In load_key_entry: Failed to commit transaction.")?;
2723
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002724 Ok((key_id_guard, key_entry))
2725 }
2726
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002727 fn mark_unreferenced(tx: &Transaction, key_id: i64) -> Result<bool> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002728 let updated = tx
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002729 .execute("DELETE FROM persistent.keyentry WHERE id = ?;", params![key_id])
2730 .context("Trying to delete keyentry.")?;
2731 tx.execute("DELETE FROM persistent.keymetadata WHERE keyentryid = ?;", params![key_id])
2732 .context("Trying to delete keymetadata.")?;
2733 tx.execute("DELETE FROM persistent.keyparameter WHERE keyentryid = ?;", params![key_id])
2734 .context("Trying to delete keyparameters.")?;
2735 tx.execute("DELETE FROM persistent.grant WHERE keyentryid = ?;", params![key_id])
2736 .context("Trying to delete grants.")?;
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002737 Ok(updated != 0)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002738 }
2739
2740 /// Marks the given key as unreferenced and removes all of the grants to this key.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002741 /// Returns Ok(true) if a key was marked unreferenced as a hint for the garbage collector.
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002742 pub fn unbind_key(
2743 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002744 key: &KeyDescriptor,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002745 key_type: KeyType,
2746 caller_uid: u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002747 check_permission: impl Fn(&KeyDescriptor, Option<KeyPermSet>) -> Result<()>,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002748 ) -> Result<()> {
Janis Danisevskis850d4862021-05-05 08:41:14 -07002749 let _wp = wd::watch_millis("KeystoreDB::unbind_key", 500);
2750
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002751 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2752 let (key_id, access_key_descriptor, access_vector) =
2753 Self::load_access_tuple(tx, key, key_type, caller_uid)
2754 .context("Trying to get access tuple.")?;
2755
2756 // Perform access control. It is vital that we return here if the permission is denied.
2757 // So do not touch that '?' at the end.
2758 check_permission(&access_key_descriptor, access_vector)
2759 .context("While checking permission.")?;
2760
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002761 Self::mark_unreferenced(tx, key_id)
2762 .map(|need_gc| (need_gc, ()))
2763 .context("Trying to mark the key unreferenced.")
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002764 })
2765 .context("In unbind_key.")
2766 }
2767
Max Bires8e93d2b2021-01-14 13:17:59 -08002768 fn get_key_km_uuid(tx: &Transaction, key_id: i64) -> Result<Uuid> {
2769 tx.query_row(
2770 "SELECT km_uuid FROM persistent.keyentry WHERE id = ?",
2771 params![key_id],
2772 |row| row.get(0),
2773 )
2774 .context("In get_key_km_uuid.")
2775 }
2776
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002777 /// Delete all artifacts belonging to the namespace given by the domain-namespace tuple.
2778 /// This leaves all of the blob entries orphaned for subsequent garbage collection.
2779 pub fn unbind_keys_for_namespace(&mut self, domain: Domain, namespace: i64) -> Result<()> {
Janis Danisevskis850d4862021-05-05 08:41:14 -07002780 let _wp = wd::watch_millis("KeystoreDB::unbind_keys_for_namespace", 500);
2781
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002782 if !(domain == Domain::APP || domain == Domain::SELINUX) {
2783 return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT))
2784 .context("In unbind_keys_for_namespace.");
2785 }
2786 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2787 tx.execute(
2788 "DELETE FROM persistent.keymetadata
2789 WHERE keyentryid IN (
2790 SELECT id FROM persistent.keyentry
Janis Danisevskisb146f312021-05-06 15:05:45 -07002791 WHERE domain = ? AND namespace = ? AND key_type = ?
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002792 );",
Janis Danisevskisb146f312021-05-06 15:05:45 -07002793 params![domain.0, namespace, KeyType::Client],
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002794 )
2795 .context("Trying to delete keymetadata.")?;
2796 tx.execute(
2797 "DELETE FROM persistent.keyparameter
2798 WHERE keyentryid IN (
2799 SELECT id FROM persistent.keyentry
Janis Danisevskisb146f312021-05-06 15:05:45 -07002800 WHERE domain = ? AND namespace = ? AND key_type = ?
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002801 );",
Janis Danisevskisb146f312021-05-06 15:05:45 -07002802 params![domain.0, namespace, KeyType::Client],
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002803 )
2804 .context("Trying to delete keyparameters.")?;
2805 tx.execute(
2806 "DELETE FROM persistent.grant
2807 WHERE keyentryid IN (
2808 SELECT id FROM persistent.keyentry
Janis Danisevskisb146f312021-05-06 15:05:45 -07002809 WHERE domain = ? AND namespace = ? AND key_type = ?
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002810 );",
Janis Danisevskisb146f312021-05-06 15:05:45 -07002811 params![domain.0, namespace, KeyType::Client],
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002812 )
2813 .context("Trying to delete grants.")?;
2814 tx.execute(
Janis Danisevskisb146f312021-05-06 15:05:45 -07002815 "DELETE FROM persistent.keyentry
2816 WHERE domain = ? AND namespace = ? AND key_type = ?;",
2817 params![domain.0, namespace, KeyType::Client],
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002818 )
2819 .context("Trying to delete keyentry.")?;
2820 Ok(()).need_gc()
2821 })
2822 .context("In unbind_keys_for_namespace")
2823 }
2824
Janis Danisevskis3cba10d2021-05-06 17:02:19 -07002825 fn cleanup_unreferenced(tx: &Transaction) -> Result<()> {
2826 let _wp = wd::watch_millis("KeystoreDB::cleanup_unreferenced", 500);
2827 {
2828 tx.execute(
2829 "DELETE FROM persistent.keymetadata
2830 WHERE keyentryid IN (
2831 SELECT id FROM persistent.keyentry
2832 WHERE state = ?
2833 );",
2834 params![KeyLifeCycle::Unreferenced],
2835 )
2836 .context("Trying to delete keymetadata.")?;
2837 tx.execute(
2838 "DELETE FROM persistent.keyparameter
2839 WHERE keyentryid IN (
2840 SELECT id FROM persistent.keyentry
2841 WHERE state = ?
2842 );",
2843 params![KeyLifeCycle::Unreferenced],
2844 )
2845 .context("Trying to delete keyparameters.")?;
2846 tx.execute(
2847 "DELETE FROM persistent.grant
2848 WHERE keyentryid IN (
2849 SELECT id FROM persistent.keyentry
2850 WHERE state = ?
2851 );",
2852 params![KeyLifeCycle::Unreferenced],
2853 )
2854 .context("Trying to delete grants.")?;
2855 tx.execute(
2856 "DELETE FROM persistent.keyentry
2857 WHERE state = ?;",
2858 params![KeyLifeCycle::Unreferenced],
2859 )
2860 .context("Trying to delete keyentry.")?;
2861 Result::<()>::Ok(())
2862 }
2863 .context("In cleanup_unreferenced")
2864 }
2865
Hasini Gunasingheda895552021-01-27 19:34:37 +00002866 /// Delete the keys created on behalf of the user, denoted by the user id.
2867 /// Delete all the keys unless 'keep_non_super_encrypted_keys' set to true.
2868 /// Returned boolean is to hint the garbage collector to delete the unbound keys.
2869 /// The caller of this function should notify the gc if the returned value is true.
2870 pub fn unbind_keys_for_user(
2871 &mut self,
2872 user_id: u32,
2873 keep_non_super_encrypted_keys: bool,
2874 ) -> Result<()> {
Janis Danisevskis850d4862021-05-05 08:41:14 -07002875 let _wp = wd::watch_millis("KeystoreDB::unbind_keys_for_user", 500);
2876
Hasini Gunasingheda895552021-01-27 19:34:37 +00002877 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2878 let mut stmt = tx
2879 .prepare(&format!(
2880 "SELECT id from persistent.keyentry
2881 WHERE (
2882 key_type = ?
2883 AND domain = ?
2884 AND cast ( (namespace/{aid_user_offset}) as int) = ?
2885 AND state = ?
2886 ) OR (
2887 key_type = ?
2888 AND namespace = ?
2889 AND alias = ?
2890 AND state = ?
2891 );",
2892 aid_user_offset = AID_USER_OFFSET
2893 ))
2894 .context(concat!(
2895 "In unbind_keys_for_user. ",
2896 "Failed to prepare the query to find the keys created by apps."
2897 ))?;
2898
2899 let mut rows = stmt
2900 .query(params![
2901 // WHERE client key:
2902 KeyType::Client,
2903 Domain::APP.0 as u32,
2904 user_id,
2905 KeyLifeCycle::Live,
2906 // OR super key:
2907 KeyType::Super,
2908 user_id,
Paul Crowley7a658392021-03-18 17:08:20 -07002909 USER_SUPER_KEY.alias,
Hasini Gunasingheda895552021-01-27 19:34:37 +00002910 KeyLifeCycle::Live
2911 ])
2912 .context("In unbind_keys_for_user. Failed to query the keys created by apps.")?;
2913
2914 let mut key_ids: Vec<i64> = Vec::new();
2915 db_utils::with_rows_extract_all(&mut rows, |row| {
2916 key_ids
2917 .push(row.get(0).context("Failed to read key id of a key created by an app.")?);
2918 Ok(())
2919 })
2920 .context("In unbind_keys_for_user.")?;
2921
2922 let mut notify_gc = false;
2923 for key_id in key_ids {
2924 if keep_non_super_encrypted_keys {
2925 // Load metadata and filter out non-super-encrypted keys.
2926 if let (_, Some((_, blob_metadata)), _, _) =
2927 Self::load_blob_components(key_id, KeyEntryLoadBits::KM, tx)
2928 .context("In unbind_keys_for_user: Trying to load blob info.")?
2929 {
2930 if blob_metadata.encrypted_by().is_none() {
2931 continue;
2932 }
2933 }
2934 }
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +00002935 notify_gc = Self::mark_unreferenced(&tx, key_id)
Hasini Gunasingheda895552021-01-27 19:34:37 +00002936 .context("In unbind_keys_for_user.")?
2937 || notify_gc;
2938 }
2939 Ok(()).do_gc(notify_gc)
2940 })
2941 .context("In unbind_keys_for_user.")
2942 }
2943
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002944 fn load_key_components(
2945 tx: &Transaction,
2946 load_bits: KeyEntryLoadBits,
2947 key_id: i64,
2948 ) -> Result<KeyEntry> {
2949 let metadata = KeyMetaData::load_from_db(key_id, &tx).context("In load_key_components.")?;
2950
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002951 let (has_km_blob, key_blob_info, cert_blob, cert_chain_blob) =
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002952 Self::load_blob_components(key_id, load_bits, &tx)
2953 .context("In load_key_components.")?;
2954
Max Bires8e93d2b2021-01-14 13:17:59 -08002955 let parameters = Self::load_key_parameters(key_id, &tx)
2956 .context("In load_key_components: Trying to load key parameters.")?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002957
Max Bires8e93d2b2021-01-14 13:17:59 -08002958 let km_uuid = Self::get_key_km_uuid(&tx, key_id)
2959 .context("In load_key_components: Trying to get KM uuid.")?;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002960
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002961 Ok(KeyEntry {
2962 id: key_id,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002963 key_blob_info,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002964 cert: cert_blob,
2965 cert_chain: cert_chain_blob,
Max Bires8e93d2b2021-01-14 13:17:59 -08002966 km_uuid,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002967 parameters,
2968 metadata,
Janis Danisevskis377d1002021-01-27 19:07:48 -08002969 pure_cert: !has_km_blob,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002970 })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002971 }
2972
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002973 /// Returns a list of KeyDescriptors in the selected domain/namespace.
2974 /// The key descriptors will have the domain, nspace, and alias field set.
2975 /// Domain must be APP or SELINUX, the caller must make sure of that.
Janis Danisevskis18313832021-05-17 13:30:32 -07002976 pub fn list(
2977 &mut self,
2978 domain: Domain,
2979 namespace: i64,
2980 key_type: KeyType,
2981 ) -> Result<Vec<KeyDescriptor>> {
Janis Danisevskis850d4862021-05-05 08:41:14 -07002982 let _wp = wd::watch_millis("KeystoreDB::list", 500);
2983
Janis Danisevskis66784c42021-01-27 08:40:25 -08002984 self.with_transaction(TransactionBehavior::Deferred, |tx| {
2985 let mut stmt = tx
2986 .prepare(
2987 "SELECT alias FROM persistent.keyentry
Janis Danisevskis18313832021-05-17 13:30:32 -07002988 WHERE domain = ?
2989 AND namespace = ?
2990 AND alias IS NOT NULL
2991 AND state = ?
2992 AND key_type = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08002993 )
2994 .context("In list: Failed to prepare.")?;
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002995
Janis Danisevskis66784c42021-01-27 08:40:25 -08002996 let mut rows = stmt
Janis Danisevskis18313832021-05-17 13:30:32 -07002997 .query(params![domain.0 as u32, namespace, KeyLifeCycle::Live, key_type])
Janis Danisevskis66784c42021-01-27 08:40:25 -08002998 .context("In list: Failed to query.")?;
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002999
Janis Danisevskis66784c42021-01-27 08:40:25 -08003000 let mut descriptors: Vec<KeyDescriptor> = Vec::new();
3001 db_utils::with_rows_extract_all(&mut rows, |row| {
3002 descriptors.push(KeyDescriptor {
3003 domain,
3004 nspace: namespace,
3005 alias: Some(row.get(0).context("Trying to extract alias.")?),
3006 blob: None,
3007 });
3008 Ok(())
3009 })
3010 .context("In list: Failed to extract rows.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003011 Ok(descriptors).no_gc()
Janis Danisevskise92a5e62020-12-02 12:57:41 -08003012 })
Janis Danisevskise92a5e62020-12-02 12:57:41 -08003013 }
3014
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003015 /// Adds a grant to the grant table.
3016 /// Like `load_key_entry` this function loads the access tuple before
3017 /// it uses the callback for a permission check. Upon success,
3018 /// it inserts the `grantee_uid`, `key_id`, and `access_vector` into the
3019 /// grant table. The new row will have a randomized id, which is used as
3020 /// grant id in the namespace field of the resulting KeyDescriptor.
3021 pub fn grant(
3022 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08003023 key: &KeyDescriptor,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003024 caller_uid: u32,
3025 grantee_uid: u32,
3026 access_vector: KeyPermSet,
Janis Danisevskis66784c42021-01-27 08:40:25 -08003027 check_permission: impl Fn(&KeyDescriptor, &KeyPermSet) -> Result<()>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003028 ) -> Result<KeyDescriptor> {
Janis Danisevskis850d4862021-05-05 08:41:14 -07003029 let _wp = wd::watch_millis("KeystoreDB::grant", 500);
3030
Janis Danisevskis66784c42021-01-27 08:40:25 -08003031 self.with_transaction(TransactionBehavior::Immediate, |tx| {
3032 // Load the key_id and complete the access control tuple.
3033 // We ignore the access vector here because grants cannot be granted.
3034 // The access vector returned here expresses the permissions the
3035 // grantee has if key.domain == Domain::GRANT. But this vector
3036 // cannot include the grant permission by design, so there is no way the
3037 // subsequent permission check can pass.
3038 // We could check key.domain == Domain::GRANT and fail early.
3039 // But even if we load the access tuple by grant here, the permission
3040 // check denies the attempt to create a grant by grant descriptor.
3041 let (key_id, access_key_descriptor, _) =
3042 Self::load_access_tuple(&tx, key, KeyType::Client, caller_uid)
3043 .context("In grant")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003044
Janis Danisevskis66784c42021-01-27 08:40:25 -08003045 // Perform access control. It is vital that we return here if the permission
3046 // was denied. So do not touch that '?' at the end of the line.
3047 // This permission check checks if the caller has the grant permission
3048 // for the given key and in addition to all of the permissions
3049 // expressed in `access_vector`.
3050 check_permission(&access_key_descriptor, &access_vector)
3051 .context("In grant: check_permission failed.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003052
Janis Danisevskis66784c42021-01-27 08:40:25 -08003053 let grant_id = if let Some(grant_id) = tx
3054 .query_row(
3055 "SELECT id FROM persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003056 WHERE keyentryid = ? AND grantee = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08003057 params![key_id, grantee_uid],
3058 |row| row.get(0),
3059 )
3060 .optional()
3061 .context("In grant: Failed get optional existing grant id.")?
3062 {
3063 tx.execute(
3064 "UPDATE persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003065 SET access_vector = ?
3066 WHERE id = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08003067 params![i32::from(access_vector), grant_id],
Joel Galenson845f74b2020-09-09 14:11:55 -07003068 )
Janis Danisevskis66784c42021-01-27 08:40:25 -08003069 .context("In grant: Failed to update existing grant.")?;
3070 grant_id
3071 } else {
3072 Self::insert_with_retry(|id| {
3073 tx.execute(
3074 "INSERT INTO persistent.grant (id, grantee, keyentryid, access_vector)
3075 VALUES (?, ?, ?, ?);",
3076 params![id, grantee_uid, key_id, i32::from(access_vector)],
3077 )
3078 })
3079 .context("In grant")?
3080 };
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003081
Janis Danisevskis66784c42021-01-27 08:40:25 -08003082 Ok(KeyDescriptor { domain: Domain::GRANT, nspace: grant_id, alias: None, blob: None })
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003083 .no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08003084 })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003085 }
3086
3087 /// This function checks permissions like `grant` and `load_key_entry`
3088 /// before removing a grant from the grant table.
3089 pub fn ungrant(
3090 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08003091 key: &KeyDescriptor,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003092 caller_uid: u32,
3093 grantee_uid: u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08003094 check_permission: impl Fn(&KeyDescriptor) -> Result<()>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003095 ) -> Result<()> {
Janis Danisevskis850d4862021-05-05 08:41:14 -07003096 let _wp = wd::watch_millis("KeystoreDB::ungrant", 500);
3097
Janis Danisevskis66784c42021-01-27 08:40:25 -08003098 self.with_transaction(TransactionBehavior::Immediate, |tx| {
3099 // Load the key_id and complete the access control tuple.
3100 // We ignore the access vector here because grants cannot be granted.
3101 let (key_id, access_key_descriptor, _) =
3102 Self::load_access_tuple(&tx, key, KeyType::Client, caller_uid)
3103 .context("In ungrant.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003104
Janis Danisevskis66784c42021-01-27 08:40:25 -08003105 // Perform access control. We must return here if the permission
3106 // was denied. So do not touch the '?' at the end of this line.
3107 check_permission(&access_key_descriptor)
3108 .context("In grant: check_permission failed.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003109
Janis Danisevskis66784c42021-01-27 08:40:25 -08003110 tx.execute(
3111 "DELETE FROM persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003112 WHERE keyentryid = ? AND grantee = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08003113 params![key_id, grantee_uid],
3114 )
3115 .context("Failed to delete grant.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003116
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003117 Ok(()).no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08003118 })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003119 }
3120
Joel Galenson845f74b2020-09-09 14:11:55 -07003121 // Generates a random id and passes it to the given function, which will
3122 // try to insert it into a database. If that insertion fails, retry;
3123 // otherwise return the id.
3124 fn insert_with_retry(inserter: impl Fn(i64) -> rusqlite::Result<usize>) -> Result<i64> {
3125 loop {
Janis Danisevskiseed69842021-02-18 20:04:10 -08003126 let newid: i64 = match random() {
3127 Self::UNASSIGNED_KEY_ID => continue, // UNASSIGNED_KEY_ID cannot be assigned.
3128 i => i,
3129 };
Joel Galenson845f74b2020-09-09 14:11:55 -07003130 match inserter(newid) {
3131 // If the id already existed, try again.
3132 Err(rusqlite::Error::SqliteFailure(
3133 libsqlite3_sys::Error {
3134 code: libsqlite3_sys::ErrorCode::ConstraintViolation,
3135 extended_code: libsqlite3_sys::SQLITE_CONSTRAINT_UNIQUE,
3136 },
3137 _,
3138 )) => (),
3139 Err(e) => {
3140 return Err(e).context("In insert_with_retry: failed to insert into database.")
3141 }
3142 _ => return Ok(newid),
3143 }
3144 }
3145 }
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00003146
Matthew Maurerd7815ca2021-05-06 21:58:45 -07003147 /// Insert or replace the auth token based on (user_id, auth_id, auth_type)
3148 pub fn insert_auth_token(&mut self, auth_token: &HardwareAuthToken) {
3149 self.perboot.insert_auth_token_entry(AuthTokenEntry::new(
3150 auth_token.clone(),
3151 MonotonicRawTime::now(),
3152 ))
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00003153 }
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00003154
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08003155 /// Find the newest auth token matching the given predicate.
Matthew Maurerd7815ca2021-05-06 21:58:45 -07003156 pub fn find_auth_token_entry<F>(&self, p: F) -> Option<(AuthTokenEntry, MonotonicRawTime)>
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08003157 where
3158 F: Fn(&AuthTokenEntry) -> bool,
3159 {
Matthew Maurerd7815ca2021-05-06 21:58:45 -07003160 self.perboot.find_auth_token_entry(p).map(|entry| (entry, self.get_last_off_body()))
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00003161 }
3162
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08003163 /// Insert last_off_body into the metadata table at the initialization of auth token table
Matthew Maurerd7815ca2021-05-06 21:58:45 -07003164 pub fn insert_last_off_body(&self, last_off_body: MonotonicRawTime) {
3165 self.perboot.set_last_off_body(last_off_body)
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00003166 }
3167
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08003168 /// Update last_off_body when on_device_off_body is called
Matthew Maurerd7815ca2021-05-06 21:58:45 -07003169 pub fn update_last_off_body(&self, last_off_body: MonotonicRawTime) {
3170 self.perboot.set_last_off_body(last_off_body)
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00003171 }
3172
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08003173 /// Get last_off_body time when finding auth tokens
Matthew Maurerd7815ca2021-05-06 21:58:45 -07003174 fn get_last_off_body(&self) -> MonotonicRawTime {
3175 self.perboot.get_last_off_body()
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00003176 }
Pavel Grafovf45034a2021-05-12 22:35:45 +01003177
3178 /// Load descriptor of a key by key id
3179 pub fn load_key_descriptor(&mut self, key_id: i64) -> Result<Option<KeyDescriptor>> {
3180 let _wp = wd::watch_millis("KeystoreDB::load_key_descriptor", 500);
3181
3182 self.with_transaction(TransactionBehavior::Deferred, |tx| {
3183 tx.query_row(
3184 "SELECT domain, namespace, alias FROM persistent.keyentry WHERE id = ?;",
3185 params![key_id],
3186 |row| {
3187 Ok(KeyDescriptor {
3188 domain: Domain(row.get(0)?),
3189 nspace: row.get(1)?,
3190 alias: row.get(2)?,
3191 blob: None,
3192 })
3193 },
3194 )
3195 .optional()
3196 .context("Trying to load key descriptor")
3197 .no_gc()
3198 })
3199 .context("In load_key_descriptor.")
3200 }
Joel Galenson26f4d012020-07-17 14:57:21 -07003201}
3202
3203#[cfg(test)]
3204mod tests {
3205
3206 use super::*;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07003207 use crate::key_parameter::{
3208 Algorithm, BlockMode, Digest, EcCurve, HardwareAuthenticatorType, KeyOrigin, KeyParameter,
3209 KeyParameterValue, KeyPurpose, PaddingMode, SecurityLevel,
3210 };
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003211 use crate::key_perm_set;
3212 use crate::permission::{KeyPerm, KeyPermSet};
Hasini Gunasingheda895552021-01-27 19:34:37 +00003213 use crate::super_key::SuperKeyManager;
Janis Danisevskis2a8330a2021-01-20 15:34:26 -08003214 use keystore2_test_utils::TempDir;
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00003215 use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
3216 HardwareAuthToken::HardwareAuthToken,
3217 HardwareAuthenticatorType::HardwareAuthenticatorType as kmhw_authenticator_type,
Janis Danisevskisc3a496b2021-01-05 10:37:22 -08003218 };
3219 use android_hardware_security_secureclock::aidl::android::hardware::security::secureclock::{
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00003220 Timestamp::Timestamp,
3221 };
Seth Moore472fcbb2021-05-12 10:07:51 -07003222 use rusqlite::DatabaseName::Attached;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003223 use rusqlite::NO_PARAMS;
Matthew Maurerd7815ca2021-05-06 21:58:45 -07003224 use rusqlite::TransactionBehavior;
Joel Galenson0891bc12020-07-20 10:37:03 -07003225 use std::cell::RefCell;
Seth Moore78c091f2021-04-09 21:38:30 +00003226 use std::collections::BTreeMap;
3227 use std::fmt::Write;
Janis Danisevskisaec14592020-11-12 09:41:49 -08003228 use std::sync::atomic::{AtomicU8, Ordering};
3229 use std::sync::Arc;
3230 use std::thread;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00003231 use std::time::{Duration, SystemTime};
Janis Danisevskis66784c42021-01-27 08:40:25 -08003232 #[cfg(disabled)]
3233 use std::time::Instant;
Joel Galenson0891bc12020-07-20 10:37:03 -07003234
Janis Danisevskis4df44f42020-08-26 14:40:03 -07003235 fn new_test_db() -> Result<KeystoreDB> {
Matthew Maurerd7815ca2021-05-06 21:58:45 -07003236 let conn = KeystoreDB::make_connection("file::memory:")?;
Janis Danisevskis4df44f42020-08-26 14:40:03 -07003237
Matthew Maurerd7815ca2021-05-06 21:58:45 -07003238 let mut db = KeystoreDB { conn, gc: None, perboot: Arc::new(perboot::PerbootDB::new()) };
Janis Danisevskis66784c42021-01-27 08:40:25 -08003239 db.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003240 KeystoreDB::init_tables(tx).context("Failed to initialize tables.").no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08003241 })?;
3242 Ok(db)
Janis Danisevskis4df44f42020-08-26 14:40:03 -07003243 }
3244
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003245 fn new_test_db_with_gc<F>(path: &Path, cb: F) -> Result<KeystoreDB>
3246 where
3247 F: Fn(&Uuid, &[u8]) -> Result<()> + Send + 'static,
3248 {
Paul Crowleye8826e52021-03-31 08:33:53 -07003249 let super_key: Arc<SuperKeyManager> = Default::default();
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00003250
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003251 let gc_db = KeystoreDB::new(path, None).expect("Failed to open test gc db_connection.");
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00003252 let gc = Gc::new_init_with(Default::default(), move || (Box::new(cb), gc_db, super_key));
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003253
Janis Danisevskis3395f862021-05-06 10:54:17 -07003254 KeystoreDB::new(path, Some(Arc::new(gc)))
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003255 }
3256
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003257 fn rebind_alias(
3258 db: &mut KeystoreDB,
3259 newid: &KeyIdGuard,
3260 alias: &str,
3261 domain: Domain,
3262 namespace: i64,
3263 ) -> Result<bool> {
3264 db.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis0cabd712021-05-25 11:07:10 -07003265 KeystoreDB::rebind_alias(tx, newid, alias, &domain, &namespace, KeyType::Client).no_gc()
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003266 })
3267 .context("In rebind_alias.")
3268 }
3269
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003270 #[test]
3271 fn datetime() -> Result<()> {
3272 let conn = Connection::open_in_memory()?;
3273 conn.execute("CREATE TABLE test (ts DATETIME);", NO_PARAMS)?;
3274 let now = SystemTime::now();
3275 let duration = Duration::from_secs(1000);
3276 let then = now.checked_sub(duration).unwrap();
3277 let soon = now.checked_add(duration).unwrap();
3278 conn.execute(
3279 "INSERT INTO test (ts) VALUES (?), (?), (?);",
3280 params![DateTime::try_from(now)?, DateTime::try_from(then)?, DateTime::try_from(soon)?],
3281 )?;
3282 let mut stmt = conn.prepare("SELECT ts FROM test ORDER BY ts ASC;")?;
3283 let mut rows = stmt.query(NO_PARAMS)?;
3284 assert_eq!(DateTime::try_from(then)?, rows.next()?.unwrap().get(0)?);
3285 assert_eq!(DateTime::try_from(now)?, rows.next()?.unwrap().get(0)?);
3286 assert_eq!(DateTime::try_from(soon)?, rows.next()?.unwrap().get(0)?);
3287 assert!(rows.next()?.is_none());
3288 assert!(DateTime::try_from(then)? < DateTime::try_from(now)?);
3289 assert!(DateTime::try_from(then)? < DateTime::try_from(soon)?);
3290 assert!(DateTime::try_from(now)? < DateTime::try_from(soon)?);
3291 Ok(())
3292 }
3293
Joel Galenson0891bc12020-07-20 10:37:03 -07003294 // Ensure that we're using the "injected" random function, not the real one.
3295 #[test]
3296 fn test_mocked_random() {
3297 let rand1 = random();
3298 let rand2 = random();
3299 let rand3 = random();
3300 if rand1 == rand2 {
3301 assert_eq!(rand2 + 1, rand3);
3302 } else {
3303 assert_eq!(rand1 + 1, rand2);
3304 assert_eq!(rand2, rand3);
3305 }
3306 }
Joel Galenson26f4d012020-07-17 14:57:21 -07003307
Joel Galenson26f4d012020-07-17 14:57:21 -07003308 // Test that we have the correct tables.
3309 #[test]
3310 fn test_tables() -> Result<()> {
Janis Danisevskis4df44f42020-08-26 14:40:03 -07003311 let db = new_test_db()?;
Joel Galenson26f4d012020-07-17 14:57:21 -07003312 let tables = db
3313 .conn
Joel Galenson2aab4432020-07-22 15:27:57 -07003314 .prepare("SELECT name from persistent.sqlite_master WHERE type='table' ORDER BY name;")?
Joel Galenson26f4d012020-07-17 14:57:21 -07003315 .query_map(params![], |row| row.get(0))?
3316 .collect::<rusqlite::Result<Vec<String>>>()?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003317 assert_eq!(tables.len(), 6);
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003318 assert_eq!(tables[0], "blobentry");
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003319 assert_eq!(tables[1], "blobmetadata");
3320 assert_eq!(tables[2], "grant");
3321 assert_eq!(tables[3], "keyentry");
3322 assert_eq!(tables[4], "keymetadata");
3323 assert_eq!(tables[5], "keyparameter");
Joel Galenson2aab4432020-07-22 15:27:57 -07003324 Ok(())
3325 }
3326
3327 #[test]
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00003328 fn test_auth_token_table_invariant() -> Result<()> {
3329 let mut db = new_test_db()?;
3330 let auth_token1 = HardwareAuthToken {
3331 challenge: i64::MAX,
3332 userId: 200,
3333 authenticatorId: 200,
3334 authenticatorType: kmhw_authenticator_type(kmhw_authenticator_type::PASSWORD.0),
3335 timestamp: Timestamp { milliSeconds: 500 },
3336 mac: String::from("mac").into_bytes(),
3337 };
Matthew Maurerd7815ca2021-05-06 21:58:45 -07003338 db.insert_auth_token(&auth_token1);
3339 let auth_tokens_returned = get_auth_tokens(&db);
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00003340 assert_eq!(auth_tokens_returned.len(), 1);
3341
3342 // insert another auth token with the same values for the columns in the UNIQUE constraint
3343 // of the auth token table and different value for timestamp
3344 let auth_token2 = HardwareAuthToken {
3345 challenge: i64::MAX,
3346 userId: 200,
3347 authenticatorId: 200,
3348 authenticatorType: kmhw_authenticator_type(kmhw_authenticator_type::PASSWORD.0),
3349 timestamp: Timestamp { milliSeconds: 600 },
3350 mac: String::from("mac").into_bytes(),
3351 };
3352
Matthew Maurerd7815ca2021-05-06 21:58:45 -07003353 db.insert_auth_token(&auth_token2);
3354 let mut auth_tokens_returned = get_auth_tokens(&db);
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00003355 assert_eq!(auth_tokens_returned.len(), 1);
3356
3357 if let Some(auth_token) = auth_tokens_returned.pop() {
3358 assert_eq!(auth_token.auth_token.timestamp.milliSeconds, 600);
3359 }
3360
3361 // insert another auth token with the different values for the columns in the UNIQUE
3362 // constraint of the auth token table
3363 let auth_token3 = HardwareAuthToken {
3364 challenge: i64::MAX,
3365 userId: 201,
3366 authenticatorId: 200,
3367 authenticatorType: kmhw_authenticator_type(kmhw_authenticator_type::PASSWORD.0),
3368 timestamp: Timestamp { milliSeconds: 600 },
3369 mac: String::from("mac").into_bytes(),
3370 };
3371
Matthew Maurerd7815ca2021-05-06 21:58:45 -07003372 db.insert_auth_token(&auth_token3);
3373 let auth_tokens_returned = get_auth_tokens(&db);
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00003374 assert_eq!(auth_tokens_returned.len(), 2);
3375
3376 Ok(())
3377 }
3378
3379 // utility function for test_auth_token_table_invariant()
Matthew Maurerd7815ca2021-05-06 21:58:45 -07003380 fn get_auth_tokens(db: &KeystoreDB) -> Vec<AuthTokenEntry> {
3381 db.perboot.get_all_auth_token_entries()
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00003382 }
3383
3384 #[test]
Joel Galenson2aab4432020-07-22 15:27:57 -07003385 fn test_persistence_for_files() -> Result<()> {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08003386 let temp_dir = TempDir::new("persistent_db_test")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003387 let mut db = KeystoreDB::new(temp_dir.path(), None)?;
Joel Galenson2aab4432020-07-22 15:27:57 -07003388
Janis Danisevskis0cabd712021-05-25 11:07:10 -07003389 db.create_key_entry(&Domain::APP, &100, KeyType::Client, &KEYSTORE_UUID)?;
Joel Galenson2aab4432020-07-22 15:27:57 -07003390 let entries = get_keyentry(&db)?;
3391 assert_eq!(entries.len(), 1);
Janis Danisevskisbf15d732020-12-08 10:35:26 -08003392
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003393 let db = KeystoreDB::new(temp_dir.path(), None)?;
Joel Galenson2aab4432020-07-22 15:27:57 -07003394
3395 let entries_new = get_keyentry(&db)?;
3396 assert_eq!(entries, entries_new);
3397 Ok(())
3398 }
3399
3400 #[test]
Joel Galenson0891bc12020-07-20 10:37:03 -07003401 fn test_create_key_entry() -> Result<()> {
Max Bires8e93d2b2021-01-14 13:17:59 -08003402 fn extractor(ke: &KeyEntryRow) -> (Domain, i64, Option<&str>, Uuid) {
3403 (ke.domain.unwrap(), ke.namespace.unwrap(), ke.alias.as_deref(), ke.km_uuid.unwrap())
Joel Galenson0891bc12020-07-20 10:37:03 -07003404 }
3405
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003406 let mut db = new_test_db()?;
Joel Galenson0891bc12020-07-20 10:37:03 -07003407
Janis Danisevskis0cabd712021-05-25 11:07:10 -07003408 db.create_key_entry(&Domain::APP, &100, KeyType::Client, &KEYSTORE_UUID)?;
3409 db.create_key_entry(&Domain::SELINUX, &101, KeyType::Client, &KEYSTORE_UUID)?;
Joel Galenson0891bc12020-07-20 10:37:03 -07003410
3411 let entries = get_keyentry(&db)?;
3412 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08003413 assert_eq!(extractor(&entries[0]), (Domain::APP, 100, None, KEYSTORE_UUID));
3414 assert_eq!(extractor(&entries[1]), (Domain::SELINUX, 101, None, KEYSTORE_UUID));
Joel Galenson0891bc12020-07-20 10:37:03 -07003415
3416 // Test that we must pass in a valid Domain.
3417 check_result_is_error_containing_string(
Janis Danisevskis0cabd712021-05-25 11:07:10 -07003418 db.create_key_entry(&Domain::GRANT, &102, KeyType::Client, &KEYSTORE_UUID),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003419 "Domain Domain(1) must be either App or SELinux.",
Joel Galenson0891bc12020-07-20 10:37:03 -07003420 );
3421 check_result_is_error_containing_string(
Janis Danisevskis0cabd712021-05-25 11:07:10 -07003422 db.create_key_entry(&Domain::BLOB, &103, KeyType::Client, &KEYSTORE_UUID),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003423 "Domain Domain(3) must be either App or SELinux.",
Joel Galenson0891bc12020-07-20 10:37:03 -07003424 );
3425 check_result_is_error_containing_string(
Janis Danisevskis0cabd712021-05-25 11:07:10 -07003426 db.create_key_entry(&Domain::KEY_ID, &104, KeyType::Client, &KEYSTORE_UUID),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003427 "Domain Domain(4) must be either App or SELinux.",
Joel Galenson0891bc12020-07-20 10:37:03 -07003428 );
3429
3430 Ok(())
3431 }
3432
Joel Galenson33c04ad2020-08-03 11:04:38 -07003433 #[test]
Max Bires2b2e6562020-09-22 11:22:36 -07003434 fn test_add_unsigned_key() -> Result<()> {
3435 let mut db = new_test_db()?;
3436 let public_key: Vec<u8> = vec![0x01, 0x02, 0x03];
3437 let private_key: Vec<u8> = vec![0x04, 0x05, 0x06];
3438 let raw_public_key: Vec<u8> = vec![0x07, 0x08, 0x09];
3439 db.create_attestation_key_entry(
3440 &public_key,
3441 &raw_public_key,
3442 &private_key,
3443 &KEYSTORE_UUID,
3444 )?;
3445 let keys = db.fetch_unsigned_attestation_keys(5, &KEYSTORE_UUID)?;
3446 assert_eq!(keys.len(), 1);
3447 assert_eq!(keys[0], public_key);
3448 Ok(())
3449 }
3450
3451 #[test]
3452 fn test_store_signed_attestation_certificate_chain() -> Result<()> {
3453 let mut db = new_test_db()?;
3454 let expiration_date: i64 = 20;
3455 let namespace: i64 = 30;
3456 let base_byte: u8 = 1;
3457 let loaded_values =
3458 load_attestation_key_pool(&mut db, expiration_date, namespace, base_byte)?;
3459 let chain =
3460 db.retrieve_attestation_key_and_cert_chain(Domain::APP, namespace, &KEYSTORE_UUID)?;
3461 assert_eq!(true, chain.is_some());
3462 let cert_chain = chain.unwrap();
Max Biresb2e1d032021-02-08 21:35:05 -08003463 assert_eq!(cert_chain.private_key.to_vec(), loaded_values.priv_key);
Max Bires97f96812021-02-23 23:44:57 -08003464 assert_eq!(cert_chain.batch_cert, loaded_values.batch_cert);
3465 assert_eq!(cert_chain.cert_chain, loaded_values.cert_chain);
Max Bires2b2e6562020-09-22 11:22:36 -07003466 Ok(())
3467 }
3468
3469 #[test]
3470 fn test_get_attestation_pool_status() -> Result<()> {
3471 let mut db = new_test_db()?;
3472 let namespace: i64 = 30;
3473 load_attestation_key_pool(
3474 &mut db, 10, /* expiration */
3475 namespace, 0x01, /* base_byte */
3476 )?;
3477 load_attestation_key_pool(&mut db, 20 /* expiration */, namespace + 1, 0x02)?;
3478 load_attestation_key_pool(&mut db, 40 /* expiration */, namespace + 2, 0x03)?;
3479 let mut status = db.get_attestation_pool_status(9 /* expiration */, &KEYSTORE_UUID)?;
3480 assert_eq!(status.expiring, 0);
3481 assert_eq!(status.attested, 3);
3482 assert_eq!(status.unassigned, 0);
3483 assert_eq!(status.total, 3);
3484 assert_eq!(
3485 db.get_attestation_pool_status(15 /* expiration */, &KEYSTORE_UUID)?.expiring,
3486 1
3487 );
3488 assert_eq!(
3489 db.get_attestation_pool_status(25 /* expiration */, &KEYSTORE_UUID)?.expiring,
3490 2
3491 );
3492 assert_eq!(
3493 db.get_attestation_pool_status(60 /* expiration */, &KEYSTORE_UUID)?.expiring,
3494 3
3495 );
3496 let public_key: Vec<u8> = vec![0x01, 0x02, 0x03];
3497 let private_key: Vec<u8> = vec![0x04, 0x05, 0x06];
3498 let raw_public_key: Vec<u8> = vec![0x07, 0x08, 0x09];
3499 let cert_chain: Vec<u8> = vec![0x0a, 0x0b, 0x0c];
Max Biresb2e1d032021-02-08 21:35:05 -08003500 let batch_cert: Vec<u8> = vec![0x0d, 0x0e, 0x0f];
Max Bires2b2e6562020-09-22 11:22:36 -07003501 db.create_attestation_key_entry(
3502 &public_key,
3503 &raw_public_key,
3504 &private_key,
3505 &KEYSTORE_UUID,
3506 )?;
3507 status = db.get_attestation_pool_status(0 /* expiration */, &KEYSTORE_UUID)?;
3508 assert_eq!(status.attested, 3);
3509 assert_eq!(status.unassigned, 0);
3510 assert_eq!(status.total, 4);
3511 db.store_signed_attestation_certificate_chain(
3512 &raw_public_key,
Max Biresb2e1d032021-02-08 21:35:05 -08003513 &batch_cert,
Max Bires2b2e6562020-09-22 11:22:36 -07003514 &cert_chain,
3515 20,
3516 &KEYSTORE_UUID,
3517 )?;
3518 status = db.get_attestation_pool_status(0 /* expiration */, &KEYSTORE_UUID)?;
3519 assert_eq!(status.attested, 4);
3520 assert_eq!(status.unassigned, 1);
3521 assert_eq!(status.total, 4);
3522 Ok(())
3523 }
3524
3525 #[test]
3526 fn test_remove_expired_certs() -> Result<()> {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003527 let temp_dir =
3528 TempDir::new("test_remove_expired_certs_").expect("Failed to create temp dir.");
3529 let mut db = new_test_db_with_gc(temp_dir.path(), |_, _| Ok(()))?;
Max Bires2b2e6562020-09-22 11:22:36 -07003530 let expiration_date: i64 =
3531 SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_millis() as i64 + 10000;
3532 let namespace: i64 = 30;
3533 let namespace_del1: i64 = 45;
3534 let namespace_del2: i64 = 60;
3535 let entry_values = load_attestation_key_pool(
3536 &mut db,
3537 expiration_date,
3538 namespace,
3539 0x01, /* base_byte */
3540 )?;
3541 load_attestation_key_pool(&mut db, 45, namespace_del1, 0x02)?;
3542 load_attestation_key_pool(&mut db, 60, namespace_del2, 0x03)?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003543
3544 let blob_entry_row_count: u32 = db
3545 .conn
3546 .query_row("SELECT COUNT(id) FROM persistent.blobentry;", NO_PARAMS, |row| row.get(0))
3547 .expect("Failed to get blob entry row count.");
Max Biresb2e1d032021-02-08 21:35:05 -08003548 // We expect 9 rows here because there are three blobs per attestation key, i.e.,
3549 // one key, one certificate chain, and one certificate.
3550 assert_eq!(blob_entry_row_count, 9);
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003551
Max Bires2b2e6562020-09-22 11:22:36 -07003552 assert_eq!(db.delete_expired_attestation_keys()?, 2);
3553
3554 let mut cert_chain =
3555 db.retrieve_attestation_key_and_cert_chain(Domain::APP, namespace, &KEYSTORE_UUID)?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003556 assert!(cert_chain.is_some());
Max Bires2b2e6562020-09-22 11:22:36 -07003557 let value = cert_chain.unwrap();
Max Bires97f96812021-02-23 23:44:57 -08003558 assert_eq!(entry_values.batch_cert, value.batch_cert);
3559 assert_eq!(entry_values.cert_chain, value.cert_chain);
Max Biresb2e1d032021-02-08 21:35:05 -08003560 assert_eq!(entry_values.priv_key, value.private_key.to_vec());
Max Bires2b2e6562020-09-22 11:22:36 -07003561
3562 cert_chain = db.retrieve_attestation_key_and_cert_chain(
3563 Domain::APP,
3564 namespace_del1,
3565 &KEYSTORE_UUID,
3566 )?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003567 assert!(!cert_chain.is_some());
Max Bires2b2e6562020-09-22 11:22:36 -07003568 cert_chain = db.retrieve_attestation_key_and_cert_chain(
3569 Domain::APP,
3570 namespace_del2,
3571 &KEYSTORE_UUID,
3572 )?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003573 assert!(!cert_chain.is_some());
Max Bires2b2e6562020-09-22 11:22:36 -07003574
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003575 // Give the garbage collector half a second to catch up.
3576 std::thread::sleep(Duration::from_millis(500));
Max Bires2b2e6562020-09-22 11:22:36 -07003577
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003578 let blob_entry_row_count: u32 = db
3579 .conn
3580 .query_row("SELECT COUNT(id) FROM persistent.blobentry;", NO_PARAMS, |row| row.get(0))
3581 .expect("Failed to get blob entry row count.");
Max Biresb2e1d032021-02-08 21:35:05 -08003582 // There shound be 3 blob entries left, because we deleted two of the attestation
3583 // key entries with three blobs each.
3584 assert_eq!(blob_entry_row_count, 3);
Max Bires2b2e6562020-09-22 11:22:36 -07003585
Max Bires2b2e6562020-09-22 11:22:36 -07003586 Ok(())
3587 }
3588
3589 #[test]
Max Bires60d7ed12021-03-05 15:59:22 -08003590 fn test_delete_all_attestation_keys() -> Result<()> {
3591 let mut db = new_test_db()?;
3592 load_attestation_key_pool(&mut db, 45 /* expiration */, 1 /* namespace */, 0x02)?;
3593 load_attestation_key_pool(&mut db, 80 /* expiration */, 2 /* namespace */, 0x03)?;
Janis Danisevskis0cabd712021-05-25 11:07:10 -07003594 db.create_key_entry(&Domain::APP, &42, KeyType::Client, &KEYSTORE_UUID)?;
Max Bires60d7ed12021-03-05 15:59:22 -08003595 let result = db.delete_all_attestation_keys()?;
3596
3597 // Give the garbage collector half a second to catch up.
3598 std::thread::sleep(Duration::from_millis(500));
3599
3600 // Attestation keys should be deleted, and the regular key should remain.
3601 assert_eq!(result, 2);
3602
3603 Ok(())
3604 }
3605
3606 #[test]
Joel Galenson33c04ad2020-08-03 11:04:38 -07003607 fn test_rebind_alias() -> Result<()> {
Max Bires8e93d2b2021-01-14 13:17:59 -08003608 fn extractor(
3609 ke: &KeyEntryRow,
3610 ) -> (Option<Domain>, Option<i64>, Option<&str>, Option<Uuid>) {
3611 (ke.domain, ke.namespace, ke.alias.as_deref(), ke.km_uuid)
Joel Galenson33c04ad2020-08-03 11:04:38 -07003612 }
3613
Janis Danisevskis4df44f42020-08-26 14:40:03 -07003614 let mut db = new_test_db()?;
Janis Danisevskis0cabd712021-05-25 11:07:10 -07003615 db.create_key_entry(&Domain::APP, &42, KeyType::Client, &KEYSTORE_UUID)?;
3616 db.create_key_entry(&Domain::APP, &42, KeyType::Client, &KEYSTORE_UUID)?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07003617 let entries = get_keyentry(&db)?;
3618 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08003619 assert_eq!(
3620 extractor(&entries[0]),
3621 (Some(Domain::APP), Some(42), None, Some(KEYSTORE_UUID))
3622 );
3623 assert_eq!(
3624 extractor(&entries[1]),
3625 (Some(Domain::APP), Some(42), None, Some(KEYSTORE_UUID))
3626 );
Joel Galenson33c04ad2020-08-03 11:04:38 -07003627
3628 // Test that the first call to rebind_alias sets the alias.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003629 rebind_alias(&mut db, &KEY_ID_LOCK.get(entries[0].id), "foo", Domain::APP, 42)?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07003630 let entries = get_keyentry(&db)?;
3631 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08003632 assert_eq!(
3633 extractor(&entries[0]),
3634 (Some(Domain::APP), Some(42), Some("foo"), Some(KEYSTORE_UUID))
3635 );
3636 assert_eq!(
3637 extractor(&entries[1]),
3638 (Some(Domain::APP), Some(42), None, Some(KEYSTORE_UUID))
3639 );
Joel Galenson33c04ad2020-08-03 11:04:38 -07003640
3641 // Test that the second call to rebind_alias also empties the old one.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003642 rebind_alias(&mut db, &KEY_ID_LOCK.get(entries[1].id), "foo", Domain::APP, 42)?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07003643 let entries = get_keyentry(&db)?;
3644 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08003645 assert_eq!(extractor(&entries[0]), (None, None, None, Some(KEYSTORE_UUID)));
3646 assert_eq!(
3647 extractor(&entries[1]),
3648 (Some(Domain::APP), Some(42), Some("foo"), Some(KEYSTORE_UUID))
3649 );
Joel Galenson33c04ad2020-08-03 11:04:38 -07003650
3651 // Test that we must pass in a valid Domain.
3652 check_result_is_error_containing_string(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003653 rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::GRANT, 42),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003654 "Domain Domain(1) must be either App or SELinux.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07003655 );
3656 check_result_is_error_containing_string(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003657 rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::BLOB, 42),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003658 "Domain Domain(3) must be either App or SELinux.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07003659 );
3660 check_result_is_error_containing_string(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003661 rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::KEY_ID, 42),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003662 "Domain Domain(4) must be either App or SELinux.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07003663 );
3664
3665 // Test that we correctly handle setting an alias for something that does not exist.
3666 check_result_is_error_containing_string(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003667 rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::SELINUX, 42),
Joel Galenson33c04ad2020-08-03 11:04:38 -07003668 "Expected to update a single entry but instead updated 0",
3669 );
3670 // Test that we correctly abort the transaction in this case.
3671 let entries = get_keyentry(&db)?;
3672 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08003673 assert_eq!(extractor(&entries[0]), (None, None, None, Some(KEYSTORE_UUID)));
3674 assert_eq!(
3675 extractor(&entries[1]),
3676 (Some(Domain::APP), Some(42), Some("foo"), Some(KEYSTORE_UUID))
3677 );
Joel Galenson33c04ad2020-08-03 11:04:38 -07003678
3679 Ok(())
3680 }
3681
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003682 #[test]
3683 fn test_grant_ungrant() -> Result<()> {
3684 const CALLER_UID: u32 = 15;
3685 const GRANTEE_UID: u32 = 12;
3686 const SELINUX_NAMESPACE: i64 = 7;
3687
3688 let mut db = new_test_db()?;
3689 db.conn.execute(
Max Bires8e93d2b2021-01-14 13:17:59 -08003690 "INSERT INTO persistent.keyentry (id, key_type, domain, namespace, alias, state, km_uuid)
3691 VALUES (1, 0, 0, 15, 'key', 1, ?), (2, 0, 2, 7, 'yek', 1, ?);",
3692 params![KEYSTORE_UUID, KEYSTORE_UUID],
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003693 )?;
3694 let app_key = KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003695 domain: super::Domain::APP,
3696 nspace: 0,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003697 alias: Some("key".to_string()),
3698 blob: None,
3699 };
3700 const PVEC1: KeyPermSet = key_perm_set![KeyPerm::use_(), KeyPerm::get_info()];
3701 const PVEC2: KeyPermSet = key_perm_set![KeyPerm::use_()];
3702
3703 // Reset totally predictable random number generator in case we
3704 // are not the first test running on this thread.
3705 reset_random();
3706 let next_random = 0i64;
3707
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003708 let app_granted_key = db
Janis Danisevskis66784c42021-01-27 08:40:25 -08003709 .grant(&app_key, CALLER_UID, GRANTEE_UID, PVEC1, |k, a| {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003710 assert_eq!(*a, PVEC1);
3711 assert_eq!(
3712 *k,
3713 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003714 domain: super::Domain::APP,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003715 // namespace must be set to the caller_uid.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003716 nspace: CALLER_UID as i64,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003717 alias: Some("key".to_string()),
3718 blob: None,
3719 }
3720 );
3721 Ok(())
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003722 })
3723 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003724
3725 assert_eq!(
3726 app_granted_key,
3727 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003728 domain: super::Domain::GRANT,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003729 // The grantid is next_random due to the mock random number generator.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003730 nspace: next_random,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003731 alias: None,
3732 blob: None,
3733 }
3734 );
3735
3736 let selinux_key = KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003737 domain: super::Domain::SELINUX,
3738 nspace: SELINUX_NAMESPACE,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003739 alias: Some("yek".to_string()),
3740 blob: None,
3741 };
3742
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003743 let selinux_granted_key = db
Janis Danisevskis66784c42021-01-27 08:40:25 -08003744 .grant(&selinux_key, CALLER_UID, 12, PVEC1, |k, a| {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003745 assert_eq!(*a, PVEC1);
3746 assert_eq!(
3747 *k,
3748 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003749 domain: super::Domain::SELINUX,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003750 // namespace must be the supplied SELinux
3751 // namespace.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003752 nspace: SELINUX_NAMESPACE,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003753 alias: Some("yek".to_string()),
3754 blob: None,
3755 }
3756 );
3757 Ok(())
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003758 })
3759 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003760
3761 assert_eq!(
3762 selinux_granted_key,
3763 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003764 domain: super::Domain::GRANT,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003765 // The grantid is next_random + 1 due to the mock random number generator.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003766 nspace: next_random + 1,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003767 alias: None,
3768 blob: None,
3769 }
3770 );
3771
3772 // This should update the existing grant with PVEC2.
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003773 let selinux_granted_key = db
Janis Danisevskis66784c42021-01-27 08:40:25 -08003774 .grant(&selinux_key, CALLER_UID, 12, PVEC2, |k, a| {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003775 assert_eq!(*a, PVEC2);
3776 assert_eq!(
3777 *k,
3778 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003779 domain: super::Domain::SELINUX,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003780 // namespace must be the supplied SELinux
3781 // namespace.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003782 nspace: SELINUX_NAMESPACE,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003783 alias: Some("yek".to_string()),
3784 blob: None,
3785 }
3786 );
3787 Ok(())
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003788 })
3789 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003790
3791 assert_eq!(
3792 selinux_granted_key,
3793 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003794 domain: super::Domain::GRANT,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003795 // Same grant id as before. The entry was only updated.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003796 nspace: next_random + 1,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003797 alias: None,
3798 blob: None,
3799 }
3800 );
3801
3802 {
3803 // Limiting scope of stmt, because it borrows db.
3804 let mut stmt = db
3805 .conn
Janis Danisevskisbf15d732020-12-08 10:35:26 -08003806 .prepare("SELECT id, grantee, keyentryid, access_vector FROM persistent.grant;")?;
Janis Danisevskisee10b5f2020-09-22 16:42:35 -07003807 let mut rows =
3808 stmt.query_map::<(i64, u32, i64, KeyPermSet), _, _>(NO_PARAMS, |row| {
3809 Ok((
3810 row.get(0)?,
3811 row.get(1)?,
3812 row.get(2)?,
3813 KeyPermSet::from(row.get::<_, i32>(3)?),
3814 ))
3815 })?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003816
3817 let r = rows.next().unwrap().unwrap();
Janis Danisevskisee10b5f2020-09-22 16:42:35 -07003818 assert_eq!(r, (next_random, GRANTEE_UID, 1, PVEC1));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003819 let r = rows.next().unwrap().unwrap();
Janis Danisevskisee10b5f2020-09-22 16:42:35 -07003820 assert_eq!(r, (next_random + 1, GRANTEE_UID, 2, PVEC2));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003821 assert!(rows.next().is_none());
3822 }
3823
3824 debug_dump_keyentry_table(&mut db)?;
3825 println!("app_key {:?}", app_key);
3826 println!("selinux_key {:?}", selinux_key);
3827
Janis Danisevskis66784c42021-01-27 08:40:25 -08003828 db.ungrant(&app_key, CALLER_UID, GRANTEE_UID, |_| Ok(()))?;
3829 db.ungrant(&selinux_key, CALLER_UID, GRANTEE_UID, |_| Ok(()))?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003830
3831 Ok(())
3832 }
3833
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003834 static TEST_KEY_BLOB: &[u8] = b"my test blob";
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003835 static TEST_CERT_BLOB: &[u8] = b"my test cert";
3836 static TEST_CERT_CHAIN_BLOB: &[u8] = b"my test cert_chain";
3837
3838 #[test]
Janis Danisevskis377d1002021-01-27 19:07:48 -08003839 fn test_set_blob() -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003840 let key_id = KEY_ID_LOCK.get(3000);
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003841 let mut db = new_test_db()?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003842 let mut blob_metadata = BlobMetaData::new();
3843 blob_metadata.add(BlobMetaEntry::KmUuid(KEYSTORE_UUID));
3844 db.set_blob(
3845 &key_id,
3846 SubComponentType::KEY_BLOB,
3847 Some(TEST_KEY_BLOB),
3848 Some(&blob_metadata),
3849 )?;
3850 db.set_blob(&key_id, SubComponentType::CERT, Some(TEST_CERT_BLOB), None)?;
3851 db.set_blob(&key_id, SubComponentType::CERT_CHAIN, Some(TEST_CERT_CHAIN_BLOB), None)?;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003852 drop(key_id);
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003853
3854 let mut stmt = db.conn.prepare(
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003855 "SELECT subcomponent_type, keyentryid, blob, id FROM persistent.blobentry
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003856 ORDER BY subcomponent_type ASC;",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003857 )?;
3858 let mut rows = stmt
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003859 .query_map::<((SubComponentType, i64, Vec<u8>), i64), _, _>(NO_PARAMS, |row| {
3860 Ok(((row.get(0)?, row.get(1)?, row.get(2)?), row.get(3)?))
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003861 })?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003862 let (r, id) = rows.next().unwrap().unwrap();
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003863 assert_eq!(r, (SubComponentType::KEY_BLOB, 3000, TEST_KEY_BLOB.to_vec()));
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003864 let (r, _) = rows.next().unwrap().unwrap();
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003865 assert_eq!(r, (SubComponentType::CERT, 3000, TEST_CERT_BLOB.to_vec()));
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003866 let (r, _) = rows.next().unwrap().unwrap();
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003867 assert_eq!(r, (SubComponentType::CERT_CHAIN, 3000, TEST_CERT_CHAIN_BLOB.to_vec()));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003868
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003869 drop(rows);
3870 drop(stmt);
3871
3872 assert_eq!(
3873 db.with_transaction(TransactionBehavior::Immediate, |tx| {
3874 BlobMetaData::load_from_db(id, tx).no_gc()
3875 })
3876 .expect("Should find blob metadata."),
3877 blob_metadata
3878 );
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003879 Ok(())
3880 }
3881
3882 static TEST_ALIAS: &str = "my super duper key";
3883
3884 #[test]
3885 fn test_insert_and_load_full_keyentry_domain_app() -> Result<()> {
3886 let mut db = new_test_db()?;
Qi Wub9433b52020-12-01 14:52:46 +08003887 let key_id = make_test_key_entry(&mut db, Domain::APP, 1, TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08003888 .context("test_insert_and_load_full_keyentry_domain_app")?
3889 .0;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003890 let (_key_guard, key_entry) = db
3891 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003892 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003893 domain: Domain::APP,
3894 nspace: 0,
3895 alias: Some(TEST_ALIAS.to_string()),
3896 blob: None,
3897 },
3898 KeyType::Client,
3899 KeyEntryLoadBits::BOTH,
3900 1,
3901 |_k, _av| Ok(()),
3902 )
3903 .unwrap();
Qi Wub9433b52020-12-01 14:52:46 +08003904 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003905
3906 db.unbind_key(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003907 &KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003908 domain: Domain::APP,
3909 nspace: 0,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003910 alias: Some(TEST_ALIAS.to_string()),
3911 blob: None,
3912 },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003913 KeyType::Client,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003914 1,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003915 |_, _| Ok(()),
3916 )
3917 .unwrap();
3918
3919 assert_eq!(
3920 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
3921 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003922 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003923 domain: Domain::APP,
3924 nspace: 0,
3925 alias: Some(TEST_ALIAS.to_string()),
3926 blob: None,
3927 },
3928 KeyType::Client,
3929 KeyEntryLoadBits::NONE,
3930 1,
3931 |_k, _av| Ok(()),
3932 )
3933 .unwrap_err()
3934 .root_cause()
3935 .downcast_ref::<KsError>()
3936 );
3937
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003938 Ok(())
3939 }
3940
3941 #[test]
Janis Danisevskis377d1002021-01-27 19:07:48 -08003942 fn test_insert_and_load_certificate_entry_domain_app() -> Result<()> {
3943 let mut db = new_test_db()?;
3944
3945 db.store_new_certificate(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003946 &KeyDescriptor {
Janis Danisevskis377d1002021-01-27 19:07:48 -08003947 domain: Domain::APP,
3948 nspace: 1,
3949 alias: Some(TEST_ALIAS.to_string()),
3950 blob: None,
3951 },
Janis Danisevskis0cabd712021-05-25 11:07:10 -07003952 KeyType::Client,
Janis Danisevskis377d1002021-01-27 19:07:48 -08003953 TEST_CERT_BLOB,
Max Bires8e93d2b2021-01-14 13:17:59 -08003954 &KEYSTORE_UUID,
Janis Danisevskis377d1002021-01-27 19:07:48 -08003955 )
3956 .expect("Trying to insert cert.");
3957
3958 let (_key_guard, mut key_entry) = db
3959 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003960 &KeyDescriptor {
Janis Danisevskis377d1002021-01-27 19:07:48 -08003961 domain: Domain::APP,
3962 nspace: 1,
3963 alias: Some(TEST_ALIAS.to_string()),
3964 blob: None,
3965 },
3966 KeyType::Client,
3967 KeyEntryLoadBits::PUBLIC,
3968 1,
3969 |_k, _av| Ok(()),
3970 )
3971 .expect("Trying to read certificate entry.");
3972
3973 assert!(key_entry.pure_cert());
3974 assert!(key_entry.cert().is_none());
3975 assert_eq!(key_entry.take_cert_chain(), Some(TEST_CERT_BLOB.to_vec()));
3976
3977 db.unbind_key(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003978 &KeyDescriptor {
Janis Danisevskis377d1002021-01-27 19:07:48 -08003979 domain: Domain::APP,
3980 nspace: 1,
3981 alias: Some(TEST_ALIAS.to_string()),
3982 blob: None,
3983 },
3984 KeyType::Client,
3985 1,
3986 |_, _| Ok(()),
3987 )
3988 .unwrap();
3989
3990 assert_eq!(
3991 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
3992 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003993 &KeyDescriptor {
Janis Danisevskis377d1002021-01-27 19:07:48 -08003994 domain: Domain::APP,
3995 nspace: 1,
3996 alias: Some(TEST_ALIAS.to_string()),
3997 blob: None,
3998 },
3999 KeyType::Client,
4000 KeyEntryLoadBits::NONE,
4001 1,
4002 |_k, _av| Ok(()),
4003 )
4004 .unwrap_err()
4005 .root_cause()
4006 .downcast_ref::<KsError>()
4007 );
4008
4009 Ok(())
4010 }
4011
4012 #[test]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004013 fn test_insert_and_load_full_keyentry_domain_selinux() -> Result<()> {
4014 let mut db = new_test_db()?;
Qi Wub9433b52020-12-01 14:52:46 +08004015 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08004016 .context("test_insert_and_load_full_keyentry_domain_selinux")?
4017 .0;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004018 let (_key_guard, key_entry) = db
4019 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004020 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004021 domain: Domain::SELINUX,
4022 nspace: 1,
4023 alias: Some(TEST_ALIAS.to_string()),
4024 blob: None,
4025 },
4026 KeyType::Client,
4027 KeyEntryLoadBits::BOTH,
4028 1,
4029 |_k, _av| Ok(()),
4030 )
4031 .unwrap();
Qi Wub9433b52020-12-01 14:52:46 +08004032 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004033
4034 db.unbind_key(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004035 &KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07004036 domain: Domain::SELINUX,
4037 nspace: 1,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004038 alias: Some(TEST_ALIAS.to_string()),
4039 blob: None,
4040 },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004041 KeyType::Client,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004042 1,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004043 |_, _| Ok(()),
4044 )
4045 .unwrap();
4046
4047 assert_eq!(
4048 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
4049 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004050 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004051 domain: Domain::SELINUX,
4052 nspace: 1,
4053 alias: Some(TEST_ALIAS.to_string()),
4054 blob: None,
4055 },
4056 KeyType::Client,
4057 KeyEntryLoadBits::NONE,
4058 1,
4059 |_k, _av| Ok(()),
4060 )
4061 .unwrap_err()
4062 .root_cause()
4063 .downcast_ref::<KsError>()
4064 );
4065
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004066 Ok(())
4067 }
4068
4069 #[test]
4070 fn test_insert_and_load_full_keyentry_domain_key_id() -> Result<()> {
4071 let mut db = new_test_db()?;
Qi Wub9433b52020-12-01 14:52:46 +08004072 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08004073 .context("test_insert_and_load_full_keyentry_domain_key_id")?
4074 .0;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004075 let (_, key_entry) = db
4076 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004077 &KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004078 KeyType::Client,
4079 KeyEntryLoadBits::BOTH,
4080 1,
4081 |_k, _av| Ok(()),
4082 )
4083 .unwrap();
4084
Qi Wub9433b52020-12-01 14:52:46 +08004085 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004086
4087 db.unbind_key(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004088 &KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004089 KeyType::Client,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004090 1,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004091 |_, _| Ok(()),
4092 )
4093 .unwrap();
4094
4095 assert_eq!(
4096 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
4097 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004098 &KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004099 KeyType::Client,
4100 KeyEntryLoadBits::NONE,
4101 1,
4102 |_k, _av| Ok(()),
4103 )
4104 .unwrap_err()
4105 .root_cause()
4106 .downcast_ref::<KsError>()
4107 );
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004108
4109 Ok(())
4110 }
4111
4112 #[test]
Qi Wub9433b52020-12-01 14:52:46 +08004113 fn test_check_and_update_key_usage_count_with_limited_use_key() -> Result<()> {
4114 let mut db = new_test_db()?;
4115 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, Some(123))
4116 .context("test_check_and_update_key_usage_count_with_limited_use_key")?
4117 .0;
4118 // Update the usage count of the limited use key.
4119 db.check_and_update_key_usage_count(key_id)?;
4120
4121 let (_key_guard, key_entry) = db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004122 &KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
Qi Wub9433b52020-12-01 14:52:46 +08004123 KeyType::Client,
4124 KeyEntryLoadBits::BOTH,
4125 1,
4126 |_k, _av| Ok(()),
4127 )?;
4128
4129 // The usage count is decremented now.
4130 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, Some(122)));
4131
4132 Ok(())
4133 }
4134
4135 #[test]
4136 fn test_check_and_update_key_usage_count_with_exhausted_limited_use_key() -> Result<()> {
4137 let mut db = new_test_db()?;
4138 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, Some(1))
4139 .context("test_check_and_update_key_usage_count_with_exhausted_limited_use_key")?
4140 .0;
4141 // Update the usage count of the limited use key.
4142 db.check_and_update_key_usage_count(key_id).expect(concat!(
4143 "In test_check_and_update_key_usage_count_with_exhausted_limited_use_key: ",
4144 "This should succeed."
4145 ));
4146
4147 // Try to update the exhausted limited use key.
4148 let e = db.check_and_update_key_usage_count(key_id).expect_err(concat!(
4149 "In test_check_and_update_key_usage_count_with_exhausted_limited_use_key: ",
4150 "This should fail."
4151 ));
4152 assert_eq!(
4153 &KsError::Km(ErrorCode::INVALID_KEY_BLOB),
4154 e.root_cause().downcast_ref::<KsError>().unwrap()
4155 );
4156
4157 Ok(())
4158 }
4159
4160 #[test]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004161 fn test_insert_and_load_full_keyentry_from_grant() -> Result<()> {
4162 let mut db = new_test_db()?;
Qi Wub9433b52020-12-01 14:52:46 +08004163 let key_id = make_test_key_entry(&mut db, Domain::APP, 1, TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08004164 .context("test_insert_and_load_full_keyentry_from_grant")?
4165 .0;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004166
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004167 let granted_key = db
4168 .grant(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004169 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004170 domain: Domain::APP,
4171 nspace: 0,
4172 alias: Some(TEST_ALIAS.to_string()),
4173 blob: None,
4174 },
4175 1,
4176 2,
4177 key_perm_set![KeyPerm::use_()],
4178 |_k, _av| Ok(()),
4179 )
4180 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004181
4182 debug_dump_grant_table(&mut db)?;
4183
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004184 let (_key_guard, key_entry) = db
Janis Danisevskis66784c42021-01-27 08:40:25 -08004185 .load_key_entry(&granted_key, KeyType::Client, KeyEntryLoadBits::BOTH, 2, |k, av| {
4186 assert_eq!(Domain::GRANT, k.domain);
4187 assert!(av.unwrap().includes(KeyPerm::use_()));
4188 Ok(())
4189 })
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004190 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004191
Qi Wub9433b52020-12-01 14:52:46 +08004192 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004193
Janis Danisevskis66784c42021-01-27 08:40:25 -08004194 db.unbind_key(&granted_key, KeyType::Client, 2, |_, _| Ok(())).unwrap();
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004195
4196 assert_eq!(
4197 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
4198 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004199 &granted_key,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004200 KeyType::Client,
4201 KeyEntryLoadBits::NONE,
4202 2,
4203 |_k, _av| Ok(()),
4204 )
4205 .unwrap_err()
4206 .root_cause()
4207 .downcast_ref::<KsError>()
4208 );
4209
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004210 Ok(())
4211 }
4212
Janis Danisevskis45760022021-01-19 16:34:10 -08004213 // This test attempts to load a key by key id while the caller is not the owner
4214 // but a grant exists for the given key and the caller.
4215 #[test]
4216 fn test_insert_and_load_full_keyentry_from_grant_by_key_id() -> Result<()> {
4217 let mut db = new_test_db()?;
4218 const OWNER_UID: u32 = 1u32;
4219 const GRANTEE_UID: u32 = 2u32;
4220 const SOMEONE_ELSE_UID: u32 = 3u32;
4221 let key_id = make_test_key_entry(&mut db, Domain::APP, OWNER_UID as i64, TEST_ALIAS, None)
4222 .context("test_insert_and_load_full_keyentry_from_grant_by_key_id")?
4223 .0;
4224
4225 db.grant(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004226 &KeyDescriptor {
Janis Danisevskis45760022021-01-19 16:34:10 -08004227 domain: Domain::APP,
4228 nspace: 0,
4229 alias: Some(TEST_ALIAS.to_string()),
4230 blob: None,
4231 },
4232 OWNER_UID,
4233 GRANTEE_UID,
4234 key_perm_set![KeyPerm::use_()],
4235 |_k, _av| Ok(()),
4236 )
4237 .unwrap();
4238
4239 debug_dump_grant_table(&mut db)?;
4240
4241 let id_descriptor =
4242 KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, ..Default::default() };
4243
4244 let (_, key_entry) = db
4245 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004246 &id_descriptor,
Janis Danisevskis45760022021-01-19 16:34:10 -08004247 KeyType::Client,
4248 KeyEntryLoadBits::BOTH,
4249 GRANTEE_UID,
4250 |k, av| {
4251 assert_eq!(Domain::APP, k.domain);
4252 assert_eq!(OWNER_UID as i64, k.nspace);
4253 assert!(av.unwrap().includes(KeyPerm::use_()));
4254 Ok(())
4255 },
4256 )
4257 .unwrap();
4258
4259 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
4260
4261 let (_, key_entry) = db
4262 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004263 &id_descriptor,
Janis Danisevskis45760022021-01-19 16:34:10 -08004264 KeyType::Client,
4265 KeyEntryLoadBits::BOTH,
4266 SOMEONE_ELSE_UID,
4267 |k, av| {
4268 assert_eq!(Domain::APP, k.domain);
4269 assert_eq!(OWNER_UID as i64, k.nspace);
4270 assert!(av.is_none());
4271 Ok(())
4272 },
4273 )
4274 .unwrap();
4275
4276 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
4277
Janis Danisevskis66784c42021-01-27 08:40:25 -08004278 db.unbind_key(&id_descriptor, KeyType::Client, OWNER_UID, |_, _| Ok(())).unwrap();
Janis Danisevskis45760022021-01-19 16:34:10 -08004279
4280 assert_eq!(
4281 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
4282 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004283 &id_descriptor,
Janis Danisevskis45760022021-01-19 16:34:10 -08004284 KeyType::Client,
4285 KeyEntryLoadBits::NONE,
4286 GRANTEE_UID,
4287 |_k, _av| Ok(()),
4288 )
4289 .unwrap_err()
4290 .root_cause()
4291 .downcast_ref::<KsError>()
4292 );
4293
4294 Ok(())
4295 }
4296
Janis Danisevskiscdcf4e52021-04-14 15:44:36 -07004297 // Creates a key migrates it to a different location and then tries to access it by the old
4298 // and new location.
4299 #[test]
4300 fn test_migrate_key_app_to_app() -> Result<()> {
4301 let mut db = new_test_db()?;
4302 const SOURCE_UID: u32 = 1u32;
4303 const DESTINATION_UID: u32 = 2u32;
4304 static SOURCE_ALIAS: &str = &"SOURCE_ALIAS";
4305 static DESTINATION_ALIAS: &str = &"DESTINATION_ALIAS";
4306 let key_id_guard =
4307 make_test_key_entry(&mut db, Domain::APP, SOURCE_UID as i64, SOURCE_ALIAS, None)
4308 .context("test_insert_and_load_full_keyentry_from_grant_by_key_id")?;
4309
4310 let source_descriptor: KeyDescriptor = KeyDescriptor {
4311 domain: Domain::APP,
4312 nspace: -1,
4313 alias: Some(SOURCE_ALIAS.to_string()),
4314 blob: None,
4315 };
4316
4317 let destination_descriptor: KeyDescriptor = KeyDescriptor {
4318 domain: Domain::APP,
4319 nspace: -1,
4320 alias: Some(DESTINATION_ALIAS.to_string()),
4321 blob: None,
4322 };
4323
4324 let key_id = key_id_guard.id();
4325
4326 db.migrate_key_namespace(key_id_guard, &destination_descriptor, DESTINATION_UID, |_k| {
4327 Ok(())
4328 })
4329 .unwrap();
4330
4331 let (_, key_entry) = db
4332 .load_key_entry(
4333 &destination_descriptor,
4334 KeyType::Client,
4335 KeyEntryLoadBits::BOTH,
4336 DESTINATION_UID,
4337 |k, av| {
4338 assert_eq!(Domain::APP, k.domain);
4339 assert_eq!(DESTINATION_UID as i64, k.nspace);
4340 assert!(av.is_none());
4341 Ok(())
4342 },
4343 )
4344 .unwrap();
4345
4346 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
4347
4348 assert_eq!(
4349 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
4350 db.load_key_entry(
4351 &source_descriptor,
4352 KeyType::Client,
4353 KeyEntryLoadBits::NONE,
4354 SOURCE_UID,
4355 |_k, _av| Ok(()),
4356 )
4357 .unwrap_err()
4358 .root_cause()
4359 .downcast_ref::<KsError>()
4360 );
4361
4362 Ok(())
4363 }
4364
4365 // Creates a key migrates it to a different location and then tries to access it by the old
4366 // and new location.
4367 #[test]
4368 fn test_migrate_key_app_to_selinux() -> Result<()> {
4369 let mut db = new_test_db()?;
4370 const SOURCE_UID: u32 = 1u32;
4371 const DESTINATION_UID: u32 = 2u32;
4372 const DESTINATION_NAMESPACE: i64 = 1000i64;
4373 static SOURCE_ALIAS: &str = &"SOURCE_ALIAS";
4374 static DESTINATION_ALIAS: &str = &"DESTINATION_ALIAS";
4375 let key_id_guard =
4376 make_test_key_entry(&mut db, Domain::APP, SOURCE_UID as i64, SOURCE_ALIAS, None)
4377 .context("test_insert_and_load_full_keyentry_from_grant_by_key_id")?;
4378
4379 let source_descriptor: KeyDescriptor = KeyDescriptor {
4380 domain: Domain::APP,
4381 nspace: -1,
4382 alias: Some(SOURCE_ALIAS.to_string()),
4383 blob: None,
4384 };
4385
4386 let destination_descriptor: KeyDescriptor = KeyDescriptor {
4387 domain: Domain::SELINUX,
4388 nspace: DESTINATION_NAMESPACE,
4389 alias: Some(DESTINATION_ALIAS.to_string()),
4390 blob: None,
4391 };
4392
4393 let key_id = key_id_guard.id();
4394
4395 db.migrate_key_namespace(key_id_guard, &destination_descriptor, DESTINATION_UID, |_k| {
4396 Ok(())
4397 })
4398 .unwrap();
4399
4400 let (_, key_entry) = db
4401 .load_key_entry(
4402 &destination_descriptor,
4403 KeyType::Client,
4404 KeyEntryLoadBits::BOTH,
4405 DESTINATION_UID,
4406 |k, av| {
4407 assert_eq!(Domain::SELINUX, k.domain);
4408 assert_eq!(DESTINATION_NAMESPACE as i64, k.nspace);
4409 assert!(av.is_none());
4410 Ok(())
4411 },
4412 )
4413 .unwrap();
4414
4415 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
4416
4417 assert_eq!(
4418 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
4419 db.load_key_entry(
4420 &source_descriptor,
4421 KeyType::Client,
4422 KeyEntryLoadBits::NONE,
4423 SOURCE_UID,
4424 |_k, _av| Ok(()),
4425 )
4426 .unwrap_err()
4427 .root_cause()
4428 .downcast_ref::<KsError>()
4429 );
4430
4431 Ok(())
4432 }
4433
4434 // Creates two keys and tries to migrate the first to the location of the second which
4435 // is expected to fail.
4436 #[test]
4437 fn test_migrate_key_destination_occupied() -> Result<()> {
4438 let mut db = new_test_db()?;
4439 const SOURCE_UID: u32 = 1u32;
4440 const DESTINATION_UID: u32 = 2u32;
4441 static SOURCE_ALIAS: &str = &"SOURCE_ALIAS";
4442 static DESTINATION_ALIAS: &str = &"DESTINATION_ALIAS";
4443 let key_id_guard =
4444 make_test_key_entry(&mut db, Domain::APP, SOURCE_UID as i64, SOURCE_ALIAS, None)
4445 .context("test_insert_and_load_full_keyentry_from_grant_by_key_id")?;
4446 make_test_key_entry(&mut db, Domain::APP, DESTINATION_UID as i64, DESTINATION_ALIAS, None)
4447 .context("test_insert_and_load_full_keyentry_from_grant_by_key_id")?;
4448
4449 let destination_descriptor: KeyDescriptor = KeyDescriptor {
4450 domain: Domain::APP,
4451 nspace: -1,
4452 alias: Some(DESTINATION_ALIAS.to_string()),
4453 blob: None,
4454 };
4455
4456 assert_eq!(
4457 Some(&KsError::Rc(ResponseCode::INVALID_ARGUMENT)),
4458 db.migrate_key_namespace(
4459 key_id_guard,
4460 &destination_descriptor,
4461 DESTINATION_UID,
4462 |_k| Ok(())
4463 )
4464 .unwrap_err()
4465 .root_cause()
4466 .downcast_ref::<KsError>()
4467 );
4468
4469 Ok(())
4470 }
4471
Janis Danisevskisaec14592020-11-12 09:41:49 -08004472 static KEY_LOCK_TEST_ALIAS: &str = "my super duper locked key";
4473
Janis Danisevskisaec14592020-11-12 09:41:49 -08004474 #[test]
4475 fn test_insert_and_load_full_keyentry_domain_app_concurrently() -> Result<()> {
4476 let handle = {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08004477 let temp_dir = Arc::new(TempDir::new("id_lock_test")?);
4478 let temp_dir_clone = temp_dir.clone();
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004479 let mut db = KeystoreDB::new(temp_dir.path(), None)?;
Qi Wub9433b52020-12-01 14:52:46 +08004480 let key_id = make_test_key_entry(&mut db, Domain::APP, 33, KEY_LOCK_TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08004481 .context("test_insert_and_load_full_keyentry_domain_app")?
4482 .0;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004483 let (_key_guard, key_entry) = db
4484 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004485 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004486 domain: Domain::APP,
4487 nspace: 0,
4488 alias: Some(KEY_LOCK_TEST_ALIAS.to_string()),
4489 blob: None,
4490 },
4491 KeyType::Client,
4492 KeyEntryLoadBits::BOTH,
4493 33,
4494 |_k, _av| Ok(()),
4495 )
4496 .unwrap();
Qi Wub9433b52020-12-01 14:52:46 +08004497 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskisaec14592020-11-12 09:41:49 -08004498 let state = Arc::new(AtomicU8::new(1));
4499 let state2 = state.clone();
4500
4501 // Spawning a second thread that attempts to acquire the key id lock
4502 // for the same key as the primary thread. The primary thread then
4503 // waits, thereby forcing the secondary thread into the second stage
4504 // of acquiring the lock (see KEY ID LOCK 2/2 above).
4505 // The test succeeds if the secondary thread observes the transition
4506 // of `state` from 1 to 2, despite having a whole second to overtake
4507 // the primary thread.
4508 let handle = thread::spawn(move || {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08004509 let temp_dir = temp_dir_clone;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004510 let mut db = KeystoreDB::new(temp_dir.path(), None).unwrap();
Janis Danisevskisaec14592020-11-12 09:41:49 -08004511 assert!(db
4512 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004513 &KeyDescriptor {
Janis Danisevskisaec14592020-11-12 09:41:49 -08004514 domain: Domain::APP,
4515 nspace: 0,
4516 alias: Some(KEY_LOCK_TEST_ALIAS.to_string()),
4517 blob: None,
4518 },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004519 KeyType::Client,
Janis Danisevskisaec14592020-11-12 09:41:49 -08004520 KeyEntryLoadBits::BOTH,
4521 33,
4522 |_k, _av| Ok(()),
4523 )
4524 .is_ok());
4525 // We should only see a 2 here because we can only return
4526 // from load_key_entry when the `_key_guard` expires,
4527 // which happens at the end of the scope.
4528 assert_eq!(2, state2.load(Ordering::Relaxed));
4529 });
4530
4531 thread::sleep(std::time::Duration::from_millis(1000));
4532
4533 assert_eq!(Ok(1), state.compare_exchange(1, 2, Ordering::Relaxed, Ordering::Relaxed));
4534
4535 // Return the handle from this scope so we can join with the
4536 // secondary thread after the key id lock has expired.
4537 handle
4538 // This is where the `_key_guard` goes out of scope,
4539 // which is the reason for concurrent load_key_entry on the same key
4540 // to unblock.
4541 };
4542 // Join with the secondary thread and unwrap, to propagate failing asserts to the
4543 // main test thread. We will not see failing asserts in secondary threads otherwise.
4544 handle.join().unwrap();
4545 Ok(())
4546 }
4547
Janis Danisevskise92a5e62020-12-02 12:57:41 -08004548 #[test]
Janis Danisevskiscdcf4e52021-04-14 15:44:36 -07004549 fn test_database_busy_error_code() {
Janis Danisevskis66784c42021-01-27 08:40:25 -08004550 let temp_dir =
4551 TempDir::new("test_database_busy_error_code_").expect("Failed to create temp dir.");
4552
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004553 let mut db1 = KeystoreDB::new(temp_dir.path(), None).expect("Failed to open database1.");
4554 let mut db2 = KeystoreDB::new(temp_dir.path(), None).expect("Failed to open database2.");
Janis Danisevskis66784c42021-01-27 08:40:25 -08004555
4556 let _tx1 = db1
4557 .conn
4558 .transaction_with_behavior(TransactionBehavior::Immediate)
4559 .expect("Failed to create first transaction.");
4560
4561 let error = db2
4562 .conn
4563 .transaction_with_behavior(TransactionBehavior::Immediate)
4564 .context("Transaction begin failed.")
4565 .expect_err("This should fail.");
4566 let root_cause = error.root_cause();
4567 if let Some(rusqlite::ffi::Error { code: rusqlite::ErrorCode::DatabaseBusy, .. }) =
4568 root_cause.downcast_ref::<rusqlite::ffi::Error>()
4569 {
4570 return;
4571 }
4572 panic!(
4573 "Unexpected error {:?} \n{:?} \n{:?}",
4574 error,
4575 root_cause,
4576 root_cause.downcast_ref::<rusqlite::ffi::Error>()
4577 )
4578 }
4579
4580 #[cfg(disabled)]
4581 #[test]
4582 fn test_large_number_of_concurrent_db_manipulations() -> Result<()> {
4583 let temp_dir = Arc::new(
4584 TempDir::new("test_large_number_of_concurrent_db_manipulations_")
4585 .expect("Failed to create temp dir."),
4586 );
4587
4588 let test_begin = Instant::now();
4589
4590 let mut db = KeystoreDB::new(temp_dir.path()).expect("Failed to open database.");
4591 const KEY_COUNT: u32 = 500u32;
4592 const OPEN_DB_COUNT: u32 = 50u32;
4593
4594 let mut actual_key_count = KEY_COUNT;
4595 // First insert KEY_COUNT keys.
4596 for count in 0..KEY_COUNT {
4597 if Instant::now().duration_since(test_begin) >= Duration::from_secs(15) {
4598 actual_key_count = count;
4599 break;
4600 }
4601 let alias = format!("test_alias_{}", count);
4602 make_test_key_entry(&mut db, Domain::APP, 1, &alias, None)
4603 .expect("Failed to make key entry.");
4604 }
4605
4606 // Insert more keys from a different thread and into a different namespace.
4607 let temp_dir1 = temp_dir.clone();
4608 let handle1 = thread::spawn(move || {
4609 let mut db = KeystoreDB::new(temp_dir1.path()).expect("Failed to open database.");
4610
4611 for count in 0..actual_key_count {
4612 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
4613 return;
4614 }
4615 let alias = format!("test_alias_{}", count);
4616 make_test_key_entry(&mut db, Domain::APP, 2, &alias, None)
4617 .expect("Failed to make key entry.");
4618 }
4619
4620 // then unbind them again.
4621 for count in 0..actual_key_count {
4622 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
4623 return;
4624 }
4625 let key = KeyDescriptor {
4626 domain: Domain::APP,
4627 nspace: -1,
4628 alias: Some(format!("test_alias_{}", count)),
4629 blob: None,
4630 };
4631 db.unbind_key(&key, KeyType::Client, 2, |_, _| Ok(())).expect("Unbind Failed.");
4632 }
4633 });
4634
4635 // And start unbinding the first set of keys.
4636 let temp_dir2 = temp_dir.clone();
4637 let handle2 = thread::spawn(move || {
4638 let mut db = KeystoreDB::new(temp_dir2.path()).expect("Failed to open database.");
4639
4640 for count in 0..actual_key_count {
4641 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
4642 return;
4643 }
4644 let key = KeyDescriptor {
4645 domain: Domain::APP,
4646 nspace: -1,
4647 alias: Some(format!("test_alias_{}", count)),
4648 blob: None,
4649 };
4650 db.unbind_key(&key, KeyType::Client, 1, |_, _| Ok(())).expect("Unbind Failed.");
4651 }
4652 });
4653
4654 let stop_deleting = Arc::new(AtomicU8::new(0));
4655 let stop_deleting2 = stop_deleting.clone();
4656
4657 // And delete anything that is unreferenced keys.
4658 let temp_dir3 = temp_dir.clone();
4659 let handle3 = thread::spawn(move || {
4660 let mut db = KeystoreDB::new(temp_dir3.path()).expect("Failed to open database.");
4661
4662 while stop_deleting2.load(Ordering::Relaxed) != 1 {
4663 while let Some((key_guard, _key)) =
4664 db.get_unreferenced_key().expect("Failed to get unreferenced Key.")
4665 {
4666 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
4667 return;
4668 }
4669 db.purge_key_entry(key_guard).expect("Failed to purge key.");
4670 }
4671 std::thread::sleep(std::time::Duration::from_millis(100));
4672 }
4673 });
4674
4675 // While a lot of inserting and deleting is going on we have to open database connections
4676 // successfully and use them.
4677 // This clone is not redundant, because temp_dir needs to be kept alive until db goes
4678 // out of scope.
4679 #[allow(clippy::redundant_clone)]
4680 let temp_dir4 = temp_dir.clone();
4681 let handle4 = thread::spawn(move || {
4682 for count in 0..OPEN_DB_COUNT {
4683 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
4684 return;
4685 }
4686 let mut db = KeystoreDB::new(temp_dir4.path()).expect("Failed to open database.");
4687
4688 let alias = format!("test_alias_{}", count);
4689 make_test_key_entry(&mut db, Domain::APP, 3, &alias, None)
4690 .expect("Failed to make key entry.");
4691 let key = KeyDescriptor {
4692 domain: Domain::APP,
4693 nspace: -1,
4694 alias: Some(alias),
4695 blob: None,
4696 };
4697 db.unbind_key(&key, KeyType::Client, 3, |_, _| Ok(())).expect("Unbind Failed.");
4698 }
4699 });
4700
4701 handle1.join().expect("Thread 1 panicked.");
4702 handle2.join().expect("Thread 2 panicked.");
4703 handle4.join().expect("Thread 4 panicked.");
4704
4705 stop_deleting.store(1, Ordering::Relaxed);
4706 handle3.join().expect("Thread 3 panicked.");
4707
4708 Ok(())
4709 }
4710
4711 #[test]
Janis Danisevskise92a5e62020-12-02 12:57:41 -08004712 fn list() -> Result<()> {
4713 let temp_dir = TempDir::new("list_test")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004714 let mut db = KeystoreDB::new(temp_dir.path(), None)?;
Janis Danisevskise92a5e62020-12-02 12:57:41 -08004715 static LIST_O_ENTRIES: &[(Domain, i64, &str)] = &[
4716 (Domain::APP, 1, "test1"),
4717 (Domain::APP, 1, "test2"),
4718 (Domain::APP, 1, "test3"),
4719 (Domain::APP, 1, "test4"),
4720 (Domain::APP, 1, "test5"),
4721 (Domain::APP, 1, "test6"),
4722 (Domain::APP, 1, "test7"),
4723 (Domain::APP, 2, "test1"),
4724 (Domain::APP, 2, "test2"),
4725 (Domain::APP, 2, "test3"),
4726 (Domain::APP, 2, "test4"),
4727 (Domain::APP, 2, "test5"),
4728 (Domain::APP, 2, "test6"),
4729 (Domain::APP, 2, "test8"),
4730 (Domain::SELINUX, 100, "test1"),
4731 (Domain::SELINUX, 100, "test2"),
4732 (Domain::SELINUX, 100, "test3"),
4733 (Domain::SELINUX, 100, "test4"),
4734 (Domain::SELINUX, 100, "test5"),
4735 (Domain::SELINUX, 100, "test6"),
4736 (Domain::SELINUX, 100, "test9"),
4737 ];
4738
4739 let list_o_keys: Vec<(i64, i64)> = LIST_O_ENTRIES
4740 .iter()
4741 .map(|(domain, ns, alias)| {
Qi Wub9433b52020-12-01 14:52:46 +08004742 let entry = make_test_key_entry(&mut db, *domain, *ns, *alias, None)
4743 .unwrap_or_else(|e| {
Janis Danisevskise92a5e62020-12-02 12:57:41 -08004744 panic!("Failed to insert {:?} {} {}. Error {:?}", domain, ns, alias, e)
4745 });
4746 (entry.id(), *ns)
4747 })
4748 .collect();
4749
4750 for (domain, namespace) in
4751 &[(Domain::APP, 1i64), (Domain::APP, 2i64), (Domain::SELINUX, 100i64)]
4752 {
4753 let mut list_o_descriptors: Vec<KeyDescriptor> = LIST_O_ENTRIES
4754 .iter()
4755 .filter_map(|(domain, ns, alias)| match ns {
4756 ns if *ns == *namespace => Some(KeyDescriptor {
4757 domain: *domain,
4758 nspace: *ns,
4759 alias: Some(alias.to_string()),
4760 blob: None,
4761 }),
4762 _ => None,
4763 })
4764 .collect();
4765 list_o_descriptors.sort();
Janis Danisevskis18313832021-05-17 13:30:32 -07004766 let mut list_result = db.list(*domain, *namespace, KeyType::Client)?;
Janis Danisevskise92a5e62020-12-02 12:57:41 -08004767 list_result.sort();
4768 assert_eq!(list_o_descriptors, list_result);
4769
4770 let mut list_o_ids: Vec<i64> = list_o_descriptors
4771 .into_iter()
4772 .map(|d| {
4773 let (_, entry) = db
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004774 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004775 &d,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004776 KeyType::Client,
4777 KeyEntryLoadBits::NONE,
4778 *namespace as u32,
4779 |_, _| Ok(()),
4780 )
Janis Danisevskise92a5e62020-12-02 12:57:41 -08004781 .unwrap();
4782 entry.id()
4783 })
4784 .collect();
4785 list_o_ids.sort_unstable();
4786 let mut loaded_entries: Vec<i64> = list_o_keys
4787 .iter()
4788 .filter_map(|(id, ns)| match ns {
4789 ns if *ns == *namespace => Some(*id),
4790 _ => None,
4791 })
4792 .collect();
4793 loaded_entries.sort_unstable();
4794 assert_eq!(list_o_ids, loaded_entries);
4795 }
Janis Danisevskis18313832021-05-17 13:30:32 -07004796 assert_eq!(Vec::<KeyDescriptor>::new(), db.list(Domain::SELINUX, 101, KeyType::Client)?);
Janis Danisevskise92a5e62020-12-02 12:57:41 -08004797
4798 Ok(())
4799 }
4800
Joel Galenson0891bc12020-07-20 10:37:03 -07004801 // Helpers
4802
4803 // Checks that the given result is an error containing the given string.
4804 fn check_result_is_error_containing_string<T>(result: Result<T>, target: &str) {
4805 let error_str = format!(
4806 "{:#?}",
4807 result.err().unwrap_or_else(|| panic!("Expected the error: {}", target))
4808 );
4809 assert!(
4810 error_str.contains(target),
4811 "The string \"{}\" should contain \"{}\"",
4812 error_str,
4813 target
4814 );
4815 }
4816
Joel Galenson2aab4432020-07-22 15:27:57 -07004817 #[derive(Debug, PartialEq)]
Joel Galenson0891bc12020-07-20 10:37:03 -07004818 struct KeyEntryRow {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004819 id: i64,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004820 key_type: KeyType,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07004821 domain: Option<Domain>,
Joel Galenson0891bc12020-07-20 10:37:03 -07004822 namespace: Option<i64>,
4823 alias: Option<String>,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004824 state: KeyLifeCycle,
Max Bires8e93d2b2021-01-14 13:17:59 -08004825 km_uuid: Option<Uuid>,
Joel Galenson0891bc12020-07-20 10:37:03 -07004826 }
4827
4828 fn get_keyentry(db: &KeystoreDB) -> Result<Vec<KeyEntryRow>> {
4829 db.conn
Joel Galenson2aab4432020-07-22 15:27:57 -07004830 .prepare("SELECT * FROM persistent.keyentry;")?
Joel Galenson0891bc12020-07-20 10:37:03 -07004831 .query_map(NO_PARAMS, |row| {
Joel Galenson0891bc12020-07-20 10:37:03 -07004832 Ok(KeyEntryRow {
4833 id: row.get(0)?,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004834 key_type: row.get(1)?,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07004835 domain: match row.get(2)? {
4836 Some(i) => Some(Domain(i)),
4837 None => None,
4838 },
Joel Galenson0891bc12020-07-20 10:37:03 -07004839 namespace: row.get(3)?,
4840 alias: row.get(4)?,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004841 state: row.get(5)?,
Max Bires8e93d2b2021-01-14 13:17:59 -08004842 km_uuid: row.get(6)?,
Joel Galenson0891bc12020-07-20 10:37:03 -07004843 })
4844 })?
4845 .map(|r| r.context("Could not read keyentry row."))
4846 .collect::<Result<Vec<_>>>()
4847 }
4848
Max Biresb2e1d032021-02-08 21:35:05 -08004849 struct RemoteProvValues {
4850 cert_chain: Vec<u8>,
4851 priv_key: Vec<u8>,
4852 batch_cert: Vec<u8>,
4853 }
4854
Max Bires2b2e6562020-09-22 11:22:36 -07004855 fn load_attestation_key_pool(
4856 db: &mut KeystoreDB,
4857 expiration_date: i64,
4858 namespace: i64,
4859 base_byte: u8,
Max Biresb2e1d032021-02-08 21:35:05 -08004860 ) -> Result<RemoteProvValues> {
Max Bires2b2e6562020-09-22 11:22:36 -07004861 let public_key: Vec<u8> = vec![base_byte, 0x02 * base_byte];
4862 let cert_chain: Vec<u8> = vec![0x03 * base_byte, 0x04 * base_byte];
4863 let priv_key: Vec<u8> = vec![0x05 * base_byte, 0x06 * base_byte];
4864 let raw_public_key: Vec<u8> = vec![0x0b * base_byte, 0x0c * base_byte];
Max Biresb2e1d032021-02-08 21:35:05 -08004865 let batch_cert: Vec<u8> = vec![base_byte * 0x0d, base_byte * 0x0e];
Max Bires2b2e6562020-09-22 11:22:36 -07004866 db.create_attestation_key_entry(&public_key, &raw_public_key, &priv_key, &KEYSTORE_UUID)?;
4867 db.store_signed_attestation_certificate_chain(
4868 &raw_public_key,
Max Biresb2e1d032021-02-08 21:35:05 -08004869 &batch_cert,
Max Bires2b2e6562020-09-22 11:22:36 -07004870 &cert_chain,
4871 expiration_date,
4872 &KEYSTORE_UUID,
4873 )?;
4874 db.assign_attestation_key(Domain::APP, namespace, &KEYSTORE_UUID)?;
Max Biresb2e1d032021-02-08 21:35:05 -08004875 Ok(RemoteProvValues { cert_chain, priv_key, batch_cert })
Max Bires2b2e6562020-09-22 11:22:36 -07004876 }
4877
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07004878 // Note: The parameters and SecurityLevel associations are nonsensical. This
4879 // collection is only used to check if the parameters are preserved as expected by the
4880 // database.
Qi Wub9433b52020-12-01 14:52:46 +08004881 fn make_test_params(max_usage_count: Option<i32>) -> Vec<KeyParameter> {
4882 let mut params = vec![
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07004883 KeyParameter::new(KeyParameterValue::Invalid, SecurityLevel::TRUSTED_ENVIRONMENT),
4884 KeyParameter::new(
4885 KeyParameterValue::KeyPurpose(KeyPurpose::SIGN),
4886 SecurityLevel::TRUSTED_ENVIRONMENT,
4887 ),
4888 KeyParameter::new(
4889 KeyParameterValue::KeyPurpose(KeyPurpose::DECRYPT),
4890 SecurityLevel::TRUSTED_ENVIRONMENT,
4891 ),
4892 KeyParameter::new(
4893 KeyParameterValue::Algorithm(Algorithm::RSA),
4894 SecurityLevel::TRUSTED_ENVIRONMENT,
4895 ),
4896 KeyParameter::new(KeyParameterValue::KeySize(1024), SecurityLevel::TRUSTED_ENVIRONMENT),
4897 KeyParameter::new(
4898 KeyParameterValue::BlockMode(BlockMode::ECB),
4899 SecurityLevel::TRUSTED_ENVIRONMENT,
4900 ),
4901 KeyParameter::new(
4902 KeyParameterValue::BlockMode(BlockMode::GCM),
4903 SecurityLevel::TRUSTED_ENVIRONMENT,
4904 ),
4905 KeyParameter::new(KeyParameterValue::Digest(Digest::NONE), SecurityLevel::STRONGBOX),
4906 KeyParameter::new(
4907 KeyParameterValue::Digest(Digest::MD5),
4908 SecurityLevel::TRUSTED_ENVIRONMENT,
4909 ),
4910 KeyParameter::new(
4911 KeyParameterValue::Digest(Digest::SHA_2_224),
4912 SecurityLevel::TRUSTED_ENVIRONMENT,
4913 ),
4914 KeyParameter::new(
4915 KeyParameterValue::Digest(Digest::SHA_2_256),
4916 SecurityLevel::STRONGBOX,
4917 ),
4918 KeyParameter::new(
4919 KeyParameterValue::PaddingMode(PaddingMode::NONE),
4920 SecurityLevel::TRUSTED_ENVIRONMENT,
4921 ),
4922 KeyParameter::new(
4923 KeyParameterValue::PaddingMode(PaddingMode::RSA_OAEP),
4924 SecurityLevel::TRUSTED_ENVIRONMENT,
4925 ),
4926 KeyParameter::new(
4927 KeyParameterValue::PaddingMode(PaddingMode::RSA_PSS),
4928 SecurityLevel::STRONGBOX,
4929 ),
4930 KeyParameter::new(
4931 KeyParameterValue::PaddingMode(PaddingMode::RSA_PKCS1_1_5_SIGN),
4932 SecurityLevel::TRUSTED_ENVIRONMENT,
4933 ),
4934 KeyParameter::new(KeyParameterValue::CallerNonce, SecurityLevel::TRUSTED_ENVIRONMENT),
4935 KeyParameter::new(KeyParameterValue::MinMacLength(256), SecurityLevel::STRONGBOX),
4936 KeyParameter::new(
4937 KeyParameterValue::EcCurve(EcCurve::P_224),
4938 SecurityLevel::TRUSTED_ENVIRONMENT,
4939 ),
4940 KeyParameter::new(KeyParameterValue::EcCurve(EcCurve::P_256), SecurityLevel::STRONGBOX),
4941 KeyParameter::new(
4942 KeyParameterValue::EcCurve(EcCurve::P_384),
4943 SecurityLevel::TRUSTED_ENVIRONMENT,
4944 ),
4945 KeyParameter::new(
4946 KeyParameterValue::EcCurve(EcCurve::P_521),
4947 SecurityLevel::TRUSTED_ENVIRONMENT,
4948 ),
4949 KeyParameter::new(
4950 KeyParameterValue::RSAPublicExponent(3),
4951 SecurityLevel::TRUSTED_ENVIRONMENT,
4952 ),
4953 KeyParameter::new(
4954 KeyParameterValue::IncludeUniqueID,
4955 SecurityLevel::TRUSTED_ENVIRONMENT,
4956 ),
4957 KeyParameter::new(KeyParameterValue::BootLoaderOnly, SecurityLevel::STRONGBOX),
4958 KeyParameter::new(KeyParameterValue::RollbackResistance, SecurityLevel::STRONGBOX),
4959 KeyParameter::new(
4960 KeyParameterValue::ActiveDateTime(1234567890),
4961 SecurityLevel::STRONGBOX,
4962 ),
4963 KeyParameter::new(
4964 KeyParameterValue::OriginationExpireDateTime(1234567890),
4965 SecurityLevel::TRUSTED_ENVIRONMENT,
4966 ),
4967 KeyParameter::new(
4968 KeyParameterValue::UsageExpireDateTime(1234567890),
4969 SecurityLevel::TRUSTED_ENVIRONMENT,
4970 ),
4971 KeyParameter::new(
4972 KeyParameterValue::MinSecondsBetweenOps(1234567890),
4973 SecurityLevel::TRUSTED_ENVIRONMENT,
4974 ),
4975 KeyParameter::new(
4976 KeyParameterValue::MaxUsesPerBoot(1234567890),
4977 SecurityLevel::TRUSTED_ENVIRONMENT,
4978 ),
4979 KeyParameter::new(KeyParameterValue::UserID(1), SecurityLevel::STRONGBOX),
4980 KeyParameter::new(KeyParameterValue::UserSecureID(42), SecurityLevel::STRONGBOX),
4981 KeyParameter::new(
4982 KeyParameterValue::NoAuthRequired,
4983 SecurityLevel::TRUSTED_ENVIRONMENT,
4984 ),
4985 KeyParameter::new(
4986 KeyParameterValue::HardwareAuthenticatorType(HardwareAuthenticatorType::PASSWORD),
4987 SecurityLevel::TRUSTED_ENVIRONMENT,
4988 ),
4989 KeyParameter::new(KeyParameterValue::AuthTimeout(1234567890), SecurityLevel::SOFTWARE),
4990 KeyParameter::new(KeyParameterValue::AllowWhileOnBody, SecurityLevel::SOFTWARE),
4991 KeyParameter::new(
4992 KeyParameterValue::TrustedUserPresenceRequired,
4993 SecurityLevel::TRUSTED_ENVIRONMENT,
4994 ),
4995 KeyParameter::new(
4996 KeyParameterValue::TrustedConfirmationRequired,
4997 SecurityLevel::TRUSTED_ENVIRONMENT,
4998 ),
4999 KeyParameter::new(
5000 KeyParameterValue::UnlockedDeviceRequired,
5001 SecurityLevel::TRUSTED_ENVIRONMENT,
5002 ),
5003 KeyParameter::new(
5004 KeyParameterValue::ApplicationID(vec![1u8, 2u8, 3u8, 4u8]),
5005 SecurityLevel::SOFTWARE,
5006 ),
5007 KeyParameter::new(
5008 KeyParameterValue::ApplicationData(vec![4u8, 3u8, 2u8, 1u8]),
5009 SecurityLevel::SOFTWARE,
5010 ),
5011 KeyParameter::new(
5012 KeyParameterValue::CreationDateTime(12345677890),
5013 SecurityLevel::SOFTWARE,
5014 ),
5015 KeyParameter::new(
5016 KeyParameterValue::KeyOrigin(KeyOrigin::GENERATED),
5017 SecurityLevel::TRUSTED_ENVIRONMENT,
5018 ),
5019 KeyParameter::new(
5020 KeyParameterValue::RootOfTrust(vec![3u8, 2u8, 1u8, 4u8]),
5021 SecurityLevel::TRUSTED_ENVIRONMENT,
5022 ),
5023 KeyParameter::new(KeyParameterValue::OSVersion(1), SecurityLevel::TRUSTED_ENVIRONMENT),
5024 KeyParameter::new(KeyParameterValue::OSPatchLevel(2), SecurityLevel::SOFTWARE),
5025 KeyParameter::new(
5026 KeyParameterValue::UniqueID(vec![4u8, 3u8, 1u8, 2u8]),
5027 SecurityLevel::SOFTWARE,
5028 ),
5029 KeyParameter::new(
5030 KeyParameterValue::AttestationChallenge(vec![4u8, 3u8, 1u8, 2u8]),
5031 SecurityLevel::TRUSTED_ENVIRONMENT,
5032 ),
5033 KeyParameter::new(
5034 KeyParameterValue::AttestationApplicationID(vec![4u8, 3u8, 1u8, 2u8]),
5035 SecurityLevel::TRUSTED_ENVIRONMENT,
5036 ),
5037 KeyParameter::new(
5038 KeyParameterValue::AttestationIdBrand(vec![4u8, 3u8, 1u8, 2u8]),
5039 SecurityLevel::TRUSTED_ENVIRONMENT,
5040 ),
5041 KeyParameter::new(
5042 KeyParameterValue::AttestationIdDevice(vec![4u8, 3u8, 1u8, 2u8]),
5043 SecurityLevel::TRUSTED_ENVIRONMENT,
5044 ),
5045 KeyParameter::new(
5046 KeyParameterValue::AttestationIdProduct(vec![4u8, 3u8, 1u8, 2u8]),
5047 SecurityLevel::TRUSTED_ENVIRONMENT,
5048 ),
5049 KeyParameter::new(
5050 KeyParameterValue::AttestationIdSerial(vec![4u8, 3u8, 1u8, 2u8]),
5051 SecurityLevel::TRUSTED_ENVIRONMENT,
5052 ),
5053 KeyParameter::new(
5054 KeyParameterValue::AttestationIdIMEI(vec![4u8, 3u8, 1u8, 2u8]),
5055 SecurityLevel::TRUSTED_ENVIRONMENT,
5056 ),
5057 KeyParameter::new(
5058 KeyParameterValue::AttestationIdMEID(vec![4u8, 3u8, 1u8, 2u8]),
5059 SecurityLevel::TRUSTED_ENVIRONMENT,
5060 ),
5061 KeyParameter::new(
5062 KeyParameterValue::AttestationIdManufacturer(vec![4u8, 3u8, 1u8, 2u8]),
5063 SecurityLevel::TRUSTED_ENVIRONMENT,
5064 ),
5065 KeyParameter::new(
5066 KeyParameterValue::AttestationIdModel(vec![4u8, 3u8, 1u8, 2u8]),
5067 SecurityLevel::TRUSTED_ENVIRONMENT,
5068 ),
5069 KeyParameter::new(
5070 KeyParameterValue::VendorPatchLevel(3),
5071 SecurityLevel::TRUSTED_ENVIRONMENT,
5072 ),
5073 KeyParameter::new(
5074 KeyParameterValue::BootPatchLevel(4),
5075 SecurityLevel::TRUSTED_ENVIRONMENT,
5076 ),
5077 KeyParameter::new(
5078 KeyParameterValue::AssociatedData(vec![4u8, 3u8, 1u8, 2u8]),
5079 SecurityLevel::TRUSTED_ENVIRONMENT,
5080 ),
5081 KeyParameter::new(
5082 KeyParameterValue::Nonce(vec![4u8, 3u8, 1u8, 2u8]),
5083 SecurityLevel::TRUSTED_ENVIRONMENT,
5084 ),
5085 KeyParameter::new(
5086 KeyParameterValue::MacLength(256),
5087 SecurityLevel::TRUSTED_ENVIRONMENT,
5088 ),
5089 KeyParameter::new(
5090 KeyParameterValue::ResetSinceIdRotation,
5091 SecurityLevel::TRUSTED_ENVIRONMENT,
5092 ),
5093 KeyParameter::new(
5094 KeyParameterValue::ConfirmationToken(vec![5u8, 5u8, 5u8, 5u8]),
5095 SecurityLevel::TRUSTED_ENVIRONMENT,
5096 ),
Qi Wub9433b52020-12-01 14:52:46 +08005097 ];
5098 if let Some(value) = max_usage_count {
5099 params.push(KeyParameter::new(
5100 KeyParameterValue::UsageCountLimit(value),
5101 SecurityLevel::SOFTWARE,
5102 ));
5103 }
5104 params
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07005105 }
5106
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07005107 fn make_test_key_entry(
5108 db: &mut KeystoreDB,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07005109 domain: Domain,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07005110 namespace: i64,
5111 alias: &str,
Qi Wub9433b52020-12-01 14:52:46 +08005112 max_usage_count: Option<i32>,
Janis Danisevskisaec14592020-11-12 09:41:49 -08005113 ) -> Result<KeyIdGuard> {
Janis Danisevskis0cabd712021-05-25 11:07:10 -07005114 let key_id = db.create_key_entry(&domain, &namespace, KeyType::Client, &KEYSTORE_UUID)?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08005115 let mut blob_metadata = BlobMetaData::new();
5116 blob_metadata.add(BlobMetaEntry::EncryptedBy(EncryptedBy::Password));
5117 blob_metadata.add(BlobMetaEntry::Salt(vec![1, 2, 3]));
5118 blob_metadata.add(BlobMetaEntry::Iv(vec![2, 3, 1]));
5119 blob_metadata.add(BlobMetaEntry::AeadTag(vec![3, 1, 2]));
5120 blob_metadata.add(BlobMetaEntry::KmUuid(KEYSTORE_UUID));
5121
5122 db.set_blob(
5123 &key_id,
5124 SubComponentType::KEY_BLOB,
5125 Some(TEST_KEY_BLOB),
5126 Some(&blob_metadata),
5127 )?;
5128 db.set_blob(&key_id, SubComponentType::CERT, Some(TEST_CERT_BLOB), None)?;
5129 db.set_blob(&key_id, SubComponentType::CERT_CHAIN, Some(TEST_CERT_CHAIN_BLOB), None)?;
Qi Wub9433b52020-12-01 14:52:46 +08005130
5131 let params = make_test_params(max_usage_count);
5132 db.insert_keyparameter(&key_id, &params)?;
5133
Janis Danisevskisb42fc182020-12-15 08:41:27 -08005134 let mut metadata = KeyMetaData::new();
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08005135 metadata.add(KeyMetaEntry::CreationDate(DateTime::from_millis_epoch(123456789)));
Janis Danisevskisb42fc182020-12-15 08:41:27 -08005136 db.insert_key_metadata(&key_id, &metadata)?;
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08005137 rebind_alias(db, &key_id, alias, domain, namespace)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07005138 Ok(key_id)
5139 }
5140
Qi Wub9433b52020-12-01 14:52:46 +08005141 fn make_test_key_entry_test_vector(key_id: i64, max_usage_count: Option<i32>) -> KeyEntry {
5142 let params = make_test_params(max_usage_count);
5143
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08005144 let mut blob_metadata = BlobMetaData::new();
5145 blob_metadata.add(BlobMetaEntry::EncryptedBy(EncryptedBy::Password));
5146 blob_metadata.add(BlobMetaEntry::Salt(vec![1, 2, 3]));
5147 blob_metadata.add(BlobMetaEntry::Iv(vec![2, 3, 1]));
5148 blob_metadata.add(BlobMetaEntry::AeadTag(vec![3, 1, 2]));
5149 blob_metadata.add(BlobMetaEntry::KmUuid(KEYSTORE_UUID));
5150
Janis Danisevskisb42fc182020-12-15 08:41:27 -08005151 let mut metadata = KeyMetaData::new();
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08005152 metadata.add(KeyMetaEntry::CreationDate(DateTime::from_millis_epoch(123456789)));
Janis Danisevskisb42fc182020-12-15 08:41:27 -08005153
5154 KeyEntry {
5155 id: key_id,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08005156 key_blob_info: Some((TEST_KEY_BLOB.to_vec(), blob_metadata)),
Janis Danisevskisb42fc182020-12-15 08:41:27 -08005157 cert: Some(TEST_CERT_BLOB.to_vec()),
5158 cert_chain: Some(TEST_CERT_CHAIN_BLOB.to_vec()),
Max Bires8e93d2b2021-01-14 13:17:59 -08005159 km_uuid: KEYSTORE_UUID,
Qi Wub9433b52020-12-01 14:52:46 +08005160 parameters: params,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08005161 metadata,
Janis Danisevskis377d1002021-01-27 19:07:48 -08005162 pure_cert: false,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08005163 }
5164 }
5165
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07005166 fn debug_dump_keyentry_table(db: &mut KeystoreDB) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08005167 let mut stmt = db.conn.prepare(
Max Bires8e93d2b2021-01-14 13:17:59 -08005168 "SELECT id, key_type, domain, namespace, alias, state, km_uuid FROM persistent.keyentry;",
Janis Danisevskis93927dd2020-12-23 12:23:08 -08005169 )?;
Max Bires8e93d2b2021-01-14 13:17:59 -08005170 let rows = stmt.query_map::<(i64, KeyType, i32, i64, String, KeyLifeCycle, Uuid), _, _>(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08005171 NO_PARAMS,
5172 |row| {
Max Bires8e93d2b2021-01-14 13:17:59 -08005173 Ok((
5174 row.get(0)?,
5175 row.get(1)?,
5176 row.get(2)?,
5177 row.get(3)?,
5178 row.get(4)?,
5179 row.get(5)?,
5180 row.get(6)?,
5181 ))
Janis Danisevskis93927dd2020-12-23 12:23:08 -08005182 },
5183 )?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07005184
5185 println!("Key entry table rows:");
5186 for r in rows {
Max Bires8e93d2b2021-01-14 13:17:59 -08005187 let (id, key_type, domain, namespace, alias, state, km_uuid) = r.unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07005188 println!(
Max Bires8e93d2b2021-01-14 13:17:59 -08005189 " id: {} KeyType: {:?} Domain: {} Namespace: {} Alias: {} State: {:?} KmUuid: {:?}",
5190 id, key_type, domain, namespace, alias, state, km_uuid
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07005191 );
5192 }
5193 Ok(())
5194 }
5195
5196 fn debug_dump_grant_table(db: &mut KeystoreDB) -> Result<()> {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08005197 let mut stmt = db
5198 .conn
5199 .prepare("SELECT id, grantee, keyentryid, access_vector FROM persistent.grant;")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07005200 let rows = stmt.query_map::<(i64, i64, i64, i64), _, _>(NO_PARAMS, |row| {
5201 Ok((row.get(0)?, row.get(1)?, row.get(2)?, row.get(3)?))
5202 })?;
5203
5204 println!("Grant table rows:");
5205 for r in rows {
5206 let (id, gt, ki, av) = r.unwrap();
5207 println!(" id: {} grantee: {} key_id: {} access_vector: {}", id, gt, ki, av);
5208 }
5209 Ok(())
5210 }
5211
Joel Galenson0891bc12020-07-20 10:37:03 -07005212 // Use a custom random number generator that repeats each number once.
5213 // This allows us to test repeated elements.
5214
5215 thread_local! {
5216 static RANDOM_COUNTER: RefCell<i64> = RefCell::new(0);
5217 }
5218
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07005219 fn reset_random() {
5220 RANDOM_COUNTER.with(|counter| {
5221 *counter.borrow_mut() = 0;
5222 })
5223 }
5224
Joel Galenson0891bc12020-07-20 10:37:03 -07005225 pub fn random() -> i64 {
5226 RANDOM_COUNTER.with(|counter| {
5227 let result = *counter.borrow() / 2;
5228 *counter.borrow_mut() += 1;
5229 result
5230 })
5231 }
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00005232
5233 #[test]
5234 fn test_last_off_body() -> Result<()> {
5235 let mut db = new_test_db()?;
Matthew Maurerd7815ca2021-05-06 21:58:45 -07005236 db.insert_last_off_body(MonotonicRawTime::now());
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00005237 let tx = db.conn.transaction_with_behavior(TransactionBehavior::Immediate)?;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00005238 tx.commit()?;
Matthew Maurerd7815ca2021-05-06 21:58:45 -07005239 let last_off_body_1 = db.get_last_off_body();
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00005240 let one_second = Duration::from_secs(1);
5241 thread::sleep(one_second);
Matthew Maurerd7815ca2021-05-06 21:58:45 -07005242 db.update_last_off_body(MonotonicRawTime::now());
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00005243 let tx2 = db.conn.transaction_with_behavior(TransactionBehavior::Immediate)?;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00005244 tx2.commit()?;
Matthew Maurerd7815ca2021-05-06 21:58:45 -07005245 let last_off_body_2 = db.get_last_off_body();
Hasini Gunasinghe66a24602021-05-12 19:03:12 +00005246 assert!(last_off_body_1 < last_off_body_2);
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00005247 Ok(())
5248 }
Hasini Gunasingheda895552021-01-27 19:34:37 +00005249
5250 #[test]
5251 fn test_unbind_keys_for_user() -> Result<()> {
5252 let mut db = new_test_db()?;
5253 db.unbind_keys_for_user(1, false)?;
5254
5255 make_test_key_entry(&mut db, Domain::APP, 210000, TEST_ALIAS, None)?;
5256 make_test_key_entry(&mut db, Domain::APP, 110000, TEST_ALIAS, None)?;
5257 db.unbind_keys_for_user(2, false)?;
5258
Janis Danisevskis18313832021-05-17 13:30:32 -07005259 assert_eq!(1, db.list(Domain::APP, 110000, KeyType::Client)?.len());
5260 assert_eq!(0, db.list(Domain::APP, 210000, KeyType::Client)?.len());
Hasini Gunasingheda895552021-01-27 19:34:37 +00005261
5262 db.unbind_keys_for_user(1, true)?;
Janis Danisevskis18313832021-05-17 13:30:32 -07005263 assert_eq!(0, db.list(Domain::APP, 110000, KeyType::Client)?.len());
Hasini Gunasingheda895552021-01-27 19:34:37 +00005264
5265 Ok(())
5266 }
5267
5268 #[test]
5269 fn test_store_super_key() -> Result<()> {
5270 let mut db = new_test_db()?;
Paul Crowleyf61fee72021-03-17 14:38:44 -07005271 let pw: keystore2_crypto::Password = (&b"xyzabc"[..]).into();
Hasini Gunasingheda895552021-01-27 19:34:37 +00005272 let super_key = keystore2_crypto::generate_aes256_key()?;
Paul Crowley7a658392021-03-18 17:08:20 -07005273 let secret_bytes = b"keystore2 is great.";
Hasini Gunasingheda895552021-01-27 19:34:37 +00005274 let (encrypted_secret, iv, tag) =
Paul Crowley7a658392021-03-18 17:08:20 -07005275 keystore2_crypto::aes_gcm_encrypt(secret_bytes, &super_key)?;
Hasini Gunasingheda895552021-01-27 19:34:37 +00005276
5277 let (encrypted_super_key, metadata) =
5278 SuperKeyManager::encrypt_with_password(&super_key, &pw)?;
Paul Crowley8d5b2532021-03-19 10:53:07 -07005279 db.store_super_key(
5280 1,
5281 &USER_SUPER_KEY,
5282 &encrypted_super_key,
5283 &metadata,
5284 &KeyMetaData::new(),
5285 )?;
Hasini Gunasingheda895552021-01-27 19:34:37 +00005286
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00005287 //check if super key exists
Paul Crowley7a658392021-03-18 17:08:20 -07005288 assert!(db.key_exists(Domain::APP, 1, &USER_SUPER_KEY.alias, KeyType::Super)?);
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00005289
Paul Crowley7a658392021-03-18 17:08:20 -07005290 let (_, key_entry) = db.load_super_key(&USER_SUPER_KEY, 1)?.unwrap();
Paul Crowley8d5b2532021-03-19 10:53:07 -07005291 let loaded_super_key = SuperKeyManager::extract_super_key_from_key_entry(
5292 USER_SUPER_KEY.algorithm,
5293 key_entry,
5294 &pw,
5295 None,
5296 )?;
Hasini Gunasingheda895552021-01-27 19:34:37 +00005297
Paul Crowley7a658392021-03-18 17:08:20 -07005298 let decrypted_secret_bytes =
5299 loaded_super_key.aes_gcm_decrypt(&encrypted_secret, &iv, &tag)?;
5300 assert_eq!(secret_bytes, &*decrypted_secret_bytes);
Hasini Gunasingheda895552021-01-27 19:34:37 +00005301 Ok(())
5302 }
Seth Moore78c091f2021-04-09 21:38:30 +00005303
5304 fn get_valid_statsd_storage_types() -> Vec<StatsdStorageType> {
5305 vec![
5306 StatsdStorageType::KeyEntry,
5307 StatsdStorageType::KeyEntryIdIndex,
5308 StatsdStorageType::KeyEntryDomainNamespaceIndex,
5309 StatsdStorageType::BlobEntry,
5310 StatsdStorageType::BlobEntryKeyEntryIdIndex,
5311 StatsdStorageType::KeyParameter,
5312 StatsdStorageType::KeyParameterKeyEntryIdIndex,
5313 StatsdStorageType::KeyMetadata,
5314 StatsdStorageType::KeyMetadataKeyEntryIdIndex,
5315 StatsdStorageType::Grant,
5316 StatsdStorageType::AuthToken,
5317 StatsdStorageType::BlobMetadata,
5318 StatsdStorageType::BlobMetadataBlobEntryIdIndex,
5319 ]
5320 }
5321
5322 /// Perform a simple check to ensure that we can query all the storage types
5323 /// that are supported by the DB. Check for reasonable values.
5324 #[test]
5325 fn test_query_all_valid_table_sizes() -> Result<()> {
5326 const PAGE_SIZE: i64 = 4096;
5327
5328 let mut db = new_test_db()?;
5329
5330 for t in get_valid_statsd_storage_types() {
5331 let stat = db.get_storage_stat(t)?;
Matthew Maurerd7815ca2021-05-06 21:58:45 -07005332 // AuthToken can be less than a page since it's in a btree, not sqlite
5333 // TODO(b/187474736) stop using if-let here
5334 if let StatsdStorageType::AuthToken = t {
5335 } else {
5336 assert!(stat.size >= PAGE_SIZE);
5337 }
Seth Moore78c091f2021-04-09 21:38:30 +00005338 assert!(stat.size >= stat.unused_size);
5339 }
5340
5341 Ok(())
5342 }
5343
5344 fn get_storage_stats_map(db: &mut KeystoreDB) -> BTreeMap<i32, Keystore2StorageStats> {
5345 get_valid_statsd_storage_types()
5346 .into_iter()
5347 .map(|t| (t as i32, db.get_storage_stat(t).unwrap()))
5348 .collect()
5349 }
5350
5351 fn assert_storage_increased(
5352 db: &mut KeystoreDB,
5353 increased_storage_types: Vec<StatsdStorageType>,
5354 baseline: &mut BTreeMap<i32, Keystore2StorageStats>,
5355 ) {
5356 for storage in increased_storage_types {
5357 // Verify the expected storage increased.
5358 let new = db.get_storage_stat(storage).unwrap();
5359 let storage = storage as i32;
5360 let old = &baseline[&storage];
5361 assert!(new.size >= old.size, "{}: {} >= {}", storage, new.size, old.size);
5362 assert!(
5363 new.unused_size <= old.unused_size,
5364 "{}: {} <= {}",
5365 storage,
5366 new.unused_size,
5367 old.unused_size
5368 );
5369
5370 // Update the baseline with the new value so that it succeeds in the
5371 // later comparison.
5372 baseline.insert(storage, new);
5373 }
5374
5375 // Get an updated map of the storage and verify there were no unexpected changes.
5376 let updated_stats = get_storage_stats_map(db);
5377 assert_eq!(updated_stats.len(), baseline.len());
5378
5379 for &k in baseline.keys() {
5380 let stringify = |map: &BTreeMap<i32, Keystore2StorageStats>| -> String {
5381 let mut s = String::new();
5382 for &k in map.keys() {
5383 writeln!(&mut s, " {}: {}, {}", &k, map[&k].size, map[&k].unused_size)
5384 .expect("string concat failed");
5385 }
5386 s
5387 };
5388
5389 assert!(
5390 updated_stats[&k].size == baseline[&k].size
5391 && updated_stats[&k].unused_size == baseline[&k].unused_size,
5392 "updated_stats:\n{}\nbaseline:\n{}",
5393 stringify(&updated_stats),
5394 stringify(&baseline)
5395 );
5396 }
5397 }
5398
5399 #[test]
5400 fn test_verify_key_table_size_reporting() -> Result<()> {
5401 let mut db = new_test_db()?;
5402 let mut working_stats = get_storage_stats_map(&mut db);
5403
Janis Danisevskis0cabd712021-05-25 11:07:10 -07005404 let key_id = db.create_key_entry(&Domain::APP, &42, KeyType::Client, &KEYSTORE_UUID)?;
Seth Moore78c091f2021-04-09 21:38:30 +00005405 assert_storage_increased(
5406 &mut db,
5407 vec![
5408 StatsdStorageType::KeyEntry,
5409 StatsdStorageType::KeyEntryIdIndex,
5410 StatsdStorageType::KeyEntryDomainNamespaceIndex,
5411 ],
5412 &mut working_stats,
5413 );
5414
5415 let mut blob_metadata = BlobMetaData::new();
5416 blob_metadata.add(BlobMetaEntry::EncryptedBy(EncryptedBy::Password));
5417 db.set_blob(&key_id, SubComponentType::KEY_BLOB, Some(TEST_KEY_BLOB), None)?;
5418 assert_storage_increased(
5419 &mut db,
5420 vec![
5421 StatsdStorageType::BlobEntry,
5422 StatsdStorageType::BlobEntryKeyEntryIdIndex,
5423 StatsdStorageType::BlobMetadata,
5424 StatsdStorageType::BlobMetadataBlobEntryIdIndex,
5425 ],
5426 &mut working_stats,
5427 );
5428
5429 let params = make_test_params(None);
5430 db.insert_keyparameter(&key_id, &params)?;
5431 assert_storage_increased(
5432 &mut db,
5433 vec![StatsdStorageType::KeyParameter, StatsdStorageType::KeyParameterKeyEntryIdIndex],
5434 &mut working_stats,
5435 );
5436
5437 let mut metadata = KeyMetaData::new();
5438 metadata.add(KeyMetaEntry::CreationDate(DateTime::from_millis_epoch(123456789)));
5439 db.insert_key_metadata(&key_id, &metadata)?;
5440 assert_storage_increased(
5441 &mut db,
5442 vec![StatsdStorageType::KeyMetadata, StatsdStorageType::KeyMetadataKeyEntryIdIndex],
5443 &mut working_stats,
5444 );
5445
5446 let mut sum = 0;
5447 for stat in working_stats.values() {
5448 sum += stat.size;
5449 }
5450 let total = db.get_storage_stat(StatsdStorageType::Database)?.size;
5451 assert!(sum <= total, "Expected sum <= total. sum: {}, total: {}", sum, total);
5452
5453 Ok(())
5454 }
5455
5456 #[test]
5457 fn test_verify_auth_table_size_reporting() -> Result<()> {
5458 let mut db = new_test_db()?;
5459 let mut working_stats = get_storage_stats_map(&mut db);
5460 db.insert_auth_token(&HardwareAuthToken {
5461 challenge: 123,
5462 userId: 456,
5463 authenticatorId: 789,
5464 authenticatorType: kmhw_authenticator_type::ANY,
5465 timestamp: Timestamp { milliSeconds: 10 },
5466 mac: b"mac".to_vec(),
Matthew Maurerd7815ca2021-05-06 21:58:45 -07005467 });
Seth Moore78c091f2021-04-09 21:38:30 +00005468 assert_storage_increased(&mut db, vec![StatsdStorageType::AuthToken], &mut working_stats);
5469 Ok(())
5470 }
5471
5472 #[test]
5473 fn test_verify_grant_table_size_reporting() -> Result<()> {
5474 const OWNER: i64 = 1;
5475 let mut db = new_test_db()?;
5476 make_test_key_entry(&mut db, Domain::APP, OWNER, TEST_ALIAS, None)?;
5477
5478 let mut working_stats = get_storage_stats_map(&mut db);
5479 db.grant(
5480 &KeyDescriptor {
5481 domain: Domain::APP,
5482 nspace: 0,
5483 alias: Some(TEST_ALIAS.to_string()),
5484 blob: None,
5485 },
5486 OWNER as u32,
5487 123,
5488 key_perm_set![KeyPerm::use_()],
5489 |_, _| Ok(()),
5490 )?;
5491
5492 assert_storage_increased(&mut db, vec![StatsdStorageType::Grant], &mut working_stats);
5493
5494 Ok(())
5495 }
Matthew Maurerd7815ca2021-05-06 21:58:45 -07005496
5497 #[test]
5498 fn find_auth_token_entry_returns_latest() -> Result<()> {
5499 let mut db = new_test_db()?;
5500 db.insert_auth_token(&HardwareAuthToken {
5501 challenge: 123,
5502 userId: 456,
5503 authenticatorId: 789,
5504 authenticatorType: kmhw_authenticator_type::ANY,
5505 timestamp: Timestamp { milliSeconds: 10 },
5506 mac: b"mac0".to_vec(),
5507 });
5508 std::thread::sleep(std::time::Duration::from_millis(1));
5509 db.insert_auth_token(&HardwareAuthToken {
5510 challenge: 123,
5511 userId: 457,
5512 authenticatorId: 789,
5513 authenticatorType: kmhw_authenticator_type::ANY,
5514 timestamp: Timestamp { milliSeconds: 12 },
5515 mac: b"mac1".to_vec(),
5516 });
5517 std::thread::sleep(std::time::Duration::from_millis(1));
5518 db.insert_auth_token(&HardwareAuthToken {
5519 challenge: 123,
5520 userId: 458,
5521 authenticatorId: 789,
5522 authenticatorType: kmhw_authenticator_type::ANY,
5523 timestamp: Timestamp { milliSeconds: 3 },
5524 mac: b"mac2".to_vec(),
5525 });
5526 // All three entries are in the database
5527 assert_eq!(db.perboot.auth_tokens_len(), 3);
5528 // It selected the most recent timestamp
5529 assert_eq!(db.find_auth_token_entry(|_| true).unwrap().0.auth_token.mac, b"mac2".to_vec());
5530 Ok(())
5531 }
Seth Moore472fcbb2021-05-12 10:07:51 -07005532
5533 #[test]
5534 fn test_set_wal_mode() -> Result<()> {
5535 let temp_dir = TempDir::new("test_set_wal_mode")?;
5536 let mut db = KeystoreDB::new(temp_dir.path(), None)?;
5537 let mode: String =
5538 db.conn.pragma_query_value(Some(Attached("persistent")), "journal_mode", |row| {
5539 row.get(0)
5540 })?;
5541 assert_eq!(mode, "delete");
5542 db.conn.close().expect("Close didn't work");
5543
5544 KeystoreDB::set_wal_mode(temp_dir.path())?;
5545
5546 db = KeystoreDB::new(temp_dir.path(), None)?;
5547 let mode: String =
5548 db.conn.pragma_query_value(Some(Attached("persistent")), "journal_mode", |row| {
5549 row.get(0)
5550 })?;
5551 assert_eq!(mode, "wal");
5552 Ok(())
5553 }
Pavel Grafovf45034a2021-05-12 22:35:45 +01005554
5555 #[test]
5556 fn test_load_key_descriptor() -> Result<()> {
5557 let mut db = new_test_db()?;
5558 let key_id = make_test_key_entry(&mut db, Domain::APP, 1, TEST_ALIAS, None)?.0;
5559
5560 let key = db.load_key_descriptor(key_id)?.unwrap();
5561
5562 assert_eq!(key.domain, Domain::APP);
5563 assert_eq!(key.nspace, 1);
5564 assert_eq!(key.alias, Some(TEST_ALIAS.to_string()));
5565
5566 // No such id
5567 assert_eq!(db.load_key_descriptor(key_id + 1)?, None);
5568 Ok(())
5569 }
Joel Galenson26f4d012020-07-17 14:57:21 -07005570}