blob: a9e4c35b8f4b72eb222f2c9c57bac910941f0224 [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.
Max Bires2b2e6562020-09-22 11:22:36 -0700584pub struct CertificateChain {
Max Bires97f96812021-02-23 23:44:57 -0800585 /// A KM key blob
586 pub private_key: ZVec,
587 /// A batch cert for private_key
588 pub batch_cert: Vec<u8>,
589 /// A full certificate chain from root signing authority to private_key, including batch_cert
590 /// for convenience.
591 pub cert_chain: Vec<u8>,
Max Bires2b2e6562020-09-22 11:22:36 -0700592}
593
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700594/// This type represents a Keystore 2.0 key entry.
595/// An entry has a unique `id` by which it can be found in the database.
596/// It has a security level field, key parameters, and three optional fields
597/// for the KeyMint blob, public certificate and a public certificate chain.
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800598#[derive(Debug, Default, Eq, PartialEq)]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700599pub struct KeyEntry {
600 id: i64,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800601 key_blob_info: Option<(Vec<u8>, BlobMetaData)>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700602 cert: Option<Vec<u8>>,
603 cert_chain: Option<Vec<u8>>,
Max Bires8e93d2b2021-01-14 13:17:59 -0800604 km_uuid: Uuid,
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700605 parameters: Vec<KeyParameter>,
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800606 metadata: KeyMetaData,
Janis Danisevskis377d1002021-01-27 19:07:48 -0800607 pure_cert: bool,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700608}
609
610impl KeyEntry {
611 /// Returns the unique id of the Key entry.
612 pub fn id(&self) -> i64 {
613 self.id
614 }
615 /// Exposes the optional KeyMint blob.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800616 pub fn key_blob_info(&self) -> &Option<(Vec<u8>, BlobMetaData)> {
617 &self.key_blob_info
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700618 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800619 /// Extracts the Optional KeyMint blob including its metadata.
620 pub fn take_key_blob_info(&mut self) -> Option<(Vec<u8>, BlobMetaData)> {
621 self.key_blob_info.take()
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700622 }
623 /// Exposes the optional public certificate.
624 pub fn cert(&self) -> &Option<Vec<u8>> {
625 &self.cert
626 }
627 /// Extracts the optional public certificate.
628 pub fn take_cert(&mut self) -> Option<Vec<u8>> {
629 self.cert.take()
630 }
631 /// Exposes the optional public certificate chain.
632 pub fn cert_chain(&self) -> &Option<Vec<u8>> {
633 &self.cert_chain
634 }
635 /// Extracts the optional public certificate_chain.
636 pub fn take_cert_chain(&mut self) -> Option<Vec<u8>> {
637 self.cert_chain.take()
638 }
Max Bires8e93d2b2021-01-14 13:17:59 -0800639 /// Returns the uuid of the owning KeyMint instance.
640 pub fn km_uuid(&self) -> &Uuid {
641 &self.km_uuid
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700642 }
Janis Danisevskis04b02832020-10-26 09:21:40 -0700643 /// Exposes the key parameters of this key entry.
644 pub fn key_parameters(&self) -> &Vec<KeyParameter> {
645 &self.parameters
646 }
647 /// Consumes this key entry and extracts the keyparameters from it.
648 pub fn into_key_parameters(self) -> Vec<KeyParameter> {
649 self.parameters
650 }
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800651 /// Exposes the key metadata of this key entry.
652 pub fn metadata(&self) -> &KeyMetaData {
653 &self.metadata
654 }
Janis Danisevskis377d1002021-01-27 19:07:48 -0800655 /// This returns true if the entry is a pure certificate entry with no
656 /// private key component.
657 pub fn pure_cert(&self) -> bool {
658 self.pure_cert
659 }
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000660 /// Consumes this key entry and extracts the keyparameters and metadata from it.
661 pub fn into_key_parameters_and_metadata(self) -> (Vec<KeyParameter>, KeyMetaData) {
662 (self.parameters, self.metadata)
663 }
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700664}
665
666/// Indicates the sub component of a key entry for persistent storage.
Janis Danisevskis377d1002021-01-27 19:07:48 -0800667#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700668pub struct SubComponentType(u32);
669impl SubComponentType {
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800670 /// Persistent identifier for a key blob.
671 pub const KEY_BLOB: SubComponentType = Self(0);
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700672 /// Persistent identifier for a certificate blob.
673 pub const CERT: SubComponentType = Self(1);
674 /// Persistent identifier for a certificate chain blob.
675 pub const CERT_CHAIN: SubComponentType = Self(2);
676}
677
678impl ToSql for SubComponentType {
679 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
680 self.0.to_sql()
681 }
682}
683
684impl FromSql for SubComponentType {
685 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
686 Ok(Self(u32::column_result(value)?))
687 }
688}
689
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800690/// This trait is private to the database module. It is used to convey whether or not the garbage
691/// collector shall be invoked after a database access. All closures passed to
692/// `KeystoreDB::with_transaction` return a tuple (bool, T) where the bool indicates if the
693/// gc needs to be triggered. This convenience function allows to turn any anyhow::Result<T>
694/// into anyhow::Result<(bool, T)> by simply appending one of `.do_gc(bool)`, `.no_gc()`, or
695/// `.need_gc()`.
696trait DoGc<T> {
697 fn do_gc(self, need_gc: bool) -> Result<(bool, T)>;
698
699 fn no_gc(self) -> Result<(bool, T)>;
700
701 fn need_gc(self) -> Result<(bool, T)>;
702}
703
704impl<T> DoGc<T> for Result<T> {
705 fn do_gc(self, need_gc: bool) -> Result<(bool, T)> {
706 self.map(|r| (need_gc, r))
707 }
708
709 fn no_gc(self) -> Result<(bool, T)> {
710 self.do_gc(false)
711 }
712
713 fn need_gc(self) -> Result<(bool, T)> {
714 self.do_gc(true)
715 }
716}
717
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700718/// KeystoreDB wraps a connection to an SQLite database and tracks its
719/// ownership. It also implements all of Keystore 2.0's database functionality.
Joel Galenson26f4d012020-07-17 14:57:21 -0700720pub struct KeystoreDB {
Joel Galenson26f4d012020-07-17 14:57:21 -0700721 conn: Connection,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800722 gc: Option<Gc>,
Joel Galenson26f4d012020-07-17 14:57:21 -0700723}
724
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000725/// Database representation of the monotonic time retrieved from the system call clock_gettime with
726/// CLOCK_MONOTONIC_RAW. Stores monotonic time as i64 in seconds.
727#[derive(Debug, Copy, Clone, Default, Eq, PartialEq, Ord, PartialOrd)]
728pub struct MonotonicRawTime(i64);
729
730impl MonotonicRawTime {
731 /// Constructs a new MonotonicRawTime
732 pub fn now() -> Self {
733 Self(get_current_time_in_seconds())
734 }
735
736 /// Returns the integer value of MonotonicRawTime as i64
737 pub fn seconds(&self) -> i64 {
738 self.0
739 }
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800740
741 /// Like i64::checked_sub.
742 pub fn checked_sub(&self, other: &Self) -> Option<Self> {
743 self.0.checked_sub(other.0).map(Self)
744 }
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000745}
746
747impl ToSql for MonotonicRawTime {
748 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
749 Ok(ToSqlOutput::Owned(Value::Integer(self.0)))
750 }
751}
752
753impl FromSql for MonotonicRawTime {
754 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
755 Ok(Self(i64::column_result(value)?))
756 }
757}
758
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000759/// This struct encapsulates the information to be stored in the database about the auth tokens
760/// received by keystore.
761pub struct AuthTokenEntry {
762 auth_token: HardwareAuthToken,
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000763 time_received: MonotonicRawTime,
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000764}
765
766impl AuthTokenEntry {
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000767 fn new(auth_token: HardwareAuthToken, time_received: MonotonicRawTime) -> Self {
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000768 AuthTokenEntry { auth_token, time_received }
769 }
770
771 /// Checks if this auth token satisfies the given authentication information.
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800772 pub fn satisfies(&self, user_secure_ids: &[i64], auth_type: HardwareAuthenticatorType) -> bool {
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000773 user_secure_ids.iter().any(|&sid| {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800774 (sid == self.auth_token.userId || sid == self.auth_token.authenticatorId)
775 && (((auth_type.0 as i32) & (self.auth_token.authenticatorType.0 as i32)) != 0)
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000776 })
777 }
778
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000779 /// Returns the auth token wrapped by the AuthTokenEntry
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800780 pub fn auth_token(&self) -> &HardwareAuthToken {
781 &self.auth_token
782 }
783
784 /// Returns the auth token wrapped by the AuthTokenEntry
785 pub fn take_auth_token(self) -> HardwareAuthToken {
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000786 self.auth_token
787 }
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800788
789 /// Returns the time that this auth token was received.
790 pub fn time_received(&self) -> MonotonicRawTime {
791 self.time_received
792 }
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000793}
794
Janis Danisevskisb00ebd02021-02-02 21:52:24 -0800795/// Shared in-memory databases get destroyed as soon as the last connection to them gets closed.
796/// This object does not allow access to the database connection. But it keeps a database
797/// connection alive in order to keep the in memory per boot database alive.
798pub struct PerBootDbKeepAlive(Connection);
799
Joel Galenson26f4d012020-07-17 14:57:21 -0700800impl KeystoreDB {
Janis Danisevskiseed69842021-02-18 20:04:10 -0800801 const UNASSIGNED_KEY_ID: i64 = -1i64;
Janis Danisevskisb00ebd02021-02-02 21:52:24 -0800802 const PERBOOT_DB_FILE_NAME: &'static str = &"file:perboot.sqlite?mode=memory&cache=shared";
803
Hasini Gunasinghe0e161452021-01-27 19:34:37 +0000804 /// The alias of the user super key.
805 pub const USER_SUPER_KEY_ALIAS: &'static str = &"USER_SUPER_KEY";
806
Janis Danisevskisb00ebd02021-02-02 21:52:24 -0800807 /// This creates a PerBootDbKeepAlive object to keep the per boot database alive.
808 pub fn keep_perboot_db_alive() -> Result<PerBootDbKeepAlive> {
809 let conn = Connection::open_in_memory()
810 .context("In keep_perboot_db_alive: Failed to initialize SQLite connection.")?;
811
812 conn.execute("ATTACH DATABASE ? as perboot;", params![Self::PERBOOT_DB_FILE_NAME])
813 .context("In keep_perboot_db_alive: Failed to attach database perboot.")?;
814 Ok(PerBootDbKeepAlive(conn))
815 }
816
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700817 /// This will create a new database connection connecting the two
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800818 /// files persistent.sqlite and perboot.sqlite in the given directory.
819 /// It also attempts to initialize all of the tables.
820 /// KeystoreDB cannot be used by multiple threads.
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700821 /// Each thread should open their own connection using `thread_local!`.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800822 pub fn new(db_root: &Path, gc: Option<Gc>) -> Result<Self> {
Janis Danisevskisb00ebd02021-02-02 21:52:24 -0800823 // Build the path to the sqlite file.
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800824 let mut persistent_path = db_root.to_path_buf();
825 persistent_path.push("persistent.sqlite");
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700826
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800827 // Now convert them to strings prefixed with "file:"
828 let mut persistent_path_str = "file:".to_owned();
829 persistent_path_str.push_str(&persistent_path.to_string_lossy());
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800830
Janis Danisevskisb00ebd02021-02-02 21:52:24 -0800831 let conn = Self::make_connection(&persistent_path_str, &Self::PERBOOT_DB_FILE_NAME)?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800832
Janis Danisevskis66784c42021-01-27 08:40:25 -0800833 // On busy fail Immediately. It is unlikely to succeed given a bug in sqlite.
834 conn.busy_handler(None).context("In KeystoreDB::new: Failed to set busy handler.")?;
835
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800836 let mut db = Self { conn, gc };
Janis Danisevskis66784c42021-01-27 08:40:25 -0800837 db.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800838 Self::init_tables(tx).context("Trying to initialize tables.").no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -0800839 })?;
840 Ok(db)
Joel Galenson2aab4432020-07-22 15:27:57 -0700841 }
842
Janis Danisevskis66784c42021-01-27 08:40:25 -0800843 fn init_tables(tx: &Transaction) -> Result<()> {
844 tx.execute(
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700845 "CREATE TABLE IF NOT EXISTS persistent.keyentry (
Joel Galenson0891bc12020-07-20 10:37:03 -0700846 id INTEGER UNIQUE,
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800847 key_type INTEGER,
Joel Galenson0891bc12020-07-20 10:37:03 -0700848 domain INTEGER,
849 namespace INTEGER,
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800850 alias BLOB,
Max Bires8e93d2b2021-01-14 13:17:59 -0800851 state INTEGER,
852 km_uuid BLOB);",
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700853 NO_PARAMS,
854 )
855 .context("Failed to initialize \"keyentry\" table.")?;
856
Janis Danisevskis66784c42021-01-27 08:40:25 -0800857 tx.execute(
Janis Danisevskisa5438182021-02-02 14:22:59 -0800858 "CREATE INDEX IF NOT EXISTS persistent.keyentry_id_index
859 ON keyentry(id);",
860 NO_PARAMS,
861 )
862 .context("Failed to create index keyentry_id_index.")?;
863
864 tx.execute(
865 "CREATE INDEX IF NOT EXISTS persistent.keyentry_domain_namespace_index
866 ON keyentry(domain, namespace, alias);",
867 NO_PARAMS,
868 )
869 .context("Failed to create index keyentry_domain_namespace_index.")?;
870
871 tx.execute(
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700872 "CREATE TABLE IF NOT EXISTS persistent.blobentry (
873 id INTEGER PRIMARY KEY,
874 subcomponent_type INTEGER,
875 keyentryid INTEGER,
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800876 blob BLOB);",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700877 NO_PARAMS,
878 )
879 .context("Failed to initialize \"blobentry\" table.")?;
880
Janis Danisevskis66784c42021-01-27 08:40:25 -0800881 tx.execute(
Janis Danisevskisa5438182021-02-02 14:22:59 -0800882 "CREATE INDEX IF NOT EXISTS persistent.blobentry_keyentryid_index
883 ON blobentry(keyentryid);",
884 NO_PARAMS,
885 )
886 .context("Failed to create index blobentry_keyentryid_index.")?;
887
888 tx.execute(
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800889 "CREATE TABLE IF NOT EXISTS persistent.blobmetadata (
890 id INTEGER PRIMARY KEY,
891 blobentryid INTEGER,
892 tag INTEGER,
893 data ANY,
894 UNIQUE (blobentryid, tag));",
895 NO_PARAMS,
896 )
897 .context("Failed to initialize \"blobmetadata\" table.")?;
898
899 tx.execute(
900 "CREATE INDEX IF NOT EXISTS persistent.blobmetadata_blobentryid_index
901 ON blobmetadata(blobentryid);",
902 NO_PARAMS,
903 )
904 .context("Failed to create index blobmetadata_blobentryid_index.")?;
905
906 tx.execute(
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700907 "CREATE TABLE IF NOT EXISTS persistent.keyparameter (
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000908 keyentryid INTEGER,
909 tag INTEGER,
910 data ANY,
911 security_level INTEGER);",
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700912 NO_PARAMS,
913 )
914 .context("Failed to initialize \"keyparameter\" table.")?;
915
Janis Danisevskis66784c42021-01-27 08:40:25 -0800916 tx.execute(
Janis Danisevskisa5438182021-02-02 14:22:59 -0800917 "CREATE INDEX IF NOT EXISTS persistent.keyparameter_keyentryid_index
918 ON keyparameter(keyentryid);",
919 NO_PARAMS,
920 )
921 .context("Failed to create index keyparameter_keyentryid_index.")?;
922
923 tx.execute(
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800924 "CREATE TABLE IF NOT EXISTS persistent.keymetadata (
925 keyentryid INTEGER,
926 tag INTEGER,
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000927 data ANY,
928 UNIQUE (keyentryid, tag));",
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800929 NO_PARAMS,
930 )
931 .context("Failed to initialize \"keymetadata\" table.")?;
932
Janis Danisevskis66784c42021-01-27 08:40:25 -0800933 tx.execute(
Janis Danisevskisa5438182021-02-02 14:22:59 -0800934 "CREATE INDEX IF NOT EXISTS persistent.keymetadata_keyentryid_index
935 ON keymetadata(keyentryid);",
936 NO_PARAMS,
937 )
938 .context("Failed to create index keymetadata_keyentryid_index.")?;
939
940 tx.execute(
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800941 "CREATE TABLE IF NOT EXISTS persistent.grant (
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700942 id INTEGER UNIQUE,
943 grantee INTEGER,
944 keyentryid INTEGER,
945 access_vector INTEGER);",
946 NO_PARAMS,
947 )
948 .context("Failed to initialize \"grant\" table.")?;
949
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000950 //TODO: only drop the following two perboot tables if this is the first start up
951 //during the boot (b/175716626).
Janis Danisevskis66784c42021-01-27 08:40:25 -0800952 // tx.execute("DROP TABLE IF EXISTS perboot.authtoken;", NO_PARAMS)
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000953 // .context("Failed to drop perboot.authtoken table")?;
Janis Danisevskis66784c42021-01-27 08:40:25 -0800954 tx.execute(
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000955 "CREATE TABLE IF NOT EXISTS perboot.authtoken (
956 id INTEGER PRIMARY KEY,
957 challenge INTEGER,
958 user_id INTEGER,
959 auth_id INTEGER,
960 authenticator_type INTEGER,
961 timestamp INTEGER,
962 mac BLOB,
963 time_received INTEGER,
964 UNIQUE(user_id, auth_id, authenticator_type));",
965 NO_PARAMS,
966 )
967 .context("Failed to initialize \"authtoken\" table.")?;
968
Janis Danisevskis66784c42021-01-27 08:40:25 -0800969 // tx.execute("DROP TABLE IF EXISTS perboot.metadata;", NO_PARAMS)
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000970 // .context("Failed to drop perboot.metadata table")?;
971 // metadata table stores certain miscellaneous information required for keystore functioning
972 // during a boot cycle, as key-value pairs.
Janis Danisevskis66784c42021-01-27 08:40:25 -0800973 tx.execute(
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000974 "CREATE TABLE IF NOT EXISTS perboot.metadata (
975 key TEXT,
976 value BLOB,
977 UNIQUE(key));",
978 NO_PARAMS,
979 )
980 .context("Failed to initialize \"metadata\" table.")?;
Joel Galenson0891bc12020-07-20 10:37:03 -0700981 Ok(())
982 }
983
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700984 fn make_connection(persistent_file: &str, perboot_file: &str) -> Result<Connection> {
985 let conn =
986 Connection::open_in_memory().context("Failed to initialize SQLite connection.")?;
987
Janis Danisevskis66784c42021-01-27 08:40:25 -0800988 loop {
989 if let Err(e) = conn
990 .execute("ATTACH DATABASE ? as persistent;", params![persistent_file])
991 .context("Failed to attach database persistent.")
992 {
993 if Self::is_locked_error(&e) {
994 std::thread::sleep(std::time::Duration::from_micros(500));
995 continue;
996 } else {
997 return Err(e);
998 }
999 }
1000 break;
1001 }
1002 loop {
1003 if let Err(e) = conn
1004 .execute("ATTACH DATABASE ? as perboot;", params![perboot_file])
1005 .context("Failed to attach database perboot.")
1006 {
1007 if Self::is_locked_error(&e) {
1008 std::thread::sleep(std::time::Duration::from_micros(500));
1009 continue;
1010 } else {
1011 return Err(e);
1012 }
1013 }
1014 break;
1015 }
Janis Danisevskis4df44f42020-08-26 14:40:03 -07001016
1017 Ok(conn)
1018 }
1019
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001020 /// This function is intended to be used by the garbage collector.
1021 /// It deletes the blob given by `blob_id_to_delete`. It then tries to find a superseded
1022 /// key blob that might need special handling by the garbage collector.
1023 /// If no further superseded blobs can be found it deletes all other superseded blobs that don't
1024 /// need special handling and returns None.
1025 pub fn handle_next_superseded_blob(
1026 &mut self,
1027 blob_id_to_delete: Option<i64>,
1028 ) -> Result<Option<(i64, Vec<u8>, BlobMetaData)>> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001029 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001030 // Delete the given blob if one was given.
1031 if let Some(blob_id_to_delete) = blob_id_to_delete {
1032 tx.execute(
1033 "DELETE FROM persistent.blobmetadata WHERE blobentryid = ?;",
1034 params![blob_id_to_delete],
1035 )
1036 .context("Trying to delete blob metadata.")?;
1037 tx.execute(
1038 "DELETE FROM persistent.blobentry WHERE id = ?;",
1039 params![blob_id_to_delete],
1040 )
1041 .context("Trying to blob.")?;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001042 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001043
1044 // Find another superseded keyblob load its metadata and return it.
1045 if let Some((blob_id, blob)) = tx
1046 .query_row(
1047 "SELECT id, blob FROM persistent.blobentry
1048 WHERE subcomponent_type = ?
1049 AND (
1050 id NOT IN (
1051 SELECT MAX(id) FROM persistent.blobentry
1052 WHERE subcomponent_type = ?
1053 GROUP BY keyentryid, subcomponent_type
1054 )
1055 OR keyentryid NOT IN (SELECT id FROM persistent.keyentry)
1056 );",
1057 params![SubComponentType::KEY_BLOB, SubComponentType::KEY_BLOB],
1058 |row| Ok((row.get(0)?, row.get(1)?)),
1059 )
1060 .optional()
1061 .context("Trying to query superseded blob.")?
1062 {
1063 let blob_metadata = BlobMetaData::load_from_db(blob_id, tx)
1064 .context("Trying to load blob metadata.")?;
1065 return Ok(Some((blob_id, blob, blob_metadata))).no_gc();
1066 }
1067
1068 // We did not find any superseded key blob, so let's remove other superseded blob in
1069 // one transaction.
1070 tx.execute(
1071 "DELETE FROM persistent.blobentry
1072 WHERE NOT subcomponent_type = ?
1073 AND (
1074 id NOT IN (
1075 SELECT MAX(id) FROM persistent.blobentry
1076 WHERE NOT subcomponent_type = ?
1077 GROUP BY keyentryid, subcomponent_type
1078 ) OR keyentryid NOT IN (SELECT id FROM persistent.keyentry)
1079 );",
1080 params![SubComponentType::KEY_BLOB, SubComponentType::KEY_BLOB],
1081 )
1082 .context("Trying to purge superseded blobs.")?;
1083
1084 Ok(None).no_gc()
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001085 })
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001086 .context("In handle_next_superseded_blob.")
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001087 }
1088
1089 /// This maintenance function should be called only once before the database is used for the
1090 /// first time. It restores the invariant that `KeyLifeCycle::Existing` is a transient state.
1091 /// The function transitions all key entries from Existing to Unreferenced unconditionally and
1092 /// returns the number of rows affected. If this returns a value greater than 0, it means that
1093 /// Keystore crashed at some point during key generation. Callers may want to log such
1094 /// occurrences.
1095 /// Unlike with `mark_unreferenced`, we don't need to purge grants, because only keys that made
1096 /// it to `KeyLifeCycle::Live` may have grants.
1097 pub fn cleanup_leftovers(&mut self) -> Result<usize> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001098 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1099 tx.execute(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001100 "UPDATE persistent.keyentry SET state = ? WHERE state = ?;",
1101 params![KeyLifeCycle::Unreferenced, KeyLifeCycle::Existing],
1102 )
Janis Danisevskis66784c42021-01-27 08:40:25 -08001103 .context("Failed to execute query.")
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001104 .need_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08001105 })
1106 .context("In cleanup_leftovers.")
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001107 }
1108
Hasini Gunasinghe0e161452021-01-27 19:34:37 +00001109 /// Checks if a key exists with given key type and key descriptor properties.
1110 pub fn key_exists(
1111 &mut self,
1112 domain: Domain,
1113 nspace: i64,
1114 alias: &str,
1115 key_type: KeyType,
1116 ) -> Result<bool> {
1117 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1118 let key_descriptor =
1119 KeyDescriptor { domain, nspace, alias: Some(alias.to_string()), blob: None };
1120 let result = Self::load_key_entry_id(&tx, &key_descriptor, key_type);
1121 match result {
1122 Ok(_) => Ok(true),
1123 Err(error) => match error.root_cause().downcast_ref::<KsError>() {
1124 Some(KsError::Rc(ResponseCode::KEY_NOT_FOUND)) => Ok(false),
1125 _ => Err(error).context("In key_exists: Failed to find if the key exists."),
1126 },
1127 }
1128 .no_gc()
1129 })
1130 .context("In key_exists.")
1131 }
1132
Hasini Gunasingheda895552021-01-27 19:34:37 +00001133 /// Stores a super key in the database.
1134 pub fn store_super_key(
1135 &mut self,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +00001136 user_id: u32,
Hasini Gunasingheda895552021-01-27 19:34:37 +00001137 blob_info: &(&[u8], &BlobMetaData),
1138 ) -> Result<KeyEntry> {
1139 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1140 let key_id = Self::insert_with_retry(|id| {
1141 tx.execute(
1142 "INSERT into persistent.keyentry
1143 (id, key_type, domain, namespace, alias, state, km_uuid)
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00001144 VALUES(?, ?, ?, ?, ?, ?, ?);",
Hasini Gunasingheda895552021-01-27 19:34:37 +00001145 params![
1146 id,
1147 KeyType::Super,
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00001148 Domain::APP.0,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +00001149 user_id as i64,
Hasini Gunasingheda895552021-01-27 19:34:37 +00001150 Self::USER_SUPER_KEY_ALIAS,
1151 KeyLifeCycle::Live,
1152 &KEYSTORE_UUID,
1153 ],
1154 )
1155 })
1156 .context("Failed to insert into keyentry table.")?;
1157
1158 let (blob, blob_metadata) = *blob_info;
1159 Self::set_blob_internal(
1160 &tx,
1161 key_id,
1162 SubComponentType::KEY_BLOB,
1163 Some(blob),
1164 Some(blob_metadata),
1165 )
1166 .context("Failed to store key blob.")?;
1167
1168 Self::load_key_components(tx, KeyEntryLoadBits::KM, key_id)
1169 .context("Trying to load key components.")
1170 .no_gc()
1171 })
1172 .context("In store_super_key.")
1173 }
1174
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +00001175 /// Loads super key of a given user, if exists
1176 pub fn load_super_key(&mut self, user_id: u32) -> Result<Option<(KeyIdGuard, KeyEntry)>> {
1177 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1178 let key_descriptor = KeyDescriptor {
1179 domain: Domain::APP,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +00001180 nspace: user_id as i64,
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +00001181 alias: Some(String::from("USER_SUPER_KEY")),
1182 blob: None,
1183 };
1184 let id = Self::load_key_entry_id(&tx, &key_descriptor, KeyType::Super);
1185 match id {
1186 Ok(id) => {
1187 let key_entry = Self::load_key_components(&tx, KeyEntryLoadBits::KM, id)
1188 .context("In load_super_key. Failed to load key entry.")?;
1189 Ok(Some((KEY_ID_LOCK.get(id), key_entry)))
1190 }
1191 Err(error) => match error.root_cause().downcast_ref::<KsError>() {
1192 Some(KsError::Rc(ResponseCode::KEY_NOT_FOUND)) => Ok(None),
1193 _ => Err(error).context("In load_super_key."),
1194 },
1195 }
1196 .no_gc()
1197 })
1198 .context("In load_super_key.")
1199 }
1200
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001201 /// Atomically loads a key entry and associated metadata or creates it using the
1202 /// callback create_new_key callback. The callback is called during a database
1203 /// transaction. This means that implementers should be mindful about using
1204 /// blocking operations such as IPC or grabbing mutexes.
1205 pub fn get_or_create_key_with<F>(
1206 &mut self,
1207 domain: Domain,
1208 namespace: i64,
1209 alias: &str,
Max Bires8e93d2b2021-01-14 13:17:59 -08001210 km_uuid: Uuid,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001211 create_new_key: F,
1212 ) -> Result<(KeyIdGuard, KeyEntry)>
1213 where
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001214 F: Fn() -> Result<(Vec<u8>, BlobMetaData)>,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001215 {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001216 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1217 let id = {
1218 let mut stmt = tx
1219 .prepare(
1220 "SELECT id FROM persistent.keyentry
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001221 WHERE
1222 key_type = ?
1223 AND domain = ?
1224 AND namespace = ?
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001225 AND alias = ?
1226 AND state = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08001227 )
1228 .context("In get_or_create_key_with: Failed to select from keyentry table.")?;
1229 let mut rows = stmt
1230 .query(params![KeyType::Super, domain.0, namespace, alias, KeyLifeCycle::Live])
1231 .context("In get_or_create_key_with: Failed to query from keyentry table.")?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001232
Janis Danisevskis66784c42021-01-27 08:40:25 -08001233 db_utils::with_rows_extract_one(&mut rows, |row| {
1234 Ok(match row {
1235 Some(r) => r.get(0).context("Failed to unpack id.")?,
1236 None => None,
1237 })
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001238 })
Janis Danisevskis66784c42021-01-27 08:40:25 -08001239 .context("In get_or_create_key_with.")?
1240 };
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001241
Janis Danisevskis66784c42021-01-27 08:40:25 -08001242 let (id, entry) = match id {
1243 Some(id) => (
1244 id,
1245 Self::load_key_components(&tx, KeyEntryLoadBits::KM, id)
1246 .context("In get_or_create_key_with.")?,
1247 ),
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001248
Janis Danisevskis66784c42021-01-27 08:40:25 -08001249 None => {
1250 let id = Self::insert_with_retry(|id| {
1251 tx.execute(
1252 "INSERT into persistent.keyentry
Max Bires8e93d2b2021-01-14 13:17:59 -08001253 (id, key_type, domain, namespace, alias, state, km_uuid)
1254 VALUES(?, ?, ?, ?, ?, ?, ?);",
Janis Danisevskis66784c42021-01-27 08:40:25 -08001255 params![
1256 id,
1257 KeyType::Super,
1258 domain.0,
1259 namespace,
1260 alias,
1261 KeyLifeCycle::Live,
1262 km_uuid,
1263 ],
1264 )
1265 })
1266 .context("In get_or_create_key_with.")?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001267
Janis Danisevskis66784c42021-01-27 08:40:25 -08001268 let (blob, metadata) =
1269 create_new_key().context("In get_or_create_key_with.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001270 Self::set_blob_internal(
1271 &tx,
1272 id,
1273 SubComponentType::KEY_BLOB,
1274 Some(&blob),
1275 Some(&metadata),
1276 )
1277 .context("In get_of_create_key_with.")?;
Janis Danisevskis66784c42021-01-27 08:40:25 -08001278 (
Janis Danisevskis377d1002021-01-27 19:07:48 -08001279 id,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001280 KeyEntry {
1281 id,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001282 key_blob_info: Some((blob, metadata)),
Janis Danisevskis66784c42021-01-27 08:40:25 -08001283 pure_cert: false,
1284 ..Default::default()
1285 },
1286 )
1287 }
1288 };
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001289 Ok((KEY_ID_LOCK.get(id), entry)).no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08001290 })
1291 .context("In get_or_create_key_with.")
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001292 }
1293
Janis Danisevskis66784c42021-01-27 08:40:25 -08001294 /// SQLite3 seems to hold a shared mutex while running the busy handler when
1295 /// waiting for the database file to become available. This makes it
1296 /// impossible to successfully recover from a locked database when the
1297 /// transaction holding the device busy is in the same process on a
1298 /// different connection. As a result the busy handler has to time out and
1299 /// fail in order to make progress.
1300 ///
1301 /// Instead, we set the busy handler to None (return immediately). And catch
1302 /// Busy and Locked errors (the latter occur on in memory databases with
1303 /// shared cache, e.g., the per-boot database.) and restart the transaction
1304 /// after a grace period of half a millisecond.
1305 ///
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001306 /// Creates a transaction with the given behavior and executes f with the new transaction.
Janis Danisevskis66784c42021-01-27 08:40:25 -08001307 /// The transaction is committed only if f returns Ok and retried if DatabaseBusy
1308 /// or DatabaseLocked is encountered.
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001309 fn with_transaction<T, F>(&mut self, behavior: TransactionBehavior, f: F) -> Result<T>
1310 where
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001311 F: Fn(&Transaction) -> Result<(bool, T)>,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001312 {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001313 loop {
1314 match self
1315 .conn
1316 .transaction_with_behavior(behavior)
1317 .context("In with_transaction.")
1318 .and_then(|tx| f(&tx).map(|result| (result, tx)))
1319 .and_then(|(result, tx)| {
1320 tx.commit().context("In with_transaction: Failed to commit transaction.")?;
1321 Ok(result)
1322 }) {
1323 Ok(result) => break Ok(result),
1324 Err(e) => {
1325 if Self::is_locked_error(&e) {
1326 std::thread::sleep(std::time::Duration::from_micros(500));
1327 continue;
1328 } else {
1329 return Err(e).context("In with_transaction.");
1330 }
1331 }
1332 }
1333 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001334 .map(|(need_gc, result)| {
1335 if need_gc {
1336 if let Some(ref gc) = self.gc {
1337 gc.notify_gc();
1338 }
1339 }
1340 result
1341 })
Janis Danisevskis66784c42021-01-27 08:40:25 -08001342 }
1343
1344 fn is_locked_error(e: &anyhow::Error) -> bool {
1345 matches!(e.root_cause().downcast_ref::<rusqlite::ffi::Error>(),
1346 Some(rusqlite::ffi::Error {
1347 code: rusqlite::ErrorCode::DatabaseBusy,
1348 ..
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001349 })
Janis Danisevskis66784c42021-01-27 08:40:25 -08001350 | Some(rusqlite::ffi::Error {
1351 code: rusqlite::ErrorCode::DatabaseLocked,
1352 ..
1353 }))
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001354 }
1355
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001356 /// Creates a new key entry and allocates a new randomized id for the new key.
1357 /// The key id gets associated with a domain and namespace but not with an alias.
1358 /// To complete key generation `rebind_alias` should be called after all of the
1359 /// key artifacts, i.e., blobs and parameters have been associated with the new
1360 /// key id. Finalizing with `rebind_alias` makes the creation of a new key entry
1361 /// atomic even if key generation is not.
Max Bires8e93d2b2021-01-14 13:17:59 -08001362 pub fn create_key_entry(
1363 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001364 domain: &Domain,
1365 namespace: &i64,
Max Bires8e93d2b2021-01-14 13:17:59 -08001366 km_uuid: &Uuid,
1367 ) -> Result<KeyIdGuard> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001368 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001369 Self::create_key_entry_internal(tx, domain, namespace, km_uuid).no_gc()
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001370 })
1371 .context("In create_key_entry.")
1372 }
1373
1374 fn create_key_entry_internal(
1375 tx: &Transaction,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001376 domain: &Domain,
1377 namespace: &i64,
Max Bires8e93d2b2021-01-14 13:17:59 -08001378 km_uuid: &Uuid,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001379 ) -> Result<KeyIdGuard> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001380 match *domain {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001381 Domain::APP | Domain::SELINUX => {}
Joel Galenson0891bc12020-07-20 10:37:03 -07001382 _ => {
1383 return Err(KsError::sys())
1384 .context(format!("Domain {:?} must be either App or SELinux.", domain));
1385 }
1386 }
Janis Danisevskisaec14592020-11-12 09:41:49 -08001387 Ok(KEY_ID_LOCK.get(
1388 Self::insert_with_retry(|id| {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001389 tx.execute(
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001390 "INSERT into persistent.keyentry
Max Bires8e93d2b2021-01-14 13:17:59 -08001391 (id, key_type, domain, namespace, alias, state, km_uuid)
1392 VALUES(?, ?, ?, ?, NULL, ?, ?);",
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001393 params![
1394 id,
1395 KeyType::Client,
1396 domain.0 as u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001397 *namespace,
Max Bires8e93d2b2021-01-14 13:17:59 -08001398 KeyLifeCycle::Existing,
1399 km_uuid,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001400 ],
Janis Danisevskisaec14592020-11-12 09:41:49 -08001401 )
1402 })
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001403 .context("In create_key_entry_internal")?,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001404 ))
Joel Galenson26f4d012020-07-17 14:57:21 -07001405 }
Joel Galenson33c04ad2020-08-03 11:04:38 -07001406
Max Bires2b2e6562020-09-22 11:22:36 -07001407 /// Creates a new attestation key entry and allocates a new randomized id for the new key.
1408 /// The key id gets associated with a domain and namespace later but not with an alias. The
1409 /// alias will be used to denote if a key has been signed as each key can only be bound to one
1410 /// domain and namespace pairing so there is no need to use them as a value for indexing into
1411 /// a key.
1412 pub fn create_attestation_key_entry(
1413 &mut self,
1414 maced_public_key: &[u8],
1415 raw_public_key: &[u8],
1416 private_key: &[u8],
1417 km_uuid: &Uuid,
1418 ) -> Result<()> {
1419 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1420 let key_id = KEY_ID_LOCK.get(
1421 Self::insert_with_retry(|id| {
1422 tx.execute(
1423 "INSERT into persistent.keyentry
1424 (id, key_type, domain, namespace, alias, state, km_uuid)
1425 VALUES(?, ?, NULL, NULL, NULL, ?, ?);",
1426 params![id, KeyType::Attestation, KeyLifeCycle::Live, km_uuid],
1427 )
1428 })
1429 .context("In create_key_entry")?,
1430 );
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001431 Self::set_blob_internal(
1432 &tx,
1433 key_id.0,
1434 SubComponentType::KEY_BLOB,
1435 Some(private_key),
1436 None,
1437 )?;
Max Bires2b2e6562020-09-22 11:22:36 -07001438 let mut metadata = KeyMetaData::new();
1439 metadata.add(KeyMetaEntry::AttestationMacedPublicKey(maced_public_key.to_vec()));
1440 metadata.add(KeyMetaEntry::AttestationRawPubKey(raw_public_key.to_vec()));
1441 metadata.store_in_db(key_id.0, &tx)?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001442 Ok(()).no_gc()
Max Bires2b2e6562020-09-22 11:22:36 -07001443 })
1444 .context("In create_attestation_key_entry")
1445 }
1446
Janis Danisevskis377d1002021-01-27 19:07:48 -08001447 /// Set a new blob and associates it with the given key id. Each blob
1448 /// has a sub component type.
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001449 /// Each key can have one of each sub component type associated. If more
1450 /// are added only the most recent can be retrieved, and superseded blobs
Janis Danisevskis377d1002021-01-27 19:07:48 -08001451 /// will get garbage collected.
1452 /// Components SubComponentType::CERT and SubComponentType::CERT_CHAIN can be
1453 /// removed by setting blob to None.
1454 pub fn set_blob(
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001455 &mut self,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001456 key_id: &KeyIdGuard,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001457 sc_type: SubComponentType,
Janis Danisevskis377d1002021-01-27 19:07:48 -08001458 blob: Option<&[u8]>,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001459 blob_metadata: Option<&BlobMetaData>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001460 ) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001461 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001462 Self::set_blob_internal(&tx, key_id.0, sc_type, blob, blob_metadata).need_gc()
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001463 })
Janis Danisevskis377d1002021-01-27 19:07:48 -08001464 .context("In set_blob.")
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001465 }
1466
Janis Danisevskiseed69842021-02-18 20:04:10 -08001467 /// Why would we insert a deleted blob? This weird function is for the purpose of legacy
1468 /// key migration in the case where we bulk delete all the keys of an app or even a user.
1469 /// We use this to insert key blobs into the database which can then be garbage collected
1470 /// lazily by the key garbage collector.
1471 pub fn set_deleted_blob(&mut self, blob: &[u8], blob_metadata: &BlobMetaData) -> Result<()> {
1472 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1473 Self::set_blob_internal(
1474 &tx,
1475 Self::UNASSIGNED_KEY_ID,
1476 SubComponentType::KEY_BLOB,
1477 Some(blob),
1478 Some(blob_metadata),
1479 )
1480 .need_gc()
1481 })
1482 .context("In set_deleted_blob.")
1483 }
1484
Janis Danisevskis377d1002021-01-27 19:07:48 -08001485 fn set_blob_internal(
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001486 tx: &Transaction,
1487 key_id: i64,
1488 sc_type: SubComponentType,
Janis Danisevskis377d1002021-01-27 19:07:48 -08001489 blob: Option<&[u8]>,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001490 blob_metadata: Option<&BlobMetaData>,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001491 ) -> Result<()> {
Janis Danisevskis377d1002021-01-27 19:07:48 -08001492 match (blob, sc_type) {
1493 (Some(blob), _) => {
1494 tx.execute(
1495 "INSERT INTO persistent.blobentry
1496 (subcomponent_type, keyentryid, blob) VALUES (?, ?, ?);",
1497 params![sc_type, key_id, blob],
1498 )
1499 .context("In set_blob_internal: Failed to insert blob.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001500 if let Some(blob_metadata) = blob_metadata {
1501 let blob_id = tx
1502 .query_row("SELECT MAX(id) FROM persistent.blobentry;", NO_PARAMS, |row| {
1503 row.get(0)
1504 })
1505 .context("In set_blob_internal: Failed to get new blob id.")?;
1506 blob_metadata
1507 .store_in_db(blob_id, tx)
1508 .context("In set_blob_internal: Trying to store blob metadata.")?;
1509 }
Janis Danisevskis377d1002021-01-27 19:07:48 -08001510 }
1511 (None, SubComponentType::CERT) | (None, SubComponentType::CERT_CHAIN) => {
1512 tx.execute(
1513 "DELETE FROM persistent.blobentry
1514 WHERE subcomponent_type = ? AND keyentryid = ?;",
1515 params![sc_type, key_id],
1516 )
1517 .context("In set_blob_internal: Failed to delete blob.")?;
1518 }
1519 (None, _) => {
1520 return Err(KsError::sys())
1521 .context("In set_blob_internal: Other blobs cannot be deleted in this way.");
1522 }
1523 }
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001524 Ok(())
1525 }
1526
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001527 /// Inserts a collection of key parameters into the `persistent.keyparameter` table
1528 /// and associates them with the given `key_id`.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001529 #[cfg(test)]
1530 fn insert_keyparameter(&mut self, key_id: &KeyIdGuard, params: &[KeyParameter]) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001531 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001532 Self::insert_keyparameter_internal(tx, key_id, params).no_gc()
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001533 })
1534 .context("In insert_keyparameter.")
1535 }
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001536
Janis Danisevskis66784c42021-01-27 08:40:25 -08001537 fn insert_keyparameter_internal(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001538 tx: &Transaction,
1539 key_id: &KeyIdGuard,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001540 params: &[KeyParameter],
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001541 ) -> Result<()> {
1542 let mut stmt = tx
1543 .prepare(
1544 "INSERT into persistent.keyparameter (keyentryid, tag, data, security_level)
1545 VALUES (?, ?, ?, ?);",
1546 )
1547 .context("In insert_keyparameter_internal: Failed to prepare statement.")?;
1548
Janis Danisevskis66784c42021-01-27 08:40:25 -08001549 for p in params.iter() {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001550 stmt.insert(params![
1551 key_id.0,
1552 p.get_tag().0,
1553 p.key_parameter_value(),
1554 p.security_level().0
1555 ])
1556 .with_context(|| {
1557 format!("In insert_keyparameter_internal: Failed to insert {:?}", p)
1558 })?;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001559 }
1560 Ok(())
1561 }
1562
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001563 /// Insert a set of key entry specific metadata into the database.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001564 #[cfg(test)]
1565 fn insert_key_metadata(&mut self, key_id: &KeyIdGuard, metadata: &KeyMetaData) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001566 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001567 metadata.store_in_db(key_id.0, &tx).no_gc()
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001568 })
1569 .context("In insert_key_metadata.")
1570 }
1571
Max Bires2b2e6562020-09-22 11:22:36 -07001572 /// Stores a signed certificate chain signed by a remote provisioning server, keyed
1573 /// on the public key.
1574 pub fn store_signed_attestation_certificate_chain(
1575 &mut self,
1576 raw_public_key: &[u8],
Max Biresb2e1d032021-02-08 21:35:05 -08001577 batch_cert: &[u8],
Max Bires2b2e6562020-09-22 11:22:36 -07001578 cert_chain: &[u8],
1579 expiration_date: i64,
1580 km_uuid: &Uuid,
1581 ) -> Result<()> {
1582 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1583 let mut stmt = tx
1584 .prepare(
1585 "SELECT keyentryid
1586 FROM persistent.keymetadata
1587 WHERE tag = ? AND data = ? AND keyentryid IN
1588 (SELECT id
1589 FROM persistent.keyentry
1590 WHERE
1591 alias IS NULL AND
1592 domain IS NULL AND
1593 namespace IS NULL AND
1594 key_type = ? AND
1595 km_uuid = ?);",
1596 )
1597 .context("Failed to store attestation certificate chain.")?;
1598 let mut rows = stmt
1599 .query(params![
1600 KeyMetaData::AttestationRawPubKey,
1601 raw_public_key,
1602 KeyType::Attestation,
1603 km_uuid
1604 ])
1605 .context("Failed to fetch keyid")?;
1606 let key_id = db_utils::with_rows_extract_one(&mut rows, |row| {
1607 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?
1608 .get(0)
1609 .context("Failed to unpack id.")
1610 })
1611 .context("Failed to get key_id.")?;
1612 let num_updated = tx
1613 .execute(
1614 "UPDATE persistent.keyentry
1615 SET alias = ?
1616 WHERE id = ?;",
1617 params!["signed", key_id],
1618 )
1619 .context("Failed to update alias.")?;
1620 if num_updated != 1 {
1621 return Err(KsError::sys()).context("Alias not updated for the key.");
1622 }
1623 let mut metadata = KeyMetaData::new();
1624 metadata.add(KeyMetaEntry::AttestationExpirationDate(DateTime::from_millis_epoch(
1625 expiration_date,
1626 )));
1627 metadata.store_in_db(key_id, &tx).context("Failed to insert key metadata.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001628 Self::set_blob_internal(
1629 &tx,
1630 key_id,
1631 SubComponentType::CERT_CHAIN,
1632 Some(cert_chain),
1633 None,
1634 )
1635 .context("Failed to insert cert chain")?;
Max Biresb2e1d032021-02-08 21:35:05 -08001636 Self::set_blob_internal(&tx, key_id, SubComponentType::CERT, Some(batch_cert), None)
1637 .context("Failed to insert cert")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001638 Ok(()).no_gc()
Max Bires2b2e6562020-09-22 11:22:36 -07001639 })
1640 .context("In store_signed_attestation_certificate_chain: ")
1641 }
1642
1643 /// Assigns the next unassigned attestation key to a domain/namespace combo that does not
1644 /// currently have a key assigned to it.
1645 pub fn assign_attestation_key(
1646 &mut self,
1647 domain: Domain,
1648 namespace: i64,
1649 km_uuid: &Uuid,
1650 ) -> Result<()> {
1651 match domain {
1652 Domain::APP | Domain::SELINUX => {}
1653 _ => {
1654 return Err(KsError::sys()).context(format!(
1655 concat!(
1656 "In assign_attestation_key: Domain {:?} ",
1657 "must be either App or SELinux.",
1658 ),
1659 domain
1660 ));
1661 }
1662 }
1663 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1664 let result = tx
1665 .execute(
1666 "UPDATE persistent.keyentry
1667 SET domain=?1, namespace=?2
1668 WHERE
1669 id =
1670 (SELECT MIN(id)
1671 FROM persistent.keyentry
1672 WHERE ALIAS IS NOT NULL
1673 AND domain IS NULL
1674 AND key_type IS ?3
1675 AND state IS ?4
1676 AND km_uuid IS ?5)
1677 AND
1678 (SELECT COUNT(*)
1679 FROM persistent.keyentry
1680 WHERE domain=?1
1681 AND namespace=?2
1682 AND key_type IS ?3
1683 AND state IS ?4
1684 AND km_uuid IS ?5) = 0;",
1685 params![
1686 domain.0 as u32,
1687 namespace,
1688 KeyType::Attestation,
1689 KeyLifeCycle::Live,
1690 km_uuid,
1691 ],
1692 )
1693 .context("Failed to assign attestation key")?;
1694 if result != 1 {
1695 return Err(KsError::sys()).context(format!(
1696 "Expected to update a single entry but instead updated {}.",
1697 result
1698 ));
1699 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001700 Ok(()).no_gc()
Max Bires2b2e6562020-09-22 11:22:36 -07001701 })
1702 .context("In assign_attestation_key: ")
1703 }
1704
1705 /// Retrieves num_keys number of attestation keys that have not yet been signed by a remote
1706 /// provisioning server, or the maximum number available if there are not num_keys number of
1707 /// entries in the table.
1708 pub fn fetch_unsigned_attestation_keys(
1709 &mut self,
1710 num_keys: i32,
1711 km_uuid: &Uuid,
1712 ) -> Result<Vec<Vec<u8>>> {
1713 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1714 let mut stmt = tx
1715 .prepare(
1716 "SELECT data
1717 FROM persistent.keymetadata
1718 WHERE tag = ? AND keyentryid IN
1719 (SELECT id
1720 FROM persistent.keyentry
1721 WHERE
1722 alias IS NULL AND
1723 domain IS NULL AND
1724 namespace IS NULL AND
1725 key_type = ? AND
1726 km_uuid = ?
1727 LIMIT ?);",
1728 )
1729 .context("Failed to prepare statement")?;
1730 let rows = stmt
1731 .query_map(
1732 params![
1733 KeyMetaData::AttestationMacedPublicKey,
1734 KeyType::Attestation,
1735 km_uuid,
1736 num_keys
1737 ],
1738 |row| Ok(row.get(0)?),
1739 )?
1740 .collect::<rusqlite::Result<Vec<Vec<u8>>>>()
1741 .context("Failed to execute statement")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001742 Ok(rows).no_gc()
Max Bires2b2e6562020-09-22 11:22:36 -07001743 })
1744 .context("In fetch_unsigned_attestation_keys")
1745 }
1746
1747 /// Removes any keys that have expired as of the current time. Returns the number of keys
1748 /// marked unreferenced that are bound to be garbage collected.
1749 pub fn delete_expired_attestation_keys(&mut self) -> Result<i32> {
1750 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1751 let mut stmt = tx
1752 .prepare(
1753 "SELECT keyentryid, data
1754 FROM persistent.keymetadata
1755 WHERE tag = ? AND keyentryid IN
1756 (SELECT id
1757 FROM persistent.keyentry
1758 WHERE key_type = ?);",
1759 )
1760 .context("Failed to prepare query")?;
1761 let key_ids_to_check = stmt
1762 .query_map(
1763 params![KeyMetaData::AttestationExpirationDate, KeyType::Attestation],
1764 |row| Ok((row.get(0)?, row.get(1)?)),
1765 )?
1766 .collect::<rusqlite::Result<Vec<(i64, DateTime)>>>()
1767 .context("Failed to get date metadata")?;
1768 let curr_time = DateTime::from_millis_epoch(
1769 SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_millis() as i64,
1770 );
1771 let mut num_deleted = 0;
1772 for id in key_ids_to_check.iter().filter(|kt| kt.1 < curr_time).map(|kt| kt.0) {
1773 if Self::mark_unreferenced(&tx, id)? {
1774 num_deleted += 1;
1775 }
1776 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001777 Ok(num_deleted).do_gc(num_deleted != 0)
Max Bires2b2e6562020-09-22 11:22:36 -07001778 })
1779 .context("In delete_expired_attestation_keys: ")
1780 }
1781
Max Bires60d7ed12021-03-05 15:59:22 -08001782 /// Deletes all remotely provisioned attestation keys in the system, regardless of the state
1783 /// they are in. This is useful primarily as a testing mechanism.
1784 pub fn delete_all_attestation_keys(&mut self) -> Result<i64> {
1785 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1786 let mut stmt = tx
1787 .prepare(
1788 "SELECT id FROM persistent.keyentry
1789 WHERE key_type IS ?;",
1790 )
1791 .context("Failed to prepare statement")?;
1792 let keys_to_delete = stmt
1793 .query_map(params![KeyType::Attestation], |row| Ok(row.get(0)?))?
1794 .collect::<rusqlite::Result<Vec<i64>>>()
1795 .context("Failed to execute statement")?;
1796 let num_deleted = keys_to_delete
1797 .iter()
1798 .map(|id| Self::mark_unreferenced(&tx, *id))
1799 .collect::<Result<Vec<bool>>>()
1800 .context("Failed to execute mark_unreferenced on a keyid")?
1801 .into_iter()
1802 .filter(|result| *result)
1803 .count() as i64;
1804 Ok(num_deleted).do_gc(num_deleted != 0)
1805 })
1806 .context("In delete_all_attestation_keys: ")
1807 }
1808
Max Bires2b2e6562020-09-22 11:22:36 -07001809 /// Counts the number of keys that will expire by the provided epoch date and the number of
1810 /// keys not currently assigned to a domain.
1811 pub fn get_attestation_pool_status(
1812 &mut self,
1813 date: i64,
1814 km_uuid: &Uuid,
1815 ) -> Result<AttestationPoolStatus> {
1816 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1817 let mut stmt = tx.prepare(
1818 "SELECT data
1819 FROM persistent.keymetadata
1820 WHERE tag = ? AND keyentryid IN
1821 (SELECT id
1822 FROM persistent.keyentry
1823 WHERE alias IS NOT NULL
1824 AND key_type = ?
1825 AND km_uuid = ?
1826 AND state = ?);",
1827 )?;
1828 let times = stmt
1829 .query_map(
1830 params![
1831 KeyMetaData::AttestationExpirationDate,
1832 KeyType::Attestation,
1833 km_uuid,
1834 KeyLifeCycle::Live
1835 ],
1836 |row| Ok(row.get(0)?),
1837 )?
1838 .collect::<rusqlite::Result<Vec<DateTime>>>()
1839 .context("Failed to execute metadata statement")?;
1840 let expiring =
1841 times.iter().filter(|time| time < &&DateTime::from_millis_epoch(date)).count()
1842 as i32;
1843 stmt = tx.prepare(
1844 "SELECT alias, domain
1845 FROM persistent.keyentry
1846 WHERE key_type = ? AND km_uuid = ? AND state = ?;",
1847 )?;
1848 let rows = stmt
1849 .query_map(params![KeyType::Attestation, km_uuid, KeyLifeCycle::Live], |row| {
1850 Ok((row.get(0)?, row.get(1)?))
1851 })?
1852 .collect::<rusqlite::Result<Vec<(Option<String>, Option<u32>)>>>()
1853 .context("Failed to execute keyentry statement")?;
1854 let mut unassigned = 0i32;
1855 let mut attested = 0i32;
1856 let total = rows.len() as i32;
1857 for (alias, domain) in rows {
1858 match (alias, domain) {
1859 (Some(_alias), None) => {
1860 attested += 1;
1861 unassigned += 1;
1862 }
1863 (Some(_alias), Some(_domain)) => {
1864 attested += 1;
1865 }
1866 _ => {}
1867 }
1868 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001869 Ok(AttestationPoolStatus { expiring, unassigned, attested, total }).no_gc()
Max Bires2b2e6562020-09-22 11:22:36 -07001870 })
1871 .context("In get_attestation_pool_status: ")
1872 }
1873
1874 /// Fetches the private key and corresponding certificate chain assigned to a
1875 /// domain/namespace pair. Will either return nothing if the domain/namespace is
1876 /// not assigned, or one CertificateChain.
1877 pub fn retrieve_attestation_key_and_cert_chain(
1878 &mut self,
1879 domain: Domain,
1880 namespace: i64,
1881 km_uuid: &Uuid,
1882 ) -> Result<Option<CertificateChain>> {
1883 match domain {
1884 Domain::APP | Domain::SELINUX => {}
1885 _ => {
1886 return Err(KsError::sys())
1887 .context(format!("Domain {:?} must be either App or SELinux.", domain));
1888 }
1889 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001890 self.with_transaction(TransactionBehavior::Deferred, |tx| {
1891 let mut stmt = tx.prepare(
1892 "SELECT subcomponent_type, blob
Max Bires2b2e6562020-09-22 11:22:36 -07001893 FROM persistent.blobentry
1894 WHERE keyentryid IN
1895 (SELECT id
1896 FROM persistent.keyentry
1897 WHERE key_type = ?
1898 AND domain = ?
1899 AND namespace = ?
1900 AND state = ?
1901 AND km_uuid = ?);",
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001902 )?;
1903 let rows = stmt
1904 .query_map(
1905 params![
1906 KeyType::Attestation,
1907 domain.0 as u32,
1908 namespace,
1909 KeyLifeCycle::Live,
1910 km_uuid
1911 ],
1912 |row| Ok((row.get(0)?, row.get(1)?)),
1913 )?
1914 .collect::<rusqlite::Result<Vec<(SubComponentType, Vec<u8>)>>>()
Max Biresb2e1d032021-02-08 21:35:05 -08001915 .context("query failed.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001916 if rows.is_empty() {
1917 return Ok(None).no_gc();
Max Biresb2e1d032021-02-08 21:35:05 -08001918 } else if rows.len() != 3 {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001919 return Err(KsError::sys()).context(format!(
1920 concat!(
Max Biresb2e1d032021-02-08 21:35:05 -08001921 "Expected to get a single attestation",
1922 "key, cert, and cert chain for a total of 3 entries, but instead got {}."
1923 ),
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001924 rows.len()
1925 ));
Max Bires2b2e6562020-09-22 11:22:36 -07001926 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001927 let mut km_blob: Vec<u8> = Vec::new();
1928 let mut cert_chain_blob: Vec<u8> = Vec::new();
Max Biresb2e1d032021-02-08 21:35:05 -08001929 let mut batch_cert_blob: Vec<u8> = Vec::new();
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001930 for row in rows {
1931 let sub_type: SubComponentType = row.0;
1932 match sub_type {
1933 SubComponentType::KEY_BLOB => {
1934 km_blob = row.1;
1935 }
1936 SubComponentType::CERT_CHAIN => {
1937 cert_chain_blob = row.1;
1938 }
Max Biresb2e1d032021-02-08 21:35:05 -08001939 SubComponentType::CERT => {
1940 batch_cert_blob = row.1;
1941 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001942 _ => Err(KsError::sys()).context("Unknown or incorrect subcomponent type.")?,
1943 }
1944 }
1945 Ok(Some(CertificateChain {
1946 private_key: ZVec::try_from(km_blob)?,
Max Bires97f96812021-02-23 23:44:57 -08001947 batch_cert: batch_cert_blob,
1948 cert_chain: cert_chain_blob,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001949 }))
1950 .no_gc()
1951 })
Max Biresb2e1d032021-02-08 21:35:05 -08001952 .context("In retrieve_attestation_key_and_cert_chain:")
Max Bires2b2e6562020-09-22 11:22:36 -07001953 }
1954
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001955 /// Updates the alias column of the given key id `newid` with the given alias,
1956 /// and atomically, removes the alias, domain, and namespace from another row
1957 /// with the same alias-domain-namespace tuple if such row exits.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001958 /// Returns Ok(true) if an old key was marked unreferenced as a hint to the garbage
1959 /// collector.
1960 fn rebind_alias(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001961 tx: &Transaction,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001962 newid: &KeyIdGuard,
Joel Galenson33c04ad2020-08-03 11:04:38 -07001963 alias: &str,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001964 domain: &Domain,
1965 namespace: &i64,
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001966 ) -> Result<bool> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001967 match *domain {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001968 Domain::APP | Domain::SELINUX => {}
Joel Galenson33c04ad2020-08-03 11:04:38 -07001969 _ => {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001970 return Err(KsError::sys()).context(format!(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001971 "In rebind_alias: Domain {:?} must be either App or SELinux.",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001972 domain
1973 ));
Joel Galenson33c04ad2020-08-03 11:04:38 -07001974 }
1975 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001976 let updated = tx
1977 .execute(
1978 "UPDATE persistent.keyentry
1979 SET alias = NULL, domain = NULL, namespace = NULL, state = ?
Joel Galenson33c04ad2020-08-03 11:04:38 -07001980 WHERE alias = ? AND domain = ? AND namespace = ?;",
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001981 params![KeyLifeCycle::Unreferenced, alias, domain.0 as u32, namespace],
1982 )
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001983 .context("In rebind_alias: Failed to rebind existing entry.")?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07001984 let result = tx
1985 .execute(
1986 "UPDATE persistent.keyentry
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001987 SET alias = ?, state = ?
1988 WHERE id = ? AND domain = ? AND namespace = ? AND state = ?;",
1989 params![
1990 alias,
1991 KeyLifeCycle::Live,
1992 newid.0,
1993 domain.0 as u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001994 *namespace,
Max Bires8e93d2b2021-01-14 13:17:59 -08001995 KeyLifeCycle::Existing,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001996 ],
Joel Galenson33c04ad2020-08-03 11:04:38 -07001997 )
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001998 .context("In rebind_alias: Failed to set alias.")?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07001999 if result != 1 {
Joel Galenson33c04ad2020-08-03 11:04:38 -07002000 return Err(KsError::sys()).context(format!(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002001 "In rebind_alias: Expected to update a single entry but instead updated {}.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07002002 result
2003 ));
2004 }
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002005 Ok(updated != 0)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002006 }
2007
2008 /// Store a new key in a single transaction.
2009 /// The function creates a new key entry, populates the blob, key parameter, and metadata
2010 /// fields, and rebinds the given alias to the new key.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002011 /// The boolean returned is a hint for the garbage collector. If true, a key was replaced,
2012 /// is now unreferenced and needs to be collected.
Janis Danisevskis66784c42021-01-27 08:40:25 -08002013 pub fn store_new_key(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002014 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002015 key: &KeyDescriptor,
2016 params: &[KeyParameter],
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002017 blob_info: &(&[u8], &BlobMetaData),
Max Bires8e93d2b2021-01-14 13:17:59 -08002018 cert_info: &CertificateInfo,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002019 metadata: &KeyMetaData,
Max Bires8e93d2b2021-01-14 13:17:59 -08002020 km_uuid: &Uuid,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002021 ) -> Result<KeyIdGuard> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002022 let (alias, domain, namespace) = match key {
2023 KeyDescriptor { alias: Some(alias), domain: Domain::APP, nspace, blob: None }
2024 | KeyDescriptor { alias: Some(alias), domain: Domain::SELINUX, nspace, blob: None } => {
2025 (alias, key.domain, nspace)
2026 }
2027 _ => {
2028 return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT))
2029 .context("In store_new_key: Need alias and domain must be APP or SELINUX.")
2030 }
2031 };
2032 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002033 let key_id = Self::create_key_entry_internal(tx, &domain, namespace, km_uuid)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002034 .context("Trying to create new key entry.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002035 let (blob, blob_metadata) = *blob_info;
2036 Self::set_blob_internal(
2037 tx,
2038 key_id.id(),
2039 SubComponentType::KEY_BLOB,
2040 Some(blob),
2041 Some(&blob_metadata),
2042 )
2043 .context("Trying to insert the key blob.")?;
Max Bires8e93d2b2021-01-14 13:17:59 -08002044 if let Some(cert) = &cert_info.cert {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002045 Self::set_blob_internal(tx, key_id.id(), SubComponentType::CERT, Some(&cert), None)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002046 .context("Trying to insert the certificate.")?;
2047 }
Max Bires8e93d2b2021-01-14 13:17:59 -08002048 if let Some(cert_chain) = &cert_info.cert_chain {
Janis Danisevskis377d1002021-01-27 19:07:48 -08002049 Self::set_blob_internal(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002050 tx,
2051 key_id.id(),
2052 SubComponentType::CERT_CHAIN,
Janis Danisevskis377d1002021-01-27 19:07:48 -08002053 Some(&cert_chain),
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002054 None,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002055 )
2056 .context("Trying to insert the certificate chain.")?;
2057 }
2058 Self::insert_keyparameter_internal(tx, &key_id, params)
2059 .context("Trying to insert key parameters.")?;
Janis Danisevskis377d1002021-01-27 19:07:48 -08002060 metadata.store_in_db(key_id.id(), tx).context("Trying to insert key metadata.")?;
Janis Danisevskis66784c42021-01-27 08:40:25 -08002061 let need_gc = Self::rebind_alias(tx, &key_id, &alias, &domain, namespace)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002062 .context("Trying to rebind alias.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002063 Ok(key_id).do_gc(need_gc)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002064 })
2065 .context("In store_new_key.")
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002066 }
2067
Janis Danisevskis377d1002021-01-27 19:07:48 -08002068 /// Store a new certificate
2069 /// The function creates a new key entry, populates the blob field and metadata, and rebinds
2070 /// the given alias to the new cert.
Max Bires8e93d2b2021-01-14 13:17:59 -08002071 pub fn store_new_certificate(
2072 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002073 key: &KeyDescriptor,
Max Bires8e93d2b2021-01-14 13:17:59 -08002074 cert: &[u8],
2075 km_uuid: &Uuid,
2076 ) -> Result<KeyIdGuard> {
Janis Danisevskis377d1002021-01-27 19:07:48 -08002077 let (alias, domain, namespace) = match key {
2078 KeyDescriptor { alias: Some(alias), domain: Domain::APP, nspace, blob: None }
2079 | KeyDescriptor { alias: Some(alias), domain: Domain::SELINUX, nspace, blob: None } => {
2080 (alias, key.domain, nspace)
2081 }
2082 _ => {
2083 return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT)).context(
2084 "In store_new_certificate: Need alias and domain must be APP or SELINUX.",
2085 )
2086 }
2087 };
2088 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002089 let key_id = Self::create_key_entry_internal(tx, &domain, namespace, km_uuid)
Janis Danisevskis377d1002021-01-27 19:07:48 -08002090 .context("Trying to create new key entry.")?;
2091
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002092 Self::set_blob_internal(
2093 tx,
2094 key_id.id(),
2095 SubComponentType::CERT_CHAIN,
2096 Some(cert),
2097 None,
2098 )
2099 .context("Trying to insert certificate.")?;
Janis Danisevskis377d1002021-01-27 19:07:48 -08002100
2101 let mut metadata = KeyMetaData::new();
2102 metadata.add(KeyMetaEntry::CreationDate(
2103 DateTime::now().context("Trying to make creation time.")?,
2104 ));
2105
2106 metadata.store_in_db(key_id.id(), tx).context("Trying to insert key metadata.")?;
2107
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002108 let need_gc = Self::rebind_alias(tx, &key_id, &alias, &domain, namespace)
Janis Danisevskis377d1002021-01-27 19:07:48 -08002109 .context("Trying to rebind alias.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002110 Ok(key_id).do_gc(need_gc)
Janis Danisevskis377d1002021-01-27 19:07:48 -08002111 })
2112 .context("In store_new_certificate.")
2113 }
2114
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002115 // Helper function loading the key_id given the key descriptor
2116 // tuple comprising domain, namespace, and alias.
2117 // Requires a valid transaction.
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002118 fn load_key_entry_id(tx: &Transaction, key: &KeyDescriptor, key_type: KeyType) -> Result<i64> {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002119 let alias = key
2120 .alias
2121 .as_ref()
2122 .map_or_else(|| Err(KsError::sys()), Ok)
2123 .context("In load_key_entry_id: Alias must be specified.")?;
2124 let mut stmt = tx
2125 .prepare(
2126 "SELECT id FROM persistent.keyentry
2127 WHERE
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00002128 key_type = ?
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002129 AND domain = ?
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002130 AND namespace = ?
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002131 AND alias = ?
2132 AND state = ?;",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002133 )
2134 .context("In load_key_entry_id: Failed to select from keyentry table.")?;
2135 let mut rows = stmt
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002136 .query(params![key_type, key.domain.0 as u32, key.nspace, alias, KeyLifeCycle::Live])
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002137 .context("In load_key_entry_id: Failed to read from keyentry table.")?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002138 db_utils::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002139 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002140 .get(0)
2141 .context("Failed to unpack id.")
2142 })
2143 .context("In load_key_entry_id.")
2144 }
2145
2146 /// This helper function completes the access tuple of a key, which is required
2147 /// to perform access control. The strategy depends on the `domain` field in the
2148 /// key descriptor.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002149 /// * Domain::SELINUX: The access tuple is complete and this function only loads
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002150 /// the key_id for further processing.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002151 /// * Domain::APP: Like Domain::SELINUX, but the tuple is completed by `caller_uid`
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002152 /// which serves as the namespace.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002153 /// * Domain::GRANT: The grant table is queried for the `key_id` and the
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002154 /// `access_vector`.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002155 /// * Domain::KEY_ID: The keyentry table is queried for the owning `domain` and
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002156 /// `namespace`.
2157 /// In each case the information returned is sufficient to perform the access
2158 /// check and the key id can be used to load further key artifacts.
2159 fn load_access_tuple(
2160 tx: &Transaction,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002161 key: &KeyDescriptor,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002162 key_type: KeyType,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002163 caller_uid: u32,
2164 ) -> Result<(i64, KeyDescriptor, Option<KeyPermSet>)> {
2165 match key.domain {
2166 // Domain App or SELinux. In this case we load the key_id from
2167 // the keyentry database for further loading of key components.
2168 // We already have the full access tuple to perform access control.
2169 // The only distinction is that we use the caller_uid instead
2170 // of the caller supplied namespace if the domain field is
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002171 // Domain::APP.
2172 Domain::APP | Domain::SELINUX => {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002173 let mut access_key = key.clone();
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002174 if access_key.domain == Domain::APP {
2175 access_key.nspace = caller_uid as i64;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002176 }
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002177 let key_id = Self::load_key_entry_id(&tx, &access_key, key_type)
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002178 .with_context(|| format!("With key.domain = {:?}.", access_key.domain))?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002179
2180 Ok((key_id, access_key, None))
2181 }
2182
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002183 // Domain::GRANT. In this case we load the key_id and the access_vector
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002184 // from the grant table.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002185 Domain::GRANT => {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002186 let mut stmt = tx
2187 .prepare(
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002188 "SELECT keyentryid, access_vector FROM persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002189 WHERE grantee = ? AND id = ?;",
2190 )
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002191 .context("Domain::GRANT prepare statement failed")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002192 let mut rows = stmt
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002193 .query(params![caller_uid as i64, key.nspace])
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002194 .context("Domain:Grant: query failed.")?;
2195 let (key_id, access_vector): (i64, i32) =
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002196 db_utils::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002197 let r =
2198 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002199 Ok((
2200 r.get(0).context("Failed to unpack key_id.")?,
2201 r.get(1).context("Failed to unpack access_vector.")?,
2202 ))
2203 })
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002204 .context("Domain::GRANT.")?;
Janis Danisevskis66784c42021-01-27 08:40:25 -08002205 Ok((key_id, key.clone(), Some(access_vector.into())))
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002206 }
2207
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002208 // Domain::KEY_ID. In this case we load the domain and namespace from the
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002209 // keyentry database because we need them for access control.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002210 Domain::KEY_ID => {
Janis Danisevskis45760022021-01-19 16:34:10 -08002211 let (domain, namespace): (Domain, i64) = {
2212 let mut stmt = tx
2213 .prepare(
2214 "SELECT domain, namespace FROM persistent.keyentry
2215 WHERE
2216 id = ?
2217 AND state = ?;",
2218 )
2219 .context("Domain::KEY_ID: prepare statement failed")?;
2220 let mut rows = stmt
2221 .query(params![key.nspace, KeyLifeCycle::Live])
2222 .context("Domain::KEY_ID: query failed.")?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002223 db_utils::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002224 let r =
2225 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002226 Ok((
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002227 Domain(r.get(0).context("Failed to unpack domain.")?),
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002228 r.get(1).context("Failed to unpack namespace.")?,
2229 ))
2230 })
Janis Danisevskis45760022021-01-19 16:34:10 -08002231 .context("Domain::KEY_ID.")?
2232 };
2233
2234 // We may use a key by id after loading it by grant.
2235 // In this case we have to check if the caller has a grant for this particular
2236 // key. We can skip this if we already know that the caller is the owner.
2237 // But we cannot know this if domain is anything but App. E.g. in the case
2238 // of Domain::SELINUX we have to speculatively check for grants because we have to
2239 // consult the SEPolicy before we know if the caller is the owner.
2240 let access_vector: Option<KeyPermSet> =
2241 if domain != Domain::APP || namespace != caller_uid as i64 {
2242 let access_vector: Option<i32> = tx
2243 .query_row(
2244 "SELECT access_vector FROM persistent.grant
2245 WHERE grantee = ? AND keyentryid = ?;",
2246 params![caller_uid as i64, key.nspace],
2247 |row| row.get(0),
2248 )
2249 .optional()
2250 .context("Domain::KEY_ID: query grant failed.")?;
2251 access_vector.map(|p| p.into())
2252 } else {
2253 None
2254 };
2255
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002256 let key_id = key.nspace;
Janis Danisevskis66784c42021-01-27 08:40:25 -08002257 let mut access_key: KeyDescriptor = key.clone();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002258 access_key.domain = domain;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002259 access_key.nspace = namespace;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002260
Janis Danisevskis45760022021-01-19 16:34:10 -08002261 Ok((key_id, access_key, access_vector))
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002262 }
2263 _ => Err(anyhow!(KsError::sys())),
2264 }
2265 }
2266
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002267 fn load_blob_components(
2268 key_id: i64,
2269 load_bits: KeyEntryLoadBits,
2270 tx: &Transaction,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002271 ) -> Result<(bool, Option<(Vec<u8>, BlobMetaData)>, Option<Vec<u8>>, Option<Vec<u8>>)> {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002272 let mut stmt = tx
2273 .prepare(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002274 "SELECT MAX(id), subcomponent_type, blob FROM persistent.blobentry
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002275 WHERE keyentryid = ? GROUP BY subcomponent_type;",
2276 )
2277 .context("In load_blob_components: prepare statement failed.")?;
2278
2279 let mut rows =
2280 stmt.query(params![key_id]).context("In load_blob_components: query failed.")?;
2281
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002282 let mut key_blob: Option<(i64, Vec<u8>)> = None;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002283 let mut cert_blob: Option<Vec<u8>> = None;
2284 let mut cert_chain_blob: Option<Vec<u8>> = None;
Janis Danisevskis377d1002021-01-27 19:07:48 -08002285 let mut has_km_blob: bool = false;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002286 db_utils::with_rows_extract_all(&mut rows, |row| {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002287 let sub_type: SubComponentType =
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002288 row.get(1).context("Failed to extract subcomponent_type.")?;
Janis Danisevskis377d1002021-01-27 19:07:48 -08002289 has_km_blob = has_km_blob || sub_type == SubComponentType::KEY_BLOB;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002290 match (sub_type, load_bits.load_public(), load_bits.load_km()) {
2291 (SubComponentType::KEY_BLOB, _, true) => {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002292 key_blob = Some((
2293 row.get(0).context("Failed to extract key blob id.")?,
2294 row.get(2).context("Failed to extract key blob.")?,
2295 ));
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002296 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002297 (SubComponentType::CERT, true, _) => {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002298 cert_blob =
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002299 Some(row.get(2).context("Failed to extract public certificate blob.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002300 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002301 (SubComponentType::CERT_CHAIN, true, _) => {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002302 cert_chain_blob =
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002303 Some(row.get(2).context("Failed to extract certificate chain blob.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002304 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002305 (SubComponentType::CERT, _, _)
2306 | (SubComponentType::CERT_CHAIN, _, _)
2307 | (SubComponentType::KEY_BLOB, _, _) => {}
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002308 _ => Err(KsError::sys()).context("Unknown subcomponent type.")?,
2309 }
2310 Ok(())
2311 })
2312 .context("In load_blob_components.")?;
2313
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002314 let blob_info = key_blob.map_or::<Result<_>, _>(Ok(None), |(blob_id, blob)| {
2315 Ok(Some((
2316 blob,
2317 BlobMetaData::load_from_db(blob_id, tx)
2318 .context("In load_blob_components: Trying to load blob_metadata.")?,
2319 )))
2320 })?;
2321
2322 Ok((has_km_blob, blob_info, cert_blob, cert_chain_blob))
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002323 }
2324
2325 fn load_key_parameters(key_id: i64, tx: &Transaction) -> Result<Vec<KeyParameter>> {
2326 let mut stmt = tx
2327 .prepare(
2328 "SELECT tag, data, security_level from persistent.keyparameter
2329 WHERE keyentryid = ?;",
2330 )
2331 .context("In load_key_parameters: prepare statement failed.")?;
2332
2333 let mut parameters: Vec<KeyParameter> = Vec::new();
2334
2335 let mut rows =
2336 stmt.query(params![key_id]).context("In load_key_parameters: query failed.")?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002337 db_utils::with_rows_extract_all(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002338 let tag = Tag(row.get(0).context("Failed to read tag.")?);
2339 let sec_level = SecurityLevel(row.get(2).context("Failed to read sec_level.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002340 parameters.push(
2341 KeyParameter::new_from_sql(tag, &SqlField::new(1, &row), sec_level)
2342 .context("Failed to read KeyParameter.")?,
2343 );
2344 Ok(())
2345 })
2346 .context("In load_key_parameters.")?;
2347
2348 Ok(parameters)
2349 }
2350
Qi Wub9433b52020-12-01 14:52:46 +08002351 /// Decrements the usage count of a limited use key. This function first checks whether the
2352 /// usage has been exhausted, if not, decreases the usage count. If the usage count reaches
2353 /// zero, the key also gets marked unreferenced and scheduled for deletion.
2354 /// Returns Ok(true) if the key was marked unreferenced as a hint to the garbage collector.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002355 pub fn check_and_update_key_usage_count(&mut self, key_id: i64) -> Result<()> {
Qi Wub9433b52020-12-01 14:52:46 +08002356 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2357 let limit: Option<i32> = tx
2358 .query_row(
2359 "SELECT data FROM persistent.keyparameter WHERE keyentryid = ? AND tag = ?;",
2360 params![key_id, Tag::USAGE_COUNT_LIMIT.0],
2361 |row| row.get(0),
2362 )
2363 .optional()
2364 .context("Trying to load usage count")?;
2365
2366 let limit = limit
2367 .ok_or(KsError::Km(ErrorCode::INVALID_KEY_BLOB))
2368 .context("The Key no longer exists. Key is exhausted.")?;
2369
2370 tx.execute(
2371 "UPDATE persistent.keyparameter
2372 SET data = data - 1
2373 WHERE keyentryid = ? AND tag = ? AND data > 0;",
2374 params![key_id, Tag::USAGE_COUNT_LIMIT.0],
2375 )
2376 .context("Failed to update key usage count.")?;
2377
2378 match limit {
2379 1 => Self::mark_unreferenced(tx, key_id)
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002380 .map(|need_gc| (need_gc, ()))
Qi Wub9433b52020-12-01 14:52:46 +08002381 .context("Trying to mark limited use key for deletion."),
2382 0 => Err(KsError::Km(ErrorCode::INVALID_KEY_BLOB)).context("Key is exhausted."),
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002383 _ => Ok(()).no_gc(),
Qi Wub9433b52020-12-01 14:52:46 +08002384 }
2385 })
2386 .context("In check_and_update_key_usage_count.")
2387 }
2388
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002389 /// Load a key entry by the given key descriptor.
2390 /// It uses the `check_permission` callback to verify if the access is allowed
2391 /// given the key access tuple read from the database using `load_access_tuple`.
2392 /// With `load_bits` the caller may specify which blobs shall be loaded from
2393 /// the blob database.
2394 pub fn load_key_entry(
2395 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002396 key: &KeyDescriptor,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002397 key_type: KeyType,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002398 load_bits: KeyEntryLoadBits,
2399 caller_uid: u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002400 check_permission: impl Fn(&KeyDescriptor, Option<KeyPermSet>) -> Result<()>,
2401 ) -> Result<(KeyIdGuard, KeyEntry)> {
2402 loop {
2403 match self.load_key_entry_internal(
2404 key,
2405 key_type,
2406 load_bits,
2407 caller_uid,
2408 &check_permission,
2409 ) {
2410 Ok(result) => break Ok(result),
2411 Err(e) => {
2412 if Self::is_locked_error(&e) {
2413 std::thread::sleep(std::time::Duration::from_micros(500));
2414 continue;
2415 } else {
2416 return Err(e).context("In load_key_entry.");
2417 }
2418 }
2419 }
2420 }
2421 }
2422
2423 fn load_key_entry_internal(
2424 &mut self,
2425 key: &KeyDescriptor,
2426 key_type: KeyType,
2427 load_bits: KeyEntryLoadBits,
2428 caller_uid: u32,
2429 check_permission: &impl Fn(&KeyDescriptor, Option<KeyPermSet>) -> Result<()>,
Janis Danisevskisaec14592020-11-12 09:41:49 -08002430 ) -> Result<(KeyIdGuard, KeyEntry)> {
2431 // KEY ID LOCK 1/2
2432 // If we got a key descriptor with a key id we can get the lock right away.
2433 // Otherwise we have to defer it until we know the key id.
2434 let key_id_guard = match key.domain {
2435 Domain::KEY_ID => Some(KEY_ID_LOCK.get(key.nspace)),
2436 _ => None,
2437 };
2438
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002439 let tx = self
2440 .conn
Janis Danisevskisaec14592020-11-12 09:41:49 -08002441 .unchecked_transaction()
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002442 .context("In load_key_entry: Failed to initialize transaction.")?;
2443
2444 // Load the key_id and complete the access control tuple.
2445 let (key_id, access_key_descriptor, access_vector) =
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002446 Self::load_access_tuple(&tx, key, key_type, caller_uid)
2447 .context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002448
2449 // Perform access control. It is vital that we return here if the permission is denied.
2450 // So do not touch that '?' at the end.
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002451 check_permission(&access_key_descriptor, access_vector).context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002452
Janis Danisevskisaec14592020-11-12 09:41:49 -08002453 // KEY ID LOCK 2/2
2454 // If we did not get a key id lock by now, it was because we got a key descriptor
2455 // without a key id. At this point we got the key id, so we can try and get a lock.
2456 // However, we cannot block here, because we are in the middle of the transaction.
2457 // So first we try to get the lock non blocking. If that fails, we roll back the
2458 // transaction and block until we get the lock. After we successfully got the lock,
2459 // we start a new transaction and load the access tuple again.
2460 //
2461 // We don't need to perform access control again, because we already established
2462 // that the caller had access to the given key. But we need to make sure that the
2463 // key id still exists. So we have to load the key entry by key id this time.
2464 let (key_id_guard, tx) = match key_id_guard {
2465 None => match KEY_ID_LOCK.try_get(key_id) {
2466 None => {
2467 // Roll back the transaction.
2468 tx.rollback().context("In load_key_entry: Failed to roll back transaction.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002469
Janis Danisevskisaec14592020-11-12 09:41:49 -08002470 // Block until we have a key id lock.
2471 let key_id_guard = KEY_ID_LOCK.get(key_id);
2472
2473 // Create a new transaction.
Janis Danisevskis66784c42021-01-27 08:40:25 -08002474 let tx = self
2475 .conn
2476 .unchecked_transaction()
2477 .context("In load_key_entry: Failed to initialize transaction.")?;
Janis Danisevskisaec14592020-11-12 09:41:49 -08002478
2479 Self::load_access_tuple(
2480 &tx,
2481 // This time we have to load the key by the retrieved key id, because the
2482 // alias may have been rebound after we rolled back the transaction.
Janis Danisevskis66784c42021-01-27 08:40:25 -08002483 &KeyDescriptor {
Janis Danisevskisaec14592020-11-12 09:41:49 -08002484 domain: Domain::KEY_ID,
2485 nspace: key_id,
2486 ..Default::default()
2487 },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002488 key_type,
Janis Danisevskisaec14592020-11-12 09:41:49 -08002489 caller_uid,
2490 )
2491 .context("In load_key_entry. (deferred key lock)")?;
2492 (key_id_guard, tx)
2493 }
2494 Some(l) => (l, tx),
2495 },
2496 Some(key_id_guard) => (key_id_guard, tx),
2497 };
2498
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002499 let key_entry = Self::load_key_components(&tx, load_bits, key_id_guard.id())
2500 .context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002501
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002502 tx.commit().context("In load_key_entry: Failed to commit transaction.")?;
2503
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002504 Ok((key_id_guard, key_entry))
2505 }
2506
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002507 fn mark_unreferenced(tx: &Transaction, key_id: i64) -> Result<bool> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002508 let updated = tx
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002509 .execute("DELETE FROM persistent.keyentry WHERE id = ?;", params![key_id])
2510 .context("Trying to delete keyentry.")?;
2511 tx.execute("DELETE FROM persistent.keymetadata WHERE keyentryid = ?;", params![key_id])
2512 .context("Trying to delete keymetadata.")?;
2513 tx.execute("DELETE FROM persistent.keyparameter WHERE keyentryid = ?;", params![key_id])
2514 .context("Trying to delete keyparameters.")?;
2515 tx.execute("DELETE FROM persistent.grant WHERE keyentryid = ?;", params![key_id])
2516 .context("Trying to delete grants.")?;
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002517 Ok(updated != 0)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002518 }
2519
2520 /// Marks the given key as unreferenced and removes all of the grants to this key.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002521 /// Returns Ok(true) if a key was marked unreferenced as a hint for the garbage collector.
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002522 pub fn unbind_key(
2523 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002524 key: &KeyDescriptor,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002525 key_type: KeyType,
2526 caller_uid: u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002527 check_permission: impl Fn(&KeyDescriptor, Option<KeyPermSet>) -> Result<()>,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002528 ) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002529 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2530 let (key_id, access_key_descriptor, access_vector) =
2531 Self::load_access_tuple(tx, key, key_type, caller_uid)
2532 .context("Trying to get access tuple.")?;
2533
2534 // Perform access control. It is vital that we return here if the permission is denied.
2535 // So do not touch that '?' at the end.
2536 check_permission(&access_key_descriptor, access_vector)
2537 .context("While checking permission.")?;
2538
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002539 Self::mark_unreferenced(tx, key_id)
2540 .map(|need_gc| (need_gc, ()))
2541 .context("Trying to mark the key unreferenced.")
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002542 })
2543 .context("In unbind_key.")
2544 }
2545
Max Bires8e93d2b2021-01-14 13:17:59 -08002546 fn get_key_km_uuid(tx: &Transaction, key_id: i64) -> Result<Uuid> {
2547 tx.query_row(
2548 "SELECT km_uuid FROM persistent.keyentry WHERE id = ?",
2549 params![key_id],
2550 |row| row.get(0),
2551 )
2552 .context("In get_key_km_uuid.")
2553 }
2554
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002555 /// Delete all artifacts belonging to the namespace given by the domain-namespace tuple.
2556 /// This leaves all of the blob entries orphaned for subsequent garbage collection.
2557 pub fn unbind_keys_for_namespace(&mut self, domain: Domain, namespace: i64) -> Result<()> {
2558 if !(domain == Domain::APP || domain == Domain::SELINUX) {
2559 return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT))
2560 .context("In unbind_keys_for_namespace.");
2561 }
2562 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2563 tx.execute(
2564 "DELETE FROM persistent.keymetadata
2565 WHERE keyentryid IN (
2566 SELECT id FROM persistent.keyentry
2567 WHERE domain = ? AND namespace = ?
2568 );",
2569 params![domain.0, namespace],
2570 )
2571 .context("Trying to delete keymetadata.")?;
2572 tx.execute(
2573 "DELETE FROM persistent.keyparameter
2574 WHERE keyentryid IN (
2575 SELECT id FROM persistent.keyentry
2576 WHERE domain = ? AND namespace = ?
2577 );",
2578 params![domain.0, namespace],
2579 )
2580 .context("Trying to delete keyparameters.")?;
2581 tx.execute(
2582 "DELETE FROM persistent.grant
2583 WHERE keyentryid IN (
2584 SELECT id FROM persistent.keyentry
2585 WHERE domain = ? AND namespace = ?
2586 );",
2587 params![domain.0, namespace],
2588 )
2589 .context("Trying to delete grants.")?;
2590 tx.execute(
2591 "DELETE FROM persistent.keyentry WHERE domain = ? AND namespace = ?;",
2592 params![domain.0, namespace],
2593 )
2594 .context("Trying to delete keyentry.")?;
2595 Ok(()).need_gc()
2596 })
2597 .context("In unbind_keys_for_namespace")
2598 }
2599
Hasini Gunasingheda895552021-01-27 19:34:37 +00002600 /// Delete the keys created on behalf of the user, denoted by the user id.
2601 /// Delete all the keys unless 'keep_non_super_encrypted_keys' set to true.
2602 /// Returned boolean is to hint the garbage collector to delete the unbound keys.
2603 /// The caller of this function should notify the gc if the returned value is true.
2604 pub fn unbind_keys_for_user(
2605 &mut self,
2606 user_id: u32,
2607 keep_non_super_encrypted_keys: bool,
2608 ) -> Result<()> {
2609 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2610 let mut stmt = tx
2611 .prepare(&format!(
2612 "SELECT id from persistent.keyentry
2613 WHERE (
2614 key_type = ?
2615 AND domain = ?
2616 AND cast ( (namespace/{aid_user_offset}) as int) = ?
2617 AND state = ?
2618 ) OR (
2619 key_type = ?
2620 AND namespace = ?
2621 AND alias = ?
2622 AND state = ?
2623 );",
2624 aid_user_offset = AID_USER_OFFSET
2625 ))
2626 .context(concat!(
2627 "In unbind_keys_for_user. ",
2628 "Failed to prepare the query to find the keys created by apps."
2629 ))?;
2630
2631 let mut rows = stmt
2632 .query(params![
2633 // WHERE client key:
2634 KeyType::Client,
2635 Domain::APP.0 as u32,
2636 user_id,
2637 KeyLifeCycle::Live,
2638 // OR super key:
2639 KeyType::Super,
2640 user_id,
2641 Self::USER_SUPER_KEY_ALIAS,
2642 KeyLifeCycle::Live
2643 ])
2644 .context("In unbind_keys_for_user. Failed to query the keys created by apps.")?;
2645
2646 let mut key_ids: Vec<i64> = Vec::new();
2647 db_utils::with_rows_extract_all(&mut rows, |row| {
2648 key_ids
2649 .push(row.get(0).context("Failed to read key id of a key created by an app.")?);
2650 Ok(())
2651 })
2652 .context("In unbind_keys_for_user.")?;
2653
2654 let mut notify_gc = false;
2655 for key_id in key_ids {
2656 if keep_non_super_encrypted_keys {
2657 // Load metadata and filter out non-super-encrypted keys.
2658 if let (_, Some((_, blob_metadata)), _, _) =
2659 Self::load_blob_components(key_id, KeyEntryLoadBits::KM, tx)
2660 .context("In unbind_keys_for_user: Trying to load blob info.")?
2661 {
2662 if blob_metadata.encrypted_by().is_none() {
2663 continue;
2664 }
2665 }
2666 }
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +00002667 notify_gc = Self::mark_unreferenced(&tx, key_id)
Hasini Gunasingheda895552021-01-27 19:34:37 +00002668 .context("In unbind_keys_for_user.")?
2669 || notify_gc;
2670 }
2671 Ok(()).do_gc(notify_gc)
2672 })
2673 .context("In unbind_keys_for_user.")
2674 }
2675
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002676 fn load_key_components(
2677 tx: &Transaction,
2678 load_bits: KeyEntryLoadBits,
2679 key_id: i64,
2680 ) -> Result<KeyEntry> {
2681 let metadata = KeyMetaData::load_from_db(key_id, &tx).context("In load_key_components.")?;
2682
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002683 let (has_km_blob, key_blob_info, cert_blob, cert_chain_blob) =
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002684 Self::load_blob_components(key_id, load_bits, &tx)
2685 .context("In load_key_components.")?;
2686
Max Bires8e93d2b2021-01-14 13:17:59 -08002687 let parameters = Self::load_key_parameters(key_id, &tx)
2688 .context("In load_key_components: Trying to load key parameters.")?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002689
Max Bires8e93d2b2021-01-14 13:17:59 -08002690 let km_uuid = Self::get_key_km_uuid(&tx, key_id)
2691 .context("In load_key_components: Trying to get KM uuid.")?;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002692
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002693 Ok(KeyEntry {
2694 id: key_id,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002695 key_blob_info,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002696 cert: cert_blob,
2697 cert_chain: cert_chain_blob,
Max Bires8e93d2b2021-01-14 13:17:59 -08002698 km_uuid,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002699 parameters,
2700 metadata,
Janis Danisevskis377d1002021-01-27 19:07:48 -08002701 pure_cert: !has_km_blob,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002702 })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002703 }
2704
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002705 /// Returns a list of KeyDescriptors in the selected domain/namespace.
2706 /// The key descriptors will have the domain, nspace, and alias field set.
2707 /// Domain must be APP or SELINUX, the caller must make sure of that.
2708 pub fn list(&mut self, domain: Domain, namespace: i64) -> Result<Vec<KeyDescriptor>> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002709 self.with_transaction(TransactionBehavior::Deferred, |tx| {
2710 let mut stmt = tx
2711 .prepare(
2712 "SELECT alias FROM persistent.keyentry
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002713 WHERE domain = ? AND namespace = ? AND alias IS NOT NULL AND state = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08002714 )
2715 .context("In list: Failed to prepare.")?;
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002716
Janis Danisevskis66784c42021-01-27 08:40:25 -08002717 let mut rows = stmt
2718 .query(params![domain.0 as u32, namespace, KeyLifeCycle::Live])
2719 .context("In list: Failed to query.")?;
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002720
Janis Danisevskis66784c42021-01-27 08:40:25 -08002721 let mut descriptors: Vec<KeyDescriptor> = Vec::new();
2722 db_utils::with_rows_extract_all(&mut rows, |row| {
2723 descriptors.push(KeyDescriptor {
2724 domain,
2725 nspace: namespace,
2726 alias: Some(row.get(0).context("Trying to extract alias.")?),
2727 blob: None,
2728 });
2729 Ok(())
2730 })
2731 .context("In list: Failed to extract rows.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002732 Ok(descriptors).no_gc()
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002733 })
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002734 }
2735
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002736 /// Adds a grant to the grant table.
2737 /// Like `load_key_entry` this function loads the access tuple before
2738 /// it uses the callback for a permission check. Upon success,
2739 /// it inserts the `grantee_uid`, `key_id`, and `access_vector` into the
2740 /// grant table. The new row will have a randomized id, which is used as
2741 /// grant id in the namespace field of the resulting KeyDescriptor.
2742 pub fn grant(
2743 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002744 key: &KeyDescriptor,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002745 caller_uid: u32,
2746 grantee_uid: u32,
2747 access_vector: KeyPermSet,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002748 check_permission: impl Fn(&KeyDescriptor, &KeyPermSet) -> Result<()>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002749 ) -> Result<KeyDescriptor> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002750 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2751 // Load the key_id and complete the access control tuple.
2752 // We ignore the access vector here because grants cannot be granted.
2753 // The access vector returned here expresses the permissions the
2754 // grantee has if key.domain == Domain::GRANT. But this vector
2755 // cannot include the grant permission by design, so there is no way the
2756 // subsequent permission check can pass.
2757 // We could check key.domain == Domain::GRANT and fail early.
2758 // But even if we load the access tuple by grant here, the permission
2759 // check denies the attempt to create a grant by grant descriptor.
2760 let (key_id, access_key_descriptor, _) =
2761 Self::load_access_tuple(&tx, key, KeyType::Client, caller_uid)
2762 .context("In grant")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002763
Janis Danisevskis66784c42021-01-27 08:40:25 -08002764 // Perform access control. It is vital that we return here if the permission
2765 // was denied. So do not touch that '?' at the end of the line.
2766 // This permission check checks if the caller has the grant permission
2767 // for the given key and in addition to all of the permissions
2768 // expressed in `access_vector`.
2769 check_permission(&access_key_descriptor, &access_vector)
2770 .context("In grant: check_permission failed.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002771
Janis Danisevskis66784c42021-01-27 08:40:25 -08002772 let grant_id = if let Some(grant_id) = tx
2773 .query_row(
2774 "SELECT id FROM persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002775 WHERE keyentryid = ? AND grantee = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08002776 params![key_id, grantee_uid],
2777 |row| row.get(0),
2778 )
2779 .optional()
2780 .context("In grant: Failed get optional existing grant id.")?
2781 {
2782 tx.execute(
2783 "UPDATE persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002784 SET access_vector = ?
2785 WHERE id = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08002786 params![i32::from(access_vector), grant_id],
Joel Galenson845f74b2020-09-09 14:11:55 -07002787 )
Janis Danisevskis66784c42021-01-27 08:40:25 -08002788 .context("In grant: Failed to update existing grant.")?;
2789 grant_id
2790 } else {
2791 Self::insert_with_retry(|id| {
2792 tx.execute(
2793 "INSERT INTO persistent.grant (id, grantee, keyentryid, access_vector)
2794 VALUES (?, ?, ?, ?);",
2795 params![id, grantee_uid, key_id, i32::from(access_vector)],
2796 )
2797 })
2798 .context("In grant")?
2799 };
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002800
Janis Danisevskis66784c42021-01-27 08:40:25 -08002801 Ok(KeyDescriptor { domain: Domain::GRANT, nspace: grant_id, alias: None, blob: None })
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002802 .no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08002803 })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002804 }
2805
2806 /// This function checks permissions like `grant` and `load_key_entry`
2807 /// before removing a grant from the grant table.
2808 pub fn ungrant(
2809 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002810 key: &KeyDescriptor,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002811 caller_uid: u32,
2812 grantee_uid: u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002813 check_permission: impl Fn(&KeyDescriptor) -> Result<()>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002814 ) -> Result<()> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002815 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2816 // Load the key_id and complete the access control tuple.
2817 // We ignore the access vector here because grants cannot be granted.
2818 let (key_id, access_key_descriptor, _) =
2819 Self::load_access_tuple(&tx, key, KeyType::Client, caller_uid)
2820 .context("In ungrant.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002821
Janis Danisevskis66784c42021-01-27 08:40:25 -08002822 // Perform access control. We must return here if the permission
2823 // was denied. So do not touch the '?' at the end of this line.
2824 check_permission(&access_key_descriptor)
2825 .context("In grant: check_permission failed.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002826
Janis Danisevskis66784c42021-01-27 08:40:25 -08002827 tx.execute(
2828 "DELETE FROM persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002829 WHERE keyentryid = ? AND grantee = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08002830 params![key_id, grantee_uid],
2831 )
2832 .context("Failed to delete grant.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002833
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002834 Ok(()).no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08002835 })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002836 }
2837
Joel Galenson845f74b2020-09-09 14:11:55 -07002838 // Generates a random id and passes it to the given function, which will
2839 // try to insert it into a database. If that insertion fails, retry;
2840 // otherwise return the id.
2841 fn insert_with_retry(inserter: impl Fn(i64) -> rusqlite::Result<usize>) -> Result<i64> {
2842 loop {
Janis Danisevskiseed69842021-02-18 20:04:10 -08002843 let newid: i64 = match random() {
2844 Self::UNASSIGNED_KEY_ID => continue, // UNASSIGNED_KEY_ID cannot be assigned.
2845 i => i,
2846 };
Joel Galenson845f74b2020-09-09 14:11:55 -07002847 match inserter(newid) {
2848 // If the id already existed, try again.
2849 Err(rusqlite::Error::SqliteFailure(
2850 libsqlite3_sys::Error {
2851 code: libsqlite3_sys::ErrorCode::ConstraintViolation,
2852 extended_code: libsqlite3_sys::SQLITE_CONSTRAINT_UNIQUE,
2853 },
2854 _,
2855 )) => (),
2856 Err(e) => {
2857 return Err(e).context("In insert_with_retry: failed to insert into database.")
2858 }
2859 _ => return Ok(newid),
2860 }
2861 }
2862 }
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002863
2864 /// Insert or replace the auth token based on the UNIQUE constraint of the auth token table
2865 pub fn insert_auth_token(&mut self, auth_token: &HardwareAuthToken) -> Result<()> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002866 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2867 tx.execute(
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002868 "INSERT OR REPLACE INTO perboot.authtoken (challenge, user_id, auth_id,
2869 authenticator_type, timestamp, mac, time_received) VALUES(?, ?, ?, ?, ?, ?, ?);",
2870 params![
2871 auth_token.challenge,
2872 auth_token.userId,
2873 auth_token.authenticatorId,
2874 auth_token.authenticatorType.0 as i32,
2875 auth_token.timestamp.milliSeconds as i64,
2876 auth_token.mac,
2877 MonotonicRawTime::now(),
2878 ],
2879 )
2880 .context("In insert_auth_token: failed to insert auth token into the database")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002881 Ok(()).no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08002882 })
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002883 }
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002884
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002885 /// Find the newest auth token matching the given predicate.
2886 pub fn find_auth_token_entry<F>(
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002887 &mut self,
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002888 p: F,
2889 ) -> Result<Option<(AuthTokenEntry, MonotonicRawTime)>>
2890 where
2891 F: Fn(&AuthTokenEntry) -> bool,
2892 {
2893 self.with_transaction(TransactionBehavior::Deferred, |tx| {
2894 let mut stmt = tx
2895 .prepare("SELECT * from perboot.authtoken ORDER BY time_received DESC;")
2896 .context("Prepare statement failed.")?;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002897
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002898 let mut rows = stmt.query(NO_PARAMS).context("Failed to query.")?;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002899
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002900 while let Some(row) = rows.next().context("Failed to get next row.")? {
2901 let entry = AuthTokenEntry::new(
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002902 HardwareAuthToken {
2903 challenge: row.get(1)?,
2904 userId: row.get(2)?,
2905 authenticatorId: row.get(3)?,
2906 authenticatorType: HardwareAuthenticatorType(row.get(4)?),
2907 timestamp: Timestamp { milliSeconds: row.get(5)? },
2908 mac: row.get(6)?,
2909 },
2910 row.get(7)?,
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002911 );
2912 if p(&entry) {
2913 return Ok(Some((
2914 entry,
2915 Self::get_last_off_body(tx)
2916 .context("In find_auth_token_entry: Trying to get last off body")?,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002917 )))
2918 .no_gc();
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002919 }
2920 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002921 Ok(None).no_gc()
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002922 })
2923 .context("In find_auth_token_entry.")
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002924 }
2925
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002926 /// Insert last_off_body into the metadata table at the initialization of auth token table
Janis Danisevskis66784c42021-01-27 08:40:25 -08002927 pub fn insert_last_off_body(&mut self, last_off_body: MonotonicRawTime) -> Result<()> {
2928 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2929 tx.execute(
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002930 "INSERT OR REPLACE INTO perboot.metadata (key, value) VALUES (?, ?);",
2931 params!["last_off_body", last_off_body],
2932 )
2933 .context("In insert_last_off_body: failed to insert.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002934 Ok(()).no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08002935 })
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002936 }
2937
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002938 /// Update last_off_body when on_device_off_body is called
Janis Danisevskis66784c42021-01-27 08:40:25 -08002939 pub fn update_last_off_body(&mut self, last_off_body: MonotonicRawTime) -> Result<()> {
2940 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2941 tx.execute(
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002942 "UPDATE perboot.metadata SET value = ? WHERE key = ?;",
2943 params![last_off_body, "last_off_body"],
2944 )
2945 .context("In update_last_off_body: failed to update.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002946 Ok(()).no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08002947 })
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002948 }
2949
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002950 /// Get last_off_body time when finding auth tokens
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002951 fn get_last_off_body(tx: &Transaction) -> Result<MonotonicRawTime> {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002952 tx.query_row(
2953 "SELECT value from perboot.metadata WHERE key = ?;",
2954 params!["last_off_body"],
2955 |row| Ok(row.get(0)?),
2956 )
2957 .context("In get_last_off_body: query_row failed.")
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002958 }
Joel Galenson26f4d012020-07-17 14:57:21 -07002959}
2960
2961#[cfg(test)]
2962mod tests {
2963
2964 use super::*;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002965 use crate::key_parameter::{
2966 Algorithm, BlockMode, Digest, EcCurve, HardwareAuthenticatorType, KeyOrigin, KeyParameter,
2967 KeyParameterValue, KeyPurpose, PaddingMode, SecurityLevel,
2968 };
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002969 use crate::key_perm_set;
2970 use crate::permission::{KeyPerm, KeyPermSet};
Hasini Gunasingheda895552021-01-27 19:34:37 +00002971 use crate::super_key::SuperKeyManager;
Janis Danisevskis2a8330a2021-01-20 15:34:26 -08002972 use keystore2_test_utils::TempDir;
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002973 use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
2974 HardwareAuthToken::HardwareAuthToken,
2975 HardwareAuthenticatorType::HardwareAuthenticatorType as kmhw_authenticator_type,
Janis Danisevskisc3a496b2021-01-05 10:37:22 -08002976 };
2977 use android_hardware_security_secureclock::aidl::android::hardware::security::secureclock::{
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002978 Timestamp::Timestamp,
2979 };
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002980 use rusqlite::NO_PARAMS;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002981 use rusqlite::{Error, TransactionBehavior};
Joel Galenson0891bc12020-07-20 10:37:03 -07002982 use std::cell::RefCell;
Janis Danisevskisaec14592020-11-12 09:41:49 -08002983 use std::sync::atomic::{AtomicU8, Ordering};
2984 use std::sync::Arc;
2985 use std::thread;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002986 use std::time::{Duration, SystemTime};
Janis Danisevskis66784c42021-01-27 08:40:25 -08002987 #[cfg(disabled)]
2988 use std::time::Instant;
Joel Galenson0891bc12020-07-20 10:37:03 -07002989
Janis Danisevskis4df44f42020-08-26 14:40:03 -07002990 fn new_test_db() -> Result<KeystoreDB> {
2991 let conn = KeystoreDB::make_connection("file::memory:", "file::memory:")?;
2992
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002993 let mut db = KeystoreDB { conn, gc: None };
Janis Danisevskis66784c42021-01-27 08:40:25 -08002994 db.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002995 KeystoreDB::init_tables(tx).context("Failed to initialize tables.").no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08002996 })?;
2997 Ok(db)
Janis Danisevskis4df44f42020-08-26 14:40:03 -07002998 }
2999
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003000 fn new_test_db_with_gc<F>(path: &Path, cb: F) -> Result<KeystoreDB>
3001 where
3002 F: Fn(&Uuid, &[u8]) -> Result<()> + Send + 'static,
3003 {
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00003004 let super_key = Arc::new(SuperKeyManager::new());
3005
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003006 let gc_db = KeystoreDB::new(path, None).expect("Failed to open test gc db_connection.");
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00003007 let gc = Gc::new_init_with(Default::default(), move || (Box::new(cb), gc_db, super_key));
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003008
3009 KeystoreDB::new(path, Some(gc))
3010 }
3011
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003012 fn rebind_alias(
3013 db: &mut KeystoreDB,
3014 newid: &KeyIdGuard,
3015 alias: &str,
3016 domain: Domain,
3017 namespace: i64,
3018 ) -> Result<bool> {
3019 db.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003020 KeystoreDB::rebind_alias(tx, newid, alias, &domain, &namespace).no_gc()
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003021 })
3022 .context("In rebind_alias.")
3023 }
3024
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003025 #[test]
3026 fn datetime() -> Result<()> {
3027 let conn = Connection::open_in_memory()?;
3028 conn.execute("CREATE TABLE test (ts DATETIME);", NO_PARAMS)?;
3029 let now = SystemTime::now();
3030 let duration = Duration::from_secs(1000);
3031 let then = now.checked_sub(duration).unwrap();
3032 let soon = now.checked_add(duration).unwrap();
3033 conn.execute(
3034 "INSERT INTO test (ts) VALUES (?), (?), (?);",
3035 params![DateTime::try_from(now)?, DateTime::try_from(then)?, DateTime::try_from(soon)?],
3036 )?;
3037 let mut stmt = conn.prepare("SELECT ts FROM test ORDER BY ts ASC;")?;
3038 let mut rows = stmt.query(NO_PARAMS)?;
3039 assert_eq!(DateTime::try_from(then)?, rows.next()?.unwrap().get(0)?);
3040 assert_eq!(DateTime::try_from(now)?, rows.next()?.unwrap().get(0)?);
3041 assert_eq!(DateTime::try_from(soon)?, rows.next()?.unwrap().get(0)?);
3042 assert!(rows.next()?.is_none());
3043 assert!(DateTime::try_from(then)? < DateTime::try_from(now)?);
3044 assert!(DateTime::try_from(then)? < DateTime::try_from(soon)?);
3045 assert!(DateTime::try_from(now)? < DateTime::try_from(soon)?);
3046 Ok(())
3047 }
3048
Joel Galenson0891bc12020-07-20 10:37:03 -07003049 // Ensure that we're using the "injected" random function, not the real one.
3050 #[test]
3051 fn test_mocked_random() {
3052 let rand1 = random();
3053 let rand2 = random();
3054 let rand3 = random();
3055 if rand1 == rand2 {
3056 assert_eq!(rand2 + 1, rand3);
3057 } else {
3058 assert_eq!(rand1 + 1, rand2);
3059 assert_eq!(rand2, rand3);
3060 }
3061 }
Joel Galenson26f4d012020-07-17 14:57:21 -07003062
Joel Galenson26f4d012020-07-17 14:57:21 -07003063 // Test that we have the correct tables.
3064 #[test]
3065 fn test_tables() -> Result<()> {
Janis Danisevskis4df44f42020-08-26 14:40:03 -07003066 let db = new_test_db()?;
Joel Galenson26f4d012020-07-17 14:57:21 -07003067 let tables = db
3068 .conn
Joel Galenson2aab4432020-07-22 15:27:57 -07003069 .prepare("SELECT name from persistent.sqlite_master WHERE type='table' ORDER BY name;")?
Joel Galenson26f4d012020-07-17 14:57:21 -07003070 .query_map(params![], |row| row.get(0))?
3071 .collect::<rusqlite::Result<Vec<String>>>()?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003072 assert_eq!(tables.len(), 6);
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003073 assert_eq!(tables[0], "blobentry");
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003074 assert_eq!(tables[1], "blobmetadata");
3075 assert_eq!(tables[2], "grant");
3076 assert_eq!(tables[3], "keyentry");
3077 assert_eq!(tables[4], "keymetadata");
3078 assert_eq!(tables[5], "keyparameter");
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003079 let tables = db
3080 .conn
3081 .prepare("SELECT name from perboot.sqlite_master WHERE type='table' ORDER BY name;")?
3082 .query_map(params![], |row| row.get(0))?
3083 .collect::<rusqlite::Result<Vec<String>>>()?;
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00003084
3085 assert_eq!(tables.len(), 2);
3086 assert_eq!(tables[0], "authtoken");
3087 assert_eq!(tables[1], "metadata");
Joel Galenson2aab4432020-07-22 15:27:57 -07003088 Ok(())
3089 }
3090
3091 #[test]
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00003092 fn test_auth_token_table_invariant() -> Result<()> {
3093 let mut db = new_test_db()?;
3094 let auth_token1 = HardwareAuthToken {
3095 challenge: i64::MAX,
3096 userId: 200,
3097 authenticatorId: 200,
3098 authenticatorType: kmhw_authenticator_type(kmhw_authenticator_type::PASSWORD.0),
3099 timestamp: Timestamp { milliSeconds: 500 },
3100 mac: String::from("mac").into_bytes(),
3101 };
3102 db.insert_auth_token(&auth_token1)?;
3103 let auth_tokens_returned = get_auth_tokens(&mut db)?;
3104 assert_eq!(auth_tokens_returned.len(), 1);
3105
3106 // insert another auth token with the same values for the columns in the UNIQUE constraint
3107 // of the auth token table and different value for timestamp
3108 let auth_token2 = HardwareAuthToken {
3109 challenge: i64::MAX,
3110 userId: 200,
3111 authenticatorId: 200,
3112 authenticatorType: kmhw_authenticator_type(kmhw_authenticator_type::PASSWORD.0),
3113 timestamp: Timestamp { milliSeconds: 600 },
3114 mac: String::from("mac").into_bytes(),
3115 };
3116
3117 db.insert_auth_token(&auth_token2)?;
3118 let mut auth_tokens_returned = get_auth_tokens(&mut db)?;
3119 assert_eq!(auth_tokens_returned.len(), 1);
3120
3121 if let Some(auth_token) = auth_tokens_returned.pop() {
3122 assert_eq!(auth_token.auth_token.timestamp.milliSeconds, 600);
3123 }
3124
3125 // insert another auth token with the different values for the columns in the UNIQUE
3126 // constraint of the auth token table
3127 let auth_token3 = HardwareAuthToken {
3128 challenge: i64::MAX,
3129 userId: 201,
3130 authenticatorId: 200,
3131 authenticatorType: kmhw_authenticator_type(kmhw_authenticator_type::PASSWORD.0),
3132 timestamp: Timestamp { milliSeconds: 600 },
3133 mac: String::from("mac").into_bytes(),
3134 };
3135
3136 db.insert_auth_token(&auth_token3)?;
3137 let auth_tokens_returned = get_auth_tokens(&mut db)?;
3138 assert_eq!(auth_tokens_returned.len(), 2);
3139
3140 Ok(())
3141 }
3142
3143 // utility function for test_auth_token_table_invariant()
3144 fn get_auth_tokens(db: &mut KeystoreDB) -> Result<Vec<AuthTokenEntry>> {
3145 let mut stmt = db.conn.prepare("SELECT * from perboot.authtoken;")?;
3146
3147 let auth_token_entries: Vec<AuthTokenEntry> = stmt
3148 .query_map(NO_PARAMS, |row| {
3149 Ok(AuthTokenEntry::new(
3150 HardwareAuthToken {
3151 challenge: row.get(1)?,
3152 userId: row.get(2)?,
3153 authenticatorId: row.get(3)?,
3154 authenticatorType: HardwareAuthenticatorType(row.get(4)?),
3155 timestamp: Timestamp { milliSeconds: row.get(5)? },
3156 mac: row.get(6)?,
3157 },
3158 row.get(7)?,
3159 ))
3160 })?
3161 .collect::<Result<Vec<AuthTokenEntry>, Error>>()?;
3162 Ok(auth_token_entries)
3163 }
3164
3165 #[test]
Joel Galenson2aab4432020-07-22 15:27:57 -07003166 fn test_persistence_for_files() -> Result<()> {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08003167 let temp_dir = TempDir::new("persistent_db_test")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003168 let mut db = KeystoreDB::new(temp_dir.path(), None)?;
Joel Galenson2aab4432020-07-22 15:27:57 -07003169
Janis Danisevskis66784c42021-01-27 08:40:25 -08003170 db.create_key_entry(&Domain::APP, &100, &KEYSTORE_UUID)?;
Joel Galenson2aab4432020-07-22 15:27:57 -07003171 let entries = get_keyentry(&db)?;
3172 assert_eq!(entries.len(), 1);
Janis Danisevskisbf15d732020-12-08 10:35:26 -08003173
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003174 let db = KeystoreDB::new(temp_dir.path(), None)?;
Joel Galenson2aab4432020-07-22 15:27:57 -07003175
3176 let entries_new = get_keyentry(&db)?;
3177 assert_eq!(entries, entries_new);
3178 Ok(())
3179 }
3180
3181 #[test]
Joel Galenson0891bc12020-07-20 10:37:03 -07003182 fn test_create_key_entry() -> Result<()> {
Max Bires8e93d2b2021-01-14 13:17:59 -08003183 fn extractor(ke: &KeyEntryRow) -> (Domain, i64, Option<&str>, Uuid) {
3184 (ke.domain.unwrap(), ke.namespace.unwrap(), ke.alias.as_deref(), ke.km_uuid.unwrap())
Joel Galenson0891bc12020-07-20 10:37:03 -07003185 }
3186
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003187 let mut db = new_test_db()?;
Joel Galenson0891bc12020-07-20 10:37:03 -07003188
Janis Danisevskis66784c42021-01-27 08:40:25 -08003189 db.create_key_entry(&Domain::APP, &100, &KEYSTORE_UUID)?;
3190 db.create_key_entry(&Domain::SELINUX, &101, &KEYSTORE_UUID)?;
Joel Galenson0891bc12020-07-20 10:37:03 -07003191
3192 let entries = get_keyentry(&db)?;
3193 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08003194 assert_eq!(extractor(&entries[0]), (Domain::APP, 100, None, KEYSTORE_UUID));
3195 assert_eq!(extractor(&entries[1]), (Domain::SELINUX, 101, None, KEYSTORE_UUID));
Joel Galenson0891bc12020-07-20 10:37:03 -07003196
3197 // Test that we must pass in a valid Domain.
3198 check_result_is_error_containing_string(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003199 db.create_key_entry(&Domain::GRANT, &102, &KEYSTORE_UUID),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003200 "Domain Domain(1) must be either App or SELinux.",
Joel Galenson0891bc12020-07-20 10:37:03 -07003201 );
3202 check_result_is_error_containing_string(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003203 db.create_key_entry(&Domain::BLOB, &103, &KEYSTORE_UUID),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003204 "Domain Domain(3) must be either App or SELinux.",
Joel Galenson0891bc12020-07-20 10:37:03 -07003205 );
3206 check_result_is_error_containing_string(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003207 db.create_key_entry(&Domain::KEY_ID, &104, &KEYSTORE_UUID),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003208 "Domain Domain(4) must be either App or SELinux.",
Joel Galenson0891bc12020-07-20 10:37:03 -07003209 );
3210
3211 Ok(())
3212 }
3213
Joel Galenson33c04ad2020-08-03 11:04:38 -07003214 #[test]
Max Bires2b2e6562020-09-22 11:22:36 -07003215 fn test_add_unsigned_key() -> Result<()> {
3216 let mut db = new_test_db()?;
3217 let public_key: Vec<u8> = vec![0x01, 0x02, 0x03];
3218 let private_key: Vec<u8> = vec![0x04, 0x05, 0x06];
3219 let raw_public_key: Vec<u8> = vec![0x07, 0x08, 0x09];
3220 db.create_attestation_key_entry(
3221 &public_key,
3222 &raw_public_key,
3223 &private_key,
3224 &KEYSTORE_UUID,
3225 )?;
3226 let keys = db.fetch_unsigned_attestation_keys(5, &KEYSTORE_UUID)?;
3227 assert_eq!(keys.len(), 1);
3228 assert_eq!(keys[0], public_key);
3229 Ok(())
3230 }
3231
3232 #[test]
3233 fn test_store_signed_attestation_certificate_chain() -> Result<()> {
3234 let mut db = new_test_db()?;
3235 let expiration_date: i64 = 20;
3236 let namespace: i64 = 30;
3237 let base_byte: u8 = 1;
3238 let loaded_values =
3239 load_attestation_key_pool(&mut db, expiration_date, namespace, base_byte)?;
3240 let chain =
3241 db.retrieve_attestation_key_and_cert_chain(Domain::APP, namespace, &KEYSTORE_UUID)?;
3242 assert_eq!(true, chain.is_some());
3243 let cert_chain = chain.unwrap();
Max Biresb2e1d032021-02-08 21:35:05 -08003244 assert_eq!(cert_chain.private_key.to_vec(), loaded_values.priv_key);
Max Bires97f96812021-02-23 23:44:57 -08003245 assert_eq!(cert_chain.batch_cert, loaded_values.batch_cert);
3246 assert_eq!(cert_chain.cert_chain, loaded_values.cert_chain);
Max Bires2b2e6562020-09-22 11:22:36 -07003247 Ok(())
3248 }
3249
3250 #[test]
3251 fn test_get_attestation_pool_status() -> Result<()> {
3252 let mut db = new_test_db()?;
3253 let namespace: i64 = 30;
3254 load_attestation_key_pool(
3255 &mut db, 10, /* expiration */
3256 namespace, 0x01, /* base_byte */
3257 )?;
3258 load_attestation_key_pool(&mut db, 20 /* expiration */, namespace + 1, 0x02)?;
3259 load_attestation_key_pool(&mut db, 40 /* expiration */, namespace + 2, 0x03)?;
3260 let mut status = db.get_attestation_pool_status(9 /* expiration */, &KEYSTORE_UUID)?;
3261 assert_eq!(status.expiring, 0);
3262 assert_eq!(status.attested, 3);
3263 assert_eq!(status.unassigned, 0);
3264 assert_eq!(status.total, 3);
3265 assert_eq!(
3266 db.get_attestation_pool_status(15 /* expiration */, &KEYSTORE_UUID)?.expiring,
3267 1
3268 );
3269 assert_eq!(
3270 db.get_attestation_pool_status(25 /* expiration */, &KEYSTORE_UUID)?.expiring,
3271 2
3272 );
3273 assert_eq!(
3274 db.get_attestation_pool_status(60 /* expiration */, &KEYSTORE_UUID)?.expiring,
3275 3
3276 );
3277 let public_key: Vec<u8> = vec![0x01, 0x02, 0x03];
3278 let private_key: Vec<u8> = vec![0x04, 0x05, 0x06];
3279 let raw_public_key: Vec<u8> = vec![0x07, 0x08, 0x09];
3280 let cert_chain: Vec<u8> = vec![0x0a, 0x0b, 0x0c];
Max Biresb2e1d032021-02-08 21:35:05 -08003281 let batch_cert: Vec<u8> = vec![0x0d, 0x0e, 0x0f];
Max Bires2b2e6562020-09-22 11:22:36 -07003282 db.create_attestation_key_entry(
3283 &public_key,
3284 &raw_public_key,
3285 &private_key,
3286 &KEYSTORE_UUID,
3287 )?;
3288 status = db.get_attestation_pool_status(0 /* expiration */, &KEYSTORE_UUID)?;
3289 assert_eq!(status.attested, 3);
3290 assert_eq!(status.unassigned, 0);
3291 assert_eq!(status.total, 4);
3292 db.store_signed_attestation_certificate_chain(
3293 &raw_public_key,
Max Biresb2e1d032021-02-08 21:35:05 -08003294 &batch_cert,
Max Bires2b2e6562020-09-22 11:22:36 -07003295 &cert_chain,
3296 20,
3297 &KEYSTORE_UUID,
3298 )?;
3299 status = db.get_attestation_pool_status(0 /* expiration */, &KEYSTORE_UUID)?;
3300 assert_eq!(status.attested, 4);
3301 assert_eq!(status.unassigned, 1);
3302 assert_eq!(status.total, 4);
3303 Ok(())
3304 }
3305
3306 #[test]
3307 fn test_remove_expired_certs() -> Result<()> {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003308 let temp_dir =
3309 TempDir::new("test_remove_expired_certs_").expect("Failed to create temp dir.");
3310 let mut db = new_test_db_with_gc(temp_dir.path(), |_, _| Ok(()))?;
Max Bires2b2e6562020-09-22 11:22:36 -07003311 let expiration_date: i64 =
3312 SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_millis() as i64 + 10000;
3313 let namespace: i64 = 30;
3314 let namespace_del1: i64 = 45;
3315 let namespace_del2: i64 = 60;
3316 let entry_values = load_attestation_key_pool(
3317 &mut db,
3318 expiration_date,
3319 namespace,
3320 0x01, /* base_byte */
3321 )?;
3322 load_attestation_key_pool(&mut db, 45, namespace_del1, 0x02)?;
3323 load_attestation_key_pool(&mut db, 60, namespace_del2, 0x03)?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003324
3325 let blob_entry_row_count: u32 = db
3326 .conn
3327 .query_row("SELECT COUNT(id) FROM persistent.blobentry;", NO_PARAMS, |row| row.get(0))
3328 .expect("Failed to get blob entry row count.");
Max Biresb2e1d032021-02-08 21:35:05 -08003329 // We expect 9 rows here because there are three blobs per attestation key, i.e.,
3330 // one key, one certificate chain, and one certificate.
3331 assert_eq!(blob_entry_row_count, 9);
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003332
Max Bires2b2e6562020-09-22 11:22:36 -07003333 assert_eq!(db.delete_expired_attestation_keys()?, 2);
3334
3335 let mut cert_chain =
3336 db.retrieve_attestation_key_and_cert_chain(Domain::APP, namespace, &KEYSTORE_UUID)?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003337 assert!(cert_chain.is_some());
Max Bires2b2e6562020-09-22 11:22:36 -07003338 let value = cert_chain.unwrap();
Max Bires97f96812021-02-23 23:44:57 -08003339 assert_eq!(entry_values.batch_cert, value.batch_cert);
3340 assert_eq!(entry_values.cert_chain, value.cert_chain);
Max Biresb2e1d032021-02-08 21:35:05 -08003341 assert_eq!(entry_values.priv_key, value.private_key.to_vec());
Max Bires2b2e6562020-09-22 11:22:36 -07003342
3343 cert_chain = db.retrieve_attestation_key_and_cert_chain(
3344 Domain::APP,
3345 namespace_del1,
3346 &KEYSTORE_UUID,
3347 )?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003348 assert!(!cert_chain.is_some());
Max Bires2b2e6562020-09-22 11:22:36 -07003349 cert_chain = db.retrieve_attestation_key_and_cert_chain(
3350 Domain::APP,
3351 namespace_del2,
3352 &KEYSTORE_UUID,
3353 )?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003354 assert!(!cert_chain.is_some());
Max Bires2b2e6562020-09-22 11:22:36 -07003355
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003356 // Give the garbage collector half a second to catch up.
3357 std::thread::sleep(Duration::from_millis(500));
Max Bires2b2e6562020-09-22 11:22:36 -07003358
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003359 let blob_entry_row_count: u32 = db
3360 .conn
3361 .query_row("SELECT COUNT(id) FROM persistent.blobentry;", NO_PARAMS, |row| row.get(0))
3362 .expect("Failed to get blob entry row count.");
Max Biresb2e1d032021-02-08 21:35:05 -08003363 // There shound be 3 blob entries left, because we deleted two of the attestation
3364 // key entries with three blobs each.
3365 assert_eq!(blob_entry_row_count, 3);
Max Bires2b2e6562020-09-22 11:22:36 -07003366
Max Bires2b2e6562020-09-22 11:22:36 -07003367 Ok(())
3368 }
3369
3370 #[test]
Max Bires60d7ed12021-03-05 15:59:22 -08003371 fn test_delete_all_attestation_keys() -> Result<()> {
3372 let mut db = new_test_db()?;
3373 load_attestation_key_pool(&mut db, 45 /* expiration */, 1 /* namespace */, 0x02)?;
3374 load_attestation_key_pool(&mut db, 80 /* expiration */, 2 /* namespace */, 0x03)?;
3375 db.create_key_entry(&Domain::APP, &42, &KEYSTORE_UUID)?;
3376 let result = db.delete_all_attestation_keys()?;
3377
3378 // Give the garbage collector half a second to catch up.
3379 std::thread::sleep(Duration::from_millis(500));
3380
3381 // Attestation keys should be deleted, and the regular key should remain.
3382 assert_eq!(result, 2);
3383
3384 Ok(())
3385 }
3386
3387 #[test]
Joel Galenson33c04ad2020-08-03 11:04:38 -07003388 fn test_rebind_alias() -> Result<()> {
Max Bires8e93d2b2021-01-14 13:17:59 -08003389 fn extractor(
3390 ke: &KeyEntryRow,
3391 ) -> (Option<Domain>, Option<i64>, Option<&str>, Option<Uuid>) {
3392 (ke.domain, ke.namespace, ke.alias.as_deref(), ke.km_uuid)
Joel Galenson33c04ad2020-08-03 11:04:38 -07003393 }
3394
Janis Danisevskis4df44f42020-08-26 14:40:03 -07003395 let mut db = new_test_db()?;
Janis Danisevskis66784c42021-01-27 08:40:25 -08003396 db.create_key_entry(&Domain::APP, &42, &KEYSTORE_UUID)?;
3397 db.create_key_entry(&Domain::APP, &42, &KEYSTORE_UUID)?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07003398 let entries = get_keyentry(&db)?;
3399 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08003400 assert_eq!(
3401 extractor(&entries[0]),
3402 (Some(Domain::APP), Some(42), None, Some(KEYSTORE_UUID))
3403 );
3404 assert_eq!(
3405 extractor(&entries[1]),
3406 (Some(Domain::APP), Some(42), None, Some(KEYSTORE_UUID))
3407 );
Joel Galenson33c04ad2020-08-03 11:04:38 -07003408
3409 // Test that the first call to rebind_alias sets the alias.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003410 rebind_alias(&mut db, &KEY_ID_LOCK.get(entries[0].id), "foo", Domain::APP, 42)?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07003411 let entries = get_keyentry(&db)?;
3412 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08003413 assert_eq!(
3414 extractor(&entries[0]),
3415 (Some(Domain::APP), Some(42), Some("foo"), Some(KEYSTORE_UUID))
3416 );
3417 assert_eq!(
3418 extractor(&entries[1]),
3419 (Some(Domain::APP), Some(42), None, Some(KEYSTORE_UUID))
3420 );
Joel Galenson33c04ad2020-08-03 11:04:38 -07003421
3422 // Test that the second call to rebind_alias also empties the old one.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003423 rebind_alias(&mut db, &KEY_ID_LOCK.get(entries[1].id), "foo", Domain::APP, 42)?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07003424 let entries = get_keyentry(&db)?;
3425 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08003426 assert_eq!(extractor(&entries[0]), (None, None, None, Some(KEYSTORE_UUID)));
3427 assert_eq!(
3428 extractor(&entries[1]),
3429 (Some(Domain::APP), Some(42), Some("foo"), Some(KEYSTORE_UUID))
3430 );
Joel Galenson33c04ad2020-08-03 11:04:38 -07003431
3432 // Test that we must pass in a valid Domain.
3433 check_result_is_error_containing_string(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003434 rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::GRANT, 42),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003435 "Domain Domain(1) must be either App or SELinux.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07003436 );
3437 check_result_is_error_containing_string(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003438 rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::BLOB, 42),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003439 "Domain Domain(3) must be either App or SELinux.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07003440 );
3441 check_result_is_error_containing_string(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003442 rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::KEY_ID, 42),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003443 "Domain Domain(4) must be either App or SELinux.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07003444 );
3445
3446 // Test that we correctly handle setting an alias for something that does not exist.
3447 check_result_is_error_containing_string(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003448 rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::SELINUX, 42),
Joel Galenson33c04ad2020-08-03 11:04:38 -07003449 "Expected to update a single entry but instead updated 0",
3450 );
3451 // Test that we correctly abort the transaction in this case.
3452 let entries = get_keyentry(&db)?;
3453 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08003454 assert_eq!(extractor(&entries[0]), (None, None, None, Some(KEYSTORE_UUID)));
3455 assert_eq!(
3456 extractor(&entries[1]),
3457 (Some(Domain::APP), Some(42), Some("foo"), Some(KEYSTORE_UUID))
3458 );
Joel Galenson33c04ad2020-08-03 11:04:38 -07003459
3460 Ok(())
3461 }
3462
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003463 #[test]
3464 fn test_grant_ungrant() -> Result<()> {
3465 const CALLER_UID: u32 = 15;
3466 const GRANTEE_UID: u32 = 12;
3467 const SELINUX_NAMESPACE: i64 = 7;
3468
3469 let mut db = new_test_db()?;
3470 db.conn.execute(
Max Bires8e93d2b2021-01-14 13:17:59 -08003471 "INSERT INTO persistent.keyentry (id, key_type, domain, namespace, alias, state, km_uuid)
3472 VALUES (1, 0, 0, 15, 'key', 1, ?), (2, 0, 2, 7, 'yek', 1, ?);",
3473 params![KEYSTORE_UUID, KEYSTORE_UUID],
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003474 )?;
3475 let app_key = KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003476 domain: super::Domain::APP,
3477 nspace: 0,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003478 alias: Some("key".to_string()),
3479 blob: None,
3480 };
3481 const PVEC1: KeyPermSet = key_perm_set![KeyPerm::use_(), KeyPerm::get_info()];
3482 const PVEC2: KeyPermSet = key_perm_set![KeyPerm::use_()];
3483
3484 // Reset totally predictable random number generator in case we
3485 // are not the first test running on this thread.
3486 reset_random();
3487 let next_random = 0i64;
3488
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003489 let app_granted_key = db
Janis Danisevskis66784c42021-01-27 08:40:25 -08003490 .grant(&app_key, CALLER_UID, GRANTEE_UID, PVEC1, |k, a| {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003491 assert_eq!(*a, PVEC1);
3492 assert_eq!(
3493 *k,
3494 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003495 domain: super::Domain::APP,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003496 // namespace must be set to the caller_uid.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003497 nspace: CALLER_UID as i64,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003498 alias: Some("key".to_string()),
3499 blob: None,
3500 }
3501 );
3502 Ok(())
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003503 })
3504 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003505
3506 assert_eq!(
3507 app_granted_key,
3508 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003509 domain: super::Domain::GRANT,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003510 // The grantid is next_random due to the mock random number generator.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003511 nspace: next_random,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003512 alias: None,
3513 blob: None,
3514 }
3515 );
3516
3517 let selinux_key = KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003518 domain: super::Domain::SELINUX,
3519 nspace: SELINUX_NAMESPACE,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003520 alias: Some("yek".to_string()),
3521 blob: None,
3522 };
3523
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003524 let selinux_granted_key = db
Janis Danisevskis66784c42021-01-27 08:40:25 -08003525 .grant(&selinux_key, CALLER_UID, 12, PVEC1, |k, a| {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003526 assert_eq!(*a, PVEC1);
3527 assert_eq!(
3528 *k,
3529 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003530 domain: super::Domain::SELINUX,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003531 // namespace must be the supplied SELinux
3532 // namespace.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003533 nspace: SELINUX_NAMESPACE,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003534 alias: Some("yek".to_string()),
3535 blob: None,
3536 }
3537 );
3538 Ok(())
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003539 })
3540 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003541
3542 assert_eq!(
3543 selinux_granted_key,
3544 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003545 domain: super::Domain::GRANT,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003546 // The grantid is next_random + 1 due to the mock random number generator.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003547 nspace: next_random + 1,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003548 alias: None,
3549 blob: None,
3550 }
3551 );
3552
3553 // This should update the existing grant with PVEC2.
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003554 let selinux_granted_key = db
Janis Danisevskis66784c42021-01-27 08:40:25 -08003555 .grant(&selinux_key, CALLER_UID, 12, PVEC2, |k, a| {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003556 assert_eq!(*a, PVEC2);
3557 assert_eq!(
3558 *k,
3559 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003560 domain: super::Domain::SELINUX,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003561 // namespace must be the supplied SELinux
3562 // namespace.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003563 nspace: SELINUX_NAMESPACE,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003564 alias: Some("yek".to_string()),
3565 blob: None,
3566 }
3567 );
3568 Ok(())
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003569 })
3570 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003571
3572 assert_eq!(
3573 selinux_granted_key,
3574 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003575 domain: super::Domain::GRANT,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003576 // Same grant id as before. The entry was only updated.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003577 nspace: next_random + 1,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003578 alias: None,
3579 blob: None,
3580 }
3581 );
3582
3583 {
3584 // Limiting scope of stmt, because it borrows db.
3585 let mut stmt = db
3586 .conn
Janis Danisevskisbf15d732020-12-08 10:35:26 -08003587 .prepare("SELECT id, grantee, keyentryid, access_vector FROM persistent.grant;")?;
Janis Danisevskisee10b5f2020-09-22 16:42:35 -07003588 let mut rows =
3589 stmt.query_map::<(i64, u32, i64, KeyPermSet), _, _>(NO_PARAMS, |row| {
3590 Ok((
3591 row.get(0)?,
3592 row.get(1)?,
3593 row.get(2)?,
3594 KeyPermSet::from(row.get::<_, i32>(3)?),
3595 ))
3596 })?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003597
3598 let r = rows.next().unwrap().unwrap();
Janis Danisevskisee10b5f2020-09-22 16:42:35 -07003599 assert_eq!(r, (next_random, GRANTEE_UID, 1, PVEC1));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003600 let r = rows.next().unwrap().unwrap();
Janis Danisevskisee10b5f2020-09-22 16:42:35 -07003601 assert_eq!(r, (next_random + 1, GRANTEE_UID, 2, PVEC2));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003602 assert!(rows.next().is_none());
3603 }
3604
3605 debug_dump_keyentry_table(&mut db)?;
3606 println!("app_key {:?}", app_key);
3607 println!("selinux_key {:?}", selinux_key);
3608
Janis Danisevskis66784c42021-01-27 08:40:25 -08003609 db.ungrant(&app_key, CALLER_UID, GRANTEE_UID, |_| Ok(()))?;
3610 db.ungrant(&selinux_key, CALLER_UID, GRANTEE_UID, |_| Ok(()))?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003611
3612 Ok(())
3613 }
3614
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003615 static TEST_KEY_BLOB: &[u8] = b"my test blob";
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003616 static TEST_CERT_BLOB: &[u8] = b"my test cert";
3617 static TEST_CERT_CHAIN_BLOB: &[u8] = b"my test cert_chain";
3618
3619 #[test]
Janis Danisevskis377d1002021-01-27 19:07:48 -08003620 fn test_set_blob() -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003621 let key_id = KEY_ID_LOCK.get(3000);
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003622 let mut db = new_test_db()?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003623 let mut blob_metadata = BlobMetaData::new();
3624 blob_metadata.add(BlobMetaEntry::KmUuid(KEYSTORE_UUID));
3625 db.set_blob(
3626 &key_id,
3627 SubComponentType::KEY_BLOB,
3628 Some(TEST_KEY_BLOB),
3629 Some(&blob_metadata),
3630 )?;
3631 db.set_blob(&key_id, SubComponentType::CERT, Some(TEST_CERT_BLOB), None)?;
3632 db.set_blob(&key_id, SubComponentType::CERT_CHAIN, Some(TEST_CERT_CHAIN_BLOB), None)?;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003633 drop(key_id);
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003634
3635 let mut stmt = db.conn.prepare(
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003636 "SELECT subcomponent_type, keyentryid, blob, id FROM persistent.blobentry
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003637 ORDER BY subcomponent_type ASC;",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003638 )?;
3639 let mut rows = stmt
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003640 .query_map::<((SubComponentType, i64, Vec<u8>), i64), _, _>(NO_PARAMS, |row| {
3641 Ok(((row.get(0)?, row.get(1)?, row.get(2)?), row.get(3)?))
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003642 })?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003643 let (r, id) = rows.next().unwrap().unwrap();
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003644 assert_eq!(r, (SubComponentType::KEY_BLOB, 3000, TEST_KEY_BLOB.to_vec()));
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003645 let (r, _) = rows.next().unwrap().unwrap();
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003646 assert_eq!(r, (SubComponentType::CERT, 3000, TEST_CERT_BLOB.to_vec()));
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003647 let (r, _) = rows.next().unwrap().unwrap();
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003648 assert_eq!(r, (SubComponentType::CERT_CHAIN, 3000, TEST_CERT_CHAIN_BLOB.to_vec()));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003649
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003650 drop(rows);
3651 drop(stmt);
3652
3653 assert_eq!(
3654 db.with_transaction(TransactionBehavior::Immediate, |tx| {
3655 BlobMetaData::load_from_db(id, tx).no_gc()
3656 })
3657 .expect("Should find blob metadata."),
3658 blob_metadata
3659 );
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003660 Ok(())
3661 }
3662
3663 static TEST_ALIAS: &str = "my super duper key";
3664
3665 #[test]
3666 fn test_insert_and_load_full_keyentry_domain_app() -> Result<()> {
3667 let mut db = new_test_db()?;
Qi Wub9433b52020-12-01 14:52:46 +08003668 let key_id = make_test_key_entry(&mut db, Domain::APP, 1, TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08003669 .context("test_insert_and_load_full_keyentry_domain_app")?
3670 .0;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003671 let (_key_guard, key_entry) = db
3672 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003673 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003674 domain: Domain::APP,
3675 nspace: 0,
3676 alias: Some(TEST_ALIAS.to_string()),
3677 blob: None,
3678 },
3679 KeyType::Client,
3680 KeyEntryLoadBits::BOTH,
3681 1,
3682 |_k, _av| Ok(()),
3683 )
3684 .unwrap();
Qi Wub9433b52020-12-01 14:52:46 +08003685 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003686
3687 db.unbind_key(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003688 &KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003689 domain: Domain::APP,
3690 nspace: 0,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003691 alias: Some(TEST_ALIAS.to_string()),
3692 blob: None,
3693 },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003694 KeyType::Client,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003695 1,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003696 |_, _| Ok(()),
3697 )
3698 .unwrap();
3699
3700 assert_eq!(
3701 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
3702 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003703 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003704 domain: Domain::APP,
3705 nspace: 0,
3706 alias: Some(TEST_ALIAS.to_string()),
3707 blob: None,
3708 },
3709 KeyType::Client,
3710 KeyEntryLoadBits::NONE,
3711 1,
3712 |_k, _av| Ok(()),
3713 )
3714 .unwrap_err()
3715 .root_cause()
3716 .downcast_ref::<KsError>()
3717 );
3718
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003719 Ok(())
3720 }
3721
3722 #[test]
Janis Danisevskis377d1002021-01-27 19:07:48 -08003723 fn test_insert_and_load_certificate_entry_domain_app() -> Result<()> {
3724 let mut db = new_test_db()?;
3725
3726 db.store_new_certificate(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003727 &KeyDescriptor {
Janis Danisevskis377d1002021-01-27 19:07:48 -08003728 domain: Domain::APP,
3729 nspace: 1,
3730 alias: Some(TEST_ALIAS.to_string()),
3731 blob: None,
3732 },
3733 TEST_CERT_BLOB,
Max Bires8e93d2b2021-01-14 13:17:59 -08003734 &KEYSTORE_UUID,
Janis Danisevskis377d1002021-01-27 19:07:48 -08003735 )
3736 .expect("Trying to insert cert.");
3737
3738 let (_key_guard, mut key_entry) = db
3739 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003740 &KeyDescriptor {
Janis Danisevskis377d1002021-01-27 19:07:48 -08003741 domain: Domain::APP,
3742 nspace: 1,
3743 alias: Some(TEST_ALIAS.to_string()),
3744 blob: None,
3745 },
3746 KeyType::Client,
3747 KeyEntryLoadBits::PUBLIC,
3748 1,
3749 |_k, _av| Ok(()),
3750 )
3751 .expect("Trying to read certificate entry.");
3752
3753 assert!(key_entry.pure_cert());
3754 assert!(key_entry.cert().is_none());
3755 assert_eq!(key_entry.take_cert_chain(), Some(TEST_CERT_BLOB.to_vec()));
3756
3757 db.unbind_key(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003758 &KeyDescriptor {
Janis Danisevskis377d1002021-01-27 19:07:48 -08003759 domain: Domain::APP,
3760 nspace: 1,
3761 alias: Some(TEST_ALIAS.to_string()),
3762 blob: None,
3763 },
3764 KeyType::Client,
3765 1,
3766 |_, _| Ok(()),
3767 )
3768 .unwrap();
3769
3770 assert_eq!(
3771 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
3772 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003773 &KeyDescriptor {
Janis Danisevskis377d1002021-01-27 19:07:48 -08003774 domain: Domain::APP,
3775 nspace: 1,
3776 alias: Some(TEST_ALIAS.to_string()),
3777 blob: None,
3778 },
3779 KeyType::Client,
3780 KeyEntryLoadBits::NONE,
3781 1,
3782 |_k, _av| Ok(()),
3783 )
3784 .unwrap_err()
3785 .root_cause()
3786 .downcast_ref::<KsError>()
3787 );
3788
3789 Ok(())
3790 }
3791
3792 #[test]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003793 fn test_insert_and_load_full_keyentry_domain_selinux() -> Result<()> {
3794 let mut db = new_test_db()?;
Qi Wub9433b52020-12-01 14:52:46 +08003795 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08003796 .context("test_insert_and_load_full_keyentry_domain_selinux")?
3797 .0;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003798 let (_key_guard, key_entry) = db
3799 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003800 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003801 domain: Domain::SELINUX,
3802 nspace: 1,
3803 alias: Some(TEST_ALIAS.to_string()),
3804 blob: None,
3805 },
3806 KeyType::Client,
3807 KeyEntryLoadBits::BOTH,
3808 1,
3809 |_k, _av| Ok(()),
3810 )
3811 .unwrap();
Qi Wub9433b52020-12-01 14:52:46 +08003812 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003813
3814 db.unbind_key(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003815 &KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003816 domain: Domain::SELINUX,
3817 nspace: 1,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003818 alias: Some(TEST_ALIAS.to_string()),
3819 blob: None,
3820 },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003821 KeyType::Client,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003822 1,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003823 |_, _| Ok(()),
3824 )
3825 .unwrap();
3826
3827 assert_eq!(
3828 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
3829 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003830 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003831 domain: Domain::SELINUX,
3832 nspace: 1,
3833 alias: Some(TEST_ALIAS.to_string()),
3834 blob: None,
3835 },
3836 KeyType::Client,
3837 KeyEntryLoadBits::NONE,
3838 1,
3839 |_k, _av| Ok(()),
3840 )
3841 .unwrap_err()
3842 .root_cause()
3843 .downcast_ref::<KsError>()
3844 );
3845
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003846 Ok(())
3847 }
3848
3849 #[test]
3850 fn test_insert_and_load_full_keyentry_domain_key_id() -> Result<()> {
3851 let mut db = new_test_db()?;
Qi Wub9433b52020-12-01 14:52:46 +08003852 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08003853 .context("test_insert_and_load_full_keyentry_domain_key_id")?
3854 .0;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003855 let (_, key_entry) = db
3856 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003857 &KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003858 KeyType::Client,
3859 KeyEntryLoadBits::BOTH,
3860 1,
3861 |_k, _av| Ok(()),
3862 )
3863 .unwrap();
3864
Qi Wub9433b52020-12-01 14:52:46 +08003865 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003866
3867 db.unbind_key(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003868 &KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003869 KeyType::Client,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003870 1,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003871 |_, _| Ok(()),
3872 )
3873 .unwrap();
3874
3875 assert_eq!(
3876 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
3877 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003878 &KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003879 KeyType::Client,
3880 KeyEntryLoadBits::NONE,
3881 1,
3882 |_k, _av| Ok(()),
3883 )
3884 .unwrap_err()
3885 .root_cause()
3886 .downcast_ref::<KsError>()
3887 );
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003888
3889 Ok(())
3890 }
3891
3892 #[test]
Qi Wub9433b52020-12-01 14:52:46 +08003893 fn test_check_and_update_key_usage_count_with_limited_use_key() -> Result<()> {
3894 let mut db = new_test_db()?;
3895 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, Some(123))
3896 .context("test_check_and_update_key_usage_count_with_limited_use_key")?
3897 .0;
3898 // Update the usage count of the limited use key.
3899 db.check_and_update_key_usage_count(key_id)?;
3900
3901 let (_key_guard, key_entry) = db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003902 &KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
Qi Wub9433b52020-12-01 14:52:46 +08003903 KeyType::Client,
3904 KeyEntryLoadBits::BOTH,
3905 1,
3906 |_k, _av| Ok(()),
3907 )?;
3908
3909 // The usage count is decremented now.
3910 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, Some(122)));
3911
3912 Ok(())
3913 }
3914
3915 #[test]
3916 fn test_check_and_update_key_usage_count_with_exhausted_limited_use_key() -> Result<()> {
3917 let mut db = new_test_db()?;
3918 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, Some(1))
3919 .context("test_check_and_update_key_usage_count_with_exhausted_limited_use_key")?
3920 .0;
3921 // Update the usage count of the limited use key.
3922 db.check_and_update_key_usage_count(key_id).expect(concat!(
3923 "In test_check_and_update_key_usage_count_with_exhausted_limited_use_key: ",
3924 "This should succeed."
3925 ));
3926
3927 // Try to update the exhausted limited use key.
3928 let e = db.check_and_update_key_usage_count(key_id).expect_err(concat!(
3929 "In test_check_and_update_key_usage_count_with_exhausted_limited_use_key: ",
3930 "This should fail."
3931 ));
3932 assert_eq!(
3933 &KsError::Km(ErrorCode::INVALID_KEY_BLOB),
3934 e.root_cause().downcast_ref::<KsError>().unwrap()
3935 );
3936
3937 Ok(())
3938 }
3939
3940 #[test]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003941 fn test_insert_and_load_full_keyentry_from_grant() -> Result<()> {
3942 let mut db = new_test_db()?;
Qi Wub9433b52020-12-01 14:52:46 +08003943 let key_id = make_test_key_entry(&mut db, Domain::APP, 1, TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08003944 .context("test_insert_and_load_full_keyentry_from_grant")?
3945 .0;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003946
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003947 let granted_key = db
3948 .grant(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003949 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003950 domain: Domain::APP,
3951 nspace: 0,
3952 alias: Some(TEST_ALIAS.to_string()),
3953 blob: None,
3954 },
3955 1,
3956 2,
3957 key_perm_set![KeyPerm::use_()],
3958 |_k, _av| Ok(()),
3959 )
3960 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003961
3962 debug_dump_grant_table(&mut db)?;
3963
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003964 let (_key_guard, key_entry) = db
Janis Danisevskis66784c42021-01-27 08:40:25 -08003965 .load_key_entry(&granted_key, KeyType::Client, KeyEntryLoadBits::BOTH, 2, |k, av| {
3966 assert_eq!(Domain::GRANT, k.domain);
3967 assert!(av.unwrap().includes(KeyPerm::use_()));
3968 Ok(())
3969 })
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003970 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003971
Qi Wub9433b52020-12-01 14:52:46 +08003972 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003973
Janis Danisevskis66784c42021-01-27 08:40:25 -08003974 db.unbind_key(&granted_key, KeyType::Client, 2, |_, _| Ok(())).unwrap();
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003975
3976 assert_eq!(
3977 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
3978 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003979 &granted_key,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003980 KeyType::Client,
3981 KeyEntryLoadBits::NONE,
3982 2,
3983 |_k, _av| Ok(()),
3984 )
3985 .unwrap_err()
3986 .root_cause()
3987 .downcast_ref::<KsError>()
3988 );
3989
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003990 Ok(())
3991 }
3992
Janis Danisevskis45760022021-01-19 16:34:10 -08003993 // This test attempts to load a key by key id while the caller is not the owner
3994 // but a grant exists for the given key and the caller.
3995 #[test]
3996 fn test_insert_and_load_full_keyentry_from_grant_by_key_id() -> Result<()> {
3997 let mut db = new_test_db()?;
3998 const OWNER_UID: u32 = 1u32;
3999 const GRANTEE_UID: u32 = 2u32;
4000 const SOMEONE_ELSE_UID: u32 = 3u32;
4001 let key_id = make_test_key_entry(&mut db, Domain::APP, OWNER_UID as i64, TEST_ALIAS, None)
4002 .context("test_insert_and_load_full_keyentry_from_grant_by_key_id")?
4003 .0;
4004
4005 db.grant(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004006 &KeyDescriptor {
Janis Danisevskis45760022021-01-19 16:34:10 -08004007 domain: Domain::APP,
4008 nspace: 0,
4009 alias: Some(TEST_ALIAS.to_string()),
4010 blob: None,
4011 },
4012 OWNER_UID,
4013 GRANTEE_UID,
4014 key_perm_set![KeyPerm::use_()],
4015 |_k, _av| Ok(()),
4016 )
4017 .unwrap();
4018
4019 debug_dump_grant_table(&mut db)?;
4020
4021 let id_descriptor =
4022 KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, ..Default::default() };
4023
4024 let (_, key_entry) = db
4025 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004026 &id_descriptor,
Janis Danisevskis45760022021-01-19 16:34:10 -08004027 KeyType::Client,
4028 KeyEntryLoadBits::BOTH,
4029 GRANTEE_UID,
4030 |k, av| {
4031 assert_eq!(Domain::APP, k.domain);
4032 assert_eq!(OWNER_UID as i64, k.nspace);
4033 assert!(av.unwrap().includes(KeyPerm::use_()));
4034 Ok(())
4035 },
4036 )
4037 .unwrap();
4038
4039 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
4040
4041 let (_, key_entry) = db
4042 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004043 &id_descriptor,
Janis Danisevskis45760022021-01-19 16:34:10 -08004044 KeyType::Client,
4045 KeyEntryLoadBits::BOTH,
4046 SOMEONE_ELSE_UID,
4047 |k, av| {
4048 assert_eq!(Domain::APP, k.domain);
4049 assert_eq!(OWNER_UID as i64, k.nspace);
4050 assert!(av.is_none());
4051 Ok(())
4052 },
4053 )
4054 .unwrap();
4055
4056 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
4057
Janis Danisevskis66784c42021-01-27 08:40:25 -08004058 db.unbind_key(&id_descriptor, KeyType::Client, OWNER_UID, |_, _| Ok(())).unwrap();
Janis Danisevskis45760022021-01-19 16:34:10 -08004059
4060 assert_eq!(
4061 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
4062 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004063 &id_descriptor,
Janis Danisevskis45760022021-01-19 16:34:10 -08004064 KeyType::Client,
4065 KeyEntryLoadBits::NONE,
4066 GRANTEE_UID,
4067 |_k, _av| Ok(()),
4068 )
4069 .unwrap_err()
4070 .root_cause()
4071 .downcast_ref::<KsError>()
4072 );
4073
4074 Ok(())
4075 }
4076
Janis Danisevskisaec14592020-11-12 09:41:49 -08004077 static KEY_LOCK_TEST_ALIAS: &str = "my super duper locked key";
4078
Janis Danisevskisaec14592020-11-12 09:41:49 -08004079 #[test]
4080 fn test_insert_and_load_full_keyentry_domain_app_concurrently() -> Result<()> {
4081 let handle = {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08004082 let temp_dir = Arc::new(TempDir::new("id_lock_test")?);
4083 let temp_dir_clone = temp_dir.clone();
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004084 let mut db = KeystoreDB::new(temp_dir.path(), None)?;
Qi Wub9433b52020-12-01 14:52:46 +08004085 let key_id = make_test_key_entry(&mut db, Domain::APP, 33, KEY_LOCK_TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08004086 .context("test_insert_and_load_full_keyentry_domain_app")?
4087 .0;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004088 let (_key_guard, key_entry) = db
4089 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004090 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004091 domain: Domain::APP,
4092 nspace: 0,
4093 alias: Some(KEY_LOCK_TEST_ALIAS.to_string()),
4094 blob: None,
4095 },
4096 KeyType::Client,
4097 KeyEntryLoadBits::BOTH,
4098 33,
4099 |_k, _av| Ok(()),
4100 )
4101 .unwrap();
Qi Wub9433b52020-12-01 14:52:46 +08004102 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskisaec14592020-11-12 09:41:49 -08004103 let state = Arc::new(AtomicU8::new(1));
4104 let state2 = state.clone();
4105
4106 // Spawning a second thread that attempts to acquire the key id lock
4107 // for the same key as the primary thread. The primary thread then
4108 // waits, thereby forcing the secondary thread into the second stage
4109 // of acquiring the lock (see KEY ID LOCK 2/2 above).
4110 // The test succeeds if the secondary thread observes the transition
4111 // of `state` from 1 to 2, despite having a whole second to overtake
4112 // the primary thread.
4113 let handle = thread::spawn(move || {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08004114 let temp_dir = temp_dir_clone;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004115 let mut db = KeystoreDB::new(temp_dir.path(), None).unwrap();
Janis Danisevskisaec14592020-11-12 09:41:49 -08004116 assert!(db
4117 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004118 &KeyDescriptor {
Janis Danisevskisaec14592020-11-12 09:41:49 -08004119 domain: Domain::APP,
4120 nspace: 0,
4121 alias: Some(KEY_LOCK_TEST_ALIAS.to_string()),
4122 blob: None,
4123 },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004124 KeyType::Client,
Janis Danisevskisaec14592020-11-12 09:41:49 -08004125 KeyEntryLoadBits::BOTH,
4126 33,
4127 |_k, _av| Ok(()),
4128 )
4129 .is_ok());
4130 // We should only see a 2 here because we can only return
4131 // from load_key_entry when the `_key_guard` expires,
4132 // which happens at the end of the scope.
4133 assert_eq!(2, state2.load(Ordering::Relaxed));
4134 });
4135
4136 thread::sleep(std::time::Duration::from_millis(1000));
4137
4138 assert_eq!(Ok(1), state.compare_exchange(1, 2, Ordering::Relaxed, Ordering::Relaxed));
4139
4140 // Return the handle from this scope so we can join with the
4141 // secondary thread after the key id lock has expired.
4142 handle
4143 // This is where the `_key_guard` goes out of scope,
4144 // which is the reason for concurrent load_key_entry on the same key
4145 // to unblock.
4146 };
4147 // Join with the secondary thread and unwrap, to propagate failing asserts to the
4148 // main test thread. We will not see failing asserts in secondary threads otherwise.
4149 handle.join().unwrap();
4150 Ok(())
4151 }
4152
Janis Danisevskise92a5e62020-12-02 12:57:41 -08004153 #[test]
Janis Danisevskis66784c42021-01-27 08:40:25 -08004154 fn teset_database_busy_error_code() {
4155 let temp_dir =
4156 TempDir::new("test_database_busy_error_code_").expect("Failed to create temp dir.");
4157
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004158 let mut db1 = KeystoreDB::new(temp_dir.path(), None).expect("Failed to open database1.");
4159 let mut db2 = KeystoreDB::new(temp_dir.path(), None).expect("Failed to open database2.");
Janis Danisevskis66784c42021-01-27 08:40:25 -08004160
4161 let _tx1 = db1
4162 .conn
4163 .transaction_with_behavior(TransactionBehavior::Immediate)
4164 .expect("Failed to create first transaction.");
4165
4166 let error = db2
4167 .conn
4168 .transaction_with_behavior(TransactionBehavior::Immediate)
4169 .context("Transaction begin failed.")
4170 .expect_err("This should fail.");
4171 let root_cause = error.root_cause();
4172 if let Some(rusqlite::ffi::Error { code: rusqlite::ErrorCode::DatabaseBusy, .. }) =
4173 root_cause.downcast_ref::<rusqlite::ffi::Error>()
4174 {
4175 return;
4176 }
4177 panic!(
4178 "Unexpected error {:?} \n{:?} \n{:?}",
4179 error,
4180 root_cause,
4181 root_cause.downcast_ref::<rusqlite::ffi::Error>()
4182 )
4183 }
4184
4185 #[cfg(disabled)]
4186 #[test]
4187 fn test_large_number_of_concurrent_db_manipulations() -> Result<()> {
4188 let temp_dir = Arc::new(
4189 TempDir::new("test_large_number_of_concurrent_db_manipulations_")
4190 .expect("Failed to create temp dir."),
4191 );
4192
4193 let test_begin = Instant::now();
4194
4195 let mut db = KeystoreDB::new(temp_dir.path()).expect("Failed to open database.");
4196 const KEY_COUNT: u32 = 500u32;
4197 const OPEN_DB_COUNT: u32 = 50u32;
4198
4199 let mut actual_key_count = KEY_COUNT;
4200 // First insert KEY_COUNT keys.
4201 for count in 0..KEY_COUNT {
4202 if Instant::now().duration_since(test_begin) >= Duration::from_secs(15) {
4203 actual_key_count = count;
4204 break;
4205 }
4206 let alias = format!("test_alias_{}", count);
4207 make_test_key_entry(&mut db, Domain::APP, 1, &alias, None)
4208 .expect("Failed to make key entry.");
4209 }
4210
4211 // Insert more keys from a different thread and into a different namespace.
4212 let temp_dir1 = temp_dir.clone();
4213 let handle1 = thread::spawn(move || {
4214 let mut db = KeystoreDB::new(temp_dir1.path()).expect("Failed to open database.");
4215
4216 for count in 0..actual_key_count {
4217 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
4218 return;
4219 }
4220 let alias = format!("test_alias_{}", count);
4221 make_test_key_entry(&mut db, Domain::APP, 2, &alias, None)
4222 .expect("Failed to make key entry.");
4223 }
4224
4225 // then unbind them again.
4226 for count in 0..actual_key_count {
4227 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
4228 return;
4229 }
4230 let key = KeyDescriptor {
4231 domain: Domain::APP,
4232 nspace: -1,
4233 alias: Some(format!("test_alias_{}", count)),
4234 blob: None,
4235 };
4236 db.unbind_key(&key, KeyType::Client, 2, |_, _| Ok(())).expect("Unbind Failed.");
4237 }
4238 });
4239
4240 // And start unbinding the first set of keys.
4241 let temp_dir2 = temp_dir.clone();
4242 let handle2 = thread::spawn(move || {
4243 let mut db = KeystoreDB::new(temp_dir2.path()).expect("Failed to open database.");
4244
4245 for count in 0..actual_key_count {
4246 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
4247 return;
4248 }
4249 let key = KeyDescriptor {
4250 domain: Domain::APP,
4251 nspace: -1,
4252 alias: Some(format!("test_alias_{}", count)),
4253 blob: None,
4254 };
4255 db.unbind_key(&key, KeyType::Client, 1, |_, _| Ok(())).expect("Unbind Failed.");
4256 }
4257 });
4258
4259 let stop_deleting = Arc::new(AtomicU8::new(0));
4260 let stop_deleting2 = stop_deleting.clone();
4261
4262 // And delete anything that is unreferenced keys.
4263 let temp_dir3 = temp_dir.clone();
4264 let handle3 = thread::spawn(move || {
4265 let mut db = KeystoreDB::new(temp_dir3.path()).expect("Failed to open database.");
4266
4267 while stop_deleting2.load(Ordering::Relaxed) != 1 {
4268 while let Some((key_guard, _key)) =
4269 db.get_unreferenced_key().expect("Failed to get unreferenced Key.")
4270 {
4271 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
4272 return;
4273 }
4274 db.purge_key_entry(key_guard).expect("Failed to purge key.");
4275 }
4276 std::thread::sleep(std::time::Duration::from_millis(100));
4277 }
4278 });
4279
4280 // While a lot of inserting and deleting is going on we have to open database connections
4281 // successfully and use them.
4282 // This clone is not redundant, because temp_dir needs to be kept alive until db goes
4283 // out of scope.
4284 #[allow(clippy::redundant_clone)]
4285 let temp_dir4 = temp_dir.clone();
4286 let handle4 = thread::spawn(move || {
4287 for count in 0..OPEN_DB_COUNT {
4288 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
4289 return;
4290 }
4291 let mut db = KeystoreDB::new(temp_dir4.path()).expect("Failed to open database.");
4292
4293 let alias = format!("test_alias_{}", count);
4294 make_test_key_entry(&mut db, Domain::APP, 3, &alias, None)
4295 .expect("Failed to make key entry.");
4296 let key = KeyDescriptor {
4297 domain: Domain::APP,
4298 nspace: -1,
4299 alias: Some(alias),
4300 blob: None,
4301 };
4302 db.unbind_key(&key, KeyType::Client, 3, |_, _| Ok(())).expect("Unbind Failed.");
4303 }
4304 });
4305
4306 handle1.join().expect("Thread 1 panicked.");
4307 handle2.join().expect("Thread 2 panicked.");
4308 handle4.join().expect("Thread 4 panicked.");
4309
4310 stop_deleting.store(1, Ordering::Relaxed);
4311 handle3.join().expect("Thread 3 panicked.");
4312
4313 Ok(())
4314 }
4315
4316 #[test]
Janis Danisevskise92a5e62020-12-02 12:57:41 -08004317 fn list() -> Result<()> {
4318 let temp_dir = TempDir::new("list_test")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004319 let mut db = KeystoreDB::new(temp_dir.path(), None)?;
Janis Danisevskise92a5e62020-12-02 12:57:41 -08004320 static LIST_O_ENTRIES: &[(Domain, i64, &str)] = &[
4321 (Domain::APP, 1, "test1"),
4322 (Domain::APP, 1, "test2"),
4323 (Domain::APP, 1, "test3"),
4324 (Domain::APP, 1, "test4"),
4325 (Domain::APP, 1, "test5"),
4326 (Domain::APP, 1, "test6"),
4327 (Domain::APP, 1, "test7"),
4328 (Domain::APP, 2, "test1"),
4329 (Domain::APP, 2, "test2"),
4330 (Domain::APP, 2, "test3"),
4331 (Domain::APP, 2, "test4"),
4332 (Domain::APP, 2, "test5"),
4333 (Domain::APP, 2, "test6"),
4334 (Domain::APP, 2, "test8"),
4335 (Domain::SELINUX, 100, "test1"),
4336 (Domain::SELINUX, 100, "test2"),
4337 (Domain::SELINUX, 100, "test3"),
4338 (Domain::SELINUX, 100, "test4"),
4339 (Domain::SELINUX, 100, "test5"),
4340 (Domain::SELINUX, 100, "test6"),
4341 (Domain::SELINUX, 100, "test9"),
4342 ];
4343
4344 let list_o_keys: Vec<(i64, i64)> = LIST_O_ENTRIES
4345 .iter()
4346 .map(|(domain, ns, alias)| {
Qi Wub9433b52020-12-01 14:52:46 +08004347 let entry = make_test_key_entry(&mut db, *domain, *ns, *alias, None)
4348 .unwrap_or_else(|e| {
Janis Danisevskise92a5e62020-12-02 12:57:41 -08004349 panic!("Failed to insert {:?} {} {}. Error {:?}", domain, ns, alias, e)
4350 });
4351 (entry.id(), *ns)
4352 })
4353 .collect();
4354
4355 for (domain, namespace) in
4356 &[(Domain::APP, 1i64), (Domain::APP, 2i64), (Domain::SELINUX, 100i64)]
4357 {
4358 let mut list_o_descriptors: Vec<KeyDescriptor> = LIST_O_ENTRIES
4359 .iter()
4360 .filter_map(|(domain, ns, alias)| match ns {
4361 ns if *ns == *namespace => Some(KeyDescriptor {
4362 domain: *domain,
4363 nspace: *ns,
4364 alias: Some(alias.to_string()),
4365 blob: None,
4366 }),
4367 _ => None,
4368 })
4369 .collect();
4370 list_o_descriptors.sort();
4371 let mut list_result = db.list(*domain, *namespace)?;
4372 list_result.sort();
4373 assert_eq!(list_o_descriptors, list_result);
4374
4375 let mut list_o_ids: Vec<i64> = list_o_descriptors
4376 .into_iter()
4377 .map(|d| {
4378 let (_, entry) = db
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004379 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004380 &d,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004381 KeyType::Client,
4382 KeyEntryLoadBits::NONE,
4383 *namespace as u32,
4384 |_, _| Ok(()),
4385 )
Janis Danisevskise92a5e62020-12-02 12:57:41 -08004386 .unwrap();
4387 entry.id()
4388 })
4389 .collect();
4390 list_o_ids.sort_unstable();
4391 let mut loaded_entries: Vec<i64> = list_o_keys
4392 .iter()
4393 .filter_map(|(id, ns)| match ns {
4394 ns if *ns == *namespace => Some(*id),
4395 _ => None,
4396 })
4397 .collect();
4398 loaded_entries.sort_unstable();
4399 assert_eq!(list_o_ids, loaded_entries);
4400 }
4401 assert_eq!(Vec::<KeyDescriptor>::new(), db.list(Domain::SELINUX, 101)?);
4402
4403 Ok(())
4404 }
4405
Joel Galenson0891bc12020-07-20 10:37:03 -07004406 // Helpers
4407
4408 // Checks that the given result is an error containing the given string.
4409 fn check_result_is_error_containing_string<T>(result: Result<T>, target: &str) {
4410 let error_str = format!(
4411 "{:#?}",
4412 result.err().unwrap_or_else(|| panic!("Expected the error: {}", target))
4413 );
4414 assert!(
4415 error_str.contains(target),
4416 "The string \"{}\" should contain \"{}\"",
4417 error_str,
4418 target
4419 );
4420 }
4421
Joel Galenson2aab4432020-07-22 15:27:57 -07004422 #[derive(Debug, PartialEq)]
Joel Galenson0891bc12020-07-20 10:37:03 -07004423 #[allow(dead_code)]
4424 struct KeyEntryRow {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004425 id: i64,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004426 key_type: KeyType,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07004427 domain: Option<Domain>,
Joel Galenson0891bc12020-07-20 10:37:03 -07004428 namespace: Option<i64>,
4429 alias: Option<String>,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004430 state: KeyLifeCycle,
Max Bires8e93d2b2021-01-14 13:17:59 -08004431 km_uuid: Option<Uuid>,
Joel Galenson0891bc12020-07-20 10:37:03 -07004432 }
4433
4434 fn get_keyentry(db: &KeystoreDB) -> Result<Vec<KeyEntryRow>> {
4435 db.conn
Joel Galenson2aab4432020-07-22 15:27:57 -07004436 .prepare("SELECT * FROM persistent.keyentry;")?
Joel Galenson0891bc12020-07-20 10:37:03 -07004437 .query_map(NO_PARAMS, |row| {
Joel Galenson0891bc12020-07-20 10:37:03 -07004438 Ok(KeyEntryRow {
4439 id: row.get(0)?,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004440 key_type: row.get(1)?,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07004441 domain: match row.get(2)? {
4442 Some(i) => Some(Domain(i)),
4443 None => None,
4444 },
Joel Galenson0891bc12020-07-20 10:37:03 -07004445 namespace: row.get(3)?,
4446 alias: row.get(4)?,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004447 state: row.get(5)?,
Max Bires8e93d2b2021-01-14 13:17:59 -08004448 km_uuid: row.get(6)?,
Joel Galenson0891bc12020-07-20 10:37:03 -07004449 })
4450 })?
4451 .map(|r| r.context("Could not read keyentry row."))
4452 .collect::<Result<Vec<_>>>()
4453 }
4454
Max Biresb2e1d032021-02-08 21:35:05 -08004455 struct RemoteProvValues {
4456 cert_chain: Vec<u8>,
4457 priv_key: Vec<u8>,
4458 batch_cert: Vec<u8>,
4459 }
4460
Max Bires2b2e6562020-09-22 11:22:36 -07004461 fn load_attestation_key_pool(
4462 db: &mut KeystoreDB,
4463 expiration_date: i64,
4464 namespace: i64,
4465 base_byte: u8,
Max Biresb2e1d032021-02-08 21:35:05 -08004466 ) -> Result<RemoteProvValues> {
Max Bires2b2e6562020-09-22 11:22:36 -07004467 let public_key: Vec<u8> = vec![base_byte, 0x02 * base_byte];
4468 let cert_chain: Vec<u8> = vec![0x03 * base_byte, 0x04 * base_byte];
4469 let priv_key: Vec<u8> = vec![0x05 * base_byte, 0x06 * base_byte];
4470 let raw_public_key: Vec<u8> = vec![0x0b * base_byte, 0x0c * base_byte];
Max Biresb2e1d032021-02-08 21:35:05 -08004471 let batch_cert: Vec<u8> = vec![base_byte * 0x0d, base_byte * 0x0e];
Max Bires2b2e6562020-09-22 11:22:36 -07004472 db.create_attestation_key_entry(&public_key, &raw_public_key, &priv_key, &KEYSTORE_UUID)?;
4473 db.store_signed_attestation_certificate_chain(
4474 &raw_public_key,
Max Biresb2e1d032021-02-08 21:35:05 -08004475 &batch_cert,
Max Bires2b2e6562020-09-22 11:22:36 -07004476 &cert_chain,
4477 expiration_date,
4478 &KEYSTORE_UUID,
4479 )?;
4480 db.assign_attestation_key(Domain::APP, namespace, &KEYSTORE_UUID)?;
Max Biresb2e1d032021-02-08 21:35:05 -08004481 Ok(RemoteProvValues { cert_chain, priv_key, batch_cert })
Max Bires2b2e6562020-09-22 11:22:36 -07004482 }
4483
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07004484 // Note: The parameters and SecurityLevel associations are nonsensical. This
4485 // collection is only used to check if the parameters are preserved as expected by the
4486 // database.
Qi Wub9433b52020-12-01 14:52:46 +08004487 fn make_test_params(max_usage_count: Option<i32>) -> Vec<KeyParameter> {
4488 let mut params = vec![
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07004489 KeyParameter::new(KeyParameterValue::Invalid, SecurityLevel::TRUSTED_ENVIRONMENT),
4490 KeyParameter::new(
4491 KeyParameterValue::KeyPurpose(KeyPurpose::SIGN),
4492 SecurityLevel::TRUSTED_ENVIRONMENT,
4493 ),
4494 KeyParameter::new(
4495 KeyParameterValue::KeyPurpose(KeyPurpose::DECRYPT),
4496 SecurityLevel::TRUSTED_ENVIRONMENT,
4497 ),
4498 KeyParameter::new(
4499 KeyParameterValue::Algorithm(Algorithm::RSA),
4500 SecurityLevel::TRUSTED_ENVIRONMENT,
4501 ),
4502 KeyParameter::new(KeyParameterValue::KeySize(1024), SecurityLevel::TRUSTED_ENVIRONMENT),
4503 KeyParameter::new(
4504 KeyParameterValue::BlockMode(BlockMode::ECB),
4505 SecurityLevel::TRUSTED_ENVIRONMENT,
4506 ),
4507 KeyParameter::new(
4508 KeyParameterValue::BlockMode(BlockMode::GCM),
4509 SecurityLevel::TRUSTED_ENVIRONMENT,
4510 ),
4511 KeyParameter::new(KeyParameterValue::Digest(Digest::NONE), SecurityLevel::STRONGBOX),
4512 KeyParameter::new(
4513 KeyParameterValue::Digest(Digest::MD5),
4514 SecurityLevel::TRUSTED_ENVIRONMENT,
4515 ),
4516 KeyParameter::new(
4517 KeyParameterValue::Digest(Digest::SHA_2_224),
4518 SecurityLevel::TRUSTED_ENVIRONMENT,
4519 ),
4520 KeyParameter::new(
4521 KeyParameterValue::Digest(Digest::SHA_2_256),
4522 SecurityLevel::STRONGBOX,
4523 ),
4524 KeyParameter::new(
4525 KeyParameterValue::PaddingMode(PaddingMode::NONE),
4526 SecurityLevel::TRUSTED_ENVIRONMENT,
4527 ),
4528 KeyParameter::new(
4529 KeyParameterValue::PaddingMode(PaddingMode::RSA_OAEP),
4530 SecurityLevel::TRUSTED_ENVIRONMENT,
4531 ),
4532 KeyParameter::new(
4533 KeyParameterValue::PaddingMode(PaddingMode::RSA_PSS),
4534 SecurityLevel::STRONGBOX,
4535 ),
4536 KeyParameter::new(
4537 KeyParameterValue::PaddingMode(PaddingMode::RSA_PKCS1_1_5_SIGN),
4538 SecurityLevel::TRUSTED_ENVIRONMENT,
4539 ),
4540 KeyParameter::new(KeyParameterValue::CallerNonce, SecurityLevel::TRUSTED_ENVIRONMENT),
4541 KeyParameter::new(KeyParameterValue::MinMacLength(256), SecurityLevel::STRONGBOX),
4542 KeyParameter::new(
4543 KeyParameterValue::EcCurve(EcCurve::P_224),
4544 SecurityLevel::TRUSTED_ENVIRONMENT,
4545 ),
4546 KeyParameter::new(KeyParameterValue::EcCurve(EcCurve::P_256), SecurityLevel::STRONGBOX),
4547 KeyParameter::new(
4548 KeyParameterValue::EcCurve(EcCurve::P_384),
4549 SecurityLevel::TRUSTED_ENVIRONMENT,
4550 ),
4551 KeyParameter::new(
4552 KeyParameterValue::EcCurve(EcCurve::P_521),
4553 SecurityLevel::TRUSTED_ENVIRONMENT,
4554 ),
4555 KeyParameter::new(
4556 KeyParameterValue::RSAPublicExponent(3),
4557 SecurityLevel::TRUSTED_ENVIRONMENT,
4558 ),
4559 KeyParameter::new(
4560 KeyParameterValue::IncludeUniqueID,
4561 SecurityLevel::TRUSTED_ENVIRONMENT,
4562 ),
4563 KeyParameter::new(KeyParameterValue::BootLoaderOnly, SecurityLevel::STRONGBOX),
4564 KeyParameter::new(KeyParameterValue::RollbackResistance, SecurityLevel::STRONGBOX),
4565 KeyParameter::new(
4566 KeyParameterValue::ActiveDateTime(1234567890),
4567 SecurityLevel::STRONGBOX,
4568 ),
4569 KeyParameter::new(
4570 KeyParameterValue::OriginationExpireDateTime(1234567890),
4571 SecurityLevel::TRUSTED_ENVIRONMENT,
4572 ),
4573 KeyParameter::new(
4574 KeyParameterValue::UsageExpireDateTime(1234567890),
4575 SecurityLevel::TRUSTED_ENVIRONMENT,
4576 ),
4577 KeyParameter::new(
4578 KeyParameterValue::MinSecondsBetweenOps(1234567890),
4579 SecurityLevel::TRUSTED_ENVIRONMENT,
4580 ),
4581 KeyParameter::new(
4582 KeyParameterValue::MaxUsesPerBoot(1234567890),
4583 SecurityLevel::TRUSTED_ENVIRONMENT,
4584 ),
4585 KeyParameter::new(KeyParameterValue::UserID(1), SecurityLevel::STRONGBOX),
4586 KeyParameter::new(KeyParameterValue::UserSecureID(42), SecurityLevel::STRONGBOX),
4587 KeyParameter::new(
4588 KeyParameterValue::NoAuthRequired,
4589 SecurityLevel::TRUSTED_ENVIRONMENT,
4590 ),
4591 KeyParameter::new(
4592 KeyParameterValue::HardwareAuthenticatorType(HardwareAuthenticatorType::PASSWORD),
4593 SecurityLevel::TRUSTED_ENVIRONMENT,
4594 ),
4595 KeyParameter::new(KeyParameterValue::AuthTimeout(1234567890), SecurityLevel::SOFTWARE),
4596 KeyParameter::new(KeyParameterValue::AllowWhileOnBody, SecurityLevel::SOFTWARE),
4597 KeyParameter::new(
4598 KeyParameterValue::TrustedUserPresenceRequired,
4599 SecurityLevel::TRUSTED_ENVIRONMENT,
4600 ),
4601 KeyParameter::new(
4602 KeyParameterValue::TrustedConfirmationRequired,
4603 SecurityLevel::TRUSTED_ENVIRONMENT,
4604 ),
4605 KeyParameter::new(
4606 KeyParameterValue::UnlockedDeviceRequired,
4607 SecurityLevel::TRUSTED_ENVIRONMENT,
4608 ),
4609 KeyParameter::new(
4610 KeyParameterValue::ApplicationID(vec![1u8, 2u8, 3u8, 4u8]),
4611 SecurityLevel::SOFTWARE,
4612 ),
4613 KeyParameter::new(
4614 KeyParameterValue::ApplicationData(vec![4u8, 3u8, 2u8, 1u8]),
4615 SecurityLevel::SOFTWARE,
4616 ),
4617 KeyParameter::new(
4618 KeyParameterValue::CreationDateTime(12345677890),
4619 SecurityLevel::SOFTWARE,
4620 ),
4621 KeyParameter::new(
4622 KeyParameterValue::KeyOrigin(KeyOrigin::GENERATED),
4623 SecurityLevel::TRUSTED_ENVIRONMENT,
4624 ),
4625 KeyParameter::new(
4626 KeyParameterValue::RootOfTrust(vec![3u8, 2u8, 1u8, 4u8]),
4627 SecurityLevel::TRUSTED_ENVIRONMENT,
4628 ),
4629 KeyParameter::new(KeyParameterValue::OSVersion(1), SecurityLevel::TRUSTED_ENVIRONMENT),
4630 KeyParameter::new(KeyParameterValue::OSPatchLevel(2), SecurityLevel::SOFTWARE),
4631 KeyParameter::new(
4632 KeyParameterValue::UniqueID(vec![4u8, 3u8, 1u8, 2u8]),
4633 SecurityLevel::SOFTWARE,
4634 ),
4635 KeyParameter::new(
4636 KeyParameterValue::AttestationChallenge(vec![4u8, 3u8, 1u8, 2u8]),
4637 SecurityLevel::TRUSTED_ENVIRONMENT,
4638 ),
4639 KeyParameter::new(
4640 KeyParameterValue::AttestationApplicationID(vec![4u8, 3u8, 1u8, 2u8]),
4641 SecurityLevel::TRUSTED_ENVIRONMENT,
4642 ),
4643 KeyParameter::new(
4644 KeyParameterValue::AttestationIdBrand(vec![4u8, 3u8, 1u8, 2u8]),
4645 SecurityLevel::TRUSTED_ENVIRONMENT,
4646 ),
4647 KeyParameter::new(
4648 KeyParameterValue::AttestationIdDevice(vec![4u8, 3u8, 1u8, 2u8]),
4649 SecurityLevel::TRUSTED_ENVIRONMENT,
4650 ),
4651 KeyParameter::new(
4652 KeyParameterValue::AttestationIdProduct(vec![4u8, 3u8, 1u8, 2u8]),
4653 SecurityLevel::TRUSTED_ENVIRONMENT,
4654 ),
4655 KeyParameter::new(
4656 KeyParameterValue::AttestationIdSerial(vec![4u8, 3u8, 1u8, 2u8]),
4657 SecurityLevel::TRUSTED_ENVIRONMENT,
4658 ),
4659 KeyParameter::new(
4660 KeyParameterValue::AttestationIdIMEI(vec![4u8, 3u8, 1u8, 2u8]),
4661 SecurityLevel::TRUSTED_ENVIRONMENT,
4662 ),
4663 KeyParameter::new(
4664 KeyParameterValue::AttestationIdMEID(vec![4u8, 3u8, 1u8, 2u8]),
4665 SecurityLevel::TRUSTED_ENVIRONMENT,
4666 ),
4667 KeyParameter::new(
4668 KeyParameterValue::AttestationIdManufacturer(vec![4u8, 3u8, 1u8, 2u8]),
4669 SecurityLevel::TRUSTED_ENVIRONMENT,
4670 ),
4671 KeyParameter::new(
4672 KeyParameterValue::AttestationIdModel(vec![4u8, 3u8, 1u8, 2u8]),
4673 SecurityLevel::TRUSTED_ENVIRONMENT,
4674 ),
4675 KeyParameter::new(
4676 KeyParameterValue::VendorPatchLevel(3),
4677 SecurityLevel::TRUSTED_ENVIRONMENT,
4678 ),
4679 KeyParameter::new(
4680 KeyParameterValue::BootPatchLevel(4),
4681 SecurityLevel::TRUSTED_ENVIRONMENT,
4682 ),
4683 KeyParameter::new(
4684 KeyParameterValue::AssociatedData(vec![4u8, 3u8, 1u8, 2u8]),
4685 SecurityLevel::TRUSTED_ENVIRONMENT,
4686 ),
4687 KeyParameter::new(
4688 KeyParameterValue::Nonce(vec![4u8, 3u8, 1u8, 2u8]),
4689 SecurityLevel::TRUSTED_ENVIRONMENT,
4690 ),
4691 KeyParameter::new(
4692 KeyParameterValue::MacLength(256),
4693 SecurityLevel::TRUSTED_ENVIRONMENT,
4694 ),
4695 KeyParameter::new(
4696 KeyParameterValue::ResetSinceIdRotation,
4697 SecurityLevel::TRUSTED_ENVIRONMENT,
4698 ),
4699 KeyParameter::new(
4700 KeyParameterValue::ConfirmationToken(vec![5u8, 5u8, 5u8, 5u8]),
4701 SecurityLevel::TRUSTED_ENVIRONMENT,
4702 ),
Qi Wub9433b52020-12-01 14:52:46 +08004703 ];
4704 if let Some(value) = max_usage_count {
4705 params.push(KeyParameter::new(
4706 KeyParameterValue::UsageCountLimit(value),
4707 SecurityLevel::SOFTWARE,
4708 ));
4709 }
4710 params
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07004711 }
4712
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004713 fn make_test_key_entry(
4714 db: &mut KeystoreDB,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07004715 domain: Domain,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004716 namespace: i64,
4717 alias: &str,
Qi Wub9433b52020-12-01 14:52:46 +08004718 max_usage_count: Option<i32>,
Janis Danisevskisaec14592020-11-12 09:41:49 -08004719 ) -> Result<KeyIdGuard> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08004720 let key_id = db.create_key_entry(&domain, &namespace, &KEYSTORE_UUID)?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004721 let mut blob_metadata = BlobMetaData::new();
4722 blob_metadata.add(BlobMetaEntry::EncryptedBy(EncryptedBy::Password));
4723 blob_metadata.add(BlobMetaEntry::Salt(vec![1, 2, 3]));
4724 blob_metadata.add(BlobMetaEntry::Iv(vec![2, 3, 1]));
4725 blob_metadata.add(BlobMetaEntry::AeadTag(vec![3, 1, 2]));
4726 blob_metadata.add(BlobMetaEntry::KmUuid(KEYSTORE_UUID));
4727
4728 db.set_blob(
4729 &key_id,
4730 SubComponentType::KEY_BLOB,
4731 Some(TEST_KEY_BLOB),
4732 Some(&blob_metadata),
4733 )?;
4734 db.set_blob(&key_id, SubComponentType::CERT, Some(TEST_CERT_BLOB), None)?;
4735 db.set_blob(&key_id, SubComponentType::CERT_CHAIN, Some(TEST_CERT_CHAIN_BLOB), None)?;
Qi Wub9433b52020-12-01 14:52:46 +08004736
4737 let params = make_test_params(max_usage_count);
4738 db.insert_keyparameter(&key_id, &params)?;
4739
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004740 let mut metadata = KeyMetaData::new();
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004741 metadata.add(KeyMetaEntry::CreationDate(DateTime::from_millis_epoch(123456789)));
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004742 db.insert_key_metadata(&key_id, &metadata)?;
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08004743 rebind_alias(db, &key_id, alias, domain, namespace)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004744 Ok(key_id)
4745 }
4746
Qi Wub9433b52020-12-01 14:52:46 +08004747 fn make_test_key_entry_test_vector(key_id: i64, max_usage_count: Option<i32>) -> KeyEntry {
4748 let params = make_test_params(max_usage_count);
4749
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004750 let mut blob_metadata = BlobMetaData::new();
4751 blob_metadata.add(BlobMetaEntry::EncryptedBy(EncryptedBy::Password));
4752 blob_metadata.add(BlobMetaEntry::Salt(vec![1, 2, 3]));
4753 blob_metadata.add(BlobMetaEntry::Iv(vec![2, 3, 1]));
4754 blob_metadata.add(BlobMetaEntry::AeadTag(vec![3, 1, 2]));
4755 blob_metadata.add(BlobMetaEntry::KmUuid(KEYSTORE_UUID));
4756
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004757 let mut metadata = KeyMetaData::new();
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004758 metadata.add(KeyMetaEntry::CreationDate(DateTime::from_millis_epoch(123456789)));
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004759
4760 KeyEntry {
4761 id: key_id,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004762 key_blob_info: Some((TEST_KEY_BLOB.to_vec(), blob_metadata)),
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004763 cert: Some(TEST_CERT_BLOB.to_vec()),
4764 cert_chain: Some(TEST_CERT_CHAIN_BLOB.to_vec()),
Max Bires8e93d2b2021-01-14 13:17:59 -08004765 km_uuid: KEYSTORE_UUID,
Qi Wub9433b52020-12-01 14:52:46 +08004766 parameters: params,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004767 metadata,
Janis Danisevskis377d1002021-01-27 19:07:48 -08004768 pure_cert: false,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004769 }
4770 }
4771
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004772 fn debug_dump_keyentry_table(db: &mut KeystoreDB) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004773 let mut stmt = db.conn.prepare(
Max Bires8e93d2b2021-01-14 13:17:59 -08004774 "SELECT id, key_type, domain, namespace, alias, state, km_uuid FROM persistent.keyentry;",
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004775 )?;
Max Bires8e93d2b2021-01-14 13:17:59 -08004776 let rows = stmt.query_map::<(i64, KeyType, i32, i64, String, KeyLifeCycle, Uuid), _, _>(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004777 NO_PARAMS,
4778 |row| {
Max Bires8e93d2b2021-01-14 13:17:59 -08004779 Ok((
4780 row.get(0)?,
4781 row.get(1)?,
4782 row.get(2)?,
4783 row.get(3)?,
4784 row.get(4)?,
4785 row.get(5)?,
4786 row.get(6)?,
4787 ))
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004788 },
4789 )?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004790
4791 println!("Key entry table rows:");
4792 for r in rows {
Max Bires8e93d2b2021-01-14 13:17:59 -08004793 let (id, key_type, domain, namespace, alias, state, km_uuid) = r.unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004794 println!(
Max Bires8e93d2b2021-01-14 13:17:59 -08004795 " id: {} KeyType: {:?} Domain: {} Namespace: {} Alias: {} State: {:?} KmUuid: {:?}",
4796 id, key_type, domain, namespace, alias, state, km_uuid
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004797 );
4798 }
4799 Ok(())
4800 }
4801
4802 fn debug_dump_grant_table(db: &mut KeystoreDB) -> Result<()> {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08004803 let mut stmt = db
4804 .conn
4805 .prepare("SELECT id, grantee, keyentryid, access_vector FROM persistent.grant;")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004806 let rows = stmt.query_map::<(i64, i64, i64, i64), _, _>(NO_PARAMS, |row| {
4807 Ok((row.get(0)?, row.get(1)?, row.get(2)?, row.get(3)?))
4808 })?;
4809
4810 println!("Grant table rows:");
4811 for r in rows {
4812 let (id, gt, ki, av) = r.unwrap();
4813 println!(" id: {} grantee: {} key_id: {} access_vector: {}", id, gt, ki, av);
4814 }
4815 Ok(())
4816 }
4817
Joel Galenson0891bc12020-07-20 10:37:03 -07004818 // Use a custom random number generator that repeats each number once.
4819 // This allows us to test repeated elements.
4820
4821 thread_local! {
4822 static RANDOM_COUNTER: RefCell<i64> = RefCell::new(0);
4823 }
4824
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004825 fn reset_random() {
4826 RANDOM_COUNTER.with(|counter| {
4827 *counter.borrow_mut() = 0;
4828 })
4829 }
4830
Joel Galenson0891bc12020-07-20 10:37:03 -07004831 pub fn random() -> i64 {
4832 RANDOM_COUNTER.with(|counter| {
4833 let result = *counter.borrow() / 2;
4834 *counter.borrow_mut() += 1;
4835 result
4836 })
4837 }
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00004838
4839 #[test]
4840 fn test_last_off_body() -> Result<()> {
4841 let mut db = new_test_db()?;
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08004842 db.insert_last_off_body(MonotonicRawTime::now())?;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00004843 let tx = db.conn.transaction_with_behavior(TransactionBehavior::Immediate)?;
4844 let last_off_body_1 = KeystoreDB::get_last_off_body(&tx)?;
4845 tx.commit()?;
4846 let one_second = Duration::from_secs(1);
4847 thread::sleep(one_second);
4848 db.update_last_off_body(MonotonicRawTime::now())?;
4849 let tx2 = db.conn.transaction_with_behavior(TransactionBehavior::Immediate)?;
4850 let last_off_body_2 = KeystoreDB::get_last_off_body(&tx2)?;
4851 tx2.commit()?;
4852 assert!(last_off_body_1.seconds() < last_off_body_2.seconds());
4853 Ok(())
4854 }
Hasini Gunasingheda895552021-01-27 19:34:37 +00004855
4856 #[test]
4857 fn test_unbind_keys_for_user() -> Result<()> {
4858 let mut db = new_test_db()?;
4859 db.unbind_keys_for_user(1, false)?;
4860
4861 make_test_key_entry(&mut db, Domain::APP, 210000, TEST_ALIAS, None)?;
4862 make_test_key_entry(&mut db, Domain::APP, 110000, TEST_ALIAS, None)?;
4863 db.unbind_keys_for_user(2, false)?;
4864
4865 assert_eq!(1, db.list(Domain::APP, 110000)?.len());
4866 assert_eq!(0, db.list(Domain::APP, 210000)?.len());
4867
4868 db.unbind_keys_for_user(1, true)?;
4869 assert_eq!(0, db.list(Domain::APP, 110000)?.len());
4870
4871 Ok(())
4872 }
4873
4874 #[test]
4875 fn test_store_super_key() -> Result<()> {
4876 let mut db = new_test_db()?;
4877 let pw = "xyzabc".as_bytes();
4878 let super_key = keystore2_crypto::generate_aes256_key()?;
4879 let secret = String::from("keystore2 is great.");
4880 let secret_bytes = secret.into_bytes();
4881 let (encrypted_secret, iv, tag) =
4882 keystore2_crypto::aes_gcm_encrypt(&secret_bytes, &super_key)?;
4883
4884 let (encrypted_super_key, metadata) =
4885 SuperKeyManager::encrypt_with_password(&super_key, &pw)?;
4886 db.store_super_key(1, &(&encrypted_super_key, &metadata))?;
4887
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00004888 //check if super key exists
4889 assert!(db.key_exists(Domain::APP, 1, "USER_SUPER_KEY", KeyType::Super)?);
4890
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +00004891 let (_, key_entry) = db.load_super_key(1)?.unwrap();
Hasini Gunasingheda895552021-01-27 19:34:37 +00004892 let loaded_super_key = SuperKeyManager::extract_super_key_from_key_entry(key_entry, &pw)?;
4893
4894 let decrypted_secret_bytes = keystore2_crypto::aes_gcm_decrypt(
4895 &encrypted_secret,
4896 &iv,
4897 &tag,
4898 &loaded_super_key.get_key(),
4899 )?;
4900 let decrypted_secret = String::from_utf8((&decrypted_secret_bytes).to_vec())?;
4901 assert_eq!(String::from("keystore2 is great."), decrypted_secret);
4902 Ok(())
4903 }
Joel Galenson26f4d012020-07-17 14:57:21 -07004904}