blob: 0e8b3d7e5d84c569c2f55150012b7f2a2c38a41e [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
David Drysdale0e45a612021-02-25 17:24:36 +0000736 /// Constructs a new MonotonicRawTime from a given number of seconds.
737 pub fn from_secs(val: i64) -> Self {
738 Self(val)
739 }
740
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000741 /// Returns the integer value of MonotonicRawTime as i64
742 pub fn seconds(&self) -> i64 {
743 self.0
744 }
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800745
Hasini Gunasingheb3715fb2021-02-26 20:34:45 +0000746 /// Returns the value of MonotonicRawTime in milli seconds as i64
747 pub fn milli_seconds(&self) -> i64 {
748 self.0 * 1000
749 }
750
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800751 /// Like i64::checked_sub.
752 pub fn checked_sub(&self, other: &Self) -> Option<Self> {
753 self.0.checked_sub(other.0).map(Self)
754 }
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000755}
756
757impl ToSql for MonotonicRawTime {
758 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
759 Ok(ToSqlOutput::Owned(Value::Integer(self.0)))
760 }
761}
762
763impl FromSql for MonotonicRawTime {
764 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
765 Ok(Self(i64::column_result(value)?))
766 }
767}
768
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000769/// This struct encapsulates the information to be stored in the database about the auth tokens
770/// received by keystore.
771pub struct AuthTokenEntry {
772 auth_token: HardwareAuthToken,
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000773 time_received: MonotonicRawTime,
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000774}
775
776impl AuthTokenEntry {
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000777 fn new(auth_token: HardwareAuthToken, time_received: MonotonicRawTime) -> Self {
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000778 AuthTokenEntry { auth_token, time_received }
779 }
780
781 /// Checks if this auth token satisfies the given authentication information.
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800782 pub fn satisfies(&self, user_secure_ids: &[i64], auth_type: HardwareAuthenticatorType) -> bool {
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000783 user_secure_ids.iter().any(|&sid| {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800784 (sid == self.auth_token.userId || sid == self.auth_token.authenticatorId)
785 && (((auth_type.0 as i32) & (self.auth_token.authenticatorType.0 as i32)) != 0)
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000786 })
787 }
788
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000789 /// Returns the auth token wrapped by the AuthTokenEntry
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800790 pub fn auth_token(&self) -> &HardwareAuthToken {
791 &self.auth_token
792 }
793
794 /// Returns the auth token wrapped by the AuthTokenEntry
795 pub fn take_auth_token(self) -> HardwareAuthToken {
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000796 self.auth_token
797 }
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800798
799 /// Returns the time that this auth token was received.
800 pub fn time_received(&self) -> MonotonicRawTime {
801 self.time_received
802 }
Hasini Gunasingheb3715fb2021-02-26 20:34:45 +0000803
804 /// Returns the challenge value of the auth token.
805 pub fn challenge(&self) -> i64 {
806 self.auth_token.challenge
807 }
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000808}
809
Janis Danisevskisb00ebd02021-02-02 21:52:24 -0800810/// Shared in-memory databases get destroyed as soon as the last connection to them gets closed.
811/// This object does not allow access to the database connection. But it keeps a database
812/// connection alive in order to keep the in memory per boot database alive.
813pub struct PerBootDbKeepAlive(Connection);
814
Joel Galenson26f4d012020-07-17 14:57:21 -0700815impl KeystoreDB {
Janis Danisevskiseed69842021-02-18 20:04:10 -0800816 const UNASSIGNED_KEY_ID: i64 = -1i64;
Janis Danisevskisb00ebd02021-02-02 21:52:24 -0800817 const PERBOOT_DB_FILE_NAME: &'static str = &"file:perboot.sqlite?mode=memory&cache=shared";
818
Hasini Gunasinghe0e161452021-01-27 19:34:37 +0000819 /// The alias of the user super key.
820 pub const USER_SUPER_KEY_ALIAS: &'static str = &"USER_SUPER_KEY";
821
Janis Danisevskisb00ebd02021-02-02 21:52:24 -0800822 /// This creates a PerBootDbKeepAlive object to keep the per boot database alive.
823 pub fn keep_perboot_db_alive() -> Result<PerBootDbKeepAlive> {
824 let conn = Connection::open_in_memory()
825 .context("In keep_perboot_db_alive: Failed to initialize SQLite connection.")?;
826
827 conn.execute("ATTACH DATABASE ? as perboot;", params![Self::PERBOOT_DB_FILE_NAME])
828 .context("In keep_perboot_db_alive: Failed to attach database perboot.")?;
829 Ok(PerBootDbKeepAlive(conn))
830 }
831
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700832 /// This will create a new database connection connecting the two
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800833 /// files persistent.sqlite and perboot.sqlite in the given directory.
834 /// It also attempts to initialize all of the tables.
835 /// KeystoreDB cannot be used by multiple threads.
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700836 /// Each thread should open their own connection using `thread_local!`.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800837 pub fn new(db_root: &Path, gc: Option<Gc>) -> Result<Self> {
Janis Danisevskisb00ebd02021-02-02 21:52:24 -0800838 // Build the path to the sqlite file.
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800839 let mut persistent_path = db_root.to_path_buf();
840 persistent_path.push("persistent.sqlite");
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700841
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800842 // Now convert them to strings prefixed with "file:"
843 let mut persistent_path_str = "file:".to_owned();
844 persistent_path_str.push_str(&persistent_path.to_string_lossy());
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800845
Janis Danisevskisb00ebd02021-02-02 21:52:24 -0800846 let conn = Self::make_connection(&persistent_path_str, &Self::PERBOOT_DB_FILE_NAME)?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800847
Janis Danisevskis66784c42021-01-27 08:40:25 -0800848 // On busy fail Immediately. It is unlikely to succeed given a bug in sqlite.
849 conn.busy_handler(None).context("In KeystoreDB::new: Failed to set busy handler.")?;
850
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800851 let mut db = Self { conn, gc };
Janis Danisevskis66784c42021-01-27 08:40:25 -0800852 db.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800853 Self::init_tables(tx).context("Trying to initialize tables.").no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -0800854 })?;
855 Ok(db)
Joel Galenson2aab4432020-07-22 15:27:57 -0700856 }
857
Janis Danisevskis66784c42021-01-27 08:40:25 -0800858 fn init_tables(tx: &Transaction) -> Result<()> {
859 tx.execute(
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700860 "CREATE TABLE IF NOT EXISTS persistent.keyentry (
Joel Galenson0891bc12020-07-20 10:37:03 -0700861 id INTEGER UNIQUE,
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800862 key_type INTEGER,
Joel Galenson0891bc12020-07-20 10:37:03 -0700863 domain INTEGER,
864 namespace INTEGER,
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800865 alias BLOB,
Max Bires8e93d2b2021-01-14 13:17:59 -0800866 state INTEGER,
867 km_uuid BLOB);",
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700868 NO_PARAMS,
869 )
870 .context("Failed to initialize \"keyentry\" table.")?;
871
Janis Danisevskis66784c42021-01-27 08:40:25 -0800872 tx.execute(
Janis Danisevskisa5438182021-02-02 14:22:59 -0800873 "CREATE INDEX IF NOT EXISTS persistent.keyentry_id_index
874 ON keyentry(id);",
875 NO_PARAMS,
876 )
877 .context("Failed to create index keyentry_id_index.")?;
878
879 tx.execute(
880 "CREATE INDEX IF NOT EXISTS persistent.keyentry_domain_namespace_index
881 ON keyentry(domain, namespace, alias);",
882 NO_PARAMS,
883 )
884 .context("Failed to create index keyentry_domain_namespace_index.")?;
885
886 tx.execute(
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700887 "CREATE TABLE IF NOT EXISTS persistent.blobentry (
888 id INTEGER PRIMARY KEY,
889 subcomponent_type INTEGER,
890 keyentryid INTEGER,
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800891 blob BLOB);",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700892 NO_PARAMS,
893 )
894 .context("Failed to initialize \"blobentry\" table.")?;
895
Janis Danisevskis66784c42021-01-27 08:40:25 -0800896 tx.execute(
Janis Danisevskisa5438182021-02-02 14:22:59 -0800897 "CREATE INDEX IF NOT EXISTS persistent.blobentry_keyentryid_index
898 ON blobentry(keyentryid);",
899 NO_PARAMS,
900 )
901 .context("Failed to create index blobentry_keyentryid_index.")?;
902
903 tx.execute(
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800904 "CREATE TABLE IF NOT EXISTS persistent.blobmetadata (
905 id INTEGER PRIMARY KEY,
906 blobentryid INTEGER,
907 tag INTEGER,
908 data ANY,
909 UNIQUE (blobentryid, tag));",
910 NO_PARAMS,
911 )
912 .context("Failed to initialize \"blobmetadata\" table.")?;
913
914 tx.execute(
915 "CREATE INDEX IF NOT EXISTS persistent.blobmetadata_blobentryid_index
916 ON blobmetadata(blobentryid);",
917 NO_PARAMS,
918 )
919 .context("Failed to create index blobmetadata_blobentryid_index.")?;
920
921 tx.execute(
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700922 "CREATE TABLE IF NOT EXISTS persistent.keyparameter (
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000923 keyentryid INTEGER,
924 tag INTEGER,
925 data ANY,
926 security_level INTEGER);",
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700927 NO_PARAMS,
928 )
929 .context("Failed to initialize \"keyparameter\" table.")?;
930
Janis Danisevskis66784c42021-01-27 08:40:25 -0800931 tx.execute(
Janis Danisevskisa5438182021-02-02 14:22:59 -0800932 "CREATE INDEX IF NOT EXISTS persistent.keyparameter_keyentryid_index
933 ON keyparameter(keyentryid);",
934 NO_PARAMS,
935 )
936 .context("Failed to create index keyparameter_keyentryid_index.")?;
937
938 tx.execute(
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800939 "CREATE TABLE IF NOT EXISTS persistent.keymetadata (
940 keyentryid INTEGER,
941 tag INTEGER,
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000942 data ANY,
943 UNIQUE (keyentryid, tag));",
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800944 NO_PARAMS,
945 )
946 .context("Failed to initialize \"keymetadata\" table.")?;
947
Janis Danisevskis66784c42021-01-27 08:40:25 -0800948 tx.execute(
Janis Danisevskisa5438182021-02-02 14:22:59 -0800949 "CREATE INDEX IF NOT EXISTS persistent.keymetadata_keyentryid_index
950 ON keymetadata(keyentryid);",
951 NO_PARAMS,
952 )
953 .context("Failed to create index keymetadata_keyentryid_index.")?;
954
955 tx.execute(
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800956 "CREATE TABLE IF NOT EXISTS persistent.grant (
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700957 id INTEGER UNIQUE,
958 grantee INTEGER,
959 keyentryid INTEGER,
960 access_vector INTEGER);",
961 NO_PARAMS,
962 )
963 .context("Failed to initialize \"grant\" table.")?;
964
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000965 //TODO: only drop the following two perboot tables if this is the first start up
966 //during the boot (b/175716626).
Janis Danisevskis66784c42021-01-27 08:40:25 -0800967 // tx.execute("DROP TABLE IF EXISTS perboot.authtoken;", NO_PARAMS)
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000968 // .context("Failed to drop perboot.authtoken table")?;
Janis Danisevskis66784c42021-01-27 08:40:25 -0800969 tx.execute(
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000970 "CREATE TABLE IF NOT EXISTS perboot.authtoken (
971 id INTEGER PRIMARY KEY,
972 challenge INTEGER,
973 user_id INTEGER,
974 auth_id INTEGER,
975 authenticator_type INTEGER,
976 timestamp INTEGER,
977 mac BLOB,
978 time_received INTEGER,
979 UNIQUE(user_id, auth_id, authenticator_type));",
980 NO_PARAMS,
981 )
982 .context("Failed to initialize \"authtoken\" table.")?;
983
Janis Danisevskis66784c42021-01-27 08:40:25 -0800984 // tx.execute("DROP TABLE IF EXISTS perboot.metadata;", NO_PARAMS)
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000985 // .context("Failed to drop perboot.metadata table")?;
986 // metadata table stores certain miscellaneous information required for keystore functioning
987 // during a boot cycle, as key-value pairs.
Janis Danisevskis66784c42021-01-27 08:40:25 -0800988 tx.execute(
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000989 "CREATE TABLE IF NOT EXISTS perboot.metadata (
990 key TEXT,
991 value BLOB,
992 UNIQUE(key));",
993 NO_PARAMS,
994 )
995 .context("Failed to initialize \"metadata\" table.")?;
Joel Galenson0891bc12020-07-20 10:37:03 -0700996 Ok(())
997 }
998
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700999 fn make_connection(persistent_file: &str, perboot_file: &str) -> Result<Connection> {
1000 let conn =
1001 Connection::open_in_memory().context("Failed to initialize SQLite connection.")?;
1002
Janis Danisevskis66784c42021-01-27 08:40:25 -08001003 loop {
1004 if let Err(e) = conn
1005 .execute("ATTACH DATABASE ? as persistent;", params![persistent_file])
1006 .context("Failed to attach database persistent.")
1007 {
1008 if Self::is_locked_error(&e) {
1009 std::thread::sleep(std::time::Duration::from_micros(500));
1010 continue;
1011 } else {
1012 return Err(e);
1013 }
1014 }
1015 break;
1016 }
1017 loop {
1018 if let Err(e) = conn
1019 .execute("ATTACH DATABASE ? as perboot;", params![perboot_file])
1020 .context("Failed to attach database perboot.")
1021 {
1022 if Self::is_locked_error(&e) {
1023 std::thread::sleep(std::time::Duration::from_micros(500));
1024 continue;
1025 } else {
1026 return Err(e);
1027 }
1028 }
1029 break;
1030 }
Janis Danisevskis4df44f42020-08-26 14:40:03 -07001031
1032 Ok(conn)
1033 }
1034
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001035 /// This function is intended to be used by the garbage collector.
1036 /// It deletes the blob given by `blob_id_to_delete`. It then tries to find a superseded
1037 /// key blob that might need special handling by the garbage collector.
1038 /// If no further superseded blobs can be found it deletes all other superseded blobs that don't
1039 /// need special handling and returns None.
1040 pub fn handle_next_superseded_blob(
1041 &mut self,
1042 blob_id_to_delete: Option<i64>,
1043 ) -> Result<Option<(i64, Vec<u8>, BlobMetaData)>> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001044 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001045 // Delete the given blob if one was given.
1046 if let Some(blob_id_to_delete) = blob_id_to_delete {
1047 tx.execute(
1048 "DELETE FROM persistent.blobmetadata WHERE blobentryid = ?;",
1049 params![blob_id_to_delete],
1050 )
1051 .context("Trying to delete blob metadata.")?;
1052 tx.execute(
1053 "DELETE FROM persistent.blobentry WHERE id = ?;",
1054 params![blob_id_to_delete],
1055 )
1056 .context("Trying to blob.")?;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001057 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001058
1059 // Find another superseded keyblob load its metadata and return it.
1060 if let Some((blob_id, blob)) = tx
1061 .query_row(
1062 "SELECT id, blob FROM persistent.blobentry
1063 WHERE subcomponent_type = ?
1064 AND (
1065 id NOT IN (
1066 SELECT MAX(id) FROM persistent.blobentry
1067 WHERE subcomponent_type = ?
1068 GROUP BY keyentryid, subcomponent_type
1069 )
1070 OR keyentryid NOT IN (SELECT id FROM persistent.keyentry)
1071 );",
1072 params![SubComponentType::KEY_BLOB, SubComponentType::KEY_BLOB],
1073 |row| Ok((row.get(0)?, row.get(1)?)),
1074 )
1075 .optional()
1076 .context("Trying to query superseded blob.")?
1077 {
1078 let blob_metadata = BlobMetaData::load_from_db(blob_id, tx)
1079 .context("Trying to load blob metadata.")?;
1080 return Ok(Some((blob_id, blob, blob_metadata))).no_gc();
1081 }
1082
1083 // We did not find any superseded key blob, so let's remove other superseded blob in
1084 // one transaction.
1085 tx.execute(
1086 "DELETE FROM persistent.blobentry
1087 WHERE NOT subcomponent_type = ?
1088 AND (
1089 id NOT IN (
1090 SELECT MAX(id) FROM persistent.blobentry
1091 WHERE NOT subcomponent_type = ?
1092 GROUP BY keyentryid, subcomponent_type
1093 ) OR keyentryid NOT IN (SELECT id FROM persistent.keyentry)
1094 );",
1095 params![SubComponentType::KEY_BLOB, SubComponentType::KEY_BLOB],
1096 )
1097 .context("Trying to purge superseded blobs.")?;
1098
1099 Ok(None).no_gc()
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001100 })
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001101 .context("In handle_next_superseded_blob.")
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001102 }
1103
1104 /// This maintenance function should be called only once before the database is used for the
1105 /// first time. It restores the invariant that `KeyLifeCycle::Existing` is a transient state.
1106 /// The function transitions all key entries from Existing to Unreferenced unconditionally and
1107 /// returns the number of rows affected. If this returns a value greater than 0, it means that
1108 /// Keystore crashed at some point during key generation. Callers may want to log such
1109 /// occurrences.
1110 /// Unlike with `mark_unreferenced`, we don't need to purge grants, because only keys that made
1111 /// it to `KeyLifeCycle::Live` may have grants.
1112 pub fn cleanup_leftovers(&mut self) -> Result<usize> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001113 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1114 tx.execute(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001115 "UPDATE persistent.keyentry SET state = ? WHERE state = ?;",
1116 params![KeyLifeCycle::Unreferenced, KeyLifeCycle::Existing],
1117 )
Janis Danisevskis66784c42021-01-27 08:40:25 -08001118 .context("Failed to execute query.")
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001119 .need_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08001120 })
1121 .context("In cleanup_leftovers.")
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001122 }
1123
Hasini Gunasinghe0e161452021-01-27 19:34:37 +00001124 /// Checks if a key exists with given key type and key descriptor properties.
1125 pub fn key_exists(
1126 &mut self,
1127 domain: Domain,
1128 nspace: i64,
1129 alias: &str,
1130 key_type: KeyType,
1131 ) -> Result<bool> {
1132 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1133 let key_descriptor =
1134 KeyDescriptor { domain, nspace, alias: Some(alias.to_string()), blob: None };
1135 let result = Self::load_key_entry_id(&tx, &key_descriptor, key_type);
1136 match result {
1137 Ok(_) => Ok(true),
1138 Err(error) => match error.root_cause().downcast_ref::<KsError>() {
1139 Some(KsError::Rc(ResponseCode::KEY_NOT_FOUND)) => Ok(false),
1140 _ => Err(error).context("In key_exists: Failed to find if the key exists."),
1141 },
1142 }
1143 .no_gc()
1144 })
1145 .context("In key_exists.")
1146 }
1147
Hasini Gunasingheda895552021-01-27 19:34:37 +00001148 /// Stores a super key in the database.
1149 pub fn store_super_key(
1150 &mut self,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +00001151 user_id: u32,
Hasini Gunasingheda895552021-01-27 19:34:37 +00001152 blob_info: &(&[u8], &BlobMetaData),
1153 ) -> Result<KeyEntry> {
1154 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1155 let key_id = Self::insert_with_retry(|id| {
1156 tx.execute(
1157 "INSERT into persistent.keyentry
1158 (id, key_type, domain, namespace, alias, state, km_uuid)
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00001159 VALUES(?, ?, ?, ?, ?, ?, ?);",
Hasini Gunasingheda895552021-01-27 19:34:37 +00001160 params![
1161 id,
1162 KeyType::Super,
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00001163 Domain::APP.0,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +00001164 user_id as i64,
Hasini Gunasingheda895552021-01-27 19:34:37 +00001165 Self::USER_SUPER_KEY_ALIAS,
1166 KeyLifeCycle::Live,
1167 &KEYSTORE_UUID,
1168 ],
1169 )
1170 })
1171 .context("Failed to insert into keyentry table.")?;
1172
1173 let (blob, blob_metadata) = *blob_info;
1174 Self::set_blob_internal(
1175 &tx,
1176 key_id,
1177 SubComponentType::KEY_BLOB,
1178 Some(blob),
1179 Some(blob_metadata),
1180 )
1181 .context("Failed to store key blob.")?;
1182
1183 Self::load_key_components(tx, KeyEntryLoadBits::KM, key_id)
1184 .context("Trying to load key components.")
1185 .no_gc()
1186 })
1187 .context("In store_super_key.")
1188 }
1189
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +00001190 /// Loads super key of a given user, if exists
1191 pub fn load_super_key(&mut self, user_id: u32) -> Result<Option<(KeyIdGuard, KeyEntry)>> {
1192 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1193 let key_descriptor = KeyDescriptor {
1194 domain: Domain::APP,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +00001195 nspace: user_id as i64,
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +00001196 alias: Some(String::from("USER_SUPER_KEY")),
1197 blob: None,
1198 };
1199 let id = Self::load_key_entry_id(&tx, &key_descriptor, KeyType::Super);
1200 match id {
1201 Ok(id) => {
1202 let key_entry = Self::load_key_components(&tx, KeyEntryLoadBits::KM, id)
1203 .context("In load_super_key. Failed to load key entry.")?;
1204 Ok(Some((KEY_ID_LOCK.get(id), key_entry)))
1205 }
1206 Err(error) => match error.root_cause().downcast_ref::<KsError>() {
1207 Some(KsError::Rc(ResponseCode::KEY_NOT_FOUND)) => Ok(None),
1208 _ => Err(error).context("In load_super_key."),
1209 },
1210 }
1211 .no_gc()
1212 })
1213 .context("In load_super_key.")
1214 }
1215
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001216 /// Atomically loads a key entry and associated metadata or creates it using the
1217 /// callback create_new_key callback. The callback is called during a database
1218 /// transaction. This means that implementers should be mindful about using
1219 /// blocking operations such as IPC or grabbing mutexes.
1220 pub fn get_or_create_key_with<F>(
1221 &mut self,
1222 domain: Domain,
1223 namespace: i64,
1224 alias: &str,
Max Bires8e93d2b2021-01-14 13:17:59 -08001225 km_uuid: Uuid,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001226 create_new_key: F,
1227 ) -> Result<(KeyIdGuard, KeyEntry)>
1228 where
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001229 F: Fn() -> Result<(Vec<u8>, BlobMetaData)>,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001230 {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001231 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1232 let id = {
1233 let mut stmt = tx
1234 .prepare(
1235 "SELECT id FROM persistent.keyentry
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001236 WHERE
1237 key_type = ?
1238 AND domain = ?
1239 AND namespace = ?
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001240 AND alias = ?
1241 AND state = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08001242 )
1243 .context("In get_or_create_key_with: Failed to select from keyentry table.")?;
1244 let mut rows = stmt
1245 .query(params![KeyType::Super, domain.0, namespace, alias, KeyLifeCycle::Live])
1246 .context("In get_or_create_key_with: Failed to query from keyentry table.")?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001247
Janis Danisevskis66784c42021-01-27 08:40:25 -08001248 db_utils::with_rows_extract_one(&mut rows, |row| {
1249 Ok(match row {
1250 Some(r) => r.get(0).context("Failed to unpack id.")?,
1251 None => None,
1252 })
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001253 })
Janis Danisevskis66784c42021-01-27 08:40:25 -08001254 .context("In get_or_create_key_with.")?
1255 };
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001256
Janis Danisevskis66784c42021-01-27 08:40:25 -08001257 let (id, entry) = match id {
1258 Some(id) => (
1259 id,
1260 Self::load_key_components(&tx, KeyEntryLoadBits::KM, id)
1261 .context("In get_or_create_key_with.")?,
1262 ),
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001263
Janis Danisevskis66784c42021-01-27 08:40:25 -08001264 None => {
1265 let id = Self::insert_with_retry(|id| {
1266 tx.execute(
1267 "INSERT into persistent.keyentry
Max Bires8e93d2b2021-01-14 13:17:59 -08001268 (id, key_type, domain, namespace, alias, state, km_uuid)
1269 VALUES(?, ?, ?, ?, ?, ?, ?);",
Janis Danisevskis66784c42021-01-27 08:40:25 -08001270 params![
1271 id,
1272 KeyType::Super,
1273 domain.0,
1274 namespace,
1275 alias,
1276 KeyLifeCycle::Live,
1277 km_uuid,
1278 ],
1279 )
1280 })
1281 .context("In get_or_create_key_with.")?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001282
Janis Danisevskis66784c42021-01-27 08:40:25 -08001283 let (blob, metadata) =
1284 create_new_key().context("In get_or_create_key_with.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001285 Self::set_blob_internal(
1286 &tx,
1287 id,
1288 SubComponentType::KEY_BLOB,
1289 Some(&blob),
1290 Some(&metadata),
1291 )
1292 .context("In get_of_create_key_with.")?;
Janis Danisevskis66784c42021-01-27 08:40:25 -08001293 (
Janis Danisevskis377d1002021-01-27 19:07:48 -08001294 id,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001295 KeyEntry {
1296 id,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001297 key_blob_info: Some((blob, metadata)),
Janis Danisevskis66784c42021-01-27 08:40:25 -08001298 pure_cert: false,
1299 ..Default::default()
1300 },
1301 )
1302 }
1303 };
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001304 Ok((KEY_ID_LOCK.get(id), entry)).no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08001305 })
1306 .context("In get_or_create_key_with.")
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001307 }
1308
Janis Danisevskis66784c42021-01-27 08:40:25 -08001309 /// SQLite3 seems to hold a shared mutex while running the busy handler when
1310 /// waiting for the database file to become available. This makes it
1311 /// impossible to successfully recover from a locked database when the
1312 /// transaction holding the device busy is in the same process on a
1313 /// different connection. As a result the busy handler has to time out and
1314 /// fail in order to make progress.
1315 ///
1316 /// Instead, we set the busy handler to None (return immediately). And catch
1317 /// Busy and Locked errors (the latter occur on in memory databases with
1318 /// shared cache, e.g., the per-boot database.) and restart the transaction
1319 /// after a grace period of half a millisecond.
1320 ///
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001321 /// Creates a transaction with the given behavior and executes f with the new transaction.
Janis Danisevskis66784c42021-01-27 08:40:25 -08001322 /// The transaction is committed only if f returns Ok and retried if DatabaseBusy
1323 /// or DatabaseLocked is encountered.
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001324 fn with_transaction<T, F>(&mut self, behavior: TransactionBehavior, f: F) -> Result<T>
1325 where
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001326 F: Fn(&Transaction) -> Result<(bool, T)>,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001327 {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001328 loop {
1329 match self
1330 .conn
1331 .transaction_with_behavior(behavior)
1332 .context("In with_transaction.")
1333 .and_then(|tx| f(&tx).map(|result| (result, tx)))
1334 .and_then(|(result, tx)| {
1335 tx.commit().context("In with_transaction: Failed to commit transaction.")?;
1336 Ok(result)
1337 }) {
1338 Ok(result) => break Ok(result),
1339 Err(e) => {
1340 if Self::is_locked_error(&e) {
1341 std::thread::sleep(std::time::Duration::from_micros(500));
1342 continue;
1343 } else {
1344 return Err(e).context("In with_transaction.");
1345 }
1346 }
1347 }
1348 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001349 .map(|(need_gc, result)| {
1350 if need_gc {
1351 if let Some(ref gc) = self.gc {
1352 gc.notify_gc();
1353 }
1354 }
1355 result
1356 })
Janis Danisevskis66784c42021-01-27 08:40:25 -08001357 }
1358
1359 fn is_locked_error(e: &anyhow::Error) -> bool {
Paul Crowleyf61fee72021-03-17 14:38:44 -07001360 matches!(
1361 e.root_cause().downcast_ref::<rusqlite::ffi::Error>(),
1362 Some(rusqlite::ffi::Error { code: rusqlite::ErrorCode::DatabaseBusy, .. })
1363 | Some(rusqlite::ffi::Error { code: rusqlite::ErrorCode::DatabaseLocked, .. })
1364 )
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001365 }
1366
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001367 /// Creates a new key entry and allocates a new randomized id for the new key.
1368 /// The key id gets associated with a domain and namespace but not with an alias.
1369 /// To complete key generation `rebind_alias` should be called after all of the
1370 /// key artifacts, i.e., blobs and parameters have been associated with the new
1371 /// key id. Finalizing with `rebind_alias` makes the creation of a new key entry
1372 /// atomic even if key generation is not.
Max Bires8e93d2b2021-01-14 13:17:59 -08001373 pub fn create_key_entry(
1374 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001375 domain: &Domain,
1376 namespace: &i64,
Max Bires8e93d2b2021-01-14 13:17:59 -08001377 km_uuid: &Uuid,
1378 ) -> Result<KeyIdGuard> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001379 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001380 Self::create_key_entry_internal(tx, domain, namespace, km_uuid).no_gc()
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001381 })
1382 .context("In create_key_entry.")
1383 }
1384
1385 fn create_key_entry_internal(
1386 tx: &Transaction,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001387 domain: &Domain,
1388 namespace: &i64,
Max Bires8e93d2b2021-01-14 13:17:59 -08001389 km_uuid: &Uuid,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001390 ) -> Result<KeyIdGuard> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001391 match *domain {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001392 Domain::APP | Domain::SELINUX => {}
Joel Galenson0891bc12020-07-20 10:37:03 -07001393 _ => {
1394 return Err(KsError::sys())
1395 .context(format!("Domain {:?} must be either App or SELinux.", domain));
1396 }
1397 }
Janis Danisevskisaec14592020-11-12 09:41:49 -08001398 Ok(KEY_ID_LOCK.get(
1399 Self::insert_with_retry(|id| {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001400 tx.execute(
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001401 "INSERT into persistent.keyentry
Max Bires8e93d2b2021-01-14 13:17:59 -08001402 (id, key_type, domain, namespace, alias, state, km_uuid)
1403 VALUES(?, ?, ?, ?, NULL, ?, ?);",
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001404 params![
1405 id,
1406 KeyType::Client,
1407 domain.0 as u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001408 *namespace,
Max Bires8e93d2b2021-01-14 13:17:59 -08001409 KeyLifeCycle::Existing,
1410 km_uuid,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001411 ],
Janis Danisevskisaec14592020-11-12 09:41:49 -08001412 )
1413 })
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001414 .context("In create_key_entry_internal")?,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001415 ))
Joel Galenson26f4d012020-07-17 14:57:21 -07001416 }
Joel Galenson33c04ad2020-08-03 11:04:38 -07001417
Max Bires2b2e6562020-09-22 11:22:36 -07001418 /// Creates a new attestation key entry and allocates a new randomized id for the new key.
1419 /// The key id gets associated with a domain and namespace later but not with an alias. The
1420 /// alias will be used to denote if a key has been signed as each key can only be bound to one
1421 /// domain and namespace pairing so there is no need to use them as a value for indexing into
1422 /// a key.
1423 pub fn create_attestation_key_entry(
1424 &mut self,
1425 maced_public_key: &[u8],
1426 raw_public_key: &[u8],
1427 private_key: &[u8],
1428 km_uuid: &Uuid,
1429 ) -> Result<()> {
1430 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1431 let key_id = KEY_ID_LOCK.get(
1432 Self::insert_with_retry(|id| {
1433 tx.execute(
1434 "INSERT into persistent.keyentry
1435 (id, key_type, domain, namespace, alias, state, km_uuid)
1436 VALUES(?, ?, NULL, NULL, NULL, ?, ?);",
1437 params![id, KeyType::Attestation, KeyLifeCycle::Live, km_uuid],
1438 )
1439 })
1440 .context("In create_key_entry")?,
1441 );
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001442 Self::set_blob_internal(
1443 &tx,
1444 key_id.0,
1445 SubComponentType::KEY_BLOB,
1446 Some(private_key),
1447 None,
1448 )?;
Max Bires2b2e6562020-09-22 11:22:36 -07001449 let mut metadata = KeyMetaData::new();
1450 metadata.add(KeyMetaEntry::AttestationMacedPublicKey(maced_public_key.to_vec()));
1451 metadata.add(KeyMetaEntry::AttestationRawPubKey(raw_public_key.to_vec()));
1452 metadata.store_in_db(key_id.0, &tx)?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001453 Ok(()).no_gc()
Max Bires2b2e6562020-09-22 11:22:36 -07001454 })
1455 .context("In create_attestation_key_entry")
1456 }
1457
Janis Danisevskis377d1002021-01-27 19:07:48 -08001458 /// Set a new blob and associates it with the given key id. Each blob
1459 /// has a sub component type.
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001460 /// Each key can have one of each sub component type associated. If more
1461 /// are added only the most recent can be retrieved, and superseded blobs
Janis Danisevskis377d1002021-01-27 19:07:48 -08001462 /// will get garbage collected.
1463 /// Components SubComponentType::CERT and SubComponentType::CERT_CHAIN can be
1464 /// removed by setting blob to None.
1465 pub fn set_blob(
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001466 &mut self,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001467 key_id: &KeyIdGuard,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001468 sc_type: SubComponentType,
Janis Danisevskis377d1002021-01-27 19:07:48 -08001469 blob: Option<&[u8]>,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001470 blob_metadata: Option<&BlobMetaData>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001471 ) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001472 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001473 Self::set_blob_internal(&tx, key_id.0, sc_type, blob, blob_metadata).need_gc()
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001474 })
Janis Danisevskis377d1002021-01-27 19:07:48 -08001475 .context("In set_blob.")
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001476 }
1477
Janis Danisevskiseed69842021-02-18 20:04:10 -08001478 /// Why would we insert a deleted blob? This weird function is for the purpose of legacy
1479 /// key migration in the case where we bulk delete all the keys of an app or even a user.
1480 /// We use this to insert key blobs into the database which can then be garbage collected
1481 /// lazily by the key garbage collector.
1482 pub fn set_deleted_blob(&mut self, blob: &[u8], blob_metadata: &BlobMetaData) -> Result<()> {
1483 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1484 Self::set_blob_internal(
1485 &tx,
1486 Self::UNASSIGNED_KEY_ID,
1487 SubComponentType::KEY_BLOB,
1488 Some(blob),
1489 Some(blob_metadata),
1490 )
1491 .need_gc()
1492 })
1493 .context("In set_deleted_blob.")
1494 }
1495
Janis Danisevskis377d1002021-01-27 19:07:48 -08001496 fn set_blob_internal(
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001497 tx: &Transaction,
1498 key_id: i64,
1499 sc_type: SubComponentType,
Janis Danisevskis377d1002021-01-27 19:07:48 -08001500 blob: Option<&[u8]>,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001501 blob_metadata: Option<&BlobMetaData>,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001502 ) -> Result<()> {
Janis Danisevskis377d1002021-01-27 19:07:48 -08001503 match (blob, sc_type) {
1504 (Some(blob), _) => {
1505 tx.execute(
1506 "INSERT INTO persistent.blobentry
1507 (subcomponent_type, keyentryid, blob) VALUES (?, ?, ?);",
1508 params![sc_type, key_id, blob],
1509 )
1510 .context("In set_blob_internal: Failed to insert blob.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001511 if let Some(blob_metadata) = blob_metadata {
1512 let blob_id = tx
1513 .query_row("SELECT MAX(id) FROM persistent.blobentry;", NO_PARAMS, |row| {
1514 row.get(0)
1515 })
1516 .context("In set_blob_internal: Failed to get new blob id.")?;
1517 blob_metadata
1518 .store_in_db(blob_id, tx)
1519 .context("In set_blob_internal: Trying to store blob metadata.")?;
1520 }
Janis Danisevskis377d1002021-01-27 19:07:48 -08001521 }
1522 (None, SubComponentType::CERT) | (None, SubComponentType::CERT_CHAIN) => {
1523 tx.execute(
1524 "DELETE FROM persistent.blobentry
1525 WHERE subcomponent_type = ? AND keyentryid = ?;",
1526 params![sc_type, key_id],
1527 )
1528 .context("In set_blob_internal: Failed to delete blob.")?;
1529 }
1530 (None, _) => {
1531 return Err(KsError::sys())
1532 .context("In set_blob_internal: Other blobs cannot be deleted in this way.");
1533 }
1534 }
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001535 Ok(())
1536 }
1537
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001538 /// Inserts a collection of key parameters into the `persistent.keyparameter` table
1539 /// and associates them with the given `key_id`.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001540 #[cfg(test)]
1541 fn insert_keyparameter(&mut self, key_id: &KeyIdGuard, params: &[KeyParameter]) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001542 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001543 Self::insert_keyparameter_internal(tx, key_id, params).no_gc()
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001544 })
1545 .context("In insert_keyparameter.")
1546 }
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001547
Janis Danisevskis66784c42021-01-27 08:40:25 -08001548 fn insert_keyparameter_internal(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001549 tx: &Transaction,
1550 key_id: &KeyIdGuard,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001551 params: &[KeyParameter],
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001552 ) -> Result<()> {
1553 let mut stmt = tx
1554 .prepare(
1555 "INSERT into persistent.keyparameter (keyentryid, tag, data, security_level)
1556 VALUES (?, ?, ?, ?);",
1557 )
1558 .context("In insert_keyparameter_internal: Failed to prepare statement.")?;
1559
Janis Danisevskis66784c42021-01-27 08:40:25 -08001560 for p in params.iter() {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001561 stmt.insert(params![
1562 key_id.0,
1563 p.get_tag().0,
1564 p.key_parameter_value(),
1565 p.security_level().0
1566 ])
1567 .with_context(|| {
1568 format!("In insert_keyparameter_internal: Failed to insert {:?}", p)
1569 })?;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001570 }
1571 Ok(())
1572 }
1573
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001574 /// Insert a set of key entry specific metadata into the database.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001575 #[cfg(test)]
1576 fn insert_key_metadata(&mut self, key_id: &KeyIdGuard, metadata: &KeyMetaData) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001577 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001578 metadata.store_in_db(key_id.0, &tx).no_gc()
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001579 })
1580 .context("In insert_key_metadata.")
1581 }
1582
Max Bires2b2e6562020-09-22 11:22:36 -07001583 /// Stores a signed certificate chain signed by a remote provisioning server, keyed
1584 /// on the public key.
1585 pub fn store_signed_attestation_certificate_chain(
1586 &mut self,
1587 raw_public_key: &[u8],
Max Biresb2e1d032021-02-08 21:35:05 -08001588 batch_cert: &[u8],
Max Bires2b2e6562020-09-22 11:22:36 -07001589 cert_chain: &[u8],
1590 expiration_date: i64,
1591 km_uuid: &Uuid,
1592 ) -> Result<()> {
1593 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1594 let mut stmt = tx
1595 .prepare(
1596 "SELECT keyentryid
1597 FROM persistent.keymetadata
1598 WHERE tag = ? AND data = ? AND keyentryid IN
1599 (SELECT id
1600 FROM persistent.keyentry
1601 WHERE
1602 alias IS NULL AND
1603 domain IS NULL AND
1604 namespace IS NULL AND
1605 key_type = ? AND
1606 km_uuid = ?);",
1607 )
1608 .context("Failed to store attestation certificate chain.")?;
1609 let mut rows = stmt
1610 .query(params![
1611 KeyMetaData::AttestationRawPubKey,
1612 raw_public_key,
1613 KeyType::Attestation,
1614 km_uuid
1615 ])
1616 .context("Failed to fetch keyid")?;
1617 let key_id = db_utils::with_rows_extract_one(&mut rows, |row| {
1618 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?
1619 .get(0)
1620 .context("Failed to unpack id.")
1621 })
1622 .context("Failed to get key_id.")?;
1623 let num_updated = tx
1624 .execute(
1625 "UPDATE persistent.keyentry
1626 SET alias = ?
1627 WHERE id = ?;",
1628 params!["signed", key_id],
1629 )
1630 .context("Failed to update alias.")?;
1631 if num_updated != 1 {
1632 return Err(KsError::sys()).context("Alias not updated for the key.");
1633 }
1634 let mut metadata = KeyMetaData::new();
1635 metadata.add(KeyMetaEntry::AttestationExpirationDate(DateTime::from_millis_epoch(
1636 expiration_date,
1637 )));
1638 metadata.store_in_db(key_id, &tx).context("Failed to insert key metadata.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001639 Self::set_blob_internal(
1640 &tx,
1641 key_id,
1642 SubComponentType::CERT_CHAIN,
1643 Some(cert_chain),
1644 None,
1645 )
1646 .context("Failed to insert cert chain")?;
Max Biresb2e1d032021-02-08 21:35:05 -08001647 Self::set_blob_internal(&tx, key_id, SubComponentType::CERT, Some(batch_cert), None)
1648 .context("Failed to insert cert")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001649 Ok(()).no_gc()
Max Bires2b2e6562020-09-22 11:22:36 -07001650 })
1651 .context("In store_signed_attestation_certificate_chain: ")
1652 }
1653
1654 /// Assigns the next unassigned attestation key to a domain/namespace combo that does not
1655 /// currently have a key assigned to it.
1656 pub fn assign_attestation_key(
1657 &mut self,
1658 domain: Domain,
1659 namespace: i64,
1660 km_uuid: &Uuid,
1661 ) -> Result<()> {
1662 match domain {
1663 Domain::APP | Domain::SELINUX => {}
1664 _ => {
1665 return Err(KsError::sys()).context(format!(
1666 concat!(
1667 "In assign_attestation_key: Domain {:?} ",
1668 "must be either App or SELinux.",
1669 ),
1670 domain
1671 ));
1672 }
1673 }
1674 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1675 let result = tx
1676 .execute(
1677 "UPDATE persistent.keyentry
1678 SET domain=?1, namespace=?2
1679 WHERE
1680 id =
1681 (SELECT MIN(id)
1682 FROM persistent.keyentry
1683 WHERE ALIAS IS NOT NULL
1684 AND domain IS NULL
1685 AND key_type IS ?3
1686 AND state IS ?4
1687 AND km_uuid IS ?5)
1688 AND
1689 (SELECT COUNT(*)
1690 FROM persistent.keyentry
1691 WHERE domain=?1
1692 AND namespace=?2
1693 AND key_type IS ?3
1694 AND state IS ?4
1695 AND km_uuid IS ?5) = 0;",
1696 params![
1697 domain.0 as u32,
1698 namespace,
1699 KeyType::Attestation,
1700 KeyLifeCycle::Live,
1701 km_uuid,
1702 ],
1703 )
1704 .context("Failed to assign attestation key")?;
1705 if result != 1 {
1706 return Err(KsError::sys()).context(format!(
1707 "Expected to update a single entry but instead updated {}.",
1708 result
1709 ));
1710 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001711 Ok(()).no_gc()
Max Bires2b2e6562020-09-22 11:22:36 -07001712 })
1713 .context("In assign_attestation_key: ")
1714 }
1715
1716 /// Retrieves num_keys number of attestation keys that have not yet been signed by a remote
1717 /// provisioning server, or the maximum number available if there are not num_keys number of
1718 /// entries in the table.
1719 pub fn fetch_unsigned_attestation_keys(
1720 &mut self,
1721 num_keys: i32,
1722 km_uuid: &Uuid,
1723 ) -> Result<Vec<Vec<u8>>> {
1724 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1725 let mut stmt = tx
1726 .prepare(
1727 "SELECT data
1728 FROM persistent.keymetadata
1729 WHERE tag = ? AND keyentryid IN
1730 (SELECT id
1731 FROM persistent.keyentry
1732 WHERE
1733 alias IS NULL AND
1734 domain IS NULL AND
1735 namespace IS NULL AND
1736 key_type = ? AND
1737 km_uuid = ?
1738 LIMIT ?);",
1739 )
1740 .context("Failed to prepare statement")?;
1741 let rows = stmt
1742 .query_map(
1743 params![
1744 KeyMetaData::AttestationMacedPublicKey,
1745 KeyType::Attestation,
1746 km_uuid,
1747 num_keys
1748 ],
1749 |row| Ok(row.get(0)?),
1750 )?
1751 .collect::<rusqlite::Result<Vec<Vec<u8>>>>()
1752 .context("Failed to execute statement")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001753 Ok(rows).no_gc()
Max Bires2b2e6562020-09-22 11:22:36 -07001754 })
1755 .context("In fetch_unsigned_attestation_keys")
1756 }
1757
1758 /// Removes any keys that have expired as of the current time. Returns the number of keys
1759 /// marked unreferenced that are bound to be garbage collected.
1760 pub fn delete_expired_attestation_keys(&mut self) -> Result<i32> {
1761 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1762 let mut stmt = tx
1763 .prepare(
1764 "SELECT keyentryid, data
1765 FROM persistent.keymetadata
1766 WHERE tag = ? AND keyentryid IN
1767 (SELECT id
1768 FROM persistent.keyentry
1769 WHERE key_type = ?);",
1770 )
1771 .context("Failed to prepare query")?;
1772 let key_ids_to_check = stmt
1773 .query_map(
1774 params![KeyMetaData::AttestationExpirationDate, KeyType::Attestation],
1775 |row| Ok((row.get(0)?, row.get(1)?)),
1776 )?
1777 .collect::<rusqlite::Result<Vec<(i64, DateTime)>>>()
1778 .context("Failed to get date metadata")?;
1779 let curr_time = DateTime::from_millis_epoch(
1780 SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_millis() as i64,
1781 );
1782 let mut num_deleted = 0;
1783 for id in key_ids_to_check.iter().filter(|kt| kt.1 < curr_time).map(|kt| kt.0) {
1784 if Self::mark_unreferenced(&tx, id)? {
1785 num_deleted += 1;
1786 }
1787 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001788 Ok(num_deleted).do_gc(num_deleted != 0)
Max Bires2b2e6562020-09-22 11:22:36 -07001789 })
1790 .context("In delete_expired_attestation_keys: ")
1791 }
1792
Max Bires60d7ed12021-03-05 15:59:22 -08001793 /// Deletes all remotely provisioned attestation keys in the system, regardless of the state
1794 /// they are in. This is useful primarily as a testing mechanism.
1795 pub fn delete_all_attestation_keys(&mut self) -> Result<i64> {
1796 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1797 let mut stmt = tx
1798 .prepare(
1799 "SELECT id FROM persistent.keyentry
1800 WHERE key_type IS ?;",
1801 )
1802 .context("Failed to prepare statement")?;
1803 let keys_to_delete = stmt
1804 .query_map(params![KeyType::Attestation], |row| Ok(row.get(0)?))?
1805 .collect::<rusqlite::Result<Vec<i64>>>()
1806 .context("Failed to execute statement")?;
1807 let num_deleted = keys_to_delete
1808 .iter()
1809 .map(|id| Self::mark_unreferenced(&tx, *id))
1810 .collect::<Result<Vec<bool>>>()
1811 .context("Failed to execute mark_unreferenced on a keyid")?
1812 .into_iter()
1813 .filter(|result| *result)
1814 .count() as i64;
1815 Ok(num_deleted).do_gc(num_deleted != 0)
1816 })
1817 .context("In delete_all_attestation_keys: ")
1818 }
1819
Max Bires2b2e6562020-09-22 11:22:36 -07001820 /// Counts the number of keys that will expire by the provided epoch date and the number of
1821 /// keys not currently assigned to a domain.
1822 pub fn get_attestation_pool_status(
1823 &mut self,
1824 date: i64,
1825 km_uuid: &Uuid,
1826 ) -> Result<AttestationPoolStatus> {
1827 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1828 let mut stmt = tx.prepare(
1829 "SELECT data
1830 FROM persistent.keymetadata
1831 WHERE tag = ? AND keyentryid IN
1832 (SELECT id
1833 FROM persistent.keyentry
1834 WHERE alias IS NOT NULL
1835 AND key_type = ?
1836 AND km_uuid = ?
1837 AND state = ?);",
1838 )?;
1839 let times = stmt
1840 .query_map(
1841 params![
1842 KeyMetaData::AttestationExpirationDate,
1843 KeyType::Attestation,
1844 km_uuid,
1845 KeyLifeCycle::Live
1846 ],
1847 |row| Ok(row.get(0)?),
1848 )?
1849 .collect::<rusqlite::Result<Vec<DateTime>>>()
1850 .context("Failed to execute metadata statement")?;
1851 let expiring =
1852 times.iter().filter(|time| time < &&DateTime::from_millis_epoch(date)).count()
1853 as i32;
1854 stmt = tx.prepare(
1855 "SELECT alias, domain
1856 FROM persistent.keyentry
1857 WHERE key_type = ? AND km_uuid = ? AND state = ?;",
1858 )?;
1859 let rows = stmt
1860 .query_map(params![KeyType::Attestation, km_uuid, KeyLifeCycle::Live], |row| {
1861 Ok((row.get(0)?, row.get(1)?))
1862 })?
1863 .collect::<rusqlite::Result<Vec<(Option<String>, Option<u32>)>>>()
1864 .context("Failed to execute keyentry statement")?;
1865 let mut unassigned = 0i32;
1866 let mut attested = 0i32;
1867 let total = rows.len() as i32;
1868 for (alias, domain) in rows {
1869 match (alias, domain) {
1870 (Some(_alias), None) => {
1871 attested += 1;
1872 unassigned += 1;
1873 }
1874 (Some(_alias), Some(_domain)) => {
1875 attested += 1;
1876 }
1877 _ => {}
1878 }
1879 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001880 Ok(AttestationPoolStatus { expiring, unassigned, attested, total }).no_gc()
Max Bires2b2e6562020-09-22 11:22:36 -07001881 })
1882 .context("In get_attestation_pool_status: ")
1883 }
1884
1885 /// Fetches the private key and corresponding certificate chain assigned to a
1886 /// domain/namespace pair. Will either return nothing if the domain/namespace is
1887 /// not assigned, or one CertificateChain.
1888 pub fn retrieve_attestation_key_and_cert_chain(
1889 &mut self,
1890 domain: Domain,
1891 namespace: i64,
1892 km_uuid: &Uuid,
1893 ) -> Result<Option<CertificateChain>> {
1894 match domain {
1895 Domain::APP | Domain::SELINUX => {}
1896 _ => {
1897 return Err(KsError::sys())
1898 .context(format!("Domain {:?} must be either App or SELinux.", domain));
1899 }
1900 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001901 self.with_transaction(TransactionBehavior::Deferred, |tx| {
1902 let mut stmt = tx.prepare(
1903 "SELECT subcomponent_type, blob
Max Bires2b2e6562020-09-22 11:22:36 -07001904 FROM persistent.blobentry
1905 WHERE keyentryid IN
1906 (SELECT id
1907 FROM persistent.keyentry
1908 WHERE key_type = ?
1909 AND domain = ?
1910 AND namespace = ?
1911 AND state = ?
1912 AND km_uuid = ?);",
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001913 )?;
1914 let rows = stmt
1915 .query_map(
1916 params![
1917 KeyType::Attestation,
1918 domain.0 as u32,
1919 namespace,
1920 KeyLifeCycle::Live,
1921 km_uuid
1922 ],
1923 |row| Ok((row.get(0)?, row.get(1)?)),
1924 )?
1925 .collect::<rusqlite::Result<Vec<(SubComponentType, Vec<u8>)>>>()
Max Biresb2e1d032021-02-08 21:35:05 -08001926 .context("query failed.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001927 if rows.is_empty() {
1928 return Ok(None).no_gc();
Max Biresb2e1d032021-02-08 21:35:05 -08001929 } else if rows.len() != 3 {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001930 return Err(KsError::sys()).context(format!(
1931 concat!(
Max Biresb2e1d032021-02-08 21:35:05 -08001932 "Expected to get a single attestation",
1933 "key, cert, and cert chain for a total of 3 entries, but instead got {}."
1934 ),
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001935 rows.len()
1936 ));
Max Bires2b2e6562020-09-22 11:22:36 -07001937 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001938 let mut km_blob: Vec<u8> = Vec::new();
1939 let mut cert_chain_blob: Vec<u8> = Vec::new();
Max Biresb2e1d032021-02-08 21:35:05 -08001940 let mut batch_cert_blob: Vec<u8> = Vec::new();
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001941 for row in rows {
1942 let sub_type: SubComponentType = row.0;
1943 match sub_type {
1944 SubComponentType::KEY_BLOB => {
1945 km_blob = row.1;
1946 }
1947 SubComponentType::CERT_CHAIN => {
1948 cert_chain_blob = row.1;
1949 }
Max Biresb2e1d032021-02-08 21:35:05 -08001950 SubComponentType::CERT => {
1951 batch_cert_blob = row.1;
1952 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001953 _ => Err(KsError::sys()).context("Unknown or incorrect subcomponent type.")?,
1954 }
1955 }
1956 Ok(Some(CertificateChain {
1957 private_key: ZVec::try_from(km_blob)?,
Max Bires97f96812021-02-23 23:44:57 -08001958 batch_cert: batch_cert_blob,
1959 cert_chain: cert_chain_blob,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001960 }))
1961 .no_gc()
1962 })
Max Biresb2e1d032021-02-08 21:35:05 -08001963 .context("In retrieve_attestation_key_and_cert_chain:")
Max Bires2b2e6562020-09-22 11:22:36 -07001964 }
1965
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001966 /// Updates the alias column of the given key id `newid` with the given alias,
1967 /// and atomically, removes the alias, domain, and namespace from another row
1968 /// with the same alias-domain-namespace tuple if such row exits.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001969 /// Returns Ok(true) if an old key was marked unreferenced as a hint to the garbage
1970 /// collector.
1971 fn rebind_alias(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001972 tx: &Transaction,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001973 newid: &KeyIdGuard,
Joel Galenson33c04ad2020-08-03 11:04:38 -07001974 alias: &str,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001975 domain: &Domain,
1976 namespace: &i64,
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001977 ) -> Result<bool> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001978 match *domain {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001979 Domain::APP | Domain::SELINUX => {}
Joel Galenson33c04ad2020-08-03 11:04:38 -07001980 _ => {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001981 return Err(KsError::sys()).context(format!(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001982 "In rebind_alias: Domain {:?} must be either App or SELinux.",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001983 domain
1984 ));
Joel Galenson33c04ad2020-08-03 11:04:38 -07001985 }
1986 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001987 let updated = tx
1988 .execute(
1989 "UPDATE persistent.keyentry
1990 SET alias = NULL, domain = NULL, namespace = NULL, state = ?
Joel Galenson33c04ad2020-08-03 11:04:38 -07001991 WHERE alias = ? AND domain = ? AND namespace = ?;",
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001992 params![KeyLifeCycle::Unreferenced, alias, domain.0 as u32, namespace],
1993 )
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001994 .context("In rebind_alias: Failed to rebind existing entry.")?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07001995 let result = tx
1996 .execute(
1997 "UPDATE persistent.keyentry
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001998 SET alias = ?, state = ?
1999 WHERE id = ? AND domain = ? AND namespace = ? AND state = ?;",
2000 params![
2001 alias,
2002 KeyLifeCycle::Live,
2003 newid.0,
2004 domain.0 as u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002005 *namespace,
Max Bires8e93d2b2021-01-14 13:17:59 -08002006 KeyLifeCycle::Existing,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002007 ],
Joel Galenson33c04ad2020-08-03 11:04:38 -07002008 )
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002009 .context("In rebind_alias: Failed to set alias.")?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07002010 if result != 1 {
Joel Galenson33c04ad2020-08-03 11:04:38 -07002011 return Err(KsError::sys()).context(format!(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002012 "In rebind_alias: Expected to update a single entry but instead updated {}.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07002013 result
2014 ));
2015 }
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002016 Ok(updated != 0)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002017 }
2018
2019 /// Store a new key in a single transaction.
2020 /// The function creates a new key entry, populates the blob, key parameter, and metadata
2021 /// fields, and rebinds the given alias to the new key.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002022 /// The boolean returned is a hint for the garbage collector. If true, a key was replaced,
2023 /// is now unreferenced and needs to be collected.
Janis Danisevskis66784c42021-01-27 08:40:25 -08002024 pub fn store_new_key(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002025 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002026 key: &KeyDescriptor,
2027 params: &[KeyParameter],
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002028 blob_info: &(&[u8], &BlobMetaData),
Max Bires8e93d2b2021-01-14 13:17:59 -08002029 cert_info: &CertificateInfo,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002030 metadata: &KeyMetaData,
Max Bires8e93d2b2021-01-14 13:17:59 -08002031 km_uuid: &Uuid,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002032 ) -> Result<KeyIdGuard> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002033 let (alias, domain, namespace) = match key {
2034 KeyDescriptor { alias: Some(alias), domain: Domain::APP, nspace, blob: None }
2035 | KeyDescriptor { alias: Some(alias), domain: Domain::SELINUX, nspace, blob: None } => {
2036 (alias, key.domain, nspace)
2037 }
2038 _ => {
2039 return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT))
2040 .context("In store_new_key: Need alias and domain must be APP or SELINUX.")
2041 }
2042 };
2043 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002044 let key_id = Self::create_key_entry_internal(tx, &domain, namespace, km_uuid)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002045 .context("Trying to create new key entry.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002046 let (blob, blob_metadata) = *blob_info;
2047 Self::set_blob_internal(
2048 tx,
2049 key_id.id(),
2050 SubComponentType::KEY_BLOB,
2051 Some(blob),
2052 Some(&blob_metadata),
2053 )
2054 .context("Trying to insert the key blob.")?;
Max Bires8e93d2b2021-01-14 13:17:59 -08002055 if let Some(cert) = &cert_info.cert {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002056 Self::set_blob_internal(tx, key_id.id(), SubComponentType::CERT, Some(&cert), None)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002057 .context("Trying to insert the certificate.")?;
2058 }
Max Bires8e93d2b2021-01-14 13:17:59 -08002059 if let Some(cert_chain) = &cert_info.cert_chain {
Janis Danisevskis377d1002021-01-27 19:07:48 -08002060 Self::set_blob_internal(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002061 tx,
2062 key_id.id(),
2063 SubComponentType::CERT_CHAIN,
Janis Danisevskis377d1002021-01-27 19:07:48 -08002064 Some(&cert_chain),
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002065 None,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002066 )
2067 .context("Trying to insert the certificate chain.")?;
2068 }
2069 Self::insert_keyparameter_internal(tx, &key_id, params)
2070 .context("Trying to insert key parameters.")?;
Janis Danisevskis377d1002021-01-27 19:07:48 -08002071 metadata.store_in_db(key_id.id(), tx).context("Trying to insert key metadata.")?;
Janis Danisevskis66784c42021-01-27 08:40:25 -08002072 let need_gc = Self::rebind_alias(tx, &key_id, &alias, &domain, namespace)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002073 .context("Trying to rebind alias.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002074 Ok(key_id).do_gc(need_gc)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002075 })
2076 .context("In store_new_key.")
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002077 }
2078
Janis Danisevskis377d1002021-01-27 19:07:48 -08002079 /// Store a new certificate
2080 /// The function creates a new key entry, populates the blob field and metadata, and rebinds
2081 /// the given alias to the new cert.
Max Bires8e93d2b2021-01-14 13:17:59 -08002082 pub fn store_new_certificate(
2083 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002084 key: &KeyDescriptor,
Max Bires8e93d2b2021-01-14 13:17:59 -08002085 cert: &[u8],
2086 km_uuid: &Uuid,
2087 ) -> Result<KeyIdGuard> {
Janis Danisevskis377d1002021-01-27 19:07:48 -08002088 let (alias, domain, namespace) = match key {
2089 KeyDescriptor { alias: Some(alias), domain: Domain::APP, nspace, blob: None }
2090 | KeyDescriptor { alias: Some(alias), domain: Domain::SELINUX, nspace, blob: None } => {
2091 (alias, key.domain, nspace)
2092 }
2093 _ => {
2094 return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT)).context(
2095 "In store_new_certificate: Need alias and domain must be APP or SELINUX.",
2096 )
2097 }
2098 };
2099 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002100 let key_id = Self::create_key_entry_internal(tx, &domain, namespace, km_uuid)
Janis Danisevskis377d1002021-01-27 19:07:48 -08002101 .context("Trying to create new key entry.")?;
2102
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002103 Self::set_blob_internal(
2104 tx,
2105 key_id.id(),
2106 SubComponentType::CERT_CHAIN,
2107 Some(cert),
2108 None,
2109 )
2110 .context("Trying to insert certificate.")?;
Janis Danisevskis377d1002021-01-27 19:07:48 -08002111
2112 let mut metadata = KeyMetaData::new();
2113 metadata.add(KeyMetaEntry::CreationDate(
2114 DateTime::now().context("Trying to make creation time.")?,
2115 ));
2116
2117 metadata.store_in_db(key_id.id(), tx).context("Trying to insert key metadata.")?;
2118
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002119 let need_gc = Self::rebind_alias(tx, &key_id, &alias, &domain, namespace)
Janis Danisevskis377d1002021-01-27 19:07:48 -08002120 .context("Trying to rebind alias.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002121 Ok(key_id).do_gc(need_gc)
Janis Danisevskis377d1002021-01-27 19:07:48 -08002122 })
2123 .context("In store_new_certificate.")
2124 }
2125
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002126 // Helper function loading the key_id given the key descriptor
2127 // tuple comprising domain, namespace, and alias.
2128 // Requires a valid transaction.
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002129 fn load_key_entry_id(tx: &Transaction, key: &KeyDescriptor, key_type: KeyType) -> Result<i64> {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002130 let alias = key
2131 .alias
2132 .as_ref()
2133 .map_or_else(|| Err(KsError::sys()), Ok)
2134 .context("In load_key_entry_id: Alias must be specified.")?;
2135 let mut stmt = tx
2136 .prepare(
2137 "SELECT id FROM persistent.keyentry
2138 WHERE
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00002139 key_type = ?
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002140 AND domain = ?
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002141 AND namespace = ?
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002142 AND alias = ?
2143 AND state = ?;",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002144 )
2145 .context("In load_key_entry_id: Failed to select from keyentry table.")?;
2146 let mut rows = stmt
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002147 .query(params![key_type, key.domain.0 as u32, key.nspace, alias, KeyLifeCycle::Live])
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002148 .context("In load_key_entry_id: Failed to read from keyentry table.")?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002149 db_utils::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002150 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002151 .get(0)
2152 .context("Failed to unpack id.")
2153 })
2154 .context("In load_key_entry_id.")
2155 }
2156
2157 /// This helper function completes the access tuple of a key, which is required
2158 /// to perform access control. The strategy depends on the `domain` field in the
2159 /// key descriptor.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002160 /// * Domain::SELINUX: The access tuple is complete and this function only loads
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002161 /// the key_id for further processing.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002162 /// * Domain::APP: Like Domain::SELINUX, but the tuple is completed by `caller_uid`
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002163 /// which serves as the namespace.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002164 /// * Domain::GRANT: The grant table is queried for the `key_id` and the
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002165 /// `access_vector`.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002166 /// * Domain::KEY_ID: The keyentry table is queried for the owning `domain` and
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002167 /// `namespace`.
2168 /// In each case the information returned is sufficient to perform the access
2169 /// check and the key id can be used to load further key artifacts.
2170 fn load_access_tuple(
2171 tx: &Transaction,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002172 key: &KeyDescriptor,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002173 key_type: KeyType,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002174 caller_uid: u32,
2175 ) -> Result<(i64, KeyDescriptor, Option<KeyPermSet>)> {
2176 match key.domain {
2177 // Domain App or SELinux. In this case we load the key_id from
2178 // the keyentry database for further loading of key components.
2179 // We already have the full access tuple to perform access control.
2180 // The only distinction is that we use the caller_uid instead
2181 // of the caller supplied namespace if the domain field is
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002182 // Domain::APP.
2183 Domain::APP | Domain::SELINUX => {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002184 let mut access_key = key.clone();
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002185 if access_key.domain == Domain::APP {
2186 access_key.nspace = caller_uid as i64;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002187 }
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002188 let key_id = Self::load_key_entry_id(&tx, &access_key, key_type)
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002189 .with_context(|| format!("With key.domain = {:?}.", access_key.domain))?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002190
2191 Ok((key_id, access_key, None))
2192 }
2193
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002194 // Domain::GRANT. In this case we load the key_id and the access_vector
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002195 // from the grant table.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002196 Domain::GRANT => {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002197 let mut stmt = tx
2198 .prepare(
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002199 "SELECT keyentryid, access_vector FROM persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002200 WHERE grantee = ? AND id = ?;",
2201 )
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002202 .context("Domain::GRANT prepare statement failed")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002203 let mut rows = stmt
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002204 .query(params![caller_uid as i64, key.nspace])
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002205 .context("Domain:Grant: query failed.")?;
2206 let (key_id, access_vector): (i64, i32) =
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002207 db_utils::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002208 let r =
2209 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002210 Ok((
2211 r.get(0).context("Failed to unpack key_id.")?,
2212 r.get(1).context("Failed to unpack access_vector.")?,
2213 ))
2214 })
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002215 .context("Domain::GRANT.")?;
Janis Danisevskis66784c42021-01-27 08:40:25 -08002216 Ok((key_id, key.clone(), Some(access_vector.into())))
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002217 }
2218
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002219 // Domain::KEY_ID. In this case we load the domain and namespace from the
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002220 // keyentry database because we need them for access control.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002221 Domain::KEY_ID => {
Janis Danisevskis45760022021-01-19 16:34:10 -08002222 let (domain, namespace): (Domain, i64) = {
2223 let mut stmt = tx
2224 .prepare(
2225 "SELECT domain, namespace FROM persistent.keyentry
2226 WHERE
2227 id = ?
2228 AND state = ?;",
2229 )
2230 .context("Domain::KEY_ID: prepare statement failed")?;
2231 let mut rows = stmt
2232 .query(params![key.nspace, KeyLifeCycle::Live])
2233 .context("Domain::KEY_ID: query failed.")?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002234 db_utils::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002235 let r =
2236 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002237 Ok((
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002238 Domain(r.get(0).context("Failed to unpack domain.")?),
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002239 r.get(1).context("Failed to unpack namespace.")?,
2240 ))
2241 })
Janis Danisevskis45760022021-01-19 16:34:10 -08002242 .context("Domain::KEY_ID.")?
2243 };
2244
2245 // We may use a key by id after loading it by grant.
2246 // In this case we have to check if the caller has a grant for this particular
2247 // key. We can skip this if we already know that the caller is the owner.
2248 // But we cannot know this if domain is anything but App. E.g. in the case
2249 // of Domain::SELINUX we have to speculatively check for grants because we have to
2250 // consult the SEPolicy before we know if the caller is the owner.
2251 let access_vector: Option<KeyPermSet> =
2252 if domain != Domain::APP || namespace != caller_uid as i64 {
2253 let access_vector: Option<i32> = tx
2254 .query_row(
2255 "SELECT access_vector FROM persistent.grant
2256 WHERE grantee = ? AND keyentryid = ?;",
2257 params![caller_uid as i64, key.nspace],
2258 |row| row.get(0),
2259 )
2260 .optional()
2261 .context("Domain::KEY_ID: query grant failed.")?;
2262 access_vector.map(|p| p.into())
2263 } else {
2264 None
2265 };
2266
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002267 let key_id = key.nspace;
Janis Danisevskis66784c42021-01-27 08:40:25 -08002268 let mut access_key: KeyDescriptor = key.clone();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002269 access_key.domain = domain;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002270 access_key.nspace = namespace;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002271
Janis Danisevskis45760022021-01-19 16:34:10 -08002272 Ok((key_id, access_key, access_vector))
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002273 }
2274 _ => Err(anyhow!(KsError::sys())),
2275 }
2276 }
2277
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002278 fn load_blob_components(
2279 key_id: i64,
2280 load_bits: KeyEntryLoadBits,
2281 tx: &Transaction,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002282 ) -> Result<(bool, Option<(Vec<u8>, BlobMetaData)>, Option<Vec<u8>>, Option<Vec<u8>>)> {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002283 let mut stmt = tx
2284 .prepare(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002285 "SELECT MAX(id), subcomponent_type, blob FROM persistent.blobentry
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002286 WHERE keyentryid = ? GROUP BY subcomponent_type;",
2287 )
2288 .context("In load_blob_components: prepare statement failed.")?;
2289
2290 let mut rows =
2291 stmt.query(params![key_id]).context("In load_blob_components: query failed.")?;
2292
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002293 let mut key_blob: Option<(i64, Vec<u8>)> = None;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002294 let mut cert_blob: Option<Vec<u8>> = None;
2295 let mut cert_chain_blob: Option<Vec<u8>> = None;
Janis Danisevskis377d1002021-01-27 19:07:48 -08002296 let mut has_km_blob: bool = false;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002297 db_utils::with_rows_extract_all(&mut rows, |row| {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002298 let sub_type: SubComponentType =
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002299 row.get(1).context("Failed to extract subcomponent_type.")?;
Janis Danisevskis377d1002021-01-27 19:07:48 -08002300 has_km_blob = has_km_blob || sub_type == SubComponentType::KEY_BLOB;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002301 match (sub_type, load_bits.load_public(), load_bits.load_km()) {
2302 (SubComponentType::KEY_BLOB, _, true) => {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002303 key_blob = Some((
2304 row.get(0).context("Failed to extract key blob id.")?,
2305 row.get(2).context("Failed to extract key blob.")?,
2306 ));
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002307 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002308 (SubComponentType::CERT, true, _) => {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002309 cert_blob =
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002310 Some(row.get(2).context("Failed to extract public certificate blob.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002311 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002312 (SubComponentType::CERT_CHAIN, true, _) => {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002313 cert_chain_blob =
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002314 Some(row.get(2).context("Failed to extract certificate chain blob.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002315 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002316 (SubComponentType::CERT, _, _)
2317 | (SubComponentType::CERT_CHAIN, _, _)
2318 | (SubComponentType::KEY_BLOB, _, _) => {}
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002319 _ => Err(KsError::sys()).context("Unknown subcomponent type.")?,
2320 }
2321 Ok(())
2322 })
2323 .context("In load_blob_components.")?;
2324
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002325 let blob_info = key_blob.map_or::<Result<_>, _>(Ok(None), |(blob_id, blob)| {
2326 Ok(Some((
2327 blob,
2328 BlobMetaData::load_from_db(blob_id, tx)
2329 .context("In load_blob_components: Trying to load blob_metadata.")?,
2330 )))
2331 })?;
2332
2333 Ok((has_km_blob, blob_info, cert_blob, cert_chain_blob))
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002334 }
2335
2336 fn load_key_parameters(key_id: i64, tx: &Transaction) -> Result<Vec<KeyParameter>> {
2337 let mut stmt = tx
2338 .prepare(
2339 "SELECT tag, data, security_level from persistent.keyparameter
2340 WHERE keyentryid = ?;",
2341 )
2342 .context("In load_key_parameters: prepare statement failed.")?;
2343
2344 let mut parameters: Vec<KeyParameter> = Vec::new();
2345
2346 let mut rows =
2347 stmt.query(params![key_id]).context("In load_key_parameters: query failed.")?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002348 db_utils::with_rows_extract_all(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002349 let tag = Tag(row.get(0).context("Failed to read tag.")?);
2350 let sec_level = SecurityLevel(row.get(2).context("Failed to read sec_level.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002351 parameters.push(
2352 KeyParameter::new_from_sql(tag, &SqlField::new(1, &row), sec_level)
2353 .context("Failed to read KeyParameter.")?,
2354 );
2355 Ok(())
2356 })
2357 .context("In load_key_parameters.")?;
2358
2359 Ok(parameters)
2360 }
2361
Qi Wub9433b52020-12-01 14:52:46 +08002362 /// Decrements the usage count of a limited use key. This function first checks whether the
2363 /// usage has been exhausted, if not, decreases the usage count. If the usage count reaches
2364 /// zero, the key also gets marked unreferenced and scheduled for deletion.
2365 /// Returns Ok(true) if the key was marked unreferenced as a hint to the garbage collector.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002366 pub fn check_and_update_key_usage_count(&mut self, key_id: i64) -> Result<()> {
Qi Wub9433b52020-12-01 14:52:46 +08002367 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2368 let limit: Option<i32> = tx
2369 .query_row(
2370 "SELECT data FROM persistent.keyparameter WHERE keyentryid = ? AND tag = ?;",
2371 params![key_id, Tag::USAGE_COUNT_LIMIT.0],
2372 |row| row.get(0),
2373 )
2374 .optional()
2375 .context("Trying to load usage count")?;
2376
2377 let limit = limit
2378 .ok_or(KsError::Km(ErrorCode::INVALID_KEY_BLOB))
2379 .context("The Key no longer exists. Key is exhausted.")?;
2380
2381 tx.execute(
2382 "UPDATE persistent.keyparameter
2383 SET data = data - 1
2384 WHERE keyentryid = ? AND tag = ? AND data > 0;",
2385 params![key_id, Tag::USAGE_COUNT_LIMIT.0],
2386 )
2387 .context("Failed to update key usage count.")?;
2388
2389 match limit {
2390 1 => Self::mark_unreferenced(tx, key_id)
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002391 .map(|need_gc| (need_gc, ()))
Qi Wub9433b52020-12-01 14:52:46 +08002392 .context("Trying to mark limited use key for deletion."),
2393 0 => Err(KsError::Km(ErrorCode::INVALID_KEY_BLOB)).context("Key is exhausted."),
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002394 _ => Ok(()).no_gc(),
Qi Wub9433b52020-12-01 14:52:46 +08002395 }
2396 })
2397 .context("In check_and_update_key_usage_count.")
2398 }
2399
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002400 /// Load a key entry by the given key descriptor.
2401 /// It uses the `check_permission` callback to verify if the access is allowed
2402 /// given the key access tuple read from the database using `load_access_tuple`.
2403 /// With `load_bits` the caller may specify which blobs shall be loaded from
2404 /// the blob database.
2405 pub fn load_key_entry(
2406 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002407 key: &KeyDescriptor,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002408 key_type: KeyType,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002409 load_bits: KeyEntryLoadBits,
2410 caller_uid: u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002411 check_permission: impl Fn(&KeyDescriptor, Option<KeyPermSet>) -> Result<()>,
2412 ) -> Result<(KeyIdGuard, KeyEntry)> {
2413 loop {
2414 match self.load_key_entry_internal(
2415 key,
2416 key_type,
2417 load_bits,
2418 caller_uid,
2419 &check_permission,
2420 ) {
2421 Ok(result) => break Ok(result),
2422 Err(e) => {
2423 if Self::is_locked_error(&e) {
2424 std::thread::sleep(std::time::Duration::from_micros(500));
2425 continue;
2426 } else {
2427 return Err(e).context("In load_key_entry.");
2428 }
2429 }
2430 }
2431 }
2432 }
2433
2434 fn load_key_entry_internal(
2435 &mut self,
2436 key: &KeyDescriptor,
2437 key_type: KeyType,
2438 load_bits: KeyEntryLoadBits,
2439 caller_uid: u32,
2440 check_permission: &impl Fn(&KeyDescriptor, Option<KeyPermSet>) -> Result<()>,
Janis Danisevskisaec14592020-11-12 09:41:49 -08002441 ) -> Result<(KeyIdGuard, KeyEntry)> {
2442 // KEY ID LOCK 1/2
2443 // If we got a key descriptor with a key id we can get the lock right away.
2444 // Otherwise we have to defer it until we know the key id.
2445 let key_id_guard = match key.domain {
2446 Domain::KEY_ID => Some(KEY_ID_LOCK.get(key.nspace)),
2447 _ => None,
2448 };
2449
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002450 let tx = self
2451 .conn
Janis Danisevskisaec14592020-11-12 09:41:49 -08002452 .unchecked_transaction()
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002453 .context("In load_key_entry: Failed to initialize transaction.")?;
2454
2455 // Load the key_id and complete the access control tuple.
2456 let (key_id, access_key_descriptor, access_vector) =
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002457 Self::load_access_tuple(&tx, key, key_type, caller_uid)
2458 .context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002459
2460 // Perform access control. It is vital that we return here if the permission is denied.
2461 // So do not touch that '?' at the end.
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002462 check_permission(&access_key_descriptor, access_vector).context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002463
Janis Danisevskisaec14592020-11-12 09:41:49 -08002464 // KEY ID LOCK 2/2
2465 // If we did not get a key id lock by now, it was because we got a key descriptor
2466 // without a key id. At this point we got the key id, so we can try and get a lock.
2467 // However, we cannot block here, because we are in the middle of the transaction.
2468 // So first we try to get the lock non blocking. If that fails, we roll back the
2469 // transaction and block until we get the lock. After we successfully got the lock,
2470 // we start a new transaction and load the access tuple again.
2471 //
2472 // We don't need to perform access control again, because we already established
2473 // that the caller had access to the given key. But we need to make sure that the
2474 // key id still exists. So we have to load the key entry by key id this time.
2475 let (key_id_guard, tx) = match key_id_guard {
2476 None => match KEY_ID_LOCK.try_get(key_id) {
2477 None => {
2478 // Roll back the transaction.
2479 tx.rollback().context("In load_key_entry: Failed to roll back transaction.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002480
Janis Danisevskisaec14592020-11-12 09:41:49 -08002481 // Block until we have a key id lock.
2482 let key_id_guard = KEY_ID_LOCK.get(key_id);
2483
2484 // Create a new transaction.
Janis Danisevskis66784c42021-01-27 08:40:25 -08002485 let tx = self
2486 .conn
2487 .unchecked_transaction()
2488 .context("In load_key_entry: Failed to initialize transaction.")?;
Janis Danisevskisaec14592020-11-12 09:41:49 -08002489
2490 Self::load_access_tuple(
2491 &tx,
2492 // This time we have to load the key by the retrieved key id, because the
2493 // alias may have been rebound after we rolled back the transaction.
Janis Danisevskis66784c42021-01-27 08:40:25 -08002494 &KeyDescriptor {
Janis Danisevskisaec14592020-11-12 09:41:49 -08002495 domain: Domain::KEY_ID,
2496 nspace: key_id,
2497 ..Default::default()
2498 },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002499 key_type,
Janis Danisevskisaec14592020-11-12 09:41:49 -08002500 caller_uid,
2501 )
2502 .context("In load_key_entry. (deferred key lock)")?;
2503 (key_id_guard, tx)
2504 }
2505 Some(l) => (l, tx),
2506 },
2507 Some(key_id_guard) => (key_id_guard, tx),
2508 };
2509
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002510 let key_entry = Self::load_key_components(&tx, load_bits, key_id_guard.id())
2511 .context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002512
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002513 tx.commit().context("In load_key_entry: Failed to commit transaction.")?;
2514
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002515 Ok((key_id_guard, key_entry))
2516 }
2517
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002518 fn mark_unreferenced(tx: &Transaction, key_id: i64) -> Result<bool> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002519 let updated = tx
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002520 .execute("DELETE FROM persistent.keyentry WHERE id = ?;", params![key_id])
2521 .context("Trying to delete keyentry.")?;
2522 tx.execute("DELETE FROM persistent.keymetadata WHERE keyentryid = ?;", params![key_id])
2523 .context("Trying to delete keymetadata.")?;
2524 tx.execute("DELETE FROM persistent.keyparameter WHERE keyentryid = ?;", params![key_id])
2525 .context("Trying to delete keyparameters.")?;
2526 tx.execute("DELETE FROM persistent.grant WHERE keyentryid = ?;", params![key_id])
2527 .context("Trying to delete grants.")?;
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002528 Ok(updated != 0)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002529 }
2530
2531 /// Marks the given key as unreferenced and removes all of the grants to this key.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002532 /// Returns Ok(true) if a key was marked unreferenced as a hint for the garbage collector.
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002533 pub fn unbind_key(
2534 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002535 key: &KeyDescriptor,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002536 key_type: KeyType,
2537 caller_uid: u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002538 check_permission: impl Fn(&KeyDescriptor, Option<KeyPermSet>) -> Result<()>,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002539 ) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002540 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2541 let (key_id, access_key_descriptor, access_vector) =
2542 Self::load_access_tuple(tx, key, key_type, caller_uid)
2543 .context("Trying to get access tuple.")?;
2544
2545 // Perform access control. It is vital that we return here if the permission is denied.
2546 // So do not touch that '?' at the end.
2547 check_permission(&access_key_descriptor, access_vector)
2548 .context("While checking permission.")?;
2549
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002550 Self::mark_unreferenced(tx, key_id)
2551 .map(|need_gc| (need_gc, ()))
2552 .context("Trying to mark the key unreferenced.")
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002553 })
2554 .context("In unbind_key.")
2555 }
2556
Max Bires8e93d2b2021-01-14 13:17:59 -08002557 fn get_key_km_uuid(tx: &Transaction, key_id: i64) -> Result<Uuid> {
2558 tx.query_row(
2559 "SELECT km_uuid FROM persistent.keyentry WHERE id = ?",
2560 params![key_id],
2561 |row| row.get(0),
2562 )
2563 .context("In get_key_km_uuid.")
2564 }
2565
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002566 /// Delete all artifacts belonging to the namespace given by the domain-namespace tuple.
2567 /// This leaves all of the blob entries orphaned for subsequent garbage collection.
2568 pub fn unbind_keys_for_namespace(&mut self, domain: Domain, namespace: i64) -> Result<()> {
2569 if !(domain == Domain::APP || domain == Domain::SELINUX) {
2570 return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT))
2571 .context("In unbind_keys_for_namespace.");
2572 }
2573 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2574 tx.execute(
2575 "DELETE FROM persistent.keymetadata
2576 WHERE keyentryid IN (
2577 SELECT id FROM persistent.keyentry
2578 WHERE domain = ? AND namespace = ?
2579 );",
2580 params![domain.0, namespace],
2581 )
2582 .context("Trying to delete keymetadata.")?;
2583 tx.execute(
2584 "DELETE FROM persistent.keyparameter
2585 WHERE keyentryid IN (
2586 SELECT id FROM persistent.keyentry
2587 WHERE domain = ? AND namespace = ?
2588 );",
2589 params![domain.0, namespace],
2590 )
2591 .context("Trying to delete keyparameters.")?;
2592 tx.execute(
2593 "DELETE FROM persistent.grant
2594 WHERE keyentryid IN (
2595 SELECT id FROM persistent.keyentry
2596 WHERE domain = ? AND namespace = ?
2597 );",
2598 params![domain.0, namespace],
2599 )
2600 .context("Trying to delete grants.")?;
2601 tx.execute(
2602 "DELETE FROM persistent.keyentry WHERE domain = ? AND namespace = ?;",
2603 params![domain.0, namespace],
2604 )
2605 .context("Trying to delete keyentry.")?;
2606 Ok(()).need_gc()
2607 })
2608 .context("In unbind_keys_for_namespace")
2609 }
2610
Hasini Gunasingheda895552021-01-27 19:34:37 +00002611 /// Delete the keys created on behalf of the user, denoted by the user id.
2612 /// Delete all the keys unless 'keep_non_super_encrypted_keys' set to true.
2613 /// Returned boolean is to hint the garbage collector to delete the unbound keys.
2614 /// The caller of this function should notify the gc if the returned value is true.
2615 pub fn unbind_keys_for_user(
2616 &mut self,
2617 user_id: u32,
2618 keep_non_super_encrypted_keys: bool,
2619 ) -> Result<()> {
2620 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2621 let mut stmt = tx
2622 .prepare(&format!(
2623 "SELECT id from persistent.keyentry
2624 WHERE (
2625 key_type = ?
2626 AND domain = ?
2627 AND cast ( (namespace/{aid_user_offset}) as int) = ?
2628 AND state = ?
2629 ) OR (
2630 key_type = ?
2631 AND namespace = ?
2632 AND alias = ?
2633 AND state = ?
2634 );",
2635 aid_user_offset = AID_USER_OFFSET
2636 ))
2637 .context(concat!(
2638 "In unbind_keys_for_user. ",
2639 "Failed to prepare the query to find the keys created by apps."
2640 ))?;
2641
2642 let mut rows = stmt
2643 .query(params![
2644 // WHERE client key:
2645 KeyType::Client,
2646 Domain::APP.0 as u32,
2647 user_id,
2648 KeyLifeCycle::Live,
2649 // OR super key:
2650 KeyType::Super,
2651 user_id,
2652 Self::USER_SUPER_KEY_ALIAS,
2653 KeyLifeCycle::Live
2654 ])
2655 .context("In unbind_keys_for_user. Failed to query the keys created by apps.")?;
2656
2657 let mut key_ids: Vec<i64> = Vec::new();
2658 db_utils::with_rows_extract_all(&mut rows, |row| {
2659 key_ids
2660 .push(row.get(0).context("Failed to read key id of a key created by an app.")?);
2661 Ok(())
2662 })
2663 .context("In unbind_keys_for_user.")?;
2664
2665 let mut notify_gc = false;
2666 for key_id in key_ids {
2667 if keep_non_super_encrypted_keys {
2668 // Load metadata and filter out non-super-encrypted keys.
2669 if let (_, Some((_, blob_metadata)), _, _) =
2670 Self::load_blob_components(key_id, KeyEntryLoadBits::KM, tx)
2671 .context("In unbind_keys_for_user: Trying to load blob info.")?
2672 {
2673 if blob_metadata.encrypted_by().is_none() {
2674 continue;
2675 }
2676 }
2677 }
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +00002678 notify_gc = Self::mark_unreferenced(&tx, key_id)
Hasini Gunasingheda895552021-01-27 19:34:37 +00002679 .context("In unbind_keys_for_user.")?
2680 || notify_gc;
2681 }
2682 Ok(()).do_gc(notify_gc)
2683 })
2684 .context("In unbind_keys_for_user.")
2685 }
2686
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002687 fn load_key_components(
2688 tx: &Transaction,
2689 load_bits: KeyEntryLoadBits,
2690 key_id: i64,
2691 ) -> Result<KeyEntry> {
2692 let metadata = KeyMetaData::load_from_db(key_id, &tx).context("In load_key_components.")?;
2693
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002694 let (has_km_blob, key_blob_info, cert_blob, cert_chain_blob) =
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002695 Self::load_blob_components(key_id, load_bits, &tx)
2696 .context("In load_key_components.")?;
2697
Max Bires8e93d2b2021-01-14 13:17:59 -08002698 let parameters = Self::load_key_parameters(key_id, &tx)
2699 .context("In load_key_components: Trying to load key parameters.")?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002700
Max Bires8e93d2b2021-01-14 13:17:59 -08002701 let km_uuid = Self::get_key_km_uuid(&tx, key_id)
2702 .context("In load_key_components: Trying to get KM uuid.")?;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002703
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002704 Ok(KeyEntry {
2705 id: key_id,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002706 key_blob_info,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002707 cert: cert_blob,
2708 cert_chain: cert_chain_blob,
Max Bires8e93d2b2021-01-14 13:17:59 -08002709 km_uuid,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002710 parameters,
2711 metadata,
Janis Danisevskis377d1002021-01-27 19:07:48 -08002712 pure_cert: !has_km_blob,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002713 })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002714 }
2715
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002716 /// Returns a list of KeyDescriptors in the selected domain/namespace.
2717 /// The key descriptors will have the domain, nspace, and alias field set.
2718 /// Domain must be APP or SELINUX, the caller must make sure of that.
2719 pub fn list(&mut self, domain: Domain, namespace: i64) -> Result<Vec<KeyDescriptor>> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002720 self.with_transaction(TransactionBehavior::Deferred, |tx| {
2721 let mut stmt = tx
2722 .prepare(
2723 "SELECT alias FROM persistent.keyentry
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002724 WHERE domain = ? AND namespace = ? AND alias IS NOT NULL AND state = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08002725 )
2726 .context("In list: Failed to prepare.")?;
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002727
Janis Danisevskis66784c42021-01-27 08:40:25 -08002728 let mut rows = stmt
2729 .query(params![domain.0 as u32, namespace, KeyLifeCycle::Live])
2730 .context("In list: Failed to query.")?;
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002731
Janis Danisevskis66784c42021-01-27 08:40:25 -08002732 let mut descriptors: Vec<KeyDescriptor> = Vec::new();
2733 db_utils::with_rows_extract_all(&mut rows, |row| {
2734 descriptors.push(KeyDescriptor {
2735 domain,
2736 nspace: namespace,
2737 alias: Some(row.get(0).context("Trying to extract alias.")?),
2738 blob: None,
2739 });
2740 Ok(())
2741 })
2742 .context("In list: Failed to extract rows.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002743 Ok(descriptors).no_gc()
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002744 })
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002745 }
2746
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002747 /// Adds a grant to the grant table.
2748 /// Like `load_key_entry` this function loads the access tuple before
2749 /// it uses the callback for a permission check. Upon success,
2750 /// it inserts the `grantee_uid`, `key_id`, and `access_vector` into the
2751 /// grant table. The new row will have a randomized id, which is used as
2752 /// grant id in the namespace field of the resulting KeyDescriptor.
2753 pub fn grant(
2754 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002755 key: &KeyDescriptor,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002756 caller_uid: u32,
2757 grantee_uid: u32,
2758 access_vector: KeyPermSet,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002759 check_permission: impl Fn(&KeyDescriptor, &KeyPermSet) -> Result<()>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002760 ) -> Result<KeyDescriptor> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002761 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2762 // Load the key_id and complete the access control tuple.
2763 // We ignore the access vector here because grants cannot be granted.
2764 // The access vector returned here expresses the permissions the
2765 // grantee has if key.domain == Domain::GRANT. But this vector
2766 // cannot include the grant permission by design, so there is no way the
2767 // subsequent permission check can pass.
2768 // We could check key.domain == Domain::GRANT and fail early.
2769 // But even if we load the access tuple by grant here, the permission
2770 // check denies the attempt to create a grant by grant descriptor.
2771 let (key_id, access_key_descriptor, _) =
2772 Self::load_access_tuple(&tx, key, KeyType::Client, caller_uid)
2773 .context("In grant")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002774
Janis Danisevskis66784c42021-01-27 08:40:25 -08002775 // Perform access control. It is vital that we return here if the permission
2776 // was denied. So do not touch that '?' at the end of the line.
2777 // This permission check checks if the caller has the grant permission
2778 // for the given key and in addition to all of the permissions
2779 // expressed in `access_vector`.
2780 check_permission(&access_key_descriptor, &access_vector)
2781 .context("In grant: check_permission failed.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002782
Janis Danisevskis66784c42021-01-27 08:40:25 -08002783 let grant_id = if let Some(grant_id) = tx
2784 .query_row(
2785 "SELECT id FROM persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002786 WHERE keyentryid = ? AND grantee = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08002787 params![key_id, grantee_uid],
2788 |row| row.get(0),
2789 )
2790 .optional()
2791 .context("In grant: Failed get optional existing grant id.")?
2792 {
2793 tx.execute(
2794 "UPDATE persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002795 SET access_vector = ?
2796 WHERE id = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08002797 params![i32::from(access_vector), grant_id],
Joel Galenson845f74b2020-09-09 14:11:55 -07002798 )
Janis Danisevskis66784c42021-01-27 08:40:25 -08002799 .context("In grant: Failed to update existing grant.")?;
2800 grant_id
2801 } else {
2802 Self::insert_with_retry(|id| {
2803 tx.execute(
2804 "INSERT INTO persistent.grant (id, grantee, keyentryid, access_vector)
2805 VALUES (?, ?, ?, ?);",
2806 params![id, grantee_uid, key_id, i32::from(access_vector)],
2807 )
2808 })
2809 .context("In grant")?
2810 };
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002811
Janis Danisevskis66784c42021-01-27 08:40:25 -08002812 Ok(KeyDescriptor { domain: Domain::GRANT, nspace: grant_id, alias: None, blob: None })
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002813 .no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08002814 })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002815 }
2816
2817 /// This function checks permissions like `grant` and `load_key_entry`
2818 /// before removing a grant from the grant table.
2819 pub fn ungrant(
2820 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002821 key: &KeyDescriptor,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002822 caller_uid: u32,
2823 grantee_uid: u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002824 check_permission: impl Fn(&KeyDescriptor) -> Result<()>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002825 ) -> Result<()> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002826 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2827 // Load the key_id and complete the access control tuple.
2828 // We ignore the access vector here because grants cannot be granted.
2829 let (key_id, access_key_descriptor, _) =
2830 Self::load_access_tuple(&tx, key, KeyType::Client, caller_uid)
2831 .context("In ungrant.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002832
Janis Danisevskis66784c42021-01-27 08:40:25 -08002833 // Perform access control. We must return here if the permission
2834 // was denied. So do not touch the '?' at the end of this line.
2835 check_permission(&access_key_descriptor)
2836 .context("In grant: check_permission failed.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002837
Janis Danisevskis66784c42021-01-27 08:40:25 -08002838 tx.execute(
2839 "DELETE FROM persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002840 WHERE keyentryid = ? AND grantee = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08002841 params![key_id, grantee_uid],
2842 )
2843 .context("Failed to delete grant.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002844
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002845 Ok(()).no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08002846 })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002847 }
2848
Joel Galenson845f74b2020-09-09 14:11:55 -07002849 // Generates a random id and passes it to the given function, which will
2850 // try to insert it into a database. If that insertion fails, retry;
2851 // otherwise return the id.
2852 fn insert_with_retry(inserter: impl Fn(i64) -> rusqlite::Result<usize>) -> Result<i64> {
2853 loop {
Janis Danisevskiseed69842021-02-18 20:04:10 -08002854 let newid: i64 = match random() {
2855 Self::UNASSIGNED_KEY_ID => continue, // UNASSIGNED_KEY_ID cannot be assigned.
2856 i => i,
2857 };
Joel Galenson845f74b2020-09-09 14:11:55 -07002858 match inserter(newid) {
2859 // If the id already existed, try again.
2860 Err(rusqlite::Error::SqliteFailure(
2861 libsqlite3_sys::Error {
2862 code: libsqlite3_sys::ErrorCode::ConstraintViolation,
2863 extended_code: libsqlite3_sys::SQLITE_CONSTRAINT_UNIQUE,
2864 },
2865 _,
2866 )) => (),
2867 Err(e) => {
2868 return Err(e).context("In insert_with_retry: failed to insert into database.")
2869 }
2870 _ => return Ok(newid),
2871 }
2872 }
2873 }
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002874
2875 /// Insert or replace the auth token based on the UNIQUE constraint of the auth token table
2876 pub fn insert_auth_token(&mut self, auth_token: &HardwareAuthToken) -> Result<()> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002877 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2878 tx.execute(
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002879 "INSERT OR REPLACE INTO perboot.authtoken (challenge, user_id, auth_id,
2880 authenticator_type, timestamp, mac, time_received) VALUES(?, ?, ?, ?, ?, ?, ?);",
2881 params![
2882 auth_token.challenge,
2883 auth_token.userId,
2884 auth_token.authenticatorId,
2885 auth_token.authenticatorType.0 as i32,
2886 auth_token.timestamp.milliSeconds as i64,
2887 auth_token.mac,
2888 MonotonicRawTime::now(),
2889 ],
2890 )
2891 .context("In insert_auth_token: failed to insert auth token into the database")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002892 Ok(()).no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08002893 })
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002894 }
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002895
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002896 /// Find the newest auth token matching the given predicate.
2897 pub fn find_auth_token_entry<F>(
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002898 &mut self,
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002899 p: F,
2900 ) -> Result<Option<(AuthTokenEntry, MonotonicRawTime)>>
2901 where
2902 F: Fn(&AuthTokenEntry) -> bool,
2903 {
2904 self.with_transaction(TransactionBehavior::Deferred, |tx| {
2905 let mut stmt = tx
2906 .prepare("SELECT * from perboot.authtoken ORDER BY time_received DESC;")
2907 .context("Prepare statement failed.")?;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002908
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002909 let mut rows = stmt.query(NO_PARAMS).context("Failed to query.")?;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002910
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002911 while let Some(row) = rows.next().context("Failed to get next row.")? {
2912 let entry = AuthTokenEntry::new(
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002913 HardwareAuthToken {
2914 challenge: row.get(1)?,
2915 userId: row.get(2)?,
2916 authenticatorId: row.get(3)?,
2917 authenticatorType: HardwareAuthenticatorType(row.get(4)?),
2918 timestamp: Timestamp { milliSeconds: row.get(5)? },
2919 mac: row.get(6)?,
2920 },
2921 row.get(7)?,
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002922 );
2923 if p(&entry) {
2924 return Ok(Some((
2925 entry,
2926 Self::get_last_off_body(tx)
2927 .context("In find_auth_token_entry: Trying to get last off body")?,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002928 )))
2929 .no_gc();
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002930 }
2931 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002932 Ok(None).no_gc()
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002933 })
2934 .context("In find_auth_token_entry.")
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002935 }
2936
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002937 /// Insert last_off_body into the metadata table at the initialization of auth token table
Janis Danisevskis66784c42021-01-27 08:40:25 -08002938 pub fn insert_last_off_body(&mut self, last_off_body: MonotonicRawTime) -> Result<()> {
2939 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2940 tx.execute(
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002941 "INSERT OR REPLACE INTO perboot.metadata (key, value) VALUES (?, ?);",
2942 params!["last_off_body", last_off_body],
2943 )
2944 .context("In insert_last_off_body: failed to insert.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002945 Ok(()).no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08002946 })
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002947 }
2948
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002949 /// Update last_off_body when on_device_off_body is called
Janis Danisevskis66784c42021-01-27 08:40:25 -08002950 pub fn update_last_off_body(&mut self, last_off_body: MonotonicRawTime) -> Result<()> {
2951 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2952 tx.execute(
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002953 "UPDATE perboot.metadata SET value = ? WHERE key = ?;",
2954 params![last_off_body, "last_off_body"],
2955 )
2956 .context("In update_last_off_body: failed to update.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002957 Ok(()).no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08002958 })
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002959 }
2960
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002961 /// Get last_off_body time when finding auth tokens
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002962 fn get_last_off_body(tx: &Transaction) -> Result<MonotonicRawTime> {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002963 tx.query_row(
2964 "SELECT value from perboot.metadata WHERE key = ?;",
2965 params!["last_off_body"],
2966 |row| Ok(row.get(0)?),
2967 )
2968 .context("In get_last_off_body: query_row failed.")
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002969 }
Joel Galenson26f4d012020-07-17 14:57:21 -07002970}
2971
2972#[cfg(test)]
2973mod tests {
2974
2975 use super::*;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002976 use crate::key_parameter::{
2977 Algorithm, BlockMode, Digest, EcCurve, HardwareAuthenticatorType, KeyOrigin, KeyParameter,
2978 KeyParameterValue, KeyPurpose, PaddingMode, SecurityLevel,
2979 };
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002980 use crate::key_perm_set;
2981 use crate::permission::{KeyPerm, KeyPermSet};
Hasini Gunasingheda895552021-01-27 19:34:37 +00002982 use crate::super_key::SuperKeyManager;
Janis Danisevskis2a8330a2021-01-20 15:34:26 -08002983 use keystore2_test_utils::TempDir;
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002984 use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
2985 HardwareAuthToken::HardwareAuthToken,
2986 HardwareAuthenticatorType::HardwareAuthenticatorType as kmhw_authenticator_type,
Janis Danisevskisc3a496b2021-01-05 10:37:22 -08002987 };
2988 use android_hardware_security_secureclock::aidl::android::hardware::security::secureclock::{
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002989 Timestamp::Timestamp,
2990 };
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002991 use rusqlite::NO_PARAMS;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002992 use rusqlite::{Error, TransactionBehavior};
Joel Galenson0891bc12020-07-20 10:37:03 -07002993 use std::cell::RefCell;
Janis Danisevskisaec14592020-11-12 09:41:49 -08002994 use std::sync::atomic::{AtomicU8, Ordering};
2995 use std::sync::Arc;
2996 use std::thread;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002997 use std::time::{Duration, SystemTime};
Janis Danisevskis66784c42021-01-27 08:40:25 -08002998 #[cfg(disabled)]
2999 use std::time::Instant;
Joel Galenson0891bc12020-07-20 10:37:03 -07003000
Janis Danisevskis4df44f42020-08-26 14:40:03 -07003001 fn new_test_db() -> Result<KeystoreDB> {
3002 let conn = KeystoreDB::make_connection("file::memory:", "file::memory:")?;
3003
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003004 let mut db = KeystoreDB { conn, gc: None };
Janis Danisevskis66784c42021-01-27 08:40:25 -08003005 db.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003006 KeystoreDB::init_tables(tx).context("Failed to initialize tables.").no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08003007 })?;
3008 Ok(db)
Janis Danisevskis4df44f42020-08-26 14:40:03 -07003009 }
3010
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003011 fn new_test_db_with_gc<F>(path: &Path, cb: F) -> Result<KeystoreDB>
3012 where
3013 F: Fn(&Uuid, &[u8]) -> Result<()> + Send + 'static,
3014 {
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00003015 let super_key = Arc::new(SuperKeyManager::new());
3016
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003017 let gc_db = KeystoreDB::new(path, None).expect("Failed to open test gc db_connection.");
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00003018 let gc = Gc::new_init_with(Default::default(), move || (Box::new(cb), gc_db, super_key));
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003019
3020 KeystoreDB::new(path, Some(gc))
3021 }
3022
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003023 fn rebind_alias(
3024 db: &mut KeystoreDB,
3025 newid: &KeyIdGuard,
3026 alias: &str,
3027 domain: Domain,
3028 namespace: i64,
3029 ) -> Result<bool> {
3030 db.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003031 KeystoreDB::rebind_alias(tx, newid, alias, &domain, &namespace).no_gc()
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003032 })
3033 .context("In rebind_alias.")
3034 }
3035
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003036 #[test]
3037 fn datetime() -> Result<()> {
3038 let conn = Connection::open_in_memory()?;
3039 conn.execute("CREATE TABLE test (ts DATETIME);", NO_PARAMS)?;
3040 let now = SystemTime::now();
3041 let duration = Duration::from_secs(1000);
3042 let then = now.checked_sub(duration).unwrap();
3043 let soon = now.checked_add(duration).unwrap();
3044 conn.execute(
3045 "INSERT INTO test (ts) VALUES (?), (?), (?);",
3046 params![DateTime::try_from(now)?, DateTime::try_from(then)?, DateTime::try_from(soon)?],
3047 )?;
3048 let mut stmt = conn.prepare("SELECT ts FROM test ORDER BY ts ASC;")?;
3049 let mut rows = stmt.query(NO_PARAMS)?;
3050 assert_eq!(DateTime::try_from(then)?, rows.next()?.unwrap().get(0)?);
3051 assert_eq!(DateTime::try_from(now)?, rows.next()?.unwrap().get(0)?);
3052 assert_eq!(DateTime::try_from(soon)?, rows.next()?.unwrap().get(0)?);
3053 assert!(rows.next()?.is_none());
3054 assert!(DateTime::try_from(then)? < DateTime::try_from(now)?);
3055 assert!(DateTime::try_from(then)? < DateTime::try_from(soon)?);
3056 assert!(DateTime::try_from(now)? < DateTime::try_from(soon)?);
3057 Ok(())
3058 }
3059
Joel Galenson0891bc12020-07-20 10:37:03 -07003060 // Ensure that we're using the "injected" random function, not the real one.
3061 #[test]
3062 fn test_mocked_random() {
3063 let rand1 = random();
3064 let rand2 = random();
3065 let rand3 = random();
3066 if rand1 == rand2 {
3067 assert_eq!(rand2 + 1, rand3);
3068 } else {
3069 assert_eq!(rand1 + 1, rand2);
3070 assert_eq!(rand2, rand3);
3071 }
3072 }
Joel Galenson26f4d012020-07-17 14:57:21 -07003073
Joel Galenson26f4d012020-07-17 14:57:21 -07003074 // Test that we have the correct tables.
3075 #[test]
3076 fn test_tables() -> Result<()> {
Janis Danisevskis4df44f42020-08-26 14:40:03 -07003077 let db = new_test_db()?;
Joel Galenson26f4d012020-07-17 14:57:21 -07003078 let tables = db
3079 .conn
Joel Galenson2aab4432020-07-22 15:27:57 -07003080 .prepare("SELECT name from persistent.sqlite_master WHERE type='table' ORDER BY name;")?
Joel Galenson26f4d012020-07-17 14:57:21 -07003081 .query_map(params![], |row| row.get(0))?
3082 .collect::<rusqlite::Result<Vec<String>>>()?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003083 assert_eq!(tables.len(), 6);
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003084 assert_eq!(tables[0], "blobentry");
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003085 assert_eq!(tables[1], "blobmetadata");
3086 assert_eq!(tables[2], "grant");
3087 assert_eq!(tables[3], "keyentry");
3088 assert_eq!(tables[4], "keymetadata");
3089 assert_eq!(tables[5], "keyparameter");
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003090 let tables = db
3091 .conn
3092 .prepare("SELECT name from perboot.sqlite_master WHERE type='table' ORDER BY name;")?
3093 .query_map(params![], |row| row.get(0))?
3094 .collect::<rusqlite::Result<Vec<String>>>()?;
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00003095
3096 assert_eq!(tables.len(), 2);
3097 assert_eq!(tables[0], "authtoken");
3098 assert_eq!(tables[1], "metadata");
Joel Galenson2aab4432020-07-22 15:27:57 -07003099 Ok(())
3100 }
3101
3102 #[test]
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00003103 fn test_auth_token_table_invariant() -> Result<()> {
3104 let mut db = new_test_db()?;
3105 let auth_token1 = HardwareAuthToken {
3106 challenge: i64::MAX,
3107 userId: 200,
3108 authenticatorId: 200,
3109 authenticatorType: kmhw_authenticator_type(kmhw_authenticator_type::PASSWORD.0),
3110 timestamp: Timestamp { milliSeconds: 500 },
3111 mac: String::from("mac").into_bytes(),
3112 };
3113 db.insert_auth_token(&auth_token1)?;
3114 let auth_tokens_returned = get_auth_tokens(&mut db)?;
3115 assert_eq!(auth_tokens_returned.len(), 1);
3116
3117 // insert another auth token with the same values for the columns in the UNIQUE constraint
3118 // of the auth token table and different value for timestamp
3119 let auth_token2 = HardwareAuthToken {
3120 challenge: i64::MAX,
3121 userId: 200,
3122 authenticatorId: 200,
3123 authenticatorType: kmhw_authenticator_type(kmhw_authenticator_type::PASSWORD.0),
3124 timestamp: Timestamp { milliSeconds: 600 },
3125 mac: String::from("mac").into_bytes(),
3126 };
3127
3128 db.insert_auth_token(&auth_token2)?;
3129 let mut auth_tokens_returned = get_auth_tokens(&mut db)?;
3130 assert_eq!(auth_tokens_returned.len(), 1);
3131
3132 if let Some(auth_token) = auth_tokens_returned.pop() {
3133 assert_eq!(auth_token.auth_token.timestamp.milliSeconds, 600);
3134 }
3135
3136 // insert another auth token with the different values for the columns in the UNIQUE
3137 // constraint of the auth token table
3138 let auth_token3 = HardwareAuthToken {
3139 challenge: i64::MAX,
3140 userId: 201,
3141 authenticatorId: 200,
3142 authenticatorType: kmhw_authenticator_type(kmhw_authenticator_type::PASSWORD.0),
3143 timestamp: Timestamp { milliSeconds: 600 },
3144 mac: String::from("mac").into_bytes(),
3145 };
3146
3147 db.insert_auth_token(&auth_token3)?;
3148 let auth_tokens_returned = get_auth_tokens(&mut db)?;
3149 assert_eq!(auth_tokens_returned.len(), 2);
3150
3151 Ok(())
3152 }
3153
3154 // utility function for test_auth_token_table_invariant()
3155 fn get_auth_tokens(db: &mut KeystoreDB) -> Result<Vec<AuthTokenEntry>> {
3156 let mut stmt = db.conn.prepare("SELECT * from perboot.authtoken;")?;
3157
3158 let auth_token_entries: Vec<AuthTokenEntry> = stmt
3159 .query_map(NO_PARAMS, |row| {
3160 Ok(AuthTokenEntry::new(
3161 HardwareAuthToken {
3162 challenge: row.get(1)?,
3163 userId: row.get(2)?,
3164 authenticatorId: row.get(3)?,
3165 authenticatorType: HardwareAuthenticatorType(row.get(4)?),
3166 timestamp: Timestamp { milliSeconds: row.get(5)? },
3167 mac: row.get(6)?,
3168 },
3169 row.get(7)?,
3170 ))
3171 })?
3172 .collect::<Result<Vec<AuthTokenEntry>, Error>>()?;
3173 Ok(auth_token_entries)
3174 }
3175
3176 #[test]
Joel Galenson2aab4432020-07-22 15:27:57 -07003177 fn test_persistence_for_files() -> Result<()> {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08003178 let temp_dir = TempDir::new("persistent_db_test")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003179 let mut db = KeystoreDB::new(temp_dir.path(), None)?;
Joel Galenson2aab4432020-07-22 15:27:57 -07003180
Janis Danisevskis66784c42021-01-27 08:40:25 -08003181 db.create_key_entry(&Domain::APP, &100, &KEYSTORE_UUID)?;
Joel Galenson2aab4432020-07-22 15:27:57 -07003182 let entries = get_keyentry(&db)?;
3183 assert_eq!(entries.len(), 1);
Janis Danisevskisbf15d732020-12-08 10:35:26 -08003184
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003185 let db = KeystoreDB::new(temp_dir.path(), None)?;
Joel Galenson2aab4432020-07-22 15:27:57 -07003186
3187 let entries_new = get_keyentry(&db)?;
3188 assert_eq!(entries, entries_new);
3189 Ok(())
3190 }
3191
3192 #[test]
Joel Galenson0891bc12020-07-20 10:37:03 -07003193 fn test_create_key_entry() -> Result<()> {
Max Bires8e93d2b2021-01-14 13:17:59 -08003194 fn extractor(ke: &KeyEntryRow) -> (Domain, i64, Option<&str>, Uuid) {
3195 (ke.domain.unwrap(), ke.namespace.unwrap(), ke.alias.as_deref(), ke.km_uuid.unwrap())
Joel Galenson0891bc12020-07-20 10:37:03 -07003196 }
3197
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003198 let mut db = new_test_db()?;
Joel Galenson0891bc12020-07-20 10:37:03 -07003199
Janis Danisevskis66784c42021-01-27 08:40:25 -08003200 db.create_key_entry(&Domain::APP, &100, &KEYSTORE_UUID)?;
3201 db.create_key_entry(&Domain::SELINUX, &101, &KEYSTORE_UUID)?;
Joel Galenson0891bc12020-07-20 10:37:03 -07003202
3203 let entries = get_keyentry(&db)?;
3204 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08003205 assert_eq!(extractor(&entries[0]), (Domain::APP, 100, None, KEYSTORE_UUID));
3206 assert_eq!(extractor(&entries[1]), (Domain::SELINUX, 101, None, KEYSTORE_UUID));
Joel Galenson0891bc12020-07-20 10:37:03 -07003207
3208 // Test that we must pass in a valid Domain.
3209 check_result_is_error_containing_string(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003210 db.create_key_entry(&Domain::GRANT, &102, &KEYSTORE_UUID),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003211 "Domain Domain(1) must be either App or SELinux.",
Joel Galenson0891bc12020-07-20 10:37:03 -07003212 );
3213 check_result_is_error_containing_string(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003214 db.create_key_entry(&Domain::BLOB, &103, &KEYSTORE_UUID),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003215 "Domain Domain(3) must be either App or SELinux.",
Joel Galenson0891bc12020-07-20 10:37:03 -07003216 );
3217 check_result_is_error_containing_string(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003218 db.create_key_entry(&Domain::KEY_ID, &104, &KEYSTORE_UUID),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003219 "Domain Domain(4) must be either App or SELinux.",
Joel Galenson0891bc12020-07-20 10:37:03 -07003220 );
3221
3222 Ok(())
3223 }
3224
Joel Galenson33c04ad2020-08-03 11:04:38 -07003225 #[test]
Max Bires2b2e6562020-09-22 11:22:36 -07003226 fn test_add_unsigned_key() -> Result<()> {
3227 let mut db = new_test_db()?;
3228 let public_key: Vec<u8> = vec![0x01, 0x02, 0x03];
3229 let private_key: Vec<u8> = vec![0x04, 0x05, 0x06];
3230 let raw_public_key: Vec<u8> = vec![0x07, 0x08, 0x09];
3231 db.create_attestation_key_entry(
3232 &public_key,
3233 &raw_public_key,
3234 &private_key,
3235 &KEYSTORE_UUID,
3236 )?;
3237 let keys = db.fetch_unsigned_attestation_keys(5, &KEYSTORE_UUID)?;
3238 assert_eq!(keys.len(), 1);
3239 assert_eq!(keys[0], public_key);
3240 Ok(())
3241 }
3242
3243 #[test]
3244 fn test_store_signed_attestation_certificate_chain() -> Result<()> {
3245 let mut db = new_test_db()?;
3246 let expiration_date: i64 = 20;
3247 let namespace: i64 = 30;
3248 let base_byte: u8 = 1;
3249 let loaded_values =
3250 load_attestation_key_pool(&mut db, expiration_date, namespace, base_byte)?;
3251 let chain =
3252 db.retrieve_attestation_key_and_cert_chain(Domain::APP, namespace, &KEYSTORE_UUID)?;
3253 assert_eq!(true, chain.is_some());
3254 let cert_chain = chain.unwrap();
Max Biresb2e1d032021-02-08 21:35:05 -08003255 assert_eq!(cert_chain.private_key.to_vec(), loaded_values.priv_key);
Max Bires97f96812021-02-23 23:44:57 -08003256 assert_eq!(cert_chain.batch_cert, loaded_values.batch_cert);
3257 assert_eq!(cert_chain.cert_chain, loaded_values.cert_chain);
Max Bires2b2e6562020-09-22 11:22:36 -07003258 Ok(())
3259 }
3260
3261 #[test]
3262 fn test_get_attestation_pool_status() -> Result<()> {
3263 let mut db = new_test_db()?;
3264 let namespace: i64 = 30;
3265 load_attestation_key_pool(
3266 &mut db, 10, /* expiration */
3267 namespace, 0x01, /* base_byte */
3268 )?;
3269 load_attestation_key_pool(&mut db, 20 /* expiration */, namespace + 1, 0x02)?;
3270 load_attestation_key_pool(&mut db, 40 /* expiration */, namespace + 2, 0x03)?;
3271 let mut status = db.get_attestation_pool_status(9 /* expiration */, &KEYSTORE_UUID)?;
3272 assert_eq!(status.expiring, 0);
3273 assert_eq!(status.attested, 3);
3274 assert_eq!(status.unassigned, 0);
3275 assert_eq!(status.total, 3);
3276 assert_eq!(
3277 db.get_attestation_pool_status(15 /* expiration */, &KEYSTORE_UUID)?.expiring,
3278 1
3279 );
3280 assert_eq!(
3281 db.get_attestation_pool_status(25 /* expiration */, &KEYSTORE_UUID)?.expiring,
3282 2
3283 );
3284 assert_eq!(
3285 db.get_attestation_pool_status(60 /* expiration */, &KEYSTORE_UUID)?.expiring,
3286 3
3287 );
3288 let public_key: Vec<u8> = vec![0x01, 0x02, 0x03];
3289 let private_key: Vec<u8> = vec![0x04, 0x05, 0x06];
3290 let raw_public_key: Vec<u8> = vec![0x07, 0x08, 0x09];
3291 let cert_chain: Vec<u8> = vec![0x0a, 0x0b, 0x0c];
Max Biresb2e1d032021-02-08 21:35:05 -08003292 let batch_cert: Vec<u8> = vec![0x0d, 0x0e, 0x0f];
Max Bires2b2e6562020-09-22 11:22:36 -07003293 db.create_attestation_key_entry(
3294 &public_key,
3295 &raw_public_key,
3296 &private_key,
3297 &KEYSTORE_UUID,
3298 )?;
3299 status = db.get_attestation_pool_status(0 /* expiration */, &KEYSTORE_UUID)?;
3300 assert_eq!(status.attested, 3);
3301 assert_eq!(status.unassigned, 0);
3302 assert_eq!(status.total, 4);
3303 db.store_signed_attestation_certificate_chain(
3304 &raw_public_key,
Max Biresb2e1d032021-02-08 21:35:05 -08003305 &batch_cert,
Max Bires2b2e6562020-09-22 11:22:36 -07003306 &cert_chain,
3307 20,
3308 &KEYSTORE_UUID,
3309 )?;
3310 status = db.get_attestation_pool_status(0 /* expiration */, &KEYSTORE_UUID)?;
3311 assert_eq!(status.attested, 4);
3312 assert_eq!(status.unassigned, 1);
3313 assert_eq!(status.total, 4);
3314 Ok(())
3315 }
3316
3317 #[test]
3318 fn test_remove_expired_certs() -> Result<()> {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003319 let temp_dir =
3320 TempDir::new("test_remove_expired_certs_").expect("Failed to create temp dir.");
3321 let mut db = new_test_db_with_gc(temp_dir.path(), |_, _| Ok(()))?;
Max Bires2b2e6562020-09-22 11:22:36 -07003322 let expiration_date: i64 =
3323 SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_millis() as i64 + 10000;
3324 let namespace: i64 = 30;
3325 let namespace_del1: i64 = 45;
3326 let namespace_del2: i64 = 60;
3327 let entry_values = load_attestation_key_pool(
3328 &mut db,
3329 expiration_date,
3330 namespace,
3331 0x01, /* base_byte */
3332 )?;
3333 load_attestation_key_pool(&mut db, 45, namespace_del1, 0x02)?;
3334 load_attestation_key_pool(&mut db, 60, namespace_del2, 0x03)?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003335
3336 let blob_entry_row_count: u32 = db
3337 .conn
3338 .query_row("SELECT COUNT(id) FROM persistent.blobentry;", NO_PARAMS, |row| row.get(0))
3339 .expect("Failed to get blob entry row count.");
Max Biresb2e1d032021-02-08 21:35:05 -08003340 // We expect 9 rows here because there are three blobs per attestation key, i.e.,
3341 // one key, one certificate chain, and one certificate.
3342 assert_eq!(blob_entry_row_count, 9);
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003343
Max Bires2b2e6562020-09-22 11:22:36 -07003344 assert_eq!(db.delete_expired_attestation_keys()?, 2);
3345
3346 let mut cert_chain =
3347 db.retrieve_attestation_key_and_cert_chain(Domain::APP, namespace, &KEYSTORE_UUID)?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003348 assert!(cert_chain.is_some());
Max Bires2b2e6562020-09-22 11:22:36 -07003349 let value = cert_chain.unwrap();
Max Bires97f96812021-02-23 23:44:57 -08003350 assert_eq!(entry_values.batch_cert, value.batch_cert);
3351 assert_eq!(entry_values.cert_chain, value.cert_chain);
Max Biresb2e1d032021-02-08 21:35:05 -08003352 assert_eq!(entry_values.priv_key, value.private_key.to_vec());
Max Bires2b2e6562020-09-22 11:22:36 -07003353
3354 cert_chain = db.retrieve_attestation_key_and_cert_chain(
3355 Domain::APP,
3356 namespace_del1,
3357 &KEYSTORE_UUID,
3358 )?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003359 assert!(!cert_chain.is_some());
Max Bires2b2e6562020-09-22 11:22:36 -07003360 cert_chain = db.retrieve_attestation_key_and_cert_chain(
3361 Domain::APP,
3362 namespace_del2,
3363 &KEYSTORE_UUID,
3364 )?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003365 assert!(!cert_chain.is_some());
Max Bires2b2e6562020-09-22 11:22:36 -07003366
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003367 // Give the garbage collector half a second to catch up.
3368 std::thread::sleep(Duration::from_millis(500));
Max Bires2b2e6562020-09-22 11:22:36 -07003369
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003370 let blob_entry_row_count: u32 = db
3371 .conn
3372 .query_row("SELECT COUNT(id) FROM persistent.blobentry;", NO_PARAMS, |row| row.get(0))
3373 .expect("Failed to get blob entry row count.");
Max Biresb2e1d032021-02-08 21:35:05 -08003374 // There shound be 3 blob entries left, because we deleted two of the attestation
3375 // key entries with three blobs each.
3376 assert_eq!(blob_entry_row_count, 3);
Max Bires2b2e6562020-09-22 11:22:36 -07003377
Max Bires2b2e6562020-09-22 11:22:36 -07003378 Ok(())
3379 }
3380
3381 #[test]
Max Bires60d7ed12021-03-05 15:59:22 -08003382 fn test_delete_all_attestation_keys() -> Result<()> {
3383 let mut db = new_test_db()?;
3384 load_attestation_key_pool(&mut db, 45 /* expiration */, 1 /* namespace */, 0x02)?;
3385 load_attestation_key_pool(&mut db, 80 /* expiration */, 2 /* namespace */, 0x03)?;
3386 db.create_key_entry(&Domain::APP, &42, &KEYSTORE_UUID)?;
3387 let result = db.delete_all_attestation_keys()?;
3388
3389 // Give the garbage collector half a second to catch up.
3390 std::thread::sleep(Duration::from_millis(500));
3391
3392 // Attestation keys should be deleted, and the regular key should remain.
3393 assert_eq!(result, 2);
3394
3395 Ok(())
3396 }
3397
3398 #[test]
Joel Galenson33c04ad2020-08-03 11:04:38 -07003399 fn test_rebind_alias() -> Result<()> {
Max Bires8e93d2b2021-01-14 13:17:59 -08003400 fn extractor(
3401 ke: &KeyEntryRow,
3402 ) -> (Option<Domain>, Option<i64>, Option<&str>, Option<Uuid>) {
3403 (ke.domain, ke.namespace, ke.alias.as_deref(), ke.km_uuid)
Joel Galenson33c04ad2020-08-03 11:04:38 -07003404 }
3405
Janis Danisevskis4df44f42020-08-26 14:40:03 -07003406 let mut db = new_test_db()?;
Janis Danisevskis66784c42021-01-27 08:40:25 -08003407 db.create_key_entry(&Domain::APP, &42, &KEYSTORE_UUID)?;
3408 db.create_key_entry(&Domain::APP, &42, &KEYSTORE_UUID)?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07003409 let entries = get_keyentry(&db)?;
3410 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08003411 assert_eq!(
3412 extractor(&entries[0]),
3413 (Some(Domain::APP), Some(42), None, Some(KEYSTORE_UUID))
3414 );
3415 assert_eq!(
3416 extractor(&entries[1]),
3417 (Some(Domain::APP), Some(42), None, Some(KEYSTORE_UUID))
3418 );
Joel Galenson33c04ad2020-08-03 11:04:38 -07003419
3420 // Test that the first call to rebind_alias sets the alias.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003421 rebind_alias(&mut db, &KEY_ID_LOCK.get(entries[0].id), "foo", Domain::APP, 42)?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07003422 let entries = get_keyentry(&db)?;
3423 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08003424 assert_eq!(
3425 extractor(&entries[0]),
3426 (Some(Domain::APP), Some(42), Some("foo"), Some(KEYSTORE_UUID))
3427 );
3428 assert_eq!(
3429 extractor(&entries[1]),
3430 (Some(Domain::APP), Some(42), None, Some(KEYSTORE_UUID))
3431 );
Joel Galenson33c04ad2020-08-03 11:04:38 -07003432
3433 // Test that the second call to rebind_alias also empties the old one.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003434 rebind_alias(&mut db, &KEY_ID_LOCK.get(entries[1].id), "foo", Domain::APP, 42)?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07003435 let entries = get_keyentry(&db)?;
3436 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08003437 assert_eq!(extractor(&entries[0]), (None, None, None, Some(KEYSTORE_UUID)));
3438 assert_eq!(
3439 extractor(&entries[1]),
3440 (Some(Domain::APP), Some(42), Some("foo"), Some(KEYSTORE_UUID))
3441 );
Joel Galenson33c04ad2020-08-03 11:04:38 -07003442
3443 // Test that we must pass in a valid Domain.
3444 check_result_is_error_containing_string(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003445 rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::GRANT, 42),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003446 "Domain Domain(1) must be either App or SELinux.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07003447 );
3448 check_result_is_error_containing_string(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003449 rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::BLOB, 42),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003450 "Domain Domain(3) must be either App or SELinux.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07003451 );
3452 check_result_is_error_containing_string(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003453 rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::KEY_ID, 42),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003454 "Domain Domain(4) must be either App or SELinux.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07003455 );
3456
3457 // Test that we correctly handle setting an alias for something that does not exist.
3458 check_result_is_error_containing_string(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003459 rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::SELINUX, 42),
Joel Galenson33c04ad2020-08-03 11:04:38 -07003460 "Expected to update a single entry but instead updated 0",
3461 );
3462 // Test that we correctly abort the transaction in this case.
3463 let entries = get_keyentry(&db)?;
3464 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08003465 assert_eq!(extractor(&entries[0]), (None, None, None, Some(KEYSTORE_UUID)));
3466 assert_eq!(
3467 extractor(&entries[1]),
3468 (Some(Domain::APP), Some(42), Some("foo"), Some(KEYSTORE_UUID))
3469 );
Joel Galenson33c04ad2020-08-03 11:04:38 -07003470
3471 Ok(())
3472 }
3473
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003474 #[test]
3475 fn test_grant_ungrant() -> Result<()> {
3476 const CALLER_UID: u32 = 15;
3477 const GRANTEE_UID: u32 = 12;
3478 const SELINUX_NAMESPACE: i64 = 7;
3479
3480 let mut db = new_test_db()?;
3481 db.conn.execute(
Max Bires8e93d2b2021-01-14 13:17:59 -08003482 "INSERT INTO persistent.keyentry (id, key_type, domain, namespace, alias, state, km_uuid)
3483 VALUES (1, 0, 0, 15, 'key', 1, ?), (2, 0, 2, 7, 'yek', 1, ?);",
3484 params![KEYSTORE_UUID, KEYSTORE_UUID],
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003485 )?;
3486 let app_key = KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003487 domain: super::Domain::APP,
3488 nspace: 0,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003489 alias: Some("key".to_string()),
3490 blob: None,
3491 };
3492 const PVEC1: KeyPermSet = key_perm_set![KeyPerm::use_(), KeyPerm::get_info()];
3493 const PVEC2: KeyPermSet = key_perm_set![KeyPerm::use_()];
3494
3495 // Reset totally predictable random number generator in case we
3496 // are not the first test running on this thread.
3497 reset_random();
3498 let next_random = 0i64;
3499
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003500 let app_granted_key = db
Janis Danisevskis66784c42021-01-27 08:40:25 -08003501 .grant(&app_key, CALLER_UID, GRANTEE_UID, PVEC1, |k, a| {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003502 assert_eq!(*a, PVEC1);
3503 assert_eq!(
3504 *k,
3505 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003506 domain: super::Domain::APP,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003507 // namespace must be set to the caller_uid.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003508 nspace: CALLER_UID as i64,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003509 alias: Some("key".to_string()),
3510 blob: None,
3511 }
3512 );
3513 Ok(())
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003514 })
3515 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003516
3517 assert_eq!(
3518 app_granted_key,
3519 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003520 domain: super::Domain::GRANT,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003521 // The grantid is next_random due to the mock random number generator.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003522 nspace: next_random,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003523 alias: None,
3524 blob: None,
3525 }
3526 );
3527
3528 let selinux_key = KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003529 domain: super::Domain::SELINUX,
3530 nspace: SELINUX_NAMESPACE,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003531 alias: Some("yek".to_string()),
3532 blob: None,
3533 };
3534
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003535 let selinux_granted_key = db
Janis Danisevskis66784c42021-01-27 08:40:25 -08003536 .grant(&selinux_key, CALLER_UID, 12, PVEC1, |k, a| {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003537 assert_eq!(*a, PVEC1);
3538 assert_eq!(
3539 *k,
3540 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003541 domain: super::Domain::SELINUX,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003542 // namespace must be the supplied SELinux
3543 // namespace.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003544 nspace: SELINUX_NAMESPACE,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003545 alias: Some("yek".to_string()),
3546 blob: None,
3547 }
3548 );
3549 Ok(())
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003550 })
3551 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003552
3553 assert_eq!(
3554 selinux_granted_key,
3555 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003556 domain: super::Domain::GRANT,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003557 // The grantid is next_random + 1 due to the mock random number generator.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003558 nspace: next_random + 1,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003559 alias: None,
3560 blob: None,
3561 }
3562 );
3563
3564 // This should update the existing grant with PVEC2.
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003565 let selinux_granted_key = db
Janis Danisevskis66784c42021-01-27 08:40:25 -08003566 .grant(&selinux_key, CALLER_UID, 12, PVEC2, |k, a| {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003567 assert_eq!(*a, PVEC2);
3568 assert_eq!(
3569 *k,
3570 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003571 domain: super::Domain::SELINUX,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003572 // namespace must be the supplied SELinux
3573 // namespace.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003574 nspace: SELINUX_NAMESPACE,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003575 alias: Some("yek".to_string()),
3576 blob: None,
3577 }
3578 );
3579 Ok(())
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003580 })
3581 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003582
3583 assert_eq!(
3584 selinux_granted_key,
3585 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003586 domain: super::Domain::GRANT,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003587 // Same grant id as before. The entry was only updated.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003588 nspace: next_random + 1,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003589 alias: None,
3590 blob: None,
3591 }
3592 );
3593
3594 {
3595 // Limiting scope of stmt, because it borrows db.
3596 let mut stmt = db
3597 .conn
Janis Danisevskisbf15d732020-12-08 10:35:26 -08003598 .prepare("SELECT id, grantee, keyentryid, access_vector FROM persistent.grant;")?;
Janis Danisevskisee10b5f2020-09-22 16:42:35 -07003599 let mut rows =
3600 stmt.query_map::<(i64, u32, i64, KeyPermSet), _, _>(NO_PARAMS, |row| {
3601 Ok((
3602 row.get(0)?,
3603 row.get(1)?,
3604 row.get(2)?,
3605 KeyPermSet::from(row.get::<_, i32>(3)?),
3606 ))
3607 })?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003608
3609 let r = rows.next().unwrap().unwrap();
Janis Danisevskisee10b5f2020-09-22 16:42:35 -07003610 assert_eq!(r, (next_random, GRANTEE_UID, 1, PVEC1));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003611 let r = rows.next().unwrap().unwrap();
Janis Danisevskisee10b5f2020-09-22 16:42:35 -07003612 assert_eq!(r, (next_random + 1, GRANTEE_UID, 2, PVEC2));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003613 assert!(rows.next().is_none());
3614 }
3615
3616 debug_dump_keyentry_table(&mut db)?;
3617 println!("app_key {:?}", app_key);
3618 println!("selinux_key {:?}", selinux_key);
3619
Janis Danisevskis66784c42021-01-27 08:40:25 -08003620 db.ungrant(&app_key, CALLER_UID, GRANTEE_UID, |_| Ok(()))?;
3621 db.ungrant(&selinux_key, CALLER_UID, GRANTEE_UID, |_| Ok(()))?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003622
3623 Ok(())
3624 }
3625
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003626 static TEST_KEY_BLOB: &[u8] = b"my test blob";
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003627 static TEST_CERT_BLOB: &[u8] = b"my test cert";
3628 static TEST_CERT_CHAIN_BLOB: &[u8] = b"my test cert_chain";
3629
3630 #[test]
Janis Danisevskis377d1002021-01-27 19:07:48 -08003631 fn test_set_blob() -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003632 let key_id = KEY_ID_LOCK.get(3000);
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003633 let mut db = new_test_db()?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003634 let mut blob_metadata = BlobMetaData::new();
3635 blob_metadata.add(BlobMetaEntry::KmUuid(KEYSTORE_UUID));
3636 db.set_blob(
3637 &key_id,
3638 SubComponentType::KEY_BLOB,
3639 Some(TEST_KEY_BLOB),
3640 Some(&blob_metadata),
3641 )?;
3642 db.set_blob(&key_id, SubComponentType::CERT, Some(TEST_CERT_BLOB), None)?;
3643 db.set_blob(&key_id, SubComponentType::CERT_CHAIN, Some(TEST_CERT_CHAIN_BLOB), None)?;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003644 drop(key_id);
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003645
3646 let mut stmt = db.conn.prepare(
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003647 "SELECT subcomponent_type, keyentryid, blob, id FROM persistent.blobentry
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003648 ORDER BY subcomponent_type ASC;",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003649 )?;
3650 let mut rows = stmt
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003651 .query_map::<((SubComponentType, i64, Vec<u8>), i64), _, _>(NO_PARAMS, |row| {
3652 Ok(((row.get(0)?, row.get(1)?, row.get(2)?), row.get(3)?))
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003653 })?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003654 let (r, id) = rows.next().unwrap().unwrap();
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003655 assert_eq!(r, (SubComponentType::KEY_BLOB, 3000, TEST_KEY_BLOB.to_vec()));
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003656 let (r, _) = rows.next().unwrap().unwrap();
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003657 assert_eq!(r, (SubComponentType::CERT, 3000, TEST_CERT_BLOB.to_vec()));
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003658 let (r, _) = rows.next().unwrap().unwrap();
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003659 assert_eq!(r, (SubComponentType::CERT_CHAIN, 3000, TEST_CERT_CHAIN_BLOB.to_vec()));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003660
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003661 drop(rows);
3662 drop(stmt);
3663
3664 assert_eq!(
3665 db.with_transaction(TransactionBehavior::Immediate, |tx| {
3666 BlobMetaData::load_from_db(id, tx).no_gc()
3667 })
3668 .expect("Should find blob metadata."),
3669 blob_metadata
3670 );
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003671 Ok(())
3672 }
3673
3674 static TEST_ALIAS: &str = "my super duper key";
3675
3676 #[test]
3677 fn test_insert_and_load_full_keyentry_domain_app() -> Result<()> {
3678 let mut db = new_test_db()?;
Qi Wub9433b52020-12-01 14:52:46 +08003679 let key_id = make_test_key_entry(&mut db, Domain::APP, 1, TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08003680 .context("test_insert_and_load_full_keyentry_domain_app")?
3681 .0;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003682 let (_key_guard, key_entry) = db
3683 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003684 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003685 domain: Domain::APP,
3686 nspace: 0,
3687 alias: Some(TEST_ALIAS.to_string()),
3688 blob: None,
3689 },
3690 KeyType::Client,
3691 KeyEntryLoadBits::BOTH,
3692 1,
3693 |_k, _av| Ok(()),
3694 )
3695 .unwrap();
Qi Wub9433b52020-12-01 14:52:46 +08003696 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003697
3698 db.unbind_key(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003699 &KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003700 domain: Domain::APP,
3701 nspace: 0,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003702 alias: Some(TEST_ALIAS.to_string()),
3703 blob: None,
3704 },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003705 KeyType::Client,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003706 1,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003707 |_, _| Ok(()),
3708 )
3709 .unwrap();
3710
3711 assert_eq!(
3712 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
3713 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003714 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003715 domain: Domain::APP,
3716 nspace: 0,
3717 alias: Some(TEST_ALIAS.to_string()),
3718 blob: None,
3719 },
3720 KeyType::Client,
3721 KeyEntryLoadBits::NONE,
3722 1,
3723 |_k, _av| Ok(()),
3724 )
3725 .unwrap_err()
3726 .root_cause()
3727 .downcast_ref::<KsError>()
3728 );
3729
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003730 Ok(())
3731 }
3732
3733 #[test]
Janis Danisevskis377d1002021-01-27 19:07:48 -08003734 fn test_insert_and_load_certificate_entry_domain_app() -> Result<()> {
3735 let mut db = new_test_db()?;
3736
3737 db.store_new_certificate(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003738 &KeyDescriptor {
Janis Danisevskis377d1002021-01-27 19:07:48 -08003739 domain: Domain::APP,
3740 nspace: 1,
3741 alias: Some(TEST_ALIAS.to_string()),
3742 blob: None,
3743 },
3744 TEST_CERT_BLOB,
Max Bires8e93d2b2021-01-14 13:17:59 -08003745 &KEYSTORE_UUID,
Janis Danisevskis377d1002021-01-27 19:07:48 -08003746 )
3747 .expect("Trying to insert cert.");
3748
3749 let (_key_guard, mut key_entry) = db
3750 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003751 &KeyDescriptor {
Janis Danisevskis377d1002021-01-27 19:07:48 -08003752 domain: Domain::APP,
3753 nspace: 1,
3754 alias: Some(TEST_ALIAS.to_string()),
3755 blob: None,
3756 },
3757 KeyType::Client,
3758 KeyEntryLoadBits::PUBLIC,
3759 1,
3760 |_k, _av| Ok(()),
3761 )
3762 .expect("Trying to read certificate entry.");
3763
3764 assert!(key_entry.pure_cert());
3765 assert!(key_entry.cert().is_none());
3766 assert_eq!(key_entry.take_cert_chain(), Some(TEST_CERT_BLOB.to_vec()));
3767
3768 db.unbind_key(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003769 &KeyDescriptor {
Janis Danisevskis377d1002021-01-27 19:07:48 -08003770 domain: Domain::APP,
3771 nspace: 1,
3772 alias: Some(TEST_ALIAS.to_string()),
3773 blob: None,
3774 },
3775 KeyType::Client,
3776 1,
3777 |_, _| Ok(()),
3778 )
3779 .unwrap();
3780
3781 assert_eq!(
3782 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
3783 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003784 &KeyDescriptor {
Janis Danisevskis377d1002021-01-27 19:07:48 -08003785 domain: Domain::APP,
3786 nspace: 1,
3787 alias: Some(TEST_ALIAS.to_string()),
3788 blob: None,
3789 },
3790 KeyType::Client,
3791 KeyEntryLoadBits::NONE,
3792 1,
3793 |_k, _av| Ok(()),
3794 )
3795 .unwrap_err()
3796 .root_cause()
3797 .downcast_ref::<KsError>()
3798 );
3799
3800 Ok(())
3801 }
3802
3803 #[test]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003804 fn test_insert_and_load_full_keyentry_domain_selinux() -> Result<()> {
3805 let mut db = new_test_db()?;
Qi Wub9433b52020-12-01 14:52:46 +08003806 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08003807 .context("test_insert_and_load_full_keyentry_domain_selinux")?
3808 .0;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003809 let (_key_guard, key_entry) = db
3810 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003811 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003812 domain: Domain::SELINUX,
3813 nspace: 1,
3814 alias: Some(TEST_ALIAS.to_string()),
3815 blob: None,
3816 },
3817 KeyType::Client,
3818 KeyEntryLoadBits::BOTH,
3819 1,
3820 |_k, _av| Ok(()),
3821 )
3822 .unwrap();
Qi Wub9433b52020-12-01 14:52:46 +08003823 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003824
3825 db.unbind_key(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003826 &KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003827 domain: Domain::SELINUX,
3828 nspace: 1,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003829 alias: Some(TEST_ALIAS.to_string()),
3830 blob: None,
3831 },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003832 KeyType::Client,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003833 1,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003834 |_, _| Ok(()),
3835 )
3836 .unwrap();
3837
3838 assert_eq!(
3839 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
3840 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003841 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003842 domain: Domain::SELINUX,
3843 nspace: 1,
3844 alias: Some(TEST_ALIAS.to_string()),
3845 blob: None,
3846 },
3847 KeyType::Client,
3848 KeyEntryLoadBits::NONE,
3849 1,
3850 |_k, _av| Ok(()),
3851 )
3852 .unwrap_err()
3853 .root_cause()
3854 .downcast_ref::<KsError>()
3855 );
3856
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003857 Ok(())
3858 }
3859
3860 #[test]
3861 fn test_insert_and_load_full_keyentry_domain_key_id() -> Result<()> {
3862 let mut db = new_test_db()?;
Qi Wub9433b52020-12-01 14:52:46 +08003863 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08003864 .context("test_insert_and_load_full_keyentry_domain_key_id")?
3865 .0;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003866 let (_, key_entry) = db
3867 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003868 &KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003869 KeyType::Client,
3870 KeyEntryLoadBits::BOTH,
3871 1,
3872 |_k, _av| Ok(()),
3873 )
3874 .unwrap();
3875
Qi Wub9433b52020-12-01 14:52:46 +08003876 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003877
3878 db.unbind_key(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003879 &KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003880 KeyType::Client,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003881 1,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003882 |_, _| Ok(()),
3883 )
3884 .unwrap();
3885
3886 assert_eq!(
3887 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
3888 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003889 &KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003890 KeyType::Client,
3891 KeyEntryLoadBits::NONE,
3892 1,
3893 |_k, _av| Ok(()),
3894 )
3895 .unwrap_err()
3896 .root_cause()
3897 .downcast_ref::<KsError>()
3898 );
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003899
3900 Ok(())
3901 }
3902
3903 #[test]
Qi Wub9433b52020-12-01 14:52:46 +08003904 fn test_check_and_update_key_usage_count_with_limited_use_key() -> Result<()> {
3905 let mut db = new_test_db()?;
3906 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, Some(123))
3907 .context("test_check_and_update_key_usage_count_with_limited_use_key")?
3908 .0;
3909 // Update the usage count of the limited use key.
3910 db.check_and_update_key_usage_count(key_id)?;
3911
3912 let (_key_guard, key_entry) = db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003913 &KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
Qi Wub9433b52020-12-01 14:52:46 +08003914 KeyType::Client,
3915 KeyEntryLoadBits::BOTH,
3916 1,
3917 |_k, _av| Ok(()),
3918 )?;
3919
3920 // The usage count is decremented now.
3921 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, Some(122)));
3922
3923 Ok(())
3924 }
3925
3926 #[test]
3927 fn test_check_and_update_key_usage_count_with_exhausted_limited_use_key() -> Result<()> {
3928 let mut db = new_test_db()?;
3929 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, Some(1))
3930 .context("test_check_and_update_key_usage_count_with_exhausted_limited_use_key")?
3931 .0;
3932 // Update the usage count of the limited use key.
3933 db.check_and_update_key_usage_count(key_id).expect(concat!(
3934 "In test_check_and_update_key_usage_count_with_exhausted_limited_use_key: ",
3935 "This should succeed."
3936 ));
3937
3938 // Try to update the exhausted limited use key.
3939 let e = db.check_and_update_key_usage_count(key_id).expect_err(concat!(
3940 "In test_check_and_update_key_usage_count_with_exhausted_limited_use_key: ",
3941 "This should fail."
3942 ));
3943 assert_eq!(
3944 &KsError::Km(ErrorCode::INVALID_KEY_BLOB),
3945 e.root_cause().downcast_ref::<KsError>().unwrap()
3946 );
3947
3948 Ok(())
3949 }
3950
3951 #[test]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003952 fn test_insert_and_load_full_keyentry_from_grant() -> Result<()> {
3953 let mut db = new_test_db()?;
Qi Wub9433b52020-12-01 14:52:46 +08003954 let key_id = make_test_key_entry(&mut db, Domain::APP, 1, TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08003955 .context("test_insert_and_load_full_keyentry_from_grant")?
3956 .0;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003957
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003958 let granted_key = db
3959 .grant(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003960 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003961 domain: Domain::APP,
3962 nspace: 0,
3963 alias: Some(TEST_ALIAS.to_string()),
3964 blob: None,
3965 },
3966 1,
3967 2,
3968 key_perm_set![KeyPerm::use_()],
3969 |_k, _av| Ok(()),
3970 )
3971 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003972
3973 debug_dump_grant_table(&mut db)?;
3974
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003975 let (_key_guard, key_entry) = db
Janis Danisevskis66784c42021-01-27 08:40:25 -08003976 .load_key_entry(&granted_key, KeyType::Client, KeyEntryLoadBits::BOTH, 2, |k, av| {
3977 assert_eq!(Domain::GRANT, k.domain);
3978 assert!(av.unwrap().includes(KeyPerm::use_()));
3979 Ok(())
3980 })
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003981 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003982
Qi Wub9433b52020-12-01 14:52:46 +08003983 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003984
Janis Danisevskis66784c42021-01-27 08:40:25 -08003985 db.unbind_key(&granted_key, KeyType::Client, 2, |_, _| Ok(())).unwrap();
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003986
3987 assert_eq!(
3988 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
3989 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003990 &granted_key,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003991 KeyType::Client,
3992 KeyEntryLoadBits::NONE,
3993 2,
3994 |_k, _av| Ok(()),
3995 )
3996 .unwrap_err()
3997 .root_cause()
3998 .downcast_ref::<KsError>()
3999 );
4000
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004001 Ok(())
4002 }
4003
Janis Danisevskis45760022021-01-19 16:34:10 -08004004 // This test attempts to load a key by key id while the caller is not the owner
4005 // but a grant exists for the given key and the caller.
4006 #[test]
4007 fn test_insert_and_load_full_keyentry_from_grant_by_key_id() -> Result<()> {
4008 let mut db = new_test_db()?;
4009 const OWNER_UID: u32 = 1u32;
4010 const GRANTEE_UID: u32 = 2u32;
4011 const SOMEONE_ELSE_UID: u32 = 3u32;
4012 let key_id = make_test_key_entry(&mut db, Domain::APP, OWNER_UID as i64, TEST_ALIAS, None)
4013 .context("test_insert_and_load_full_keyentry_from_grant_by_key_id")?
4014 .0;
4015
4016 db.grant(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004017 &KeyDescriptor {
Janis Danisevskis45760022021-01-19 16:34:10 -08004018 domain: Domain::APP,
4019 nspace: 0,
4020 alias: Some(TEST_ALIAS.to_string()),
4021 blob: None,
4022 },
4023 OWNER_UID,
4024 GRANTEE_UID,
4025 key_perm_set![KeyPerm::use_()],
4026 |_k, _av| Ok(()),
4027 )
4028 .unwrap();
4029
4030 debug_dump_grant_table(&mut db)?;
4031
4032 let id_descriptor =
4033 KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, ..Default::default() };
4034
4035 let (_, key_entry) = db
4036 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004037 &id_descriptor,
Janis Danisevskis45760022021-01-19 16:34:10 -08004038 KeyType::Client,
4039 KeyEntryLoadBits::BOTH,
4040 GRANTEE_UID,
4041 |k, av| {
4042 assert_eq!(Domain::APP, k.domain);
4043 assert_eq!(OWNER_UID as i64, k.nspace);
4044 assert!(av.unwrap().includes(KeyPerm::use_()));
4045 Ok(())
4046 },
4047 )
4048 .unwrap();
4049
4050 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
4051
4052 let (_, key_entry) = db
4053 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004054 &id_descriptor,
Janis Danisevskis45760022021-01-19 16:34:10 -08004055 KeyType::Client,
4056 KeyEntryLoadBits::BOTH,
4057 SOMEONE_ELSE_UID,
4058 |k, av| {
4059 assert_eq!(Domain::APP, k.domain);
4060 assert_eq!(OWNER_UID as i64, k.nspace);
4061 assert!(av.is_none());
4062 Ok(())
4063 },
4064 )
4065 .unwrap();
4066
4067 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
4068
Janis Danisevskis66784c42021-01-27 08:40:25 -08004069 db.unbind_key(&id_descriptor, KeyType::Client, OWNER_UID, |_, _| Ok(())).unwrap();
Janis Danisevskis45760022021-01-19 16:34:10 -08004070
4071 assert_eq!(
4072 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
4073 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004074 &id_descriptor,
Janis Danisevskis45760022021-01-19 16:34:10 -08004075 KeyType::Client,
4076 KeyEntryLoadBits::NONE,
4077 GRANTEE_UID,
4078 |_k, _av| Ok(()),
4079 )
4080 .unwrap_err()
4081 .root_cause()
4082 .downcast_ref::<KsError>()
4083 );
4084
4085 Ok(())
4086 }
4087
Janis Danisevskisaec14592020-11-12 09:41:49 -08004088 static KEY_LOCK_TEST_ALIAS: &str = "my super duper locked key";
4089
Janis Danisevskisaec14592020-11-12 09:41:49 -08004090 #[test]
4091 fn test_insert_and_load_full_keyentry_domain_app_concurrently() -> Result<()> {
4092 let handle = {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08004093 let temp_dir = Arc::new(TempDir::new("id_lock_test")?);
4094 let temp_dir_clone = temp_dir.clone();
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004095 let mut db = KeystoreDB::new(temp_dir.path(), None)?;
Qi Wub9433b52020-12-01 14:52:46 +08004096 let key_id = make_test_key_entry(&mut db, Domain::APP, 33, KEY_LOCK_TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08004097 .context("test_insert_and_load_full_keyentry_domain_app")?
4098 .0;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004099 let (_key_guard, key_entry) = db
4100 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004101 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004102 domain: Domain::APP,
4103 nspace: 0,
4104 alias: Some(KEY_LOCK_TEST_ALIAS.to_string()),
4105 blob: None,
4106 },
4107 KeyType::Client,
4108 KeyEntryLoadBits::BOTH,
4109 33,
4110 |_k, _av| Ok(()),
4111 )
4112 .unwrap();
Qi Wub9433b52020-12-01 14:52:46 +08004113 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskisaec14592020-11-12 09:41:49 -08004114 let state = Arc::new(AtomicU8::new(1));
4115 let state2 = state.clone();
4116
4117 // Spawning a second thread that attempts to acquire the key id lock
4118 // for the same key as the primary thread. The primary thread then
4119 // waits, thereby forcing the secondary thread into the second stage
4120 // of acquiring the lock (see KEY ID LOCK 2/2 above).
4121 // The test succeeds if the secondary thread observes the transition
4122 // of `state` from 1 to 2, despite having a whole second to overtake
4123 // the primary thread.
4124 let handle = thread::spawn(move || {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08004125 let temp_dir = temp_dir_clone;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004126 let mut db = KeystoreDB::new(temp_dir.path(), None).unwrap();
Janis Danisevskisaec14592020-11-12 09:41:49 -08004127 assert!(db
4128 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004129 &KeyDescriptor {
Janis Danisevskisaec14592020-11-12 09:41:49 -08004130 domain: Domain::APP,
4131 nspace: 0,
4132 alias: Some(KEY_LOCK_TEST_ALIAS.to_string()),
4133 blob: None,
4134 },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004135 KeyType::Client,
Janis Danisevskisaec14592020-11-12 09:41:49 -08004136 KeyEntryLoadBits::BOTH,
4137 33,
4138 |_k, _av| Ok(()),
4139 )
4140 .is_ok());
4141 // We should only see a 2 here because we can only return
4142 // from load_key_entry when the `_key_guard` expires,
4143 // which happens at the end of the scope.
4144 assert_eq!(2, state2.load(Ordering::Relaxed));
4145 });
4146
4147 thread::sleep(std::time::Duration::from_millis(1000));
4148
4149 assert_eq!(Ok(1), state.compare_exchange(1, 2, Ordering::Relaxed, Ordering::Relaxed));
4150
4151 // Return the handle from this scope so we can join with the
4152 // secondary thread after the key id lock has expired.
4153 handle
4154 // This is where the `_key_guard` goes out of scope,
4155 // which is the reason for concurrent load_key_entry on the same key
4156 // to unblock.
4157 };
4158 // Join with the secondary thread and unwrap, to propagate failing asserts to the
4159 // main test thread. We will not see failing asserts in secondary threads otherwise.
4160 handle.join().unwrap();
4161 Ok(())
4162 }
4163
Janis Danisevskise92a5e62020-12-02 12:57:41 -08004164 #[test]
Janis Danisevskis66784c42021-01-27 08:40:25 -08004165 fn teset_database_busy_error_code() {
4166 let temp_dir =
4167 TempDir::new("test_database_busy_error_code_").expect("Failed to create temp dir.");
4168
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004169 let mut db1 = KeystoreDB::new(temp_dir.path(), None).expect("Failed to open database1.");
4170 let mut db2 = KeystoreDB::new(temp_dir.path(), None).expect("Failed to open database2.");
Janis Danisevskis66784c42021-01-27 08:40:25 -08004171
4172 let _tx1 = db1
4173 .conn
4174 .transaction_with_behavior(TransactionBehavior::Immediate)
4175 .expect("Failed to create first transaction.");
4176
4177 let error = db2
4178 .conn
4179 .transaction_with_behavior(TransactionBehavior::Immediate)
4180 .context("Transaction begin failed.")
4181 .expect_err("This should fail.");
4182 let root_cause = error.root_cause();
4183 if let Some(rusqlite::ffi::Error { code: rusqlite::ErrorCode::DatabaseBusy, .. }) =
4184 root_cause.downcast_ref::<rusqlite::ffi::Error>()
4185 {
4186 return;
4187 }
4188 panic!(
4189 "Unexpected error {:?} \n{:?} \n{:?}",
4190 error,
4191 root_cause,
4192 root_cause.downcast_ref::<rusqlite::ffi::Error>()
4193 )
4194 }
4195
4196 #[cfg(disabled)]
4197 #[test]
4198 fn test_large_number_of_concurrent_db_manipulations() -> Result<()> {
4199 let temp_dir = Arc::new(
4200 TempDir::new("test_large_number_of_concurrent_db_manipulations_")
4201 .expect("Failed to create temp dir."),
4202 );
4203
4204 let test_begin = Instant::now();
4205
4206 let mut db = KeystoreDB::new(temp_dir.path()).expect("Failed to open database.");
4207 const KEY_COUNT: u32 = 500u32;
4208 const OPEN_DB_COUNT: u32 = 50u32;
4209
4210 let mut actual_key_count = KEY_COUNT;
4211 // First insert KEY_COUNT keys.
4212 for count in 0..KEY_COUNT {
4213 if Instant::now().duration_since(test_begin) >= Duration::from_secs(15) {
4214 actual_key_count = count;
4215 break;
4216 }
4217 let alias = format!("test_alias_{}", count);
4218 make_test_key_entry(&mut db, Domain::APP, 1, &alias, None)
4219 .expect("Failed to make key entry.");
4220 }
4221
4222 // Insert more keys from a different thread and into a different namespace.
4223 let temp_dir1 = temp_dir.clone();
4224 let handle1 = thread::spawn(move || {
4225 let mut db = KeystoreDB::new(temp_dir1.path()).expect("Failed to open database.");
4226
4227 for count in 0..actual_key_count {
4228 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
4229 return;
4230 }
4231 let alias = format!("test_alias_{}", count);
4232 make_test_key_entry(&mut db, Domain::APP, 2, &alias, None)
4233 .expect("Failed to make key entry.");
4234 }
4235
4236 // then unbind them again.
4237 for count in 0..actual_key_count {
4238 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
4239 return;
4240 }
4241 let key = KeyDescriptor {
4242 domain: Domain::APP,
4243 nspace: -1,
4244 alias: Some(format!("test_alias_{}", count)),
4245 blob: None,
4246 };
4247 db.unbind_key(&key, KeyType::Client, 2, |_, _| Ok(())).expect("Unbind Failed.");
4248 }
4249 });
4250
4251 // And start unbinding the first set of keys.
4252 let temp_dir2 = temp_dir.clone();
4253 let handle2 = thread::spawn(move || {
4254 let mut db = KeystoreDB::new(temp_dir2.path()).expect("Failed to open database.");
4255
4256 for count in 0..actual_key_count {
4257 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
4258 return;
4259 }
4260 let key = KeyDescriptor {
4261 domain: Domain::APP,
4262 nspace: -1,
4263 alias: Some(format!("test_alias_{}", count)),
4264 blob: None,
4265 };
4266 db.unbind_key(&key, KeyType::Client, 1, |_, _| Ok(())).expect("Unbind Failed.");
4267 }
4268 });
4269
4270 let stop_deleting = Arc::new(AtomicU8::new(0));
4271 let stop_deleting2 = stop_deleting.clone();
4272
4273 // And delete anything that is unreferenced keys.
4274 let temp_dir3 = temp_dir.clone();
4275 let handle3 = thread::spawn(move || {
4276 let mut db = KeystoreDB::new(temp_dir3.path()).expect("Failed to open database.");
4277
4278 while stop_deleting2.load(Ordering::Relaxed) != 1 {
4279 while let Some((key_guard, _key)) =
4280 db.get_unreferenced_key().expect("Failed to get unreferenced Key.")
4281 {
4282 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
4283 return;
4284 }
4285 db.purge_key_entry(key_guard).expect("Failed to purge key.");
4286 }
4287 std::thread::sleep(std::time::Duration::from_millis(100));
4288 }
4289 });
4290
4291 // While a lot of inserting and deleting is going on we have to open database connections
4292 // successfully and use them.
4293 // This clone is not redundant, because temp_dir needs to be kept alive until db goes
4294 // out of scope.
4295 #[allow(clippy::redundant_clone)]
4296 let temp_dir4 = temp_dir.clone();
4297 let handle4 = thread::spawn(move || {
4298 for count in 0..OPEN_DB_COUNT {
4299 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
4300 return;
4301 }
4302 let mut db = KeystoreDB::new(temp_dir4.path()).expect("Failed to open database.");
4303
4304 let alias = format!("test_alias_{}", count);
4305 make_test_key_entry(&mut db, Domain::APP, 3, &alias, None)
4306 .expect("Failed to make key entry.");
4307 let key = KeyDescriptor {
4308 domain: Domain::APP,
4309 nspace: -1,
4310 alias: Some(alias),
4311 blob: None,
4312 };
4313 db.unbind_key(&key, KeyType::Client, 3, |_, _| Ok(())).expect("Unbind Failed.");
4314 }
4315 });
4316
4317 handle1.join().expect("Thread 1 panicked.");
4318 handle2.join().expect("Thread 2 panicked.");
4319 handle4.join().expect("Thread 4 panicked.");
4320
4321 stop_deleting.store(1, Ordering::Relaxed);
4322 handle3.join().expect("Thread 3 panicked.");
4323
4324 Ok(())
4325 }
4326
4327 #[test]
Janis Danisevskise92a5e62020-12-02 12:57:41 -08004328 fn list() -> Result<()> {
4329 let temp_dir = TempDir::new("list_test")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004330 let mut db = KeystoreDB::new(temp_dir.path(), None)?;
Janis Danisevskise92a5e62020-12-02 12:57:41 -08004331 static LIST_O_ENTRIES: &[(Domain, i64, &str)] = &[
4332 (Domain::APP, 1, "test1"),
4333 (Domain::APP, 1, "test2"),
4334 (Domain::APP, 1, "test3"),
4335 (Domain::APP, 1, "test4"),
4336 (Domain::APP, 1, "test5"),
4337 (Domain::APP, 1, "test6"),
4338 (Domain::APP, 1, "test7"),
4339 (Domain::APP, 2, "test1"),
4340 (Domain::APP, 2, "test2"),
4341 (Domain::APP, 2, "test3"),
4342 (Domain::APP, 2, "test4"),
4343 (Domain::APP, 2, "test5"),
4344 (Domain::APP, 2, "test6"),
4345 (Domain::APP, 2, "test8"),
4346 (Domain::SELINUX, 100, "test1"),
4347 (Domain::SELINUX, 100, "test2"),
4348 (Domain::SELINUX, 100, "test3"),
4349 (Domain::SELINUX, 100, "test4"),
4350 (Domain::SELINUX, 100, "test5"),
4351 (Domain::SELINUX, 100, "test6"),
4352 (Domain::SELINUX, 100, "test9"),
4353 ];
4354
4355 let list_o_keys: Vec<(i64, i64)> = LIST_O_ENTRIES
4356 .iter()
4357 .map(|(domain, ns, alias)| {
Qi Wub9433b52020-12-01 14:52:46 +08004358 let entry = make_test_key_entry(&mut db, *domain, *ns, *alias, None)
4359 .unwrap_or_else(|e| {
Janis Danisevskise92a5e62020-12-02 12:57:41 -08004360 panic!("Failed to insert {:?} {} {}. Error {:?}", domain, ns, alias, e)
4361 });
4362 (entry.id(), *ns)
4363 })
4364 .collect();
4365
4366 for (domain, namespace) in
4367 &[(Domain::APP, 1i64), (Domain::APP, 2i64), (Domain::SELINUX, 100i64)]
4368 {
4369 let mut list_o_descriptors: Vec<KeyDescriptor> = LIST_O_ENTRIES
4370 .iter()
4371 .filter_map(|(domain, ns, alias)| match ns {
4372 ns if *ns == *namespace => Some(KeyDescriptor {
4373 domain: *domain,
4374 nspace: *ns,
4375 alias: Some(alias.to_string()),
4376 blob: None,
4377 }),
4378 _ => None,
4379 })
4380 .collect();
4381 list_o_descriptors.sort();
4382 let mut list_result = db.list(*domain, *namespace)?;
4383 list_result.sort();
4384 assert_eq!(list_o_descriptors, list_result);
4385
4386 let mut list_o_ids: Vec<i64> = list_o_descriptors
4387 .into_iter()
4388 .map(|d| {
4389 let (_, entry) = db
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004390 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004391 &d,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004392 KeyType::Client,
4393 KeyEntryLoadBits::NONE,
4394 *namespace as u32,
4395 |_, _| Ok(()),
4396 )
Janis Danisevskise92a5e62020-12-02 12:57:41 -08004397 .unwrap();
4398 entry.id()
4399 })
4400 .collect();
4401 list_o_ids.sort_unstable();
4402 let mut loaded_entries: Vec<i64> = list_o_keys
4403 .iter()
4404 .filter_map(|(id, ns)| match ns {
4405 ns if *ns == *namespace => Some(*id),
4406 _ => None,
4407 })
4408 .collect();
4409 loaded_entries.sort_unstable();
4410 assert_eq!(list_o_ids, loaded_entries);
4411 }
4412 assert_eq!(Vec::<KeyDescriptor>::new(), db.list(Domain::SELINUX, 101)?);
4413
4414 Ok(())
4415 }
4416
Joel Galenson0891bc12020-07-20 10:37:03 -07004417 // Helpers
4418
4419 // Checks that the given result is an error containing the given string.
4420 fn check_result_is_error_containing_string<T>(result: Result<T>, target: &str) {
4421 let error_str = format!(
4422 "{:#?}",
4423 result.err().unwrap_or_else(|| panic!("Expected the error: {}", target))
4424 );
4425 assert!(
4426 error_str.contains(target),
4427 "The string \"{}\" should contain \"{}\"",
4428 error_str,
4429 target
4430 );
4431 }
4432
Joel Galenson2aab4432020-07-22 15:27:57 -07004433 #[derive(Debug, PartialEq)]
Joel Galenson0891bc12020-07-20 10:37:03 -07004434 #[allow(dead_code)]
4435 struct KeyEntryRow {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004436 id: i64,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004437 key_type: KeyType,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07004438 domain: Option<Domain>,
Joel Galenson0891bc12020-07-20 10:37:03 -07004439 namespace: Option<i64>,
4440 alias: Option<String>,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004441 state: KeyLifeCycle,
Max Bires8e93d2b2021-01-14 13:17:59 -08004442 km_uuid: Option<Uuid>,
Joel Galenson0891bc12020-07-20 10:37:03 -07004443 }
4444
4445 fn get_keyentry(db: &KeystoreDB) -> Result<Vec<KeyEntryRow>> {
4446 db.conn
Joel Galenson2aab4432020-07-22 15:27:57 -07004447 .prepare("SELECT * FROM persistent.keyentry;")?
Joel Galenson0891bc12020-07-20 10:37:03 -07004448 .query_map(NO_PARAMS, |row| {
Joel Galenson0891bc12020-07-20 10:37:03 -07004449 Ok(KeyEntryRow {
4450 id: row.get(0)?,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004451 key_type: row.get(1)?,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07004452 domain: match row.get(2)? {
4453 Some(i) => Some(Domain(i)),
4454 None => None,
4455 },
Joel Galenson0891bc12020-07-20 10:37:03 -07004456 namespace: row.get(3)?,
4457 alias: row.get(4)?,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004458 state: row.get(5)?,
Max Bires8e93d2b2021-01-14 13:17:59 -08004459 km_uuid: row.get(6)?,
Joel Galenson0891bc12020-07-20 10:37:03 -07004460 })
4461 })?
4462 .map(|r| r.context("Could not read keyentry row."))
4463 .collect::<Result<Vec<_>>>()
4464 }
4465
Max Biresb2e1d032021-02-08 21:35:05 -08004466 struct RemoteProvValues {
4467 cert_chain: Vec<u8>,
4468 priv_key: Vec<u8>,
4469 batch_cert: Vec<u8>,
4470 }
4471
Max Bires2b2e6562020-09-22 11:22:36 -07004472 fn load_attestation_key_pool(
4473 db: &mut KeystoreDB,
4474 expiration_date: i64,
4475 namespace: i64,
4476 base_byte: u8,
Max Biresb2e1d032021-02-08 21:35:05 -08004477 ) -> Result<RemoteProvValues> {
Max Bires2b2e6562020-09-22 11:22:36 -07004478 let public_key: Vec<u8> = vec![base_byte, 0x02 * base_byte];
4479 let cert_chain: Vec<u8> = vec![0x03 * base_byte, 0x04 * base_byte];
4480 let priv_key: Vec<u8> = vec![0x05 * base_byte, 0x06 * base_byte];
4481 let raw_public_key: Vec<u8> = vec![0x0b * base_byte, 0x0c * base_byte];
Max Biresb2e1d032021-02-08 21:35:05 -08004482 let batch_cert: Vec<u8> = vec![base_byte * 0x0d, base_byte * 0x0e];
Max Bires2b2e6562020-09-22 11:22:36 -07004483 db.create_attestation_key_entry(&public_key, &raw_public_key, &priv_key, &KEYSTORE_UUID)?;
4484 db.store_signed_attestation_certificate_chain(
4485 &raw_public_key,
Max Biresb2e1d032021-02-08 21:35:05 -08004486 &batch_cert,
Max Bires2b2e6562020-09-22 11:22:36 -07004487 &cert_chain,
4488 expiration_date,
4489 &KEYSTORE_UUID,
4490 )?;
4491 db.assign_attestation_key(Domain::APP, namespace, &KEYSTORE_UUID)?;
Max Biresb2e1d032021-02-08 21:35:05 -08004492 Ok(RemoteProvValues { cert_chain, priv_key, batch_cert })
Max Bires2b2e6562020-09-22 11:22:36 -07004493 }
4494
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07004495 // Note: The parameters and SecurityLevel associations are nonsensical. This
4496 // collection is only used to check if the parameters are preserved as expected by the
4497 // database.
Qi Wub9433b52020-12-01 14:52:46 +08004498 fn make_test_params(max_usage_count: Option<i32>) -> Vec<KeyParameter> {
4499 let mut params = vec![
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07004500 KeyParameter::new(KeyParameterValue::Invalid, SecurityLevel::TRUSTED_ENVIRONMENT),
4501 KeyParameter::new(
4502 KeyParameterValue::KeyPurpose(KeyPurpose::SIGN),
4503 SecurityLevel::TRUSTED_ENVIRONMENT,
4504 ),
4505 KeyParameter::new(
4506 KeyParameterValue::KeyPurpose(KeyPurpose::DECRYPT),
4507 SecurityLevel::TRUSTED_ENVIRONMENT,
4508 ),
4509 KeyParameter::new(
4510 KeyParameterValue::Algorithm(Algorithm::RSA),
4511 SecurityLevel::TRUSTED_ENVIRONMENT,
4512 ),
4513 KeyParameter::new(KeyParameterValue::KeySize(1024), SecurityLevel::TRUSTED_ENVIRONMENT),
4514 KeyParameter::new(
4515 KeyParameterValue::BlockMode(BlockMode::ECB),
4516 SecurityLevel::TRUSTED_ENVIRONMENT,
4517 ),
4518 KeyParameter::new(
4519 KeyParameterValue::BlockMode(BlockMode::GCM),
4520 SecurityLevel::TRUSTED_ENVIRONMENT,
4521 ),
4522 KeyParameter::new(KeyParameterValue::Digest(Digest::NONE), SecurityLevel::STRONGBOX),
4523 KeyParameter::new(
4524 KeyParameterValue::Digest(Digest::MD5),
4525 SecurityLevel::TRUSTED_ENVIRONMENT,
4526 ),
4527 KeyParameter::new(
4528 KeyParameterValue::Digest(Digest::SHA_2_224),
4529 SecurityLevel::TRUSTED_ENVIRONMENT,
4530 ),
4531 KeyParameter::new(
4532 KeyParameterValue::Digest(Digest::SHA_2_256),
4533 SecurityLevel::STRONGBOX,
4534 ),
4535 KeyParameter::new(
4536 KeyParameterValue::PaddingMode(PaddingMode::NONE),
4537 SecurityLevel::TRUSTED_ENVIRONMENT,
4538 ),
4539 KeyParameter::new(
4540 KeyParameterValue::PaddingMode(PaddingMode::RSA_OAEP),
4541 SecurityLevel::TRUSTED_ENVIRONMENT,
4542 ),
4543 KeyParameter::new(
4544 KeyParameterValue::PaddingMode(PaddingMode::RSA_PSS),
4545 SecurityLevel::STRONGBOX,
4546 ),
4547 KeyParameter::new(
4548 KeyParameterValue::PaddingMode(PaddingMode::RSA_PKCS1_1_5_SIGN),
4549 SecurityLevel::TRUSTED_ENVIRONMENT,
4550 ),
4551 KeyParameter::new(KeyParameterValue::CallerNonce, SecurityLevel::TRUSTED_ENVIRONMENT),
4552 KeyParameter::new(KeyParameterValue::MinMacLength(256), SecurityLevel::STRONGBOX),
4553 KeyParameter::new(
4554 KeyParameterValue::EcCurve(EcCurve::P_224),
4555 SecurityLevel::TRUSTED_ENVIRONMENT,
4556 ),
4557 KeyParameter::new(KeyParameterValue::EcCurve(EcCurve::P_256), SecurityLevel::STRONGBOX),
4558 KeyParameter::new(
4559 KeyParameterValue::EcCurve(EcCurve::P_384),
4560 SecurityLevel::TRUSTED_ENVIRONMENT,
4561 ),
4562 KeyParameter::new(
4563 KeyParameterValue::EcCurve(EcCurve::P_521),
4564 SecurityLevel::TRUSTED_ENVIRONMENT,
4565 ),
4566 KeyParameter::new(
4567 KeyParameterValue::RSAPublicExponent(3),
4568 SecurityLevel::TRUSTED_ENVIRONMENT,
4569 ),
4570 KeyParameter::new(
4571 KeyParameterValue::IncludeUniqueID,
4572 SecurityLevel::TRUSTED_ENVIRONMENT,
4573 ),
4574 KeyParameter::new(KeyParameterValue::BootLoaderOnly, SecurityLevel::STRONGBOX),
4575 KeyParameter::new(KeyParameterValue::RollbackResistance, SecurityLevel::STRONGBOX),
4576 KeyParameter::new(
4577 KeyParameterValue::ActiveDateTime(1234567890),
4578 SecurityLevel::STRONGBOX,
4579 ),
4580 KeyParameter::new(
4581 KeyParameterValue::OriginationExpireDateTime(1234567890),
4582 SecurityLevel::TRUSTED_ENVIRONMENT,
4583 ),
4584 KeyParameter::new(
4585 KeyParameterValue::UsageExpireDateTime(1234567890),
4586 SecurityLevel::TRUSTED_ENVIRONMENT,
4587 ),
4588 KeyParameter::new(
4589 KeyParameterValue::MinSecondsBetweenOps(1234567890),
4590 SecurityLevel::TRUSTED_ENVIRONMENT,
4591 ),
4592 KeyParameter::new(
4593 KeyParameterValue::MaxUsesPerBoot(1234567890),
4594 SecurityLevel::TRUSTED_ENVIRONMENT,
4595 ),
4596 KeyParameter::new(KeyParameterValue::UserID(1), SecurityLevel::STRONGBOX),
4597 KeyParameter::new(KeyParameterValue::UserSecureID(42), SecurityLevel::STRONGBOX),
4598 KeyParameter::new(
4599 KeyParameterValue::NoAuthRequired,
4600 SecurityLevel::TRUSTED_ENVIRONMENT,
4601 ),
4602 KeyParameter::new(
4603 KeyParameterValue::HardwareAuthenticatorType(HardwareAuthenticatorType::PASSWORD),
4604 SecurityLevel::TRUSTED_ENVIRONMENT,
4605 ),
4606 KeyParameter::new(KeyParameterValue::AuthTimeout(1234567890), SecurityLevel::SOFTWARE),
4607 KeyParameter::new(KeyParameterValue::AllowWhileOnBody, SecurityLevel::SOFTWARE),
4608 KeyParameter::new(
4609 KeyParameterValue::TrustedUserPresenceRequired,
4610 SecurityLevel::TRUSTED_ENVIRONMENT,
4611 ),
4612 KeyParameter::new(
4613 KeyParameterValue::TrustedConfirmationRequired,
4614 SecurityLevel::TRUSTED_ENVIRONMENT,
4615 ),
4616 KeyParameter::new(
4617 KeyParameterValue::UnlockedDeviceRequired,
4618 SecurityLevel::TRUSTED_ENVIRONMENT,
4619 ),
4620 KeyParameter::new(
4621 KeyParameterValue::ApplicationID(vec![1u8, 2u8, 3u8, 4u8]),
4622 SecurityLevel::SOFTWARE,
4623 ),
4624 KeyParameter::new(
4625 KeyParameterValue::ApplicationData(vec![4u8, 3u8, 2u8, 1u8]),
4626 SecurityLevel::SOFTWARE,
4627 ),
4628 KeyParameter::new(
4629 KeyParameterValue::CreationDateTime(12345677890),
4630 SecurityLevel::SOFTWARE,
4631 ),
4632 KeyParameter::new(
4633 KeyParameterValue::KeyOrigin(KeyOrigin::GENERATED),
4634 SecurityLevel::TRUSTED_ENVIRONMENT,
4635 ),
4636 KeyParameter::new(
4637 KeyParameterValue::RootOfTrust(vec![3u8, 2u8, 1u8, 4u8]),
4638 SecurityLevel::TRUSTED_ENVIRONMENT,
4639 ),
4640 KeyParameter::new(KeyParameterValue::OSVersion(1), SecurityLevel::TRUSTED_ENVIRONMENT),
4641 KeyParameter::new(KeyParameterValue::OSPatchLevel(2), SecurityLevel::SOFTWARE),
4642 KeyParameter::new(
4643 KeyParameterValue::UniqueID(vec![4u8, 3u8, 1u8, 2u8]),
4644 SecurityLevel::SOFTWARE,
4645 ),
4646 KeyParameter::new(
4647 KeyParameterValue::AttestationChallenge(vec![4u8, 3u8, 1u8, 2u8]),
4648 SecurityLevel::TRUSTED_ENVIRONMENT,
4649 ),
4650 KeyParameter::new(
4651 KeyParameterValue::AttestationApplicationID(vec![4u8, 3u8, 1u8, 2u8]),
4652 SecurityLevel::TRUSTED_ENVIRONMENT,
4653 ),
4654 KeyParameter::new(
4655 KeyParameterValue::AttestationIdBrand(vec![4u8, 3u8, 1u8, 2u8]),
4656 SecurityLevel::TRUSTED_ENVIRONMENT,
4657 ),
4658 KeyParameter::new(
4659 KeyParameterValue::AttestationIdDevice(vec![4u8, 3u8, 1u8, 2u8]),
4660 SecurityLevel::TRUSTED_ENVIRONMENT,
4661 ),
4662 KeyParameter::new(
4663 KeyParameterValue::AttestationIdProduct(vec![4u8, 3u8, 1u8, 2u8]),
4664 SecurityLevel::TRUSTED_ENVIRONMENT,
4665 ),
4666 KeyParameter::new(
4667 KeyParameterValue::AttestationIdSerial(vec![4u8, 3u8, 1u8, 2u8]),
4668 SecurityLevel::TRUSTED_ENVIRONMENT,
4669 ),
4670 KeyParameter::new(
4671 KeyParameterValue::AttestationIdIMEI(vec![4u8, 3u8, 1u8, 2u8]),
4672 SecurityLevel::TRUSTED_ENVIRONMENT,
4673 ),
4674 KeyParameter::new(
4675 KeyParameterValue::AttestationIdMEID(vec![4u8, 3u8, 1u8, 2u8]),
4676 SecurityLevel::TRUSTED_ENVIRONMENT,
4677 ),
4678 KeyParameter::new(
4679 KeyParameterValue::AttestationIdManufacturer(vec![4u8, 3u8, 1u8, 2u8]),
4680 SecurityLevel::TRUSTED_ENVIRONMENT,
4681 ),
4682 KeyParameter::new(
4683 KeyParameterValue::AttestationIdModel(vec![4u8, 3u8, 1u8, 2u8]),
4684 SecurityLevel::TRUSTED_ENVIRONMENT,
4685 ),
4686 KeyParameter::new(
4687 KeyParameterValue::VendorPatchLevel(3),
4688 SecurityLevel::TRUSTED_ENVIRONMENT,
4689 ),
4690 KeyParameter::new(
4691 KeyParameterValue::BootPatchLevel(4),
4692 SecurityLevel::TRUSTED_ENVIRONMENT,
4693 ),
4694 KeyParameter::new(
4695 KeyParameterValue::AssociatedData(vec![4u8, 3u8, 1u8, 2u8]),
4696 SecurityLevel::TRUSTED_ENVIRONMENT,
4697 ),
4698 KeyParameter::new(
4699 KeyParameterValue::Nonce(vec![4u8, 3u8, 1u8, 2u8]),
4700 SecurityLevel::TRUSTED_ENVIRONMENT,
4701 ),
4702 KeyParameter::new(
4703 KeyParameterValue::MacLength(256),
4704 SecurityLevel::TRUSTED_ENVIRONMENT,
4705 ),
4706 KeyParameter::new(
4707 KeyParameterValue::ResetSinceIdRotation,
4708 SecurityLevel::TRUSTED_ENVIRONMENT,
4709 ),
4710 KeyParameter::new(
4711 KeyParameterValue::ConfirmationToken(vec![5u8, 5u8, 5u8, 5u8]),
4712 SecurityLevel::TRUSTED_ENVIRONMENT,
4713 ),
Qi Wub9433b52020-12-01 14:52:46 +08004714 ];
4715 if let Some(value) = max_usage_count {
4716 params.push(KeyParameter::new(
4717 KeyParameterValue::UsageCountLimit(value),
4718 SecurityLevel::SOFTWARE,
4719 ));
4720 }
4721 params
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07004722 }
4723
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004724 fn make_test_key_entry(
4725 db: &mut KeystoreDB,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07004726 domain: Domain,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004727 namespace: i64,
4728 alias: &str,
Qi Wub9433b52020-12-01 14:52:46 +08004729 max_usage_count: Option<i32>,
Janis Danisevskisaec14592020-11-12 09:41:49 -08004730 ) -> Result<KeyIdGuard> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08004731 let key_id = db.create_key_entry(&domain, &namespace, &KEYSTORE_UUID)?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004732 let mut blob_metadata = BlobMetaData::new();
4733 blob_metadata.add(BlobMetaEntry::EncryptedBy(EncryptedBy::Password));
4734 blob_metadata.add(BlobMetaEntry::Salt(vec![1, 2, 3]));
4735 blob_metadata.add(BlobMetaEntry::Iv(vec![2, 3, 1]));
4736 blob_metadata.add(BlobMetaEntry::AeadTag(vec![3, 1, 2]));
4737 blob_metadata.add(BlobMetaEntry::KmUuid(KEYSTORE_UUID));
4738
4739 db.set_blob(
4740 &key_id,
4741 SubComponentType::KEY_BLOB,
4742 Some(TEST_KEY_BLOB),
4743 Some(&blob_metadata),
4744 )?;
4745 db.set_blob(&key_id, SubComponentType::CERT, Some(TEST_CERT_BLOB), None)?;
4746 db.set_blob(&key_id, SubComponentType::CERT_CHAIN, Some(TEST_CERT_CHAIN_BLOB), None)?;
Qi Wub9433b52020-12-01 14:52:46 +08004747
4748 let params = make_test_params(max_usage_count);
4749 db.insert_keyparameter(&key_id, &params)?;
4750
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004751 let mut metadata = KeyMetaData::new();
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004752 metadata.add(KeyMetaEntry::CreationDate(DateTime::from_millis_epoch(123456789)));
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004753 db.insert_key_metadata(&key_id, &metadata)?;
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08004754 rebind_alias(db, &key_id, alias, domain, namespace)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004755 Ok(key_id)
4756 }
4757
Qi Wub9433b52020-12-01 14:52:46 +08004758 fn make_test_key_entry_test_vector(key_id: i64, max_usage_count: Option<i32>) -> KeyEntry {
4759 let params = make_test_params(max_usage_count);
4760
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004761 let mut blob_metadata = BlobMetaData::new();
4762 blob_metadata.add(BlobMetaEntry::EncryptedBy(EncryptedBy::Password));
4763 blob_metadata.add(BlobMetaEntry::Salt(vec![1, 2, 3]));
4764 blob_metadata.add(BlobMetaEntry::Iv(vec![2, 3, 1]));
4765 blob_metadata.add(BlobMetaEntry::AeadTag(vec![3, 1, 2]));
4766 blob_metadata.add(BlobMetaEntry::KmUuid(KEYSTORE_UUID));
4767
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004768 let mut metadata = KeyMetaData::new();
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004769 metadata.add(KeyMetaEntry::CreationDate(DateTime::from_millis_epoch(123456789)));
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004770
4771 KeyEntry {
4772 id: key_id,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004773 key_blob_info: Some((TEST_KEY_BLOB.to_vec(), blob_metadata)),
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004774 cert: Some(TEST_CERT_BLOB.to_vec()),
4775 cert_chain: Some(TEST_CERT_CHAIN_BLOB.to_vec()),
Max Bires8e93d2b2021-01-14 13:17:59 -08004776 km_uuid: KEYSTORE_UUID,
Qi Wub9433b52020-12-01 14:52:46 +08004777 parameters: params,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004778 metadata,
Janis Danisevskis377d1002021-01-27 19:07:48 -08004779 pure_cert: false,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004780 }
4781 }
4782
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004783 fn debug_dump_keyentry_table(db: &mut KeystoreDB) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004784 let mut stmt = db.conn.prepare(
Max Bires8e93d2b2021-01-14 13:17:59 -08004785 "SELECT id, key_type, domain, namespace, alias, state, km_uuid FROM persistent.keyentry;",
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004786 )?;
Max Bires8e93d2b2021-01-14 13:17:59 -08004787 let rows = stmt.query_map::<(i64, KeyType, i32, i64, String, KeyLifeCycle, Uuid), _, _>(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004788 NO_PARAMS,
4789 |row| {
Max Bires8e93d2b2021-01-14 13:17:59 -08004790 Ok((
4791 row.get(0)?,
4792 row.get(1)?,
4793 row.get(2)?,
4794 row.get(3)?,
4795 row.get(4)?,
4796 row.get(5)?,
4797 row.get(6)?,
4798 ))
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004799 },
4800 )?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004801
4802 println!("Key entry table rows:");
4803 for r in rows {
Max Bires8e93d2b2021-01-14 13:17:59 -08004804 let (id, key_type, domain, namespace, alias, state, km_uuid) = r.unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004805 println!(
Max Bires8e93d2b2021-01-14 13:17:59 -08004806 " id: {} KeyType: {:?} Domain: {} Namespace: {} Alias: {} State: {:?} KmUuid: {:?}",
4807 id, key_type, domain, namespace, alias, state, km_uuid
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004808 );
4809 }
4810 Ok(())
4811 }
4812
4813 fn debug_dump_grant_table(db: &mut KeystoreDB) -> Result<()> {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08004814 let mut stmt = db
4815 .conn
4816 .prepare("SELECT id, grantee, keyentryid, access_vector FROM persistent.grant;")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004817 let rows = stmt.query_map::<(i64, i64, i64, i64), _, _>(NO_PARAMS, |row| {
4818 Ok((row.get(0)?, row.get(1)?, row.get(2)?, row.get(3)?))
4819 })?;
4820
4821 println!("Grant table rows:");
4822 for r in rows {
4823 let (id, gt, ki, av) = r.unwrap();
4824 println!(" id: {} grantee: {} key_id: {} access_vector: {}", id, gt, ki, av);
4825 }
4826 Ok(())
4827 }
4828
Joel Galenson0891bc12020-07-20 10:37:03 -07004829 // Use a custom random number generator that repeats each number once.
4830 // This allows us to test repeated elements.
4831
4832 thread_local! {
4833 static RANDOM_COUNTER: RefCell<i64> = RefCell::new(0);
4834 }
4835
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004836 fn reset_random() {
4837 RANDOM_COUNTER.with(|counter| {
4838 *counter.borrow_mut() = 0;
4839 })
4840 }
4841
Joel Galenson0891bc12020-07-20 10:37:03 -07004842 pub fn random() -> i64 {
4843 RANDOM_COUNTER.with(|counter| {
4844 let result = *counter.borrow() / 2;
4845 *counter.borrow_mut() += 1;
4846 result
4847 })
4848 }
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00004849
4850 #[test]
4851 fn test_last_off_body() -> Result<()> {
4852 let mut db = new_test_db()?;
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08004853 db.insert_last_off_body(MonotonicRawTime::now())?;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00004854 let tx = db.conn.transaction_with_behavior(TransactionBehavior::Immediate)?;
4855 let last_off_body_1 = KeystoreDB::get_last_off_body(&tx)?;
4856 tx.commit()?;
4857 let one_second = Duration::from_secs(1);
4858 thread::sleep(one_second);
4859 db.update_last_off_body(MonotonicRawTime::now())?;
4860 let tx2 = db.conn.transaction_with_behavior(TransactionBehavior::Immediate)?;
4861 let last_off_body_2 = KeystoreDB::get_last_off_body(&tx2)?;
4862 tx2.commit()?;
4863 assert!(last_off_body_1.seconds() < last_off_body_2.seconds());
4864 Ok(())
4865 }
Hasini Gunasingheda895552021-01-27 19:34:37 +00004866
4867 #[test]
4868 fn test_unbind_keys_for_user() -> Result<()> {
4869 let mut db = new_test_db()?;
4870 db.unbind_keys_for_user(1, false)?;
4871
4872 make_test_key_entry(&mut db, Domain::APP, 210000, TEST_ALIAS, None)?;
4873 make_test_key_entry(&mut db, Domain::APP, 110000, TEST_ALIAS, None)?;
4874 db.unbind_keys_for_user(2, false)?;
4875
4876 assert_eq!(1, db.list(Domain::APP, 110000)?.len());
4877 assert_eq!(0, db.list(Domain::APP, 210000)?.len());
4878
4879 db.unbind_keys_for_user(1, true)?;
4880 assert_eq!(0, db.list(Domain::APP, 110000)?.len());
4881
4882 Ok(())
4883 }
4884
4885 #[test]
4886 fn test_store_super_key() -> Result<()> {
4887 let mut db = new_test_db()?;
Paul Crowleyf61fee72021-03-17 14:38:44 -07004888 let pw: keystore2_crypto::Password = (&b"xyzabc"[..]).into();
Hasini Gunasingheda895552021-01-27 19:34:37 +00004889 let super_key = keystore2_crypto::generate_aes256_key()?;
4890 let secret = String::from("keystore2 is great.");
4891 let secret_bytes = secret.into_bytes();
4892 let (encrypted_secret, iv, tag) =
4893 keystore2_crypto::aes_gcm_encrypt(&secret_bytes, &super_key)?;
4894
4895 let (encrypted_super_key, metadata) =
4896 SuperKeyManager::encrypt_with_password(&super_key, &pw)?;
4897 db.store_super_key(1, &(&encrypted_super_key, &metadata))?;
4898
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00004899 //check if super key exists
4900 assert!(db.key_exists(Domain::APP, 1, "USER_SUPER_KEY", KeyType::Super)?);
4901
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +00004902 let (_, key_entry) = db.load_super_key(1)?.unwrap();
Hasini Gunasingheda895552021-01-27 19:34:37 +00004903 let loaded_super_key = SuperKeyManager::extract_super_key_from_key_entry(key_entry, &pw)?;
4904
4905 let decrypted_secret_bytes = keystore2_crypto::aes_gcm_decrypt(
4906 &encrypted_secret,
4907 &iv,
4908 &tag,
4909 &loaded_super_key.get_key(),
4910 )?;
4911 let decrypted_secret = String::from_utf8((&decrypted_secret_bytes).to_vec())?;
4912 assert_eq!(String::from("keystore2 is great."), decrypted_secret);
4913 Ok(())
4914 }
Joel Galenson26f4d012020-07-17 14:57:21 -07004915}