blob: 2663c6e8f2c9298e3b3e37f259221b342544b542 [file] [log] [blame]
Joel Galenson26f4d012020-07-17 14:57:21 -07001// Copyright 2020, The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
Janis Danisevskis63f7bc82020-09-03 10:12:56 -070015//! This is the Keystore 2.0 database module.
16//! The database module provides a connection to the backing SQLite store.
17//! We have two databases one for persistent key blob storage and one for
18//! items that have a per boot life cycle.
19//!
20//! ## Persistent database
21//! The persistent database has tables for key blobs. They are organized
22//! as follows:
23//! The `keyentry` table is the primary table for key entries. It is
24//! accompanied by two tables for blobs and parameters.
25//! Each key entry occupies exactly one row in the `keyentry` table and
26//! zero or more rows in the tables `blobentry` and `keyparameter`.
27//!
28//! ## Per boot database
29//! The per boot database stores items with a per boot lifecycle.
30//! Currently, there is only the `grant` table in this database.
31//! Grants are references to a key that can be used to access a key by
32//! clients that don't own that key. Grants can only be created by the
33//! owner of a key. And only certain components can create grants.
34//! This is governed by SEPolicy.
35//!
36//! ## Access control
37//! Some database functions that load keys or create grants perform
38//! access control. This is because in some cases access control
39//! can only be performed after some information about the designated
40//! key was loaded from the database. To decouple the permission checks
41//! from the database module these functions take permission check
42//! callbacks.
Joel Galenson26f4d012020-07-17 14:57:21 -070043
Qi Wub9433b52020-12-01 14:52:46 +080044use crate::error::{Error as KsError, ErrorCode, ResponseCode};
Janis Danisevskisb42fc182020-12-15 08:41:27 -080045use crate::impl_metadata; // This is in db_utils.rs
Janis Danisevskis4522c2b2020-11-27 18:04:58 -080046use crate::key_parameter::{KeyParameter, Tag};
Janis Danisevskisc5b210b2020-09-11 13:27:37 -070047use crate::permission::KeyPermSet;
Hasini Gunasingheda895552021-01-27 19:34:37 +000048use crate::utils::{get_current_time_in_seconds, AID_USER_OFFSET};
Janis Danisevskis7e8b4622021-02-13 10:01:59 -080049use crate::{
50 db_utils::{self, SqlField},
51 gc::Gc,
52};
Janis Danisevskisb42fc182020-12-15 08:41:27 -080053use anyhow::{anyhow, Context, Result};
Max Bires8e93d2b2021-01-14 13:17:59 -080054use std::{convert::TryFrom, convert::TryInto, ops::Deref, time::SystemTimeError};
Janis Danisevskis60400fe2020-08-26 15:24:42 -070055
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +000056use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
Janis Danisevskis5ed8c532021-01-11 14:19:42 -080057 HardwareAuthToken::HardwareAuthToken,
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +000058 HardwareAuthenticatorType::HardwareAuthenticatorType, SecurityLevel::SecurityLevel,
Janis Danisevskisc3a496b2021-01-05 10:37:22 -080059};
60use android_hardware_security_secureclock::aidl::android::hardware::security::secureclock::{
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +000061 Timestamp::Timestamp,
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +000062};
Janis Danisevskisc5b210b2020-09-11 13:27:37 -070063use android_system_keystore2::aidl::android::system::keystore2::{
Janis Danisevskis04b02832020-10-26 09:21:40 -070064 Domain::Domain, KeyDescriptor::KeyDescriptor,
Janis Danisevskis60400fe2020-08-26 15:24:42 -070065};
Max Bires2b2e6562020-09-22 11:22:36 -070066use android_security_remoteprovisioning::aidl::android::security::remoteprovisioning::{
67 AttestationPoolStatus::AttestationPoolStatus,
68};
69
70use keystore2_crypto::ZVec;
Janis Danisevskisaec14592020-11-12 09:41:49 -080071use lazy_static::lazy_static;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +000072use log::error;
Joel Galenson0891bc12020-07-20 10:37:03 -070073#[cfg(not(test))]
74use rand::prelude::random;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -070075use rusqlite::{
Janis Danisevskisb42fc182020-12-15 08:41:27 -080076 params,
77 types::FromSql,
78 types::FromSqlResult,
79 types::ToSqlOutput,
80 types::{FromSqlError, Value, ValueRef},
Janis Danisevskis5ed8c532021-01-11 14:19:42 -080081 Connection, OptionalExtension, ToSql, Transaction, TransactionBehavior, NO_PARAMS,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -070082};
Max Bires2b2e6562020-09-22 11:22:36 -070083
Janis Danisevskisaec14592020-11-12 09:41:49 -080084use std::{
Janis Danisevskisb42fc182020-12-15 08:41:27 -080085 collections::{HashMap, HashSet},
Janis Danisevskisbf15d732020-12-08 10:35:26 -080086 path::Path,
87 sync::{Condvar, Mutex},
Janis Danisevskisb42fc182020-12-15 08:41:27 -080088 time::{Duration, SystemTime},
Janis Danisevskisaec14592020-11-12 09:41:49 -080089};
Max Bires2b2e6562020-09-22 11:22:36 -070090
Joel Galenson0891bc12020-07-20 10:37:03 -070091#[cfg(test)]
92use tests::random;
Joel Galenson26f4d012020-07-17 14:57:21 -070093
Janis Danisevskisb42fc182020-12-15 08:41:27 -080094impl_metadata!(
95 /// A set of metadata for key entries.
96 #[derive(Debug, Default, Eq, PartialEq)]
97 pub struct KeyMetaData;
98 /// A metadata entry for key entries.
99 #[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
100 pub enum KeyMetaEntry {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800101 /// Date of the creation of the key entry.
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800102 CreationDate(DateTime) with accessor creation_date,
103 /// Expiration date for attestation keys.
104 AttestationExpirationDate(DateTime) with accessor attestation_expiration_date,
Max Bires2b2e6562020-09-22 11:22:36 -0700105 /// CBOR Blob that represents a COSE_Key and associated metadata needed for remote
106 /// provisioning
107 AttestationMacedPublicKey(Vec<u8>) with accessor attestation_maced_public_key,
108 /// Vector representing the raw public key so results from the server can be matched
109 /// to the right entry
110 AttestationRawPubKey(Vec<u8>) with accessor attestation_raw_pub_key,
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800111 // --- ADD NEW META DATA FIELDS HERE ---
112 // For backwards compatibility add new entries only to
113 // end of this list and above this comment.
114 };
115);
116
117impl KeyMetaData {
118 fn load_from_db(key_id: i64, tx: &Transaction) -> Result<Self> {
119 let mut stmt = tx
120 .prepare(
121 "SELECT tag, data from persistent.keymetadata
122 WHERE keyentryid = ?;",
123 )
124 .context("In KeyMetaData::load_from_db: prepare statement failed.")?;
125
126 let mut metadata: HashMap<i64, KeyMetaEntry> = Default::default();
127
128 let mut rows =
129 stmt.query(params![key_id]).context("In KeyMetaData::load_from_db: query failed.")?;
130 db_utils::with_rows_extract_all(&mut rows, |row| {
131 let db_tag: i64 = row.get(0).context("Failed to read tag.")?;
132 metadata.insert(
133 db_tag,
134 KeyMetaEntry::new_from_sql(db_tag, &SqlField::new(1, &row))
135 .context("Failed to read KeyMetaEntry.")?,
136 );
137 Ok(())
138 })
139 .context("In KeyMetaData::load_from_db.")?;
140
141 Ok(Self { data: metadata })
142 }
143
144 fn store_in_db(&self, key_id: i64, tx: &Transaction) -> Result<()> {
145 let mut stmt = tx
146 .prepare(
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000147 "INSERT or REPLACE INTO persistent.keymetadata (keyentryid, tag, data)
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800148 VALUES (?, ?, ?);",
149 )
150 .context("In KeyMetaData::store_in_db: Failed to prepare statement.")?;
151
152 let iter = self.data.iter();
153 for (tag, entry) in iter {
154 stmt.insert(params![key_id, tag, entry,]).with_context(|| {
155 format!("In KeyMetaData::store_in_db: Failed to insert {:?}", entry)
156 })?;
157 }
158 Ok(())
159 }
160}
161
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800162impl_metadata!(
163 /// A set of metadata for key blobs.
164 #[derive(Debug, Default, Eq, PartialEq)]
165 pub struct BlobMetaData;
166 /// A metadata entry for key blobs.
167 #[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
168 pub enum BlobMetaEntry {
169 /// If present, indicates that the blob is encrypted with another key or a key derived
170 /// from a password.
171 EncryptedBy(EncryptedBy) with accessor encrypted_by,
172 /// If the blob is password encrypted this field is set to the
173 /// salt used for the key derivation.
174 Salt(Vec<u8>) with accessor salt,
175 /// If the blob is encrypted, this field is set to the initialization vector.
176 Iv(Vec<u8>) with accessor iv,
177 /// If the blob is encrypted, this field holds the AEAD TAG.
178 AeadTag(Vec<u8>) with accessor aead_tag,
179 /// The uuid of the owning KeyMint instance.
180 KmUuid(Uuid) with accessor km_uuid,
181 // --- ADD NEW META DATA FIELDS HERE ---
182 // For backwards compatibility add new entries only to
183 // end of this list and above this comment.
184 };
185);
186
187impl BlobMetaData {
188 fn load_from_db(blob_id: i64, tx: &Transaction) -> Result<Self> {
189 let mut stmt = tx
190 .prepare(
191 "SELECT tag, data from persistent.blobmetadata
192 WHERE blobentryid = ?;",
193 )
194 .context("In BlobMetaData::load_from_db: prepare statement failed.")?;
195
196 let mut metadata: HashMap<i64, BlobMetaEntry> = Default::default();
197
198 let mut rows =
199 stmt.query(params![blob_id]).context("In BlobMetaData::load_from_db: query failed.")?;
200 db_utils::with_rows_extract_all(&mut rows, |row| {
201 let db_tag: i64 = row.get(0).context("Failed to read tag.")?;
202 metadata.insert(
203 db_tag,
204 BlobMetaEntry::new_from_sql(db_tag, &SqlField::new(1, &row))
205 .context("Failed to read BlobMetaEntry.")?,
206 );
207 Ok(())
208 })
209 .context("In BlobMetaData::load_from_db.")?;
210
211 Ok(Self { data: metadata })
212 }
213
214 fn store_in_db(&self, blob_id: i64, tx: &Transaction) -> Result<()> {
215 let mut stmt = tx
216 .prepare(
217 "INSERT or REPLACE INTO persistent.blobmetadata (blobentryid, tag, data)
218 VALUES (?, ?, ?);",
219 )
220 .context("In BlobMetaData::store_in_db: Failed to prepare statement.")?;
221
222 let iter = self.data.iter();
223 for (tag, entry) in iter {
224 stmt.insert(params![blob_id, tag, entry,]).with_context(|| {
225 format!("In BlobMetaData::store_in_db: Failed to insert {:?}", entry)
226 })?;
227 }
228 Ok(())
229 }
230}
231
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800232/// Indicates the type of the keyentry.
233#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
234pub enum KeyType {
235 /// This is a client key type. These keys are created or imported through the Keystore 2.0
236 /// AIDL interface android.system.keystore2.
237 Client,
238 /// This is a super key type. These keys are created by keystore itself and used to encrypt
239 /// other key blobs to provide LSKF binding.
240 Super,
241 /// This is an attestation key. These keys are created by the remote provisioning mechanism.
242 Attestation,
243}
244
245impl ToSql for KeyType {
246 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
247 Ok(ToSqlOutput::Owned(Value::Integer(match self {
248 KeyType::Client => 0,
249 KeyType::Super => 1,
250 KeyType::Attestation => 2,
251 })))
252 }
253}
254
255impl FromSql for KeyType {
256 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
257 match i64::column_result(value)? {
258 0 => Ok(KeyType::Client),
259 1 => Ok(KeyType::Super),
260 2 => Ok(KeyType::Attestation),
261 v => Err(FromSqlError::OutOfRange(v)),
262 }
263 }
264}
265
Max Bires8e93d2b2021-01-14 13:17:59 -0800266/// Uuid representation that can be stored in the database.
267/// Right now it can only be initialized from SecurityLevel.
268/// Once KeyMint provides a UUID type a corresponding From impl shall be added.
269#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
270pub struct Uuid([u8; 16]);
271
272impl Deref for Uuid {
273 type Target = [u8; 16];
274
275 fn deref(&self) -> &Self::Target {
276 &self.0
277 }
278}
279
280impl From<SecurityLevel> for Uuid {
281 fn from(sec_level: SecurityLevel) -> Self {
282 Self((sec_level.0 as u128).to_be_bytes())
283 }
284}
285
286impl ToSql for Uuid {
287 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
288 self.0.to_sql()
289 }
290}
291
292impl FromSql for Uuid {
293 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
294 let blob = Vec::<u8>::column_result(value)?;
295 if blob.len() != 16 {
296 return Err(FromSqlError::OutOfRange(blob.len() as i64));
297 }
298 let mut arr = [0u8; 16];
299 arr.copy_from_slice(&blob);
300 Ok(Self(arr))
301 }
302}
303
304/// Key entries that are not associated with any KeyMint instance, such as pure certificate
305/// entries are associated with this UUID.
306pub static KEYSTORE_UUID: Uuid = Uuid([
307 0x41, 0xe3, 0xb9, 0xce, 0x27, 0x58, 0x4e, 0x91, 0xbc, 0xfd, 0xa5, 0x5d, 0x91, 0x85, 0xab, 0x11,
308]);
309
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800310/// Indicates how the sensitive part of this key blob is encrypted.
311#[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
312pub enum EncryptedBy {
313 /// The keyblob is encrypted by a user password.
314 /// In the database this variant is represented as NULL.
315 Password,
316 /// The keyblob is encrypted by another key with wrapped key id.
317 /// In the database this variant is represented as non NULL value
318 /// that is convertible to i64, typically NUMERIC.
319 KeyId(i64),
320}
321
322impl ToSql for EncryptedBy {
323 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
324 match self {
325 Self::Password => Ok(ToSqlOutput::Owned(Value::Null)),
326 Self::KeyId(id) => id.to_sql(),
327 }
328 }
329}
330
331impl FromSql for EncryptedBy {
332 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
333 match value {
334 ValueRef::Null => Ok(Self::Password),
335 _ => Ok(Self::KeyId(i64::column_result(value)?)),
336 }
337 }
338}
339
340/// A database representation of wall clock time. DateTime stores unix epoch time as
341/// i64 in milliseconds.
342#[derive(Debug, Copy, Clone, Default, Eq, PartialEq, Ord, PartialOrd)]
343pub struct DateTime(i64);
344
345/// Error type returned when creating DateTime or converting it from and to
346/// SystemTime.
347#[derive(thiserror::Error, Debug)]
348pub enum DateTimeError {
349 /// This is returned when SystemTime and Duration computations fail.
350 #[error(transparent)]
351 SystemTimeError(#[from] SystemTimeError),
352
353 /// This is returned when type conversions fail.
354 #[error(transparent)]
355 TypeConversion(#[from] std::num::TryFromIntError),
356
357 /// This is returned when checked time arithmetic failed.
358 #[error("Time arithmetic failed.")]
359 TimeArithmetic,
360}
361
362impl DateTime {
363 /// Constructs a new DateTime object denoting the current time. This may fail during
364 /// conversion to unix epoch time and during conversion to the internal i64 representation.
365 pub fn now() -> Result<Self, DateTimeError> {
366 Ok(Self(SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_millis().try_into()?))
367 }
368
369 /// Constructs a new DateTime object from milliseconds.
370 pub fn from_millis_epoch(millis: i64) -> Self {
371 Self(millis)
372 }
373
374 /// Returns unix epoch time in milliseconds.
375 pub fn to_millis_epoch(&self) -> i64 {
376 self.0
377 }
378
379 /// Returns unix epoch time in seconds.
380 pub fn to_secs_epoch(&self) -> i64 {
381 self.0 / 1000
382 }
383}
384
385impl ToSql for DateTime {
386 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
387 Ok(ToSqlOutput::Owned(Value::Integer(self.0)))
388 }
389}
390
391impl FromSql for DateTime {
392 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
393 Ok(Self(i64::column_result(value)?))
394 }
395}
396
397impl TryInto<SystemTime> for DateTime {
398 type Error = DateTimeError;
399
400 fn try_into(self) -> Result<SystemTime, Self::Error> {
401 // We want to construct a SystemTime representation equivalent to self, denoting
402 // a point in time THEN, but we cannot set the time directly. We can only construct
403 // a SystemTime denoting NOW, and we can get the duration between EPOCH and NOW,
404 // and between EPOCH and THEN. With this common reference we can construct the
405 // duration between NOW and THEN which we can add to our SystemTime representation
406 // of NOW to get a SystemTime representation of THEN.
407 // Durations can only be positive, thus the if statement below.
408 let now = SystemTime::now();
409 let now_epoch = now.duration_since(SystemTime::UNIX_EPOCH)?;
410 let then_epoch = Duration::from_millis(self.0.try_into()?);
411 Ok(if now_epoch > then_epoch {
412 // then = now - (now_epoch - then_epoch)
413 now_epoch
414 .checked_sub(then_epoch)
415 .and_then(|d| now.checked_sub(d))
416 .ok_or(DateTimeError::TimeArithmetic)?
417 } else {
418 // then = now + (then_epoch - now_epoch)
419 then_epoch
420 .checked_sub(now_epoch)
421 .and_then(|d| now.checked_add(d))
422 .ok_or(DateTimeError::TimeArithmetic)?
423 })
424 }
425}
426
427impl TryFrom<SystemTime> for DateTime {
428 type Error = DateTimeError;
429
430 fn try_from(t: SystemTime) -> Result<Self, Self::Error> {
431 Ok(Self(t.duration_since(SystemTime::UNIX_EPOCH)?.as_millis().try_into()?))
432 }
433}
434
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800435#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone)]
436enum KeyLifeCycle {
437 /// Existing keys have a key ID but are not fully populated yet.
438 /// This is a transient state. If Keystore finds any such keys when it starts up, it must move
439 /// them to Unreferenced for garbage collection.
440 Existing,
441 /// A live key is fully populated and usable by clients.
442 Live,
443 /// An unreferenced key is scheduled for garbage collection.
444 Unreferenced,
445}
446
447impl ToSql for KeyLifeCycle {
448 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
449 match self {
450 Self::Existing => Ok(ToSqlOutput::Owned(Value::Integer(0))),
451 Self::Live => Ok(ToSqlOutput::Owned(Value::Integer(1))),
452 Self::Unreferenced => Ok(ToSqlOutput::Owned(Value::Integer(2))),
453 }
454 }
455}
456
457impl FromSql for KeyLifeCycle {
458 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
459 match i64::column_result(value)? {
460 0 => Ok(KeyLifeCycle::Existing),
461 1 => Ok(KeyLifeCycle::Live),
462 2 => Ok(KeyLifeCycle::Unreferenced),
463 v => Err(FromSqlError::OutOfRange(v)),
464 }
465 }
466}
467
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700468/// Keys have a KeyMint blob component and optional public certificate and
469/// certificate chain components.
470/// KeyEntryLoadBits is a bitmap that indicates to `KeystoreDB::load_key_entry`
471/// which components shall be loaded from the database if present.
Janis Danisevskis66784c42021-01-27 08:40:25 -0800472#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700473pub struct KeyEntryLoadBits(u32);
474
475impl KeyEntryLoadBits {
476 /// Indicate to `KeystoreDB::load_key_entry` that no component shall be loaded.
477 pub const NONE: KeyEntryLoadBits = Self(0);
478 /// Indicate to `KeystoreDB::load_key_entry` that the KeyMint component shall be loaded.
479 pub const KM: KeyEntryLoadBits = Self(1);
480 /// Indicate to `KeystoreDB::load_key_entry` that the Public components shall be loaded.
481 pub const PUBLIC: KeyEntryLoadBits = Self(2);
482 /// Indicate to `KeystoreDB::load_key_entry` that both components shall be loaded.
483 pub const BOTH: KeyEntryLoadBits = Self(3);
484
485 /// Returns true if this object indicates that the public components shall be loaded.
486 pub const fn load_public(&self) -> bool {
487 self.0 & Self::PUBLIC.0 != 0
488 }
489
490 /// Returns true if the object indicates that the KeyMint component shall be loaded.
491 pub const fn load_km(&self) -> bool {
492 self.0 & Self::KM.0 != 0
493 }
494}
495
Janis Danisevskisaec14592020-11-12 09:41:49 -0800496lazy_static! {
497 static ref KEY_ID_LOCK: KeyIdLockDb = KeyIdLockDb::new();
498}
499
500struct KeyIdLockDb {
501 locked_keys: Mutex<HashSet<i64>>,
502 cond_var: Condvar,
503}
504
505/// A locked key. While a guard exists for a given key id, the same key cannot be loaded
506/// from the database a second time. Most functions manipulating the key blob database
507/// require a KeyIdGuard.
508#[derive(Debug)]
509pub struct KeyIdGuard(i64);
510
511impl KeyIdLockDb {
512 fn new() -> Self {
513 Self { locked_keys: Mutex::new(HashSet::new()), cond_var: Condvar::new() }
514 }
515
516 /// This function blocks until an exclusive lock for the given key entry id can
517 /// be acquired. It returns a guard object, that represents the lifecycle of the
518 /// acquired lock.
519 pub fn get(&self, key_id: i64) -> KeyIdGuard {
520 let mut locked_keys = self.locked_keys.lock().unwrap();
521 while locked_keys.contains(&key_id) {
522 locked_keys = self.cond_var.wait(locked_keys).unwrap();
523 }
524 locked_keys.insert(key_id);
525 KeyIdGuard(key_id)
526 }
527
528 /// This function attempts to acquire an exclusive lock on a given key id. If the
529 /// given key id is already taken the function returns None immediately. If a lock
530 /// can be acquired this function returns a guard object, that represents the
531 /// lifecycle of the acquired lock.
532 pub fn try_get(&self, key_id: i64) -> Option<KeyIdGuard> {
533 let mut locked_keys = self.locked_keys.lock().unwrap();
534 if locked_keys.insert(key_id) {
535 Some(KeyIdGuard(key_id))
536 } else {
537 None
538 }
539 }
540}
541
542impl KeyIdGuard {
543 /// Get the numeric key id of the locked key.
544 pub fn id(&self) -> i64 {
545 self.0
546 }
547}
548
549impl Drop for KeyIdGuard {
550 fn drop(&mut self) {
551 let mut locked_keys = KEY_ID_LOCK.locked_keys.lock().unwrap();
552 locked_keys.remove(&self.0);
Janis Danisevskis7fd53582020-11-23 13:40:34 -0800553 drop(locked_keys);
Janis Danisevskisaec14592020-11-12 09:41:49 -0800554 KEY_ID_LOCK.cond_var.notify_all();
555 }
556}
557
Max Bires8e93d2b2021-01-14 13:17:59 -0800558/// This type represents a certificate and certificate chain entry for a key.
Max Bires2b2e6562020-09-22 11:22:36 -0700559#[derive(Debug, Default)]
Max Bires8e93d2b2021-01-14 13:17:59 -0800560pub struct CertificateInfo {
561 cert: Option<Vec<u8>>,
562 cert_chain: Option<Vec<u8>>,
563}
564
565impl CertificateInfo {
566 /// Constructs a new CertificateInfo object from `cert` and `cert_chain`
567 pub fn new(cert: Option<Vec<u8>>, cert_chain: Option<Vec<u8>>) -> Self {
568 Self { cert, cert_chain }
569 }
570
571 /// Take the cert
572 pub fn take_cert(&mut self) -> Option<Vec<u8>> {
573 self.cert.take()
574 }
575
576 /// Take the cert chain
577 pub fn take_cert_chain(&mut self) -> Option<Vec<u8>> {
578 self.cert_chain.take()
579 }
580}
581
Max Bires2b2e6562020-09-22 11:22:36 -0700582/// This type represents a certificate chain with a private key corresponding to the leaf
583/// certificate. TODO(jbires): This will be used in a follow-on CL, for now it's used in the tests.
584#[allow(dead_code)]
585pub struct CertificateChain {
586 private_key: ZVec,
587 cert_chain: ZVec,
588}
589
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700590/// This type represents a Keystore 2.0 key entry.
591/// An entry has a unique `id` by which it can be found in the database.
592/// It has a security level field, key parameters, and three optional fields
593/// for the KeyMint blob, public certificate and a public certificate chain.
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800594#[derive(Debug, Default, Eq, PartialEq)]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700595pub struct KeyEntry {
596 id: i64,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800597 key_blob_info: Option<(Vec<u8>, BlobMetaData)>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700598 cert: Option<Vec<u8>>,
599 cert_chain: Option<Vec<u8>>,
Max Bires8e93d2b2021-01-14 13:17:59 -0800600 km_uuid: Uuid,
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700601 parameters: Vec<KeyParameter>,
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800602 metadata: KeyMetaData,
Janis Danisevskis377d1002021-01-27 19:07:48 -0800603 pure_cert: bool,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700604}
605
606impl KeyEntry {
607 /// Returns the unique id of the Key entry.
608 pub fn id(&self) -> i64 {
609 self.id
610 }
611 /// Exposes the optional KeyMint blob.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800612 pub fn key_blob_info(&self) -> &Option<(Vec<u8>, BlobMetaData)> {
613 &self.key_blob_info
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700614 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800615 /// Extracts the Optional KeyMint blob including its metadata.
616 pub fn take_key_blob_info(&mut self) -> Option<(Vec<u8>, BlobMetaData)> {
617 self.key_blob_info.take()
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700618 }
619 /// Exposes the optional public certificate.
620 pub fn cert(&self) -> &Option<Vec<u8>> {
621 &self.cert
622 }
623 /// Extracts the optional public certificate.
624 pub fn take_cert(&mut self) -> Option<Vec<u8>> {
625 self.cert.take()
626 }
627 /// Exposes the optional public certificate chain.
628 pub fn cert_chain(&self) -> &Option<Vec<u8>> {
629 &self.cert_chain
630 }
631 /// Extracts the optional public certificate_chain.
632 pub fn take_cert_chain(&mut self) -> Option<Vec<u8>> {
633 self.cert_chain.take()
634 }
Max Bires8e93d2b2021-01-14 13:17:59 -0800635 /// Returns the uuid of the owning KeyMint instance.
636 pub fn km_uuid(&self) -> &Uuid {
637 &self.km_uuid
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700638 }
Janis Danisevskis04b02832020-10-26 09:21:40 -0700639 /// Exposes the key parameters of this key entry.
640 pub fn key_parameters(&self) -> &Vec<KeyParameter> {
641 &self.parameters
642 }
643 /// Consumes this key entry and extracts the keyparameters from it.
644 pub fn into_key_parameters(self) -> Vec<KeyParameter> {
645 self.parameters
646 }
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800647 /// Exposes the key metadata of this key entry.
648 pub fn metadata(&self) -> &KeyMetaData {
649 &self.metadata
650 }
Janis Danisevskis377d1002021-01-27 19:07:48 -0800651 /// This returns true if the entry is a pure certificate entry with no
652 /// private key component.
653 pub fn pure_cert(&self) -> bool {
654 self.pure_cert
655 }
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000656 /// Consumes this key entry and extracts the keyparameters and metadata from it.
657 pub fn into_key_parameters_and_metadata(self) -> (Vec<KeyParameter>, KeyMetaData) {
658 (self.parameters, self.metadata)
659 }
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700660}
661
662/// Indicates the sub component of a key entry for persistent storage.
Janis Danisevskis377d1002021-01-27 19:07:48 -0800663#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700664pub struct SubComponentType(u32);
665impl SubComponentType {
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800666 /// Persistent identifier for a key blob.
667 pub const KEY_BLOB: SubComponentType = Self(0);
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700668 /// Persistent identifier for a certificate blob.
669 pub const CERT: SubComponentType = Self(1);
670 /// Persistent identifier for a certificate chain blob.
671 pub const CERT_CHAIN: SubComponentType = Self(2);
672}
673
674impl ToSql for SubComponentType {
675 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
676 self.0.to_sql()
677 }
678}
679
680impl FromSql for SubComponentType {
681 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
682 Ok(Self(u32::column_result(value)?))
683 }
684}
685
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800686/// This trait is private to the database module. It is used to convey whether or not the garbage
687/// collector shall be invoked after a database access. All closures passed to
688/// `KeystoreDB::with_transaction` return a tuple (bool, T) where the bool indicates if the
689/// gc needs to be triggered. This convenience function allows to turn any anyhow::Result<T>
690/// into anyhow::Result<(bool, T)> by simply appending one of `.do_gc(bool)`, `.no_gc()`, or
691/// `.need_gc()`.
692trait DoGc<T> {
693 fn do_gc(self, need_gc: bool) -> Result<(bool, T)>;
694
695 fn no_gc(self) -> Result<(bool, T)>;
696
697 fn need_gc(self) -> Result<(bool, T)>;
698}
699
700impl<T> DoGc<T> for Result<T> {
701 fn do_gc(self, need_gc: bool) -> Result<(bool, T)> {
702 self.map(|r| (need_gc, r))
703 }
704
705 fn no_gc(self) -> Result<(bool, T)> {
706 self.do_gc(false)
707 }
708
709 fn need_gc(self) -> Result<(bool, T)> {
710 self.do_gc(true)
711 }
712}
713
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700714/// KeystoreDB wraps a connection to an SQLite database and tracks its
715/// ownership. It also implements all of Keystore 2.0's database functionality.
Joel Galenson26f4d012020-07-17 14:57:21 -0700716pub struct KeystoreDB {
Joel Galenson26f4d012020-07-17 14:57:21 -0700717 conn: Connection,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800718 gc: Option<Gc>,
Joel Galenson26f4d012020-07-17 14:57:21 -0700719}
720
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000721/// Database representation of the monotonic time retrieved from the system call clock_gettime with
722/// CLOCK_MONOTONIC_RAW. Stores monotonic time as i64 in seconds.
723#[derive(Debug, Copy, Clone, Default, Eq, PartialEq, Ord, PartialOrd)]
724pub struct MonotonicRawTime(i64);
725
726impl MonotonicRawTime {
727 /// Constructs a new MonotonicRawTime
728 pub fn now() -> Self {
729 Self(get_current_time_in_seconds())
730 }
731
732 /// Returns the integer value of MonotonicRawTime as i64
733 pub fn seconds(&self) -> i64 {
734 self.0
735 }
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800736
737 /// Like i64::checked_sub.
738 pub fn checked_sub(&self, other: &Self) -> Option<Self> {
739 self.0.checked_sub(other.0).map(Self)
740 }
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000741}
742
743impl ToSql for MonotonicRawTime {
744 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
745 Ok(ToSqlOutput::Owned(Value::Integer(self.0)))
746 }
747}
748
749impl FromSql for MonotonicRawTime {
750 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
751 Ok(Self(i64::column_result(value)?))
752 }
753}
754
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000755/// This struct encapsulates the information to be stored in the database about the auth tokens
756/// received by keystore.
757pub struct AuthTokenEntry {
758 auth_token: HardwareAuthToken,
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000759 time_received: MonotonicRawTime,
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000760}
761
762impl AuthTokenEntry {
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000763 fn new(auth_token: HardwareAuthToken, time_received: MonotonicRawTime) -> Self {
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000764 AuthTokenEntry { auth_token, time_received }
765 }
766
767 /// Checks if this auth token satisfies the given authentication information.
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800768 pub fn satisfies(&self, user_secure_ids: &[i64], auth_type: HardwareAuthenticatorType) -> bool {
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000769 user_secure_ids.iter().any(|&sid| {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800770 (sid == self.auth_token.userId || sid == self.auth_token.authenticatorId)
771 && (((auth_type.0 as i32) & (self.auth_token.authenticatorType.0 as i32)) != 0)
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000772 })
773 }
774
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000775 /// Returns the auth token wrapped by the AuthTokenEntry
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800776 pub fn auth_token(&self) -> &HardwareAuthToken {
777 &self.auth_token
778 }
779
780 /// Returns the auth token wrapped by the AuthTokenEntry
781 pub fn take_auth_token(self) -> HardwareAuthToken {
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000782 self.auth_token
783 }
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800784
785 /// Returns the time that this auth token was received.
786 pub fn time_received(&self) -> MonotonicRawTime {
787 self.time_received
788 }
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000789}
790
Janis Danisevskisb00ebd02021-02-02 21:52:24 -0800791/// Shared in-memory databases get destroyed as soon as the last connection to them gets closed.
792/// This object does not allow access to the database connection. But it keeps a database
793/// connection alive in order to keep the in memory per boot database alive.
794pub struct PerBootDbKeepAlive(Connection);
795
Joel Galenson26f4d012020-07-17 14:57:21 -0700796impl KeystoreDB {
Janis Danisevskisb00ebd02021-02-02 21:52:24 -0800797 const PERBOOT_DB_FILE_NAME: &'static str = &"file:perboot.sqlite?mode=memory&cache=shared";
798
Hasini Gunasinghe0e161452021-01-27 19:34:37 +0000799 /// The alias of the user super key.
800 pub const USER_SUPER_KEY_ALIAS: &'static str = &"USER_SUPER_KEY";
801
Janis Danisevskisb00ebd02021-02-02 21:52:24 -0800802 /// This creates a PerBootDbKeepAlive object to keep the per boot database alive.
803 pub fn keep_perboot_db_alive() -> Result<PerBootDbKeepAlive> {
804 let conn = Connection::open_in_memory()
805 .context("In keep_perboot_db_alive: Failed to initialize SQLite connection.")?;
806
807 conn.execute("ATTACH DATABASE ? as perboot;", params![Self::PERBOOT_DB_FILE_NAME])
808 .context("In keep_perboot_db_alive: Failed to attach database perboot.")?;
809 Ok(PerBootDbKeepAlive(conn))
810 }
811
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700812 /// This will create a new database connection connecting the two
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800813 /// files persistent.sqlite and perboot.sqlite in the given directory.
814 /// It also attempts to initialize all of the tables.
815 /// KeystoreDB cannot be used by multiple threads.
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700816 /// Each thread should open their own connection using `thread_local!`.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800817 pub fn new(db_root: &Path, gc: Option<Gc>) -> Result<Self> {
Janis Danisevskisb00ebd02021-02-02 21:52:24 -0800818 // Build the path to the sqlite file.
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800819 let mut persistent_path = db_root.to_path_buf();
820 persistent_path.push("persistent.sqlite");
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700821
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800822 // Now convert them to strings prefixed with "file:"
823 let mut persistent_path_str = "file:".to_owned();
824 persistent_path_str.push_str(&persistent_path.to_string_lossy());
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800825
Janis Danisevskisb00ebd02021-02-02 21:52:24 -0800826 let conn = Self::make_connection(&persistent_path_str, &Self::PERBOOT_DB_FILE_NAME)?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800827
Janis Danisevskis66784c42021-01-27 08:40:25 -0800828 // On busy fail Immediately. It is unlikely to succeed given a bug in sqlite.
829 conn.busy_handler(None).context("In KeystoreDB::new: Failed to set busy handler.")?;
830
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800831 let mut db = Self { conn, gc };
Janis Danisevskis66784c42021-01-27 08:40:25 -0800832 db.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800833 Self::init_tables(tx).context("Trying to initialize tables.").no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -0800834 })?;
835 Ok(db)
Joel Galenson2aab4432020-07-22 15:27:57 -0700836 }
837
Janis Danisevskis66784c42021-01-27 08:40:25 -0800838 fn init_tables(tx: &Transaction) -> Result<()> {
839 tx.execute(
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700840 "CREATE TABLE IF NOT EXISTS persistent.keyentry (
Joel Galenson0891bc12020-07-20 10:37:03 -0700841 id INTEGER UNIQUE,
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800842 key_type INTEGER,
Joel Galenson0891bc12020-07-20 10:37:03 -0700843 domain INTEGER,
844 namespace INTEGER,
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800845 alias BLOB,
Max Bires8e93d2b2021-01-14 13:17:59 -0800846 state INTEGER,
847 km_uuid BLOB);",
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700848 NO_PARAMS,
849 )
850 .context("Failed to initialize \"keyentry\" table.")?;
851
Janis Danisevskis66784c42021-01-27 08:40:25 -0800852 tx.execute(
Janis Danisevskisa5438182021-02-02 14:22:59 -0800853 "CREATE INDEX IF NOT EXISTS persistent.keyentry_id_index
854 ON keyentry(id);",
855 NO_PARAMS,
856 )
857 .context("Failed to create index keyentry_id_index.")?;
858
859 tx.execute(
860 "CREATE INDEX IF NOT EXISTS persistent.keyentry_domain_namespace_index
861 ON keyentry(domain, namespace, alias);",
862 NO_PARAMS,
863 )
864 .context("Failed to create index keyentry_domain_namespace_index.")?;
865
866 tx.execute(
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700867 "CREATE TABLE IF NOT EXISTS persistent.blobentry (
868 id INTEGER PRIMARY KEY,
869 subcomponent_type INTEGER,
870 keyentryid INTEGER,
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800871 blob BLOB);",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700872 NO_PARAMS,
873 )
874 .context("Failed to initialize \"blobentry\" table.")?;
875
Janis Danisevskis66784c42021-01-27 08:40:25 -0800876 tx.execute(
Janis Danisevskisa5438182021-02-02 14:22:59 -0800877 "CREATE INDEX IF NOT EXISTS persistent.blobentry_keyentryid_index
878 ON blobentry(keyentryid);",
879 NO_PARAMS,
880 )
881 .context("Failed to create index blobentry_keyentryid_index.")?;
882
883 tx.execute(
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800884 "CREATE TABLE IF NOT EXISTS persistent.blobmetadata (
885 id INTEGER PRIMARY KEY,
886 blobentryid INTEGER,
887 tag INTEGER,
888 data ANY,
889 UNIQUE (blobentryid, tag));",
890 NO_PARAMS,
891 )
892 .context("Failed to initialize \"blobmetadata\" table.")?;
893
894 tx.execute(
895 "CREATE INDEX IF NOT EXISTS persistent.blobmetadata_blobentryid_index
896 ON blobmetadata(blobentryid);",
897 NO_PARAMS,
898 )
899 .context("Failed to create index blobmetadata_blobentryid_index.")?;
900
901 tx.execute(
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700902 "CREATE TABLE IF NOT EXISTS persistent.keyparameter (
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000903 keyentryid INTEGER,
904 tag INTEGER,
905 data ANY,
906 security_level INTEGER);",
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700907 NO_PARAMS,
908 )
909 .context("Failed to initialize \"keyparameter\" table.")?;
910
Janis Danisevskis66784c42021-01-27 08:40:25 -0800911 tx.execute(
Janis Danisevskisa5438182021-02-02 14:22:59 -0800912 "CREATE INDEX IF NOT EXISTS persistent.keyparameter_keyentryid_index
913 ON keyparameter(keyentryid);",
914 NO_PARAMS,
915 )
916 .context("Failed to create index keyparameter_keyentryid_index.")?;
917
918 tx.execute(
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800919 "CREATE TABLE IF NOT EXISTS persistent.keymetadata (
920 keyentryid INTEGER,
921 tag INTEGER,
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000922 data ANY,
923 UNIQUE (keyentryid, tag));",
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800924 NO_PARAMS,
925 )
926 .context("Failed to initialize \"keymetadata\" table.")?;
927
Janis Danisevskis66784c42021-01-27 08:40:25 -0800928 tx.execute(
Janis Danisevskisa5438182021-02-02 14:22:59 -0800929 "CREATE INDEX IF NOT EXISTS persistent.keymetadata_keyentryid_index
930 ON keymetadata(keyentryid);",
931 NO_PARAMS,
932 )
933 .context("Failed to create index keymetadata_keyentryid_index.")?;
934
935 tx.execute(
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800936 "CREATE TABLE IF NOT EXISTS persistent.grant (
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700937 id INTEGER UNIQUE,
938 grantee INTEGER,
939 keyentryid INTEGER,
940 access_vector INTEGER);",
941 NO_PARAMS,
942 )
943 .context("Failed to initialize \"grant\" table.")?;
944
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000945 //TODO: only drop the following two perboot tables if this is the first start up
946 //during the boot (b/175716626).
Janis Danisevskis66784c42021-01-27 08:40:25 -0800947 // tx.execute("DROP TABLE IF EXISTS perboot.authtoken;", NO_PARAMS)
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000948 // .context("Failed to drop perboot.authtoken table")?;
Janis Danisevskis66784c42021-01-27 08:40:25 -0800949 tx.execute(
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000950 "CREATE TABLE IF NOT EXISTS perboot.authtoken (
951 id INTEGER PRIMARY KEY,
952 challenge INTEGER,
953 user_id INTEGER,
954 auth_id INTEGER,
955 authenticator_type INTEGER,
956 timestamp INTEGER,
957 mac BLOB,
958 time_received INTEGER,
959 UNIQUE(user_id, auth_id, authenticator_type));",
960 NO_PARAMS,
961 )
962 .context("Failed to initialize \"authtoken\" table.")?;
963
Janis Danisevskis66784c42021-01-27 08:40:25 -0800964 // tx.execute("DROP TABLE IF EXISTS perboot.metadata;", NO_PARAMS)
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000965 // .context("Failed to drop perboot.metadata table")?;
966 // metadata table stores certain miscellaneous information required for keystore functioning
967 // during a boot cycle, as key-value pairs.
Janis Danisevskis66784c42021-01-27 08:40:25 -0800968 tx.execute(
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000969 "CREATE TABLE IF NOT EXISTS perboot.metadata (
970 key TEXT,
971 value BLOB,
972 UNIQUE(key));",
973 NO_PARAMS,
974 )
975 .context("Failed to initialize \"metadata\" table.")?;
Joel Galenson0891bc12020-07-20 10:37:03 -0700976 Ok(())
977 }
978
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700979 fn make_connection(persistent_file: &str, perboot_file: &str) -> Result<Connection> {
980 let conn =
981 Connection::open_in_memory().context("Failed to initialize SQLite connection.")?;
982
Janis Danisevskis66784c42021-01-27 08:40:25 -0800983 loop {
984 if let Err(e) = conn
985 .execute("ATTACH DATABASE ? as persistent;", params![persistent_file])
986 .context("Failed to attach database persistent.")
987 {
988 if Self::is_locked_error(&e) {
989 std::thread::sleep(std::time::Duration::from_micros(500));
990 continue;
991 } else {
992 return Err(e);
993 }
994 }
995 break;
996 }
997 loop {
998 if let Err(e) = conn
999 .execute("ATTACH DATABASE ? as perboot;", params![perboot_file])
1000 .context("Failed to attach database perboot.")
1001 {
1002 if Self::is_locked_error(&e) {
1003 std::thread::sleep(std::time::Duration::from_micros(500));
1004 continue;
1005 } else {
1006 return Err(e);
1007 }
1008 }
1009 break;
1010 }
Janis Danisevskis4df44f42020-08-26 14:40:03 -07001011
1012 Ok(conn)
1013 }
1014
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001015 /// This function is intended to be used by the garbage collector.
1016 /// It deletes the blob given by `blob_id_to_delete`. It then tries to find a superseded
1017 /// key blob that might need special handling by the garbage collector.
1018 /// If no further superseded blobs can be found it deletes all other superseded blobs that don't
1019 /// need special handling and returns None.
1020 pub fn handle_next_superseded_blob(
1021 &mut self,
1022 blob_id_to_delete: Option<i64>,
1023 ) -> Result<Option<(i64, Vec<u8>, BlobMetaData)>> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001024 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001025 // Delete the given blob if one was given.
1026 if let Some(blob_id_to_delete) = blob_id_to_delete {
1027 tx.execute(
1028 "DELETE FROM persistent.blobmetadata WHERE blobentryid = ?;",
1029 params![blob_id_to_delete],
1030 )
1031 .context("Trying to delete blob metadata.")?;
1032 tx.execute(
1033 "DELETE FROM persistent.blobentry WHERE id = ?;",
1034 params![blob_id_to_delete],
1035 )
1036 .context("Trying to blob.")?;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001037 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001038
1039 // Find another superseded keyblob load its metadata and return it.
1040 if let Some((blob_id, blob)) = tx
1041 .query_row(
1042 "SELECT id, blob FROM persistent.blobentry
1043 WHERE subcomponent_type = ?
1044 AND (
1045 id NOT IN (
1046 SELECT MAX(id) FROM persistent.blobentry
1047 WHERE subcomponent_type = ?
1048 GROUP BY keyentryid, subcomponent_type
1049 )
1050 OR keyentryid NOT IN (SELECT id FROM persistent.keyentry)
1051 );",
1052 params![SubComponentType::KEY_BLOB, SubComponentType::KEY_BLOB],
1053 |row| Ok((row.get(0)?, row.get(1)?)),
1054 )
1055 .optional()
1056 .context("Trying to query superseded blob.")?
1057 {
1058 let blob_metadata = BlobMetaData::load_from_db(blob_id, tx)
1059 .context("Trying to load blob metadata.")?;
1060 return Ok(Some((blob_id, blob, blob_metadata))).no_gc();
1061 }
1062
1063 // We did not find any superseded key blob, so let's remove other superseded blob in
1064 // one transaction.
1065 tx.execute(
1066 "DELETE FROM persistent.blobentry
1067 WHERE NOT subcomponent_type = ?
1068 AND (
1069 id NOT IN (
1070 SELECT MAX(id) FROM persistent.blobentry
1071 WHERE NOT subcomponent_type = ?
1072 GROUP BY keyentryid, subcomponent_type
1073 ) OR keyentryid NOT IN (SELECT id FROM persistent.keyentry)
1074 );",
1075 params![SubComponentType::KEY_BLOB, SubComponentType::KEY_BLOB],
1076 )
1077 .context("Trying to purge superseded blobs.")?;
1078
1079 Ok(None).no_gc()
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001080 })
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001081 .context("In handle_next_superseded_blob.")
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001082 }
1083
1084 /// This maintenance function should be called only once before the database is used for the
1085 /// first time. It restores the invariant that `KeyLifeCycle::Existing` is a transient state.
1086 /// The function transitions all key entries from Existing to Unreferenced unconditionally and
1087 /// returns the number of rows affected. If this returns a value greater than 0, it means that
1088 /// Keystore crashed at some point during key generation. Callers may want to log such
1089 /// occurrences.
1090 /// Unlike with `mark_unreferenced`, we don't need to purge grants, because only keys that made
1091 /// it to `KeyLifeCycle::Live` may have grants.
1092 pub fn cleanup_leftovers(&mut self) -> Result<usize> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001093 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1094 tx.execute(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001095 "UPDATE persistent.keyentry SET state = ? WHERE state = ?;",
1096 params![KeyLifeCycle::Unreferenced, KeyLifeCycle::Existing],
1097 )
Janis Danisevskis66784c42021-01-27 08:40:25 -08001098 .context("Failed to execute query.")
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001099 .need_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08001100 })
1101 .context("In cleanup_leftovers.")
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001102 }
1103
Hasini Gunasinghe0e161452021-01-27 19:34:37 +00001104 /// Checks if a key exists with given key type and key descriptor properties.
1105 pub fn key_exists(
1106 &mut self,
1107 domain: Domain,
1108 nspace: i64,
1109 alias: &str,
1110 key_type: KeyType,
1111 ) -> Result<bool> {
1112 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1113 let key_descriptor =
1114 KeyDescriptor { domain, nspace, alias: Some(alias.to_string()), blob: None };
1115 let result = Self::load_key_entry_id(&tx, &key_descriptor, key_type);
1116 match result {
1117 Ok(_) => Ok(true),
1118 Err(error) => match error.root_cause().downcast_ref::<KsError>() {
1119 Some(KsError::Rc(ResponseCode::KEY_NOT_FOUND)) => Ok(false),
1120 _ => Err(error).context("In key_exists: Failed to find if the key exists."),
1121 },
1122 }
1123 .no_gc()
1124 })
1125 .context("In key_exists.")
1126 }
1127
Hasini Gunasingheda895552021-01-27 19:34:37 +00001128 /// Stores a super key in the database.
1129 pub fn store_super_key(
1130 &mut self,
1131 user_id: i64,
1132 blob_info: &(&[u8], &BlobMetaData),
1133 ) -> Result<KeyEntry> {
1134 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1135 let key_id = Self::insert_with_retry(|id| {
1136 tx.execute(
1137 "INSERT into persistent.keyentry
1138 (id, key_type, domain, namespace, alias, state, km_uuid)
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00001139 VALUES(?, ?, ?, ?, ?, ?, ?);",
Hasini Gunasingheda895552021-01-27 19:34:37 +00001140 params![
1141 id,
1142 KeyType::Super,
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00001143 Domain::APP.0,
Hasini Gunasingheda895552021-01-27 19:34:37 +00001144 user_id,
1145 Self::USER_SUPER_KEY_ALIAS,
1146 KeyLifeCycle::Live,
1147 &KEYSTORE_UUID,
1148 ],
1149 )
1150 })
1151 .context("Failed to insert into keyentry table.")?;
1152
1153 let (blob, blob_metadata) = *blob_info;
1154 Self::set_blob_internal(
1155 &tx,
1156 key_id,
1157 SubComponentType::KEY_BLOB,
1158 Some(blob),
1159 Some(blob_metadata),
1160 )
1161 .context("Failed to store key blob.")?;
1162
1163 Self::load_key_components(tx, KeyEntryLoadBits::KM, key_id)
1164 .context("Trying to load key components.")
1165 .no_gc()
1166 })
1167 .context("In store_super_key.")
1168 }
1169
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001170 /// Atomically loads a key entry and associated metadata or creates it using the
1171 /// callback create_new_key callback. The callback is called during a database
1172 /// transaction. This means that implementers should be mindful about using
1173 /// blocking operations such as IPC or grabbing mutexes.
1174 pub fn get_or_create_key_with<F>(
1175 &mut self,
1176 domain: Domain,
1177 namespace: i64,
1178 alias: &str,
Max Bires8e93d2b2021-01-14 13:17:59 -08001179 km_uuid: Uuid,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001180 create_new_key: F,
1181 ) -> Result<(KeyIdGuard, KeyEntry)>
1182 where
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001183 F: Fn() -> Result<(Vec<u8>, BlobMetaData)>,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001184 {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001185 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1186 let id = {
1187 let mut stmt = tx
1188 .prepare(
1189 "SELECT id FROM persistent.keyentry
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001190 WHERE
1191 key_type = ?
1192 AND domain = ?
1193 AND namespace = ?
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001194 AND alias = ?
1195 AND state = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08001196 )
1197 .context("In get_or_create_key_with: Failed to select from keyentry table.")?;
1198 let mut rows = stmt
1199 .query(params![KeyType::Super, domain.0, namespace, alias, KeyLifeCycle::Live])
1200 .context("In get_or_create_key_with: Failed to query from keyentry table.")?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001201
Janis Danisevskis66784c42021-01-27 08:40:25 -08001202 db_utils::with_rows_extract_one(&mut rows, |row| {
1203 Ok(match row {
1204 Some(r) => r.get(0).context("Failed to unpack id.")?,
1205 None => None,
1206 })
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001207 })
Janis Danisevskis66784c42021-01-27 08:40:25 -08001208 .context("In get_or_create_key_with.")?
1209 };
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001210
Janis Danisevskis66784c42021-01-27 08:40:25 -08001211 let (id, entry) = match id {
1212 Some(id) => (
1213 id,
1214 Self::load_key_components(&tx, KeyEntryLoadBits::KM, id)
1215 .context("In get_or_create_key_with.")?,
1216 ),
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001217
Janis Danisevskis66784c42021-01-27 08:40:25 -08001218 None => {
1219 let id = Self::insert_with_retry(|id| {
1220 tx.execute(
1221 "INSERT into persistent.keyentry
Max Bires8e93d2b2021-01-14 13:17:59 -08001222 (id, key_type, domain, namespace, alias, state, km_uuid)
1223 VALUES(?, ?, ?, ?, ?, ?, ?);",
Janis Danisevskis66784c42021-01-27 08:40:25 -08001224 params![
1225 id,
1226 KeyType::Super,
1227 domain.0,
1228 namespace,
1229 alias,
1230 KeyLifeCycle::Live,
1231 km_uuid,
1232 ],
1233 )
1234 })
1235 .context("In get_or_create_key_with.")?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001236
Janis Danisevskis66784c42021-01-27 08:40:25 -08001237 let (blob, metadata) =
1238 create_new_key().context("In get_or_create_key_with.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001239 Self::set_blob_internal(
1240 &tx,
1241 id,
1242 SubComponentType::KEY_BLOB,
1243 Some(&blob),
1244 Some(&metadata),
1245 )
1246 .context("In get_of_create_key_with.")?;
Janis Danisevskis66784c42021-01-27 08:40:25 -08001247 (
Janis Danisevskis377d1002021-01-27 19:07:48 -08001248 id,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001249 KeyEntry {
1250 id,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001251 key_blob_info: Some((blob, metadata)),
Janis Danisevskis66784c42021-01-27 08:40:25 -08001252 pure_cert: false,
1253 ..Default::default()
1254 },
1255 )
1256 }
1257 };
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001258 Ok((KEY_ID_LOCK.get(id), entry)).no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08001259 })
1260 .context("In get_or_create_key_with.")
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001261 }
1262
Janis Danisevskis66784c42021-01-27 08:40:25 -08001263 /// SQLite3 seems to hold a shared mutex while running the busy handler when
1264 /// waiting for the database file to become available. This makes it
1265 /// impossible to successfully recover from a locked database when the
1266 /// transaction holding the device busy is in the same process on a
1267 /// different connection. As a result the busy handler has to time out and
1268 /// fail in order to make progress.
1269 ///
1270 /// Instead, we set the busy handler to None (return immediately). And catch
1271 /// Busy and Locked errors (the latter occur on in memory databases with
1272 /// shared cache, e.g., the per-boot database.) and restart the transaction
1273 /// after a grace period of half a millisecond.
1274 ///
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001275 /// Creates a transaction with the given behavior and executes f with the new transaction.
Janis Danisevskis66784c42021-01-27 08:40:25 -08001276 /// The transaction is committed only if f returns Ok and retried if DatabaseBusy
1277 /// or DatabaseLocked is encountered.
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001278 fn with_transaction<T, F>(&mut self, behavior: TransactionBehavior, f: F) -> Result<T>
1279 where
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001280 F: Fn(&Transaction) -> Result<(bool, T)>,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001281 {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001282 loop {
1283 match self
1284 .conn
1285 .transaction_with_behavior(behavior)
1286 .context("In with_transaction.")
1287 .and_then(|tx| f(&tx).map(|result| (result, tx)))
1288 .and_then(|(result, tx)| {
1289 tx.commit().context("In with_transaction: Failed to commit transaction.")?;
1290 Ok(result)
1291 }) {
1292 Ok(result) => break Ok(result),
1293 Err(e) => {
1294 if Self::is_locked_error(&e) {
1295 std::thread::sleep(std::time::Duration::from_micros(500));
1296 continue;
1297 } else {
1298 return Err(e).context("In with_transaction.");
1299 }
1300 }
1301 }
1302 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001303 .map(|(need_gc, result)| {
1304 if need_gc {
1305 if let Some(ref gc) = self.gc {
1306 gc.notify_gc();
1307 }
1308 }
1309 result
1310 })
Janis Danisevskis66784c42021-01-27 08:40:25 -08001311 }
1312
1313 fn is_locked_error(e: &anyhow::Error) -> bool {
1314 matches!(e.root_cause().downcast_ref::<rusqlite::ffi::Error>(),
1315 Some(rusqlite::ffi::Error {
1316 code: rusqlite::ErrorCode::DatabaseBusy,
1317 ..
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001318 })
Janis Danisevskis66784c42021-01-27 08:40:25 -08001319 | Some(rusqlite::ffi::Error {
1320 code: rusqlite::ErrorCode::DatabaseLocked,
1321 ..
1322 }))
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001323 }
1324
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001325 /// Creates a new key entry and allocates a new randomized id for the new key.
1326 /// The key id gets associated with a domain and namespace but not with an alias.
1327 /// To complete key generation `rebind_alias` should be called after all of the
1328 /// key artifacts, i.e., blobs and parameters have been associated with the new
1329 /// key id. Finalizing with `rebind_alias` makes the creation of a new key entry
1330 /// atomic even if key generation is not.
Max Bires8e93d2b2021-01-14 13:17:59 -08001331 pub fn create_key_entry(
1332 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001333 domain: &Domain,
1334 namespace: &i64,
Max Bires8e93d2b2021-01-14 13:17:59 -08001335 km_uuid: &Uuid,
1336 ) -> Result<KeyIdGuard> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001337 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001338 Self::create_key_entry_internal(tx, domain, namespace, km_uuid).no_gc()
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001339 })
1340 .context("In create_key_entry.")
1341 }
1342
1343 fn create_key_entry_internal(
1344 tx: &Transaction,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001345 domain: &Domain,
1346 namespace: &i64,
Max Bires8e93d2b2021-01-14 13:17:59 -08001347 km_uuid: &Uuid,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001348 ) -> Result<KeyIdGuard> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001349 match *domain {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001350 Domain::APP | Domain::SELINUX => {}
Joel Galenson0891bc12020-07-20 10:37:03 -07001351 _ => {
1352 return Err(KsError::sys())
1353 .context(format!("Domain {:?} must be either App or SELinux.", domain));
1354 }
1355 }
Janis Danisevskisaec14592020-11-12 09:41:49 -08001356 Ok(KEY_ID_LOCK.get(
1357 Self::insert_with_retry(|id| {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001358 tx.execute(
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001359 "INSERT into persistent.keyentry
Max Bires8e93d2b2021-01-14 13:17:59 -08001360 (id, key_type, domain, namespace, alias, state, km_uuid)
1361 VALUES(?, ?, ?, ?, NULL, ?, ?);",
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001362 params![
1363 id,
1364 KeyType::Client,
1365 domain.0 as u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001366 *namespace,
Max Bires8e93d2b2021-01-14 13:17:59 -08001367 KeyLifeCycle::Existing,
1368 km_uuid,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001369 ],
Janis Danisevskisaec14592020-11-12 09:41:49 -08001370 )
1371 })
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001372 .context("In create_key_entry_internal")?,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001373 ))
Joel Galenson26f4d012020-07-17 14:57:21 -07001374 }
Joel Galenson33c04ad2020-08-03 11:04:38 -07001375
Max Bires2b2e6562020-09-22 11:22:36 -07001376 /// Creates a new attestation key entry and allocates a new randomized id for the new key.
1377 /// The key id gets associated with a domain and namespace later but not with an alias. The
1378 /// alias will be used to denote if a key has been signed as each key can only be bound to one
1379 /// domain and namespace pairing so there is no need to use them as a value for indexing into
1380 /// a key.
1381 pub fn create_attestation_key_entry(
1382 &mut self,
1383 maced_public_key: &[u8],
1384 raw_public_key: &[u8],
1385 private_key: &[u8],
1386 km_uuid: &Uuid,
1387 ) -> Result<()> {
1388 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1389 let key_id = KEY_ID_LOCK.get(
1390 Self::insert_with_retry(|id| {
1391 tx.execute(
1392 "INSERT into persistent.keyentry
1393 (id, key_type, domain, namespace, alias, state, km_uuid)
1394 VALUES(?, ?, NULL, NULL, NULL, ?, ?);",
1395 params![id, KeyType::Attestation, KeyLifeCycle::Live, km_uuid],
1396 )
1397 })
1398 .context("In create_key_entry")?,
1399 );
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001400 Self::set_blob_internal(
1401 &tx,
1402 key_id.0,
1403 SubComponentType::KEY_BLOB,
1404 Some(private_key),
1405 None,
1406 )?;
Max Bires2b2e6562020-09-22 11:22:36 -07001407 let mut metadata = KeyMetaData::new();
1408 metadata.add(KeyMetaEntry::AttestationMacedPublicKey(maced_public_key.to_vec()));
1409 metadata.add(KeyMetaEntry::AttestationRawPubKey(raw_public_key.to_vec()));
1410 metadata.store_in_db(key_id.0, &tx)?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001411 Ok(()).no_gc()
Max Bires2b2e6562020-09-22 11:22:36 -07001412 })
1413 .context("In create_attestation_key_entry")
1414 }
1415
Janis Danisevskis377d1002021-01-27 19:07:48 -08001416 /// Set a new blob and associates it with the given key id. Each blob
1417 /// has a sub component type.
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001418 /// Each key can have one of each sub component type associated. If more
1419 /// are added only the most recent can be retrieved, and superseded blobs
Janis Danisevskis377d1002021-01-27 19:07:48 -08001420 /// will get garbage collected.
1421 /// Components SubComponentType::CERT and SubComponentType::CERT_CHAIN can be
1422 /// removed by setting blob to None.
1423 pub fn set_blob(
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001424 &mut self,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001425 key_id: &KeyIdGuard,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001426 sc_type: SubComponentType,
Janis Danisevskis377d1002021-01-27 19:07:48 -08001427 blob: Option<&[u8]>,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001428 blob_metadata: Option<&BlobMetaData>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001429 ) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001430 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001431 Self::set_blob_internal(&tx, key_id.0, sc_type, blob, blob_metadata).need_gc()
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001432 })
Janis Danisevskis377d1002021-01-27 19:07:48 -08001433 .context("In set_blob.")
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001434 }
1435
Janis Danisevskis377d1002021-01-27 19:07:48 -08001436 fn set_blob_internal(
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001437 tx: &Transaction,
1438 key_id: i64,
1439 sc_type: SubComponentType,
Janis Danisevskis377d1002021-01-27 19:07:48 -08001440 blob: Option<&[u8]>,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001441 blob_metadata: Option<&BlobMetaData>,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001442 ) -> Result<()> {
Janis Danisevskis377d1002021-01-27 19:07:48 -08001443 match (blob, sc_type) {
1444 (Some(blob), _) => {
1445 tx.execute(
1446 "INSERT INTO persistent.blobentry
1447 (subcomponent_type, keyentryid, blob) VALUES (?, ?, ?);",
1448 params![sc_type, key_id, blob],
1449 )
1450 .context("In set_blob_internal: Failed to insert blob.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001451 if let Some(blob_metadata) = blob_metadata {
1452 let blob_id = tx
1453 .query_row("SELECT MAX(id) FROM persistent.blobentry;", NO_PARAMS, |row| {
1454 row.get(0)
1455 })
1456 .context("In set_blob_internal: Failed to get new blob id.")?;
1457 blob_metadata
1458 .store_in_db(blob_id, tx)
1459 .context("In set_blob_internal: Trying to store blob metadata.")?;
1460 }
Janis Danisevskis377d1002021-01-27 19:07:48 -08001461 }
1462 (None, SubComponentType::CERT) | (None, SubComponentType::CERT_CHAIN) => {
1463 tx.execute(
1464 "DELETE FROM persistent.blobentry
1465 WHERE subcomponent_type = ? AND keyentryid = ?;",
1466 params![sc_type, key_id],
1467 )
1468 .context("In set_blob_internal: Failed to delete blob.")?;
1469 }
1470 (None, _) => {
1471 return Err(KsError::sys())
1472 .context("In set_blob_internal: Other blobs cannot be deleted in this way.");
1473 }
1474 }
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001475 Ok(())
1476 }
1477
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001478 /// Inserts a collection of key parameters into the `persistent.keyparameter` table
1479 /// and associates them with the given `key_id`.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001480 #[cfg(test)]
1481 fn insert_keyparameter(&mut self, key_id: &KeyIdGuard, params: &[KeyParameter]) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001482 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001483 Self::insert_keyparameter_internal(tx, key_id, params).no_gc()
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001484 })
1485 .context("In insert_keyparameter.")
1486 }
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001487
Janis Danisevskis66784c42021-01-27 08:40:25 -08001488 fn insert_keyparameter_internal(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001489 tx: &Transaction,
1490 key_id: &KeyIdGuard,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001491 params: &[KeyParameter],
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001492 ) -> Result<()> {
1493 let mut stmt = tx
1494 .prepare(
1495 "INSERT into persistent.keyparameter (keyentryid, tag, data, security_level)
1496 VALUES (?, ?, ?, ?);",
1497 )
1498 .context("In insert_keyparameter_internal: Failed to prepare statement.")?;
1499
Janis Danisevskis66784c42021-01-27 08:40:25 -08001500 for p in params.iter() {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001501 stmt.insert(params![
1502 key_id.0,
1503 p.get_tag().0,
1504 p.key_parameter_value(),
1505 p.security_level().0
1506 ])
1507 .with_context(|| {
1508 format!("In insert_keyparameter_internal: Failed to insert {:?}", p)
1509 })?;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001510 }
1511 Ok(())
1512 }
1513
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001514 /// Insert a set of key entry specific metadata into the database.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001515 #[cfg(test)]
1516 fn insert_key_metadata(&mut self, key_id: &KeyIdGuard, metadata: &KeyMetaData) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001517 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001518 metadata.store_in_db(key_id.0, &tx).no_gc()
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001519 })
1520 .context("In insert_key_metadata.")
1521 }
1522
Max Bires2b2e6562020-09-22 11:22:36 -07001523 /// Stores a signed certificate chain signed by a remote provisioning server, keyed
1524 /// on the public key.
1525 pub fn store_signed_attestation_certificate_chain(
1526 &mut self,
1527 raw_public_key: &[u8],
1528 cert_chain: &[u8],
1529 expiration_date: i64,
1530 km_uuid: &Uuid,
1531 ) -> Result<()> {
1532 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1533 let mut stmt = tx
1534 .prepare(
1535 "SELECT keyentryid
1536 FROM persistent.keymetadata
1537 WHERE tag = ? AND data = ? AND keyentryid IN
1538 (SELECT id
1539 FROM persistent.keyentry
1540 WHERE
1541 alias IS NULL AND
1542 domain IS NULL AND
1543 namespace IS NULL AND
1544 key_type = ? AND
1545 km_uuid = ?);",
1546 )
1547 .context("Failed to store attestation certificate chain.")?;
1548 let mut rows = stmt
1549 .query(params![
1550 KeyMetaData::AttestationRawPubKey,
1551 raw_public_key,
1552 KeyType::Attestation,
1553 km_uuid
1554 ])
1555 .context("Failed to fetch keyid")?;
1556 let key_id = db_utils::with_rows_extract_one(&mut rows, |row| {
1557 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?
1558 .get(0)
1559 .context("Failed to unpack id.")
1560 })
1561 .context("Failed to get key_id.")?;
1562 let num_updated = tx
1563 .execute(
1564 "UPDATE persistent.keyentry
1565 SET alias = ?
1566 WHERE id = ?;",
1567 params!["signed", key_id],
1568 )
1569 .context("Failed to update alias.")?;
1570 if num_updated != 1 {
1571 return Err(KsError::sys()).context("Alias not updated for the key.");
1572 }
1573 let mut metadata = KeyMetaData::new();
1574 metadata.add(KeyMetaEntry::AttestationExpirationDate(DateTime::from_millis_epoch(
1575 expiration_date,
1576 )));
1577 metadata.store_in_db(key_id, &tx).context("Failed to insert key metadata.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001578 Self::set_blob_internal(
1579 &tx,
1580 key_id,
1581 SubComponentType::CERT_CHAIN,
1582 Some(cert_chain),
1583 None,
1584 )
1585 .context("Failed to insert cert chain")?;
1586 Ok(()).no_gc()
Max Bires2b2e6562020-09-22 11:22:36 -07001587 })
1588 .context("In store_signed_attestation_certificate_chain: ")
1589 }
1590
1591 /// Assigns the next unassigned attestation key to a domain/namespace combo that does not
1592 /// currently have a key assigned to it.
1593 pub fn assign_attestation_key(
1594 &mut self,
1595 domain: Domain,
1596 namespace: i64,
1597 km_uuid: &Uuid,
1598 ) -> Result<()> {
1599 match domain {
1600 Domain::APP | Domain::SELINUX => {}
1601 _ => {
1602 return Err(KsError::sys()).context(format!(
1603 concat!(
1604 "In assign_attestation_key: Domain {:?} ",
1605 "must be either App or SELinux.",
1606 ),
1607 domain
1608 ));
1609 }
1610 }
1611 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1612 let result = tx
1613 .execute(
1614 "UPDATE persistent.keyentry
1615 SET domain=?1, namespace=?2
1616 WHERE
1617 id =
1618 (SELECT MIN(id)
1619 FROM persistent.keyentry
1620 WHERE ALIAS IS NOT NULL
1621 AND domain IS NULL
1622 AND key_type IS ?3
1623 AND state IS ?4
1624 AND km_uuid IS ?5)
1625 AND
1626 (SELECT COUNT(*)
1627 FROM persistent.keyentry
1628 WHERE domain=?1
1629 AND namespace=?2
1630 AND key_type IS ?3
1631 AND state IS ?4
1632 AND km_uuid IS ?5) = 0;",
1633 params![
1634 domain.0 as u32,
1635 namespace,
1636 KeyType::Attestation,
1637 KeyLifeCycle::Live,
1638 km_uuid,
1639 ],
1640 )
1641 .context("Failed to assign attestation key")?;
1642 if result != 1 {
1643 return Err(KsError::sys()).context(format!(
1644 "Expected to update a single entry but instead updated {}.",
1645 result
1646 ));
1647 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001648 Ok(()).no_gc()
Max Bires2b2e6562020-09-22 11:22:36 -07001649 })
1650 .context("In assign_attestation_key: ")
1651 }
1652
1653 /// Retrieves num_keys number of attestation keys that have not yet been signed by a remote
1654 /// provisioning server, or the maximum number available if there are not num_keys number of
1655 /// entries in the table.
1656 pub fn fetch_unsigned_attestation_keys(
1657 &mut self,
1658 num_keys: i32,
1659 km_uuid: &Uuid,
1660 ) -> Result<Vec<Vec<u8>>> {
1661 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1662 let mut stmt = tx
1663 .prepare(
1664 "SELECT data
1665 FROM persistent.keymetadata
1666 WHERE tag = ? AND keyentryid IN
1667 (SELECT id
1668 FROM persistent.keyentry
1669 WHERE
1670 alias IS NULL AND
1671 domain IS NULL AND
1672 namespace IS NULL AND
1673 key_type = ? AND
1674 km_uuid = ?
1675 LIMIT ?);",
1676 )
1677 .context("Failed to prepare statement")?;
1678 let rows = stmt
1679 .query_map(
1680 params![
1681 KeyMetaData::AttestationMacedPublicKey,
1682 KeyType::Attestation,
1683 km_uuid,
1684 num_keys
1685 ],
1686 |row| Ok(row.get(0)?),
1687 )?
1688 .collect::<rusqlite::Result<Vec<Vec<u8>>>>()
1689 .context("Failed to execute statement")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001690 Ok(rows).no_gc()
Max Bires2b2e6562020-09-22 11:22:36 -07001691 })
1692 .context("In fetch_unsigned_attestation_keys")
1693 }
1694
1695 /// Removes any keys that have expired as of the current time. Returns the number of keys
1696 /// marked unreferenced that are bound to be garbage collected.
1697 pub fn delete_expired_attestation_keys(&mut self) -> Result<i32> {
1698 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1699 let mut stmt = tx
1700 .prepare(
1701 "SELECT keyentryid, data
1702 FROM persistent.keymetadata
1703 WHERE tag = ? AND keyentryid IN
1704 (SELECT id
1705 FROM persistent.keyentry
1706 WHERE key_type = ?);",
1707 )
1708 .context("Failed to prepare query")?;
1709 let key_ids_to_check = stmt
1710 .query_map(
1711 params![KeyMetaData::AttestationExpirationDate, KeyType::Attestation],
1712 |row| Ok((row.get(0)?, row.get(1)?)),
1713 )?
1714 .collect::<rusqlite::Result<Vec<(i64, DateTime)>>>()
1715 .context("Failed to get date metadata")?;
1716 let curr_time = DateTime::from_millis_epoch(
1717 SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_millis() as i64,
1718 );
1719 let mut num_deleted = 0;
1720 for id in key_ids_to_check.iter().filter(|kt| kt.1 < curr_time).map(|kt| kt.0) {
1721 if Self::mark_unreferenced(&tx, id)? {
1722 num_deleted += 1;
1723 }
1724 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001725 Ok(num_deleted).do_gc(num_deleted != 0)
Max Bires2b2e6562020-09-22 11:22:36 -07001726 })
1727 .context("In delete_expired_attestation_keys: ")
1728 }
1729
1730 /// Counts the number of keys that will expire by the provided epoch date and the number of
1731 /// keys not currently assigned to a domain.
1732 pub fn get_attestation_pool_status(
1733 &mut self,
1734 date: i64,
1735 km_uuid: &Uuid,
1736 ) -> Result<AttestationPoolStatus> {
1737 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1738 let mut stmt = tx.prepare(
1739 "SELECT data
1740 FROM persistent.keymetadata
1741 WHERE tag = ? AND keyentryid IN
1742 (SELECT id
1743 FROM persistent.keyentry
1744 WHERE alias IS NOT NULL
1745 AND key_type = ?
1746 AND km_uuid = ?
1747 AND state = ?);",
1748 )?;
1749 let times = stmt
1750 .query_map(
1751 params![
1752 KeyMetaData::AttestationExpirationDate,
1753 KeyType::Attestation,
1754 km_uuid,
1755 KeyLifeCycle::Live
1756 ],
1757 |row| Ok(row.get(0)?),
1758 )?
1759 .collect::<rusqlite::Result<Vec<DateTime>>>()
1760 .context("Failed to execute metadata statement")?;
1761 let expiring =
1762 times.iter().filter(|time| time < &&DateTime::from_millis_epoch(date)).count()
1763 as i32;
1764 stmt = tx.prepare(
1765 "SELECT alias, domain
1766 FROM persistent.keyentry
1767 WHERE key_type = ? AND km_uuid = ? AND state = ?;",
1768 )?;
1769 let rows = stmt
1770 .query_map(params![KeyType::Attestation, km_uuid, KeyLifeCycle::Live], |row| {
1771 Ok((row.get(0)?, row.get(1)?))
1772 })?
1773 .collect::<rusqlite::Result<Vec<(Option<String>, Option<u32>)>>>()
1774 .context("Failed to execute keyentry statement")?;
1775 let mut unassigned = 0i32;
1776 let mut attested = 0i32;
1777 let total = rows.len() as i32;
1778 for (alias, domain) in rows {
1779 match (alias, domain) {
1780 (Some(_alias), None) => {
1781 attested += 1;
1782 unassigned += 1;
1783 }
1784 (Some(_alias), Some(_domain)) => {
1785 attested += 1;
1786 }
1787 _ => {}
1788 }
1789 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001790 Ok(AttestationPoolStatus { expiring, unassigned, attested, total }).no_gc()
Max Bires2b2e6562020-09-22 11:22:36 -07001791 })
1792 .context("In get_attestation_pool_status: ")
1793 }
1794
1795 /// Fetches the private key and corresponding certificate chain assigned to a
1796 /// domain/namespace pair. Will either return nothing if the domain/namespace is
1797 /// not assigned, or one CertificateChain.
1798 pub fn retrieve_attestation_key_and_cert_chain(
1799 &mut self,
1800 domain: Domain,
1801 namespace: i64,
1802 km_uuid: &Uuid,
1803 ) -> Result<Option<CertificateChain>> {
1804 match domain {
1805 Domain::APP | Domain::SELINUX => {}
1806 _ => {
1807 return Err(KsError::sys())
1808 .context(format!("Domain {:?} must be either App or SELinux.", domain));
1809 }
1810 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001811 self.with_transaction(TransactionBehavior::Deferred, |tx| {
1812 let mut stmt = tx.prepare(
1813 "SELECT subcomponent_type, blob
Max Bires2b2e6562020-09-22 11:22:36 -07001814 FROM persistent.blobentry
1815 WHERE keyentryid IN
1816 (SELECT id
1817 FROM persistent.keyentry
1818 WHERE key_type = ?
1819 AND domain = ?
1820 AND namespace = ?
1821 AND state = ?
1822 AND km_uuid = ?);",
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001823 )?;
1824 let rows = stmt
1825 .query_map(
1826 params![
1827 KeyType::Attestation,
1828 domain.0 as u32,
1829 namespace,
1830 KeyLifeCycle::Live,
1831 km_uuid
1832 ],
1833 |row| Ok((row.get(0)?, row.get(1)?)),
1834 )?
1835 .collect::<rusqlite::Result<Vec<(SubComponentType, Vec<u8>)>>>()
1836 .context("In retrieve_attestation_key_and_cert_chain: query failed.")?;
1837 if rows.is_empty() {
1838 return Ok(None).no_gc();
1839 } else if rows.len() != 2 {
1840 return Err(KsError::sys()).context(format!(
1841 concat!(
Max Bires2b2e6562020-09-22 11:22:36 -07001842 "In retrieve_attestation_key_and_cert_chain: Expected to get a single attestation",
1843 "key chain but instead got {}."),
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001844 rows.len()
1845 ));
Max Bires2b2e6562020-09-22 11:22:36 -07001846 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001847 let mut km_blob: Vec<u8> = Vec::new();
1848 let mut cert_chain_blob: Vec<u8> = Vec::new();
1849 for row in rows {
1850 let sub_type: SubComponentType = row.0;
1851 match sub_type {
1852 SubComponentType::KEY_BLOB => {
1853 km_blob = row.1;
1854 }
1855 SubComponentType::CERT_CHAIN => {
1856 cert_chain_blob = row.1;
1857 }
1858 _ => Err(KsError::sys()).context("Unknown or incorrect subcomponent type.")?,
1859 }
1860 }
1861 Ok(Some(CertificateChain {
1862 private_key: ZVec::try_from(km_blob)?,
1863 cert_chain: ZVec::try_from(cert_chain_blob)?,
1864 }))
1865 .no_gc()
1866 })
Max Bires2b2e6562020-09-22 11:22:36 -07001867 }
1868
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001869 /// Updates the alias column of the given key id `newid` with the given alias,
1870 /// and atomically, removes the alias, domain, and namespace from another row
1871 /// with the same alias-domain-namespace tuple if such row exits.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001872 /// Returns Ok(true) if an old key was marked unreferenced as a hint to the garbage
1873 /// collector.
1874 fn rebind_alias(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001875 tx: &Transaction,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001876 newid: &KeyIdGuard,
Joel Galenson33c04ad2020-08-03 11:04:38 -07001877 alias: &str,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001878 domain: &Domain,
1879 namespace: &i64,
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001880 ) -> Result<bool> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001881 match *domain {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001882 Domain::APP | Domain::SELINUX => {}
Joel Galenson33c04ad2020-08-03 11:04:38 -07001883 _ => {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001884 return Err(KsError::sys()).context(format!(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001885 "In rebind_alias: Domain {:?} must be either App or SELinux.",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001886 domain
1887 ));
Joel Galenson33c04ad2020-08-03 11:04:38 -07001888 }
1889 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001890 let updated = tx
1891 .execute(
1892 "UPDATE persistent.keyentry
1893 SET alias = NULL, domain = NULL, namespace = NULL, state = ?
Joel Galenson33c04ad2020-08-03 11:04:38 -07001894 WHERE alias = ? AND domain = ? AND namespace = ?;",
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001895 params![KeyLifeCycle::Unreferenced, alias, domain.0 as u32, namespace],
1896 )
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001897 .context("In rebind_alias: Failed to rebind existing entry.")?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07001898 let result = tx
1899 .execute(
1900 "UPDATE persistent.keyentry
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001901 SET alias = ?, state = ?
1902 WHERE id = ? AND domain = ? AND namespace = ? AND state = ?;",
1903 params![
1904 alias,
1905 KeyLifeCycle::Live,
1906 newid.0,
1907 domain.0 as u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001908 *namespace,
Max Bires8e93d2b2021-01-14 13:17:59 -08001909 KeyLifeCycle::Existing,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001910 ],
Joel Galenson33c04ad2020-08-03 11:04:38 -07001911 )
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001912 .context("In rebind_alias: Failed to set alias.")?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07001913 if result != 1 {
Joel Galenson33c04ad2020-08-03 11:04:38 -07001914 return Err(KsError::sys()).context(format!(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001915 "In rebind_alias: Expected to update a single entry but instead updated {}.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07001916 result
1917 ));
1918 }
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001919 Ok(updated != 0)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001920 }
1921
1922 /// Store a new key in a single transaction.
1923 /// The function creates a new key entry, populates the blob, key parameter, and metadata
1924 /// fields, and rebinds the given alias to the new key.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001925 /// The boolean returned is a hint for the garbage collector. If true, a key was replaced,
1926 /// is now unreferenced and needs to be collected.
Janis Danisevskis66784c42021-01-27 08:40:25 -08001927 pub fn store_new_key(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001928 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001929 key: &KeyDescriptor,
1930 params: &[KeyParameter],
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001931 blob_info: &(&[u8], &BlobMetaData),
Max Bires8e93d2b2021-01-14 13:17:59 -08001932 cert_info: &CertificateInfo,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001933 metadata: &KeyMetaData,
Max Bires8e93d2b2021-01-14 13:17:59 -08001934 km_uuid: &Uuid,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001935 ) -> Result<KeyIdGuard> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001936 let (alias, domain, namespace) = match key {
1937 KeyDescriptor { alias: Some(alias), domain: Domain::APP, nspace, blob: None }
1938 | KeyDescriptor { alias: Some(alias), domain: Domain::SELINUX, nspace, blob: None } => {
1939 (alias, key.domain, nspace)
1940 }
1941 _ => {
1942 return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT))
1943 .context("In store_new_key: Need alias and domain must be APP or SELINUX.")
1944 }
1945 };
1946 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001947 let key_id = Self::create_key_entry_internal(tx, &domain, namespace, km_uuid)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001948 .context("Trying to create new key entry.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001949 let (blob, blob_metadata) = *blob_info;
1950 Self::set_blob_internal(
1951 tx,
1952 key_id.id(),
1953 SubComponentType::KEY_BLOB,
1954 Some(blob),
1955 Some(&blob_metadata),
1956 )
1957 .context("Trying to insert the key blob.")?;
Max Bires8e93d2b2021-01-14 13:17:59 -08001958 if let Some(cert) = &cert_info.cert {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001959 Self::set_blob_internal(tx, key_id.id(), SubComponentType::CERT, Some(&cert), None)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001960 .context("Trying to insert the certificate.")?;
1961 }
Max Bires8e93d2b2021-01-14 13:17:59 -08001962 if let Some(cert_chain) = &cert_info.cert_chain {
Janis Danisevskis377d1002021-01-27 19:07:48 -08001963 Self::set_blob_internal(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001964 tx,
1965 key_id.id(),
1966 SubComponentType::CERT_CHAIN,
Janis Danisevskis377d1002021-01-27 19:07:48 -08001967 Some(&cert_chain),
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001968 None,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001969 )
1970 .context("Trying to insert the certificate chain.")?;
1971 }
1972 Self::insert_keyparameter_internal(tx, &key_id, params)
1973 .context("Trying to insert key parameters.")?;
Janis Danisevskis377d1002021-01-27 19:07:48 -08001974 metadata.store_in_db(key_id.id(), tx).context("Trying to insert key metadata.")?;
Janis Danisevskis66784c42021-01-27 08:40:25 -08001975 let need_gc = Self::rebind_alias(tx, &key_id, &alias, &domain, namespace)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001976 .context("Trying to rebind alias.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001977 Ok(key_id).do_gc(need_gc)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001978 })
1979 .context("In store_new_key.")
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001980 }
1981
Janis Danisevskis377d1002021-01-27 19:07:48 -08001982 /// Store a new certificate
1983 /// The function creates a new key entry, populates the blob field and metadata, and rebinds
1984 /// the given alias to the new cert.
Max Bires8e93d2b2021-01-14 13:17:59 -08001985 pub fn store_new_certificate(
1986 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001987 key: &KeyDescriptor,
Max Bires8e93d2b2021-01-14 13:17:59 -08001988 cert: &[u8],
1989 km_uuid: &Uuid,
1990 ) -> Result<KeyIdGuard> {
Janis Danisevskis377d1002021-01-27 19:07:48 -08001991 let (alias, domain, namespace) = match key {
1992 KeyDescriptor { alias: Some(alias), domain: Domain::APP, nspace, blob: None }
1993 | KeyDescriptor { alias: Some(alias), domain: Domain::SELINUX, nspace, blob: None } => {
1994 (alias, key.domain, nspace)
1995 }
1996 _ => {
1997 return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT)).context(
1998 "In store_new_certificate: Need alias and domain must be APP or SELINUX.",
1999 )
2000 }
2001 };
2002 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002003 let key_id = Self::create_key_entry_internal(tx, &domain, namespace, km_uuid)
Janis Danisevskis377d1002021-01-27 19:07:48 -08002004 .context("Trying to create new key entry.")?;
2005
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002006 Self::set_blob_internal(
2007 tx,
2008 key_id.id(),
2009 SubComponentType::CERT_CHAIN,
2010 Some(cert),
2011 None,
2012 )
2013 .context("Trying to insert certificate.")?;
Janis Danisevskis377d1002021-01-27 19:07:48 -08002014
2015 let mut metadata = KeyMetaData::new();
2016 metadata.add(KeyMetaEntry::CreationDate(
2017 DateTime::now().context("Trying to make creation time.")?,
2018 ));
2019
2020 metadata.store_in_db(key_id.id(), tx).context("Trying to insert key metadata.")?;
2021
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002022 let need_gc = Self::rebind_alias(tx, &key_id, &alias, &domain, namespace)
Janis Danisevskis377d1002021-01-27 19:07:48 -08002023 .context("Trying to rebind alias.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002024 Ok(key_id).do_gc(need_gc)
Janis Danisevskis377d1002021-01-27 19:07:48 -08002025 })
2026 .context("In store_new_certificate.")
2027 }
2028
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002029 // Helper function loading the key_id given the key descriptor
2030 // tuple comprising domain, namespace, and alias.
2031 // Requires a valid transaction.
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002032 fn load_key_entry_id(tx: &Transaction, key: &KeyDescriptor, key_type: KeyType) -> Result<i64> {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002033 let alias = key
2034 .alias
2035 .as_ref()
2036 .map_or_else(|| Err(KsError::sys()), Ok)
2037 .context("In load_key_entry_id: Alias must be specified.")?;
2038 let mut stmt = tx
2039 .prepare(
2040 "SELECT id FROM persistent.keyentry
2041 WHERE
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00002042 key_type = ?
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002043 AND domain = ?
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002044 AND namespace = ?
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002045 AND alias = ?
2046 AND state = ?;",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002047 )
2048 .context("In load_key_entry_id: Failed to select from keyentry table.")?;
2049 let mut rows = stmt
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002050 .query(params![key_type, key.domain.0 as u32, key.nspace, alias, KeyLifeCycle::Live])
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002051 .context("In load_key_entry_id: Failed to read from keyentry table.")?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002052 db_utils::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002053 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002054 .get(0)
2055 .context("Failed to unpack id.")
2056 })
2057 .context("In load_key_entry_id.")
2058 }
2059
2060 /// This helper function completes the access tuple of a key, which is required
2061 /// to perform access control. The strategy depends on the `domain` field in the
2062 /// key descriptor.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002063 /// * Domain::SELINUX: The access tuple is complete and this function only loads
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002064 /// the key_id for further processing.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002065 /// * Domain::APP: Like Domain::SELINUX, but the tuple is completed by `caller_uid`
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002066 /// which serves as the namespace.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002067 /// * Domain::GRANT: The grant table is queried for the `key_id` and the
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002068 /// `access_vector`.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002069 /// * Domain::KEY_ID: The keyentry table is queried for the owning `domain` and
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002070 /// `namespace`.
2071 /// In each case the information returned is sufficient to perform the access
2072 /// check and the key id can be used to load further key artifacts.
2073 fn load_access_tuple(
2074 tx: &Transaction,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002075 key: &KeyDescriptor,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002076 key_type: KeyType,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002077 caller_uid: u32,
2078 ) -> Result<(i64, KeyDescriptor, Option<KeyPermSet>)> {
2079 match key.domain {
2080 // Domain App or SELinux. In this case we load the key_id from
2081 // the keyentry database for further loading of key components.
2082 // We already have the full access tuple to perform access control.
2083 // The only distinction is that we use the caller_uid instead
2084 // of the caller supplied namespace if the domain field is
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002085 // Domain::APP.
2086 Domain::APP | Domain::SELINUX => {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002087 let mut access_key = key.clone();
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002088 if access_key.domain == Domain::APP {
2089 access_key.nspace = caller_uid as i64;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002090 }
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002091 let key_id = Self::load_key_entry_id(&tx, &access_key, key_type)
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002092 .with_context(|| format!("With key.domain = {:?}.", access_key.domain))?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002093
2094 Ok((key_id, access_key, None))
2095 }
2096
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002097 // Domain::GRANT. In this case we load the key_id and the access_vector
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002098 // from the grant table.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002099 Domain::GRANT => {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002100 let mut stmt = tx
2101 .prepare(
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002102 "SELECT keyentryid, access_vector FROM persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002103 WHERE grantee = ? AND id = ?;",
2104 )
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002105 .context("Domain::GRANT prepare statement failed")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002106 let mut rows = stmt
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002107 .query(params![caller_uid as i64, key.nspace])
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002108 .context("Domain:Grant: query failed.")?;
2109 let (key_id, access_vector): (i64, i32) =
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002110 db_utils::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002111 let r =
2112 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002113 Ok((
2114 r.get(0).context("Failed to unpack key_id.")?,
2115 r.get(1).context("Failed to unpack access_vector.")?,
2116 ))
2117 })
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002118 .context("Domain::GRANT.")?;
Janis Danisevskis66784c42021-01-27 08:40:25 -08002119 Ok((key_id, key.clone(), Some(access_vector.into())))
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002120 }
2121
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002122 // Domain::KEY_ID. In this case we load the domain and namespace from the
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002123 // keyentry database because we need them for access control.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002124 Domain::KEY_ID => {
Janis Danisevskis45760022021-01-19 16:34:10 -08002125 let (domain, namespace): (Domain, i64) = {
2126 let mut stmt = tx
2127 .prepare(
2128 "SELECT domain, namespace FROM persistent.keyentry
2129 WHERE
2130 id = ?
2131 AND state = ?;",
2132 )
2133 .context("Domain::KEY_ID: prepare statement failed")?;
2134 let mut rows = stmt
2135 .query(params![key.nspace, KeyLifeCycle::Live])
2136 .context("Domain::KEY_ID: query failed.")?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002137 db_utils::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002138 let r =
2139 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002140 Ok((
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002141 Domain(r.get(0).context("Failed to unpack domain.")?),
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002142 r.get(1).context("Failed to unpack namespace.")?,
2143 ))
2144 })
Janis Danisevskis45760022021-01-19 16:34:10 -08002145 .context("Domain::KEY_ID.")?
2146 };
2147
2148 // We may use a key by id after loading it by grant.
2149 // In this case we have to check if the caller has a grant for this particular
2150 // key. We can skip this if we already know that the caller is the owner.
2151 // But we cannot know this if domain is anything but App. E.g. in the case
2152 // of Domain::SELINUX we have to speculatively check for grants because we have to
2153 // consult the SEPolicy before we know if the caller is the owner.
2154 let access_vector: Option<KeyPermSet> =
2155 if domain != Domain::APP || namespace != caller_uid as i64 {
2156 let access_vector: Option<i32> = tx
2157 .query_row(
2158 "SELECT access_vector FROM persistent.grant
2159 WHERE grantee = ? AND keyentryid = ?;",
2160 params![caller_uid as i64, key.nspace],
2161 |row| row.get(0),
2162 )
2163 .optional()
2164 .context("Domain::KEY_ID: query grant failed.")?;
2165 access_vector.map(|p| p.into())
2166 } else {
2167 None
2168 };
2169
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002170 let key_id = key.nspace;
Janis Danisevskis66784c42021-01-27 08:40:25 -08002171 let mut access_key: KeyDescriptor = key.clone();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002172 access_key.domain = domain;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002173 access_key.nspace = namespace;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002174
Janis Danisevskis45760022021-01-19 16:34:10 -08002175 Ok((key_id, access_key, access_vector))
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002176 }
2177 _ => Err(anyhow!(KsError::sys())),
2178 }
2179 }
2180
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002181 fn load_blob_components(
2182 key_id: i64,
2183 load_bits: KeyEntryLoadBits,
2184 tx: &Transaction,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002185 ) -> Result<(bool, Option<(Vec<u8>, BlobMetaData)>, Option<Vec<u8>>, Option<Vec<u8>>)> {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002186 let mut stmt = tx
2187 .prepare(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002188 "SELECT MAX(id), subcomponent_type, blob FROM persistent.blobentry
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002189 WHERE keyentryid = ? GROUP BY subcomponent_type;",
2190 )
2191 .context("In load_blob_components: prepare statement failed.")?;
2192
2193 let mut rows =
2194 stmt.query(params![key_id]).context("In load_blob_components: query failed.")?;
2195
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002196 let mut key_blob: Option<(i64, Vec<u8>)> = None;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002197 let mut cert_blob: Option<Vec<u8>> = None;
2198 let mut cert_chain_blob: Option<Vec<u8>> = None;
Janis Danisevskis377d1002021-01-27 19:07:48 -08002199 let mut has_km_blob: bool = false;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002200 db_utils::with_rows_extract_all(&mut rows, |row| {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002201 let sub_type: SubComponentType =
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002202 row.get(1).context("Failed to extract subcomponent_type.")?;
Janis Danisevskis377d1002021-01-27 19:07:48 -08002203 has_km_blob = has_km_blob || sub_type == SubComponentType::KEY_BLOB;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002204 match (sub_type, load_bits.load_public(), load_bits.load_km()) {
2205 (SubComponentType::KEY_BLOB, _, true) => {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002206 key_blob = Some((
2207 row.get(0).context("Failed to extract key blob id.")?,
2208 row.get(2).context("Failed to extract key blob.")?,
2209 ));
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002210 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002211 (SubComponentType::CERT, true, _) => {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002212 cert_blob =
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002213 Some(row.get(2).context("Failed to extract public certificate blob.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002214 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002215 (SubComponentType::CERT_CHAIN, true, _) => {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002216 cert_chain_blob =
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002217 Some(row.get(2).context("Failed to extract certificate chain blob.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002218 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002219 (SubComponentType::CERT, _, _)
2220 | (SubComponentType::CERT_CHAIN, _, _)
2221 | (SubComponentType::KEY_BLOB, _, _) => {}
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002222 _ => Err(KsError::sys()).context("Unknown subcomponent type.")?,
2223 }
2224 Ok(())
2225 })
2226 .context("In load_blob_components.")?;
2227
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002228 let blob_info = key_blob.map_or::<Result<_>, _>(Ok(None), |(blob_id, blob)| {
2229 Ok(Some((
2230 blob,
2231 BlobMetaData::load_from_db(blob_id, tx)
2232 .context("In load_blob_components: Trying to load blob_metadata.")?,
2233 )))
2234 })?;
2235
2236 Ok((has_km_blob, blob_info, cert_blob, cert_chain_blob))
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002237 }
2238
2239 fn load_key_parameters(key_id: i64, tx: &Transaction) -> Result<Vec<KeyParameter>> {
2240 let mut stmt = tx
2241 .prepare(
2242 "SELECT tag, data, security_level from persistent.keyparameter
2243 WHERE keyentryid = ?;",
2244 )
2245 .context("In load_key_parameters: prepare statement failed.")?;
2246
2247 let mut parameters: Vec<KeyParameter> = Vec::new();
2248
2249 let mut rows =
2250 stmt.query(params![key_id]).context("In load_key_parameters: query failed.")?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002251 db_utils::with_rows_extract_all(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002252 let tag = Tag(row.get(0).context("Failed to read tag.")?);
2253 let sec_level = SecurityLevel(row.get(2).context("Failed to read sec_level.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002254 parameters.push(
2255 KeyParameter::new_from_sql(tag, &SqlField::new(1, &row), sec_level)
2256 .context("Failed to read KeyParameter.")?,
2257 );
2258 Ok(())
2259 })
2260 .context("In load_key_parameters.")?;
2261
2262 Ok(parameters)
2263 }
2264
Qi Wub9433b52020-12-01 14:52:46 +08002265 /// Decrements the usage count of a limited use key. This function first checks whether the
2266 /// usage has been exhausted, if not, decreases the usage count. If the usage count reaches
2267 /// zero, the key also gets marked unreferenced and scheduled for deletion.
2268 /// Returns Ok(true) if the key was marked unreferenced as a hint to the garbage collector.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002269 pub fn check_and_update_key_usage_count(&mut self, key_id: i64) -> Result<()> {
Qi Wub9433b52020-12-01 14:52:46 +08002270 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2271 let limit: Option<i32> = tx
2272 .query_row(
2273 "SELECT data FROM persistent.keyparameter WHERE keyentryid = ? AND tag = ?;",
2274 params![key_id, Tag::USAGE_COUNT_LIMIT.0],
2275 |row| row.get(0),
2276 )
2277 .optional()
2278 .context("Trying to load usage count")?;
2279
2280 let limit = limit
2281 .ok_or(KsError::Km(ErrorCode::INVALID_KEY_BLOB))
2282 .context("The Key no longer exists. Key is exhausted.")?;
2283
2284 tx.execute(
2285 "UPDATE persistent.keyparameter
2286 SET data = data - 1
2287 WHERE keyentryid = ? AND tag = ? AND data > 0;",
2288 params![key_id, Tag::USAGE_COUNT_LIMIT.0],
2289 )
2290 .context("Failed to update key usage count.")?;
2291
2292 match limit {
2293 1 => Self::mark_unreferenced(tx, key_id)
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002294 .map(|need_gc| (need_gc, ()))
Qi Wub9433b52020-12-01 14:52:46 +08002295 .context("Trying to mark limited use key for deletion."),
2296 0 => Err(KsError::Km(ErrorCode::INVALID_KEY_BLOB)).context("Key is exhausted."),
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002297 _ => Ok(()).no_gc(),
Qi Wub9433b52020-12-01 14:52:46 +08002298 }
2299 })
2300 .context("In check_and_update_key_usage_count.")
2301 }
2302
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002303 /// Load a key entry by the given key descriptor.
2304 /// It uses the `check_permission` callback to verify if the access is allowed
2305 /// given the key access tuple read from the database using `load_access_tuple`.
2306 /// With `load_bits` the caller may specify which blobs shall be loaded from
2307 /// the blob database.
2308 pub fn load_key_entry(
2309 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002310 key: &KeyDescriptor,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002311 key_type: KeyType,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002312 load_bits: KeyEntryLoadBits,
2313 caller_uid: u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002314 check_permission: impl Fn(&KeyDescriptor, Option<KeyPermSet>) -> Result<()>,
2315 ) -> Result<(KeyIdGuard, KeyEntry)> {
2316 loop {
2317 match self.load_key_entry_internal(
2318 key,
2319 key_type,
2320 load_bits,
2321 caller_uid,
2322 &check_permission,
2323 ) {
2324 Ok(result) => break Ok(result),
2325 Err(e) => {
2326 if Self::is_locked_error(&e) {
2327 std::thread::sleep(std::time::Duration::from_micros(500));
2328 continue;
2329 } else {
2330 return Err(e).context("In load_key_entry.");
2331 }
2332 }
2333 }
2334 }
2335 }
2336
2337 fn load_key_entry_internal(
2338 &mut self,
2339 key: &KeyDescriptor,
2340 key_type: KeyType,
2341 load_bits: KeyEntryLoadBits,
2342 caller_uid: u32,
2343 check_permission: &impl Fn(&KeyDescriptor, Option<KeyPermSet>) -> Result<()>,
Janis Danisevskisaec14592020-11-12 09:41:49 -08002344 ) -> Result<(KeyIdGuard, KeyEntry)> {
2345 // KEY ID LOCK 1/2
2346 // If we got a key descriptor with a key id we can get the lock right away.
2347 // Otherwise we have to defer it until we know the key id.
2348 let key_id_guard = match key.domain {
2349 Domain::KEY_ID => Some(KEY_ID_LOCK.get(key.nspace)),
2350 _ => None,
2351 };
2352
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002353 let tx = self
2354 .conn
Janis Danisevskisaec14592020-11-12 09:41:49 -08002355 .unchecked_transaction()
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002356 .context("In load_key_entry: Failed to initialize transaction.")?;
2357
2358 // Load the key_id and complete the access control tuple.
2359 let (key_id, access_key_descriptor, access_vector) =
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002360 Self::load_access_tuple(&tx, key, key_type, caller_uid)
2361 .context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002362
2363 // Perform access control. It is vital that we return here if the permission is denied.
2364 // So do not touch that '?' at the end.
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002365 check_permission(&access_key_descriptor, access_vector).context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002366
Janis Danisevskisaec14592020-11-12 09:41:49 -08002367 // KEY ID LOCK 2/2
2368 // If we did not get a key id lock by now, it was because we got a key descriptor
2369 // without a key id. At this point we got the key id, so we can try and get a lock.
2370 // However, we cannot block here, because we are in the middle of the transaction.
2371 // So first we try to get the lock non blocking. If that fails, we roll back the
2372 // transaction and block until we get the lock. After we successfully got the lock,
2373 // we start a new transaction and load the access tuple again.
2374 //
2375 // We don't need to perform access control again, because we already established
2376 // that the caller had access to the given key. But we need to make sure that the
2377 // key id still exists. So we have to load the key entry by key id this time.
2378 let (key_id_guard, tx) = match key_id_guard {
2379 None => match KEY_ID_LOCK.try_get(key_id) {
2380 None => {
2381 // Roll back the transaction.
2382 tx.rollback().context("In load_key_entry: Failed to roll back transaction.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002383
Janis Danisevskisaec14592020-11-12 09:41:49 -08002384 // Block until we have a key id lock.
2385 let key_id_guard = KEY_ID_LOCK.get(key_id);
2386
2387 // Create a new transaction.
Janis Danisevskis66784c42021-01-27 08:40:25 -08002388 let tx = self
2389 .conn
2390 .unchecked_transaction()
2391 .context("In load_key_entry: Failed to initialize transaction.")?;
Janis Danisevskisaec14592020-11-12 09:41:49 -08002392
2393 Self::load_access_tuple(
2394 &tx,
2395 // This time we have to load the key by the retrieved key id, because the
2396 // alias may have been rebound after we rolled back the transaction.
Janis Danisevskis66784c42021-01-27 08:40:25 -08002397 &KeyDescriptor {
Janis Danisevskisaec14592020-11-12 09:41:49 -08002398 domain: Domain::KEY_ID,
2399 nspace: key_id,
2400 ..Default::default()
2401 },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002402 key_type,
Janis Danisevskisaec14592020-11-12 09:41:49 -08002403 caller_uid,
2404 )
2405 .context("In load_key_entry. (deferred key lock)")?;
2406 (key_id_guard, tx)
2407 }
2408 Some(l) => (l, tx),
2409 },
2410 Some(key_id_guard) => (key_id_guard, tx),
2411 };
2412
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002413 let key_entry = Self::load_key_components(&tx, load_bits, key_id_guard.id())
2414 .context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002415
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002416 tx.commit().context("In load_key_entry: Failed to commit transaction.")?;
2417
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002418 Ok((key_id_guard, key_entry))
2419 }
2420
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002421 fn mark_unreferenced(tx: &Transaction, key_id: i64) -> Result<bool> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002422 let updated = tx
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002423 .execute("DELETE FROM persistent.keyentry WHERE id = ?;", params![key_id])
2424 .context("Trying to delete keyentry.")?;
2425 tx.execute("DELETE FROM persistent.keymetadata WHERE keyentryid = ?;", params![key_id])
2426 .context("Trying to delete keymetadata.")?;
2427 tx.execute("DELETE FROM persistent.keyparameter WHERE keyentryid = ?;", params![key_id])
2428 .context("Trying to delete keyparameters.")?;
2429 tx.execute("DELETE FROM persistent.grant WHERE keyentryid = ?;", params![key_id])
2430 .context("Trying to delete grants.")?;
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002431 Ok(updated != 0)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002432 }
2433
2434 /// Marks the given key as unreferenced and removes all of the grants to this key.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002435 /// Returns Ok(true) if a key was marked unreferenced as a hint for the garbage collector.
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002436 pub fn unbind_key(
2437 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002438 key: &KeyDescriptor,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002439 key_type: KeyType,
2440 caller_uid: u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002441 check_permission: impl Fn(&KeyDescriptor, Option<KeyPermSet>) -> Result<()>,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002442 ) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002443 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2444 let (key_id, access_key_descriptor, access_vector) =
2445 Self::load_access_tuple(tx, key, key_type, caller_uid)
2446 .context("Trying to get access tuple.")?;
2447
2448 // Perform access control. It is vital that we return here if the permission is denied.
2449 // So do not touch that '?' at the end.
2450 check_permission(&access_key_descriptor, access_vector)
2451 .context("While checking permission.")?;
2452
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002453 Self::mark_unreferenced(tx, key_id)
2454 .map(|need_gc| (need_gc, ()))
2455 .context("Trying to mark the key unreferenced.")
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002456 })
2457 .context("In unbind_key.")
2458 }
2459
Max Bires8e93d2b2021-01-14 13:17:59 -08002460 fn get_key_km_uuid(tx: &Transaction, key_id: i64) -> Result<Uuid> {
2461 tx.query_row(
2462 "SELECT km_uuid FROM persistent.keyentry WHERE id = ?",
2463 params![key_id],
2464 |row| row.get(0),
2465 )
2466 .context("In get_key_km_uuid.")
2467 }
2468
Hasini Gunasingheda895552021-01-27 19:34:37 +00002469 /// Delete the keys created on behalf of the user, denoted by the user id.
2470 /// Delete all the keys unless 'keep_non_super_encrypted_keys' set to true.
2471 /// Returned boolean is to hint the garbage collector to delete the unbound keys.
2472 /// The caller of this function should notify the gc if the returned value is true.
2473 pub fn unbind_keys_for_user(
2474 &mut self,
2475 user_id: u32,
2476 keep_non_super_encrypted_keys: bool,
2477 ) -> Result<()> {
2478 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2479 let mut stmt = tx
2480 .prepare(&format!(
2481 "SELECT id from persistent.keyentry
2482 WHERE (
2483 key_type = ?
2484 AND domain = ?
2485 AND cast ( (namespace/{aid_user_offset}) as int) = ?
2486 AND state = ?
2487 ) OR (
2488 key_type = ?
2489 AND namespace = ?
2490 AND alias = ?
2491 AND state = ?
2492 );",
2493 aid_user_offset = AID_USER_OFFSET
2494 ))
2495 .context(concat!(
2496 "In unbind_keys_for_user. ",
2497 "Failed to prepare the query to find the keys created by apps."
2498 ))?;
2499
2500 let mut rows = stmt
2501 .query(params![
2502 // WHERE client key:
2503 KeyType::Client,
2504 Domain::APP.0 as u32,
2505 user_id,
2506 KeyLifeCycle::Live,
2507 // OR super key:
2508 KeyType::Super,
2509 user_id,
2510 Self::USER_SUPER_KEY_ALIAS,
2511 KeyLifeCycle::Live
2512 ])
2513 .context("In unbind_keys_for_user. Failed to query the keys created by apps.")?;
2514
2515 let mut key_ids: Vec<i64> = Vec::new();
2516 db_utils::with_rows_extract_all(&mut rows, |row| {
2517 key_ids
2518 .push(row.get(0).context("Failed to read key id of a key created by an app.")?);
2519 Ok(())
2520 })
2521 .context("In unbind_keys_for_user.")?;
2522
2523 let mut notify_gc = false;
2524 for key_id in key_ids {
2525 if keep_non_super_encrypted_keys {
2526 // Load metadata and filter out non-super-encrypted keys.
2527 if let (_, Some((_, blob_metadata)), _, _) =
2528 Self::load_blob_components(key_id, KeyEntryLoadBits::KM, tx)
2529 .context("In unbind_keys_for_user: Trying to load blob info.")?
2530 {
2531 if blob_metadata.encrypted_by().is_none() {
2532 continue;
2533 }
2534 }
2535 }
2536 notify_gc = Self::mark_unreferenced(&tx, key_id as u64 as i64)
2537 .context("In unbind_keys_for_user.")?
2538 || notify_gc;
2539 }
2540 Ok(()).do_gc(notify_gc)
2541 })
2542 .context("In unbind_keys_for_user.")
2543 }
2544
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002545 fn load_key_components(
2546 tx: &Transaction,
2547 load_bits: KeyEntryLoadBits,
2548 key_id: i64,
2549 ) -> Result<KeyEntry> {
2550 let metadata = KeyMetaData::load_from_db(key_id, &tx).context("In load_key_components.")?;
2551
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002552 let (has_km_blob, key_blob_info, cert_blob, cert_chain_blob) =
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002553 Self::load_blob_components(key_id, load_bits, &tx)
2554 .context("In load_key_components.")?;
2555
Max Bires8e93d2b2021-01-14 13:17:59 -08002556 let parameters = Self::load_key_parameters(key_id, &tx)
2557 .context("In load_key_components: Trying to load key parameters.")?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002558
Max Bires8e93d2b2021-01-14 13:17:59 -08002559 let km_uuid = Self::get_key_km_uuid(&tx, key_id)
2560 .context("In load_key_components: Trying to get KM uuid.")?;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002561
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002562 Ok(KeyEntry {
2563 id: key_id,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002564 key_blob_info,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002565 cert: cert_blob,
2566 cert_chain: cert_chain_blob,
Max Bires8e93d2b2021-01-14 13:17:59 -08002567 km_uuid,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002568 parameters,
2569 metadata,
Janis Danisevskis377d1002021-01-27 19:07:48 -08002570 pure_cert: !has_km_blob,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002571 })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002572 }
2573
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002574 /// Returns a list of KeyDescriptors in the selected domain/namespace.
2575 /// The key descriptors will have the domain, nspace, and alias field set.
2576 /// Domain must be APP or SELINUX, the caller must make sure of that.
2577 pub fn list(&mut self, domain: Domain, namespace: i64) -> Result<Vec<KeyDescriptor>> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002578 self.with_transaction(TransactionBehavior::Deferred, |tx| {
2579 let mut stmt = tx
2580 .prepare(
2581 "SELECT alias FROM persistent.keyentry
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002582 WHERE domain = ? AND namespace = ? AND alias IS NOT NULL AND state = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08002583 )
2584 .context("In list: Failed to prepare.")?;
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002585
Janis Danisevskis66784c42021-01-27 08:40:25 -08002586 let mut rows = stmt
2587 .query(params![domain.0 as u32, namespace, KeyLifeCycle::Live])
2588 .context("In list: Failed to query.")?;
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002589
Janis Danisevskis66784c42021-01-27 08:40:25 -08002590 let mut descriptors: Vec<KeyDescriptor> = Vec::new();
2591 db_utils::with_rows_extract_all(&mut rows, |row| {
2592 descriptors.push(KeyDescriptor {
2593 domain,
2594 nspace: namespace,
2595 alias: Some(row.get(0).context("Trying to extract alias.")?),
2596 blob: None,
2597 });
2598 Ok(())
2599 })
2600 .context("In list: Failed to extract rows.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002601 Ok(descriptors).no_gc()
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002602 })
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002603 }
2604
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002605 /// Adds a grant to the grant table.
2606 /// Like `load_key_entry` this function loads the access tuple before
2607 /// it uses the callback for a permission check. Upon success,
2608 /// it inserts the `grantee_uid`, `key_id`, and `access_vector` into the
2609 /// grant table. The new row will have a randomized id, which is used as
2610 /// grant id in the namespace field of the resulting KeyDescriptor.
2611 pub fn grant(
2612 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002613 key: &KeyDescriptor,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002614 caller_uid: u32,
2615 grantee_uid: u32,
2616 access_vector: KeyPermSet,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002617 check_permission: impl Fn(&KeyDescriptor, &KeyPermSet) -> Result<()>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002618 ) -> Result<KeyDescriptor> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002619 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2620 // Load the key_id and complete the access control tuple.
2621 // We ignore the access vector here because grants cannot be granted.
2622 // The access vector returned here expresses the permissions the
2623 // grantee has if key.domain == Domain::GRANT. But this vector
2624 // cannot include the grant permission by design, so there is no way the
2625 // subsequent permission check can pass.
2626 // We could check key.domain == Domain::GRANT and fail early.
2627 // But even if we load the access tuple by grant here, the permission
2628 // check denies the attempt to create a grant by grant descriptor.
2629 let (key_id, access_key_descriptor, _) =
2630 Self::load_access_tuple(&tx, key, KeyType::Client, caller_uid)
2631 .context("In grant")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002632
Janis Danisevskis66784c42021-01-27 08:40:25 -08002633 // Perform access control. It is vital that we return here if the permission
2634 // was denied. So do not touch that '?' at the end of the line.
2635 // This permission check checks if the caller has the grant permission
2636 // for the given key and in addition to all of the permissions
2637 // expressed in `access_vector`.
2638 check_permission(&access_key_descriptor, &access_vector)
2639 .context("In grant: check_permission failed.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002640
Janis Danisevskis66784c42021-01-27 08:40:25 -08002641 let grant_id = if let Some(grant_id) = tx
2642 .query_row(
2643 "SELECT id FROM persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002644 WHERE keyentryid = ? AND grantee = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08002645 params![key_id, grantee_uid],
2646 |row| row.get(0),
2647 )
2648 .optional()
2649 .context("In grant: Failed get optional existing grant id.")?
2650 {
2651 tx.execute(
2652 "UPDATE persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002653 SET access_vector = ?
2654 WHERE id = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08002655 params![i32::from(access_vector), grant_id],
Joel Galenson845f74b2020-09-09 14:11:55 -07002656 )
Janis Danisevskis66784c42021-01-27 08:40:25 -08002657 .context("In grant: Failed to update existing grant.")?;
2658 grant_id
2659 } else {
2660 Self::insert_with_retry(|id| {
2661 tx.execute(
2662 "INSERT INTO persistent.grant (id, grantee, keyentryid, access_vector)
2663 VALUES (?, ?, ?, ?);",
2664 params![id, grantee_uid, key_id, i32::from(access_vector)],
2665 )
2666 })
2667 .context("In grant")?
2668 };
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002669
Janis Danisevskis66784c42021-01-27 08:40:25 -08002670 Ok(KeyDescriptor { domain: Domain::GRANT, nspace: grant_id, alias: None, blob: None })
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002671 .no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08002672 })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002673 }
2674
2675 /// This function checks permissions like `grant` and `load_key_entry`
2676 /// before removing a grant from the grant table.
2677 pub fn ungrant(
2678 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002679 key: &KeyDescriptor,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002680 caller_uid: u32,
2681 grantee_uid: u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002682 check_permission: impl Fn(&KeyDescriptor) -> Result<()>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002683 ) -> Result<()> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002684 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2685 // Load the key_id and complete the access control tuple.
2686 // We ignore the access vector here because grants cannot be granted.
2687 let (key_id, access_key_descriptor, _) =
2688 Self::load_access_tuple(&tx, key, KeyType::Client, caller_uid)
2689 .context("In ungrant.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002690
Janis Danisevskis66784c42021-01-27 08:40:25 -08002691 // Perform access control. We must return here if the permission
2692 // was denied. So do not touch the '?' at the end of this line.
2693 check_permission(&access_key_descriptor)
2694 .context("In grant: check_permission failed.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002695
Janis Danisevskis66784c42021-01-27 08:40:25 -08002696 tx.execute(
2697 "DELETE FROM persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002698 WHERE keyentryid = ? AND grantee = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08002699 params![key_id, grantee_uid],
2700 )
2701 .context("Failed to delete grant.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002702
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002703 Ok(()).no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08002704 })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002705 }
2706
Joel Galenson845f74b2020-09-09 14:11:55 -07002707 // Generates a random id and passes it to the given function, which will
2708 // try to insert it into a database. If that insertion fails, retry;
2709 // otherwise return the id.
2710 fn insert_with_retry(inserter: impl Fn(i64) -> rusqlite::Result<usize>) -> Result<i64> {
2711 loop {
2712 let newid: i64 = random();
2713 match inserter(newid) {
2714 // If the id already existed, try again.
2715 Err(rusqlite::Error::SqliteFailure(
2716 libsqlite3_sys::Error {
2717 code: libsqlite3_sys::ErrorCode::ConstraintViolation,
2718 extended_code: libsqlite3_sys::SQLITE_CONSTRAINT_UNIQUE,
2719 },
2720 _,
2721 )) => (),
2722 Err(e) => {
2723 return Err(e).context("In insert_with_retry: failed to insert into database.")
2724 }
2725 _ => return Ok(newid),
2726 }
2727 }
2728 }
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002729
2730 /// Insert or replace the auth token based on the UNIQUE constraint of the auth token table
2731 pub fn insert_auth_token(&mut self, auth_token: &HardwareAuthToken) -> Result<()> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002732 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2733 tx.execute(
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002734 "INSERT OR REPLACE INTO perboot.authtoken (challenge, user_id, auth_id,
2735 authenticator_type, timestamp, mac, time_received) VALUES(?, ?, ?, ?, ?, ?, ?);",
2736 params![
2737 auth_token.challenge,
2738 auth_token.userId,
2739 auth_token.authenticatorId,
2740 auth_token.authenticatorType.0 as i32,
2741 auth_token.timestamp.milliSeconds as i64,
2742 auth_token.mac,
2743 MonotonicRawTime::now(),
2744 ],
2745 )
2746 .context("In insert_auth_token: failed to insert auth token into the database")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002747 Ok(()).no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08002748 })
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002749 }
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002750
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002751 /// Find the newest auth token matching the given predicate.
2752 pub fn find_auth_token_entry<F>(
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002753 &mut self,
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002754 p: F,
2755 ) -> Result<Option<(AuthTokenEntry, MonotonicRawTime)>>
2756 where
2757 F: Fn(&AuthTokenEntry) -> bool,
2758 {
2759 self.with_transaction(TransactionBehavior::Deferred, |tx| {
2760 let mut stmt = tx
2761 .prepare("SELECT * from perboot.authtoken ORDER BY time_received DESC;")
2762 .context("Prepare statement failed.")?;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002763
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002764 let mut rows = stmt.query(NO_PARAMS).context("Failed to query.")?;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002765
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002766 while let Some(row) = rows.next().context("Failed to get next row.")? {
2767 let entry = AuthTokenEntry::new(
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002768 HardwareAuthToken {
2769 challenge: row.get(1)?,
2770 userId: row.get(2)?,
2771 authenticatorId: row.get(3)?,
2772 authenticatorType: HardwareAuthenticatorType(row.get(4)?),
2773 timestamp: Timestamp { milliSeconds: row.get(5)? },
2774 mac: row.get(6)?,
2775 },
2776 row.get(7)?,
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002777 );
2778 if p(&entry) {
2779 return Ok(Some((
2780 entry,
2781 Self::get_last_off_body(tx)
2782 .context("In find_auth_token_entry: Trying to get last off body")?,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002783 )))
2784 .no_gc();
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002785 }
2786 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002787 Ok(None).no_gc()
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002788 })
2789 .context("In find_auth_token_entry.")
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002790 }
2791
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002792 /// Insert last_off_body into the metadata table at the initialization of auth token table
Janis Danisevskis66784c42021-01-27 08:40:25 -08002793 pub fn insert_last_off_body(&mut self, last_off_body: MonotonicRawTime) -> Result<()> {
2794 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2795 tx.execute(
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002796 "INSERT OR REPLACE INTO perboot.metadata (key, value) VALUES (?, ?);",
2797 params!["last_off_body", last_off_body],
2798 )
2799 .context("In insert_last_off_body: failed to insert.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002800 Ok(()).no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08002801 })
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002802 }
2803
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002804 /// Update last_off_body when on_device_off_body is called
Janis Danisevskis66784c42021-01-27 08:40:25 -08002805 pub fn update_last_off_body(&mut self, last_off_body: MonotonicRawTime) -> Result<()> {
2806 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2807 tx.execute(
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002808 "UPDATE perboot.metadata SET value = ? WHERE key = ?;",
2809 params![last_off_body, "last_off_body"],
2810 )
2811 .context("In update_last_off_body: failed to update.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002812 Ok(()).no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08002813 })
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002814 }
2815
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002816 /// Get last_off_body time when finding auth tokens
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002817 fn get_last_off_body(tx: &Transaction) -> Result<MonotonicRawTime> {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002818 tx.query_row(
2819 "SELECT value from perboot.metadata WHERE key = ?;",
2820 params!["last_off_body"],
2821 |row| Ok(row.get(0)?),
2822 )
2823 .context("In get_last_off_body: query_row failed.")
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002824 }
Joel Galenson26f4d012020-07-17 14:57:21 -07002825}
2826
2827#[cfg(test)]
2828mod tests {
2829
2830 use super::*;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002831 use crate::key_parameter::{
2832 Algorithm, BlockMode, Digest, EcCurve, HardwareAuthenticatorType, KeyOrigin, KeyParameter,
2833 KeyParameterValue, KeyPurpose, PaddingMode, SecurityLevel,
2834 };
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002835 use crate::key_perm_set;
2836 use crate::permission::{KeyPerm, KeyPermSet};
Hasini Gunasingheda895552021-01-27 19:34:37 +00002837 use crate::super_key::SuperKeyManager;
Janis Danisevskis2a8330a2021-01-20 15:34:26 -08002838 use keystore2_test_utils::TempDir;
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002839 use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
2840 HardwareAuthToken::HardwareAuthToken,
2841 HardwareAuthenticatorType::HardwareAuthenticatorType as kmhw_authenticator_type,
Janis Danisevskisc3a496b2021-01-05 10:37:22 -08002842 };
2843 use android_hardware_security_secureclock::aidl::android::hardware::security::secureclock::{
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002844 Timestamp::Timestamp,
2845 };
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002846 use rusqlite::NO_PARAMS;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002847 use rusqlite::{Error, TransactionBehavior};
Joel Galenson0891bc12020-07-20 10:37:03 -07002848 use std::cell::RefCell;
Janis Danisevskisaec14592020-11-12 09:41:49 -08002849 use std::sync::atomic::{AtomicU8, Ordering};
2850 use std::sync::Arc;
2851 use std::thread;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002852 use std::time::{Duration, SystemTime};
Janis Danisevskis66784c42021-01-27 08:40:25 -08002853 #[cfg(disabled)]
2854 use std::time::Instant;
Joel Galenson0891bc12020-07-20 10:37:03 -07002855
Janis Danisevskis4df44f42020-08-26 14:40:03 -07002856 fn new_test_db() -> Result<KeystoreDB> {
2857 let conn = KeystoreDB::make_connection("file::memory:", "file::memory:")?;
2858
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002859 let mut db = KeystoreDB { conn, gc: None };
Janis Danisevskis66784c42021-01-27 08:40:25 -08002860 db.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002861 KeystoreDB::init_tables(tx).context("Failed to initialize tables.").no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08002862 })?;
2863 Ok(db)
Janis Danisevskis4df44f42020-08-26 14:40:03 -07002864 }
2865
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002866 fn new_test_db_with_gc<F>(path: &Path, cb: F) -> Result<KeystoreDB>
2867 where
2868 F: Fn(&Uuid, &[u8]) -> Result<()> + Send + 'static,
2869 {
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00002870 let super_key = Arc::new(SuperKeyManager::new());
2871
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002872 let gc_db = KeystoreDB::new(path, None).expect("Failed to open test gc db_connection.");
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00002873 let gc = Gc::new_init_with(Default::default(), move || (Box::new(cb), gc_db, super_key));
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002874
2875 KeystoreDB::new(path, Some(gc))
2876 }
2877
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002878 fn rebind_alias(
2879 db: &mut KeystoreDB,
2880 newid: &KeyIdGuard,
2881 alias: &str,
2882 domain: Domain,
2883 namespace: i64,
2884 ) -> Result<bool> {
2885 db.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002886 KeystoreDB::rebind_alias(tx, newid, alias, &domain, &namespace).no_gc()
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002887 })
2888 .context("In rebind_alias.")
2889 }
2890
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002891 #[test]
2892 fn datetime() -> Result<()> {
2893 let conn = Connection::open_in_memory()?;
2894 conn.execute("CREATE TABLE test (ts DATETIME);", NO_PARAMS)?;
2895 let now = SystemTime::now();
2896 let duration = Duration::from_secs(1000);
2897 let then = now.checked_sub(duration).unwrap();
2898 let soon = now.checked_add(duration).unwrap();
2899 conn.execute(
2900 "INSERT INTO test (ts) VALUES (?), (?), (?);",
2901 params![DateTime::try_from(now)?, DateTime::try_from(then)?, DateTime::try_from(soon)?],
2902 )?;
2903 let mut stmt = conn.prepare("SELECT ts FROM test ORDER BY ts ASC;")?;
2904 let mut rows = stmt.query(NO_PARAMS)?;
2905 assert_eq!(DateTime::try_from(then)?, rows.next()?.unwrap().get(0)?);
2906 assert_eq!(DateTime::try_from(now)?, rows.next()?.unwrap().get(0)?);
2907 assert_eq!(DateTime::try_from(soon)?, rows.next()?.unwrap().get(0)?);
2908 assert!(rows.next()?.is_none());
2909 assert!(DateTime::try_from(then)? < DateTime::try_from(now)?);
2910 assert!(DateTime::try_from(then)? < DateTime::try_from(soon)?);
2911 assert!(DateTime::try_from(now)? < DateTime::try_from(soon)?);
2912 Ok(())
2913 }
2914
Joel Galenson0891bc12020-07-20 10:37:03 -07002915 // Ensure that we're using the "injected" random function, not the real one.
2916 #[test]
2917 fn test_mocked_random() {
2918 let rand1 = random();
2919 let rand2 = random();
2920 let rand3 = random();
2921 if rand1 == rand2 {
2922 assert_eq!(rand2 + 1, rand3);
2923 } else {
2924 assert_eq!(rand1 + 1, rand2);
2925 assert_eq!(rand2, rand3);
2926 }
2927 }
Joel Galenson26f4d012020-07-17 14:57:21 -07002928
Joel Galenson26f4d012020-07-17 14:57:21 -07002929 // Test that we have the correct tables.
2930 #[test]
2931 fn test_tables() -> Result<()> {
Janis Danisevskis4df44f42020-08-26 14:40:03 -07002932 let db = new_test_db()?;
Joel Galenson26f4d012020-07-17 14:57:21 -07002933 let tables = db
2934 .conn
Joel Galenson2aab4432020-07-22 15:27:57 -07002935 .prepare("SELECT name from persistent.sqlite_master WHERE type='table' ORDER BY name;")?
Joel Galenson26f4d012020-07-17 14:57:21 -07002936 .query_map(params![], |row| row.get(0))?
2937 .collect::<rusqlite::Result<Vec<String>>>()?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002938 assert_eq!(tables.len(), 6);
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002939 assert_eq!(tables[0], "blobentry");
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002940 assert_eq!(tables[1], "blobmetadata");
2941 assert_eq!(tables[2], "grant");
2942 assert_eq!(tables[3], "keyentry");
2943 assert_eq!(tables[4], "keymetadata");
2944 assert_eq!(tables[5], "keyparameter");
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002945 let tables = db
2946 .conn
2947 .prepare("SELECT name from perboot.sqlite_master WHERE type='table' ORDER BY name;")?
2948 .query_map(params![], |row| row.get(0))?
2949 .collect::<rusqlite::Result<Vec<String>>>()?;
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002950
2951 assert_eq!(tables.len(), 2);
2952 assert_eq!(tables[0], "authtoken");
2953 assert_eq!(tables[1], "metadata");
Joel Galenson2aab4432020-07-22 15:27:57 -07002954 Ok(())
2955 }
2956
2957 #[test]
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002958 fn test_auth_token_table_invariant() -> Result<()> {
2959 let mut db = new_test_db()?;
2960 let auth_token1 = HardwareAuthToken {
2961 challenge: i64::MAX,
2962 userId: 200,
2963 authenticatorId: 200,
2964 authenticatorType: kmhw_authenticator_type(kmhw_authenticator_type::PASSWORD.0),
2965 timestamp: Timestamp { milliSeconds: 500 },
2966 mac: String::from("mac").into_bytes(),
2967 };
2968 db.insert_auth_token(&auth_token1)?;
2969 let auth_tokens_returned = get_auth_tokens(&mut db)?;
2970 assert_eq!(auth_tokens_returned.len(), 1);
2971
2972 // insert another auth token with the same values for the columns in the UNIQUE constraint
2973 // of the auth token table and different value for timestamp
2974 let auth_token2 = HardwareAuthToken {
2975 challenge: i64::MAX,
2976 userId: 200,
2977 authenticatorId: 200,
2978 authenticatorType: kmhw_authenticator_type(kmhw_authenticator_type::PASSWORD.0),
2979 timestamp: Timestamp { milliSeconds: 600 },
2980 mac: String::from("mac").into_bytes(),
2981 };
2982
2983 db.insert_auth_token(&auth_token2)?;
2984 let mut auth_tokens_returned = get_auth_tokens(&mut db)?;
2985 assert_eq!(auth_tokens_returned.len(), 1);
2986
2987 if let Some(auth_token) = auth_tokens_returned.pop() {
2988 assert_eq!(auth_token.auth_token.timestamp.milliSeconds, 600);
2989 }
2990
2991 // insert another auth token with the different values for the columns in the UNIQUE
2992 // constraint of the auth token table
2993 let auth_token3 = HardwareAuthToken {
2994 challenge: i64::MAX,
2995 userId: 201,
2996 authenticatorId: 200,
2997 authenticatorType: kmhw_authenticator_type(kmhw_authenticator_type::PASSWORD.0),
2998 timestamp: Timestamp { milliSeconds: 600 },
2999 mac: String::from("mac").into_bytes(),
3000 };
3001
3002 db.insert_auth_token(&auth_token3)?;
3003 let auth_tokens_returned = get_auth_tokens(&mut db)?;
3004 assert_eq!(auth_tokens_returned.len(), 2);
3005
3006 Ok(())
3007 }
3008
3009 // utility function for test_auth_token_table_invariant()
3010 fn get_auth_tokens(db: &mut KeystoreDB) -> Result<Vec<AuthTokenEntry>> {
3011 let mut stmt = db.conn.prepare("SELECT * from perboot.authtoken;")?;
3012
3013 let auth_token_entries: Vec<AuthTokenEntry> = stmt
3014 .query_map(NO_PARAMS, |row| {
3015 Ok(AuthTokenEntry::new(
3016 HardwareAuthToken {
3017 challenge: row.get(1)?,
3018 userId: row.get(2)?,
3019 authenticatorId: row.get(3)?,
3020 authenticatorType: HardwareAuthenticatorType(row.get(4)?),
3021 timestamp: Timestamp { milliSeconds: row.get(5)? },
3022 mac: row.get(6)?,
3023 },
3024 row.get(7)?,
3025 ))
3026 })?
3027 .collect::<Result<Vec<AuthTokenEntry>, Error>>()?;
3028 Ok(auth_token_entries)
3029 }
3030
3031 #[test]
Joel Galenson2aab4432020-07-22 15:27:57 -07003032 fn test_persistence_for_files() -> Result<()> {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08003033 let temp_dir = TempDir::new("persistent_db_test")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003034 let mut db = KeystoreDB::new(temp_dir.path(), None)?;
Joel Galenson2aab4432020-07-22 15:27:57 -07003035
Janis Danisevskis66784c42021-01-27 08:40:25 -08003036 db.create_key_entry(&Domain::APP, &100, &KEYSTORE_UUID)?;
Joel Galenson2aab4432020-07-22 15:27:57 -07003037 let entries = get_keyentry(&db)?;
3038 assert_eq!(entries.len(), 1);
Janis Danisevskisbf15d732020-12-08 10:35:26 -08003039
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003040 let db = KeystoreDB::new(temp_dir.path(), None)?;
Joel Galenson2aab4432020-07-22 15:27:57 -07003041
3042 let entries_new = get_keyentry(&db)?;
3043 assert_eq!(entries, entries_new);
3044 Ok(())
3045 }
3046
3047 #[test]
Joel Galenson0891bc12020-07-20 10:37:03 -07003048 fn test_create_key_entry() -> Result<()> {
Max Bires8e93d2b2021-01-14 13:17:59 -08003049 fn extractor(ke: &KeyEntryRow) -> (Domain, i64, Option<&str>, Uuid) {
3050 (ke.domain.unwrap(), ke.namespace.unwrap(), ke.alias.as_deref(), ke.km_uuid.unwrap())
Joel Galenson0891bc12020-07-20 10:37:03 -07003051 }
3052
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003053 let mut db = new_test_db()?;
Joel Galenson0891bc12020-07-20 10:37:03 -07003054
Janis Danisevskis66784c42021-01-27 08:40:25 -08003055 db.create_key_entry(&Domain::APP, &100, &KEYSTORE_UUID)?;
3056 db.create_key_entry(&Domain::SELINUX, &101, &KEYSTORE_UUID)?;
Joel Galenson0891bc12020-07-20 10:37:03 -07003057
3058 let entries = get_keyentry(&db)?;
3059 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08003060 assert_eq!(extractor(&entries[0]), (Domain::APP, 100, None, KEYSTORE_UUID));
3061 assert_eq!(extractor(&entries[1]), (Domain::SELINUX, 101, None, KEYSTORE_UUID));
Joel Galenson0891bc12020-07-20 10:37:03 -07003062
3063 // Test that we must pass in a valid Domain.
3064 check_result_is_error_containing_string(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003065 db.create_key_entry(&Domain::GRANT, &102, &KEYSTORE_UUID),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003066 "Domain Domain(1) must be either App or SELinux.",
Joel Galenson0891bc12020-07-20 10:37:03 -07003067 );
3068 check_result_is_error_containing_string(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003069 db.create_key_entry(&Domain::BLOB, &103, &KEYSTORE_UUID),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003070 "Domain Domain(3) must be either App or SELinux.",
Joel Galenson0891bc12020-07-20 10:37:03 -07003071 );
3072 check_result_is_error_containing_string(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003073 db.create_key_entry(&Domain::KEY_ID, &104, &KEYSTORE_UUID),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003074 "Domain Domain(4) must be either App or SELinux.",
Joel Galenson0891bc12020-07-20 10:37:03 -07003075 );
3076
3077 Ok(())
3078 }
3079
Joel Galenson33c04ad2020-08-03 11:04:38 -07003080 #[test]
Max Bires2b2e6562020-09-22 11:22:36 -07003081 fn test_add_unsigned_key() -> Result<()> {
3082 let mut db = new_test_db()?;
3083 let public_key: Vec<u8> = vec![0x01, 0x02, 0x03];
3084 let private_key: Vec<u8> = vec![0x04, 0x05, 0x06];
3085 let raw_public_key: Vec<u8> = vec![0x07, 0x08, 0x09];
3086 db.create_attestation_key_entry(
3087 &public_key,
3088 &raw_public_key,
3089 &private_key,
3090 &KEYSTORE_UUID,
3091 )?;
3092 let keys = db.fetch_unsigned_attestation_keys(5, &KEYSTORE_UUID)?;
3093 assert_eq!(keys.len(), 1);
3094 assert_eq!(keys[0], public_key);
3095 Ok(())
3096 }
3097
3098 #[test]
3099 fn test_store_signed_attestation_certificate_chain() -> Result<()> {
3100 let mut db = new_test_db()?;
3101 let expiration_date: i64 = 20;
3102 let namespace: i64 = 30;
3103 let base_byte: u8 = 1;
3104 let loaded_values =
3105 load_attestation_key_pool(&mut db, expiration_date, namespace, base_byte)?;
3106 let chain =
3107 db.retrieve_attestation_key_and_cert_chain(Domain::APP, namespace, &KEYSTORE_UUID)?;
3108 assert_eq!(true, chain.is_some());
3109 let cert_chain = chain.unwrap();
3110 assert_eq!(cert_chain.private_key.to_vec(), loaded_values[2]);
3111 assert_eq!(cert_chain.cert_chain.to_vec(), loaded_values[1]);
3112 Ok(())
3113 }
3114
3115 #[test]
3116 fn test_get_attestation_pool_status() -> Result<()> {
3117 let mut db = new_test_db()?;
3118 let namespace: i64 = 30;
3119 load_attestation_key_pool(
3120 &mut db, 10, /* expiration */
3121 namespace, 0x01, /* base_byte */
3122 )?;
3123 load_attestation_key_pool(&mut db, 20 /* expiration */, namespace + 1, 0x02)?;
3124 load_attestation_key_pool(&mut db, 40 /* expiration */, namespace + 2, 0x03)?;
3125 let mut status = db.get_attestation_pool_status(9 /* expiration */, &KEYSTORE_UUID)?;
3126 assert_eq!(status.expiring, 0);
3127 assert_eq!(status.attested, 3);
3128 assert_eq!(status.unassigned, 0);
3129 assert_eq!(status.total, 3);
3130 assert_eq!(
3131 db.get_attestation_pool_status(15 /* expiration */, &KEYSTORE_UUID)?.expiring,
3132 1
3133 );
3134 assert_eq!(
3135 db.get_attestation_pool_status(25 /* expiration */, &KEYSTORE_UUID)?.expiring,
3136 2
3137 );
3138 assert_eq!(
3139 db.get_attestation_pool_status(60 /* expiration */, &KEYSTORE_UUID)?.expiring,
3140 3
3141 );
3142 let public_key: Vec<u8> = vec![0x01, 0x02, 0x03];
3143 let private_key: Vec<u8> = vec![0x04, 0x05, 0x06];
3144 let raw_public_key: Vec<u8> = vec![0x07, 0x08, 0x09];
3145 let cert_chain: Vec<u8> = vec![0x0a, 0x0b, 0x0c];
3146 db.create_attestation_key_entry(
3147 &public_key,
3148 &raw_public_key,
3149 &private_key,
3150 &KEYSTORE_UUID,
3151 )?;
3152 status = db.get_attestation_pool_status(0 /* expiration */, &KEYSTORE_UUID)?;
3153 assert_eq!(status.attested, 3);
3154 assert_eq!(status.unassigned, 0);
3155 assert_eq!(status.total, 4);
3156 db.store_signed_attestation_certificate_chain(
3157 &raw_public_key,
3158 &cert_chain,
3159 20,
3160 &KEYSTORE_UUID,
3161 )?;
3162 status = db.get_attestation_pool_status(0 /* expiration */, &KEYSTORE_UUID)?;
3163 assert_eq!(status.attested, 4);
3164 assert_eq!(status.unassigned, 1);
3165 assert_eq!(status.total, 4);
3166 Ok(())
3167 }
3168
3169 #[test]
3170 fn test_remove_expired_certs() -> Result<()> {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003171 let temp_dir =
3172 TempDir::new("test_remove_expired_certs_").expect("Failed to create temp dir.");
3173 let mut db = new_test_db_with_gc(temp_dir.path(), |_, _| Ok(()))?;
Max Bires2b2e6562020-09-22 11:22:36 -07003174 let expiration_date: i64 =
3175 SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_millis() as i64 + 10000;
3176 let namespace: i64 = 30;
3177 let namespace_del1: i64 = 45;
3178 let namespace_del2: i64 = 60;
3179 let entry_values = load_attestation_key_pool(
3180 &mut db,
3181 expiration_date,
3182 namespace,
3183 0x01, /* base_byte */
3184 )?;
3185 load_attestation_key_pool(&mut db, 45, namespace_del1, 0x02)?;
3186 load_attestation_key_pool(&mut db, 60, namespace_del2, 0x03)?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003187
3188 let blob_entry_row_count: u32 = db
3189 .conn
3190 .query_row("SELECT COUNT(id) FROM persistent.blobentry;", NO_PARAMS, |row| row.get(0))
3191 .expect("Failed to get blob entry row count.");
3192 // We expect 6 rows here because there are two blobs per attestation key, i.e.,
3193 // One key and one certificate.
3194 assert_eq!(blob_entry_row_count, 6);
3195
Max Bires2b2e6562020-09-22 11:22:36 -07003196 assert_eq!(db.delete_expired_attestation_keys()?, 2);
3197
3198 let mut cert_chain =
3199 db.retrieve_attestation_key_and_cert_chain(Domain::APP, namespace, &KEYSTORE_UUID)?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003200 assert!(cert_chain.is_some());
Max Bires2b2e6562020-09-22 11:22:36 -07003201 let value = cert_chain.unwrap();
3202 assert_eq!(entry_values[1], value.cert_chain.to_vec());
3203 assert_eq!(entry_values[2], value.private_key.to_vec());
3204
3205 cert_chain = db.retrieve_attestation_key_and_cert_chain(
3206 Domain::APP,
3207 namespace_del1,
3208 &KEYSTORE_UUID,
3209 )?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003210 assert!(!cert_chain.is_some());
Max Bires2b2e6562020-09-22 11:22:36 -07003211 cert_chain = db.retrieve_attestation_key_and_cert_chain(
3212 Domain::APP,
3213 namespace_del2,
3214 &KEYSTORE_UUID,
3215 )?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003216 assert!(!cert_chain.is_some());
Max Bires2b2e6562020-09-22 11:22:36 -07003217
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003218 // Give the garbage collector half a second to catch up.
3219 std::thread::sleep(Duration::from_millis(500));
Max Bires2b2e6562020-09-22 11:22:36 -07003220
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003221 let blob_entry_row_count: u32 = db
3222 .conn
3223 .query_row("SELECT COUNT(id) FROM persistent.blobentry;", NO_PARAMS, |row| row.get(0))
3224 .expect("Failed to get blob entry row count.");
3225 // There shound be 2 blob entries left, because we deleted two of the attestation
3226 // key entries with two blobs each.
3227 assert_eq!(blob_entry_row_count, 2);
Max Bires2b2e6562020-09-22 11:22:36 -07003228
Max Bires2b2e6562020-09-22 11:22:36 -07003229 Ok(())
3230 }
3231
3232 #[test]
Joel Galenson33c04ad2020-08-03 11:04:38 -07003233 fn test_rebind_alias() -> Result<()> {
Max Bires8e93d2b2021-01-14 13:17:59 -08003234 fn extractor(
3235 ke: &KeyEntryRow,
3236 ) -> (Option<Domain>, Option<i64>, Option<&str>, Option<Uuid>) {
3237 (ke.domain, ke.namespace, ke.alias.as_deref(), ke.km_uuid)
Joel Galenson33c04ad2020-08-03 11:04:38 -07003238 }
3239
Janis Danisevskis4df44f42020-08-26 14:40:03 -07003240 let mut db = new_test_db()?;
Janis Danisevskis66784c42021-01-27 08:40:25 -08003241 db.create_key_entry(&Domain::APP, &42, &KEYSTORE_UUID)?;
3242 db.create_key_entry(&Domain::APP, &42, &KEYSTORE_UUID)?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07003243 let entries = get_keyentry(&db)?;
3244 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08003245 assert_eq!(
3246 extractor(&entries[0]),
3247 (Some(Domain::APP), Some(42), None, Some(KEYSTORE_UUID))
3248 );
3249 assert_eq!(
3250 extractor(&entries[1]),
3251 (Some(Domain::APP), Some(42), None, Some(KEYSTORE_UUID))
3252 );
Joel Galenson33c04ad2020-08-03 11:04:38 -07003253
3254 // Test that the first call to rebind_alias sets the alias.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003255 rebind_alias(&mut db, &KEY_ID_LOCK.get(entries[0].id), "foo", Domain::APP, 42)?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07003256 let entries = get_keyentry(&db)?;
3257 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08003258 assert_eq!(
3259 extractor(&entries[0]),
3260 (Some(Domain::APP), Some(42), Some("foo"), Some(KEYSTORE_UUID))
3261 );
3262 assert_eq!(
3263 extractor(&entries[1]),
3264 (Some(Domain::APP), Some(42), None, Some(KEYSTORE_UUID))
3265 );
Joel Galenson33c04ad2020-08-03 11:04:38 -07003266
3267 // Test that the second call to rebind_alias also empties the old one.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003268 rebind_alias(&mut db, &KEY_ID_LOCK.get(entries[1].id), "foo", Domain::APP, 42)?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07003269 let entries = get_keyentry(&db)?;
3270 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08003271 assert_eq!(extractor(&entries[0]), (None, None, None, Some(KEYSTORE_UUID)));
3272 assert_eq!(
3273 extractor(&entries[1]),
3274 (Some(Domain::APP), Some(42), Some("foo"), Some(KEYSTORE_UUID))
3275 );
Joel Galenson33c04ad2020-08-03 11:04:38 -07003276
3277 // Test that we must pass in a valid Domain.
3278 check_result_is_error_containing_string(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003279 rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::GRANT, 42),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003280 "Domain Domain(1) must be either App or SELinux.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07003281 );
3282 check_result_is_error_containing_string(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003283 rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::BLOB, 42),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003284 "Domain Domain(3) must be either App or SELinux.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07003285 );
3286 check_result_is_error_containing_string(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003287 rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::KEY_ID, 42),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003288 "Domain Domain(4) must be either App or SELinux.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07003289 );
3290
3291 // Test that we correctly handle setting an alias for something that does not exist.
3292 check_result_is_error_containing_string(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003293 rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::SELINUX, 42),
Joel Galenson33c04ad2020-08-03 11:04:38 -07003294 "Expected to update a single entry but instead updated 0",
3295 );
3296 // Test that we correctly abort the transaction in this case.
3297 let entries = get_keyentry(&db)?;
3298 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08003299 assert_eq!(extractor(&entries[0]), (None, None, None, Some(KEYSTORE_UUID)));
3300 assert_eq!(
3301 extractor(&entries[1]),
3302 (Some(Domain::APP), Some(42), Some("foo"), Some(KEYSTORE_UUID))
3303 );
Joel Galenson33c04ad2020-08-03 11:04:38 -07003304
3305 Ok(())
3306 }
3307
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003308 #[test]
3309 fn test_grant_ungrant() -> Result<()> {
3310 const CALLER_UID: u32 = 15;
3311 const GRANTEE_UID: u32 = 12;
3312 const SELINUX_NAMESPACE: i64 = 7;
3313
3314 let mut db = new_test_db()?;
3315 db.conn.execute(
Max Bires8e93d2b2021-01-14 13:17:59 -08003316 "INSERT INTO persistent.keyentry (id, key_type, domain, namespace, alias, state, km_uuid)
3317 VALUES (1, 0, 0, 15, 'key', 1, ?), (2, 0, 2, 7, 'yek', 1, ?);",
3318 params![KEYSTORE_UUID, KEYSTORE_UUID],
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003319 )?;
3320 let app_key = KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003321 domain: super::Domain::APP,
3322 nspace: 0,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003323 alias: Some("key".to_string()),
3324 blob: None,
3325 };
3326 const PVEC1: KeyPermSet = key_perm_set![KeyPerm::use_(), KeyPerm::get_info()];
3327 const PVEC2: KeyPermSet = key_perm_set![KeyPerm::use_()];
3328
3329 // Reset totally predictable random number generator in case we
3330 // are not the first test running on this thread.
3331 reset_random();
3332 let next_random = 0i64;
3333
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003334 let app_granted_key = db
Janis Danisevskis66784c42021-01-27 08:40:25 -08003335 .grant(&app_key, CALLER_UID, GRANTEE_UID, PVEC1, |k, a| {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003336 assert_eq!(*a, PVEC1);
3337 assert_eq!(
3338 *k,
3339 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003340 domain: super::Domain::APP,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003341 // namespace must be set to the caller_uid.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003342 nspace: CALLER_UID as i64,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003343 alias: Some("key".to_string()),
3344 blob: None,
3345 }
3346 );
3347 Ok(())
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003348 })
3349 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003350
3351 assert_eq!(
3352 app_granted_key,
3353 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003354 domain: super::Domain::GRANT,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003355 // The grantid is next_random due to the mock random number generator.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003356 nspace: next_random,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003357 alias: None,
3358 blob: None,
3359 }
3360 );
3361
3362 let selinux_key = KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003363 domain: super::Domain::SELINUX,
3364 nspace: SELINUX_NAMESPACE,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003365 alias: Some("yek".to_string()),
3366 blob: None,
3367 };
3368
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003369 let selinux_granted_key = db
Janis Danisevskis66784c42021-01-27 08:40:25 -08003370 .grant(&selinux_key, CALLER_UID, 12, PVEC1, |k, a| {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003371 assert_eq!(*a, PVEC1);
3372 assert_eq!(
3373 *k,
3374 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003375 domain: super::Domain::SELINUX,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003376 // namespace must be the supplied SELinux
3377 // namespace.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003378 nspace: SELINUX_NAMESPACE,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003379 alias: Some("yek".to_string()),
3380 blob: None,
3381 }
3382 );
3383 Ok(())
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003384 })
3385 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003386
3387 assert_eq!(
3388 selinux_granted_key,
3389 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003390 domain: super::Domain::GRANT,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003391 // The grantid is next_random + 1 due to the mock random number generator.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003392 nspace: next_random + 1,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003393 alias: None,
3394 blob: None,
3395 }
3396 );
3397
3398 // This should update the existing grant with PVEC2.
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003399 let selinux_granted_key = db
Janis Danisevskis66784c42021-01-27 08:40:25 -08003400 .grant(&selinux_key, CALLER_UID, 12, PVEC2, |k, a| {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003401 assert_eq!(*a, PVEC2);
3402 assert_eq!(
3403 *k,
3404 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003405 domain: super::Domain::SELINUX,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003406 // namespace must be the supplied SELinux
3407 // namespace.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003408 nspace: SELINUX_NAMESPACE,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003409 alias: Some("yek".to_string()),
3410 blob: None,
3411 }
3412 );
3413 Ok(())
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003414 })
3415 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003416
3417 assert_eq!(
3418 selinux_granted_key,
3419 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003420 domain: super::Domain::GRANT,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003421 // Same grant id as before. The entry was only updated.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003422 nspace: next_random + 1,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003423 alias: None,
3424 blob: None,
3425 }
3426 );
3427
3428 {
3429 // Limiting scope of stmt, because it borrows db.
3430 let mut stmt = db
3431 .conn
Janis Danisevskisbf15d732020-12-08 10:35:26 -08003432 .prepare("SELECT id, grantee, keyentryid, access_vector FROM persistent.grant;")?;
Janis Danisevskisee10b5f2020-09-22 16:42:35 -07003433 let mut rows =
3434 stmt.query_map::<(i64, u32, i64, KeyPermSet), _, _>(NO_PARAMS, |row| {
3435 Ok((
3436 row.get(0)?,
3437 row.get(1)?,
3438 row.get(2)?,
3439 KeyPermSet::from(row.get::<_, i32>(3)?),
3440 ))
3441 })?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003442
3443 let r = rows.next().unwrap().unwrap();
Janis Danisevskisee10b5f2020-09-22 16:42:35 -07003444 assert_eq!(r, (next_random, GRANTEE_UID, 1, PVEC1));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003445 let r = rows.next().unwrap().unwrap();
Janis Danisevskisee10b5f2020-09-22 16:42:35 -07003446 assert_eq!(r, (next_random + 1, GRANTEE_UID, 2, PVEC2));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003447 assert!(rows.next().is_none());
3448 }
3449
3450 debug_dump_keyentry_table(&mut db)?;
3451 println!("app_key {:?}", app_key);
3452 println!("selinux_key {:?}", selinux_key);
3453
Janis Danisevskis66784c42021-01-27 08:40:25 -08003454 db.ungrant(&app_key, CALLER_UID, GRANTEE_UID, |_| Ok(()))?;
3455 db.ungrant(&selinux_key, CALLER_UID, GRANTEE_UID, |_| Ok(()))?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003456
3457 Ok(())
3458 }
3459
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003460 static TEST_KEY_BLOB: &[u8] = b"my test blob";
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003461 static TEST_CERT_BLOB: &[u8] = b"my test cert";
3462 static TEST_CERT_CHAIN_BLOB: &[u8] = b"my test cert_chain";
3463
3464 #[test]
Janis Danisevskis377d1002021-01-27 19:07:48 -08003465 fn test_set_blob() -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003466 let key_id = KEY_ID_LOCK.get(3000);
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003467 let mut db = new_test_db()?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003468 let mut blob_metadata = BlobMetaData::new();
3469 blob_metadata.add(BlobMetaEntry::KmUuid(KEYSTORE_UUID));
3470 db.set_blob(
3471 &key_id,
3472 SubComponentType::KEY_BLOB,
3473 Some(TEST_KEY_BLOB),
3474 Some(&blob_metadata),
3475 )?;
3476 db.set_blob(&key_id, SubComponentType::CERT, Some(TEST_CERT_BLOB), None)?;
3477 db.set_blob(&key_id, SubComponentType::CERT_CHAIN, Some(TEST_CERT_CHAIN_BLOB), None)?;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003478 drop(key_id);
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003479
3480 let mut stmt = db.conn.prepare(
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003481 "SELECT subcomponent_type, keyentryid, blob, id FROM persistent.blobentry
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003482 ORDER BY subcomponent_type ASC;",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003483 )?;
3484 let mut rows = stmt
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003485 .query_map::<((SubComponentType, i64, Vec<u8>), i64), _, _>(NO_PARAMS, |row| {
3486 Ok(((row.get(0)?, row.get(1)?, row.get(2)?), row.get(3)?))
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003487 })?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003488 let (r, id) = rows.next().unwrap().unwrap();
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003489 assert_eq!(r, (SubComponentType::KEY_BLOB, 3000, TEST_KEY_BLOB.to_vec()));
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003490 let (r, _) = rows.next().unwrap().unwrap();
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003491 assert_eq!(r, (SubComponentType::CERT, 3000, TEST_CERT_BLOB.to_vec()));
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003492 let (r, _) = rows.next().unwrap().unwrap();
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003493 assert_eq!(r, (SubComponentType::CERT_CHAIN, 3000, TEST_CERT_CHAIN_BLOB.to_vec()));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003494
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003495 drop(rows);
3496 drop(stmt);
3497
3498 assert_eq!(
3499 db.with_transaction(TransactionBehavior::Immediate, |tx| {
3500 BlobMetaData::load_from_db(id, tx).no_gc()
3501 })
3502 .expect("Should find blob metadata."),
3503 blob_metadata
3504 );
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003505 Ok(())
3506 }
3507
3508 static TEST_ALIAS: &str = "my super duper key";
3509
3510 #[test]
3511 fn test_insert_and_load_full_keyentry_domain_app() -> Result<()> {
3512 let mut db = new_test_db()?;
Qi Wub9433b52020-12-01 14:52:46 +08003513 let key_id = make_test_key_entry(&mut db, Domain::APP, 1, TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08003514 .context("test_insert_and_load_full_keyentry_domain_app")?
3515 .0;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003516 let (_key_guard, key_entry) = db
3517 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003518 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003519 domain: Domain::APP,
3520 nspace: 0,
3521 alias: Some(TEST_ALIAS.to_string()),
3522 blob: None,
3523 },
3524 KeyType::Client,
3525 KeyEntryLoadBits::BOTH,
3526 1,
3527 |_k, _av| Ok(()),
3528 )
3529 .unwrap();
Qi Wub9433b52020-12-01 14:52:46 +08003530 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003531
3532 db.unbind_key(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003533 &KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003534 domain: Domain::APP,
3535 nspace: 0,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003536 alias: Some(TEST_ALIAS.to_string()),
3537 blob: None,
3538 },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003539 KeyType::Client,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003540 1,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003541 |_, _| Ok(()),
3542 )
3543 .unwrap();
3544
3545 assert_eq!(
3546 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
3547 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003548 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003549 domain: Domain::APP,
3550 nspace: 0,
3551 alias: Some(TEST_ALIAS.to_string()),
3552 blob: None,
3553 },
3554 KeyType::Client,
3555 KeyEntryLoadBits::NONE,
3556 1,
3557 |_k, _av| Ok(()),
3558 )
3559 .unwrap_err()
3560 .root_cause()
3561 .downcast_ref::<KsError>()
3562 );
3563
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003564 Ok(())
3565 }
3566
3567 #[test]
Janis Danisevskis377d1002021-01-27 19:07:48 -08003568 fn test_insert_and_load_certificate_entry_domain_app() -> Result<()> {
3569 let mut db = new_test_db()?;
3570
3571 db.store_new_certificate(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003572 &KeyDescriptor {
Janis Danisevskis377d1002021-01-27 19:07:48 -08003573 domain: Domain::APP,
3574 nspace: 1,
3575 alias: Some(TEST_ALIAS.to_string()),
3576 blob: None,
3577 },
3578 TEST_CERT_BLOB,
Max Bires8e93d2b2021-01-14 13:17:59 -08003579 &KEYSTORE_UUID,
Janis Danisevskis377d1002021-01-27 19:07:48 -08003580 )
3581 .expect("Trying to insert cert.");
3582
3583 let (_key_guard, mut key_entry) = db
3584 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003585 &KeyDescriptor {
Janis Danisevskis377d1002021-01-27 19:07:48 -08003586 domain: Domain::APP,
3587 nspace: 1,
3588 alias: Some(TEST_ALIAS.to_string()),
3589 blob: None,
3590 },
3591 KeyType::Client,
3592 KeyEntryLoadBits::PUBLIC,
3593 1,
3594 |_k, _av| Ok(()),
3595 )
3596 .expect("Trying to read certificate entry.");
3597
3598 assert!(key_entry.pure_cert());
3599 assert!(key_entry.cert().is_none());
3600 assert_eq!(key_entry.take_cert_chain(), Some(TEST_CERT_BLOB.to_vec()));
3601
3602 db.unbind_key(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003603 &KeyDescriptor {
Janis Danisevskis377d1002021-01-27 19:07:48 -08003604 domain: Domain::APP,
3605 nspace: 1,
3606 alias: Some(TEST_ALIAS.to_string()),
3607 blob: None,
3608 },
3609 KeyType::Client,
3610 1,
3611 |_, _| Ok(()),
3612 )
3613 .unwrap();
3614
3615 assert_eq!(
3616 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
3617 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003618 &KeyDescriptor {
Janis Danisevskis377d1002021-01-27 19:07:48 -08003619 domain: Domain::APP,
3620 nspace: 1,
3621 alias: Some(TEST_ALIAS.to_string()),
3622 blob: None,
3623 },
3624 KeyType::Client,
3625 KeyEntryLoadBits::NONE,
3626 1,
3627 |_k, _av| Ok(()),
3628 )
3629 .unwrap_err()
3630 .root_cause()
3631 .downcast_ref::<KsError>()
3632 );
3633
3634 Ok(())
3635 }
3636
3637 #[test]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003638 fn test_insert_and_load_full_keyentry_domain_selinux() -> Result<()> {
3639 let mut db = new_test_db()?;
Qi Wub9433b52020-12-01 14:52:46 +08003640 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08003641 .context("test_insert_and_load_full_keyentry_domain_selinux")?
3642 .0;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003643 let (_key_guard, key_entry) = db
3644 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003645 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003646 domain: Domain::SELINUX,
3647 nspace: 1,
3648 alias: Some(TEST_ALIAS.to_string()),
3649 blob: None,
3650 },
3651 KeyType::Client,
3652 KeyEntryLoadBits::BOTH,
3653 1,
3654 |_k, _av| Ok(()),
3655 )
3656 .unwrap();
Qi Wub9433b52020-12-01 14:52:46 +08003657 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003658
3659 db.unbind_key(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003660 &KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003661 domain: Domain::SELINUX,
3662 nspace: 1,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003663 alias: Some(TEST_ALIAS.to_string()),
3664 blob: None,
3665 },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003666 KeyType::Client,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003667 1,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003668 |_, _| Ok(()),
3669 )
3670 .unwrap();
3671
3672 assert_eq!(
3673 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
3674 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003675 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003676 domain: Domain::SELINUX,
3677 nspace: 1,
3678 alias: Some(TEST_ALIAS.to_string()),
3679 blob: None,
3680 },
3681 KeyType::Client,
3682 KeyEntryLoadBits::NONE,
3683 1,
3684 |_k, _av| Ok(()),
3685 )
3686 .unwrap_err()
3687 .root_cause()
3688 .downcast_ref::<KsError>()
3689 );
3690
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003691 Ok(())
3692 }
3693
3694 #[test]
3695 fn test_insert_and_load_full_keyentry_domain_key_id() -> Result<()> {
3696 let mut db = new_test_db()?;
Qi Wub9433b52020-12-01 14:52:46 +08003697 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08003698 .context("test_insert_and_load_full_keyentry_domain_key_id")?
3699 .0;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003700 let (_, key_entry) = db
3701 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003702 &KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003703 KeyType::Client,
3704 KeyEntryLoadBits::BOTH,
3705 1,
3706 |_k, _av| Ok(()),
3707 )
3708 .unwrap();
3709
Qi Wub9433b52020-12-01 14:52:46 +08003710 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003711
3712 db.unbind_key(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003713 &KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003714 KeyType::Client,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003715 1,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003716 |_, _| Ok(()),
3717 )
3718 .unwrap();
3719
3720 assert_eq!(
3721 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
3722 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003723 &KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003724 KeyType::Client,
3725 KeyEntryLoadBits::NONE,
3726 1,
3727 |_k, _av| Ok(()),
3728 )
3729 .unwrap_err()
3730 .root_cause()
3731 .downcast_ref::<KsError>()
3732 );
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003733
3734 Ok(())
3735 }
3736
3737 #[test]
Qi Wub9433b52020-12-01 14:52:46 +08003738 fn test_check_and_update_key_usage_count_with_limited_use_key() -> Result<()> {
3739 let mut db = new_test_db()?;
3740 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, Some(123))
3741 .context("test_check_and_update_key_usage_count_with_limited_use_key")?
3742 .0;
3743 // Update the usage count of the limited use key.
3744 db.check_and_update_key_usage_count(key_id)?;
3745
3746 let (_key_guard, key_entry) = db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003747 &KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
Qi Wub9433b52020-12-01 14:52:46 +08003748 KeyType::Client,
3749 KeyEntryLoadBits::BOTH,
3750 1,
3751 |_k, _av| Ok(()),
3752 )?;
3753
3754 // The usage count is decremented now.
3755 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, Some(122)));
3756
3757 Ok(())
3758 }
3759
3760 #[test]
3761 fn test_check_and_update_key_usage_count_with_exhausted_limited_use_key() -> Result<()> {
3762 let mut db = new_test_db()?;
3763 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, Some(1))
3764 .context("test_check_and_update_key_usage_count_with_exhausted_limited_use_key")?
3765 .0;
3766 // Update the usage count of the limited use key.
3767 db.check_and_update_key_usage_count(key_id).expect(concat!(
3768 "In test_check_and_update_key_usage_count_with_exhausted_limited_use_key: ",
3769 "This should succeed."
3770 ));
3771
3772 // Try to update the exhausted limited use key.
3773 let e = db.check_and_update_key_usage_count(key_id).expect_err(concat!(
3774 "In test_check_and_update_key_usage_count_with_exhausted_limited_use_key: ",
3775 "This should fail."
3776 ));
3777 assert_eq!(
3778 &KsError::Km(ErrorCode::INVALID_KEY_BLOB),
3779 e.root_cause().downcast_ref::<KsError>().unwrap()
3780 );
3781
3782 Ok(())
3783 }
3784
3785 #[test]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003786 fn test_insert_and_load_full_keyentry_from_grant() -> Result<()> {
3787 let mut db = new_test_db()?;
Qi Wub9433b52020-12-01 14:52:46 +08003788 let key_id = make_test_key_entry(&mut db, Domain::APP, 1, TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08003789 .context("test_insert_and_load_full_keyentry_from_grant")?
3790 .0;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003791
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003792 let granted_key = db
3793 .grant(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003794 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003795 domain: Domain::APP,
3796 nspace: 0,
3797 alias: Some(TEST_ALIAS.to_string()),
3798 blob: None,
3799 },
3800 1,
3801 2,
3802 key_perm_set![KeyPerm::use_()],
3803 |_k, _av| Ok(()),
3804 )
3805 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003806
3807 debug_dump_grant_table(&mut db)?;
3808
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003809 let (_key_guard, key_entry) = db
Janis Danisevskis66784c42021-01-27 08:40:25 -08003810 .load_key_entry(&granted_key, KeyType::Client, KeyEntryLoadBits::BOTH, 2, |k, av| {
3811 assert_eq!(Domain::GRANT, k.domain);
3812 assert!(av.unwrap().includes(KeyPerm::use_()));
3813 Ok(())
3814 })
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003815 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003816
Qi Wub9433b52020-12-01 14:52:46 +08003817 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003818
Janis Danisevskis66784c42021-01-27 08:40:25 -08003819 db.unbind_key(&granted_key, KeyType::Client, 2, |_, _| Ok(())).unwrap();
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003820
3821 assert_eq!(
3822 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
3823 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003824 &granted_key,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003825 KeyType::Client,
3826 KeyEntryLoadBits::NONE,
3827 2,
3828 |_k, _av| Ok(()),
3829 )
3830 .unwrap_err()
3831 .root_cause()
3832 .downcast_ref::<KsError>()
3833 );
3834
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003835 Ok(())
3836 }
3837
Janis Danisevskis45760022021-01-19 16:34:10 -08003838 // This test attempts to load a key by key id while the caller is not the owner
3839 // but a grant exists for the given key and the caller.
3840 #[test]
3841 fn test_insert_and_load_full_keyentry_from_grant_by_key_id() -> Result<()> {
3842 let mut db = new_test_db()?;
3843 const OWNER_UID: u32 = 1u32;
3844 const GRANTEE_UID: u32 = 2u32;
3845 const SOMEONE_ELSE_UID: u32 = 3u32;
3846 let key_id = make_test_key_entry(&mut db, Domain::APP, OWNER_UID as i64, TEST_ALIAS, None)
3847 .context("test_insert_and_load_full_keyentry_from_grant_by_key_id")?
3848 .0;
3849
3850 db.grant(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003851 &KeyDescriptor {
Janis Danisevskis45760022021-01-19 16:34:10 -08003852 domain: Domain::APP,
3853 nspace: 0,
3854 alias: Some(TEST_ALIAS.to_string()),
3855 blob: None,
3856 },
3857 OWNER_UID,
3858 GRANTEE_UID,
3859 key_perm_set![KeyPerm::use_()],
3860 |_k, _av| Ok(()),
3861 )
3862 .unwrap();
3863
3864 debug_dump_grant_table(&mut db)?;
3865
3866 let id_descriptor =
3867 KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, ..Default::default() };
3868
3869 let (_, key_entry) = db
3870 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003871 &id_descriptor,
Janis Danisevskis45760022021-01-19 16:34:10 -08003872 KeyType::Client,
3873 KeyEntryLoadBits::BOTH,
3874 GRANTEE_UID,
3875 |k, av| {
3876 assert_eq!(Domain::APP, k.domain);
3877 assert_eq!(OWNER_UID as i64, k.nspace);
3878 assert!(av.unwrap().includes(KeyPerm::use_()));
3879 Ok(())
3880 },
3881 )
3882 .unwrap();
3883
3884 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
3885
3886 let (_, key_entry) = db
3887 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003888 &id_descriptor,
Janis Danisevskis45760022021-01-19 16:34:10 -08003889 KeyType::Client,
3890 KeyEntryLoadBits::BOTH,
3891 SOMEONE_ELSE_UID,
3892 |k, av| {
3893 assert_eq!(Domain::APP, k.domain);
3894 assert_eq!(OWNER_UID as i64, k.nspace);
3895 assert!(av.is_none());
3896 Ok(())
3897 },
3898 )
3899 .unwrap();
3900
3901 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
3902
Janis Danisevskis66784c42021-01-27 08:40:25 -08003903 db.unbind_key(&id_descriptor, KeyType::Client, OWNER_UID, |_, _| Ok(())).unwrap();
Janis Danisevskis45760022021-01-19 16:34:10 -08003904
3905 assert_eq!(
3906 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
3907 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003908 &id_descriptor,
Janis Danisevskis45760022021-01-19 16:34:10 -08003909 KeyType::Client,
3910 KeyEntryLoadBits::NONE,
3911 GRANTEE_UID,
3912 |_k, _av| Ok(()),
3913 )
3914 .unwrap_err()
3915 .root_cause()
3916 .downcast_ref::<KsError>()
3917 );
3918
3919 Ok(())
3920 }
3921
Janis Danisevskisaec14592020-11-12 09:41:49 -08003922 static KEY_LOCK_TEST_ALIAS: &str = "my super duper locked key";
3923
Janis Danisevskisaec14592020-11-12 09:41:49 -08003924 #[test]
3925 fn test_insert_and_load_full_keyentry_domain_app_concurrently() -> Result<()> {
3926 let handle = {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08003927 let temp_dir = Arc::new(TempDir::new("id_lock_test")?);
3928 let temp_dir_clone = temp_dir.clone();
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003929 let mut db = KeystoreDB::new(temp_dir.path(), None)?;
Qi Wub9433b52020-12-01 14:52:46 +08003930 let key_id = make_test_key_entry(&mut db, Domain::APP, 33, KEY_LOCK_TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08003931 .context("test_insert_and_load_full_keyentry_domain_app")?
3932 .0;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003933 let (_key_guard, key_entry) = db
3934 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003935 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003936 domain: Domain::APP,
3937 nspace: 0,
3938 alias: Some(KEY_LOCK_TEST_ALIAS.to_string()),
3939 blob: None,
3940 },
3941 KeyType::Client,
3942 KeyEntryLoadBits::BOTH,
3943 33,
3944 |_k, _av| Ok(()),
3945 )
3946 .unwrap();
Qi Wub9433b52020-12-01 14:52:46 +08003947 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskisaec14592020-11-12 09:41:49 -08003948 let state = Arc::new(AtomicU8::new(1));
3949 let state2 = state.clone();
3950
3951 // Spawning a second thread that attempts to acquire the key id lock
3952 // for the same key as the primary thread. The primary thread then
3953 // waits, thereby forcing the secondary thread into the second stage
3954 // of acquiring the lock (see KEY ID LOCK 2/2 above).
3955 // The test succeeds if the secondary thread observes the transition
3956 // of `state` from 1 to 2, despite having a whole second to overtake
3957 // the primary thread.
3958 let handle = thread::spawn(move || {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08003959 let temp_dir = temp_dir_clone;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003960 let mut db = KeystoreDB::new(temp_dir.path(), None).unwrap();
Janis Danisevskisaec14592020-11-12 09:41:49 -08003961 assert!(db
3962 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003963 &KeyDescriptor {
Janis Danisevskisaec14592020-11-12 09:41:49 -08003964 domain: Domain::APP,
3965 nspace: 0,
3966 alias: Some(KEY_LOCK_TEST_ALIAS.to_string()),
3967 blob: None,
3968 },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003969 KeyType::Client,
Janis Danisevskisaec14592020-11-12 09:41:49 -08003970 KeyEntryLoadBits::BOTH,
3971 33,
3972 |_k, _av| Ok(()),
3973 )
3974 .is_ok());
3975 // We should only see a 2 here because we can only return
3976 // from load_key_entry when the `_key_guard` expires,
3977 // which happens at the end of the scope.
3978 assert_eq!(2, state2.load(Ordering::Relaxed));
3979 });
3980
3981 thread::sleep(std::time::Duration::from_millis(1000));
3982
3983 assert_eq!(Ok(1), state.compare_exchange(1, 2, Ordering::Relaxed, Ordering::Relaxed));
3984
3985 // Return the handle from this scope so we can join with the
3986 // secondary thread after the key id lock has expired.
3987 handle
3988 // This is where the `_key_guard` goes out of scope,
3989 // which is the reason for concurrent load_key_entry on the same key
3990 // to unblock.
3991 };
3992 // Join with the secondary thread and unwrap, to propagate failing asserts to the
3993 // main test thread. We will not see failing asserts in secondary threads otherwise.
3994 handle.join().unwrap();
3995 Ok(())
3996 }
3997
Janis Danisevskise92a5e62020-12-02 12:57:41 -08003998 #[test]
Janis Danisevskis66784c42021-01-27 08:40:25 -08003999 fn teset_database_busy_error_code() {
4000 let temp_dir =
4001 TempDir::new("test_database_busy_error_code_").expect("Failed to create temp dir.");
4002
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004003 let mut db1 = KeystoreDB::new(temp_dir.path(), None).expect("Failed to open database1.");
4004 let mut db2 = KeystoreDB::new(temp_dir.path(), None).expect("Failed to open database2.");
Janis Danisevskis66784c42021-01-27 08:40:25 -08004005
4006 let _tx1 = db1
4007 .conn
4008 .transaction_with_behavior(TransactionBehavior::Immediate)
4009 .expect("Failed to create first transaction.");
4010
4011 let error = db2
4012 .conn
4013 .transaction_with_behavior(TransactionBehavior::Immediate)
4014 .context("Transaction begin failed.")
4015 .expect_err("This should fail.");
4016 let root_cause = error.root_cause();
4017 if let Some(rusqlite::ffi::Error { code: rusqlite::ErrorCode::DatabaseBusy, .. }) =
4018 root_cause.downcast_ref::<rusqlite::ffi::Error>()
4019 {
4020 return;
4021 }
4022 panic!(
4023 "Unexpected error {:?} \n{:?} \n{:?}",
4024 error,
4025 root_cause,
4026 root_cause.downcast_ref::<rusqlite::ffi::Error>()
4027 )
4028 }
4029
4030 #[cfg(disabled)]
4031 #[test]
4032 fn test_large_number_of_concurrent_db_manipulations() -> Result<()> {
4033 let temp_dir = Arc::new(
4034 TempDir::new("test_large_number_of_concurrent_db_manipulations_")
4035 .expect("Failed to create temp dir."),
4036 );
4037
4038 let test_begin = Instant::now();
4039
4040 let mut db = KeystoreDB::new(temp_dir.path()).expect("Failed to open database.");
4041 const KEY_COUNT: u32 = 500u32;
4042 const OPEN_DB_COUNT: u32 = 50u32;
4043
4044 let mut actual_key_count = KEY_COUNT;
4045 // First insert KEY_COUNT keys.
4046 for count in 0..KEY_COUNT {
4047 if Instant::now().duration_since(test_begin) >= Duration::from_secs(15) {
4048 actual_key_count = count;
4049 break;
4050 }
4051 let alias = format!("test_alias_{}", count);
4052 make_test_key_entry(&mut db, Domain::APP, 1, &alias, None)
4053 .expect("Failed to make key entry.");
4054 }
4055
4056 // Insert more keys from a different thread and into a different namespace.
4057 let temp_dir1 = temp_dir.clone();
4058 let handle1 = thread::spawn(move || {
4059 let mut db = KeystoreDB::new(temp_dir1.path()).expect("Failed to open database.");
4060
4061 for count in 0..actual_key_count {
4062 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
4063 return;
4064 }
4065 let alias = format!("test_alias_{}", count);
4066 make_test_key_entry(&mut db, Domain::APP, 2, &alias, None)
4067 .expect("Failed to make key entry.");
4068 }
4069
4070 // then unbind them again.
4071 for count in 0..actual_key_count {
4072 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
4073 return;
4074 }
4075 let key = KeyDescriptor {
4076 domain: Domain::APP,
4077 nspace: -1,
4078 alias: Some(format!("test_alias_{}", count)),
4079 blob: None,
4080 };
4081 db.unbind_key(&key, KeyType::Client, 2, |_, _| Ok(())).expect("Unbind Failed.");
4082 }
4083 });
4084
4085 // And start unbinding the first set of keys.
4086 let temp_dir2 = temp_dir.clone();
4087 let handle2 = thread::spawn(move || {
4088 let mut db = KeystoreDB::new(temp_dir2.path()).expect("Failed to open database.");
4089
4090 for count in 0..actual_key_count {
4091 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
4092 return;
4093 }
4094 let key = KeyDescriptor {
4095 domain: Domain::APP,
4096 nspace: -1,
4097 alias: Some(format!("test_alias_{}", count)),
4098 blob: None,
4099 };
4100 db.unbind_key(&key, KeyType::Client, 1, |_, _| Ok(())).expect("Unbind Failed.");
4101 }
4102 });
4103
4104 let stop_deleting = Arc::new(AtomicU8::new(0));
4105 let stop_deleting2 = stop_deleting.clone();
4106
4107 // And delete anything that is unreferenced keys.
4108 let temp_dir3 = temp_dir.clone();
4109 let handle3 = thread::spawn(move || {
4110 let mut db = KeystoreDB::new(temp_dir3.path()).expect("Failed to open database.");
4111
4112 while stop_deleting2.load(Ordering::Relaxed) != 1 {
4113 while let Some((key_guard, _key)) =
4114 db.get_unreferenced_key().expect("Failed to get unreferenced Key.")
4115 {
4116 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
4117 return;
4118 }
4119 db.purge_key_entry(key_guard).expect("Failed to purge key.");
4120 }
4121 std::thread::sleep(std::time::Duration::from_millis(100));
4122 }
4123 });
4124
4125 // While a lot of inserting and deleting is going on we have to open database connections
4126 // successfully and use them.
4127 // This clone is not redundant, because temp_dir needs to be kept alive until db goes
4128 // out of scope.
4129 #[allow(clippy::redundant_clone)]
4130 let temp_dir4 = temp_dir.clone();
4131 let handle4 = thread::spawn(move || {
4132 for count in 0..OPEN_DB_COUNT {
4133 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
4134 return;
4135 }
4136 let mut db = KeystoreDB::new(temp_dir4.path()).expect("Failed to open database.");
4137
4138 let alias = format!("test_alias_{}", count);
4139 make_test_key_entry(&mut db, Domain::APP, 3, &alias, None)
4140 .expect("Failed to make key entry.");
4141 let key = KeyDescriptor {
4142 domain: Domain::APP,
4143 nspace: -1,
4144 alias: Some(alias),
4145 blob: None,
4146 };
4147 db.unbind_key(&key, KeyType::Client, 3, |_, _| Ok(())).expect("Unbind Failed.");
4148 }
4149 });
4150
4151 handle1.join().expect("Thread 1 panicked.");
4152 handle2.join().expect("Thread 2 panicked.");
4153 handle4.join().expect("Thread 4 panicked.");
4154
4155 stop_deleting.store(1, Ordering::Relaxed);
4156 handle3.join().expect("Thread 3 panicked.");
4157
4158 Ok(())
4159 }
4160
4161 #[test]
Janis Danisevskise92a5e62020-12-02 12:57:41 -08004162 fn list() -> Result<()> {
4163 let temp_dir = TempDir::new("list_test")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004164 let mut db = KeystoreDB::new(temp_dir.path(), None)?;
Janis Danisevskise92a5e62020-12-02 12:57:41 -08004165 static LIST_O_ENTRIES: &[(Domain, i64, &str)] = &[
4166 (Domain::APP, 1, "test1"),
4167 (Domain::APP, 1, "test2"),
4168 (Domain::APP, 1, "test3"),
4169 (Domain::APP, 1, "test4"),
4170 (Domain::APP, 1, "test5"),
4171 (Domain::APP, 1, "test6"),
4172 (Domain::APP, 1, "test7"),
4173 (Domain::APP, 2, "test1"),
4174 (Domain::APP, 2, "test2"),
4175 (Domain::APP, 2, "test3"),
4176 (Domain::APP, 2, "test4"),
4177 (Domain::APP, 2, "test5"),
4178 (Domain::APP, 2, "test6"),
4179 (Domain::APP, 2, "test8"),
4180 (Domain::SELINUX, 100, "test1"),
4181 (Domain::SELINUX, 100, "test2"),
4182 (Domain::SELINUX, 100, "test3"),
4183 (Domain::SELINUX, 100, "test4"),
4184 (Domain::SELINUX, 100, "test5"),
4185 (Domain::SELINUX, 100, "test6"),
4186 (Domain::SELINUX, 100, "test9"),
4187 ];
4188
4189 let list_o_keys: Vec<(i64, i64)> = LIST_O_ENTRIES
4190 .iter()
4191 .map(|(domain, ns, alias)| {
Qi Wub9433b52020-12-01 14:52:46 +08004192 let entry = make_test_key_entry(&mut db, *domain, *ns, *alias, None)
4193 .unwrap_or_else(|e| {
Janis Danisevskise92a5e62020-12-02 12:57:41 -08004194 panic!("Failed to insert {:?} {} {}. Error {:?}", domain, ns, alias, e)
4195 });
4196 (entry.id(), *ns)
4197 })
4198 .collect();
4199
4200 for (domain, namespace) in
4201 &[(Domain::APP, 1i64), (Domain::APP, 2i64), (Domain::SELINUX, 100i64)]
4202 {
4203 let mut list_o_descriptors: Vec<KeyDescriptor> = LIST_O_ENTRIES
4204 .iter()
4205 .filter_map(|(domain, ns, alias)| match ns {
4206 ns if *ns == *namespace => Some(KeyDescriptor {
4207 domain: *domain,
4208 nspace: *ns,
4209 alias: Some(alias.to_string()),
4210 blob: None,
4211 }),
4212 _ => None,
4213 })
4214 .collect();
4215 list_o_descriptors.sort();
4216 let mut list_result = db.list(*domain, *namespace)?;
4217 list_result.sort();
4218 assert_eq!(list_o_descriptors, list_result);
4219
4220 let mut list_o_ids: Vec<i64> = list_o_descriptors
4221 .into_iter()
4222 .map(|d| {
4223 let (_, entry) = db
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004224 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004225 &d,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004226 KeyType::Client,
4227 KeyEntryLoadBits::NONE,
4228 *namespace as u32,
4229 |_, _| Ok(()),
4230 )
Janis Danisevskise92a5e62020-12-02 12:57:41 -08004231 .unwrap();
4232 entry.id()
4233 })
4234 .collect();
4235 list_o_ids.sort_unstable();
4236 let mut loaded_entries: Vec<i64> = list_o_keys
4237 .iter()
4238 .filter_map(|(id, ns)| match ns {
4239 ns if *ns == *namespace => Some(*id),
4240 _ => None,
4241 })
4242 .collect();
4243 loaded_entries.sort_unstable();
4244 assert_eq!(list_o_ids, loaded_entries);
4245 }
4246 assert_eq!(Vec::<KeyDescriptor>::new(), db.list(Domain::SELINUX, 101)?);
4247
4248 Ok(())
4249 }
4250
Joel Galenson0891bc12020-07-20 10:37:03 -07004251 // Helpers
4252
4253 // Checks that the given result is an error containing the given string.
4254 fn check_result_is_error_containing_string<T>(result: Result<T>, target: &str) {
4255 let error_str = format!(
4256 "{:#?}",
4257 result.err().unwrap_or_else(|| panic!("Expected the error: {}", target))
4258 );
4259 assert!(
4260 error_str.contains(target),
4261 "The string \"{}\" should contain \"{}\"",
4262 error_str,
4263 target
4264 );
4265 }
4266
Joel Galenson2aab4432020-07-22 15:27:57 -07004267 #[derive(Debug, PartialEq)]
Joel Galenson0891bc12020-07-20 10:37:03 -07004268 #[allow(dead_code)]
4269 struct KeyEntryRow {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004270 id: i64,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004271 key_type: KeyType,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07004272 domain: Option<Domain>,
Joel Galenson0891bc12020-07-20 10:37:03 -07004273 namespace: Option<i64>,
4274 alias: Option<String>,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004275 state: KeyLifeCycle,
Max Bires8e93d2b2021-01-14 13:17:59 -08004276 km_uuid: Option<Uuid>,
Joel Galenson0891bc12020-07-20 10:37:03 -07004277 }
4278
4279 fn get_keyentry(db: &KeystoreDB) -> Result<Vec<KeyEntryRow>> {
4280 db.conn
Joel Galenson2aab4432020-07-22 15:27:57 -07004281 .prepare("SELECT * FROM persistent.keyentry;")?
Joel Galenson0891bc12020-07-20 10:37:03 -07004282 .query_map(NO_PARAMS, |row| {
Joel Galenson0891bc12020-07-20 10:37:03 -07004283 Ok(KeyEntryRow {
4284 id: row.get(0)?,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004285 key_type: row.get(1)?,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07004286 domain: match row.get(2)? {
4287 Some(i) => Some(Domain(i)),
4288 None => None,
4289 },
Joel Galenson0891bc12020-07-20 10:37:03 -07004290 namespace: row.get(3)?,
4291 alias: row.get(4)?,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004292 state: row.get(5)?,
Max Bires8e93d2b2021-01-14 13:17:59 -08004293 km_uuid: row.get(6)?,
Joel Galenson0891bc12020-07-20 10:37:03 -07004294 })
4295 })?
4296 .map(|r| r.context("Could not read keyentry row."))
4297 .collect::<Result<Vec<_>>>()
4298 }
4299
Max Bires2b2e6562020-09-22 11:22:36 -07004300 fn load_attestation_key_pool(
4301 db: &mut KeystoreDB,
4302 expiration_date: i64,
4303 namespace: i64,
4304 base_byte: u8,
4305 ) -> Result<Vec<Vec<u8>>> {
4306 let mut chain: Vec<Vec<u8>> = Vec::new();
4307 let public_key: Vec<u8> = vec![base_byte, 0x02 * base_byte];
4308 let cert_chain: Vec<u8> = vec![0x03 * base_byte, 0x04 * base_byte];
4309 let priv_key: Vec<u8> = vec![0x05 * base_byte, 0x06 * base_byte];
4310 let raw_public_key: Vec<u8> = vec![0x0b * base_byte, 0x0c * base_byte];
4311 db.create_attestation_key_entry(&public_key, &raw_public_key, &priv_key, &KEYSTORE_UUID)?;
4312 db.store_signed_attestation_certificate_chain(
4313 &raw_public_key,
4314 &cert_chain,
4315 expiration_date,
4316 &KEYSTORE_UUID,
4317 )?;
4318 db.assign_attestation_key(Domain::APP, namespace, &KEYSTORE_UUID)?;
4319 chain.push(public_key);
4320 chain.push(cert_chain);
4321 chain.push(priv_key);
4322 chain.push(raw_public_key);
4323 Ok(chain)
4324 }
4325
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07004326 // Note: The parameters and SecurityLevel associations are nonsensical. This
4327 // collection is only used to check if the parameters are preserved as expected by the
4328 // database.
Qi Wub9433b52020-12-01 14:52:46 +08004329 fn make_test_params(max_usage_count: Option<i32>) -> Vec<KeyParameter> {
4330 let mut params = vec![
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07004331 KeyParameter::new(KeyParameterValue::Invalid, SecurityLevel::TRUSTED_ENVIRONMENT),
4332 KeyParameter::new(
4333 KeyParameterValue::KeyPurpose(KeyPurpose::SIGN),
4334 SecurityLevel::TRUSTED_ENVIRONMENT,
4335 ),
4336 KeyParameter::new(
4337 KeyParameterValue::KeyPurpose(KeyPurpose::DECRYPT),
4338 SecurityLevel::TRUSTED_ENVIRONMENT,
4339 ),
4340 KeyParameter::new(
4341 KeyParameterValue::Algorithm(Algorithm::RSA),
4342 SecurityLevel::TRUSTED_ENVIRONMENT,
4343 ),
4344 KeyParameter::new(KeyParameterValue::KeySize(1024), SecurityLevel::TRUSTED_ENVIRONMENT),
4345 KeyParameter::new(
4346 KeyParameterValue::BlockMode(BlockMode::ECB),
4347 SecurityLevel::TRUSTED_ENVIRONMENT,
4348 ),
4349 KeyParameter::new(
4350 KeyParameterValue::BlockMode(BlockMode::GCM),
4351 SecurityLevel::TRUSTED_ENVIRONMENT,
4352 ),
4353 KeyParameter::new(KeyParameterValue::Digest(Digest::NONE), SecurityLevel::STRONGBOX),
4354 KeyParameter::new(
4355 KeyParameterValue::Digest(Digest::MD5),
4356 SecurityLevel::TRUSTED_ENVIRONMENT,
4357 ),
4358 KeyParameter::new(
4359 KeyParameterValue::Digest(Digest::SHA_2_224),
4360 SecurityLevel::TRUSTED_ENVIRONMENT,
4361 ),
4362 KeyParameter::new(
4363 KeyParameterValue::Digest(Digest::SHA_2_256),
4364 SecurityLevel::STRONGBOX,
4365 ),
4366 KeyParameter::new(
4367 KeyParameterValue::PaddingMode(PaddingMode::NONE),
4368 SecurityLevel::TRUSTED_ENVIRONMENT,
4369 ),
4370 KeyParameter::new(
4371 KeyParameterValue::PaddingMode(PaddingMode::RSA_OAEP),
4372 SecurityLevel::TRUSTED_ENVIRONMENT,
4373 ),
4374 KeyParameter::new(
4375 KeyParameterValue::PaddingMode(PaddingMode::RSA_PSS),
4376 SecurityLevel::STRONGBOX,
4377 ),
4378 KeyParameter::new(
4379 KeyParameterValue::PaddingMode(PaddingMode::RSA_PKCS1_1_5_SIGN),
4380 SecurityLevel::TRUSTED_ENVIRONMENT,
4381 ),
4382 KeyParameter::new(KeyParameterValue::CallerNonce, SecurityLevel::TRUSTED_ENVIRONMENT),
4383 KeyParameter::new(KeyParameterValue::MinMacLength(256), SecurityLevel::STRONGBOX),
4384 KeyParameter::new(
4385 KeyParameterValue::EcCurve(EcCurve::P_224),
4386 SecurityLevel::TRUSTED_ENVIRONMENT,
4387 ),
4388 KeyParameter::new(KeyParameterValue::EcCurve(EcCurve::P_256), SecurityLevel::STRONGBOX),
4389 KeyParameter::new(
4390 KeyParameterValue::EcCurve(EcCurve::P_384),
4391 SecurityLevel::TRUSTED_ENVIRONMENT,
4392 ),
4393 KeyParameter::new(
4394 KeyParameterValue::EcCurve(EcCurve::P_521),
4395 SecurityLevel::TRUSTED_ENVIRONMENT,
4396 ),
4397 KeyParameter::new(
4398 KeyParameterValue::RSAPublicExponent(3),
4399 SecurityLevel::TRUSTED_ENVIRONMENT,
4400 ),
4401 KeyParameter::new(
4402 KeyParameterValue::IncludeUniqueID,
4403 SecurityLevel::TRUSTED_ENVIRONMENT,
4404 ),
4405 KeyParameter::new(KeyParameterValue::BootLoaderOnly, SecurityLevel::STRONGBOX),
4406 KeyParameter::new(KeyParameterValue::RollbackResistance, SecurityLevel::STRONGBOX),
4407 KeyParameter::new(
4408 KeyParameterValue::ActiveDateTime(1234567890),
4409 SecurityLevel::STRONGBOX,
4410 ),
4411 KeyParameter::new(
4412 KeyParameterValue::OriginationExpireDateTime(1234567890),
4413 SecurityLevel::TRUSTED_ENVIRONMENT,
4414 ),
4415 KeyParameter::new(
4416 KeyParameterValue::UsageExpireDateTime(1234567890),
4417 SecurityLevel::TRUSTED_ENVIRONMENT,
4418 ),
4419 KeyParameter::new(
4420 KeyParameterValue::MinSecondsBetweenOps(1234567890),
4421 SecurityLevel::TRUSTED_ENVIRONMENT,
4422 ),
4423 KeyParameter::new(
4424 KeyParameterValue::MaxUsesPerBoot(1234567890),
4425 SecurityLevel::TRUSTED_ENVIRONMENT,
4426 ),
4427 KeyParameter::new(KeyParameterValue::UserID(1), SecurityLevel::STRONGBOX),
4428 KeyParameter::new(KeyParameterValue::UserSecureID(42), SecurityLevel::STRONGBOX),
4429 KeyParameter::new(
4430 KeyParameterValue::NoAuthRequired,
4431 SecurityLevel::TRUSTED_ENVIRONMENT,
4432 ),
4433 KeyParameter::new(
4434 KeyParameterValue::HardwareAuthenticatorType(HardwareAuthenticatorType::PASSWORD),
4435 SecurityLevel::TRUSTED_ENVIRONMENT,
4436 ),
4437 KeyParameter::new(KeyParameterValue::AuthTimeout(1234567890), SecurityLevel::SOFTWARE),
4438 KeyParameter::new(KeyParameterValue::AllowWhileOnBody, SecurityLevel::SOFTWARE),
4439 KeyParameter::new(
4440 KeyParameterValue::TrustedUserPresenceRequired,
4441 SecurityLevel::TRUSTED_ENVIRONMENT,
4442 ),
4443 KeyParameter::new(
4444 KeyParameterValue::TrustedConfirmationRequired,
4445 SecurityLevel::TRUSTED_ENVIRONMENT,
4446 ),
4447 KeyParameter::new(
4448 KeyParameterValue::UnlockedDeviceRequired,
4449 SecurityLevel::TRUSTED_ENVIRONMENT,
4450 ),
4451 KeyParameter::new(
4452 KeyParameterValue::ApplicationID(vec![1u8, 2u8, 3u8, 4u8]),
4453 SecurityLevel::SOFTWARE,
4454 ),
4455 KeyParameter::new(
4456 KeyParameterValue::ApplicationData(vec![4u8, 3u8, 2u8, 1u8]),
4457 SecurityLevel::SOFTWARE,
4458 ),
4459 KeyParameter::new(
4460 KeyParameterValue::CreationDateTime(12345677890),
4461 SecurityLevel::SOFTWARE,
4462 ),
4463 KeyParameter::new(
4464 KeyParameterValue::KeyOrigin(KeyOrigin::GENERATED),
4465 SecurityLevel::TRUSTED_ENVIRONMENT,
4466 ),
4467 KeyParameter::new(
4468 KeyParameterValue::RootOfTrust(vec![3u8, 2u8, 1u8, 4u8]),
4469 SecurityLevel::TRUSTED_ENVIRONMENT,
4470 ),
4471 KeyParameter::new(KeyParameterValue::OSVersion(1), SecurityLevel::TRUSTED_ENVIRONMENT),
4472 KeyParameter::new(KeyParameterValue::OSPatchLevel(2), SecurityLevel::SOFTWARE),
4473 KeyParameter::new(
4474 KeyParameterValue::UniqueID(vec![4u8, 3u8, 1u8, 2u8]),
4475 SecurityLevel::SOFTWARE,
4476 ),
4477 KeyParameter::new(
4478 KeyParameterValue::AttestationChallenge(vec![4u8, 3u8, 1u8, 2u8]),
4479 SecurityLevel::TRUSTED_ENVIRONMENT,
4480 ),
4481 KeyParameter::new(
4482 KeyParameterValue::AttestationApplicationID(vec![4u8, 3u8, 1u8, 2u8]),
4483 SecurityLevel::TRUSTED_ENVIRONMENT,
4484 ),
4485 KeyParameter::new(
4486 KeyParameterValue::AttestationIdBrand(vec![4u8, 3u8, 1u8, 2u8]),
4487 SecurityLevel::TRUSTED_ENVIRONMENT,
4488 ),
4489 KeyParameter::new(
4490 KeyParameterValue::AttestationIdDevice(vec![4u8, 3u8, 1u8, 2u8]),
4491 SecurityLevel::TRUSTED_ENVIRONMENT,
4492 ),
4493 KeyParameter::new(
4494 KeyParameterValue::AttestationIdProduct(vec![4u8, 3u8, 1u8, 2u8]),
4495 SecurityLevel::TRUSTED_ENVIRONMENT,
4496 ),
4497 KeyParameter::new(
4498 KeyParameterValue::AttestationIdSerial(vec![4u8, 3u8, 1u8, 2u8]),
4499 SecurityLevel::TRUSTED_ENVIRONMENT,
4500 ),
4501 KeyParameter::new(
4502 KeyParameterValue::AttestationIdIMEI(vec![4u8, 3u8, 1u8, 2u8]),
4503 SecurityLevel::TRUSTED_ENVIRONMENT,
4504 ),
4505 KeyParameter::new(
4506 KeyParameterValue::AttestationIdMEID(vec![4u8, 3u8, 1u8, 2u8]),
4507 SecurityLevel::TRUSTED_ENVIRONMENT,
4508 ),
4509 KeyParameter::new(
4510 KeyParameterValue::AttestationIdManufacturer(vec![4u8, 3u8, 1u8, 2u8]),
4511 SecurityLevel::TRUSTED_ENVIRONMENT,
4512 ),
4513 KeyParameter::new(
4514 KeyParameterValue::AttestationIdModel(vec![4u8, 3u8, 1u8, 2u8]),
4515 SecurityLevel::TRUSTED_ENVIRONMENT,
4516 ),
4517 KeyParameter::new(
4518 KeyParameterValue::VendorPatchLevel(3),
4519 SecurityLevel::TRUSTED_ENVIRONMENT,
4520 ),
4521 KeyParameter::new(
4522 KeyParameterValue::BootPatchLevel(4),
4523 SecurityLevel::TRUSTED_ENVIRONMENT,
4524 ),
4525 KeyParameter::new(
4526 KeyParameterValue::AssociatedData(vec![4u8, 3u8, 1u8, 2u8]),
4527 SecurityLevel::TRUSTED_ENVIRONMENT,
4528 ),
4529 KeyParameter::new(
4530 KeyParameterValue::Nonce(vec![4u8, 3u8, 1u8, 2u8]),
4531 SecurityLevel::TRUSTED_ENVIRONMENT,
4532 ),
4533 KeyParameter::new(
4534 KeyParameterValue::MacLength(256),
4535 SecurityLevel::TRUSTED_ENVIRONMENT,
4536 ),
4537 KeyParameter::new(
4538 KeyParameterValue::ResetSinceIdRotation,
4539 SecurityLevel::TRUSTED_ENVIRONMENT,
4540 ),
4541 KeyParameter::new(
4542 KeyParameterValue::ConfirmationToken(vec![5u8, 5u8, 5u8, 5u8]),
4543 SecurityLevel::TRUSTED_ENVIRONMENT,
4544 ),
Qi Wub9433b52020-12-01 14:52:46 +08004545 ];
4546 if let Some(value) = max_usage_count {
4547 params.push(KeyParameter::new(
4548 KeyParameterValue::UsageCountLimit(value),
4549 SecurityLevel::SOFTWARE,
4550 ));
4551 }
4552 params
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07004553 }
4554
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004555 fn make_test_key_entry(
4556 db: &mut KeystoreDB,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07004557 domain: Domain,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004558 namespace: i64,
4559 alias: &str,
Qi Wub9433b52020-12-01 14:52:46 +08004560 max_usage_count: Option<i32>,
Janis Danisevskisaec14592020-11-12 09:41:49 -08004561 ) -> Result<KeyIdGuard> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08004562 let key_id = db.create_key_entry(&domain, &namespace, &KEYSTORE_UUID)?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004563 let mut blob_metadata = BlobMetaData::new();
4564 blob_metadata.add(BlobMetaEntry::EncryptedBy(EncryptedBy::Password));
4565 blob_metadata.add(BlobMetaEntry::Salt(vec![1, 2, 3]));
4566 blob_metadata.add(BlobMetaEntry::Iv(vec![2, 3, 1]));
4567 blob_metadata.add(BlobMetaEntry::AeadTag(vec![3, 1, 2]));
4568 blob_metadata.add(BlobMetaEntry::KmUuid(KEYSTORE_UUID));
4569
4570 db.set_blob(
4571 &key_id,
4572 SubComponentType::KEY_BLOB,
4573 Some(TEST_KEY_BLOB),
4574 Some(&blob_metadata),
4575 )?;
4576 db.set_blob(&key_id, SubComponentType::CERT, Some(TEST_CERT_BLOB), None)?;
4577 db.set_blob(&key_id, SubComponentType::CERT_CHAIN, Some(TEST_CERT_CHAIN_BLOB), None)?;
Qi Wub9433b52020-12-01 14:52:46 +08004578
4579 let params = make_test_params(max_usage_count);
4580 db.insert_keyparameter(&key_id, &params)?;
4581
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004582 let mut metadata = KeyMetaData::new();
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004583 metadata.add(KeyMetaEntry::CreationDate(DateTime::from_millis_epoch(123456789)));
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004584 db.insert_key_metadata(&key_id, &metadata)?;
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08004585 rebind_alias(db, &key_id, alias, domain, namespace)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004586 Ok(key_id)
4587 }
4588
Qi Wub9433b52020-12-01 14:52:46 +08004589 fn make_test_key_entry_test_vector(key_id: i64, max_usage_count: Option<i32>) -> KeyEntry {
4590 let params = make_test_params(max_usage_count);
4591
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004592 let mut blob_metadata = BlobMetaData::new();
4593 blob_metadata.add(BlobMetaEntry::EncryptedBy(EncryptedBy::Password));
4594 blob_metadata.add(BlobMetaEntry::Salt(vec![1, 2, 3]));
4595 blob_metadata.add(BlobMetaEntry::Iv(vec![2, 3, 1]));
4596 blob_metadata.add(BlobMetaEntry::AeadTag(vec![3, 1, 2]));
4597 blob_metadata.add(BlobMetaEntry::KmUuid(KEYSTORE_UUID));
4598
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004599 let mut metadata = KeyMetaData::new();
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004600 metadata.add(KeyMetaEntry::CreationDate(DateTime::from_millis_epoch(123456789)));
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004601
4602 KeyEntry {
4603 id: key_id,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004604 key_blob_info: Some((TEST_KEY_BLOB.to_vec(), blob_metadata)),
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004605 cert: Some(TEST_CERT_BLOB.to_vec()),
4606 cert_chain: Some(TEST_CERT_CHAIN_BLOB.to_vec()),
Max Bires8e93d2b2021-01-14 13:17:59 -08004607 km_uuid: KEYSTORE_UUID,
Qi Wub9433b52020-12-01 14:52:46 +08004608 parameters: params,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004609 metadata,
Janis Danisevskis377d1002021-01-27 19:07:48 -08004610 pure_cert: false,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004611 }
4612 }
4613
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004614 fn debug_dump_keyentry_table(db: &mut KeystoreDB) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004615 let mut stmt = db.conn.prepare(
Max Bires8e93d2b2021-01-14 13:17:59 -08004616 "SELECT id, key_type, domain, namespace, alias, state, km_uuid FROM persistent.keyentry;",
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004617 )?;
Max Bires8e93d2b2021-01-14 13:17:59 -08004618 let rows = stmt.query_map::<(i64, KeyType, i32, i64, String, KeyLifeCycle, Uuid), _, _>(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004619 NO_PARAMS,
4620 |row| {
Max Bires8e93d2b2021-01-14 13:17:59 -08004621 Ok((
4622 row.get(0)?,
4623 row.get(1)?,
4624 row.get(2)?,
4625 row.get(3)?,
4626 row.get(4)?,
4627 row.get(5)?,
4628 row.get(6)?,
4629 ))
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004630 },
4631 )?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004632
4633 println!("Key entry table rows:");
4634 for r in rows {
Max Bires8e93d2b2021-01-14 13:17:59 -08004635 let (id, key_type, domain, namespace, alias, state, km_uuid) = r.unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004636 println!(
Max Bires8e93d2b2021-01-14 13:17:59 -08004637 " id: {} KeyType: {:?} Domain: {} Namespace: {} Alias: {} State: {:?} KmUuid: {:?}",
4638 id, key_type, domain, namespace, alias, state, km_uuid
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004639 );
4640 }
4641 Ok(())
4642 }
4643
4644 fn debug_dump_grant_table(db: &mut KeystoreDB) -> Result<()> {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08004645 let mut stmt = db
4646 .conn
4647 .prepare("SELECT id, grantee, keyentryid, access_vector FROM persistent.grant;")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004648 let rows = stmt.query_map::<(i64, i64, i64, i64), _, _>(NO_PARAMS, |row| {
4649 Ok((row.get(0)?, row.get(1)?, row.get(2)?, row.get(3)?))
4650 })?;
4651
4652 println!("Grant table rows:");
4653 for r in rows {
4654 let (id, gt, ki, av) = r.unwrap();
4655 println!(" id: {} grantee: {} key_id: {} access_vector: {}", id, gt, ki, av);
4656 }
4657 Ok(())
4658 }
4659
Joel Galenson0891bc12020-07-20 10:37:03 -07004660 // Use a custom random number generator that repeats each number once.
4661 // This allows us to test repeated elements.
4662
4663 thread_local! {
4664 static RANDOM_COUNTER: RefCell<i64> = RefCell::new(0);
4665 }
4666
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004667 fn reset_random() {
4668 RANDOM_COUNTER.with(|counter| {
4669 *counter.borrow_mut() = 0;
4670 })
4671 }
4672
Joel Galenson0891bc12020-07-20 10:37:03 -07004673 pub fn random() -> i64 {
4674 RANDOM_COUNTER.with(|counter| {
4675 let result = *counter.borrow() / 2;
4676 *counter.borrow_mut() += 1;
4677 result
4678 })
4679 }
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00004680
4681 #[test]
4682 fn test_last_off_body() -> Result<()> {
4683 let mut db = new_test_db()?;
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08004684 db.insert_last_off_body(MonotonicRawTime::now())?;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00004685 let tx = db.conn.transaction_with_behavior(TransactionBehavior::Immediate)?;
4686 let last_off_body_1 = KeystoreDB::get_last_off_body(&tx)?;
4687 tx.commit()?;
4688 let one_second = Duration::from_secs(1);
4689 thread::sleep(one_second);
4690 db.update_last_off_body(MonotonicRawTime::now())?;
4691 let tx2 = db.conn.transaction_with_behavior(TransactionBehavior::Immediate)?;
4692 let last_off_body_2 = KeystoreDB::get_last_off_body(&tx2)?;
4693 tx2.commit()?;
4694 assert!(last_off_body_1.seconds() < last_off_body_2.seconds());
4695 Ok(())
4696 }
Hasini Gunasingheda895552021-01-27 19:34:37 +00004697
4698 #[test]
4699 fn test_unbind_keys_for_user() -> Result<()> {
4700 let mut db = new_test_db()?;
4701 db.unbind_keys_for_user(1, false)?;
4702
4703 make_test_key_entry(&mut db, Domain::APP, 210000, TEST_ALIAS, None)?;
4704 make_test_key_entry(&mut db, Domain::APP, 110000, TEST_ALIAS, None)?;
4705 db.unbind_keys_for_user(2, false)?;
4706
4707 assert_eq!(1, db.list(Domain::APP, 110000)?.len());
4708 assert_eq!(0, db.list(Domain::APP, 210000)?.len());
4709
4710 db.unbind_keys_for_user(1, true)?;
4711 assert_eq!(0, db.list(Domain::APP, 110000)?.len());
4712
4713 Ok(())
4714 }
4715
4716 #[test]
4717 fn test_store_super_key() -> Result<()> {
4718 let mut db = new_test_db()?;
4719 let pw = "xyzabc".as_bytes();
4720 let super_key = keystore2_crypto::generate_aes256_key()?;
4721 let secret = String::from("keystore2 is great.");
4722 let secret_bytes = secret.into_bytes();
4723 let (encrypted_secret, iv, tag) =
4724 keystore2_crypto::aes_gcm_encrypt(&secret_bytes, &super_key)?;
4725
4726 let (encrypted_super_key, metadata) =
4727 SuperKeyManager::encrypt_with_password(&super_key, &pw)?;
4728 db.store_super_key(1, &(&encrypted_super_key, &metadata))?;
4729
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00004730 //check if super key exists
4731 assert!(db.key_exists(Domain::APP, 1, "USER_SUPER_KEY", KeyType::Super)?);
4732
Hasini Gunasingheda895552021-01-27 19:34:37 +00004733 //load the super key from the database
4734 let tx = db.conn.transaction_with_behavior(TransactionBehavior::Immediate)?;
4735 let key_descriptor = KeyDescriptor {
4736 domain: Domain::APP,
4737 nspace: 1,
4738 alias: Some(String::from("USER_SUPER_KEY")),
4739 blob: None,
4740 };
4741 let id = KeystoreDB::load_key_entry_id(&tx, &key_descriptor, KeyType::Super)?;
4742 let key_entry = KeystoreDB::load_key_components(&tx, KeyEntryLoadBits::KM, id)?;
4743 let loaded_super_key = SuperKeyManager::extract_super_key_from_key_entry(key_entry, &pw)?;
4744
4745 let decrypted_secret_bytes = keystore2_crypto::aes_gcm_decrypt(
4746 &encrypted_secret,
4747 &iv,
4748 &tag,
4749 &loaded_super_key.get_key(),
4750 )?;
4751 let decrypted_secret = String::from_utf8((&decrypted_secret_bytes).to_vec())?;
4752 assert_eq!(String::from("keystore2 is great."), decrypted_secret);
4753 Ok(())
4754 }
Joel Galenson26f4d012020-07-17 14:57:21 -07004755}