blob: 3d9cffecff874a65d041b73a3442c08261ac9cb8 [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
Janis Danisevskisb42fc182020-12-15 08:41:27 -080044use crate::impl_metadata; // This is in db_utils.rs
Janis Danisevskis4522c2b2020-11-27 18:04:58 -080045use crate::key_parameter::{KeyParameter, Tag};
Janis Danisevskisc5b210b2020-09-11 13:27:37 -070046use crate::permission::KeyPermSet;
Hasini Gunasingheda895552021-01-27 19:34:37 +000047use crate::utils::{get_current_time_in_seconds, AID_USER_OFFSET};
Janis Danisevskis7e8b4622021-02-13 10:01:59 -080048use crate::{
49 db_utils::{self, SqlField},
50 gc::Gc,
Paul Crowley7a658392021-03-18 17:08:20 -070051 super_key::USER_SUPER_KEY,
52};
53use crate::{
54 error::{Error as KsError, ErrorCode, ResponseCode},
55 super_key::SuperKeyType,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -080056};
Janis Danisevskisb42fc182020-12-15 08:41:27 -080057use anyhow::{anyhow, Context, Result};
Max Bires8e93d2b2021-01-14 13:17:59 -080058use std::{convert::TryFrom, convert::TryInto, ops::Deref, time::SystemTimeError};
Janis Danisevskis60400fe2020-08-26 15:24:42 -070059
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +000060use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
Janis Danisevskis5ed8c532021-01-11 14:19:42 -080061 HardwareAuthToken::HardwareAuthToken,
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +000062 HardwareAuthenticatorType::HardwareAuthenticatorType, SecurityLevel::SecurityLevel,
Janis Danisevskisc3a496b2021-01-05 10:37:22 -080063};
64use android_hardware_security_secureclock::aidl::android::hardware::security::secureclock::{
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +000065 Timestamp::Timestamp,
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +000066};
Janis Danisevskisc5b210b2020-09-11 13:27:37 -070067use android_system_keystore2::aidl::android::system::keystore2::{
Janis Danisevskis04b02832020-10-26 09:21:40 -070068 Domain::Domain, KeyDescriptor::KeyDescriptor,
Janis Danisevskis60400fe2020-08-26 15:24:42 -070069};
Max Bires2b2e6562020-09-22 11:22:36 -070070use android_security_remoteprovisioning::aidl::android::security::remoteprovisioning::{
71 AttestationPoolStatus::AttestationPoolStatus,
72};
73
74use keystore2_crypto::ZVec;
Janis Danisevskisaec14592020-11-12 09:41:49 -080075use lazy_static::lazy_static;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +000076use log::error;
Joel Galenson0891bc12020-07-20 10:37:03 -070077#[cfg(not(test))]
78use rand::prelude::random;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -070079use rusqlite::{
Janis Danisevskisb42fc182020-12-15 08:41:27 -080080 params,
81 types::FromSql,
82 types::FromSqlResult,
83 types::ToSqlOutput,
84 types::{FromSqlError, Value, ValueRef},
Janis Danisevskis5ed8c532021-01-11 14:19:42 -080085 Connection, OptionalExtension, ToSql, Transaction, TransactionBehavior, NO_PARAMS,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -070086};
Max Bires2b2e6562020-09-22 11:22:36 -070087
Janis Danisevskisaec14592020-11-12 09:41:49 -080088use std::{
Janis Danisevskisb42fc182020-12-15 08:41:27 -080089 collections::{HashMap, HashSet},
Janis Danisevskisbf15d732020-12-08 10:35:26 -080090 path::Path,
91 sync::{Condvar, Mutex},
Janis Danisevskisb42fc182020-12-15 08:41:27 -080092 time::{Duration, SystemTime},
Janis Danisevskisaec14592020-11-12 09:41:49 -080093};
Max Bires2b2e6562020-09-22 11:22:36 -070094
Joel Galenson0891bc12020-07-20 10:37:03 -070095#[cfg(test)]
96use tests::random;
Joel Galenson26f4d012020-07-17 14:57:21 -070097
Janis Danisevskisb42fc182020-12-15 08:41:27 -080098impl_metadata!(
99 /// A set of metadata for key entries.
100 #[derive(Debug, Default, Eq, PartialEq)]
101 pub struct KeyMetaData;
102 /// A metadata entry for key entries.
103 #[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
104 pub enum KeyMetaEntry {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800105 /// Date of the creation of the key entry.
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800106 CreationDate(DateTime) with accessor creation_date,
107 /// Expiration date for attestation keys.
108 AttestationExpirationDate(DateTime) with accessor attestation_expiration_date,
Max Bires2b2e6562020-09-22 11:22:36 -0700109 /// CBOR Blob that represents a COSE_Key and associated metadata needed for remote
110 /// provisioning
111 AttestationMacedPublicKey(Vec<u8>) with accessor attestation_maced_public_key,
112 /// Vector representing the raw public key so results from the server can be matched
113 /// to the right entry
114 AttestationRawPubKey(Vec<u8>) with accessor attestation_raw_pub_key,
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800115 // --- ADD NEW META DATA FIELDS HERE ---
116 // For backwards compatibility add new entries only to
117 // end of this list and above this comment.
118 };
119);
120
121impl KeyMetaData {
122 fn load_from_db(key_id: i64, tx: &Transaction) -> Result<Self> {
123 let mut stmt = tx
124 .prepare(
125 "SELECT tag, data from persistent.keymetadata
126 WHERE keyentryid = ?;",
127 )
128 .context("In KeyMetaData::load_from_db: prepare statement failed.")?;
129
130 let mut metadata: HashMap<i64, KeyMetaEntry> = Default::default();
131
132 let mut rows =
133 stmt.query(params![key_id]).context("In KeyMetaData::load_from_db: query failed.")?;
134 db_utils::with_rows_extract_all(&mut rows, |row| {
135 let db_tag: i64 = row.get(0).context("Failed to read tag.")?;
136 metadata.insert(
137 db_tag,
138 KeyMetaEntry::new_from_sql(db_tag, &SqlField::new(1, &row))
139 .context("Failed to read KeyMetaEntry.")?,
140 );
141 Ok(())
142 })
143 .context("In KeyMetaData::load_from_db.")?;
144
145 Ok(Self { data: metadata })
146 }
147
148 fn store_in_db(&self, key_id: i64, tx: &Transaction) -> Result<()> {
149 let mut stmt = tx
150 .prepare(
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000151 "INSERT or REPLACE INTO persistent.keymetadata (keyentryid, tag, data)
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800152 VALUES (?, ?, ?);",
153 )
154 .context("In KeyMetaData::store_in_db: Failed to prepare statement.")?;
155
156 let iter = self.data.iter();
157 for (tag, entry) in iter {
158 stmt.insert(params![key_id, tag, entry,]).with_context(|| {
159 format!("In KeyMetaData::store_in_db: Failed to insert {:?}", entry)
160 })?;
161 }
162 Ok(())
163 }
164}
165
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800166impl_metadata!(
167 /// A set of metadata for key blobs.
168 #[derive(Debug, Default, Eq, PartialEq)]
169 pub struct BlobMetaData;
170 /// A metadata entry for key blobs.
171 #[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
172 pub enum BlobMetaEntry {
173 /// If present, indicates that the blob is encrypted with another key or a key derived
174 /// from a password.
175 EncryptedBy(EncryptedBy) with accessor encrypted_by,
176 /// If the blob is password encrypted this field is set to the
177 /// salt used for the key derivation.
178 Salt(Vec<u8>) with accessor salt,
179 /// If the blob is encrypted, this field is set to the initialization vector.
180 Iv(Vec<u8>) with accessor iv,
181 /// If the blob is encrypted, this field holds the AEAD TAG.
182 AeadTag(Vec<u8>) with accessor aead_tag,
183 /// The uuid of the owning KeyMint instance.
184 KmUuid(Uuid) with accessor km_uuid,
185 // --- ADD NEW META DATA FIELDS HERE ---
186 // For backwards compatibility add new entries only to
187 // end of this list and above this comment.
188 };
189);
190
191impl BlobMetaData {
192 fn load_from_db(blob_id: i64, tx: &Transaction) -> Result<Self> {
193 let mut stmt = tx
194 .prepare(
195 "SELECT tag, data from persistent.blobmetadata
196 WHERE blobentryid = ?;",
197 )
198 .context("In BlobMetaData::load_from_db: prepare statement failed.")?;
199
200 let mut metadata: HashMap<i64, BlobMetaEntry> = Default::default();
201
202 let mut rows =
203 stmt.query(params![blob_id]).context("In BlobMetaData::load_from_db: query failed.")?;
204 db_utils::with_rows_extract_all(&mut rows, |row| {
205 let db_tag: i64 = row.get(0).context("Failed to read tag.")?;
206 metadata.insert(
207 db_tag,
208 BlobMetaEntry::new_from_sql(db_tag, &SqlField::new(1, &row))
209 .context("Failed to read BlobMetaEntry.")?,
210 );
211 Ok(())
212 })
213 .context("In BlobMetaData::load_from_db.")?;
214
215 Ok(Self { data: metadata })
216 }
217
218 fn store_in_db(&self, blob_id: i64, tx: &Transaction) -> Result<()> {
219 let mut stmt = tx
220 .prepare(
221 "INSERT or REPLACE INTO persistent.blobmetadata (blobentryid, tag, data)
222 VALUES (?, ?, ?);",
223 )
224 .context("In BlobMetaData::store_in_db: Failed to prepare statement.")?;
225
226 let iter = self.data.iter();
227 for (tag, entry) in iter {
228 stmt.insert(params![blob_id, tag, entry,]).with_context(|| {
229 format!("In BlobMetaData::store_in_db: Failed to insert {:?}", entry)
230 })?;
231 }
232 Ok(())
233 }
234}
235
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800236/// Indicates the type of the keyentry.
237#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
238pub enum KeyType {
239 /// This is a client key type. These keys are created or imported through the Keystore 2.0
240 /// AIDL interface android.system.keystore2.
241 Client,
242 /// This is a super key type. These keys are created by keystore itself and used to encrypt
243 /// other key blobs to provide LSKF binding.
244 Super,
245 /// This is an attestation key. These keys are created by the remote provisioning mechanism.
246 Attestation,
247}
248
249impl ToSql for KeyType {
250 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
251 Ok(ToSqlOutput::Owned(Value::Integer(match self {
252 KeyType::Client => 0,
253 KeyType::Super => 1,
254 KeyType::Attestation => 2,
255 })))
256 }
257}
258
259impl FromSql for KeyType {
260 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
261 match i64::column_result(value)? {
262 0 => Ok(KeyType::Client),
263 1 => Ok(KeyType::Super),
264 2 => Ok(KeyType::Attestation),
265 v => Err(FromSqlError::OutOfRange(v)),
266 }
267 }
268}
269
Max Bires8e93d2b2021-01-14 13:17:59 -0800270/// Uuid representation that can be stored in the database.
271/// Right now it can only be initialized from SecurityLevel.
272/// Once KeyMint provides a UUID type a corresponding From impl shall be added.
273#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
274pub struct Uuid([u8; 16]);
275
276impl Deref for Uuid {
277 type Target = [u8; 16];
278
279 fn deref(&self) -> &Self::Target {
280 &self.0
281 }
282}
283
284impl From<SecurityLevel> for Uuid {
285 fn from(sec_level: SecurityLevel) -> Self {
286 Self((sec_level.0 as u128).to_be_bytes())
287 }
288}
289
290impl ToSql for Uuid {
291 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
292 self.0.to_sql()
293 }
294}
295
296impl FromSql for Uuid {
297 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
298 let blob = Vec::<u8>::column_result(value)?;
299 if blob.len() != 16 {
300 return Err(FromSqlError::OutOfRange(blob.len() as i64));
301 }
302 let mut arr = [0u8; 16];
303 arr.copy_from_slice(&blob);
304 Ok(Self(arr))
305 }
306}
307
308/// Key entries that are not associated with any KeyMint instance, such as pure certificate
309/// entries are associated with this UUID.
310pub static KEYSTORE_UUID: Uuid = Uuid([
311 0x41, 0xe3, 0xb9, 0xce, 0x27, 0x58, 0x4e, 0x91, 0xbc, 0xfd, 0xa5, 0x5d, 0x91, 0x85, 0xab, 0x11,
312]);
313
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800314/// Indicates how the sensitive part of this key blob is encrypted.
315#[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
316pub enum EncryptedBy {
317 /// The keyblob is encrypted by a user password.
318 /// In the database this variant is represented as NULL.
319 Password,
320 /// The keyblob is encrypted by another key with wrapped key id.
321 /// In the database this variant is represented as non NULL value
322 /// that is convertible to i64, typically NUMERIC.
323 KeyId(i64),
324}
325
326impl ToSql for EncryptedBy {
327 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
328 match self {
329 Self::Password => Ok(ToSqlOutput::Owned(Value::Null)),
330 Self::KeyId(id) => id.to_sql(),
331 }
332 }
333}
334
335impl FromSql for EncryptedBy {
336 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
337 match value {
338 ValueRef::Null => Ok(Self::Password),
339 _ => Ok(Self::KeyId(i64::column_result(value)?)),
340 }
341 }
342}
343
344/// A database representation of wall clock time. DateTime stores unix epoch time as
345/// i64 in milliseconds.
346#[derive(Debug, Copy, Clone, Default, Eq, PartialEq, Ord, PartialOrd)]
347pub struct DateTime(i64);
348
349/// Error type returned when creating DateTime or converting it from and to
350/// SystemTime.
351#[derive(thiserror::Error, Debug)]
352pub enum DateTimeError {
353 /// This is returned when SystemTime and Duration computations fail.
354 #[error(transparent)]
355 SystemTimeError(#[from] SystemTimeError),
356
357 /// This is returned when type conversions fail.
358 #[error(transparent)]
359 TypeConversion(#[from] std::num::TryFromIntError),
360
361 /// This is returned when checked time arithmetic failed.
362 #[error("Time arithmetic failed.")]
363 TimeArithmetic,
364}
365
366impl DateTime {
367 /// Constructs a new DateTime object denoting the current time. This may fail during
368 /// conversion to unix epoch time and during conversion to the internal i64 representation.
369 pub fn now() -> Result<Self, DateTimeError> {
370 Ok(Self(SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_millis().try_into()?))
371 }
372
373 /// Constructs a new DateTime object from milliseconds.
374 pub fn from_millis_epoch(millis: i64) -> Self {
375 Self(millis)
376 }
377
378 /// Returns unix epoch time in milliseconds.
379 pub fn to_millis_epoch(&self) -> i64 {
380 self.0
381 }
382
383 /// Returns unix epoch time in seconds.
384 pub fn to_secs_epoch(&self) -> i64 {
385 self.0 / 1000
386 }
387}
388
389impl ToSql for DateTime {
390 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
391 Ok(ToSqlOutput::Owned(Value::Integer(self.0)))
392 }
393}
394
395impl FromSql for DateTime {
396 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
397 Ok(Self(i64::column_result(value)?))
398 }
399}
400
401impl TryInto<SystemTime> for DateTime {
402 type Error = DateTimeError;
403
404 fn try_into(self) -> Result<SystemTime, Self::Error> {
405 // We want to construct a SystemTime representation equivalent to self, denoting
406 // a point in time THEN, but we cannot set the time directly. We can only construct
407 // a SystemTime denoting NOW, and we can get the duration between EPOCH and NOW,
408 // and between EPOCH and THEN. With this common reference we can construct the
409 // duration between NOW and THEN which we can add to our SystemTime representation
410 // of NOW to get a SystemTime representation of THEN.
411 // Durations can only be positive, thus the if statement below.
412 let now = SystemTime::now();
413 let now_epoch = now.duration_since(SystemTime::UNIX_EPOCH)?;
414 let then_epoch = Duration::from_millis(self.0.try_into()?);
415 Ok(if now_epoch > then_epoch {
416 // then = now - (now_epoch - then_epoch)
417 now_epoch
418 .checked_sub(then_epoch)
419 .and_then(|d| now.checked_sub(d))
420 .ok_or(DateTimeError::TimeArithmetic)?
421 } else {
422 // then = now + (then_epoch - now_epoch)
423 then_epoch
424 .checked_sub(now_epoch)
425 .and_then(|d| now.checked_add(d))
426 .ok_or(DateTimeError::TimeArithmetic)?
427 })
428 }
429}
430
431impl TryFrom<SystemTime> for DateTime {
432 type Error = DateTimeError;
433
434 fn try_from(t: SystemTime) -> Result<Self, Self::Error> {
435 Ok(Self(t.duration_since(SystemTime::UNIX_EPOCH)?.as_millis().try_into()?))
436 }
437}
438
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800439#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone)]
440enum KeyLifeCycle {
441 /// Existing keys have a key ID but are not fully populated yet.
442 /// This is a transient state. If Keystore finds any such keys when it starts up, it must move
443 /// them to Unreferenced for garbage collection.
444 Existing,
445 /// A live key is fully populated and usable by clients.
446 Live,
447 /// An unreferenced key is scheduled for garbage collection.
448 Unreferenced,
449}
450
451impl ToSql for KeyLifeCycle {
452 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
453 match self {
454 Self::Existing => Ok(ToSqlOutput::Owned(Value::Integer(0))),
455 Self::Live => Ok(ToSqlOutput::Owned(Value::Integer(1))),
456 Self::Unreferenced => Ok(ToSqlOutput::Owned(Value::Integer(2))),
457 }
458 }
459}
460
461impl FromSql for KeyLifeCycle {
462 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
463 match i64::column_result(value)? {
464 0 => Ok(KeyLifeCycle::Existing),
465 1 => Ok(KeyLifeCycle::Live),
466 2 => Ok(KeyLifeCycle::Unreferenced),
467 v => Err(FromSqlError::OutOfRange(v)),
468 }
469 }
470}
471
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700472/// Keys have a KeyMint blob component and optional public certificate and
473/// certificate chain components.
474/// KeyEntryLoadBits is a bitmap that indicates to `KeystoreDB::load_key_entry`
475/// which components shall be loaded from the database if present.
Janis Danisevskis66784c42021-01-27 08:40:25 -0800476#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700477pub struct KeyEntryLoadBits(u32);
478
479impl KeyEntryLoadBits {
480 /// Indicate to `KeystoreDB::load_key_entry` that no component shall be loaded.
481 pub const NONE: KeyEntryLoadBits = Self(0);
482 /// Indicate to `KeystoreDB::load_key_entry` that the KeyMint component shall be loaded.
483 pub const KM: KeyEntryLoadBits = Self(1);
484 /// Indicate to `KeystoreDB::load_key_entry` that the Public components shall be loaded.
485 pub const PUBLIC: KeyEntryLoadBits = Self(2);
486 /// Indicate to `KeystoreDB::load_key_entry` that both components shall be loaded.
487 pub const BOTH: KeyEntryLoadBits = Self(3);
488
489 /// Returns true if this object indicates that the public components shall be loaded.
490 pub const fn load_public(&self) -> bool {
491 self.0 & Self::PUBLIC.0 != 0
492 }
493
494 /// Returns true if the object indicates that the KeyMint component shall be loaded.
495 pub const fn load_km(&self) -> bool {
496 self.0 & Self::KM.0 != 0
497 }
498}
499
Janis Danisevskisaec14592020-11-12 09:41:49 -0800500lazy_static! {
501 static ref KEY_ID_LOCK: KeyIdLockDb = KeyIdLockDb::new();
502}
503
504struct KeyIdLockDb {
505 locked_keys: Mutex<HashSet<i64>>,
506 cond_var: Condvar,
507}
508
509/// A locked key. While a guard exists for a given key id, the same key cannot be loaded
510/// from the database a second time. Most functions manipulating the key blob database
511/// require a KeyIdGuard.
512#[derive(Debug)]
513pub struct KeyIdGuard(i64);
514
515impl KeyIdLockDb {
516 fn new() -> Self {
517 Self { locked_keys: Mutex::new(HashSet::new()), cond_var: Condvar::new() }
518 }
519
520 /// This function blocks until an exclusive lock for the given key entry id can
521 /// be acquired. It returns a guard object, that represents the lifecycle of the
522 /// acquired lock.
523 pub fn get(&self, key_id: i64) -> KeyIdGuard {
524 let mut locked_keys = self.locked_keys.lock().unwrap();
525 while locked_keys.contains(&key_id) {
526 locked_keys = self.cond_var.wait(locked_keys).unwrap();
527 }
528 locked_keys.insert(key_id);
529 KeyIdGuard(key_id)
530 }
531
532 /// This function attempts to acquire an exclusive lock on a given key id. If the
533 /// given key id is already taken the function returns None immediately. If a lock
534 /// can be acquired this function returns a guard object, that represents the
535 /// lifecycle of the acquired lock.
536 pub fn try_get(&self, key_id: i64) -> Option<KeyIdGuard> {
537 let mut locked_keys = self.locked_keys.lock().unwrap();
538 if locked_keys.insert(key_id) {
539 Some(KeyIdGuard(key_id))
540 } else {
541 None
542 }
543 }
544}
545
546impl KeyIdGuard {
547 /// Get the numeric key id of the locked key.
548 pub fn id(&self) -> i64 {
549 self.0
550 }
551}
552
553impl Drop for KeyIdGuard {
554 fn drop(&mut self) {
555 let mut locked_keys = KEY_ID_LOCK.locked_keys.lock().unwrap();
556 locked_keys.remove(&self.0);
Janis Danisevskis7fd53582020-11-23 13:40:34 -0800557 drop(locked_keys);
Janis Danisevskisaec14592020-11-12 09:41:49 -0800558 KEY_ID_LOCK.cond_var.notify_all();
559 }
560}
561
Max Bires8e93d2b2021-01-14 13:17:59 -0800562/// This type represents a certificate and certificate chain entry for a key.
Max Bires2b2e6562020-09-22 11:22:36 -0700563#[derive(Debug, Default)]
Max Bires8e93d2b2021-01-14 13:17:59 -0800564pub struct CertificateInfo {
565 cert: Option<Vec<u8>>,
566 cert_chain: Option<Vec<u8>>,
567}
568
569impl CertificateInfo {
570 /// Constructs a new CertificateInfo object from `cert` and `cert_chain`
571 pub fn new(cert: Option<Vec<u8>>, cert_chain: Option<Vec<u8>>) -> Self {
572 Self { cert, cert_chain }
573 }
574
575 /// Take the cert
576 pub fn take_cert(&mut self) -> Option<Vec<u8>> {
577 self.cert.take()
578 }
579
580 /// Take the cert chain
581 pub fn take_cert_chain(&mut self) -> Option<Vec<u8>> {
582 self.cert_chain.take()
583 }
584}
585
Max Bires2b2e6562020-09-22 11:22:36 -0700586/// This type represents a certificate chain with a private key corresponding to the leaf
587/// 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 -0700588pub struct CertificateChain {
Max Bires97f96812021-02-23 23:44:57 -0800589 /// A KM key blob
590 pub private_key: ZVec,
591 /// A batch cert for private_key
592 pub batch_cert: Vec<u8>,
593 /// A full certificate chain from root signing authority to private_key, including batch_cert
594 /// for convenience.
595 pub cert_chain: Vec<u8>,
Max Bires2b2e6562020-09-22 11:22:36 -0700596}
597
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700598/// This type represents a Keystore 2.0 key entry.
599/// An entry has a unique `id` by which it can be found in the database.
600/// It has a security level field, key parameters, and three optional fields
601/// for the KeyMint blob, public certificate and a public certificate chain.
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800602#[derive(Debug, Default, Eq, PartialEq)]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700603pub struct KeyEntry {
604 id: i64,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800605 key_blob_info: Option<(Vec<u8>, BlobMetaData)>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700606 cert: Option<Vec<u8>>,
607 cert_chain: Option<Vec<u8>>,
Max Bires8e93d2b2021-01-14 13:17:59 -0800608 km_uuid: Uuid,
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700609 parameters: Vec<KeyParameter>,
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800610 metadata: KeyMetaData,
Janis Danisevskis377d1002021-01-27 19:07:48 -0800611 pure_cert: bool,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700612}
613
614impl KeyEntry {
615 /// Returns the unique id of the Key entry.
616 pub fn id(&self) -> i64 {
617 self.id
618 }
619 /// Exposes the optional KeyMint blob.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800620 pub fn key_blob_info(&self) -> &Option<(Vec<u8>, BlobMetaData)> {
621 &self.key_blob_info
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700622 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800623 /// Extracts the Optional KeyMint blob including its metadata.
624 pub fn take_key_blob_info(&mut self) -> Option<(Vec<u8>, BlobMetaData)> {
625 self.key_blob_info.take()
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700626 }
627 /// Exposes the optional public certificate.
628 pub fn cert(&self) -> &Option<Vec<u8>> {
629 &self.cert
630 }
631 /// Extracts the optional public certificate.
632 pub fn take_cert(&mut self) -> Option<Vec<u8>> {
633 self.cert.take()
634 }
635 /// Exposes the optional public certificate chain.
636 pub fn cert_chain(&self) -> &Option<Vec<u8>> {
637 &self.cert_chain
638 }
639 /// Extracts the optional public certificate_chain.
640 pub fn take_cert_chain(&mut self) -> Option<Vec<u8>> {
641 self.cert_chain.take()
642 }
Max Bires8e93d2b2021-01-14 13:17:59 -0800643 /// Returns the uuid of the owning KeyMint instance.
644 pub fn km_uuid(&self) -> &Uuid {
645 &self.km_uuid
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700646 }
Janis Danisevskis04b02832020-10-26 09:21:40 -0700647 /// Exposes the key parameters of this key entry.
648 pub fn key_parameters(&self) -> &Vec<KeyParameter> {
649 &self.parameters
650 }
651 /// Consumes this key entry and extracts the keyparameters from it.
652 pub fn into_key_parameters(self) -> Vec<KeyParameter> {
653 self.parameters
654 }
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800655 /// Exposes the key metadata of this key entry.
656 pub fn metadata(&self) -> &KeyMetaData {
657 &self.metadata
658 }
Janis Danisevskis377d1002021-01-27 19:07:48 -0800659 /// This returns true if the entry is a pure certificate entry with no
660 /// private key component.
661 pub fn pure_cert(&self) -> bool {
662 self.pure_cert
663 }
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000664 /// Consumes this key entry and extracts the keyparameters and metadata from it.
665 pub fn into_key_parameters_and_metadata(self) -> (Vec<KeyParameter>, KeyMetaData) {
666 (self.parameters, self.metadata)
667 }
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700668}
669
670/// Indicates the sub component of a key entry for persistent storage.
Janis Danisevskis377d1002021-01-27 19:07:48 -0800671#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700672pub struct SubComponentType(u32);
673impl SubComponentType {
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800674 /// Persistent identifier for a key blob.
675 pub const KEY_BLOB: SubComponentType = Self(0);
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700676 /// Persistent identifier for a certificate blob.
677 pub const CERT: SubComponentType = Self(1);
678 /// Persistent identifier for a certificate chain blob.
679 pub const CERT_CHAIN: SubComponentType = Self(2);
680}
681
682impl ToSql for SubComponentType {
683 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
684 self.0.to_sql()
685 }
686}
687
688impl FromSql for SubComponentType {
689 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
690 Ok(Self(u32::column_result(value)?))
691 }
692}
693
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800694/// This trait is private to the database module. It is used to convey whether or not the garbage
695/// collector shall be invoked after a database access. All closures passed to
696/// `KeystoreDB::with_transaction` return a tuple (bool, T) where the bool indicates if the
697/// gc needs to be triggered. This convenience function allows to turn any anyhow::Result<T>
698/// into anyhow::Result<(bool, T)> by simply appending one of `.do_gc(bool)`, `.no_gc()`, or
699/// `.need_gc()`.
700trait DoGc<T> {
701 fn do_gc(self, need_gc: bool) -> Result<(bool, T)>;
702
703 fn no_gc(self) -> Result<(bool, T)>;
704
705 fn need_gc(self) -> Result<(bool, T)>;
706}
707
708impl<T> DoGc<T> for Result<T> {
709 fn do_gc(self, need_gc: bool) -> Result<(bool, T)> {
710 self.map(|r| (need_gc, r))
711 }
712
713 fn no_gc(self) -> Result<(bool, T)> {
714 self.do_gc(false)
715 }
716
717 fn need_gc(self) -> Result<(bool, T)> {
718 self.do_gc(true)
719 }
720}
721
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700722/// KeystoreDB wraps a connection to an SQLite database and tracks its
723/// ownership. It also implements all of Keystore 2.0's database functionality.
Joel Galenson26f4d012020-07-17 14:57:21 -0700724pub struct KeystoreDB {
Joel Galenson26f4d012020-07-17 14:57:21 -0700725 conn: Connection,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800726 gc: Option<Gc>,
Joel Galenson26f4d012020-07-17 14:57:21 -0700727}
728
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000729/// Database representation of the monotonic time retrieved from the system call clock_gettime with
730/// CLOCK_MONOTONIC_RAW. Stores monotonic time as i64 in seconds.
731#[derive(Debug, Copy, Clone, Default, Eq, PartialEq, Ord, PartialOrd)]
732pub struct MonotonicRawTime(i64);
733
734impl MonotonicRawTime {
735 /// Constructs a new MonotonicRawTime
736 pub fn now() -> Self {
737 Self(get_current_time_in_seconds())
738 }
739
David Drysdale0e45a612021-02-25 17:24:36 +0000740 /// Constructs a new MonotonicRawTime from a given number of seconds.
741 pub fn from_secs(val: i64) -> Self {
742 Self(val)
743 }
744
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000745 /// Returns the integer value of MonotonicRawTime as i64
746 pub fn seconds(&self) -> i64 {
747 self.0
748 }
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800749
Hasini Gunasingheb3715fb2021-02-26 20:34:45 +0000750 /// Returns the value of MonotonicRawTime in milli seconds as i64
751 pub fn milli_seconds(&self) -> i64 {
752 self.0 * 1000
753 }
754
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800755 /// Like i64::checked_sub.
756 pub fn checked_sub(&self, other: &Self) -> Option<Self> {
757 self.0.checked_sub(other.0).map(Self)
758 }
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000759}
760
761impl ToSql for MonotonicRawTime {
762 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
763 Ok(ToSqlOutput::Owned(Value::Integer(self.0)))
764 }
765}
766
767impl FromSql for MonotonicRawTime {
768 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
769 Ok(Self(i64::column_result(value)?))
770 }
771}
772
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000773/// This struct encapsulates the information to be stored in the database about the auth tokens
774/// received by keystore.
775pub struct AuthTokenEntry {
776 auth_token: HardwareAuthToken,
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000777 time_received: MonotonicRawTime,
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000778}
779
780impl AuthTokenEntry {
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000781 fn new(auth_token: HardwareAuthToken, time_received: MonotonicRawTime) -> Self {
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000782 AuthTokenEntry { auth_token, time_received }
783 }
784
785 /// Checks if this auth token satisfies the given authentication information.
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800786 pub fn satisfies(&self, user_secure_ids: &[i64], auth_type: HardwareAuthenticatorType) -> bool {
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000787 user_secure_ids.iter().any(|&sid| {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800788 (sid == self.auth_token.userId || sid == self.auth_token.authenticatorId)
789 && (((auth_type.0 as i32) & (self.auth_token.authenticatorType.0 as i32)) != 0)
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000790 })
791 }
792
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000793 /// Returns the auth token wrapped by the AuthTokenEntry
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800794 pub fn auth_token(&self) -> &HardwareAuthToken {
795 &self.auth_token
796 }
797
798 /// Returns the auth token wrapped by the AuthTokenEntry
799 pub fn take_auth_token(self) -> HardwareAuthToken {
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000800 self.auth_token
801 }
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800802
803 /// Returns the time that this auth token was received.
804 pub fn time_received(&self) -> MonotonicRawTime {
805 self.time_received
806 }
Hasini Gunasingheb3715fb2021-02-26 20:34:45 +0000807
808 /// Returns the challenge value of the auth token.
809 pub fn challenge(&self) -> i64 {
810 self.auth_token.challenge
811 }
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000812}
813
Janis Danisevskisb00ebd02021-02-02 21:52:24 -0800814/// Shared in-memory databases get destroyed as soon as the last connection to them gets closed.
815/// This object does not allow access to the database connection. But it keeps a database
816/// connection alive in order to keep the in memory per boot database alive.
817pub struct PerBootDbKeepAlive(Connection);
818
Joel Galenson26f4d012020-07-17 14:57:21 -0700819impl KeystoreDB {
Janis Danisevskiseed69842021-02-18 20:04:10 -0800820 const UNASSIGNED_KEY_ID: i64 = -1i64;
Janis Danisevskisb00ebd02021-02-02 21:52:24 -0800821 const PERBOOT_DB_FILE_NAME: &'static str = &"file:perboot.sqlite?mode=memory&cache=shared";
822
823 /// This creates a PerBootDbKeepAlive object to keep the per boot database alive.
824 pub fn keep_perboot_db_alive() -> Result<PerBootDbKeepAlive> {
825 let conn = Connection::open_in_memory()
826 .context("In keep_perboot_db_alive: Failed to initialize SQLite connection.")?;
827
828 conn.execute("ATTACH DATABASE ? as perboot;", params![Self::PERBOOT_DB_FILE_NAME])
829 .context("In keep_perboot_db_alive: Failed to attach database perboot.")?;
830 Ok(PerBootDbKeepAlive(conn))
831 }
832
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700833 /// This will create a new database connection connecting the two
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800834 /// files persistent.sqlite and perboot.sqlite in the given directory.
835 /// It also attempts to initialize all of the tables.
836 /// KeystoreDB cannot be used by multiple threads.
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700837 /// Each thread should open their own connection using `thread_local!`.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800838 pub fn new(db_root: &Path, gc: Option<Gc>) -> Result<Self> {
Janis Danisevskisb00ebd02021-02-02 21:52:24 -0800839 // Build the path to the sqlite file.
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800840 let mut persistent_path = db_root.to_path_buf();
841 persistent_path.push("persistent.sqlite");
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700842
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800843 // Now convert them to strings prefixed with "file:"
844 let mut persistent_path_str = "file:".to_owned();
845 persistent_path_str.push_str(&persistent_path.to_string_lossy());
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800846
Janis Danisevskisb00ebd02021-02-02 21:52:24 -0800847 let conn = Self::make_connection(&persistent_path_str, &Self::PERBOOT_DB_FILE_NAME)?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800848
Janis Danisevskis66784c42021-01-27 08:40:25 -0800849 // On busy fail Immediately. It is unlikely to succeed given a bug in sqlite.
850 conn.busy_handler(None).context("In KeystoreDB::new: Failed to set busy handler.")?;
851
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800852 let mut db = Self { conn, gc };
Janis Danisevskis66784c42021-01-27 08:40:25 -0800853 db.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800854 Self::init_tables(tx).context("Trying to initialize tables.").no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -0800855 })?;
856 Ok(db)
Joel Galenson2aab4432020-07-22 15:27:57 -0700857 }
858
Janis Danisevskis66784c42021-01-27 08:40:25 -0800859 fn init_tables(tx: &Transaction) -> Result<()> {
860 tx.execute(
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700861 "CREATE TABLE IF NOT EXISTS persistent.keyentry (
Joel Galenson0891bc12020-07-20 10:37:03 -0700862 id INTEGER UNIQUE,
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800863 key_type INTEGER,
Joel Galenson0891bc12020-07-20 10:37:03 -0700864 domain INTEGER,
865 namespace INTEGER,
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800866 alias BLOB,
Max Bires8e93d2b2021-01-14 13:17:59 -0800867 state INTEGER,
868 km_uuid BLOB);",
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700869 NO_PARAMS,
870 )
871 .context("Failed to initialize \"keyentry\" table.")?;
872
Janis Danisevskis66784c42021-01-27 08:40:25 -0800873 tx.execute(
Janis Danisevskisa5438182021-02-02 14:22:59 -0800874 "CREATE INDEX IF NOT EXISTS persistent.keyentry_id_index
875 ON keyentry(id);",
876 NO_PARAMS,
877 )
878 .context("Failed to create index keyentry_id_index.")?;
879
880 tx.execute(
881 "CREATE INDEX IF NOT EXISTS persistent.keyentry_domain_namespace_index
882 ON keyentry(domain, namespace, alias);",
883 NO_PARAMS,
884 )
885 .context("Failed to create index keyentry_domain_namespace_index.")?;
886
887 tx.execute(
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700888 "CREATE TABLE IF NOT EXISTS persistent.blobentry (
889 id INTEGER PRIMARY KEY,
890 subcomponent_type INTEGER,
891 keyentryid INTEGER,
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800892 blob BLOB);",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700893 NO_PARAMS,
894 )
895 .context("Failed to initialize \"blobentry\" table.")?;
896
Janis Danisevskis66784c42021-01-27 08:40:25 -0800897 tx.execute(
Janis Danisevskisa5438182021-02-02 14:22:59 -0800898 "CREATE INDEX IF NOT EXISTS persistent.blobentry_keyentryid_index
899 ON blobentry(keyentryid);",
900 NO_PARAMS,
901 )
902 .context("Failed to create index blobentry_keyentryid_index.")?;
903
904 tx.execute(
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800905 "CREATE TABLE IF NOT EXISTS persistent.blobmetadata (
906 id INTEGER PRIMARY KEY,
907 blobentryid INTEGER,
908 tag INTEGER,
909 data ANY,
910 UNIQUE (blobentryid, tag));",
911 NO_PARAMS,
912 )
913 .context("Failed to initialize \"blobmetadata\" table.")?;
914
915 tx.execute(
916 "CREATE INDEX IF NOT EXISTS persistent.blobmetadata_blobentryid_index
917 ON blobmetadata(blobentryid);",
918 NO_PARAMS,
919 )
920 .context("Failed to create index blobmetadata_blobentryid_index.")?;
921
922 tx.execute(
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700923 "CREATE TABLE IF NOT EXISTS persistent.keyparameter (
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000924 keyentryid INTEGER,
925 tag INTEGER,
926 data ANY,
927 security_level INTEGER);",
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700928 NO_PARAMS,
929 )
930 .context("Failed to initialize \"keyparameter\" table.")?;
931
Janis Danisevskis66784c42021-01-27 08:40:25 -0800932 tx.execute(
Janis Danisevskisa5438182021-02-02 14:22:59 -0800933 "CREATE INDEX IF NOT EXISTS persistent.keyparameter_keyentryid_index
934 ON keyparameter(keyentryid);",
935 NO_PARAMS,
936 )
937 .context("Failed to create index keyparameter_keyentryid_index.")?;
938
939 tx.execute(
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800940 "CREATE TABLE IF NOT EXISTS persistent.keymetadata (
941 keyentryid INTEGER,
942 tag INTEGER,
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000943 data ANY,
944 UNIQUE (keyentryid, tag));",
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800945 NO_PARAMS,
946 )
947 .context("Failed to initialize \"keymetadata\" table.")?;
948
Janis Danisevskis66784c42021-01-27 08:40:25 -0800949 tx.execute(
Janis Danisevskisa5438182021-02-02 14:22:59 -0800950 "CREATE INDEX IF NOT EXISTS persistent.keymetadata_keyentryid_index
951 ON keymetadata(keyentryid);",
952 NO_PARAMS,
953 )
954 .context("Failed to create index keymetadata_keyentryid_index.")?;
955
956 tx.execute(
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800957 "CREATE TABLE IF NOT EXISTS persistent.grant (
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700958 id INTEGER UNIQUE,
959 grantee INTEGER,
960 keyentryid INTEGER,
961 access_vector INTEGER);",
962 NO_PARAMS,
963 )
964 .context("Failed to initialize \"grant\" table.")?;
965
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000966 //TODO: only drop the following two perboot tables if this is the first start up
967 //during the boot (b/175716626).
Janis Danisevskis66784c42021-01-27 08:40:25 -0800968 // tx.execute("DROP TABLE IF EXISTS perboot.authtoken;", NO_PARAMS)
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000969 // .context("Failed to drop perboot.authtoken table")?;
Janis Danisevskis66784c42021-01-27 08:40:25 -0800970 tx.execute(
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000971 "CREATE TABLE IF NOT EXISTS perboot.authtoken (
972 id INTEGER PRIMARY KEY,
973 challenge INTEGER,
974 user_id INTEGER,
975 auth_id INTEGER,
976 authenticator_type INTEGER,
977 timestamp INTEGER,
978 mac BLOB,
979 time_received INTEGER,
980 UNIQUE(user_id, auth_id, authenticator_type));",
981 NO_PARAMS,
982 )
983 .context("Failed to initialize \"authtoken\" table.")?;
984
Janis Danisevskis66784c42021-01-27 08:40:25 -0800985 // tx.execute("DROP TABLE IF EXISTS perboot.metadata;", NO_PARAMS)
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000986 // .context("Failed to drop perboot.metadata table")?;
987 // metadata table stores certain miscellaneous information required for keystore functioning
988 // during a boot cycle, as key-value pairs.
Janis Danisevskis66784c42021-01-27 08:40:25 -0800989 tx.execute(
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000990 "CREATE TABLE IF NOT EXISTS perboot.metadata (
991 key TEXT,
992 value BLOB,
993 UNIQUE(key));",
994 NO_PARAMS,
995 )
996 .context("Failed to initialize \"metadata\" table.")?;
Joel Galenson0891bc12020-07-20 10:37:03 -0700997 Ok(())
998 }
999
Janis Danisevskis4df44f42020-08-26 14:40:03 -07001000 fn make_connection(persistent_file: &str, perboot_file: &str) -> Result<Connection> {
1001 let conn =
1002 Connection::open_in_memory().context("Failed to initialize SQLite connection.")?;
1003
Janis Danisevskis66784c42021-01-27 08:40:25 -08001004 loop {
1005 if let Err(e) = conn
1006 .execute("ATTACH DATABASE ? as persistent;", params![persistent_file])
1007 .context("Failed to attach database persistent.")
1008 {
1009 if Self::is_locked_error(&e) {
1010 std::thread::sleep(std::time::Duration::from_micros(500));
1011 continue;
1012 } else {
1013 return Err(e);
1014 }
1015 }
1016 break;
1017 }
1018 loop {
1019 if let Err(e) = conn
1020 .execute("ATTACH DATABASE ? as perboot;", params![perboot_file])
1021 .context("Failed to attach database perboot.")
1022 {
1023 if Self::is_locked_error(&e) {
1024 std::thread::sleep(std::time::Duration::from_micros(500));
1025 continue;
1026 } else {
1027 return Err(e);
1028 }
1029 }
1030 break;
1031 }
Janis Danisevskis4df44f42020-08-26 14:40:03 -07001032
1033 Ok(conn)
1034 }
1035
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001036 /// This function is intended to be used by the garbage collector.
1037 /// It deletes the blob given by `blob_id_to_delete`. It then tries to find a superseded
1038 /// key blob that might need special handling by the garbage collector.
1039 /// If no further superseded blobs can be found it deletes all other superseded blobs that don't
1040 /// need special handling and returns None.
1041 pub fn handle_next_superseded_blob(
1042 &mut self,
1043 blob_id_to_delete: Option<i64>,
1044 ) -> Result<Option<(i64, Vec<u8>, BlobMetaData)>> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001045 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001046 // Delete the given blob if one was given.
1047 if let Some(blob_id_to_delete) = blob_id_to_delete {
1048 tx.execute(
1049 "DELETE FROM persistent.blobmetadata WHERE blobentryid = ?;",
1050 params![blob_id_to_delete],
1051 )
1052 .context("Trying to delete blob metadata.")?;
1053 tx.execute(
1054 "DELETE FROM persistent.blobentry WHERE id = ?;",
1055 params![blob_id_to_delete],
1056 )
1057 .context("Trying to blob.")?;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001058 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001059
1060 // Find another superseded keyblob load its metadata and return it.
1061 if let Some((blob_id, blob)) = tx
1062 .query_row(
1063 "SELECT id, blob FROM persistent.blobentry
1064 WHERE subcomponent_type = ?
1065 AND (
1066 id NOT IN (
1067 SELECT MAX(id) FROM persistent.blobentry
1068 WHERE subcomponent_type = ?
1069 GROUP BY keyentryid, subcomponent_type
1070 )
1071 OR keyentryid NOT IN (SELECT id FROM persistent.keyentry)
1072 );",
1073 params![SubComponentType::KEY_BLOB, SubComponentType::KEY_BLOB],
1074 |row| Ok((row.get(0)?, row.get(1)?)),
1075 )
1076 .optional()
1077 .context("Trying to query superseded blob.")?
1078 {
1079 let blob_metadata = BlobMetaData::load_from_db(blob_id, tx)
1080 .context("Trying to load blob metadata.")?;
1081 return Ok(Some((blob_id, blob, blob_metadata))).no_gc();
1082 }
1083
1084 // We did not find any superseded key blob, so let's remove other superseded blob in
1085 // one transaction.
1086 tx.execute(
1087 "DELETE FROM persistent.blobentry
1088 WHERE NOT subcomponent_type = ?
1089 AND (
1090 id NOT IN (
1091 SELECT MAX(id) FROM persistent.blobentry
1092 WHERE NOT subcomponent_type = ?
1093 GROUP BY keyentryid, subcomponent_type
1094 ) OR keyentryid NOT IN (SELECT id FROM persistent.keyentry)
1095 );",
1096 params![SubComponentType::KEY_BLOB, SubComponentType::KEY_BLOB],
1097 )
1098 .context("Trying to purge superseded blobs.")?;
1099
1100 Ok(None).no_gc()
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001101 })
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001102 .context("In handle_next_superseded_blob.")
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001103 }
1104
1105 /// This maintenance function should be called only once before the database is used for the
1106 /// first time. It restores the invariant that `KeyLifeCycle::Existing` is a transient state.
1107 /// The function transitions all key entries from Existing to Unreferenced unconditionally and
1108 /// returns the number of rows affected. If this returns a value greater than 0, it means that
1109 /// Keystore crashed at some point during key generation. Callers may want to log such
1110 /// occurrences.
1111 /// Unlike with `mark_unreferenced`, we don't need to purge grants, because only keys that made
1112 /// it to `KeyLifeCycle::Live` may have grants.
1113 pub fn cleanup_leftovers(&mut self) -> Result<usize> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001114 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1115 tx.execute(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001116 "UPDATE persistent.keyentry SET state = ? WHERE state = ?;",
1117 params![KeyLifeCycle::Unreferenced, KeyLifeCycle::Existing],
1118 )
Janis Danisevskis66784c42021-01-27 08:40:25 -08001119 .context("Failed to execute query.")
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001120 .need_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08001121 })
1122 .context("In cleanup_leftovers.")
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001123 }
1124
Hasini Gunasinghe0e161452021-01-27 19:34:37 +00001125 /// Checks if a key exists with given key type and key descriptor properties.
1126 pub fn key_exists(
1127 &mut self,
1128 domain: Domain,
1129 nspace: i64,
1130 alias: &str,
1131 key_type: KeyType,
1132 ) -> Result<bool> {
1133 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1134 let key_descriptor =
1135 KeyDescriptor { domain, nspace, alias: Some(alias.to_string()), blob: None };
1136 let result = Self::load_key_entry_id(&tx, &key_descriptor, key_type);
1137 match result {
1138 Ok(_) => Ok(true),
1139 Err(error) => match error.root_cause().downcast_ref::<KsError>() {
1140 Some(KsError::Rc(ResponseCode::KEY_NOT_FOUND)) => Ok(false),
1141 _ => Err(error).context("In key_exists: Failed to find if the key exists."),
1142 },
1143 }
1144 .no_gc()
1145 })
1146 .context("In key_exists.")
1147 }
1148
Hasini Gunasingheda895552021-01-27 19:34:37 +00001149 /// Stores a super key in the database.
1150 pub fn store_super_key(
1151 &mut self,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +00001152 user_id: u32,
Paul Crowley7a658392021-03-18 17:08:20 -07001153 key_type: &SuperKeyType,
1154 blob: &[u8],
1155 blob_metadata: &BlobMetaData,
Hasini Gunasingheda895552021-01-27 19:34:37 +00001156 ) -> Result<KeyEntry> {
1157 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1158 let key_id = Self::insert_with_retry(|id| {
1159 tx.execute(
1160 "INSERT into persistent.keyentry
1161 (id, key_type, domain, namespace, alias, state, km_uuid)
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00001162 VALUES(?, ?, ?, ?, ?, ?, ?);",
Hasini Gunasingheda895552021-01-27 19:34:37 +00001163 params![
1164 id,
1165 KeyType::Super,
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00001166 Domain::APP.0,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +00001167 user_id as i64,
Paul Crowley7a658392021-03-18 17:08:20 -07001168 key_type.alias,
Hasini Gunasingheda895552021-01-27 19:34:37 +00001169 KeyLifeCycle::Live,
1170 &KEYSTORE_UUID,
1171 ],
1172 )
1173 })
1174 .context("Failed to insert into keyentry table.")?;
1175
Hasini Gunasingheda895552021-01-27 19:34:37 +00001176 Self::set_blob_internal(
1177 &tx,
1178 key_id,
1179 SubComponentType::KEY_BLOB,
1180 Some(blob),
1181 Some(blob_metadata),
1182 )
1183 .context("Failed to store key blob.")?;
1184
1185 Self::load_key_components(tx, KeyEntryLoadBits::KM, key_id)
1186 .context("Trying to load key components.")
1187 .no_gc()
1188 })
1189 .context("In store_super_key.")
1190 }
1191
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +00001192 /// Loads super key of a given user, if exists
Paul Crowley7a658392021-03-18 17:08:20 -07001193 pub fn load_super_key(
1194 &mut self,
1195 key_type: &SuperKeyType,
1196 user_id: u32,
1197 ) -> Result<Option<(KeyIdGuard, KeyEntry)>> {
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +00001198 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1199 let key_descriptor = KeyDescriptor {
1200 domain: Domain::APP,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +00001201 nspace: user_id as i64,
Paul Crowley7a658392021-03-18 17:08:20 -07001202 alias: Some(key_type.alias.into()),
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +00001203 blob: None,
1204 };
1205 let id = Self::load_key_entry_id(&tx, &key_descriptor, KeyType::Super);
1206 match id {
1207 Ok(id) => {
1208 let key_entry = Self::load_key_components(&tx, KeyEntryLoadBits::KM, id)
1209 .context("In load_super_key. Failed to load key entry.")?;
1210 Ok(Some((KEY_ID_LOCK.get(id), key_entry)))
1211 }
1212 Err(error) => match error.root_cause().downcast_ref::<KsError>() {
1213 Some(KsError::Rc(ResponseCode::KEY_NOT_FOUND)) => Ok(None),
1214 _ => Err(error).context("In load_super_key."),
1215 },
1216 }
1217 .no_gc()
1218 })
1219 .context("In load_super_key.")
1220 }
1221
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001222 /// Atomically loads a key entry and associated metadata or creates it using the
1223 /// callback create_new_key callback. The callback is called during a database
1224 /// transaction. This means that implementers should be mindful about using
1225 /// blocking operations such as IPC or grabbing mutexes.
1226 pub fn get_or_create_key_with<F>(
1227 &mut self,
1228 domain: Domain,
1229 namespace: i64,
1230 alias: &str,
Max Bires8e93d2b2021-01-14 13:17:59 -08001231 km_uuid: Uuid,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001232 create_new_key: F,
1233 ) -> Result<(KeyIdGuard, KeyEntry)>
1234 where
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001235 F: Fn() -> Result<(Vec<u8>, BlobMetaData)>,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001236 {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001237 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1238 let id = {
1239 let mut stmt = tx
1240 .prepare(
1241 "SELECT id FROM persistent.keyentry
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001242 WHERE
1243 key_type = ?
1244 AND domain = ?
1245 AND namespace = ?
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001246 AND alias = ?
1247 AND state = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08001248 )
1249 .context("In get_or_create_key_with: Failed to select from keyentry table.")?;
1250 let mut rows = stmt
1251 .query(params![KeyType::Super, domain.0, namespace, alias, KeyLifeCycle::Live])
1252 .context("In get_or_create_key_with: Failed to query from keyentry table.")?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001253
Janis Danisevskis66784c42021-01-27 08:40:25 -08001254 db_utils::with_rows_extract_one(&mut rows, |row| {
1255 Ok(match row {
1256 Some(r) => r.get(0).context("Failed to unpack id.")?,
1257 None => None,
1258 })
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001259 })
Janis Danisevskis66784c42021-01-27 08:40:25 -08001260 .context("In get_or_create_key_with.")?
1261 };
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001262
Janis Danisevskis66784c42021-01-27 08:40:25 -08001263 let (id, entry) = match id {
1264 Some(id) => (
1265 id,
1266 Self::load_key_components(&tx, KeyEntryLoadBits::KM, id)
1267 .context("In get_or_create_key_with.")?,
1268 ),
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001269
Janis Danisevskis66784c42021-01-27 08:40:25 -08001270 None => {
1271 let id = Self::insert_with_retry(|id| {
1272 tx.execute(
1273 "INSERT into persistent.keyentry
Max Bires8e93d2b2021-01-14 13:17:59 -08001274 (id, key_type, domain, namespace, alias, state, km_uuid)
1275 VALUES(?, ?, ?, ?, ?, ?, ?);",
Janis Danisevskis66784c42021-01-27 08:40:25 -08001276 params![
1277 id,
1278 KeyType::Super,
1279 domain.0,
1280 namespace,
1281 alias,
1282 KeyLifeCycle::Live,
1283 km_uuid,
1284 ],
1285 )
1286 })
1287 .context("In get_or_create_key_with.")?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001288
Janis Danisevskis66784c42021-01-27 08:40:25 -08001289 let (blob, metadata) =
1290 create_new_key().context("In get_or_create_key_with.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001291 Self::set_blob_internal(
1292 &tx,
1293 id,
1294 SubComponentType::KEY_BLOB,
1295 Some(&blob),
1296 Some(&metadata),
1297 )
Paul Crowley7a658392021-03-18 17:08:20 -07001298 .context("In get_or_create_key_with.")?;
Janis Danisevskis66784c42021-01-27 08:40:25 -08001299 (
Janis Danisevskis377d1002021-01-27 19:07:48 -08001300 id,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001301 KeyEntry {
1302 id,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001303 key_blob_info: Some((blob, metadata)),
Janis Danisevskis66784c42021-01-27 08:40:25 -08001304 pure_cert: false,
1305 ..Default::default()
1306 },
1307 )
1308 }
1309 };
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001310 Ok((KEY_ID_LOCK.get(id), entry)).no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08001311 })
1312 .context("In get_or_create_key_with.")
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001313 }
1314
Janis Danisevskis66784c42021-01-27 08:40:25 -08001315 /// SQLite3 seems to hold a shared mutex while running the busy handler when
1316 /// waiting for the database file to become available. This makes it
1317 /// impossible to successfully recover from a locked database when the
1318 /// transaction holding the device busy is in the same process on a
1319 /// different connection. As a result the busy handler has to time out and
1320 /// fail in order to make progress.
1321 ///
1322 /// Instead, we set the busy handler to None (return immediately). And catch
1323 /// Busy and Locked errors (the latter occur on in memory databases with
1324 /// shared cache, e.g., the per-boot database.) and restart the transaction
1325 /// after a grace period of half a millisecond.
1326 ///
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001327 /// Creates a transaction with the given behavior and executes f with the new transaction.
Janis Danisevskis66784c42021-01-27 08:40:25 -08001328 /// The transaction is committed only if f returns Ok and retried if DatabaseBusy
1329 /// or DatabaseLocked is encountered.
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001330 fn with_transaction<T, F>(&mut self, behavior: TransactionBehavior, f: F) -> Result<T>
1331 where
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001332 F: Fn(&Transaction) -> Result<(bool, T)>,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001333 {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001334 loop {
1335 match self
1336 .conn
1337 .transaction_with_behavior(behavior)
1338 .context("In with_transaction.")
1339 .and_then(|tx| f(&tx).map(|result| (result, tx)))
1340 .and_then(|(result, tx)| {
1341 tx.commit().context("In with_transaction: Failed to commit transaction.")?;
1342 Ok(result)
1343 }) {
1344 Ok(result) => break Ok(result),
1345 Err(e) => {
1346 if Self::is_locked_error(&e) {
1347 std::thread::sleep(std::time::Duration::from_micros(500));
1348 continue;
1349 } else {
1350 return Err(e).context("In with_transaction.");
1351 }
1352 }
1353 }
1354 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001355 .map(|(need_gc, result)| {
1356 if need_gc {
1357 if let Some(ref gc) = self.gc {
1358 gc.notify_gc();
1359 }
1360 }
1361 result
1362 })
Janis Danisevskis66784c42021-01-27 08:40:25 -08001363 }
1364
1365 fn is_locked_error(e: &anyhow::Error) -> bool {
Paul Crowleyf61fee72021-03-17 14:38:44 -07001366 matches!(
1367 e.root_cause().downcast_ref::<rusqlite::ffi::Error>(),
1368 Some(rusqlite::ffi::Error { code: rusqlite::ErrorCode::DatabaseBusy, .. })
1369 | Some(rusqlite::ffi::Error { code: rusqlite::ErrorCode::DatabaseLocked, .. })
1370 )
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001371 }
1372
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001373 /// Creates a new key entry and allocates a new randomized id for the new key.
1374 /// The key id gets associated with a domain and namespace but not with an alias.
1375 /// To complete key generation `rebind_alias` should be called after all of the
1376 /// key artifacts, i.e., blobs and parameters have been associated with the new
1377 /// key id. Finalizing with `rebind_alias` makes the creation of a new key entry
1378 /// atomic even if key generation is not.
Max Bires8e93d2b2021-01-14 13:17:59 -08001379 pub fn create_key_entry(
1380 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001381 domain: &Domain,
1382 namespace: &i64,
Max Bires8e93d2b2021-01-14 13:17:59 -08001383 km_uuid: &Uuid,
1384 ) -> Result<KeyIdGuard> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001385 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001386 Self::create_key_entry_internal(tx, domain, namespace, km_uuid).no_gc()
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001387 })
1388 .context("In create_key_entry.")
1389 }
1390
1391 fn create_key_entry_internal(
1392 tx: &Transaction,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001393 domain: &Domain,
1394 namespace: &i64,
Max Bires8e93d2b2021-01-14 13:17:59 -08001395 km_uuid: &Uuid,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001396 ) -> Result<KeyIdGuard> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001397 match *domain {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001398 Domain::APP | Domain::SELINUX => {}
Joel Galenson0891bc12020-07-20 10:37:03 -07001399 _ => {
1400 return Err(KsError::sys())
1401 .context(format!("Domain {:?} must be either App or SELinux.", domain));
1402 }
1403 }
Janis Danisevskisaec14592020-11-12 09:41:49 -08001404 Ok(KEY_ID_LOCK.get(
1405 Self::insert_with_retry(|id| {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001406 tx.execute(
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001407 "INSERT into persistent.keyentry
Max Bires8e93d2b2021-01-14 13:17:59 -08001408 (id, key_type, domain, namespace, alias, state, km_uuid)
1409 VALUES(?, ?, ?, ?, NULL, ?, ?);",
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001410 params![
1411 id,
1412 KeyType::Client,
1413 domain.0 as u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001414 *namespace,
Max Bires8e93d2b2021-01-14 13:17:59 -08001415 KeyLifeCycle::Existing,
1416 km_uuid,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001417 ],
Janis Danisevskisaec14592020-11-12 09:41:49 -08001418 )
1419 })
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001420 .context("In create_key_entry_internal")?,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001421 ))
Joel Galenson26f4d012020-07-17 14:57:21 -07001422 }
Joel Galenson33c04ad2020-08-03 11:04:38 -07001423
Max Bires2b2e6562020-09-22 11:22:36 -07001424 /// Creates a new attestation key entry and allocates a new randomized id for the new key.
1425 /// The key id gets associated with a domain and namespace later but not with an alias. The
1426 /// alias will be used to denote if a key has been signed as each key can only be bound to one
1427 /// domain and namespace pairing so there is no need to use them as a value for indexing into
1428 /// a key.
1429 pub fn create_attestation_key_entry(
1430 &mut self,
1431 maced_public_key: &[u8],
1432 raw_public_key: &[u8],
1433 private_key: &[u8],
1434 km_uuid: &Uuid,
1435 ) -> Result<()> {
1436 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1437 let key_id = KEY_ID_LOCK.get(
1438 Self::insert_with_retry(|id| {
1439 tx.execute(
1440 "INSERT into persistent.keyentry
1441 (id, key_type, domain, namespace, alias, state, km_uuid)
1442 VALUES(?, ?, NULL, NULL, NULL, ?, ?);",
1443 params![id, KeyType::Attestation, KeyLifeCycle::Live, km_uuid],
1444 )
1445 })
1446 .context("In create_key_entry")?,
1447 );
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001448 Self::set_blob_internal(
1449 &tx,
1450 key_id.0,
1451 SubComponentType::KEY_BLOB,
1452 Some(private_key),
1453 None,
1454 )?;
Max Bires2b2e6562020-09-22 11:22:36 -07001455 let mut metadata = KeyMetaData::new();
1456 metadata.add(KeyMetaEntry::AttestationMacedPublicKey(maced_public_key.to_vec()));
1457 metadata.add(KeyMetaEntry::AttestationRawPubKey(raw_public_key.to_vec()));
1458 metadata.store_in_db(key_id.0, &tx)?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001459 Ok(()).no_gc()
Max Bires2b2e6562020-09-22 11:22:36 -07001460 })
1461 .context("In create_attestation_key_entry")
1462 }
1463
Janis Danisevskis377d1002021-01-27 19:07:48 -08001464 /// Set a new blob and associates it with the given key id. Each blob
1465 /// has a sub component type.
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001466 /// Each key can have one of each sub component type associated. If more
1467 /// are added only the most recent can be retrieved, and superseded blobs
Janis Danisevskis377d1002021-01-27 19:07:48 -08001468 /// will get garbage collected.
1469 /// Components SubComponentType::CERT and SubComponentType::CERT_CHAIN can be
1470 /// removed by setting blob to None.
1471 pub fn set_blob(
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001472 &mut self,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001473 key_id: &KeyIdGuard,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001474 sc_type: SubComponentType,
Janis Danisevskis377d1002021-01-27 19:07:48 -08001475 blob: Option<&[u8]>,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001476 blob_metadata: Option<&BlobMetaData>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001477 ) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001478 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001479 Self::set_blob_internal(&tx, key_id.0, sc_type, blob, blob_metadata).need_gc()
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001480 })
Janis Danisevskis377d1002021-01-27 19:07:48 -08001481 .context("In set_blob.")
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001482 }
1483
Janis Danisevskiseed69842021-02-18 20:04:10 -08001484 /// Why would we insert a deleted blob? This weird function is for the purpose of legacy
1485 /// key migration in the case where we bulk delete all the keys of an app or even a user.
1486 /// We use this to insert key blobs into the database which can then be garbage collected
1487 /// lazily by the key garbage collector.
1488 pub fn set_deleted_blob(&mut self, blob: &[u8], blob_metadata: &BlobMetaData) -> Result<()> {
1489 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1490 Self::set_blob_internal(
1491 &tx,
1492 Self::UNASSIGNED_KEY_ID,
1493 SubComponentType::KEY_BLOB,
1494 Some(blob),
1495 Some(blob_metadata),
1496 )
1497 .need_gc()
1498 })
1499 .context("In set_deleted_blob.")
1500 }
1501
Janis Danisevskis377d1002021-01-27 19:07:48 -08001502 fn set_blob_internal(
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001503 tx: &Transaction,
1504 key_id: i64,
1505 sc_type: SubComponentType,
Janis Danisevskis377d1002021-01-27 19:07:48 -08001506 blob: Option<&[u8]>,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001507 blob_metadata: Option<&BlobMetaData>,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001508 ) -> Result<()> {
Janis Danisevskis377d1002021-01-27 19:07:48 -08001509 match (blob, sc_type) {
1510 (Some(blob), _) => {
1511 tx.execute(
1512 "INSERT INTO persistent.blobentry
1513 (subcomponent_type, keyentryid, blob) VALUES (?, ?, ?);",
1514 params![sc_type, key_id, blob],
1515 )
1516 .context("In set_blob_internal: Failed to insert blob.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001517 if let Some(blob_metadata) = blob_metadata {
1518 let blob_id = tx
1519 .query_row("SELECT MAX(id) FROM persistent.blobentry;", NO_PARAMS, |row| {
1520 row.get(0)
1521 })
1522 .context("In set_blob_internal: Failed to get new blob id.")?;
1523 blob_metadata
1524 .store_in_db(blob_id, tx)
1525 .context("In set_blob_internal: Trying to store blob metadata.")?;
1526 }
Janis Danisevskis377d1002021-01-27 19:07:48 -08001527 }
1528 (None, SubComponentType::CERT) | (None, SubComponentType::CERT_CHAIN) => {
1529 tx.execute(
1530 "DELETE FROM persistent.blobentry
1531 WHERE subcomponent_type = ? AND keyentryid = ?;",
1532 params![sc_type, key_id],
1533 )
1534 .context("In set_blob_internal: Failed to delete blob.")?;
1535 }
1536 (None, _) => {
1537 return Err(KsError::sys())
1538 .context("In set_blob_internal: Other blobs cannot be deleted in this way.");
1539 }
1540 }
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001541 Ok(())
1542 }
1543
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001544 /// Inserts a collection of key parameters into the `persistent.keyparameter` table
1545 /// and associates them with the given `key_id`.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001546 #[cfg(test)]
1547 fn insert_keyparameter(&mut self, key_id: &KeyIdGuard, params: &[KeyParameter]) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001548 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001549 Self::insert_keyparameter_internal(tx, key_id, params).no_gc()
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001550 })
1551 .context("In insert_keyparameter.")
1552 }
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001553
Janis Danisevskis66784c42021-01-27 08:40:25 -08001554 fn insert_keyparameter_internal(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001555 tx: &Transaction,
1556 key_id: &KeyIdGuard,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001557 params: &[KeyParameter],
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001558 ) -> Result<()> {
1559 let mut stmt = tx
1560 .prepare(
1561 "INSERT into persistent.keyparameter (keyentryid, tag, data, security_level)
1562 VALUES (?, ?, ?, ?);",
1563 )
1564 .context("In insert_keyparameter_internal: Failed to prepare statement.")?;
1565
Janis Danisevskis66784c42021-01-27 08:40:25 -08001566 for p in params.iter() {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001567 stmt.insert(params![
1568 key_id.0,
1569 p.get_tag().0,
1570 p.key_parameter_value(),
1571 p.security_level().0
1572 ])
1573 .with_context(|| {
1574 format!("In insert_keyparameter_internal: Failed to insert {:?}", p)
1575 })?;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001576 }
1577 Ok(())
1578 }
1579
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001580 /// Insert a set of key entry specific metadata into the database.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001581 #[cfg(test)]
1582 fn insert_key_metadata(&mut self, key_id: &KeyIdGuard, metadata: &KeyMetaData) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001583 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001584 metadata.store_in_db(key_id.0, &tx).no_gc()
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001585 })
1586 .context("In insert_key_metadata.")
1587 }
1588
Max Bires2b2e6562020-09-22 11:22:36 -07001589 /// Stores a signed certificate chain signed by a remote provisioning server, keyed
1590 /// on the public key.
1591 pub fn store_signed_attestation_certificate_chain(
1592 &mut self,
1593 raw_public_key: &[u8],
Max Biresb2e1d032021-02-08 21:35:05 -08001594 batch_cert: &[u8],
Max Bires2b2e6562020-09-22 11:22:36 -07001595 cert_chain: &[u8],
1596 expiration_date: i64,
1597 km_uuid: &Uuid,
1598 ) -> Result<()> {
1599 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1600 let mut stmt = tx
1601 .prepare(
1602 "SELECT keyentryid
1603 FROM persistent.keymetadata
1604 WHERE tag = ? AND data = ? AND keyentryid IN
1605 (SELECT id
1606 FROM persistent.keyentry
1607 WHERE
1608 alias IS NULL AND
1609 domain IS NULL AND
1610 namespace IS NULL AND
1611 key_type = ? AND
1612 km_uuid = ?);",
1613 )
1614 .context("Failed to store attestation certificate chain.")?;
1615 let mut rows = stmt
1616 .query(params![
1617 KeyMetaData::AttestationRawPubKey,
1618 raw_public_key,
1619 KeyType::Attestation,
1620 km_uuid
1621 ])
1622 .context("Failed to fetch keyid")?;
1623 let key_id = db_utils::with_rows_extract_one(&mut rows, |row| {
1624 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?
1625 .get(0)
1626 .context("Failed to unpack id.")
1627 })
1628 .context("Failed to get key_id.")?;
1629 let num_updated = tx
1630 .execute(
1631 "UPDATE persistent.keyentry
1632 SET alias = ?
1633 WHERE id = ?;",
1634 params!["signed", key_id],
1635 )
1636 .context("Failed to update alias.")?;
1637 if num_updated != 1 {
1638 return Err(KsError::sys()).context("Alias not updated for the key.");
1639 }
1640 let mut metadata = KeyMetaData::new();
1641 metadata.add(KeyMetaEntry::AttestationExpirationDate(DateTime::from_millis_epoch(
1642 expiration_date,
1643 )));
1644 metadata.store_in_db(key_id, &tx).context("Failed to insert key metadata.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001645 Self::set_blob_internal(
1646 &tx,
1647 key_id,
1648 SubComponentType::CERT_CHAIN,
1649 Some(cert_chain),
1650 None,
1651 )
1652 .context("Failed to insert cert chain")?;
Max Biresb2e1d032021-02-08 21:35:05 -08001653 Self::set_blob_internal(&tx, key_id, SubComponentType::CERT, Some(batch_cert), None)
1654 .context("Failed to insert cert")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001655 Ok(()).no_gc()
Max Bires2b2e6562020-09-22 11:22:36 -07001656 })
1657 .context("In store_signed_attestation_certificate_chain: ")
1658 }
1659
1660 /// Assigns the next unassigned attestation key to a domain/namespace combo that does not
1661 /// currently have a key assigned to it.
1662 pub fn assign_attestation_key(
1663 &mut self,
1664 domain: Domain,
1665 namespace: i64,
1666 km_uuid: &Uuid,
1667 ) -> Result<()> {
1668 match domain {
1669 Domain::APP | Domain::SELINUX => {}
1670 _ => {
1671 return Err(KsError::sys()).context(format!(
1672 concat!(
1673 "In assign_attestation_key: Domain {:?} ",
1674 "must be either App or SELinux.",
1675 ),
1676 domain
1677 ));
1678 }
1679 }
1680 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1681 let result = tx
1682 .execute(
1683 "UPDATE persistent.keyentry
1684 SET domain=?1, namespace=?2
1685 WHERE
1686 id =
1687 (SELECT MIN(id)
1688 FROM persistent.keyentry
1689 WHERE ALIAS IS NOT NULL
1690 AND domain IS NULL
1691 AND key_type IS ?3
1692 AND state IS ?4
1693 AND km_uuid IS ?5)
1694 AND
1695 (SELECT COUNT(*)
1696 FROM persistent.keyentry
1697 WHERE domain=?1
1698 AND namespace=?2
1699 AND key_type IS ?3
1700 AND state IS ?4
1701 AND km_uuid IS ?5) = 0;",
1702 params![
1703 domain.0 as u32,
1704 namespace,
1705 KeyType::Attestation,
1706 KeyLifeCycle::Live,
1707 km_uuid,
1708 ],
1709 )
1710 .context("Failed to assign attestation key")?;
Max Bires01f8af22021-03-02 23:24:50 -08001711 if result == 0 {
1712 return Err(KsError::Rc(ResponseCode::OUT_OF_KEYS)).context("Out of keys.");
1713 } else if result > 1 {
1714 return Err(KsError::sys())
1715 .context(format!("Expected to update 1 entry, instead updated {}", result));
Max Bires2b2e6562020-09-22 11:22:36 -07001716 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001717 Ok(()).no_gc()
Max Bires2b2e6562020-09-22 11:22:36 -07001718 })
1719 .context("In assign_attestation_key: ")
1720 }
1721
1722 /// Retrieves num_keys number of attestation keys that have not yet been signed by a remote
1723 /// provisioning server, or the maximum number available if there are not num_keys number of
1724 /// entries in the table.
1725 pub fn fetch_unsigned_attestation_keys(
1726 &mut self,
1727 num_keys: i32,
1728 km_uuid: &Uuid,
1729 ) -> Result<Vec<Vec<u8>>> {
1730 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1731 let mut stmt = tx
1732 .prepare(
1733 "SELECT data
1734 FROM persistent.keymetadata
1735 WHERE tag = ? AND keyentryid IN
1736 (SELECT id
1737 FROM persistent.keyentry
1738 WHERE
1739 alias IS NULL AND
1740 domain IS NULL AND
1741 namespace IS NULL AND
1742 key_type = ? AND
1743 km_uuid = ?
1744 LIMIT ?);",
1745 )
1746 .context("Failed to prepare statement")?;
1747 let rows = stmt
1748 .query_map(
1749 params![
1750 KeyMetaData::AttestationMacedPublicKey,
1751 KeyType::Attestation,
1752 km_uuid,
1753 num_keys
1754 ],
1755 |row| Ok(row.get(0)?),
1756 )?
1757 .collect::<rusqlite::Result<Vec<Vec<u8>>>>()
1758 .context("Failed to execute statement")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001759 Ok(rows).no_gc()
Max Bires2b2e6562020-09-22 11:22:36 -07001760 })
1761 .context("In fetch_unsigned_attestation_keys")
1762 }
1763
1764 /// Removes any keys that have expired as of the current time. Returns the number of keys
1765 /// marked unreferenced that are bound to be garbage collected.
1766 pub fn delete_expired_attestation_keys(&mut self) -> Result<i32> {
1767 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1768 let mut stmt = tx
1769 .prepare(
1770 "SELECT keyentryid, data
1771 FROM persistent.keymetadata
1772 WHERE tag = ? AND keyentryid IN
1773 (SELECT id
1774 FROM persistent.keyentry
1775 WHERE key_type = ?);",
1776 )
1777 .context("Failed to prepare query")?;
1778 let key_ids_to_check = stmt
1779 .query_map(
1780 params![KeyMetaData::AttestationExpirationDate, KeyType::Attestation],
1781 |row| Ok((row.get(0)?, row.get(1)?)),
1782 )?
1783 .collect::<rusqlite::Result<Vec<(i64, DateTime)>>>()
1784 .context("Failed to get date metadata")?;
1785 let curr_time = DateTime::from_millis_epoch(
1786 SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_millis() as i64,
1787 );
1788 let mut num_deleted = 0;
1789 for id in key_ids_to_check.iter().filter(|kt| kt.1 < curr_time).map(|kt| kt.0) {
1790 if Self::mark_unreferenced(&tx, id)? {
1791 num_deleted += 1;
1792 }
1793 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001794 Ok(num_deleted).do_gc(num_deleted != 0)
Max Bires2b2e6562020-09-22 11:22:36 -07001795 })
1796 .context("In delete_expired_attestation_keys: ")
1797 }
1798
Max Bires60d7ed12021-03-05 15:59:22 -08001799 /// Deletes all remotely provisioned attestation keys in the system, regardless of the state
1800 /// they are in. This is useful primarily as a testing mechanism.
1801 pub fn delete_all_attestation_keys(&mut self) -> Result<i64> {
1802 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1803 let mut stmt = tx
1804 .prepare(
1805 "SELECT id FROM persistent.keyentry
1806 WHERE key_type IS ?;",
1807 )
1808 .context("Failed to prepare statement")?;
1809 let keys_to_delete = stmt
1810 .query_map(params![KeyType::Attestation], |row| Ok(row.get(0)?))?
1811 .collect::<rusqlite::Result<Vec<i64>>>()
1812 .context("Failed to execute statement")?;
1813 let num_deleted = keys_to_delete
1814 .iter()
1815 .map(|id| Self::mark_unreferenced(&tx, *id))
1816 .collect::<Result<Vec<bool>>>()
1817 .context("Failed to execute mark_unreferenced on a keyid")?
1818 .into_iter()
1819 .filter(|result| *result)
1820 .count() as i64;
1821 Ok(num_deleted).do_gc(num_deleted != 0)
1822 })
1823 .context("In delete_all_attestation_keys: ")
1824 }
1825
Max Bires2b2e6562020-09-22 11:22:36 -07001826 /// Counts the number of keys that will expire by the provided epoch date and the number of
1827 /// keys not currently assigned to a domain.
1828 pub fn get_attestation_pool_status(
1829 &mut self,
1830 date: i64,
1831 km_uuid: &Uuid,
1832 ) -> Result<AttestationPoolStatus> {
1833 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1834 let mut stmt = tx.prepare(
1835 "SELECT data
1836 FROM persistent.keymetadata
1837 WHERE tag = ? AND keyentryid IN
1838 (SELECT id
1839 FROM persistent.keyentry
1840 WHERE alias IS NOT NULL
1841 AND key_type = ?
1842 AND km_uuid = ?
1843 AND state = ?);",
1844 )?;
1845 let times = stmt
1846 .query_map(
1847 params![
1848 KeyMetaData::AttestationExpirationDate,
1849 KeyType::Attestation,
1850 km_uuid,
1851 KeyLifeCycle::Live
1852 ],
1853 |row| Ok(row.get(0)?),
1854 )?
1855 .collect::<rusqlite::Result<Vec<DateTime>>>()
1856 .context("Failed to execute metadata statement")?;
1857 let expiring =
1858 times.iter().filter(|time| time < &&DateTime::from_millis_epoch(date)).count()
1859 as i32;
1860 stmt = tx.prepare(
1861 "SELECT alias, domain
1862 FROM persistent.keyentry
1863 WHERE key_type = ? AND km_uuid = ? AND state = ?;",
1864 )?;
1865 let rows = stmt
1866 .query_map(params![KeyType::Attestation, km_uuid, KeyLifeCycle::Live], |row| {
1867 Ok((row.get(0)?, row.get(1)?))
1868 })?
1869 .collect::<rusqlite::Result<Vec<(Option<String>, Option<u32>)>>>()
1870 .context("Failed to execute keyentry statement")?;
1871 let mut unassigned = 0i32;
1872 let mut attested = 0i32;
1873 let total = rows.len() as i32;
1874 for (alias, domain) in rows {
1875 match (alias, domain) {
1876 (Some(_alias), None) => {
1877 attested += 1;
1878 unassigned += 1;
1879 }
1880 (Some(_alias), Some(_domain)) => {
1881 attested += 1;
1882 }
1883 _ => {}
1884 }
1885 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001886 Ok(AttestationPoolStatus { expiring, unassigned, attested, total }).no_gc()
Max Bires2b2e6562020-09-22 11:22:36 -07001887 })
1888 .context("In get_attestation_pool_status: ")
1889 }
1890
1891 /// Fetches the private key and corresponding certificate chain assigned to a
1892 /// domain/namespace pair. Will either return nothing if the domain/namespace is
1893 /// not assigned, or one CertificateChain.
1894 pub fn retrieve_attestation_key_and_cert_chain(
1895 &mut self,
1896 domain: Domain,
1897 namespace: i64,
1898 km_uuid: &Uuid,
1899 ) -> Result<Option<CertificateChain>> {
1900 match domain {
1901 Domain::APP | Domain::SELINUX => {}
1902 _ => {
1903 return Err(KsError::sys())
1904 .context(format!("Domain {:?} must be either App or SELinux.", domain));
1905 }
1906 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001907 self.with_transaction(TransactionBehavior::Deferred, |tx| {
1908 let mut stmt = tx.prepare(
1909 "SELECT subcomponent_type, blob
Max Bires2b2e6562020-09-22 11:22:36 -07001910 FROM persistent.blobentry
1911 WHERE keyentryid IN
1912 (SELECT id
1913 FROM persistent.keyentry
1914 WHERE key_type = ?
1915 AND domain = ?
1916 AND namespace = ?
1917 AND state = ?
1918 AND km_uuid = ?);",
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001919 )?;
1920 let rows = stmt
1921 .query_map(
1922 params![
1923 KeyType::Attestation,
1924 domain.0 as u32,
1925 namespace,
1926 KeyLifeCycle::Live,
1927 km_uuid
1928 ],
1929 |row| Ok((row.get(0)?, row.get(1)?)),
1930 )?
1931 .collect::<rusqlite::Result<Vec<(SubComponentType, Vec<u8>)>>>()
Max Biresb2e1d032021-02-08 21:35:05 -08001932 .context("query failed.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001933 if rows.is_empty() {
1934 return Ok(None).no_gc();
Max Biresb2e1d032021-02-08 21:35:05 -08001935 } else if rows.len() != 3 {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001936 return Err(KsError::sys()).context(format!(
1937 concat!(
Max Biresb2e1d032021-02-08 21:35:05 -08001938 "Expected to get a single attestation",
1939 "key, cert, and cert chain for a total of 3 entries, but instead got {}."
1940 ),
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001941 rows.len()
1942 ));
Max Bires2b2e6562020-09-22 11:22:36 -07001943 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001944 let mut km_blob: Vec<u8> = Vec::new();
1945 let mut cert_chain_blob: Vec<u8> = Vec::new();
Max Biresb2e1d032021-02-08 21:35:05 -08001946 let mut batch_cert_blob: Vec<u8> = Vec::new();
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001947 for row in rows {
1948 let sub_type: SubComponentType = row.0;
1949 match sub_type {
1950 SubComponentType::KEY_BLOB => {
1951 km_blob = row.1;
1952 }
1953 SubComponentType::CERT_CHAIN => {
1954 cert_chain_blob = row.1;
1955 }
Max Biresb2e1d032021-02-08 21:35:05 -08001956 SubComponentType::CERT => {
1957 batch_cert_blob = row.1;
1958 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001959 _ => Err(KsError::sys()).context("Unknown or incorrect subcomponent type.")?,
1960 }
1961 }
1962 Ok(Some(CertificateChain {
1963 private_key: ZVec::try_from(km_blob)?,
Max Bires97f96812021-02-23 23:44:57 -08001964 batch_cert: batch_cert_blob,
1965 cert_chain: cert_chain_blob,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001966 }))
1967 .no_gc()
1968 })
Max Biresb2e1d032021-02-08 21:35:05 -08001969 .context("In retrieve_attestation_key_and_cert_chain:")
Max Bires2b2e6562020-09-22 11:22:36 -07001970 }
1971
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001972 /// Updates the alias column of the given key id `newid` with the given alias,
1973 /// and atomically, removes the alias, domain, and namespace from another row
1974 /// with the same alias-domain-namespace tuple if such row exits.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001975 /// Returns Ok(true) if an old key was marked unreferenced as a hint to the garbage
1976 /// collector.
1977 fn rebind_alias(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001978 tx: &Transaction,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001979 newid: &KeyIdGuard,
Joel Galenson33c04ad2020-08-03 11:04:38 -07001980 alias: &str,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001981 domain: &Domain,
1982 namespace: &i64,
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001983 ) -> Result<bool> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001984 match *domain {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001985 Domain::APP | Domain::SELINUX => {}
Joel Galenson33c04ad2020-08-03 11:04:38 -07001986 _ => {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001987 return Err(KsError::sys()).context(format!(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001988 "In rebind_alias: Domain {:?} must be either App or SELinux.",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001989 domain
1990 ));
Joel Galenson33c04ad2020-08-03 11:04:38 -07001991 }
1992 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001993 let updated = tx
1994 .execute(
1995 "UPDATE persistent.keyentry
1996 SET alias = NULL, domain = NULL, namespace = NULL, state = ?
Joel Galenson33c04ad2020-08-03 11:04:38 -07001997 WHERE alias = ? AND domain = ? AND namespace = ?;",
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001998 params![KeyLifeCycle::Unreferenced, alias, domain.0 as u32, namespace],
1999 )
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002000 .context("In rebind_alias: Failed to rebind existing entry.")?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07002001 let result = tx
2002 .execute(
2003 "UPDATE persistent.keyentry
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002004 SET alias = ?, state = ?
2005 WHERE id = ? AND domain = ? AND namespace = ? AND state = ?;",
2006 params![
2007 alias,
2008 KeyLifeCycle::Live,
2009 newid.0,
2010 domain.0 as u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002011 *namespace,
Max Bires8e93d2b2021-01-14 13:17:59 -08002012 KeyLifeCycle::Existing,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002013 ],
Joel Galenson33c04ad2020-08-03 11:04:38 -07002014 )
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002015 .context("In rebind_alias: Failed to set alias.")?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07002016 if result != 1 {
Joel Galenson33c04ad2020-08-03 11:04:38 -07002017 return Err(KsError::sys()).context(format!(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002018 "In rebind_alias: Expected to update a single entry but instead updated {}.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07002019 result
2020 ));
2021 }
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002022 Ok(updated != 0)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002023 }
2024
2025 /// Store a new key in a single transaction.
2026 /// The function creates a new key entry, populates the blob, key parameter, and metadata
2027 /// fields, and rebinds the given alias to the new key.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002028 /// The boolean returned is a hint for the garbage collector. If true, a key was replaced,
2029 /// is now unreferenced and needs to be collected.
Janis Danisevskis66784c42021-01-27 08:40:25 -08002030 pub fn store_new_key(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002031 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002032 key: &KeyDescriptor,
2033 params: &[KeyParameter],
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002034 blob_info: &(&[u8], &BlobMetaData),
Max Bires8e93d2b2021-01-14 13:17:59 -08002035 cert_info: &CertificateInfo,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002036 metadata: &KeyMetaData,
Max Bires8e93d2b2021-01-14 13:17:59 -08002037 km_uuid: &Uuid,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002038 ) -> Result<KeyIdGuard> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002039 let (alias, domain, namespace) = match key {
2040 KeyDescriptor { alias: Some(alias), domain: Domain::APP, nspace, blob: None }
2041 | KeyDescriptor { alias: Some(alias), domain: Domain::SELINUX, nspace, blob: None } => {
2042 (alias, key.domain, nspace)
2043 }
2044 _ => {
2045 return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT))
2046 .context("In store_new_key: Need alias and domain must be APP or SELINUX.")
2047 }
2048 };
2049 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002050 let key_id = Self::create_key_entry_internal(tx, &domain, namespace, km_uuid)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002051 .context("Trying to create new key entry.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002052 let (blob, blob_metadata) = *blob_info;
2053 Self::set_blob_internal(
2054 tx,
2055 key_id.id(),
2056 SubComponentType::KEY_BLOB,
2057 Some(blob),
2058 Some(&blob_metadata),
2059 )
2060 .context("Trying to insert the key blob.")?;
Max Bires8e93d2b2021-01-14 13:17:59 -08002061 if let Some(cert) = &cert_info.cert {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002062 Self::set_blob_internal(tx, key_id.id(), SubComponentType::CERT, Some(&cert), None)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002063 .context("Trying to insert the certificate.")?;
2064 }
Max Bires8e93d2b2021-01-14 13:17:59 -08002065 if let Some(cert_chain) = &cert_info.cert_chain {
Janis Danisevskis377d1002021-01-27 19:07:48 -08002066 Self::set_blob_internal(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002067 tx,
2068 key_id.id(),
2069 SubComponentType::CERT_CHAIN,
Janis Danisevskis377d1002021-01-27 19:07:48 -08002070 Some(&cert_chain),
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002071 None,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002072 )
2073 .context("Trying to insert the certificate chain.")?;
2074 }
2075 Self::insert_keyparameter_internal(tx, &key_id, params)
2076 .context("Trying to insert key parameters.")?;
Janis Danisevskis377d1002021-01-27 19:07:48 -08002077 metadata.store_in_db(key_id.id(), tx).context("Trying to insert key metadata.")?;
Janis Danisevskis66784c42021-01-27 08:40:25 -08002078 let need_gc = Self::rebind_alias(tx, &key_id, &alias, &domain, namespace)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002079 .context("Trying to rebind alias.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002080 Ok(key_id).do_gc(need_gc)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002081 })
2082 .context("In store_new_key.")
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002083 }
2084
Janis Danisevskis377d1002021-01-27 19:07:48 -08002085 /// Store a new certificate
2086 /// The function creates a new key entry, populates the blob field and metadata, and rebinds
2087 /// the given alias to the new cert.
Max Bires8e93d2b2021-01-14 13:17:59 -08002088 pub fn store_new_certificate(
2089 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002090 key: &KeyDescriptor,
Max Bires8e93d2b2021-01-14 13:17:59 -08002091 cert: &[u8],
2092 km_uuid: &Uuid,
2093 ) -> Result<KeyIdGuard> {
Janis Danisevskis377d1002021-01-27 19:07:48 -08002094 let (alias, domain, namespace) = match key {
2095 KeyDescriptor { alias: Some(alias), domain: Domain::APP, nspace, blob: None }
2096 | KeyDescriptor { alias: Some(alias), domain: Domain::SELINUX, nspace, blob: None } => {
2097 (alias, key.domain, nspace)
2098 }
2099 _ => {
2100 return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT)).context(
2101 "In store_new_certificate: Need alias and domain must be APP or SELINUX.",
2102 )
2103 }
2104 };
2105 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002106 let key_id = Self::create_key_entry_internal(tx, &domain, namespace, km_uuid)
Janis Danisevskis377d1002021-01-27 19:07:48 -08002107 .context("Trying to create new key entry.")?;
2108
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002109 Self::set_blob_internal(
2110 tx,
2111 key_id.id(),
2112 SubComponentType::CERT_CHAIN,
2113 Some(cert),
2114 None,
2115 )
2116 .context("Trying to insert certificate.")?;
Janis Danisevskis377d1002021-01-27 19:07:48 -08002117
2118 let mut metadata = KeyMetaData::new();
2119 metadata.add(KeyMetaEntry::CreationDate(
2120 DateTime::now().context("Trying to make creation time.")?,
2121 ));
2122
2123 metadata.store_in_db(key_id.id(), tx).context("Trying to insert key metadata.")?;
2124
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002125 let need_gc = Self::rebind_alias(tx, &key_id, &alias, &domain, namespace)
Janis Danisevskis377d1002021-01-27 19:07:48 -08002126 .context("Trying to rebind alias.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002127 Ok(key_id).do_gc(need_gc)
Janis Danisevskis377d1002021-01-27 19:07:48 -08002128 })
2129 .context("In store_new_certificate.")
2130 }
2131
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002132 // Helper function loading the key_id given the key descriptor
2133 // tuple comprising domain, namespace, and alias.
2134 // Requires a valid transaction.
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002135 fn load_key_entry_id(tx: &Transaction, key: &KeyDescriptor, key_type: KeyType) -> Result<i64> {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002136 let alias = key
2137 .alias
2138 .as_ref()
2139 .map_or_else(|| Err(KsError::sys()), Ok)
2140 .context("In load_key_entry_id: Alias must be specified.")?;
2141 let mut stmt = tx
2142 .prepare(
2143 "SELECT id FROM persistent.keyentry
2144 WHERE
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00002145 key_type = ?
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002146 AND domain = ?
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002147 AND namespace = ?
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002148 AND alias = ?
2149 AND state = ?;",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002150 )
2151 .context("In load_key_entry_id: Failed to select from keyentry table.")?;
2152 let mut rows = stmt
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002153 .query(params![key_type, key.domain.0 as u32, key.nspace, alias, KeyLifeCycle::Live])
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002154 .context("In load_key_entry_id: Failed to read from keyentry table.")?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002155 db_utils::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002156 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002157 .get(0)
2158 .context("Failed to unpack id.")
2159 })
2160 .context("In load_key_entry_id.")
2161 }
2162
2163 /// This helper function completes the access tuple of a key, which is required
2164 /// to perform access control. The strategy depends on the `domain` field in the
2165 /// key descriptor.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002166 /// * Domain::SELINUX: The access tuple is complete and this function only loads
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002167 /// the key_id for further processing.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002168 /// * Domain::APP: Like Domain::SELINUX, but the tuple is completed by `caller_uid`
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002169 /// which serves as the namespace.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002170 /// * Domain::GRANT: The grant table is queried for the `key_id` and the
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002171 /// `access_vector`.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002172 /// * Domain::KEY_ID: The keyentry table is queried for the owning `domain` and
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002173 /// `namespace`.
2174 /// In each case the information returned is sufficient to perform the access
2175 /// check and the key id can be used to load further key artifacts.
2176 fn load_access_tuple(
2177 tx: &Transaction,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002178 key: &KeyDescriptor,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002179 key_type: KeyType,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002180 caller_uid: u32,
2181 ) -> Result<(i64, KeyDescriptor, Option<KeyPermSet>)> {
2182 match key.domain {
2183 // Domain App or SELinux. In this case we load the key_id from
2184 // the keyentry database for further loading of key components.
2185 // We already have the full access tuple to perform access control.
2186 // The only distinction is that we use the caller_uid instead
2187 // of the caller supplied namespace if the domain field is
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002188 // Domain::APP.
2189 Domain::APP | Domain::SELINUX => {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002190 let mut access_key = key.clone();
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002191 if access_key.domain == Domain::APP {
2192 access_key.nspace = caller_uid as i64;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002193 }
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002194 let key_id = Self::load_key_entry_id(&tx, &access_key, key_type)
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002195 .with_context(|| format!("With key.domain = {:?}.", access_key.domain))?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002196
2197 Ok((key_id, access_key, None))
2198 }
2199
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002200 // Domain::GRANT. In this case we load the key_id and the access_vector
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002201 // from the grant table.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002202 Domain::GRANT => {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002203 let mut stmt = tx
2204 .prepare(
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002205 "SELECT keyentryid, access_vector FROM persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002206 WHERE grantee = ? AND id = ?;",
2207 )
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002208 .context("Domain::GRANT prepare statement failed")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002209 let mut rows = stmt
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002210 .query(params![caller_uid as i64, key.nspace])
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002211 .context("Domain:Grant: query failed.")?;
2212 let (key_id, access_vector): (i64, i32) =
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002213 db_utils::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002214 let r =
2215 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002216 Ok((
2217 r.get(0).context("Failed to unpack key_id.")?,
2218 r.get(1).context("Failed to unpack access_vector.")?,
2219 ))
2220 })
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002221 .context("Domain::GRANT.")?;
Janis Danisevskis66784c42021-01-27 08:40:25 -08002222 Ok((key_id, key.clone(), Some(access_vector.into())))
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002223 }
2224
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002225 // Domain::KEY_ID. In this case we load the domain and namespace from the
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002226 // keyentry database because we need them for access control.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002227 Domain::KEY_ID => {
Janis Danisevskis45760022021-01-19 16:34:10 -08002228 let (domain, namespace): (Domain, i64) = {
2229 let mut stmt = tx
2230 .prepare(
2231 "SELECT domain, namespace FROM persistent.keyentry
2232 WHERE
2233 id = ?
2234 AND state = ?;",
2235 )
2236 .context("Domain::KEY_ID: prepare statement failed")?;
2237 let mut rows = stmt
2238 .query(params![key.nspace, KeyLifeCycle::Live])
2239 .context("Domain::KEY_ID: query failed.")?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002240 db_utils::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002241 let r =
2242 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002243 Ok((
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002244 Domain(r.get(0).context("Failed to unpack domain.")?),
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002245 r.get(1).context("Failed to unpack namespace.")?,
2246 ))
2247 })
Janis Danisevskis45760022021-01-19 16:34:10 -08002248 .context("Domain::KEY_ID.")?
2249 };
2250
2251 // We may use a key by id after loading it by grant.
2252 // In this case we have to check if the caller has a grant for this particular
2253 // key. We can skip this if we already know that the caller is the owner.
2254 // But we cannot know this if domain is anything but App. E.g. in the case
2255 // of Domain::SELINUX we have to speculatively check for grants because we have to
2256 // consult the SEPolicy before we know if the caller is the owner.
2257 let access_vector: Option<KeyPermSet> =
2258 if domain != Domain::APP || namespace != caller_uid as i64 {
2259 let access_vector: Option<i32> = tx
2260 .query_row(
2261 "SELECT access_vector FROM persistent.grant
2262 WHERE grantee = ? AND keyentryid = ?;",
2263 params![caller_uid as i64, key.nspace],
2264 |row| row.get(0),
2265 )
2266 .optional()
2267 .context("Domain::KEY_ID: query grant failed.")?;
2268 access_vector.map(|p| p.into())
2269 } else {
2270 None
2271 };
2272
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002273 let key_id = key.nspace;
Janis Danisevskis66784c42021-01-27 08:40:25 -08002274 let mut access_key: KeyDescriptor = key.clone();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002275 access_key.domain = domain;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002276 access_key.nspace = namespace;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002277
Janis Danisevskis45760022021-01-19 16:34:10 -08002278 Ok((key_id, access_key, access_vector))
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002279 }
2280 _ => Err(anyhow!(KsError::sys())),
2281 }
2282 }
2283
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002284 fn load_blob_components(
2285 key_id: i64,
2286 load_bits: KeyEntryLoadBits,
2287 tx: &Transaction,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002288 ) -> Result<(bool, Option<(Vec<u8>, BlobMetaData)>, Option<Vec<u8>>, Option<Vec<u8>>)> {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002289 let mut stmt = tx
2290 .prepare(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002291 "SELECT MAX(id), subcomponent_type, blob FROM persistent.blobentry
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002292 WHERE keyentryid = ? GROUP BY subcomponent_type;",
2293 )
2294 .context("In load_blob_components: prepare statement failed.")?;
2295
2296 let mut rows =
2297 stmt.query(params![key_id]).context("In load_blob_components: query failed.")?;
2298
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002299 let mut key_blob: Option<(i64, Vec<u8>)> = None;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002300 let mut cert_blob: Option<Vec<u8>> = None;
2301 let mut cert_chain_blob: Option<Vec<u8>> = None;
Janis Danisevskis377d1002021-01-27 19:07:48 -08002302 let mut has_km_blob: bool = false;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002303 db_utils::with_rows_extract_all(&mut rows, |row| {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002304 let sub_type: SubComponentType =
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002305 row.get(1).context("Failed to extract subcomponent_type.")?;
Janis Danisevskis377d1002021-01-27 19:07:48 -08002306 has_km_blob = has_km_blob || sub_type == SubComponentType::KEY_BLOB;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002307 match (sub_type, load_bits.load_public(), load_bits.load_km()) {
2308 (SubComponentType::KEY_BLOB, _, true) => {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002309 key_blob = Some((
2310 row.get(0).context("Failed to extract key blob id.")?,
2311 row.get(2).context("Failed to extract key blob.")?,
2312 ));
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002313 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002314 (SubComponentType::CERT, true, _) => {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002315 cert_blob =
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002316 Some(row.get(2).context("Failed to extract public certificate blob.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002317 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002318 (SubComponentType::CERT_CHAIN, true, _) => {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002319 cert_chain_blob =
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002320 Some(row.get(2).context("Failed to extract certificate chain blob.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002321 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002322 (SubComponentType::CERT, _, _)
2323 | (SubComponentType::CERT_CHAIN, _, _)
2324 | (SubComponentType::KEY_BLOB, _, _) => {}
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002325 _ => Err(KsError::sys()).context("Unknown subcomponent type.")?,
2326 }
2327 Ok(())
2328 })
2329 .context("In load_blob_components.")?;
2330
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002331 let blob_info = key_blob.map_or::<Result<_>, _>(Ok(None), |(blob_id, blob)| {
2332 Ok(Some((
2333 blob,
2334 BlobMetaData::load_from_db(blob_id, tx)
2335 .context("In load_blob_components: Trying to load blob_metadata.")?,
2336 )))
2337 })?;
2338
2339 Ok((has_km_blob, blob_info, cert_blob, cert_chain_blob))
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002340 }
2341
2342 fn load_key_parameters(key_id: i64, tx: &Transaction) -> Result<Vec<KeyParameter>> {
2343 let mut stmt = tx
2344 .prepare(
2345 "SELECT tag, data, security_level from persistent.keyparameter
2346 WHERE keyentryid = ?;",
2347 )
2348 .context("In load_key_parameters: prepare statement failed.")?;
2349
2350 let mut parameters: Vec<KeyParameter> = Vec::new();
2351
2352 let mut rows =
2353 stmt.query(params![key_id]).context("In load_key_parameters: query failed.")?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002354 db_utils::with_rows_extract_all(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002355 let tag = Tag(row.get(0).context("Failed to read tag.")?);
2356 let sec_level = SecurityLevel(row.get(2).context("Failed to read sec_level.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002357 parameters.push(
2358 KeyParameter::new_from_sql(tag, &SqlField::new(1, &row), sec_level)
2359 .context("Failed to read KeyParameter.")?,
2360 );
2361 Ok(())
2362 })
2363 .context("In load_key_parameters.")?;
2364
2365 Ok(parameters)
2366 }
2367
Qi Wub9433b52020-12-01 14:52:46 +08002368 /// Decrements the usage count of a limited use key. This function first checks whether the
2369 /// usage has been exhausted, if not, decreases the usage count. If the usage count reaches
2370 /// zero, the key also gets marked unreferenced and scheduled for deletion.
2371 /// Returns Ok(true) if the key was marked unreferenced as a hint to the garbage collector.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002372 pub fn check_and_update_key_usage_count(&mut self, key_id: i64) -> Result<()> {
Qi Wub9433b52020-12-01 14:52:46 +08002373 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2374 let limit: Option<i32> = tx
2375 .query_row(
2376 "SELECT data FROM persistent.keyparameter WHERE keyentryid = ? AND tag = ?;",
2377 params![key_id, Tag::USAGE_COUNT_LIMIT.0],
2378 |row| row.get(0),
2379 )
2380 .optional()
2381 .context("Trying to load usage count")?;
2382
2383 let limit = limit
2384 .ok_or(KsError::Km(ErrorCode::INVALID_KEY_BLOB))
2385 .context("The Key no longer exists. Key is exhausted.")?;
2386
2387 tx.execute(
2388 "UPDATE persistent.keyparameter
2389 SET data = data - 1
2390 WHERE keyentryid = ? AND tag = ? AND data > 0;",
2391 params![key_id, Tag::USAGE_COUNT_LIMIT.0],
2392 )
2393 .context("Failed to update key usage count.")?;
2394
2395 match limit {
2396 1 => Self::mark_unreferenced(tx, key_id)
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002397 .map(|need_gc| (need_gc, ()))
Qi Wub9433b52020-12-01 14:52:46 +08002398 .context("Trying to mark limited use key for deletion."),
2399 0 => Err(KsError::Km(ErrorCode::INVALID_KEY_BLOB)).context("Key is exhausted."),
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002400 _ => Ok(()).no_gc(),
Qi Wub9433b52020-12-01 14:52:46 +08002401 }
2402 })
2403 .context("In check_and_update_key_usage_count.")
2404 }
2405
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002406 /// Load a key entry by the given key descriptor.
2407 /// It uses the `check_permission` callback to verify if the access is allowed
2408 /// given the key access tuple read from the database using `load_access_tuple`.
2409 /// With `load_bits` the caller may specify which blobs shall be loaded from
2410 /// the blob database.
2411 pub fn load_key_entry(
2412 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002413 key: &KeyDescriptor,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002414 key_type: KeyType,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002415 load_bits: KeyEntryLoadBits,
2416 caller_uid: u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002417 check_permission: impl Fn(&KeyDescriptor, Option<KeyPermSet>) -> Result<()>,
2418 ) -> Result<(KeyIdGuard, KeyEntry)> {
2419 loop {
2420 match self.load_key_entry_internal(
2421 key,
2422 key_type,
2423 load_bits,
2424 caller_uid,
2425 &check_permission,
2426 ) {
2427 Ok(result) => break Ok(result),
2428 Err(e) => {
2429 if Self::is_locked_error(&e) {
2430 std::thread::sleep(std::time::Duration::from_micros(500));
2431 continue;
2432 } else {
2433 return Err(e).context("In load_key_entry.");
2434 }
2435 }
2436 }
2437 }
2438 }
2439
2440 fn load_key_entry_internal(
2441 &mut self,
2442 key: &KeyDescriptor,
2443 key_type: KeyType,
2444 load_bits: KeyEntryLoadBits,
2445 caller_uid: u32,
2446 check_permission: &impl Fn(&KeyDescriptor, Option<KeyPermSet>) -> Result<()>,
Janis Danisevskisaec14592020-11-12 09:41:49 -08002447 ) -> Result<(KeyIdGuard, KeyEntry)> {
2448 // KEY ID LOCK 1/2
2449 // If we got a key descriptor with a key id we can get the lock right away.
2450 // Otherwise we have to defer it until we know the key id.
2451 let key_id_guard = match key.domain {
2452 Domain::KEY_ID => Some(KEY_ID_LOCK.get(key.nspace)),
2453 _ => None,
2454 };
2455
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002456 let tx = self
2457 .conn
Janis Danisevskisaec14592020-11-12 09:41:49 -08002458 .unchecked_transaction()
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002459 .context("In load_key_entry: Failed to initialize transaction.")?;
2460
2461 // Load the key_id and complete the access control tuple.
2462 let (key_id, access_key_descriptor, access_vector) =
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002463 Self::load_access_tuple(&tx, key, key_type, caller_uid)
2464 .context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002465
2466 // Perform access control. It is vital that we return here if the permission is denied.
2467 // So do not touch that '?' at the end.
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002468 check_permission(&access_key_descriptor, access_vector).context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002469
Janis Danisevskisaec14592020-11-12 09:41:49 -08002470 // KEY ID LOCK 2/2
2471 // If we did not get a key id lock by now, it was because we got a key descriptor
2472 // without a key id. At this point we got the key id, so we can try and get a lock.
2473 // However, we cannot block here, because we are in the middle of the transaction.
2474 // So first we try to get the lock non blocking. If that fails, we roll back the
2475 // transaction and block until we get the lock. After we successfully got the lock,
2476 // we start a new transaction and load the access tuple again.
2477 //
2478 // We don't need to perform access control again, because we already established
2479 // that the caller had access to the given key. But we need to make sure that the
2480 // key id still exists. So we have to load the key entry by key id this time.
2481 let (key_id_guard, tx) = match key_id_guard {
2482 None => match KEY_ID_LOCK.try_get(key_id) {
2483 None => {
2484 // Roll back the transaction.
2485 tx.rollback().context("In load_key_entry: Failed to roll back transaction.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002486
Janis Danisevskisaec14592020-11-12 09:41:49 -08002487 // Block until we have a key id lock.
2488 let key_id_guard = KEY_ID_LOCK.get(key_id);
2489
2490 // Create a new transaction.
Janis Danisevskis66784c42021-01-27 08:40:25 -08002491 let tx = self
2492 .conn
2493 .unchecked_transaction()
2494 .context("In load_key_entry: Failed to initialize transaction.")?;
Janis Danisevskisaec14592020-11-12 09:41:49 -08002495
2496 Self::load_access_tuple(
2497 &tx,
2498 // This time we have to load the key by the retrieved key id, because the
2499 // alias may have been rebound after we rolled back the transaction.
Janis Danisevskis66784c42021-01-27 08:40:25 -08002500 &KeyDescriptor {
Janis Danisevskisaec14592020-11-12 09:41:49 -08002501 domain: Domain::KEY_ID,
2502 nspace: key_id,
2503 ..Default::default()
2504 },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002505 key_type,
Janis Danisevskisaec14592020-11-12 09:41:49 -08002506 caller_uid,
2507 )
2508 .context("In load_key_entry. (deferred key lock)")?;
2509 (key_id_guard, tx)
2510 }
2511 Some(l) => (l, tx),
2512 },
2513 Some(key_id_guard) => (key_id_guard, tx),
2514 };
2515
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002516 let key_entry = Self::load_key_components(&tx, load_bits, key_id_guard.id())
2517 .context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002518
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002519 tx.commit().context("In load_key_entry: Failed to commit transaction.")?;
2520
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002521 Ok((key_id_guard, key_entry))
2522 }
2523
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002524 fn mark_unreferenced(tx: &Transaction, key_id: i64) -> Result<bool> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002525 let updated = tx
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002526 .execute("DELETE FROM persistent.keyentry WHERE id = ?;", params![key_id])
2527 .context("Trying to delete keyentry.")?;
2528 tx.execute("DELETE FROM persistent.keymetadata WHERE keyentryid = ?;", params![key_id])
2529 .context("Trying to delete keymetadata.")?;
2530 tx.execute("DELETE FROM persistent.keyparameter WHERE keyentryid = ?;", params![key_id])
2531 .context("Trying to delete keyparameters.")?;
2532 tx.execute("DELETE FROM persistent.grant WHERE keyentryid = ?;", params![key_id])
2533 .context("Trying to delete grants.")?;
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002534 Ok(updated != 0)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002535 }
2536
2537 /// Marks the given key as unreferenced and removes all of the grants to this key.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002538 /// Returns Ok(true) if a key was marked unreferenced as a hint for the garbage collector.
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002539 pub fn unbind_key(
2540 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002541 key: &KeyDescriptor,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002542 key_type: KeyType,
2543 caller_uid: u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002544 check_permission: impl Fn(&KeyDescriptor, Option<KeyPermSet>) -> Result<()>,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002545 ) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002546 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2547 let (key_id, access_key_descriptor, access_vector) =
2548 Self::load_access_tuple(tx, key, key_type, caller_uid)
2549 .context("Trying to get access tuple.")?;
2550
2551 // Perform access control. It is vital that we return here if the permission is denied.
2552 // So do not touch that '?' at the end.
2553 check_permission(&access_key_descriptor, access_vector)
2554 .context("While checking permission.")?;
2555
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002556 Self::mark_unreferenced(tx, key_id)
2557 .map(|need_gc| (need_gc, ()))
2558 .context("Trying to mark the key unreferenced.")
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002559 })
2560 .context("In unbind_key.")
2561 }
2562
Max Bires8e93d2b2021-01-14 13:17:59 -08002563 fn get_key_km_uuid(tx: &Transaction, key_id: i64) -> Result<Uuid> {
2564 tx.query_row(
2565 "SELECT km_uuid FROM persistent.keyentry WHERE id = ?",
2566 params![key_id],
2567 |row| row.get(0),
2568 )
2569 .context("In get_key_km_uuid.")
2570 }
2571
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002572 /// Delete all artifacts belonging to the namespace given by the domain-namespace tuple.
2573 /// This leaves all of the blob entries orphaned for subsequent garbage collection.
2574 pub fn unbind_keys_for_namespace(&mut self, domain: Domain, namespace: i64) -> Result<()> {
2575 if !(domain == Domain::APP || domain == Domain::SELINUX) {
2576 return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT))
2577 .context("In unbind_keys_for_namespace.");
2578 }
2579 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2580 tx.execute(
2581 "DELETE FROM persistent.keymetadata
2582 WHERE keyentryid IN (
2583 SELECT id FROM persistent.keyentry
2584 WHERE domain = ? AND namespace = ?
2585 );",
2586 params![domain.0, namespace],
2587 )
2588 .context("Trying to delete keymetadata.")?;
2589 tx.execute(
2590 "DELETE FROM persistent.keyparameter
2591 WHERE keyentryid IN (
2592 SELECT id FROM persistent.keyentry
2593 WHERE domain = ? AND namespace = ?
2594 );",
2595 params![domain.0, namespace],
2596 )
2597 .context("Trying to delete keyparameters.")?;
2598 tx.execute(
2599 "DELETE FROM persistent.grant
2600 WHERE keyentryid IN (
2601 SELECT id FROM persistent.keyentry
2602 WHERE domain = ? AND namespace = ?
2603 );",
2604 params![domain.0, namespace],
2605 )
2606 .context("Trying to delete grants.")?;
2607 tx.execute(
2608 "DELETE FROM persistent.keyentry WHERE domain = ? AND namespace = ?;",
2609 params![domain.0, namespace],
2610 )
2611 .context("Trying to delete keyentry.")?;
2612 Ok(()).need_gc()
2613 })
2614 .context("In unbind_keys_for_namespace")
2615 }
2616
Hasini Gunasingheda895552021-01-27 19:34:37 +00002617 /// Delete the keys created on behalf of the user, denoted by the user id.
2618 /// Delete all the keys unless 'keep_non_super_encrypted_keys' set to true.
2619 /// Returned boolean is to hint the garbage collector to delete the unbound keys.
2620 /// The caller of this function should notify the gc if the returned value is true.
2621 pub fn unbind_keys_for_user(
2622 &mut self,
2623 user_id: u32,
2624 keep_non_super_encrypted_keys: bool,
2625 ) -> Result<()> {
2626 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2627 let mut stmt = tx
2628 .prepare(&format!(
2629 "SELECT id from persistent.keyentry
2630 WHERE (
2631 key_type = ?
2632 AND domain = ?
2633 AND cast ( (namespace/{aid_user_offset}) as int) = ?
2634 AND state = ?
2635 ) OR (
2636 key_type = ?
2637 AND namespace = ?
2638 AND alias = ?
2639 AND state = ?
2640 );",
2641 aid_user_offset = AID_USER_OFFSET
2642 ))
2643 .context(concat!(
2644 "In unbind_keys_for_user. ",
2645 "Failed to prepare the query to find the keys created by apps."
2646 ))?;
2647
2648 let mut rows = stmt
2649 .query(params![
2650 // WHERE client key:
2651 KeyType::Client,
2652 Domain::APP.0 as u32,
2653 user_id,
2654 KeyLifeCycle::Live,
2655 // OR super key:
2656 KeyType::Super,
2657 user_id,
Paul Crowley7a658392021-03-18 17:08:20 -07002658 USER_SUPER_KEY.alias,
Hasini Gunasingheda895552021-01-27 19:34:37 +00002659 KeyLifeCycle::Live
2660 ])
2661 .context("In unbind_keys_for_user. Failed to query the keys created by apps.")?;
2662
2663 let mut key_ids: Vec<i64> = Vec::new();
2664 db_utils::with_rows_extract_all(&mut rows, |row| {
2665 key_ids
2666 .push(row.get(0).context("Failed to read key id of a key created by an app.")?);
2667 Ok(())
2668 })
2669 .context("In unbind_keys_for_user.")?;
2670
2671 let mut notify_gc = false;
2672 for key_id in key_ids {
2673 if keep_non_super_encrypted_keys {
2674 // Load metadata and filter out non-super-encrypted keys.
2675 if let (_, Some((_, blob_metadata)), _, _) =
2676 Self::load_blob_components(key_id, KeyEntryLoadBits::KM, tx)
2677 .context("In unbind_keys_for_user: Trying to load blob info.")?
2678 {
2679 if blob_metadata.encrypted_by().is_none() {
2680 continue;
2681 }
2682 }
2683 }
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +00002684 notify_gc = Self::mark_unreferenced(&tx, key_id)
Hasini Gunasingheda895552021-01-27 19:34:37 +00002685 .context("In unbind_keys_for_user.")?
2686 || notify_gc;
2687 }
2688 Ok(()).do_gc(notify_gc)
2689 })
2690 .context("In unbind_keys_for_user.")
2691 }
2692
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002693 fn load_key_components(
2694 tx: &Transaction,
2695 load_bits: KeyEntryLoadBits,
2696 key_id: i64,
2697 ) -> Result<KeyEntry> {
2698 let metadata = KeyMetaData::load_from_db(key_id, &tx).context("In load_key_components.")?;
2699
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002700 let (has_km_blob, key_blob_info, cert_blob, cert_chain_blob) =
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002701 Self::load_blob_components(key_id, load_bits, &tx)
2702 .context("In load_key_components.")?;
2703
Max Bires8e93d2b2021-01-14 13:17:59 -08002704 let parameters = Self::load_key_parameters(key_id, &tx)
2705 .context("In load_key_components: Trying to load key parameters.")?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002706
Max Bires8e93d2b2021-01-14 13:17:59 -08002707 let km_uuid = Self::get_key_km_uuid(&tx, key_id)
2708 .context("In load_key_components: Trying to get KM uuid.")?;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002709
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002710 Ok(KeyEntry {
2711 id: key_id,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002712 key_blob_info,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002713 cert: cert_blob,
2714 cert_chain: cert_chain_blob,
Max Bires8e93d2b2021-01-14 13:17:59 -08002715 km_uuid,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002716 parameters,
2717 metadata,
Janis Danisevskis377d1002021-01-27 19:07:48 -08002718 pure_cert: !has_km_blob,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002719 })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002720 }
2721
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002722 /// Returns a list of KeyDescriptors in the selected domain/namespace.
2723 /// The key descriptors will have the domain, nspace, and alias field set.
2724 /// Domain must be APP or SELINUX, the caller must make sure of that.
2725 pub fn list(&mut self, domain: Domain, namespace: i64) -> Result<Vec<KeyDescriptor>> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002726 self.with_transaction(TransactionBehavior::Deferred, |tx| {
2727 let mut stmt = tx
2728 .prepare(
2729 "SELECT alias FROM persistent.keyentry
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002730 WHERE domain = ? AND namespace = ? AND alias IS NOT NULL AND state = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08002731 )
2732 .context("In list: Failed to prepare.")?;
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002733
Janis Danisevskis66784c42021-01-27 08:40:25 -08002734 let mut rows = stmt
2735 .query(params![domain.0 as u32, namespace, KeyLifeCycle::Live])
2736 .context("In list: Failed to query.")?;
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002737
Janis Danisevskis66784c42021-01-27 08:40:25 -08002738 let mut descriptors: Vec<KeyDescriptor> = Vec::new();
2739 db_utils::with_rows_extract_all(&mut rows, |row| {
2740 descriptors.push(KeyDescriptor {
2741 domain,
2742 nspace: namespace,
2743 alias: Some(row.get(0).context("Trying to extract alias.")?),
2744 blob: None,
2745 });
2746 Ok(())
2747 })
2748 .context("In list: Failed to extract rows.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002749 Ok(descriptors).no_gc()
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002750 })
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002751 }
2752
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002753 /// Adds a grant to the grant table.
2754 /// Like `load_key_entry` this function loads the access tuple before
2755 /// it uses the callback for a permission check. Upon success,
2756 /// it inserts the `grantee_uid`, `key_id`, and `access_vector` into the
2757 /// grant table. The new row will have a randomized id, which is used as
2758 /// grant id in the namespace field of the resulting KeyDescriptor.
2759 pub fn grant(
2760 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002761 key: &KeyDescriptor,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002762 caller_uid: u32,
2763 grantee_uid: u32,
2764 access_vector: KeyPermSet,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002765 check_permission: impl Fn(&KeyDescriptor, &KeyPermSet) -> Result<()>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002766 ) -> Result<KeyDescriptor> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002767 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2768 // Load the key_id and complete the access control tuple.
2769 // We ignore the access vector here because grants cannot be granted.
2770 // The access vector returned here expresses the permissions the
2771 // grantee has if key.domain == Domain::GRANT. But this vector
2772 // cannot include the grant permission by design, so there is no way the
2773 // subsequent permission check can pass.
2774 // We could check key.domain == Domain::GRANT and fail early.
2775 // But even if we load the access tuple by grant here, the permission
2776 // check denies the attempt to create a grant by grant descriptor.
2777 let (key_id, access_key_descriptor, _) =
2778 Self::load_access_tuple(&tx, key, KeyType::Client, caller_uid)
2779 .context("In grant")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002780
Janis Danisevskis66784c42021-01-27 08:40:25 -08002781 // Perform access control. It is vital that we return here if the permission
2782 // was denied. So do not touch that '?' at the end of the line.
2783 // This permission check checks if the caller has the grant permission
2784 // for the given key and in addition to all of the permissions
2785 // expressed in `access_vector`.
2786 check_permission(&access_key_descriptor, &access_vector)
2787 .context("In grant: check_permission failed.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002788
Janis Danisevskis66784c42021-01-27 08:40:25 -08002789 let grant_id = if let Some(grant_id) = tx
2790 .query_row(
2791 "SELECT id FROM persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002792 WHERE keyentryid = ? AND grantee = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08002793 params![key_id, grantee_uid],
2794 |row| row.get(0),
2795 )
2796 .optional()
2797 .context("In grant: Failed get optional existing grant id.")?
2798 {
2799 tx.execute(
2800 "UPDATE persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002801 SET access_vector = ?
2802 WHERE id = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08002803 params![i32::from(access_vector), grant_id],
Joel Galenson845f74b2020-09-09 14:11:55 -07002804 )
Janis Danisevskis66784c42021-01-27 08:40:25 -08002805 .context("In grant: Failed to update existing grant.")?;
2806 grant_id
2807 } else {
2808 Self::insert_with_retry(|id| {
2809 tx.execute(
2810 "INSERT INTO persistent.grant (id, grantee, keyentryid, access_vector)
2811 VALUES (?, ?, ?, ?);",
2812 params![id, grantee_uid, key_id, i32::from(access_vector)],
2813 )
2814 })
2815 .context("In grant")?
2816 };
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002817
Janis Danisevskis66784c42021-01-27 08:40:25 -08002818 Ok(KeyDescriptor { domain: Domain::GRANT, nspace: grant_id, alias: None, blob: None })
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002819 .no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08002820 })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002821 }
2822
2823 /// This function checks permissions like `grant` and `load_key_entry`
2824 /// before removing a grant from the grant table.
2825 pub fn ungrant(
2826 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002827 key: &KeyDescriptor,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002828 caller_uid: u32,
2829 grantee_uid: u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002830 check_permission: impl Fn(&KeyDescriptor) -> Result<()>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002831 ) -> Result<()> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002832 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2833 // Load the key_id and complete the access control tuple.
2834 // We ignore the access vector here because grants cannot be granted.
2835 let (key_id, access_key_descriptor, _) =
2836 Self::load_access_tuple(&tx, key, KeyType::Client, caller_uid)
2837 .context("In ungrant.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002838
Janis Danisevskis66784c42021-01-27 08:40:25 -08002839 // Perform access control. We must return here if the permission
2840 // was denied. So do not touch the '?' at the end of this line.
2841 check_permission(&access_key_descriptor)
2842 .context("In grant: check_permission failed.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002843
Janis Danisevskis66784c42021-01-27 08:40:25 -08002844 tx.execute(
2845 "DELETE FROM persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002846 WHERE keyentryid = ? AND grantee = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08002847 params![key_id, grantee_uid],
2848 )
2849 .context("Failed to delete grant.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002850
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002851 Ok(()).no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08002852 })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002853 }
2854
Joel Galenson845f74b2020-09-09 14:11:55 -07002855 // Generates a random id and passes it to the given function, which will
2856 // try to insert it into a database. If that insertion fails, retry;
2857 // otherwise return the id.
2858 fn insert_with_retry(inserter: impl Fn(i64) -> rusqlite::Result<usize>) -> Result<i64> {
2859 loop {
Janis Danisevskiseed69842021-02-18 20:04:10 -08002860 let newid: i64 = match random() {
2861 Self::UNASSIGNED_KEY_ID => continue, // UNASSIGNED_KEY_ID cannot be assigned.
2862 i => i,
2863 };
Joel Galenson845f74b2020-09-09 14:11:55 -07002864 match inserter(newid) {
2865 // If the id already existed, try again.
2866 Err(rusqlite::Error::SqliteFailure(
2867 libsqlite3_sys::Error {
2868 code: libsqlite3_sys::ErrorCode::ConstraintViolation,
2869 extended_code: libsqlite3_sys::SQLITE_CONSTRAINT_UNIQUE,
2870 },
2871 _,
2872 )) => (),
2873 Err(e) => {
2874 return Err(e).context("In insert_with_retry: failed to insert into database.")
2875 }
2876 _ => return Ok(newid),
2877 }
2878 }
2879 }
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002880
2881 /// Insert or replace the auth token based on the UNIQUE constraint of the auth token table
2882 pub fn insert_auth_token(&mut self, auth_token: &HardwareAuthToken) -> Result<()> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002883 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2884 tx.execute(
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002885 "INSERT OR REPLACE INTO perboot.authtoken (challenge, user_id, auth_id,
2886 authenticator_type, timestamp, mac, time_received) VALUES(?, ?, ?, ?, ?, ?, ?);",
2887 params![
2888 auth_token.challenge,
2889 auth_token.userId,
2890 auth_token.authenticatorId,
2891 auth_token.authenticatorType.0 as i32,
2892 auth_token.timestamp.milliSeconds as i64,
2893 auth_token.mac,
2894 MonotonicRawTime::now(),
2895 ],
2896 )
2897 .context("In insert_auth_token: failed to insert auth token into the database")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002898 Ok(()).no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08002899 })
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002900 }
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002901
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002902 /// Find the newest auth token matching the given predicate.
2903 pub fn find_auth_token_entry<F>(
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002904 &mut self,
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002905 p: F,
2906 ) -> Result<Option<(AuthTokenEntry, MonotonicRawTime)>>
2907 where
2908 F: Fn(&AuthTokenEntry) -> bool,
2909 {
2910 self.with_transaction(TransactionBehavior::Deferred, |tx| {
2911 let mut stmt = tx
2912 .prepare("SELECT * from perboot.authtoken ORDER BY time_received DESC;")
2913 .context("Prepare statement failed.")?;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002914
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002915 let mut rows = stmt.query(NO_PARAMS).context("Failed to query.")?;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002916
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002917 while let Some(row) = rows.next().context("Failed to get next row.")? {
2918 let entry = AuthTokenEntry::new(
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002919 HardwareAuthToken {
2920 challenge: row.get(1)?,
2921 userId: row.get(2)?,
2922 authenticatorId: row.get(3)?,
2923 authenticatorType: HardwareAuthenticatorType(row.get(4)?),
2924 timestamp: Timestamp { milliSeconds: row.get(5)? },
2925 mac: row.get(6)?,
2926 },
2927 row.get(7)?,
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002928 );
2929 if p(&entry) {
2930 return Ok(Some((
2931 entry,
2932 Self::get_last_off_body(tx)
2933 .context("In find_auth_token_entry: Trying to get last off body")?,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002934 )))
2935 .no_gc();
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002936 }
2937 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002938 Ok(None).no_gc()
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002939 })
2940 .context("In find_auth_token_entry.")
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002941 }
2942
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002943 /// Insert last_off_body into the metadata table at the initialization of auth token table
Janis Danisevskis66784c42021-01-27 08:40:25 -08002944 pub fn insert_last_off_body(&mut self, last_off_body: MonotonicRawTime) -> Result<()> {
2945 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2946 tx.execute(
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002947 "INSERT OR REPLACE INTO perboot.metadata (key, value) VALUES (?, ?);",
2948 params!["last_off_body", last_off_body],
2949 )
2950 .context("In insert_last_off_body: failed to insert.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002951 Ok(()).no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08002952 })
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002953 }
2954
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002955 /// Update last_off_body when on_device_off_body is called
Janis Danisevskis66784c42021-01-27 08:40:25 -08002956 pub fn update_last_off_body(&mut self, last_off_body: MonotonicRawTime) -> Result<()> {
2957 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2958 tx.execute(
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002959 "UPDATE perboot.metadata SET value = ? WHERE key = ?;",
2960 params![last_off_body, "last_off_body"],
2961 )
2962 .context("In update_last_off_body: failed to update.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002963 Ok(()).no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08002964 })
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002965 }
2966
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002967 /// Get last_off_body time when finding auth tokens
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002968 fn get_last_off_body(tx: &Transaction) -> Result<MonotonicRawTime> {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002969 tx.query_row(
2970 "SELECT value from perboot.metadata WHERE key = ?;",
2971 params!["last_off_body"],
2972 |row| Ok(row.get(0)?),
2973 )
2974 .context("In get_last_off_body: query_row failed.")
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002975 }
Joel Galenson26f4d012020-07-17 14:57:21 -07002976}
2977
2978#[cfg(test)]
2979mod tests {
2980
2981 use super::*;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002982 use crate::key_parameter::{
2983 Algorithm, BlockMode, Digest, EcCurve, HardwareAuthenticatorType, KeyOrigin, KeyParameter,
2984 KeyParameterValue, KeyPurpose, PaddingMode, SecurityLevel,
2985 };
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002986 use crate::key_perm_set;
2987 use crate::permission::{KeyPerm, KeyPermSet};
Hasini Gunasingheda895552021-01-27 19:34:37 +00002988 use crate::super_key::SuperKeyManager;
Janis Danisevskis2a8330a2021-01-20 15:34:26 -08002989 use keystore2_test_utils::TempDir;
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002990 use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
2991 HardwareAuthToken::HardwareAuthToken,
2992 HardwareAuthenticatorType::HardwareAuthenticatorType as kmhw_authenticator_type,
Janis Danisevskisc3a496b2021-01-05 10:37:22 -08002993 };
2994 use android_hardware_security_secureclock::aidl::android::hardware::security::secureclock::{
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002995 Timestamp::Timestamp,
2996 };
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002997 use rusqlite::NO_PARAMS;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002998 use rusqlite::{Error, TransactionBehavior};
Joel Galenson0891bc12020-07-20 10:37:03 -07002999 use std::cell::RefCell;
Janis Danisevskisaec14592020-11-12 09:41:49 -08003000 use std::sync::atomic::{AtomicU8, Ordering};
3001 use std::sync::Arc;
3002 use std::thread;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00003003 use std::time::{Duration, SystemTime};
Janis Danisevskis66784c42021-01-27 08:40:25 -08003004 #[cfg(disabled)]
3005 use std::time::Instant;
Joel Galenson0891bc12020-07-20 10:37:03 -07003006
Janis Danisevskis4df44f42020-08-26 14:40:03 -07003007 fn new_test_db() -> Result<KeystoreDB> {
3008 let conn = KeystoreDB::make_connection("file::memory:", "file::memory:")?;
3009
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003010 let mut db = KeystoreDB { conn, gc: None };
Janis Danisevskis66784c42021-01-27 08:40:25 -08003011 db.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003012 KeystoreDB::init_tables(tx).context("Failed to initialize tables.").no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08003013 })?;
3014 Ok(db)
Janis Danisevskis4df44f42020-08-26 14:40:03 -07003015 }
3016
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003017 fn new_test_db_with_gc<F>(path: &Path, cb: F) -> Result<KeystoreDB>
3018 where
3019 F: Fn(&Uuid, &[u8]) -> Result<()> + Send + 'static,
3020 {
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00003021 let super_key = Arc::new(SuperKeyManager::new());
3022
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003023 let gc_db = KeystoreDB::new(path, None).expect("Failed to open test gc db_connection.");
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00003024 let gc = Gc::new_init_with(Default::default(), move || (Box::new(cb), gc_db, super_key));
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003025
3026 KeystoreDB::new(path, Some(gc))
3027 }
3028
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003029 fn rebind_alias(
3030 db: &mut KeystoreDB,
3031 newid: &KeyIdGuard,
3032 alias: &str,
3033 domain: Domain,
3034 namespace: i64,
3035 ) -> Result<bool> {
3036 db.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003037 KeystoreDB::rebind_alias(tx, newid, alias, &domain, &namespace).no_gc()
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003038 })
3039 .context("In rebind_alias.")
3040 }
3041
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003042 #[test]
3043 fn datetime() -> Result<()> {
3044 let conn = Connection::open_in_memory()?;
3045 conn.execute("CREATE TABLE test (ts DATETIME);", NO_PARAMS)?;
3046 let now = SystemTime::now();
3047 let duration = Duration::from_secs(1000);
3048 let then = now.checked_sub(duration).unwrap();
3049 let soon = now.checked_add(duration).unwrap();
3050 conn.execute(
3051 "INSERT INTO test (ts) VALUES (?), (?), (?);",
3052 params![DateTime::try_from(now)?, DateTime::try_from(then)?, DateTime::try_from(soon)?],
3053 )?;
3054 let mut stmt = conn.prepare("SELECT ts FROM test ORDER BY ts ASC;")?;
3055 let mut rows = stmt.query(NO_PARAMS)?;
3056 assert_eq!(DateTime::try_from(then)?, rows.next()?.unwrap().get(0)?);
3057 assert_eq!(DateTime::try_from(now)?, rows.next()?.unwrap().get(0)?);
3058 assert_eq!(DateTime::try_from(soon)?, rows.next()?.unwrap().get(0)?);
3059 assert!(rows.next()?.is_none());
3060 assert!(DateTime::try_from(then)? < DateTime::try_from(now)?);
3061 assert!(DateTime::try_from(then)? < DateTime::try_from(soon)?);
3062 assert!(DateTime::try_from(now)? < DateTime::try_from(soon)?);
3063 Ok(())
3064 }
3065
Joel Galenson0891bc12020-07-20 10:37:03 -07003066 // Ensure that we're using the "injected" random function, not the real one.
3067 #[test]
3068 fn test_mocked_random() {
3069 let rand1 = random();
3070 let rand2 = random();
3071 let rand3 = random();
3072 if rand1 == rand2 {
3073 assert_eq!(rand2 + 1, rand3);
3074 } else {
3075 assert_eq!(rand1 + 1, rand2);
3076 assert_eq!(rand2, rand3);
3077 }
3078 }
Joel Galenson26f4d012020-07-17 14:57:21 -07003079
Joel Galenson26f4d012020-07-17 14:57:21 -07003080 // Test that we have the correct tables.
3081 #[test]
3082 fn test_tables() -> Result<()> {
Janis Danisevskis4df44f42020-08-26 14:40:03 -07003083 let db = new_test_db()?;
Joel Galenson26f4d012020-07-17 14:57:21 -07003084 let tables = db
3085 .conn
Joel Galenson2aab4432020-07-22 15:27:57 -07003086 .prepare("SELECT name from persistent.sqlite_master WHERE type='table' ORDER BY name;")?
Joel Galenson26f4d012020-07-17 14:57:21 -07003087 .query_map(params![], |row| row.get(0))?
3088 .collect::<rusqlite::Result<Vec<String>>>()?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003089 assert_eq!(tables.len(), 6);
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003090 assert_eq!(tables[0], "blobentry");
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003091 assert_eq!(tables[1], "blobmetadata");
3092 assert_eq!(tables[2], "grant");
3093 assert_eq!(tables[3], "keyentry");
3094 assert_eq!(tables[4], "keymetadata");
3095 assert_eq!(tables[5], "keyparameter");
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003096 let tables = db
3097 .conn
3098 .prepare("SELECT name from perboot.sqlite_master WHERE type='table' ORDER BY name;")?
3099 .query_map(params![], |row| row.get(0))?
3100 .collect::<rusqlite::Result<Vec<String>>>()?;
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00003101
3102 assert_eq!(tables.len(), 2);
3103 assert_eq!(tables[0], "authtoken");
3104 assert_eq!(tables[1], "metadata");
Joel Galenson2aab4432020-07-22 15:27:57 -07003105 Ok(())
3106 }
3107
3108 #[test]
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00003109 fn test_auth_token_table_invariant() -> Result<()> {
3110 let mut db = new_test_db()?;
3111 let auth_token1 = HardwareAuthToken {
3112 challenge: i64::MAX,
3113 userId: 200,
3114 authenticatorId: 200,
3115 authenticatorType: kmhw_authenticator_type(kmhw_authenticator_type::PASSWORD.0),
3116 timestamp: Timestamp { milliSeconds: 500 },
3117 mac: String::from("mac").into_bytes(),
3118 };
3119 db.insert_auth_token(&auth_token1)?;
3120 let auth_tokens_returned = get_auth_tokens(&mut db)?;
3121 assert_eq!(auth_tokens_returned.len(), 1);
3122
3123 // insert another auth token with the same values for the columns in the UNIQUE constraint
3124 // of the auth token table and different value for timestamp
3125 let auth_token2 = HardwareAuthToken {
3126 challenge: i64::MAX,
3127 userId: 200,
3128 authenticatorId: 200,
3129 authenticatorType: kmhw_authenticator_type(kmhw_authenticator_type::PASSWORD.0),
3130 timestamp: Timestamp { milliSeconds: 600 },
3131 mac: String::from("mac").into_bytes(),
3132 };
3133
3134 db.insert_auth_token(&auth_token2)?;
3135 let mut auth_tokens_returned = get_auth_tokens(&mut db)?;
3136 assert_eq!(auth_tokens_returned.len(), 1);
3137
3138 if let Some(auth_token) = auth_tokens_returned.pop() {
3139 assert_eq!(auth_token.auth_token.timestamp.milliSeconds, 600);
3140 }
3141
3142 // insert another auth token with the different values for the columns in the UNIQUE
3143 // constraint of the auth token table
3144 let auth_token3 = HardwareAuthToken {
3145 challenge: i64::MAX,
3146 userId: 201,
3147 authenticatorId: 200,
3148 authenticatorType: kmhw_authenticator_type(kmhw_authenticator_type::PASSWORD.0),
3149 timestamp: Timestamp { milliSeconds: 600 },
3150 mac: String::from("mac").into_bytes(),
3151 };
3152
3153 db.insert_auth_token(&auth_token3)?;
3154 let auth_tokens_returned = get_auth_tokens(&mut db)?;
3155 assert_eq!(auth_tokens_returned.len(), 2);
3156
3157 Ok(())
3158 }
3159
3160 // utility function for test_auth_token_table_invariant()
3161 fn get_auth_tokens(db: &mut KeystoreDB) -> Result<Vec<AuthTokenEntry>> {
3162 let mut stmt = db.conn.prepare("SELECT * from perboot.authtoken;")?;
3163
3164 let auth_token_entries: Vec<AuthTokenEntry> = stmt
3165 .query_map(NO_PARAMS, |row| {
3166 Ok(AuthTokenEntry::new(
3167 HardwareAuthToken {
3168 challenge: row.get(1)?,
3169 userId: row.get(2)?,
3170 authenticatorId: row.get(3)?,
3171 authenticatorType: HardwareAuthenticatorType(row.get(4)?),
3172 timestamp: Timestamp { milliSeconds: row.get(5)? },
3173 mac: row.get(6)?,
3174 },
3175 row.get(7)?,
3176 ))
3177 })?
3178 .collect::<Result<Vec<AuthTokenEntry>, Error>>()?;
3179 Ok(auth_token_entries)
3180 }
3181
3182 #[test]
Joel Galenson2aab4432020-07-22 15:27:57 -07003183 fn test_persistence_for_files() -> Result<()> {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08003184 let temp_dir = TempDir::new("persistent_db_test")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003185 let mut db = KeystoreDB::new(temp_dir.path(), None)?;
Joel Galenson2aab4432020-07-22 15:27:57 -07003186
Janis Danisevskis66784c42021-01-27 08:40:25 -08003187 db.create_key_entry(&Domain::APP, &100, &KEYSTORE_UUID)?;
Joel Galenson2aab4432020-07-22 15:27:57 -07003188 let entries = get_keyentry(&db)?;
3189 assert_eq!(entries.len(), 1);
Janis Danisevskisbf15d732020-12-08 10:35:26 -08003190
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003191 let db = KeystoreDB::new(temp_dir.path(), None)?;
Joel Galenson2aab4432020-07-22 15:27:57 -07003192
3193 let entries_new = get_keyentry(&db)?;
3194 assert_eq!(entries, entries_new);
3195 Ok(())
3196 }
3197
3198 #[test]
Joel Galenson0891bc12020-07-20 10:37:03 -07003199 fn test_create_key_entry() -> Result<()> {
Max Bires8e93d2b2021-01-14 13:17:59 -08003200 fn extractor(ke: &KeyEntryRow) -> (Domain, i64, Option<&str>, Uuid) {
3201 (ke.domain.unwrap(), ke.namespace.unwrap(), ke.alias.as_deref(), ke.km_uuid.unwrap())
Joel Galenson0891bc12020-07-20 10:37:03 -07003202 }
3203
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003204 let mut db = new_test_db()?;
Joel Galenson0891bc12020-07-20 10:37:03 -07003205
Janis Danisevskis66784c42021-01-27 08:40:25 -08003206 db.create_key_entry(&Domain::APP, &100, &KEYSTORE_UUID)?;
3207 db.create_key_entry(&Domain::SELINUX, &101, &KEYSTORE_UUID)?;
Joel Galenson0891bc12020-07-20 10:37:03 -07003208
3209 let entries = get_keyentry(&db)?;
3210 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08003211 assert_eq!(extractor(&entries[0]), (Domain::APP, 100, None, KEYSTORE_UUID));
3212 assert_eq!(extractor(&entries[1]), (Domain::SELINUX, 101, None, KEYSTORE_UUID));
Joel Galenson0891bc12020-07-20 10:37:03 -07003213
3214 // Test that we must pass in a valid Domain.
3215 check_result_is_error_containing_string(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003216 db.create_key_entry(&Domain::GRANT, &102, &KEYSTORE_UUID),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003217 "Domain Domain(1) must be either App or SELinux.",
Joel Galenson0891bc12020-07-20 10:37:03 -07003218 );
3219 check_result_is_error_containing_string(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003220 db.create_key_entry(&Domain::BLOB, &103, &KEYSTORE_UUID),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003221 "Domain Domain(3) must be either App or SELinux.",
Joel Galenson0891bc12020-07-20 10:37:03 -07003222 );
3223 check_result_is_error_containing_string(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003224 db.create_key_entry(&Domain::KEY_ID, &104, &KEYSTORE_UUID),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003225 "Domain Domain(4) must be either App or SELinux.",
Joel Galenson0891bc12020-07-20 10:37:03 -07003226 );
3227
3228 Ok(())
3229 }
3230
Joel Galenson33c04ad2020-08-03 11:04:38 -07003231 #[test]
Max Bires2b2e6562020-09-22 11:22:36 -07003232 fn test_add_unsigned_key() -> Result<()> {
3233 let mut db = new_test_db()?;
3234 let public_key: Vec<u8> = vec![0x01, 0x02, 0x03];
3235 let private_key: Vec<u8> = vec![0x04, 0x05, 0x06];
3236 let raw_public_key: Vec<u8> = vec![0x07, 0x08, 0x09];
3237 db.create_attestation_key_entry(
3238 &public_key,
3239 &raw_public_key,
3240 &private_key,
3241 &KEYSTORE_UUID,
3242 )?;
3243 let keys = db.fetch_unsigned_attestation_keys(5, &KEYSTORE_UUID)?;
3244 assert_eq!(keys.len(), 1);
3245 assert_eq!(keys[0], public_key);
3246 Ok(())
3247 }
3248
3249 #[test]
3250 fn test_store_signed_attestation_certificate_chain() -> Result<()> {
3251 let mut db = new_test_db()?;
3252 let expiration_date: i64 = 20;
3253 let namespace: i64 = 30;
3254 let base_byte: u8 = 1;
3255 let loaded_values =
3256 load_attestation_key_pool(&mut db, expiration_date, namespace, base_byte)?;
3257 let chain =
3258 db.retrieve_attestation_key_and_cert_chain(Domain::APP, namespace, &KEYSTORE_UUID)?;
3259 assert_eq!(true, chain.is_some());
3260 let cert_chain = chain.unwrap();
Max Biresb2e1d032021-02-08 21:35:05 -08003261 assert_eq!(cert_chain.private_key.to_vec(), loaded_values.priv_key);
Max Bires97f96812021-02-23 23:44:57 -08003262 assert_eq!(cert_chain.batch_cert, loaded_values.batch_cert);
3263 assert_eq!(cert_chain.cert_chain, loaded_values.cert_chain);
Max Bires2b2e6562020-09-22 11:22:36 -07003264 Ok(())
3265 }
3266
3267 #[test]
3268 fn test_get_attestation_pool_status() -> Result<()> {
3269 let mut db = new_test_db()?;
3270 let namespace: i64 = 30;
3271 load_attestation_key_pool(
3272 &mut db, 10, /* expiration */
3273 namespace, 0x01, /* base_byte */
3274 )?;
3275 load_attestation_key_pool(&mut db, 20 /* expiration */, namespace + 1, 0x02)?;
3276 load_attestation_key_pool(&mut db, 40 /* expiration */, namespace + 2, 0x03)?;
3277 let mut status = db.get_attestation_pool_status(9 /* expiration */, &KEYSTORE_UUID)?;
3278 assert_eq!(status.expiring, 0);
3279 assert_eq!(status.attested, 3);
3280 assert_eq!(status.unassigned, 0);
3281 assert_eq!(status.total, 3);
3282 assert_eq!(
3283 db.get_attestation_pool_status(15 /* expiration */, &KEYSTORE_UUID)?.expiring,
3284 1
3285 );
3286 assert_eq!(
3287 db.get_attestation_pool_status(25 /* expiration */, &KEYSTORE_UUID)?.expiring,
3288 2
3289 );
3290 assert_eq!(
3291 db.get_attestation_pool_status(60 /* expiration */, &KEYSTORE_UUID)?.expiring,
3292 3
3293 );
3294 let public_key: Vec<u8> = vec![0x01, 0x02, 0x03];
3295 let private_key: Vec<u8> = vec![0x04, 0x05, 0x06];
3296 let raw_public_key: Vec<u8> = vec![0x07, 0x08, 0x09];
3297 let cert_chain: Vec<u8> = vec![0x0a, 0x0b, 0x0c];
Max Biresb2e1d032021-02-08 21:35:05 -08003298 let batch_cert: Vec<u8> = vec![0x0d, 0x0e, 0x0f];
Max Bires2b2e6562020-09-22 11:22:36 -07003299 db.create_attestation_key_entry(
3300 &public_key,
3301 &raw_public_key,
3302 &private_key,
3303 &KEYSTORE_UUID,
3304 )?;
3305 status = db.get_attestation_pool_status(0 /* expiration */, &KEYSTORE_UUID)?;
3306 assert_eq!(status.attested, 3);
3307 assert_eq!(status.unassigned, 0);
3308 assert_eq!(status.total, 4);
3309 db.store_signed_attestation_certificate_chain(
3310 &raw_public_key,
Max Biresb2e1d032021-02-08 21:35:05 -08003311 &batch_cert,
Max Bires2b2e6562020-09-22 11:22:36 -07003312 &cert_chain,
3313 20,
3314 &KEYSTORE_UUID,
3315 )?;
3316 status = db.get_attestation_pool_status(0 /* expiration */, &KEYSTORE_UUID)?;
3317 assert_eq!(status.attested, 4);
3318 assert_eq!(status.unassigned, 1);
3319 assert_eq!(status.total, 4);
3320 Ok(())
3321 }
3322
3323 #[test]
3324 fn test_remove_expired_certs() -> Result<()> {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003325 let temp_dir =
3326 TempDir::new("test_remove_expired_certs_").expect("Failed to create temp dir.");
3327 let mut db = new_test_db_with_gc(temp_dir.path(), |_, _| Ok(()))?;
Max Bires2b2e6562020-09-22 11:22:36 -07003328 let expiration_date: i64 =
3329 SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_millis() as i64 + 10000;
3330 let namespace: i64 = 30;
3331 let namespace_del1: i64 = 45;
3332 let namespace_del2: i64 = 60;
3333 let entry_values = load_attestation_key_pool(
3334 &mut db,
3335 expiration_date,
3336 namespace,
3337 0x01, /* base_byte */
3338 )?;
3339 load_attestation_key_pool(&mut db, 45, namespace_del1, 0x02)?;
3340 load_attestation_key_pool(&mut db, 60, namespace_del2, 0x03)?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003341
3342 let blob_entry_row_count: u32 = db
3343 .conn
3344 .query_row("SELECT COUNT(id) FROM persistent.blobentry;", NO_PARAMS, |row| row.get(0))
3345 .expect("Failed to get blob entry row count.");
Max Biresb2e1d032021-02-08 21:35:05 -08003346 // We expect 9 rows here because there are three blobs per attestation key, i.e.,
3347 // one key, one certificate chain, and one certificate.
3348 assert_eq!(blob_entry_row_count, 9);
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003349
Max Bires2b2e6562020-09-22 11:22:36 -07003350 assert_eq!(db.delete_expired_attestation_keys()?, 2);
3351
3352 let mut cert_chain =
3353 db.retrieve_attestation_key_and_cert_chain(Domain::APP, namespace, &KEYSTORE_UUID)?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003354 assert!(cert_chain.is_some());
Max Bires2b2e6562020-09-22 11:22:36 -07003355 let value = cert_chain.unwrap();
Max Bires97f96812021-02-23 23:44:57 -08003356 assert_eq!(entry_values.batch_cert, value.batch_cert);
3357 assert_eq!(entry_values.cert_chain, value.cert_chain);
Max Biresb2e1d032021-02-08 21:35:05 -08003358 assert_eq!(entry_values.priv_key, value.private_key.to_vec());
Max Bires2b2e6562020-09-22 11:22:36 -07003359
3360 cert_chain = db.retrieve_attestation_key_and_cert_chain(
3361 Domain::APP,
3362 namespace_del1,
3363 &KEYSTORE_UUID,
3364 )?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003365 assert!(!cert_chain.is_some());
Max Bires2b2e6562020-09-22 11:22:36 -07003366 cert_chain = db.retrieve_attestation_key_and_cert_chain(
3367 Domain::APP,
3368 namespace_del2,
3369 &KEYSTORE_UUID,
3370 )?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003371 assert!(!cert_chain.is_some());
Max Bires2b2e6562020-09-22 11:22:36 -07003372
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003373 // Give the garbage collector half a second to catch up.
3374 std::thread::sleep(Duration::from_millis(500));
Max Bires2b2e6562020-09-22 11:22:36 -07003375
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003376 let blob_entry_row_count: u32 = db
3377 .conn
3378 .query_row("SELECT COUNT(id) FROM persistent.blobentry;", NO_PARAMS, |row| row.get(0))
3379 .expect("Failed to get blob entry row count.");
Max Biresb2e1d032021-02-08 21:35:05 -08003380 // There shound be 3 blob entries left, because we deleted two of the attestation
3381 // key entries with three blobs each.
3382 assert_eq!(blob_entry_row_count, 3);
Max Bires2b2e6562020-09-22 11:22:36 -07003383
Max Bires2b2e6562020-09-22 11:22:36 -07003384 Ok(())
3385 }
3386
3387 #[test]
Max Bires60d7ed12021-03-05 15:59:22 -08003388 fn test_delete_all_attestation_keys() -> Result<()> {
3389 let mut db = new_test_db()?;
3390 load_attestation_key_pool(&mut db, 45 /* expiration */, 1 /* namespace */, 0x02)?;
3391 load_attestation_key_pool(&mut db, 80 /* expiration */, 2 /* namespace */, 0x03)?;
3392 db.create_key_entry(&Domain::APP, &42, &KEYSTORE_UUID)?;
3393 let result = db.delete_all_attestation_keys()?;
3394
3395 // Give the garbage collector half a second to catch up.
3396 std::thread::sleep(Duration::from_millis(500));
3397
3398 // Attestation keys should be deleted, and the regular key should remain.
3399 assert_eq!(result, 2);
3400
3401 Ok(())
3402 }
3403
3404 #[test]
Joel Galenson33c04ad2020-08-03 11:04:38 -07003405 fn test_rebind_alias() -> Result<()> {
Max Bires8e93d2b2021-01-14 13:17:59 -08003406 fn extractor(
3407 ke: &KeyEntryRow,
3408 ) -> (Option<Domain>, Option<i64>, Option<&str>, Option<Uuid>) {
3409 (ke.domain, ke.namespace, ke.alias.as_deref(), ke.km_uuid)
Joel Galenson33c04ad2020-08-03 11:04:38 -07003410 }
3411
Janis Danisevskis4df44f42020-08-26 14:40:03 -07003412 let mut db = new_test_db()?;
Janis Danisevskis66784c42021-01-27 08:40:25 -08003413 db.create_key_entry(&Domain::APP, &42, &KEYSTORE_UUID)?;
3414 db.create_key_entry(&Domain::APP, &42, &KEYSTORE_UUID)?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07003415 let entries = get_keyentry(&db)?;
3416 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08003417 assert_eq!(
3418 extractor(&entries[0]),
3419 (Some(Domain::APP), Some(42), None, Some(KEYSTORE_UUID))
3420 );
3421 assert_eq!(
3422 extractor(&entries[1]),
3423 (Some(Domain::APP), Some(42), None, Some(KEYSTORE_UUID))
3424 );
Joel Galenson33c04ad2020-08-03 11:04:38 -07003425
3426 // Test that the first call to rebind_alias sets the alias.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003427 rebind_alias(&mut db, &KEY_ID_LOCK.get(entries[0].id), "foo", Domain::APP, 42)?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07003428 let entries = get_keyentry(&db)?;
3429 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08003430 assert_eq!(
3431 extractor(&entries[0]),
3432 (Some(Domain::APP), Some(42), Some("foo"), Some(KEYSTORE_UUID))
3433 );
3434 assert_eq!(
3435 extractor(&entries[1]),
3436 (Some(Domain::APP), Some(42), None, Some(KEYSTORE_UUID))
3437 );
Joel Galenson33c04ad2020-08-03 11:04:38 -07003438
3439 // Test that the second call to rebind_alias also empties the old one.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003440 rebind_alias(&mut db, &KEY_ID_LOCK.get(entries[1].id), "foo", Domain::APP, 42)?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07003441 let entries = get_keyentry(&db)?;
3442 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08003443 assert_eq!(extractor(&entries[0]), (None, None, None, Some(KEYSTORE_UUID)));
3444 assert_eq!(
3445 extractor(&entries[1]),
3446 (Some(Domain::APP), Some(42), Some("foo"), Some(KEYSTORE_UUID))
3447 );
Joel Galenson33c04ad2020-08-03 11:04:38 -07003448
3449 // Test that we must pass in a valid Domain.
3450 check_result_is_error_containing_string(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003451 rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::GRANT, 42),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003452 "Domain Domain(1) must be either App or SELinux.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07003453 );
3454 check_result_is_error_containing_string(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003455 rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::BLOB, 42),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003456 "Domain Domain(3) must be either App or SELinux.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07003457 );
3458 check_result_is_error_containing_string(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003459 rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::KEY_ID, 42),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003460 "Domain Domain(4) must be either App or SELinux.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07003461 );
3462
3463 // Test that we correctly handle setting an alias for something that does not exist.
3464 check_result_is_error_containing_string(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003465 rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::SELINUX, 42),
Joel Galenson33c04ad2020-08-03 11:04:38 -07003466 "Expected to update a single entry but instead updated 0",
3467 );
3468 // Test that we correctly abort the transaction in this case.
3469 let entries = get_keyentry(&db)?;
3470 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08003471 assert_eq!(extractor(&entries[0]), (None, None, None, Some(KEYSTORE_UUID)));
3472 assert_eq!(
3473 extractor(&entries[1]),
3474 (Some(Domain::APP), Some(42), Some("foo"), Some(KEYSTORE_UUID))
3475 );
Joel Galenson33c04ad2020-08-03 11:04:38 -07003476
3477 Ok(())
3478 }
3479
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003480 #[test]
3481 fn test_grant_ungrant() -> Result<()> {
3482 const CALLER_UID: u32 = 15;
3483 const GRANTEE_UID: u32 = 12;
3484 const SELINUX_NAMESPACE: i64 = 7;
3485
3486 let mut db = new_test_db()?;
3487 db.conn.execute(
Max Bires8e93d2b2021-01-14 13:17:59 -08003488 "INSERT INTO persistent.keyentry (id, key_type, domain, namespace, alias, state, km_uuid)
3489 VALUES (1, 0, 0, 15, 'key', 1, ?), (2, 0, 2, 7, 'yek', 1, ?);",
3490 params![KEYSTORE_UUID, KEYSTORE_UUID],
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003491 )?;
3492 let app_key = KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003493 domain: super::Domain::APP,
3494 nspace: 0,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003495 alias: Some("key".to_string()),
3496 blob: None,
3497 };
3498 const PVEC1: KeyPermSet = key_perm_set![KeyPerm::use_(), KeyPerm::get_info()];
3499 const PVEC2: KeyPermSet = key_perm_set![KeyPerm::use_()];
3500
3501 // Reset totally predictable random number generator in case we
3502 // are not the first test running on this thread.
3503 reset_random();
3504 let next_random = 0i64;
3505
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003506 let app_granted_key = db
Janis Danisevskis66784c42021-01-27 08:40:25 -08003507 .grant(&app_key, CALLER_UID, GRANTEE_UID, PVEC1, |k, a| {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003508 assert_eq!(*a, PVEC1);
3509 assert_eq!(
3510 *k,
3511 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003512 domain: super::Domain::APP,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003513 // namespace must be set to the caller_uid.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003514 nspace: CALLER_UID as i64,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003515 alias: Some("key".to_string()),
3516 blob: None,
3517 }
3518 );
3519 Ok(())
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003520 })
3521 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003522
3523 assert_eq!(
3524 app_granted_key,
3525 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003526 domain: super::Domain::GRANT,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003527 // The grantid is next_random due to the mock random number generator.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003528 nspace: next_random,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003529 alias: None,
3530 blob: None,
3531 }
3532 );
3533
3534 let selinux_key = KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003535 domain: super::Domain::SELINUX,
3536 nspace: SELINUX_NAMESPACE,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003537 alias: Some("yek".to_string()),
3538 blob: None,
3539 };
3540
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003541 let selinux_granted_key = db
Janis Danisevskis66784c42021-01-27 08:40:25 -08003542 .grant(&selinux_key, CALLER_UID, 12, PVEC1, |k, a| {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003543 assert_eq!(*a, PVEC1);
3544 assert_eq!(
3545 *k,
3546 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003547 domain: super::Domain::SELINUX,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003548 // namespace must be the supplied SELinux
3549 // namespace.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003550 nspace: SELINUX_NAMESPACE,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003551 alias: Some("yek".to_string()),
3552 blob: None,
3553 }
3554 );
3555 Ok(())
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003556 })
3557 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003558
3559 assert_eq!(
3560 selinux_granted_key,
3561 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003562 domain: super::Domain::GRANT,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003563 // The grantid is next_random + 1 due to the mock random number generator.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003564 nspace: next_random + 1,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003565 alias: None,
3566 blob: None,
3567 }
3568 );
3569
3570 // This should update the existing grant with PVEC2.
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003571 let selinux_granted_key = db
Janis Danisevskis66784c42021-01-27 08:40:25 -08003572 .grant(&selinux_key, CALLER_UID, 12, PVEC2, |k, a| {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003573 assert_eq!(*a, PVEC2);
3574 assert_eq!(
3575 *k,
3576 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003577 domain: super::Domain::SELINUX,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003578 // namespace must be the supplied SELinux
3579 // namespace.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003580 nspace: SELINUX_NAMESPACE,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003581 alias: Some("yek".to_string()),
3582 blob: None,
3583 }
3584 );
3585 Ok(())
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003586 })
3587 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003588
3589 assert_eq!(
3590 selinux_granted_key,
3591 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003592 domain: super::Domain::GRANT,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003593 // Same grant id as before. The entry was only updated.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003594 nspace: next_random + 1,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003595 alias: None,
3596 blob: None,
3597 }
3598 );
3599
3600 {
3601 // Limiting scope of stmt, because it borrows db.
3602 let mut stmt = db
3603 .conn
Janis Danisevskisbf15d732020-12-08 10:35:26 -08003604 .prepare("SELECT id, grantee, keyentryid, access_vector FROM persistent.grant;")?;
Janis Danisevskisee10b5f2020-09-22 16:42:35 -07003605 let mut rows =
3606 stmt.query_map::<(i64, u32, i64, KeyPermSet), _, _>(NO_PARAMS, |row| {
3607 Ok((
3608 row.get(0)?,
3609 row.get(1)?,
3610 row.get(2)?,
3611 KeyPermSet::from(row.get::<_, i32>(3)?),
3612 ))
3613 })?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003614
3615 let r = rows.next().unwrap().unwrap();
Janis Danisevskisee10b5f2020-09-22 16:42:35 -07003616 assert_eq!(r, (next_random, GRANTEE_UID, 1, PVEC1));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003617 let r = rows.next().unwrap().unwrap();
Janis Danisevskisee10b5f2020-09-22 16:42:35 -07003618 assert_eq!(r, (next_random + 1, GRANTEE_UID, 2, PVEC2));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003619 assert!(rows.next().is_none());
3620 }
3621
3622 debug_dump_keyentry_table(&mut db)?;
3623 println!("app_key {:?}", app_key);
3624 println!("selinux_key {:?}", selinux_key);
3625
Janis Danisevskis66784c42021-01-27 08:40:25 -08003626 db.ungrant(&app_key, CALLER_UID, GRANTEE_UID, |_| Ok(()))?;
3627 db.ungrant(&selinux_key, CALLER_UID, GRANTEE_UID, |_| Ok(()))?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003628
3629 Ok(())
3630 }
3631
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003632 static TEST_KEY_BLOB: &[u8] = b"my test blob";
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003633 static TEST_CERT_BLOB: &[u8] = b"my test cert";
3634 static TEST_CERT_CHAIN_BLOB: &[u8] = b"my test cert_chain";
3635
3636 #[test]
Janis Danisevskis377d1002021-01-27 19:07:48 -08003637 fn test_set_blob() -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003638 let key_id = KEY_ID_LOCK.get(3000);
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003639 let mut db = new_test_db()?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003640 let mut blob_metadata = BlobMetaData::new();
3641 blob_metadata.add(BlobMetaEntry::KmUuid(KEYSTORE_UUID));
3642 db.set_blob(
3643 &key_id,
3644 SubComponentType::KEY_BLOB,
3645 Some(TEST_KEY_BLOB),
3646 Some(&blob_metadata),
3647 )?;
3648 db.set_blob(&key_id, SubComponentType::CERT, Some(TEST_CERT_BLOB), None)?;
3649 db.set_blob(&key_id, SubComponentType::CERT_CHAIN, Some(TEST_CERT_CHAIN_BLOB), None)?;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003650 drop(key_id);
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003651
3652 let mut stmt = db.conn.prepare(
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003653 "SELECT subcomponent_type, keyentryid, blob, id FROM persistent.blobentry
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003654 ORDER BY subcomponent_type ASC;",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003655 )?;
3656 let mut rows = stmt
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003657 .query_map::<((SubComponentType, i64, Vec<u8>), i64), _, _>(NO_PARAMS, |row| {
3658 Ok(((row.get(0)?, row.get(1)?, row.get(2)?), row.get(3)?))
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003659 })?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003660 let (r, id) = rows.next().unwrap().unwrap();
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003661 assert_eq!(r, (SubComponentType::KEY_BLOB, 3000, TEST_KEY_BLOB.to_vec()));
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003662 let (r, _) = rows.next().unwrap().unwrap();
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003663 assert_eq!(r, (SubComponentType::CERT, 3000, TEST_CERT_BLOB.to_vec()));
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003664 let (r, _) = rows.next().unwrap().unwrap();
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003665 assert_eq!(r, (SubComponentType::CERT_CHAIN, 3000, TEST_CERT_CHAIN_BLOB.to_vec()));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003666
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003667 drop(rows);
3668 drop(stmt);
3669
3670 assert_eq!(
3671 db.with_transaction(TransactionBehavior::Immediate, |tx| {
3672 BlobMetaData::load_from_db(id, tx).no_gc()
3673 })
3674 .expect("Should find blob metadata."),
3675 blob_metadata
3676 );
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003677 Ok(())
3678 }
3679
3680 static TEST_ALIAS: &str = "my super duper key";
3681
3682 #[test]
3683 fn test_insert_and_load_full_keyentry_domain_app() -> Result<()> {
3684 let mut db = new_test_db()?;
Qi Wub9433b52020-12-01 14:52:46 +08003685 let key_id = make_test_key_entry(&mut db, Domain::APP, 1, TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08003686 .context("test_insert_and_load_full_keyentry_domain_app")?
3687 .0;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003688 let (_key_guard, key_entry) = db
3689 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003690 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003691 domain: Domain::APP,
3692 nspace: 0,
3693 alias: Some(TEST_ALIAS.to_string()),
3694 blob: None,
3695 },
3696 KeyType::Client,
3697 KeyEntryLoadBits::BOTH,
3698 1,
3699 |_k, _av| Ok(()),
3700 )
3701 .unwrap();
Qi Wub9433b52020-12-01 14:52:46 +08003702 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003703
3704 db.unbind_key(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003705 &KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003706 domain: Domain::APP,
3707 nspace: 0,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003708 alias: Some(TEST_ALIAS.to_string()),
3709 blob: None,
3710 },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003711 KeyType::Client,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003712 1,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003713 |_, _| Ok(()),
3714 )
3715 .unwrap();
3716
3717 assert_eq!(
3718 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
3719 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003720 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003721 domain: Domain::APP,
3722 nspace: 0,
3723 alias: Some(TEST_ALIAS.to_string()),
3724 blob: None,
3725 },
3726 KeyType::Client,
3727 KeyEntryLoadBits::NONE,
3728 1,
3729 |_k, _av| Ok(()),
3730 )
3731 .unwrap_err()
3732 .root_cause()
3733 .downcast_ref::<KsError>()
3734 );
3735
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003736 Ok(())
3737 }
3738
3739 #[test]
Janis Danisevskis377d1002021-01-27 19:07:48 -08003740 fn test_insert_and_load_certificate_entry_domain_app() -> Result<()> {
3741 let mut db = new_test_db()?;
3742
3743 db.store_new_certificate(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003744 &KeyDescriptor {
Janis Danisevskis377d1002021-01-27 19:07:48 -08003745 domain: Domain::APP,
3746 nspace: 1,
3747 alias: Some(TEST_ALIAS.to_string()),
3748 blob: None,
3749 },
3750 TEST_CERT_BLOB,
Max Bires8e93d2b2021-01-14 13:17:59 -08003751 &KEYSTORE_UUID,
Janis Danisevskis377d1002021-01-27 19:07:48 -08003752 )
3753 .expect("Trying to insert cert.");
3754
3755 let (_key_guard, mut key_entry) = db
3756 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003757 &KeyDescriptor {
Janis Danisevskis377d1002021-01-27 19:07:48 -08003758 domain: Domain::APP,
3759 nspace: 1,
3760 alias: Some(TEST_ALIAS.to_string()),
3761 blob: None,
3762 },
3763 KeyType::Client,
3764 KeyEntryLoadBits::PUBLIC,
3765 1,
3766 |_k, _av| Ok(()),
3767 )
3768 .expect("Trying to read certificate entry.");
3769
3770 assert!(key_entry.pure_cert());
3771 assert!(key_entry.cert().is_none());
3772 assert_eq!(key_entry.take_cert_chain(), Some(TEST_CERT_BLOB.to_vec()));
3773
3774 db.unbind_key(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003775 &KeyDescriptor {
Janis Danisevskis377d1002021-01-27 19:07:48 -08003776 domain: Domain::APP,
3777 nspace: 1,
3778 alias: Some(TEST_ALIAS.to_string()),
3779 blob: None,
3780 },
3781 KeyType::Client,
3782 1,
3783 |_, _| Ok(()),
3784 )
3785 .unwrap();
3786
3787 assert_eq!(
3788 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
3789 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003790 &KeyDescriptor {
Janis Danisevskis377d1002021-01-27 19:07:48 -08003791 domain: Domain::APP,
3792 nspace: 1,
3793 alias: Some(TEST_ALIAS.to_string()),
3794 blob: None,
3795 },
3796 KeyType::Client,
3797 KeyEntryLoadBits::NONE,
3798 1,
3799 |_k, _av| Ok(()),
3800 )
3801 .unwrap_err()
3802 .root_cause()
3803 .downcast_ref::<KsError>()
3804 );
3805
3806 Ok(())
3807 }
3808
3809 #[test]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003810 fn test_insert_and_load_full_keyentry_domain_selinux() -> Result<()> {
3811 let mut db = new_test_db()?;
Qi Wub9433b52020-12-01 14:52:46 +08003812 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08003813 .context("test_insert_and_load_full_keyentry_domain_selinux")?
3814 .0;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003815 let (_key_guard, key_entry) = db
3816 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003817 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003818 domain: Domain::SELINUX,
3819 nspace: 1,
3820 alias: Some(TEST_ALIAS.to_string()),
3821 blob: None,
3822 },
3823 KeyType::Client,
3824 KeyEntryLoadBits::BOTH,
3825 1,
3826 |_k, _av| Ok(()),
3827 )
3828 .unwrap();
Qi Wub9433b52020-12-01 14:52:46 +08003829 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003830
3831 db.unbind_key(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003832 &KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003833 domain: Domain::SELINUX,
3834 nspace: 1,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003835 alias: Some(TEST_ALIAS.to_string()),
3836 blob: None,
3837 },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003838 KeyType::Client,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003839 1,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003840 |_, _| Ok(()),
3841 )
3842 .unwrap();
3843
3844 assert_eq!(
3845 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
3846 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003847 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003848 domain: Domain::SELINUX,
3849 nspace: 1,
3850 alias: Some(TEST_ALIAS.to_string()),
3851 blob: None,
3852 },
3853 KeyType::Client,
3854 KeyEntryLoadBits::NONE,
3855 1,
3856 |_k, _av| Ok(()),
3857 )
3858 .unwrap_err()
3859 .root_cause()
3860 .downcast_ref::<KsError>()
3861 );
3862
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003863 Ok(())
3864 }
3865
3866 #[test]
3867 fn test_insert_and_load_full_keyentry_domain_key_id() -> Result<()> {
3868 let mut db = new_test_db()?;
Qi Wub9433b52020-12-01 14:52:46 +08003869 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08003870 .context("test_insert_and_load_full_keyentry_domain_key_id")?
3871 .0;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003872 let (_, key_entry) = db
3873 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003874 &KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003875 KeyType::Client,
3876 KeyEntryLoadBits::BOTH,
3877 1,
3878 |_k, _av| Ok(()),
3879 )
3880 .unwrap();
3881
Qi Wub9433b52020-12-01 14:52:46 +08003882 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003883
3884 db.unbind_key(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003885 &KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003886 KeyType::Client,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003887 1,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003888 |_, _| Ok(()),
3889 )
3890 .unwrap();
3891
3892 assert_eq!(
3893 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
3894 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003895 &KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003896 KeyType::Client,
3897 KeyEntryLoadBits::NONE,
3898 1,
3899 |_k, _av| Ok(()),
3900 )
3901 .unwrap_err()
3902 .root_cause()
3903 .downcast_ref::<KsError>()
3904 );
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003905
3906 Ok(())
3907 }
3908
3909 #[test]
Qi Wub9433b52020-12-01 14:52:46 +08003910 fn test_check_and_update_key_usage_count_with_limited_use_key() -> Result<()> {
3911 let mut db = new_test_db()?;
3912 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, Some(123))
3913 .context("test_check_and_update_key_usage_count_with_limited_use_key")?
3914 .0;
3915 // Update the usage count of the limited use key.
3916 db.check_and_update_key_usage_count(key_id)?;
3917
3918 let (_key_guard, key_entry) = db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003919 &KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
Qi Wub9433b52020-12-01 14:52:46 +08003920 KeyType::Client,
3921 KeyEntryLoadBits::BOTH,
3922 1,
3923 |_k, _av| Ok(()),
3924 )?;
3925
3926 // The usage count is decremented now.
3927 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, Some(122)));
3928
3929 Ok(())
3930 }
3931
3932 #[test]
3933 fn test_check_and_update_key_usage_count_with_exhausted_limited_use_key() -> Result<()> {
3934 let mut db = new_test_db()?;
3935 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, Some(1))
3936 .context("test_check_and_update_key_usage_count_with_exhausted_limited_use_key")?
3937 .0;
3938 // Update the usage count of the limited use key.
3939 db.check_and_update_key_usage_count(key_id).expect(concat!(
3940 "In test_check_and_update_key_usage_count_with_exhausted_limited_use_key: ",
3941 "This should succeed."
3942 ));
3943
3944 // Try to update the exhausted limited use key.
3945 let e = db.check_and_update_key_usage_count(key_id).expect_err(concat!(
3946 "In test_check_and_update_key_usage_count_with_exhausted_limited_use_key: ",
3947 "This should fail."
3948 ));
3949 assert_eq!(
3950 &KsError::Km(ErrorCode::INVALID_KEY_BLOB),
3951 e.root_cause().downcast_ref::<KsError>().unwrap()
3952 );
3953
3954 Ok(())
3955 }
3956
3957 #[test]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003958 fn test_insert_and_load_full_keyentry_from_grant() -> Result<()> {
3959 let mut db = new_test_db()?;
Qi Wub9433b52020-12-01 14:52:46 +08003960 let key_id = make_test_key_entry(&mut db, Domain::APP, 1, TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08003961 .context("test_insert_and_load_full_keyentry_from_grant")?
3962 .0;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003963
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003964 let granted_key = db
3965 .grant(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003966 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003967 domain: Domain::APP,
3968 nspace: 0,
3969 alias: Some(TEST_ALIAS.to_string()),
3970 blob: None,
3971 },
3972 1,
3973 2,
3974 key_perm_set![KeyPerm::use_()],
3975 |_k, _av| Ok(()),
3976 )
3977 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003978
3979 debug_dump_grant_table(&mut db)?;
3980
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003981 let (_key_guard, key_entry) = db
Janis Danisevskis66784c42021-01-27 08:40:25 -08003982 .load_key_entry(&granted_key, KeyType::Client, KeyEntryLoadBits::BOTH, 2, |k, av| {
3983 assert_eq!(Domain::GRANT, k.domain);
3984 assert!(av.unwrap().includes(KeyPerm::use_()));
3985 Ok(())
3986 })
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003987 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003988
Qi Wub9433b52020-12-01 14:52:46 +08003989 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003990
Janis Danisevskis66784c42021-01-27 08:40:25 -08003991 db.unbind_key(&granted_key, KeyType::Client, 2, |_, _| Ok(())).unwrap();
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003992
3993 assert_eq!(
3994 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
3995 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003996 &granted_key,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003997 KeyType::Client,
3998 KeyEntryLoadBits::NONE,
3999 2,
4000 |_k, _av| Ok(()),
4001 )
4002 .unwrap_err()
4003 .root_cause()
4004 .downcast_ref::<KsError>()
4005 );
4006
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004007 Ok(())
4008 }
4009
Janis Danisevskis45760022021-01-19 16:34:10 -08004010 // This test attempts to load a key by key id while the caller is not the owner
4011 // but a grant exists for the given key and the caller.
4012 #[test]
4013 fn test_insert_and_load_full_keyentry_from_grant_by_key_id() -> Result<()> {
4014 let mut db = new_test_db()?;
4015 const OWNER_UID: u32 = 1u32;
4016 const GRANTEE_UID: u32 = 2u32;
4017 const SOMEONE_ELSE_UID: u32 = 3u32;
4018 let key_id = make_test_key_entry(&mut db, Domain::APP, OWNER_UID as i64, TEST_ALIAS, None)
4019 .context("test_insert_and_load_full_keyentry_from_grant_by_key_id")?
4020 .0;
4021
4022 db.grant(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004023 &KeyDescriptor {
Janis Danisevskis45760022021-01-19 16:34:10 -08004024 domain: Domain::APP,
4025 nspace: 0,
4026 alias: Some(TEST_ALIAS.to_string()),
4027 blob: None,
4028 },
4029 OWNER_UID,
4030 GRANTEE_UID,
4031 key_perm_set![KeyPerm::use_()],
4032 |_k, _av| Ok(()),
4033 )
4034 .unwrap();
4035
4036 debug_dump_grant_table(&mut db)?;
4037
4038 let id_descriptor =
4039 KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, ..Default::default() };
4040
4041 let (_, key_entry) = db
4042 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004043 &id_descriptor,
Janis Danisevskis45760022021-01-19 16:34:10 -08004044 KeyType::Client,
4045 KeyEntryLoadBits::BOTH,
4046 GRANTEE_UID,
4047 |k, av| {
4048 assert_eq!(Domain::APP, k.domain);
4049 assert_eq!(OWNER_UID as i64, k.nspace);
4050 assert!(av.unwrap().includes(KeyPerm::use_()));
4051 Ok(())
4052 },
4053 )
4054 .unwrap();
4055
4056 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
4057
4058 let (_, key_entry) = db
4059 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004060 &id_descriptor,
Janis Danisevskis45760022021-01-19 16:34:10 -08004061 KeyType::Client,
4062 KeyEntryLoadBits::BOTH,
4063 SOMEONE_ELSE_UID,
4064 |k, av| {
4065 assert_eq!(Domain::APP, k.domain);
4066 assert_eq!(OWNER_UID as i64, k.nspace);
4067 assert!(av.is_none());
4068 Ok(())
4069 },
4070 )
4071 .unwrap();
4072
4073 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
4074
Janis Danisevskis66784c42021-01-27 08:40:25 -08004075 db.unbind_key(&id_descriptor, KeyType::Client, OWNER_UID, |_, _| Ok(())).unwrap();
Janis Danisevskis45760022021-01-19 16:34:10 -08004076
4077 assert_eq!(
4078 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
4079 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004080 &id_descriptor,
Janis Danisevskis45760022021-01-19 16:34:10 -08004081 KeyType::Client,
4082 KeyEntryLoadBits::NONE,
4083 GRANTEE_UID,
4084 |_k, _av| Ok(()),
4085 )
4086 .unwrap_err()
4087 .root_cause()
4088 .downcast_ref::<KsError>()
4089 );
4090
4091 Ok(())
4092 }
4093
Janis Danisevskisaec14592020-11-12 09:41:49 -08004094 static KEY_LOCK_TEST_ALIAS: &str = "my super duper locked key";
4095
Janis Danisevskisaec14592020-11-12 09:41:49 -08004096 #[test]
4097 fn test_insert_and_load_full_keyentry_domain_app_concurrently() -> Result<()> {
4098 let handle = {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08004099 let temp_dir = Arc::new(TempDir::new("id_lock_test")?);
4100 let temp_dir_clone = temp_dir.clone();
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004101 let mut db = KeystoreDB::new(temp_dir.path(), None)?;
Qi Wub9433b52020-12-01 14:52:46 +08004102 let key_id = make_test_key_entry(&mut db, Domain::APP, 33, KEY_LOCK_TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08004103 .context("test_insert_and_load_full_keyentry_domain_app")?
4104 .0;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004105 let (_key_guard, key_entry) = db
4106 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004107 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004108 domain: Domain::APP,
4109 nspace: 0,
4110 alias: Some(KEY_LOCK_TEST_ALIAS.to_string()),
4111 blob: None,
4112 },
4113 KeyType::Client,
4114 KeyEntryLoadBits::BOTH,
4115 33,
4116 |_k, _av| Ok(()),
4117 )
4118 .unwrap();
Qi Wub9433b52020-12-01 14:52:46 +08004119 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskisaec14592020-11-12 09:41:49 -08004120 let state = Arc::new(AtomicU8::new(1));
4121 let state2 = state.clone();
4122
4123 // Spawning a second thread that attempts to acquire the key id lock
4124 // for the same key as the primary thread. The primary thread then
4125 // waits, thereby forcing the secondary thread into the second stage
4126 // of acquiring the lock (see KEY ID LOCK 2/2 above).
4127 // The test succeeds if the secondary thread observes the transition
4128 // of `state` from 1 to 2, despite having a whole second to overtake
4129 // the primary thread.
4130 let handle = thread::spawn(move || {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08004131 let temp_dir = temp_dir_clone;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004132 let mut db = KeystoreDB::new(temp_dir.path(), None).unwrap();
Janis Danisevskisaec14592020-11-12 09:41:49 -08004133 assert!(db
4134 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004135 &KeyDescriptor {
Janis Danisevskisaec14592020-11-12 09:41:49 -08004136 domain: Domain::APP,
4137 nspace: 0,
4138 alias: Some(KEY_LOCK_TEST_ALIAS.to_string()),
4139 blob: None,
4140 },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004141 KeyType::Client,
Janis Danisevskisaec14592020-11-12 09:41:49 -08004142 KeyEntryLoadBits::BOTH,
4143 33,
4144 |_k, _av| Ok(()),
4145 )
4146 .is_ok());
4147 // We should only see a 2 here because we can only return
4148 // from load_key_entry when the `_key_guard` expires,
4149 // which happens at the end of the scope.
4150 assert_eq!(2, state2.load(Ordering::Relaxed));
4151 });
4152
4153 thread::sleep(std::time::Duration::from_millis(1000));
4154
4155 assert_eq!(Ok(1), state.compare_exchange(1, 2, Ordering::Relaxed, Ordering::Relaxed));
4156
4157 // Return the handle from this scope so we can join with the
4158 // secondary thread after the key id lock has expired.
4159 handle
4160 // This is where the `_key_guard` goes out of scope,
4161 // which is the reason for concurrent load_key_entry on the same key
4162 // to unblock.
4163 };
4164 // Join with the secondary thread and unwrap, to propagate failing asserts to the
4165 // main test thread. We will not see failing asserts in secondary threads otherwise.
4166 handle.join().unwrap();
4167 Ok(())
4168 }
4169
Janis Danisevskise92a5e62020-12-02 12:57:41 -08004170 #[test]
Janis Danisevskis66784c42021-01-27 08:40:25 -08004171 fn teset_database_busy_error_code() {
4172 let temp_dir =
4173 TempDir::new("test_database_busy_error_code_").expect("Failed to create temp dir.");
4174
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004175 let mut db1 = KeystoreDB::new(temp_dir.path(), None).expect("Failed to open database1.");
4176 let mut db2 = KeystoreDB::new(temp_dir.path(), None).expect("Failed to open database2.");
Janis Danisevskis66784c42021-01-27 08:40:25 -08004177
4178 let _tx1 = db1
4179 .conn
4180 .transaction_with_behavior(TransactionBehavior::Immediate)
4181 .expect("Failed to create first transaction.");
4182
4183 let error = db2
4184 .conn
4185 .transaction_with_behavior(TransactionBehavior::Immediate)
4186 .context("Transaction begin failed.")
4187 .expect_err("This should fail.");
4188 let root_cause = error.root_cause();
4189 if let Some(rusqlite::ffi::Error { code: rusqlite::ErrorCode::DatabaseBusy, .. }) =
4190 root_cause.downcast_ref::<rusqlite::ffi::Error>()
4191 {
4192 return;
4193 }
4194 panic!(
4195 "Unexpected error {:?} \n{:?} \n{:?}",
4196 error,
4197 root_cause,
4198 root_cause.downcast_ref::<rusqlite::ffi::Error>()
4199 )
4200 }
4201
4202 #[cfg(disabled)]
4203 #[test]
4204 fn test_large_number_of_concurrent_db_manipulations() -> Result<()> {
4205 let temp_dir = Arc::new(
4206 TempDir::new("test_large_number_of_concurrent_db_manipulations_")
4207 .expect("Failed to create temp dir."),
4208 );
4209
4210 let test_begin = Instant::now();
4211
4212 let mut db = KeystoreDB::new(temp_dir.path()).expect("Failed to open database.");
4213 const KEY_COUNT: u32 = 500u32;
4214 const OPEN_DB_COUNT: u32 = 50u32;
4215
4216 let mut actual_key_count = KEY_COUNT;
4217 // First insert KEY_COUNT keys.
4218 for count in 0..KEY_COUNT {
4219 if Instant::now().duration_since(test_begin) >= Duration::from_secs(15) {
4220 actual_key_count = count;
4221 break;
4222 }
4223 let alias = format!("test_alias_{}", count);
4224 make_test_key_entry(&mut db, Domain::APP, 1, &alias, None)
4225 .expect("Failed to make key entry.");
4226 }
4227
4228 // Insert more keys from a different thread and into a different namespace.
4229 let temp_dir1 = temp_dir.clone();
4230 let handle1 = thread::spawn(move || {
4231 let mut db = KeystoreDB::new(temp_dir1.path()).expect("Failed to open database.");
4232
4233 for count in 0..actual_key_count {
4234 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
4235 return;
4236 }
4237 let alias = format!("test_alias_{}", count);
4238 make_test_key_entry(&mut db, Domain::APP, 2, &alias, None)
4239 .expect("Failed to make key entry.");
4240 }
4241
4242 // then unbind them again.
4243 for count in 0..actual_key_count {
4244 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
4245 return;
4246 }
4247 let key = KeyDescriptor {
4248 domain: Domain::APP,
4249 nspace: -1,
4250 alias: Some(format!("test_alias_{}", count)),
4251 blob: None,
4252 };
4253 db.unbind_key(&key, KeyType::Client, 2, |_, _| Ok(())).expect("Unbind Failed.");
4254 }
4255 });
4256
4257 // And start unbinding the first set of keys.
4258 let temp_dir2 = temp_dir.clone();
4259 let handle2 = thread::spawn(move || {
4260 let mut db = KeystoreDB::new(temp_dir2.path()).expect("Failed to open database.");
4261
4262 for count in 0..actual_key_count {
4263 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
4264 return;
4265 }
4266 let key = KeyDescriptor {
4267 domain: Domain::APP,
4268 nspace: -1,
4269 alias: Some(format!("test_alias_{}", count)),
4270 blob: None,
4271 };
4272 db.unbind_key(&key, KeyType::Client, 1, |_, _| Ok(())).expect("Unbind Failed.");
4273 }
4274 });
4275
4276 let stop_deleting = Arc::new(AtomicU8::new(0));
4277 let stop_deleting2 = stop_deleting.clone();
4278
4279 // And delete anything that is unreferenced keys.
4280 let temp_dir3 = temp_dir.clone();
4281 let handle3 = thread::spawn(move || {
4282 let mut db = KeystoreDB::new(temp_dir3.path()).expect("Failed to open database.");
4283
4284 while stop_deleting2.load(Ordering::Relaxed) != 1 {
4285 while let Some((key_guard, _key)) =
4286 db.get_unreferenced_key().expect("Failed to get unreferenced Key.")
4287 {
4288 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
4289 return;
4290 }
4291 db.purge_key_entry(key_guard).expect("Failed to purge key.");
4292 }
4293 std::thread::sleep(std::time::Duration::from_millis(100));
4294 }
4295 });
4296
4297 // While a lot of inserting and deleting is going on we have to open database connections
4298 // successfully and use them.
4299 // This clone is not redundant, because temp_dir needs to be kept alive until db goes
4300 // out of scope.
4301 #[allow(clippy::redundant_clone)]
4302 let temp_dir4 = temp_dir.clone();
4303 let handle4 = thread::spawn(move || {
4304 for count in 0..OPEN_DB_COUNT {
4305 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
4306 return;
4307 }
4308 let mut db = KeystoreDB::new(temp_dir4.path()).expect("Failed to open database.");
4309
4310 let alias = format!("test_alias_{}", count);
4311 make_test_key_entry(&mut db, Domain::APP, 3, &alias, None)
4312 .expect("Failed to make key entry.");
4313 let key = KeyDescriptor {
4314 domain: Domain::APP,
4315 nspace: -1,
4316 alias: Some(alias),
4317 blob: None,
4318 };
4319 db.unbind_key(&key, KeyType::Client, 3, |_, _| Ok(())).expect("Unbind Failed.");
4320 }
4321 });
4322
4323 handle1.join().expect("Thread 1 panicked.");
4324 handle2.join().expect("Thread 2 panicked.");
4325 handle4.join().expect("Thread 4 panicked.");
4326
4327 stop_deleting.store(1, Ordering::Relaxed);
4328 handle3.join().expect("Thread 3 panicked.");
4329
4330 Ok(())
4331 }
4332
4333 #[test]
Janis Danisevskise92a5e62020-12-02 12:57:41 -08004334 fn list() -> Result<()> {
4335 let temp_dir = TempDir::new("list_test")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004336 let mut db = KeystoreDB::new(temp_dir.path(), None)?;
Janis Danisevskise92a5e62020-12-02 12:57:41 -08004337 static LIST_O_ENTRIES: &[(Domain, i64, &str)] = &[
4338 (Domain::APP, 1, "test1"),
4339 (Domain::APP, 1, "test2"),
4340 (Domain::APP, 1, "test3"),
4341 (Domain::APP, 1, "test4"),
4342 (Domain::APP, 1, "test5"),
4343 (Domain::APP, 1, "test6"),
4344 (Domain::APP, 1, "test7"),
4345 (Domain::APP, 2, "test1"),
4346 (Domain::APP, 2, "test2"),
4347 (Domain::APP, 2, "test3"),
4348 (Domain::APP, 2, "test4"),
4349 (Domain::APP, 2, "test5"),
4350 (Domain::APP, 2, "test6"),
4351 (Domain::APP, 2, "test8"),
4352 (Domain::SELINUX, 100, "test1"),
4353 (Domain::SELINUX, 100, "test2"),
4354 (Domain::SELINUX, 100, "test3"),
4355 (Domain::SELINUX, 100, "test4"),
4356 (Domain::SELINUX, 100, "test5"),
4357 (Domain::SELINUX, 100, "test6"),
4358 (Domain::SELINUX, 100, "test9"),
4359 ];
4360
4361 let list_o_keys: Vec<(i64, i64)> = LIST_O_ENTRIES
4362 .iter()
4363 .map(|(domain, ns, alias)| {
Qi Wub9433b52020-12-01 14:52:46 +08004364 let entry = make_test_key_entry(&mut db, *domain, *ns, *alias, None)
4365 .unwrap_or_else(|e| {
Janis Danisevskise92a5e62020-12-02 12:57:41 -08004366 panic!("Failed to insert {:?} {} {}. Error {:?}", domain, ns, alias, e)
4367 });
4368 (entry.id(), *ns)
4369 })
4370 .collect();
4371
4372 for (domain, namespace) in
4373 &[(Domain::APP, 1i64), (Domain::APP, 2i64), (Domain::SELINUX, 100i64)]
4374 {
4375 let mut list_o_descriptors: Vec<KeyDescriptor> = LIST_O_ENTRIES
4376 .iter()
4377 .filter_map(|(domain, ns, alias)| match ns {
4378 ns if *ns == *namespace => Some(KeyDescriptor {
4379 domain: *domain,
4380 nspace: *ns,
4381 alias: Some(alias.to_string()),
4382 blob: None,
4383 }),
4384 _ => None,
4385 })
4386 .collect();
4387 list_o_descriptors.sort();
4388 let mut list_result = db.list(*domain, *namespace)?;
4389 list_result.sort();
4390 assert_eq!(list_o_descriptors, list_result);
4391
4392 let mut list_o_ids: Vec<i64> = list_o_descriptors
4393 .into_iter()
4394 .map(|d| {
4395 let (_, entry) = db
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004396 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004397 &d,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004398 KeyType::Client,
4399 KeyEntryLoadBits::NONE,
4400 *namespace as u32,
4401 |_, _| Ok(()),
4402 )
Janis Danisevskise92a5e62020-12-02 12:57:41 -08004403 .unwrap();
4404 entry.id()
4405 })
4406 .collect();
4407 list_o_ids.sort_unstable();
4408 let mut loaded_entries: Vec<i64> = list_o_keys
4409 .iter()
4410 .filter_map(|(id, ns)| match ns {
4411 ns if *ns == *namespace => Some(*id),
4412 _ => None,
4413 })
4414 .collect();
4415 loaded_entries.sort_unstable();
4416 assert_eq!(list_o_ids, loaded_entries);
4417 }
4418 assert_eq!(Vec::<KeyDescriptor>::new(), db.list(Domain::SELINUX, 101)?);
4419
4420 Ok(())
4421 }
4422
Joel Galenson0891bc12020-07-20 10:37:03 -07004423 // Helpers
4424
4425 // Checks that the given result is an error containing the given string.
4426 fn check_result_is_error_containing_string<T>(result: Result<T>, target: &str) {
4427 let error_str = format!(
4428 "{:#?}",
4429 result.err().unwrap_or_else(|| panic!("Expected the error: {}", target))
4430 );
4431 assert!(
4432 error_str.contains(target),
4433 "The string \"{}\" should contain \"{}\"",
4434 error_str,
4435 target
4436 );
4437 }
4438
Joel Galenson2aab4432020-07-22 15:27:57 -07004439 #[derive(Debug, PartialEq)]
Joel Galenson0891bc12020-07-20 10:37:03 -07004440 #[allow(dead_code)]
4441 struct KeyEntryRow {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004442 id: i64,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004443 key_type: KeyType,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07004444 domain: Option<Domain>,
Joel Galenson0891bc12020-07-20 10:37:03 -07004445 namespace: Option<i64>,
4446 alias: Option<String>,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004447 state: KeyLifeCycle,
Max Bires8e93d2b2021-01-14 13:17:59 -08004448 km_uuid: Option<Uuid>,
Joel Galenson0891bc12020-07-20 10:37:03 -07004449 }
4450
4451 fn get_keyentry(db: &KeystoreDB) -> Result<Vec<KeyEntryRow>> {
4452 db.conn
Joel Galenson2aab4432020-07-22 15:27:57 -07004453 .prepare("SELECT * FROM persistent.keyentry;")?
Joel Galenson0891bc12020-07-20 10:37:03 -07004454 .query_map(NO_PARAMS, |row| {
Joel Galenson0891bc12020-07-20 10:37:03 -07004455 Ok(KeyEntryRow {
4456 id: row.get(0)?,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004457 key_type: row.get(1)?,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07004458 domain: match row.get(2)? {
4459 Some(i) => Some(Domain(i)),
4460 None => None,
4461 },
Joel Galenson0891bc12020-07-20 10:37:03 -07004462 namespace: row.get(3)?,
4463 alias: row.get(4)?,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004464 state: row.get(5)?,
Max Bires8e93d2b2021-01-14 13:17:59 -08004465 km_uuid: row.get(6)?,
Joel Galenson0891bc12020-07-20 10:37:03 -07004466 })
4467 })?
4468 .map(|r| r.context("Could not read keyentry row."))
4469 .collect::<Result<Vec<_>>>()
4470 }
4471
Max Biresb2e1d032021-02-08 21:35:05 -08004472 struct RemoteProvValues {
4473 cert_chain: Vec<u8>,
4474 priv_key: Vec<u8>,
4475 batch_cert: Vec<u8>,
4476 }
4477
Max Bires2b2e6562020-09-22 11:22:36 -07004478 fn load_attestation_key_pool(
4479 db: &mut KeystoreDB,
4480 expiration_date: i64,
4481 namespace: i64,
4482 base_byte: u8,
Max Biresb2e1d032021-02-08 21:35:05 -08004483 ) -> Result<RemoteProvValues> {
Max Bires2b2e6562020-09-22 11:22:36 -07004484 let public_key: Vec<u8> = vec![base_byte, 0x02 * base_byte];
4485 let cert_chain: Vec<u8> = vec![0x03 * base_byte, 0x04 * base_byte];
4486 let priv_key: Vec<u8> = vec![0x05 * base_byte, 0x06 * base_byte];
4487 let raw_public_key: Vec<u8> = vec![0x0b * base_byte, 0x0c * base_byte];
Max Biresb2e1d032021-02-08 21:35:05 -08004488 let batch_cert: Vec<u8> = vec![base_byte * 0x0d, base_byte * 0x0e];
Max Bires2b2e6562020-09-22 11:22:36 -07004489 db.create_attestation_key_entry(&public_key, &raw_public_key, &priv_key, &KEYSTORE_UUID)?;
4490 db.store_signed_attestation_certificate_chain(
4491 &raw_public_key,
Max Biresb2e1d032021-02-08 21:35:05 -08004492 &batch_cert,
Max Bires2b2e6562020-09-22 11:22:36 -07004493 &cert_chain,
4494 expiration_date,
4495 &KEYSTORE_UUID,
4496 )?;
4497 db.assign_attestation_key(Domain::APP, namespace, &KEYSTORE_UUID)?;
Max Biresb2e1d032021-02-08 21:35:05 -08004498 Ok(RemoteProvValues { cert_chain, priv_key, batch_cert })
Max Bires2b2e6562020-09-22 11:22:36 -07004499 }
4500
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07004501 // Note: The parameters and SecurityLevel associations are nonsensical. This
4502 // collection is only used to check if the parameters are preserved as expected by the
4503 // database.
Qi Wub9433b52020-12-01 14:52:46 +08004504 fn make_test_params(max_usage_count: Option<i32>) -> Vec<KeyParameter> {
4505 let mut params = vec![
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07004506 KeyParameter::new(KeyParameterValue::Invalid, SecurityLevel::TRUSTED_ENVIRONMENT),
4507 KeyParameter::new(
4508 KeyParameterValue::KeyPurpose(KeyPurpose::SIGN),
4509 SecurityLevel::TRUSTED_ENVIRONMENT,
4510 ),
4511 KeyParameter::new(
4512 KeyParameterValue::KeyPurpose(KeyPurpose::DECRYPT),
4513 SecurityLevel::TRUSTED_ENVIRONMENT,
4514 ),
4515 KeyParameter::new(
4516 KeyParameterValue::Algorithm(Algorithm::RSA),
4517 SecurityLevel::TRUSTED_ENVIRONMENT,
4518 ),
4519 KeyParameter::new(KeyParameterValue::KeySize(1024), SecurityLevel::TRUSTED_ENVIRONMENT),
4520 KeyParameter::new(
4521 KeyParameterValue::BlockMode(BlockMode::ECB),
4522 SecurityLevel::TRUSTED_ENVIRONMENT,
4523 ),
4524 KeyParameter::new(
4525 KeyParameterValue::BlockMode(BlockMode::GCM),
4526 SecurityLevel::TRUSTED_ENVIRONMENT,
4527 ),
4528 KeyParameter::new(KeyParameterValue::Digest(Digest::NONE), SecurityLevel::STRONGBOX),
4529 KeyParameter::new(
4530 KeyParameterValue::Digest(Digest::MD5),
4531 SecurityLevel::TRUSTED_ENVIRONMENT,
4532 ),
4533 KeyParameter::new(
4534 KeyParameterValue::Digest(Digest::SHA_2_224),
4535 SecurityLevel::TRUSTED_ENVIRONMENT,
4536 ),
4537 KeyParameter::new(
4538 KeyParameterValue::Digest(Digest::SHA_2_256),
4539 SecurityLevel::STRONGBOX,
4540 ),
4541 KeyParameter::new(
4542 KeyParameterValue::PaddingMode(PaddingMode::NONE),
4543 SecurityLevel::TRUSTED_ENVIRONMENT,
4544 ),
4545 KeyParameter::new(
4546 KeyParameterValue::PaddingMode(PaddingMode::RSA_OAEP),
4547 SecurityLevel::TRUSTED_ENVIRONMENT,
4548 ),
4549 KeyParameter::new(
4550 KeyParameterValue::PaddingMode(PaddingMode::RSA_PSS),
4551 SecurityLevel::STRONGBOX,
4552 ),
4553 KeyParameter::new(
4554 KeyParameterValue::PaddingMode(PaddingMode::RSA_PKCS1_1_5_SIGN),
4555 SecurityLevel::TRUSTED_ENVIRONMENT,
4556 ),
4557 KeyParameter::new(KeyParameterValue::CallerNonce, SecurityLevel::TRUSTED_ENVIRONMENT),
4558 KeyParameter::new(KeyParameterValue::MinMacLength(256), SecurityLevel::STRONGBOX),
4559 KeyParameter::new(
4560 KeyParameterValue::EcCurve(EcCurve::P_224),
4561 SecurityLevel::TRUSTED_ENVIRONMENT,
4562 ),
4563 KeyParameter::new(KeyParameterValue::EcCurve(EcCurve::P_256), SecurityLevel::STRONGBOX),
4564 KeyParameter::new(
4565 KeyParameterValue::EcCurve(EcCurve::P_384),
4566 SecurityLevel::TRUSTED_ENVIRONMENT,
4567 ),
4568 KeyParameter::new(
4569 KeyParameterValue::EcCurve(EcCurve::P_521),
4570 SecurityLevel::TRUSTED_ENVIRONMENT,
4571 ),
4572 KeyParameter::new(
4573 KeyParameterValue::RSAPublicExponent(3),
4574 SecurityLevel::TRUSTED_ENVIRONMENT,
4575 ),
4576 KeyParameter::new(
4577 KeyParameterValue::IncludeUniqueID,
4578 SecurityLevel::TRUSTED_ENVIRONMENT,
4579 ),
4580 KeyParameter::new(KeyParameterValue::BootLoaderOnly, SecurityLevel::STRONGBOX),
4581 KeyParameter::new(KeyParameterValue::RollbackResistance, SecurityLevel::STRONGBOX),
4582 KeyParameter::new(
4583 KeyParameterValue::ActiveDateTime(1234567890),
4584 SecurityLevel::STRONGBOX,
4585 ),
4586 KeyParameter::new(
4587 KeyParameterValue::OriginationExpireDateTime(1234567890),
4588 SecurityLevel::TRUSTED_ENVIRONMENT,
4589 ),
4590 KeyParameter::new(
4591 KeyParameterValue::UsageExpireDateTime(1234567890),
4592 SecurityLevel::TRUSTED_ENVIRONMENT,
4593 ),
4594 KeyParameter::new(
4595 KeyParameterValue::MinSecondsBetweenOps(1234567890),
4596 SecurityLevel::TRUSTED_ENVIRONMENT,
4597 ),
4598 KeyParameter::new(
4599 KeyParameterValue::MaxUsesPerBoot(1234567890),
4600 SecurityLevel::TRUSTED_ENVIRONMENT,
4601 ),
4602 KeyParameter::new(KeyParameterValue::UserID(1), SecurityLevel::STRONGBOX),
4603 KeyParameter::new(KeyParameterValue::UserSecureID(42), SecurityLevel::STRONGBOX),
4604 KeyParameter::new(
4605 KeyParameterValue::NoAuthRequired,
4606 SecurityLevel::TRUSTED_ENVIRONMENT,
4607 ),
4608 KeyParameter::new(
4609 KeyParameterValue::HardwareAuthenticatorType(HardwareAuthenticatorType::PASSWORD),
4610 SecurityLevel::TRUSTED_ENVIRONMENT,
4611 ),
4612 KeyParameter::new(KeyParameterValue::AuthTimeout(1234567890), SecurityLevel::SOFTWARE),
4613 KeyParameter::new(KeyParameterValue::AllowWhileOnBody, SecurityLevel::SOFTWARE),
4614 KeyParameter::new(
4615 KeyParameterValue::TrustedUserPresenceRequired,
4616 SecurityLevel::TRUSTED_ENVIRONMENT,
4617 ),
4618 KeyParameter::new(
4619 KeyParameterValue::TrustedConfirmationRequired,
4620 SecurityLevel::TRUSTED_ENVIRONMENT,
4621 ),
4622 KeyParameter::new(
4623 KeyParameterValue::UnlockedDeviceRequired,
4624 SecurityLevel::TRUSTED_ENVIRONMENT,
4625 ),
4626 KeyParameter::new(
4627 KeyParameterValue::ApplicationID(vec![1u8, 2u8, 3u8, 4u8]),
4628 SecurityLevel::SOFTWARE,
4629 ),
4630 KeyParameter::new(
4631 KeyParameterValue::ApplicationData(vec![4u8, 3u8, 2u8, 1u8]),
4632 SecurityLevel::SOFTWARE,
4633 ),
4634 KeyParameter::new(
4635 KeyParameterValue::CreationDateTime(12345677890),
4636 SecurityLevel::SOFTWARE,
4637 ),
4638 KeyParameter::new(
4639 KeyParameterValue::KeyOrigin(KeyOrigin::GENERATED),
4640 SecurityLevel::TRUSTED_ENVIRONMENT,
4641 ),
4642 KeyParameter::new(
4643 KeyParameterValue::RootOfTrust(vec![3u8, 2u8, 1u8, 4u8]),
4644 SecurityLevel::TRUSTED_ENVIRONMENT,
4645 ),
4646 KeyParameter::new(KeyParameterValue::OSVersion(1), SecurityLevel::TRUSTED_ENVIRONMENT),
4647 KeyParameter::new(KeyParameterValue::OSPatchLevel(2), SecurityLevel::SOFTWARE),
4648 KeyParameter::new(
4649 KeyParameterValue::UniqueID(vec![4u8, 3u8, 1u8, 2u8]),
4650 SecurityLevel::SOFTWARE,
4651 ),
4652 KeyParameter::new(
4653 KeyParameterValue::AttestationChallenge(vec![4u8, 3u8, 1u8, 2u8]),
4654 SecurityLevel::TRUSTED_ENVIRONMENT,
4655 ),
4656 KeyParameter::new(
4657 KeyParameterValue::AttestationApplicationID(vec![4u8, 3u8, 1u8, 2u8]),
4658 SecurityLevel::TRUSTED_ENVIRONMENT,
4659 ),
4660 KeyParameter::new(
4661 KeyParameterValue::AttestationIdBrand(vec![4u8, 3u8, 1u8, 2u8]),
4662 SecurityLevel::TRUSTED_ENVIRONMENT,
4663 ),
4664 KeyParameter::new(
4665 KeyParameterValue::AttestationIdDevice(vec![4u8, 3u8, 1u8, 2u8]),
4666 SecurityLevel::TRUSTED_ENVIRONMENT,
4667 ),
4668 KeyParameter::new(
4669 KeyParameterValue::AttestationIdProduct(vec![4u8, 3u8, 1u8, 2u8]),
4670 SecurityLevel::TRUSTED_ENVIRONMENT,
4671 ),
4672 KeyParameter::new(
4673 KeyParameterValue::AttestationIdSerial(vec![4u8, 3u8, 1u8, 2u8]),
4674 SecurityLevel::TRUSTED_ENVIRONMENT,
4675 ),
4676 KeyParameter::new(
4677 KeyParameterValue::AttestationIdIMEI(vec![4u8, 3u8, 1u8, 2u8]),
4678 SecurityLevel::TRUSTED_ENVIRONMENT,
4679 ),
4680 KeyParameter::new(
4681 KeyParameterValue::AttestationIdMEID(vec![4u8, 3u8, 1u8, 2u8]),
4682 SecurityLevel::TRUSTED_ENVIRONMENT,
4683 ),
4684 KeyParameter::new(
4685 KeyParameterValue::AttestationIdManufacturer(vec![4u8, 3u8, 1u8, 2u8]),
4686 SecurityLevel::TRUSTED_ENVIRONMENT,
4687 ),
4688 KeyParameter::new(
4689 KeyParameterValue::AttestationIdModel(vec![4u8, 3u8, 1u8, 2u8]),
4690 SecurityLevel::TRUSTED_ENVIRONMENT,
4691 ),
4692 KeyParameter::new(
4693 KeyParameterValue::VendorPatchLevel(3),
4694 SecurityLevel::TRUSTED_ENVIRONMENT,
4695 ),
4696 KeyParameter::new(
4697 KeyParameterValue::BootPatchLevel(4),
4698 SecurityLevel::TRUSTED_ENVIRONMENT,
4699 ),
4700 KeyParameter::new(
4701 KeyParameterValue::AssociatedData(vec![4u8, 3u8, 1u8, 2u8]),
4702 SecurityLevel::TRUSTED_ENVIRONMENT,
4703 ),
4704 KeyParameter::new(
4705 KeyParameterValue::Nonce(vec![4u8, 3u8, 1u8, 2u8]),
4706 SecurityLevel::TRUSTED_ENVIRONMENT,
4707 ),
4708 KeyParameter::new(
4709 KeyParameterValue::MacLength(256),
4710 SecurityLevel::TRUSTED_ENVIRONMENT,
4711 ),
4712 KeyParameter::new(
4713 KeyParameterValue::ResetSinceIdRotation,
4714 SecurityLevel::TRUSTED_ENVIRONMENT,
4715 ),
4716 KeyParameter::new(
4717 KeyParameterValue::ConfirmationToken(vec![5u8, 5u8, 5u8, 5u8]),
4718 SecurityLevel::TRUSTED_ENVIRONMENT,
4719 ),
Qi Wub9433b52020-12-01 14:52:46 +08004720 ];
4721 if let Some(value) = max_usage_count {
4722 params.push(KeyParameter::new(
4723 KeyParameterValue::UsageCountLimit(value),
4724 SecurityLevel::SOFTWARE,
4725 ));
4726 }
4727 params
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07004728 }
4729
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004730 fn make_test_key_entry(
4731 db: &mut KeystoreDB,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07004732 domain: Domain,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004733 namespace: i64,
4734 alias: &str,
Qi Wub9433b52020-12-01 14:52:46 +08004735 max_usage_count: Option<i32>,
Janis Danisevskisaec14592020-11-12 09:41:49 -08004736 ) -> Result<KeyIdGuard> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08004737 let key_id = db.create_key_entry(&domain, &namespace, &KEYSTORE_UUID)?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004738 let mut blob_metadata = BlobMetaData::new();
4739 blob_metadata.add(BlobMetaEntry::EncryptedBy(EncryptedBy::Password));
4740 blob_metadata.add(BlobMetaEntry::Salt(vec![1, 2, 3]));
4741 blob_metadata.add(BlobMetaEntry::Iv(vec![2, 3, 1]));
4742 blob_metadata.add(BlobMetaEntry::AeadTag(vec![3, 1, 2]));
4743 blob_metadata.add(BlobMetaEntry::KmUuid(KEYSTORE_UUID));
4744
4745 db.set_blob(
4746 &key_id,
4747 SubComponentType::KEY_BLOB,
4748 Some(TEST_KEY_BLOB),
4749 Some(&blob_metadata),
4750 )?;
4751 db.set_blob(&key_id, SubComponentType::CERT, Some(TEST_CERT_BLOB), None)?;
4752 db.set_blob(&key_id, SubComponentType::CERT_CHAIN, Some(TEST_CERT_CHAIN_BLOB), None)?;
Qi Wub9433b52020-12-01 14:52:46 +08004753
4754 let params = make_test_params(max_usage_count);
4755 db.insert_keyparameter(&key_id, &params)?;
4756
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004757 let mut metadata = KeyMetaData::new();
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004758 metadata.add(KeyMetaEntry::CreationDate(DateTime::from_millis_epoch(123456789)));
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004759 db.insert_key_metadata(&key_id, &metadata)?;
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08004760 rebind_alias(db, &key_id, alias, domain, namespace)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004761 Ok(key_id)
4762 }
4763
Qi Wub9433b52020-12-01 14:52:46 +08004764 fn make_test_key_entry_test_vector(key_id: i64, max_usage_count: Option<i32>) -> KeyEntry {
4765 let params = make_test_params(max_usage_count);
4766
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004767 let mut blob_metadata = BlobMetaData::new();
4768 blob_metadata.add(BlobMetaEntry::EncryptedBy(EncryptedBy::Password));
4769 blob_metadata.add(BlobMetaEntry::Salt(vec![1, 2, 3]));
4770 blob_metadata.add(BlobMetaEntry::Iv(vec![2, 3, 1]));
4771 blob_metadata.add(BlobMetaEntry::AeadTag(vec![3, 1, 2]));
4772 blob_metadata.add(BlobMetaEntry::KmUuid(KEYSTORE_UUID));
4773
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004774 let mut metadata = KeyMetaData::new();
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004775 metadata.add(KeyMetaEntry::CreationDate(DateTime::from_millis_epoch(123456789)));
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004776
4777 KeyEntry {
4778 id: key_id,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004779 key_blob_info: Some((TEST_KEY_BLOB.to_vec(), blob_metadata)),
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004780 cert: Some(TEST_CERT_BLOB.to_vec()),
4781 cert_chain: Some(TEST_CERT_CHAIN_BLOB.to_vec()),
Max Bires8e93d2b2021-01-14 13:17:59 -08004782 km_uuid: KEYSTORE_UUID,
Qi Wub9433b52020-12-01 14:52:46 +08004783 parameters: params,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004784 metadata,
Janis Danisevskis377d1002021-01-27 19:07:48 -08004785 pure_cert: false,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004786 }
4787 }
4788
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004789 fn debug_dump_keyentry_table(db: &mut KeystoreDB) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004790 let mut stmt = db.conn.prepare(
Max Bires8e93d2b2021-01-14 13:17:59 -08004791 "SELECT id, key_type, domain, namespace, alias, state, km_uuid FROM persistent.keyentry;",
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004792 )?;
Max Bires8e93d2b2021-01-14 13:17:59 -08004793 let rows = stmt.query_map::<(i64, KeyType, i32, i64, String, KeyLifeCycle, Uuid), _, _>(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004794 NO_PARAMS,
4795 |row| {
Max Bires8e93d2b2021-01-14 13:17:59 -08004796 Ok((
4797 row.get(0)?,
4798 row.get(1)?,
4799 row.get(2)?,
4800 row.get(3)?,
4801 row.get(4)?,
4802 row.get(5)?,
4803 row.get(6)?,
4804 ))
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004805 },
4806 )?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004807
4808 println!("Key entry table rows:");
4809 for r in rows {
Max Bires8e93d2b2021-01-14 13:17:59 -08004810 let (id, key_type, domain, namespace, alias, state, km_uuid) = r.unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004811 println!(
Max Bires8e93d2b2021-01-14 13:17:59 -08004812 " id: {} KeyType: {:?} Domain: {} Namespace: {} Alias: {} State: {:?} KmUuid: {:?}",
4813 id, key_type, domain, namespace, alias, state, km_uuid
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004814 );
4815 }
4816 Ok(())
4817 }
4818
4819 fn debug_dump_grant_table(db: &mut KeystoreDB) -> Result<()> {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08004820 let mut stmt = db
4821 .conn
4822 .prepare("SELECT id, grantee, keyentryid, access_vector FROM persistent.grant;")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004823 let rows = stmt.query_map::<(i64, i64, i64, i64), _, _>(NO_PARAMS, |row| {
4824 Ok((row.get(0)?, row.get(1)?, row.get(2)?, row.get(3)?))
4825 })?;
4826
4827 println!("Grant table rows:");
4828 for r in rows {
4829 let (id, gt, ki, av) = r.unwrap();
4830 println!(" id: {} grantee: {} key_id: {} access_vector: {}", id, gt, ki, av);
4831 }
4832 Ok(())
4833 }
4834
Joel Galenson0891bc12020-07-20 10:37:03 -07004835 // Use a custom random number generator that repeats each number once.
4836 // This allows us to test repeated elements.
4837
4838 thread_local! {
4839 static RANDOM_COUNTER: RefCell<i64> = RefCell::new(0);
4840 }
4841
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004842 fn reset_random() {
4843 RANDOM_COUNTER.with(|counter| {
4844 *counter.borrow_mut() = 0;
4845 })
4846 }
4847
Joel Galenson0891bc12020-07-20 10:37:03 -07004848 pub fn random() -> i64 {
4849 RANDOM_COUNTER.with(|counter| {
4850 let result = *counter.borrow() / 2;
4851 *counter.borrow_mut() += 1;
4852 result
4853 })
4854 }
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00004855
4856 #[test]
4857 fn test_last_off_body() -> Result<()> {
4858 let mut db = new_test_db()?;
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08004859 db.insert_last_off_body(MonotonicRawTime::now())?;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00004860 let tx = db.conn.transaction_with_behavior(TransactionBehavior::Immediate)?;
4861 let last_off_body_1 = KeystoreDB::get_last_off_body(&tx)?;
4862 tx.commit()?;
4863 let one_second = Duration::from_secs(1);
4864 thread::sleep(one_second);
4865 db.update_last_off_body(MonotonicRawTime::now())?;
4866 let tx2 = db.conn.transaction_with_behavior(TransactionBehavior::Immediate)?;
4867 let last_off_body_2 = KeystoreDB::get_last_off_body(&tx2)?;
4868 tx2.commit()?;
4869 assert!(last_off_body_1.seconds() < last_off_body_2.seconds());
4870 Ok(())
4871 }
Hasini Gunasingheda895552021-01-27 19:34:37 +00004872
4873 #[test]
4874 fn test_unbind_keys_for_user() -> Result<()> {
4875 let mut db = new_test_db()?;
4876 db.unbind_keys_for_user(1, false)?;
4877
4878 make_test_key_entry(&mut db, Domain::APP, 210000, TEST_ALIAS, None)?;
4879 make_test_key_entry(&mut db, Domain::APP, 110000, TEST_ALIAS, None)?;
4880 db.unbind_keys_for_user(2, false)?;
4881
4882 assert_eq!(1, db.list(Domain::APP, 110000)?.len());
4883 assert_eq!(0, db.list(Domain::APP, 210000)?.len());
4884
4885 db.unbind_keys_for_user(1, true)?;
4886 assert_eq!(0, db.list(Domain::APP, 110000)?.len());
4887
4888 Ok(())
4889 }
4890
4891 #[test]
4892 fn test_store_super_key() -> Result<()> {
4893 let mut db = new_test_db()?;
Paul Crowleyf61fee72021-03-17 14:38:44 -07004894 let pw: keystore2_crypto::Password = (&b"xyzabc"[..]).into();
Hasini Gunasingheda895552021-01-27 19:34:37 +00004895 let super_key = keystore2_crypto::generate_aes256_key()?;
Paul Crowley7a658392021-03-18 17:08:20 -07004896 let secret_bytes = b"keystore2 is great.";
Hasini Gunasingheda895552021-01-27 19:34:37 +00004897 let (encrypted_secret, iv, tag) =
Paul Crowley7a658392021-03-18 17:08:20 -07004898 keystore2_crypto::aes_gcm_encrypt(secret_bytes, &super_key)?;
Hasini Gunasingheda895552021-01-27 19:34:37 +00004899
4900 let (encrypted_super_key, metadata) =
4901 SuperKeyManager::encrypt_with_password(&super_key, &pw)?;
Paul Crowley7a658392021-03-18 17:08:20 -07004902 db.store_super_key(1, &USER_SUPER_KEY, &encrypted_super_key, &metadata)?;
Hasini Gunasingheda895552021-01-27 19:34:37 +00004903
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00004904 //check if super key exists
Paul Crowley7a658392021-03-18 17:08:20 -07004905 assert!(db.key_exists(Domain::APP, 1, &USER_SUPER_KEY.alias, KeyType::Super)?);
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00004906
Paul Crowley7a658392021-03-18 17:08:20 -07004907 let (_, key_entry) = db.load_super_key(&USER_SUPER_KEY, 1)?.unwrap();
Hasini Gunasingheda895552021-01-27 19:34:37 +00004908 let loaded_super_key = SuperKeyManager::extract_super_key_from_key_entry(key_entry, &pw)?;
4909
Paul Crowley7a658392021-03-18 17:08:20 -07004910 let decrypted_secret_bytes =
4911 loaded_super_key.aes_gcm_decrypt(&encrypted_secret, &iv, &tag)?;
4912 assert_eq!(secret_bytes, &*decrypted_secret_bytes);
Hasini Gunasingheda895552021-01-27 19:34:37 +00004913 Ok(())
4914 }
Joel Galenson26f4d012020-07-17 14:57:21 -07004915}