blob: 3789d282d480f664f59e9bc88e2ec6daa87f7e04 [file] [log] [blame]
Joel Galenson26f4d012020-07-17 14:57:21 -07001// Copyright 2020, The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
Janis Danisevskis63f7bc82020-09-03 10:12:56 -070015//! This is the Keystore 2.0 database module.
16//! The database module provides a connection to the backing SQLite store.
17//! We have two databases one for persistent key blob storage and one for
18//! items that have a per boot life cycle.
19//!
20//! ## Persistent database
21//! The persistent database has tables for key blobs. They are organized
22//! as follows:
23//! The `keyentry` table is the primary table for key entries. It is
24//! accompanied by two tables for blobs and parameters.
25//! Each key entry occupies exactly one row in the `keyentry` table and
26//! zero or more rows in the tables `blobentry` and `keyparameter`.
27//!
28//! ## Per boot database
29//! The per boot database stores items with a per boot lifecycle.
30//! Currently, there is only the `grant` table in this database.
31//! Grants are references to a key that can be used to access a key by
32//! clients that don't own that key. Grants can only be created by the
33//! owner of a key. And only certain components can create grants.
34//! This is governed by SEPolicy.
35//!
36//! ## Access control
37//! Some database functions that load keys or create grants perform
38//! access control. This is because in some cases access control
39//! can only be performed after some information about the designated
40//! key was loaded from the database. To decouple the permission checks
41//! from the database module these functions take permission check
42//! callbacks.
Joel Galenson26f4d012020-07-17 14:57:21 -070043
Janis Danisevskis4507f3b2021-01-13 16:34:39 -080044use crate::db_utils::{self, SqlField};
Qi Wub9433b52020-12-01 14:52:46 +080045use crate::error::{Error as KsError, ErrorCode, ResponseCode};
Janis Danisevskisb42fc182020-12-15 08:41:27 -080046use crate::impl_metadata; // This is in db_utils.rs
Janis Danisevskis4522c2b2020-11-27 18:04:58 -080047use crate::key_parameter::{KeyParameter, Tag};
Janis Danisevskisc5b210b2020-09-11 13:27:37 -070048use crate::permission::KeyPermSet;
Hasini Gunasinghe557b1032020-11-10 01:35:30 +000049use crate::utils::get_current_time_in_seconds;
Janis Danisevskisb42fc182020-12-15 08:41:27 -080050use anyhow::{anyhow, Context, Result};
Max Bires8e93d2b2021-01-14 13:17:59 -080051use std::{convert::TryFrom, convert::TryInto, ops::Deref, time::SystemTimeError};
Janis Danisevskis60400fe2020-08-26 15:24:42 -070052
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +000053use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
Janis Danisevskis5ed8c532021-01-11 14:19:42 -080054 HardwareAuthToken::HardwareAuthToken,
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +000055 HardwareAuthenticatorType::HardwareAuthenticatorType, SecurityLevel::SecurityLevel,
Janis Danisevskisc3a496b2021-01-05 10:37:22 -080056};
57use android_hardware_security_secureclock::aidl::android::hardware::security::secureclock::{
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +000058 Timestamp::Timestamp,
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +000059};
Janis Danisevskisc5b210b2020-09-11 13:27:37 -070060use android_system_keystore2::aidl::android::system::keystore2::{
Janis Danisevskis04b02832020-10-26 09:21:40 -070061 Domain::Domain, KeyDescriptor::KeyDescriptor,
Janis Danisevskis60400fe2020-08-26 15:24:42 -070062};
Max Bires2b2e6562020-09-22 11:22:36 -070063use android_security_remoteprovisioning::aidl::android::security::remoteprovisioning::{
64 AttestationPoolStatus::AttestationPoolStatus,
65};
66
67use keystore2_crypto::ZVec;
Janis Danisevskisaec14592020-11-12 09:41:49 -080068use lazy_static::lazy_static;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +000069use log::error;
Joel Galenson0891bc12020-07-20 10:37:03 -070070#[cfg(not(test))]
71use rand::prelude::random;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -070072use rusqlite::{
Janis Danisevskisb42fc182020-12-15 08:41:27 -080073 params,
74 types::FromSql,
75 types::FromSqlResult,
76 types::ToSqlOutput,
77 types::{FromSqlError, Value, ValueRef},
Janis Danisevskis5ed8c532021-01-11 14:19:42 -080078 Connection, OptionalExtension, ToSql, Transaction, TransactionBehavior, NO_PARAMS,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -070079};
Max Bires2b2e6562020-09-22 11:22:36 -070080
Janis Danisevskisaec14592020-11-12 09:41:49 -080081use std::{
Janis Danisevskisb42fc182020-12-15 08:41:27 -080082 collections::{HashMap, HashSet},
Janis Danisevskisbf15d732020-12-08 10:35:26 -080083 path::Path,
84 sync::{Condvar, Mutex},
Janis Danisevskisb42fc182020-12-15 08:41:27 -080085 time::{Duration, SystemTime},
Janis Danisevskisaec14592020-11-12 09:41:49 -080086};
Max Bires2b2e6562020-09-22 11:22:36 -070087
Joel Galenson0891bc12020-07-20 10:37:03 -070088#[cfg(test)]
89use tests::random;
Joel Galenson26f4d012020-07-17 14:57:21 -070090
Janis Danisevskisb42fc182020-12-15 08:41:27 -080091impl_metadata!(
92 /// A set of metadata for key entries.
93 #[derive(Debug, Default, Eq, PartialEq)]
94 pub struct KeyMetaData;
95 /// A metadata entry for key entries.
96 #[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
97 pub enum KeyMetaEntry {
98 /// If present, indicates that the sensitive part of key
99 /// is encrypted with another key or a key derived from a password.
100 EncryptedBy(EncryptedBy) with accessor encrypted_by,
101 /// If the blob is password encrypted this field is set to the
102 /// salt used for the key derivation.
103 Salt(Vec<u8>) with accessor salt,
104 /// If the blob is encrypted, this field is set to the initialization vector.
105 Iv(Vec<u8>) with accessor iv,
106 /// If the blob is encrypted, this field holds the AEAD TAG.
107 AeadTag(Vec<u8>) with accessor aead_tag,
108 /// Creation date of a the key entry.
109 CreationDate(DateTime) with accessor creation_date,
110 /// Expiration date for attestation keys.
111 AttestationExpirationDate(DateTime) with accessor attestation_expiration_date,
Max Bires2b2e6562020-09-22 11:22:36 -0700112 /// CBOR Blob that represents a COSE_Key and associated metadata needed for remote
113 /// provisioning
114 AttestationMacedPublicKey(Vec<u8>) with accessor attestation_maced_public_key,
115 /// Vector representing the raw public key so results from the server can be matched
116 /// to the right entry
117 AttestationRawPubKey(Vec<u8>) with accessor attestation_raw_pub_key,
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800118 // --- ADD NEW META DATA FIELDS HERE ---
119 // For backwards compatibility add new entries only to
120 // end of this list and above this comment.
121 };
122);
123
124impl KeyMetaData {
125 fn load_from_db(key_id: i64, tx: &Transaction) -> Result<Self> {
126 let mut stmt = tx
127 .prepare(
128 "SELECT tag, data from persistent.keymetadata
129 WHERE keyentryid = ?;",
130 )
131 .context("In KeyMetaData::load_from_db: prepare statement failed.")?;
132
133 let mut metadata: HashMap<i64, KeyMetaEntry> = Default::default();
134
135 let mut rows =
136 stmt.query(params![key_id]).context("In KeyMetaData::load_from_db: query failed.")?;
137 db_utils::with_rows_extract_all(&mut rows, |row| {
138 let db_tag: i64 = row.get(0).context("Failed to read tag.")?;
139 metadata.insert(
140 db_tag,
141 KeyMetaEntry::new_from_sql(db_tag, &SqlField::new(1, &row))
142 .context("Failed to read KeyMetaEntry.")?,
143 );
144 Ok(())
145 })
146 .context("In KeyMetaData::load_from_db.")?;
147
148 Ok(Self { data: metadata })
149 }
150
151 fn store_in_db(&self, key_id: i64, tx: &Transaction) -> Result<()> {
152 let mut stmt = tx
153 .prepare(
154 "INSERT into persistent.keymetadata (keyentryid, tag, data)
155 VALUES (?, ?, ?);",
156 )
157 .context("In KeyMetaData::store_in_db: Failed to prepare statement.")?;
158
159 let iter = self.data.iter();
160 for (tag, entry) in iter {
161 stmt.insert(params![key_id, tag, entry,]).with_context(|| {
162 format!("In KeyMetaData::store_in_db: Failed to insert {:?}", entry)
163 })?;
164 }
165 Ok(())
166 }
167}
168
169/// Indicates the type of the keyentry.
170#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
171pub enum KeyType {
172 /// This is a client key type. These keys are created or imported through the Keystore 2.0
173 /// AIDL interface android.system.keystore2.
174 Client,
175 /// This is a super key type. These keys are created by keystore itself and used to encrypt
176 /// other key blobs to provide LSKF binding.
177 Super,
178 /// This is an attestation key. These keys are created by the remote provisioning mechanism.
179 Attestation,
180}
181
182impl ToSql for KeyType {
183 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
184 Ok(ToSqlOutput::Owned(Value::Integer(match self {
185 KeyType::Client => 0,
186 KeyType::Super => 1,
187 KeyType::Attestation => 2,
188 })))
189 }
190}
191
192impl FromSql for KeyType {
193 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
194 match i64::column_result(value)? {
195 0 => Ok(KeyType::Client),
196 1 => Ok(KeyType::Super),
197 2 => Ok(KeyType::Attestation),
198 v => Err(FromSqlError::OutOfRange(v)),
199 }
200 }
201}
202
Max Bires8e93d2b2021-01-14 13:17:59 -0800203/// Uuid representation that can be stored in the database.
204/// Right now it can only be initialized from SecurityLevel.
205/// Once KeyMint provides a UUID type a corresponding From impl shall be added.
206#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
207pub struct Uuid([u8; 16]);
208
209impl Deref for Uuid {
210 type Target = [u8; 16];
211
212 fn deref(&self) -> &Self::Target {
213 &self.0
214 }
215}
216
217impl From<SecurityLevel> for Uuid {
218 fn from(sec_level: SecurityLevel) -> Self {
219 Self((sec_level.0 as u128).to_be_bytes())
220 }
221}
222
223impl ToSql for Uuid {
224 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
225 self.0.to_sql()
226 }
227}
228
229impl FromSql for Uuid {
230 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
231 let blob = Vec::<u8>::column_result(value)?;
232 if blob.len() != 16 {
233 return Err(FromSqlError::OutOfRange(blob.len() as i64));
234 }
235 let mut arr = [0u8; 16];
236 arr.copy_from_slice(&blob);
237 Ok(Self(arr))
238 }
239}
240
241/// Key entries that are not associated with any KeyMint instance, such as pure certificate
242/// entries are associated with this UUID.
243pub static KEYSTORE_UUID: Uuid = Uuid([
244 0x41, 0xe3, 0xb9, 0xce, 0x27, 0x58, 0x4e, 0x91, 0xbc, 0xfd, 0xa5, 0x5d, 0x91, 0x85, 0xab, 0x11,
245]);
246
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800247/// Indicates how the sensitive part of this key blob is encrypted.
248#[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
249pub enum EncryptedBy {
250 /// The keyblob is encrypted by a user password.
251 /// In the database this variant is represented as NULL.
252 Password,
253 /// The keyblob is encrypted by another key with wrapped key id.
254 /// In the database this variant is represented as non NULL value
255 /// that is convertible to i64, typically NUMERIC.
256 KeyId(i64),
257}
258
259impl ToSql for EncryptedBy {
260 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
261 match self {
262 Self::Password => Ok(ToSqlOutput::Owned(Value::Null)),
263 Self::KeyId(id) => id.to_sql(),
264 }
265 }
266}
267
268impl FromSql for EncryptedBy {
269 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
270 match value {
271 ValueRef::Null => Ok(Self::Password),
272 _ => Ok(Self::KeyId(i64::column_result(value)?)),
273 }
274 }
275}
276
277/// A database representation of wall clock time. DateTime stores unix epoch time as
278/// i64 in milliseconds.
279#[derive(Debug, Copy, Clone, Default, Eq, PartialEq, Ord, PartialOrd)]
280pub struct DateTime(i64);
281
282/// Error type returned when creating DateTime or converting it from and to
283/// SystemTime.
284#[derive(thiserror::Error, Debug)]
285pub enum DateTimeError {
286 /// This is returned when SystemTime and Duration computations fail.
287 #[error(transparent)]
288 SystemTimeError(#[from] SystemTimeError),
289
290 /// This is returned when type conversions fail.
291 #[error(transparent)]
292 TypeConversion(#[from] std::num::TryFromIntError),
293
294 /// This is returned when checked time arithmetic failed.
295 #[error("Time arithmetic failed.")]
296 TimeArithmetic,
297}
298
299impl DateTime {
300 /// Constructs a new DateTime object denoting the current time. This may fail during
301 /// conversion to unix epoch time and during conversion to the internal i64 representation.
302 pub fn now() -> Result<Self, DateTimeError> {
303 Ok(Self(SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_millis().try_into()?))
304 }
305
306 /// Constructs a new DateTime object from milliseconds.
307 pub fn from_millis_epoch(millis: i64) -> Self {
308 Self(millis)
309 }
310
311 /// Returns unix epoch time in milliseconds.
312 pub fn to_millis_epoch(&self) -> i64 {
313 self.0
314 }
315
316 /// Returns unix epoch time in seconds.
317 pub fn to_secs_epoch(&self) -> i64 {
318 self.0 / 1000
319 }
320}
321
322impl ToSql for DateTime {
323 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
324 Ok(ToSqlOutput::Owned(Value::Integer(self.0)))
325 }
326}
327
328impl FromSql for DateTime {
329 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
330 Ok(Self(i64::column_result(value)?))
331 }
332}
333
334impl TryInto<SystemTime> for DateTime {
335 type Error = DateTimeError;
336
337 fn try_into(self) -> Result<SystemTime, Self::Error> {
338 // We want to construct a SystemTime representation equivalent to self, denoting
339 // a point in time THEN, but we cannot set the time directly. We can only construct
340 // a SystemTime denoting NOW, and we can get the duration between EPOCH and NOW,
341 // and between EPOCH and THEN. With this common reference we can construct the
342 // duration between NOW and THEN which we can add to our SystemTime representation
343 // of NOW to get a SystemTime representation of THEN.
344 // Durations can only be positive, thus the if statement below.
345 let now = SystemTime::now();
346 let now_epoch = now.duration_since(SystemTime::UNIX_EPOCH)?;
347 let then_epoch = Duration::from_millis(self.0.try_into()?);
348 Ok(if now_epoch > then_epoch {
349 // then = now - (now_epoch - then_epoch)
350 now_epoch
351 .checked_sub(then_epoch)
352 .and_then(|d| now.checked_sub(d))
353 .ok_or(DateTimeError::TimeArithmetic)?
354 } else {
355 // then = now + (then_epoch - now_epoch)
356 then_epoch
357 .checked_sub(now_epoch)
358 .and_then(|d| now.checked_add(d))
359 .ok_or(DateTimeError::TimeArithmetic)?
360 })
361 }
362}
363
364impl TryFrom<SystemTime> for DateTime {
365 type Error = DateTimeError;
366
367 fn try_from(t: SystemTime) -> Result<Self, Self::Error> {
368 Ok(Self(t.duration_since(SystemTime::UNIX_EPOCH)?.as_millis().try_into()?))
369 }
370}
371
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800372#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone)]
373enum KeyLifeCycle {
374 /// Existing keys have a key ID but are not fully populated yet.
375 /// This is a transient state. If Keystore finds any such keys when it starts up, it must move
376 /// them to Unreferenced for garbage collection.
377 Existing,
378 /// A live key is fully populated and usable by clients.
379 Live,
380 /// An unreferenced key is scheduled for garbage collection.
381 Unreferenced,
382}
383
384impl ToSql for KeyLifeCycle {
385 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
386 match self {
387 Self::Existing => Ok(ToSqlOutput::Owned(Value::Integer(0))),
388 Self::Live => Ok(ToSqlOutput::Owned(Value::Integer(1))),
389 Self::Unreferenced => Ok(ToSqlOutput::Owned(Value::Integer(2))),
390 }
391 }
392}
393
394impl FromSql for KeyLifeCycle {
395 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
396 match i64::column_result(value)? {
397 0 => Ok(KeyLifeCycle::Existing),
398 1 => Ok(KeyLifeCycle::Live),
399 2 => Ok(KeyLifeCycle::Unreferenced),
400 v => Err(FromSqlError::OutOfRange(v)),
401 }
402 }
403}
404
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700405/// Keys have a KeyMint blob component and optional public certificate and
406/// certificate chain components.
407/// KeyEntryLoadBits is a bitmap that indicates to `KeystoreDB::load_key_entry`
408/// which components shall be loaded from the database if present.
Janis Danisevskis66784c42021-01-27 08:40:25 -0800409#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700410pub struct KeyEntryLoadBits(u32);
411
412impl KeyEntryLoadBits {
413 /// Indicate to `KeystoreDB::load_key_entry` that no component shall be loaded.
414 pub const NONE: KeyEntryLoadBits = Self(0);
415 /// Indicate to `KeystoreDB::load_key_entry` that the KeyMint component shall be loaded.
416 pub const KM: KeyEntryLoadBits = Self(1);
417 /// Indicate to `KeystoreDB::load_key_entry` that the Public components shall be loaded.
418 pub const PUBLIC: KeyEntryLoadBits = Self(2);
419 /// Indicate to `KeystoreDB::load_key_entry` that both components shall be loaded.
420 pub const BOTH: KeyEntryLoadBits = Self(3);
421
422 /// Returns true if this object indicates that the public components shall be loaded.
423 pub const fn load_public(&self) -> bool {
424 self.0 & Self::PUBLIC.0 != 0
425 }
426
427 /// Returns true if the object indicates that the KeyMint component shall be loaded.
428 pub const fn load_km(&self) -> bool {
429 self.0 & Self::KM.0 != 0
430 }
431}
432
Janis Danisevskisaec14592020-11-12 09:41:49 -0800433lazy_static! {
434 static ref KEY_ID_LOCK: KeyIdLockDb = KeyIdLockDb::new();
435}
436
437struct KeyIdLockDb {
438 locked_keys: Mutex<HashSet<i64>>,
439 cond_var: Condvar,
440}
441
442/// A locked key. While a guard exists for a given key id, the same key cannot be loaded
443/// from the database a second time. Most functions manipulating the key blob database
444/// require a KeyIdGuard.
445#[derive(Debug)]
446pub struct KeyIdGuard(i64);
447
448impl KeyIdLockDb {
449 fn new() -> Self {
450 Self { locked_keys: Mutex::new(HashSet::new()), cond_var: Condvar::new() }
451 }
452
453 /// This function blocks until an exclusive lock for the given key entry id can
454 /// be acquired. It returns a guard object, that represents the lifecycle of the
455 /// acquired lock.
456 pub fn get(&self, key_id: i64) -> KeyIdGuard {
457 let mut locked_keys = self.locked_keys.lock().unwrap();
458 while locked_keys.contains(&key_id) {
459 locked_keys = self.cond_var.wait(locked_keys).unwrap();
460 }
461 locked_keys.insert(key_id);
462 KeyIdGuard(key_id)
463 }
464
465 /// This function attempts to acquire an exclusive lock on a given key id. If the
466 /// given key id is already taken the function returns None immediately. If a lock
467 /// can be acquired this function returns a guard object, that represents the
468 /// lifecycle of the acquired lock.
469 pub fn try_get(&self, key_id: i64) -> Option<KeyIdGuard> {
470 let mut locked_keys = self.locked_keys.lock().unwrap();
471 if locked_keys.insert(key_id) {
472 Some(KeyIdGuard(key_id))
473 } else {
474 None
475 }
476 }
477}
478
479impl KeyIdGuard {
480 /// Get the numeric key id of the locked key.
481 pub fn id(&self) -> i64 {
482 self.0
483 }
484}
485
486impl Drop for KeyIdGuard {
487 fn drop(&mut self) {
488 let mut locked_keys = KEY_ID_LOCK.locked_keys.lock().unwrap();
489 locked_keys.remove(&self.0);
Janis Danisevskis7fd53582020-11-23 13:40:34 -0800490 drop(locked_keys);
Janis Danisevskisaec14592020-11-12 09:41:49 -0800491 KEY_ID_LOCK.cond_var.notify_all();
492 }
493}
494
Max Bires8e93d2b2021-01-14 13:17:59 -0800495/// This type represents a certificate and certificate chain entry for a key.
Max Bires2b2e6562020-09-22 11:22:36 -0700496#[derive(Debug, Default)]
Max Bires8e93d2b2021-01-14 13:17:59 -0800497pub struct CertificateInfo {
498 cert: Option<Vec<u8>>,
499 cert_chain: Option<Vec<u8>>,
500}
501
502impl CertificateInfo {
503 /// Constructs a new CertificateInfo object from `cert` and `cert_chain`
504 pub fn new(cert: Option<Vec<u8>>, cert_chain: Option<Vec<u8>>) -> Self {
505 Self { cert, cert_chain }
506 }
507
508 /// Take the cert
509 pub fn take_cert(&mut self) -> Option<Vec<u8>> {
510 self.cert.take()
511 }
512
513 /// Take the cert chain
514 pub fn take_cert_chain(&mut self) -> Option<Vec<u8>> {
515 self.cert_chain.take()
516 }
517}
518
Max Bires2b2e6562020-09-22 11:22:36 -0700519/// This type represents a certificate chain with a private key corresponding to the leaf
520/// certificate. TODO(jbires): This will be used in a follow-on CL, for now it's used in the tests.
521#[allow(dead_code)]
522pub struct CertificateChain {
523 private_key: ZVec,
524 cert_chain: ZVec,
525}
526
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700527/// This type represents a Keystore 2.0 key entry.
528/// An entry has a unique `id` by which it can be found in the database.
529/// It has a security level field, key parameters, and three optional fields
530/// for the KeyMint blob, public certificate and a public certificate chain.
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800531#[derive(Debug, Default, Eq, PartialEq)]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700532pub struct KeyEntry {
533 id: i64,
534 km_blob: Option<Vec<u8>>,
535 cert: Option<Vec<u8>>,
536 cert_chain: Option<Vec<u8>>,
Max Bires8e93d2b2021-01-14 13:17:59 -0800537 km_uuid: Uuid,
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700538 parameters: Vec<KeyParameter>,
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800539 metadata: KeyMetaData,
Janis Danisevskis377d1002021-01-27 19:07:48 -0800540 pure_cert: bool,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700541}
542
543impl KeyEntry {
544 /// Returns the unique id of the Key entry.
545 pub fn id(&self) -> i64 {
546 self.id
547 }
548 /// Exposes the optional KeyMint blob.
549 pub fn km_blob(&self) -> &Option<Vec<u8>> {
550 &self.km_blob
551 }
552 /// Extracts the Optional KeyMint blob.
553 pub fn take_km_blob(&mut self) -> Option<Vec<u8>> {
554 self.km_blob.take()
555 }
556 /// Exposes the optional public certificate.
557 pub fn cert(&self) -> &Option<Vec<u8>> {
558 &self.cert
559 }
560 /// Extracts the optional public certificate.
561 pub fn take_cert(&mut self) -> Option<Vec<u8>> {
562 self.cert.take()
563 }
564 /// Exposes the optional public certificate chain.
565 pub fn cert_chain(&self) -> &Option<Vec<u8>> {
566 &self.cert_chain
567 }
568 /// Extracts the optional public certificate_chain.
569 pub fn take_cert_chain(&mut self) -> Option<Vec<u8>> {
570 self.cert_chain.take()
571 }
Max Bires8e93d2b2021-01-14 13:17:59 -0800572 /// Returns the uuid of the owning KeyMint instance.
573 pub fn km_uuid(&self) -> &Uuid {
574 &self.km_uuid
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700575 }
Janis Danisevskis04b02832020-10-26 09:21:40 -0700576 /// Exposes the key parameters of this key entry.
577 pub fn key_parameters(&self) -> &Vec<KeyParameter> {
578 &self.parameters
579 }
580 /// Consumes this key entry and extracts the keyparameters from it.
581 pub fn into_key_parameters(self) -> Vec<KeyParameter> {
582 self.parameters
583 }
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800584 /// Exposes the key metadata of this key entry.
585 pub fn metadata(&self) -> &KeyMetaData {
586 &self.metadata
587 }
Janis Danisevskis377d1002021-01-27 19:07:48 -0800588 /// This returns true if the entry is a pure certificate entry with no
589 /// private key component.
590 pub fn pure_cert(&self) -> bool {
591 self.pure_cert
592 }
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700593}
594
595/// Indicates the sub component of a key entry for persistent storage.
Janis Danisevskis377d1002021-01-27 19:07:48 -0800596#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700597pub struct SubComponentType(u32);
598impl SubComponentType {
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800599 /// Persistent identifier for a key blob.
600 pub const KEY_BLOB: SubComponentType = Self(0);
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700601 /// Persistent identifier for a certificate blob.
602 pub const CERT: SubComponentType = Self(1);
603 /// Persistent identifier for a certificate chain blob.
604 pub const CERT_CHAIN: SubComponentType = Self(2);
605}
606
607impl ToSql for SubComponentType {
608 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
609 self.0.to_sql()
610 }
611}
612
613impl FromSql for SubComponentType {
614 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
615 Ok(Self(u32::column_result(value)?))
616 }
617}
618
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700619/// KeystoreDB wraps a connection to an SQLite database and tracks its
620/// ownership. It also implements all of Keystore 2.0's database functionality.
Joel Galenson26f4d012020-07-17 14:57:21 -0700621pub struct KeystoreDB {
Joel Galenson26f4d012020-07-17 14:57:21 -0700622 conn: Connection,
623}
624
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000625/// Database representation of the monotonic time retrieved from the system call clock_gettime with
626/// CLOCK_MONOTONIC_RAW. Stores monotonic time as i64 in seconds.
627#[derive(Debug, Copy, Clone, Default, Eq, PartialEq, Ord, PartialOrd)]
628pub struct MonotonicRawTime(i64);
629
630impl MonotonicRawTime {
631 /// Constructs a new MonotonicRawTime
632 pub fn now() -> Self {
633 Self(get_current_time_in_seconds())
634 }
635
636 /// Returns the integer value of MonotonicRawTime as i64
637 pub fn seconds(&self) -> i64 {
638 self.0
639 }
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800640
641 /// Like i64::checked_sub.
642 pub fn checked_sub(&self, other: &Self) -> Option<Self> {
643 self.0.checked_sub(other.0).map(Self)
644 }
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000645}
646
647impl ToSql for MonotonicRawTime {
648 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
649 Ok(ToSqlOutput::Owned(Value::Integer(self.0)))
650 }
651}
652
653impl FromSql for MonotonicRawTime {
654 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
655 Ok(Self(i64::column_result(value)?))
656 }
657}
658
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000659/// This struct encapsulates the information to be stored in the database about the auth tokens
660/// received by keystore.
661pub struct AuthTokenEntry {
662 auth_token: HardwareAuthToken,
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000663 time_received: MonotonicRawTime,
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000664}
665
666impl AuthTokenEntry {
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000667 fn new(auth_token: HardwareAuthToken, time_received: MonotonicRawTime) -> Self {
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000668 AuthTokenEntry { auth_token, time_received }
669 }
670
671 /// Checks if this auth token satisfies the given authentication information.
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800672 pub fn satisfies(&self, user_secure_ids: &[i64], auth_type: HardwareAuthenticatorType) -> bool {
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000673 user_secure_ids.iter().any(|&sid| {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800674 (sid == self.auth_token.userId || sid == self.auth_token.authenticatorId)
675 && (((auth_type.0 as i32) & (self.auth_token.authenticatorType.0 as i32)) != 0)
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000676 })
677 }
678
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000679 /// Returns the auth token wrapped by the AuthTokenEntry
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800680 pub fn auth_token(&self) -> &HardwareAuthToken {
681 &self.auth_token
682 }
683
684 /// Returns the auth token wrapped by the AuthTokenEntry
685 pub fn take_auth_token(self) -> HardwareAuthToken {
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000686 self.auth_token
687 }
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800688
689 /// Returns the time that this auth token was received.
690 pub fn time_received(&self) -> MonotonicRawTime {
691 self.time_received
692 }
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000693}
694
Janis Danisevskisb00ebd02021-02-02 21:52:24 -0800695/// Shared in-memory databases get destroyed as soon as the last connection to them gets closed.
696/// This object does not allow access to the database connection. But it keeps a database
697/// connection alive in order to keep the in memory per boot database alive.
698pub struct PerBootDbKeepAlive(Connection);
699
Joel Galenson26f4d012020-07-17 14:57:21 -0700700impl KeystoreDB {
Janis Danisevskisb00ebd02021-02-02 21:52:24 -0800701 const PERBOOT_DB_FILE_NAME: &'static str = &"file:perboot.sqlite?mode=memory&cache=shared";
702
703 /// This creates a PerBootDbKeepAlive object to keep the per boot database alive.
704 pub fn keep_perboot_db_alive() -> Result<PerBootDbKeepAlive> {
705 let conn = Connection::open_in_memory()
706 .context("In keep_perboot_db_alive: Failed to initialize SQLite connection.")?;
707
708 conn.execute("ATTACH DATABASE ? as perboot;", params![Self::PERBOOT_DB_FILE_NAME])
709 .context("In keep_perboot_db_alive: Failed to attach database perboot.")?;
710 Ok(PerBootDbKeepAlive(conn))
711 }
712
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700713 /// This will create a new database connection connecting the two
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800714 /// files persistent.sqlite and perboot.sqlite in the given directory.
715 /// It also attempts to initialize all of the tables.
716 /// KeystoreDB cannot be used by multiple threads.
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700717 /// Each thread should open their own connection using `thread_local!`.
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800718 pub fn new(db_root: &Path) -> Result<Self> {
Janis Danisevskisb00ebd02021-02-02 21:52:24 -0800719 // Build the path to the sqlite file.
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800720 let mut persistent_path = db_root.to_path_buf();
721 persistent_path.push("persistent.sqlite");
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700722
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800723 // Now convert them to strings prefixed with "file:"
724 let mut persistent_path_str = "file:".to_owned();
725 persistent_path_str.push_str(&persistent_path.to_string_lossy());
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800726
Janis Danisevskisb00ebd02021-02-02 21:52:24 -0800727 let conn = Self::make_connection(&persistent_path_str, &Self::PERBOOT_DB_FILE_NAME)?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800728
Janis Danisevskis66784c42021-01-27 08:40:25 -0800729 // On busy fail Immediately. It is unlikely to succeed given a bug in sqlite.
730 conn.busy_handler(None).context("In KeystoreDB::new: Failed to set busy handler.")?;
731
732 let mut db = Self { conn };
733 db.with_transaction(TransactionBehavior::Immediate, |tx| {
734 Self::init_tables(tx).context("Trying to initialize tables.")
735 })?;
736 Ok(db)
Joel Galenson2aab4432020-07-22 15:27:57 -0700737 }
738
Janis Danisevskis66784c42021-01-27 08:40:25 -0800739 fn init_tables(tx: &Transaction) -> Result<()> {
740 tx.execute(
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700741 "CREATE TABLE IF NOT EXISTS persistent.keyentry (
Joel Galenson0891bc12020-07-20 10:37:03 -0700742 id INTEGER UNIQUE,
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800743 key_type INTEGER,
Joel Galenson0891bc12020-07-20 10:37:03 -0700744 domain INTEGER,
745 namespace INTEGER,
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800746 alias BLOB,
Max Bires8e93d2b2021-01-14 13:17:59 -0800747 state INTEGER,
748 km_uuid BLOB);",
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700749 NO_PARAMS,
750 )
751 .context("Failed to initialize \"keyentry\" table.")?;
752
Janis Danisevskis66784c42021-01-27 08:40:25 -0800753 tx.execute(
Janis Danisevskisa5438182021-02-02 14:22:59 -0800754 "CREATE INDEX IF NOT EXISTS persistent.keyentry_id_index
755 ON keyentry(id);",
756 NO_PARAMS,
757 )
758 .context("Failed to create index keyentry_id_index.")?;
759
760 tx.execute(
761 "CREATE INDEX IF NOT EXISTS persistent.keyentry_domain_namespace_index
762 ON keyentry(domain, namespace, alias);",
763 NO_PARAMS,
764 )
765 .context("Failed to create index keyentry_domain_namespace_index.")?;
766
767 tx.execute(
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700768 "CREATE TABLE IF NOT EXISTS persistent.blobentry (
769 id INTEGER PRIMARY KEY,
770 subcomponent_type INTEGER,
771 keyentryid INTEGER,
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800772 blob BLOB);",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700773 NO_PARAMS,
774 )
775 .context("Failed to initialize \"blobentry\" table.")?;
776
Janis Danisevskis66784c42021-01-27 08:40:25 -0800777 tx.execute(
Janis Danisevskisa5438182021-02-02 14:22:59 -0800778 "CREATE INDEX IF NOT EXISTS persistent.blobentry_keyentryid_index
779 ON blobentry(keyentryid);",
780 NO_PARAMS,
781 )
782 .context("Failed to create index blobentry_keyentryid_index.")?;
783
784 tx.execute(
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700785 "CREATE TABLE IF NOT EXISTS persistent.keyparameter (
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000786 keyentryid INTEGER,
787 tag INTEGER,
788 data ANY,
789 security_level INTEGER);",
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700790 NO_PARAMS,
791 )
792 .context("Failed to initialize \"keyparameter\" table.")?;
793
Janis Danisevskis66784c42021-01-27 08:40:25 -0800794 tx.execute(
Janis Danisevskisa5438182021-02-02 14:22:59 -0800795 "CREATE INDEX IF NOT EXISTS persistent.keyparameter_keyentryid_index
796 ON keyparameter(keyentryid);",
797 NO_PARAMS,
798 )
799 .context("Failed to create index keyparameter_keyentryid_index.")?;
800
801 tx.execute(
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800802 "CREATE TABLE IF NOT EXISTS persistent.keymetadata (
803 keyentryid INTEGER,
804 tag INTEGER,
805 data ANY);",
806 NO_PARAMS,
807 )
808 .context("Failed to initialize \"keymetadata\" table.")?;
809
Janis Danisevskis66784c42021-01-27 08:40:25 -0800810 tx.execute(
Janis Danisevskisa5438182021-02-02 14:22:59 -0800811 "CREATE INDEX IF NOT EXISTS persistent.keymetadata_keyentryid_index
812 ON keymetadata(keyentryid);",
813 NO_PARAMS,
814 )
815 .context("Failed to create index keymetadata_keyentryid_index.")?;
816
817 tx.execute(
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800818 "CREATE TABLE IF NOT EXISTS persistent.grant (
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700819 id INTEGER UNIQUE,
820 grantee INTEGER,
821 keyentryid INTEGER,
822 access_vector INTEGER);",
823 NO_PARAMS,
824 )
825 .context("Failed to initialize \"grant\" table.")?;
826
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000827 //TODO: only drop the following two perboot tables if this is the first start up
828 //during the boot (b/175716626).
Janis Danisevskis66784c42021-01-27 08:40:25 -0800829 // tx.execute("DROP TABLE IF EXISTS perboot.authtoken;", NO_PARAMS)
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000830 // .context("Failed to drop perboot.authtoken table")?;
Janis Danisevskis66784c42021-01-27 08:40:25 -0800831 tx.execute(
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000832 "CREATE TABLE IF NOT EXISTS perboot.authtoken (
833 id INTEGER PRIMARY KEY,
834 challenge INTEGER,
835 user_id INTEGER,
836 auth_id INTEGER,
837 authenticator_type INTEGER,
838 timestamp INTEGER,
839 mac BLOB,
840 time_received INTEGER,
841 UNIQUE(user_id, auth_id, authenticator_type));",
842 NO_PARAMS,
843 )
844 .context("Failed to initialize \"authtoken\" table.")?;
845
Janis Danisevskis66784c42021-01-27 08:40:25 -0800846 // tx.execute("DROP TABLE IF EXISTS perboot.metadata;", NO_PARAMS)
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000847 // .context("Failed to drop perboot.metadata table")?;
848 // metadata table stores certain miscellaneous information required for keystore functioning
849 // during a boot cycle, as key-value pairs.
Janis Danisevskis66784c42021-01-27 08:40:25 -0800850 tx.execute(
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000851 "CREATE TABLE IF NOT EXISTS perboot.metadata (
852 key TEXT,
853 value BLOB,
854 UNIQUE(key));",
855 NO_PARAMS,
856 )
857 .context("Failed to initialize \"metadata\" table.")?;
Joel Galenson0891bc12020-07-20 10:37:03 -0700858 Ok(())
859 }
860
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700861 fn make_connection(persistent_file: &str, perboot_file: &str) -> Result<Connection> {
862 let conn =
863 Connection::open_in_memory().context("Failed to initialize SQLite connection.")?;
864
Janis Danisevskis66784c42021-01-27 08:40:25 -0800865 loop {
866 if let Err(e) = conn
867 .execute("ATTACH DATABASE ? as persistent;", params![persistent_file])
868 .context("Failed to attach database persistent.")
869 {
870 if Self::is_locked_error(&e) {
871 std::thread::sleep(std::time::Duration::from_micros(500));
872 continue;
873 } else {
874 return Err(e);
875 }
876 }
877 break;
878 }
879 loop {
880 if let Err(e) = conn
881 .execute("ATTACH DATABASE ? as perboot;", params![perboot_file])
882 .context("Failed to attach database perboot.")
883 {
884 if Self::is_locked_error(&e) {
885 std::thread::sleep(std::time::Duration::from_micros(500));
886 continue;
887 } else {
888 return Err(e);
889 }
890 }
891 break;
892 }
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700893
894 Ok(conn)
895 }
896
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800897 /// Get one unreferenced key. There is no particular order in which the keys are returned.
898 fn get_unreferenced_key_id(tx: &Transaction) -> Result<Option<i64>> {
899 tx.query_row(
900 "SELECT id FROM persistent.keyentry WHERE state = ?",
901 params![KeyLifeCycle::Unreferenced],
902 |row| row.get(0),
903 )
904 .optional()
905 .context("In get_unreferenced_key_id: Trying to get unreferenced key id.")
906 }
907
908 /// Returns a key id guard and key entry for one unreferenced key entry. Of the optional
909 /// fields of the key entry only the km_blob field will be populated. This is required
910 /// to subject the blob to its KeyMint instance for deletion.
911 pub fn get_unreferenced_key(&mut self) -> Result<Option<(KeyIdGuard, KeyEntry)>> {
912 self.with_transaction(TransactionBehavior::Deferred, |tx| {
913 let key_id = match Self::get_unreferenced_key_id(tx)
914 .context("Trying to get unreferenced key id")?
915 {
916 None => return Ok(None),
917 Some(id) => KEY_ID_LOCK.try_get(id).ok_or_else(KsError::sys).context(concat!(
918 "A key id lock was held for an unreferenced key. ",
919 "This should never happen."
920 ))?,
921 };
922 let key_entry = Self::load_key_components(tx, KeyEntryLoadBits::KM, key_id.id())
923 .context("Trying to get key components.")?;
924 Ok(Some((key_id, key_entry)))
925 })
926 .context("In get_unreferenced_key.")
927 }
928
929 /// This function purges all remnants of a key entry from the database.
930 /// Important: This does not check if the key was unreferenced, nor does it
931 /// subject the key to its KeyMint instance for permanent invalidation.
932 /// This function should only be called by the garbage collector.
933 /// To delete a key call `mark_unreferenced`, which transitions the key to the unreferenced
934 /// state, deletes all grants to the key, and notifies the garbage collector.
935 /// The garbage collector will:
936 /// 1. Call get_unreferenced_key.
937 /// 2. Determine the proper way to dispose of sensitive key material, e.g., call
938 /// `KeyMintDevice::delete()`.
939 /// 3. Call `purge_key_entry`.
940 pub fn purge_key_entry(&mut self, key_id: KeyIdGuard) -> Result<()> {
941 self.with_transaction(TransactionBehavior::Immediate, |tx| {
942 tx.execute("DELETE FROM persistent.keyentry WHERE id = ?;", params![key_id.id()])
943 .context("Trying to delete keyentry.")?;
944 tx.execute(
945 "DELETE FROM persistent.blobentry WHERE keyentryid = ?;",
946 params![key_id.id()],
947 )
948 .context("Trying to delete blobentries.")?;
949 tx.execute(
950 "DELETE FROM persistent.keymetadata WHERE keyentryid = ?;",
951 params![key_id.id()],
952 )
953 .context("Trying to delete keymetadata.")?;
954 tx.execute(
955 "DELETE FROM persistent.keyparameter WHERE keyentryid = ?;",
956 params![key_id.id()],
957 )
958 .context("Trying to delete keyparameters.")?;
959 let grants_deleted = tx
960 .execute("DELETE FROM persistent.grant WHERE keyentryid = ?;", params![key_id.id()])
961 .context("Trying to delete grants.")?;
962 if grants_deleted != 0 {
963 log::error!("Purged key that still had grants. This should not happen.");
964 }
965 Ok(())
966 })
967 .context("In purge_key_entry.")
968 }
969
970 /// This maintenance function should be called only once before the database is used for the
971 /// first time. It restores the invariant that `KeyLifeCycle::Existing` is a transient state.
972 /// The function transitions all key entries from Existing to Unreferenced unconditionally and
973 /// returns the number of rows affected. If this returns a value greater than 0, it means that
974 /// Keystore crashed at some point during key generation. Callers may want to log such
975 /// occurrences.
976 /// Unlike with `mark_unreferenced`, we don't need to purge grants, because only keys that made
977 /// it to `KeyLifeCycle::Live` may have grants.
978 pub fn cleanup_leftovers(&mut self) -> Result<usize> {
Janis Danisevskis66784c42021-01-27 08:40:25 -0800979 self.with_transaction(TransactionBehavior::Immediate, |tx| {
980 tx.execute(
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800981 "UPDATE persistent.keyentry SET state = ? WHERE state = ?;",
982 params![KeyLifeCycle::Unreferenced, KeyLifeCycle::Existing],
983 )
Janis Danisevskis66784c42021-01-27 08:40:25 -0800984 .context("Failed to execute query.")
985 })
986 .context("In cleanup_leftovers.")
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800987 }
988
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800989 /// Atomically loads a key entry and associated metadata or creates it using the
990 /// callback create_new_key callback. The callback is called during a database
991 /// transaction. This means that implementers should be mindful about using
992 /// blocking operations such as IPC or grabbing mutexes.
993 pub fn get_or_create_key_with<F>(
994 &mut self,
995 domain: Domain,
996 namespace: i64,
997 alias: &str,
Max Bires8e93d2b2021-01-14 13:17:59 -0800998 km_uuid: Uuid,
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800999 create_new_key: F,
1000 ) -> Result<(KeyIdGuard, KeyEntry)>
1001 where
Janis Danisevskis66784c42021-01-27 08:40:25 -08001002 F: Fn() -> Result<(Vec<u8>, KeyMetaData)>,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001003 {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001004 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1005 let id = {
1006 let mut stmt = tx
1007 .prepare(
1008 "SELECT id FROM persistent.keyentry
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001009 WHERE
1010 key_type = ?
1011 AND domain = ?
1012 AND namespace = ?
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001013 AND alias = ?
1014 AND state = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08001015 )
1016 .context("In get_or_create_key_with: Failed to select from keyentry table.")?;
1017 let mut rows = stmt
1018 .query(params![KeyType::Super, domain.0, namespace, alias, KeyLifeCycle::Live])
1019 .context("In get_or_create_key_with: Failed to query from keyentry table.")?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001020
Janis Danisevskis66784c42021-01-27 08:40:25 -08001021 db_utils::with_rows_extract_one(&mut rows, |row| {
1022 Ok(match row {
1023 Some(r) => r.get(0).context("Failed to unpack id.")?,
1024 None => None,
1025 })
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001026 })
Janis Danisevskis66784c42021-01-27 08:40:25 -08001027 .context("In get_or_create_key_with.")?
1028 };
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001029
Janis Danisevskis66784c42021-01-27 08:40:25 -08001030 let (id, entry) = match id {
1031 Some(id) => (
1032 id,
1033 Self::load_key_components(&tx, KeyEntryLoadBits::KM, id)
1034 .context("In get_or_create_key_with.")?,
1035 ),
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001036
Janis Danisevskis66784c42021-01-27 08:40:25 -08001037 None => {
1038 let id = Self::insert_with_retry(|id| {
1039 tx.execute(
1040 "INSERT into persistent.keyentry
Max Bires8e93d2b2021-01-14 13:17:59 -08001041 (id, key_type, domain, namespace, alias, state, km_uuid)
1042 VALUES(?, ?, ?, ?, ?, ?, ?);",
Janis Danisevskis66784c42021-01-27 08:40:25 -08001043 params![
1044 id,
1045 KeyType::Super,
1046 domain.0,
1047 namespace,
1048 alias,
1049 KeyLifeCycle::Live,
1050 km_uuid,
1051 ],
1052 )
1053 })
1054 .context("In get_or_create_key_with.")?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001055
Janis Danisevskis66784c42021-01-27 08:40:25 -08001056 let (blob, metadata) =
1057 create_new_key().context("In get_or_create_key_with.")?;
1058 Self::set_blob_internal(&tx, id, SubComponentType::KEY_BLOB, Some(&blob))
1059 .context("In get_of_create_key_with.")?;
1060 metadata.store_in_db(id, &tx).context("In get_or_create_key_with.")?;
1061 (
Janis Danisevskis377d1002021-01-27 19:07:48 -08001062 id,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001063 KeyEntry {
1064 id,
1065 km_blob: Some(blob),
1066 metadata,
1067 pure_cert: false,
1068 ..Default::default()
1069 },
1070 )
1071 }
1072 };
1073 Ok((KEY_ID_LOCK.get(id), entry))
1074 })
1075 .context("In get_or_create_key_with.")
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001076 }
1077
Janis Danisevskis66784c42021-01-27 08:40:25 -08001078 /// SQLite3 seems to hold a shared mutex while running the busy handler when
1079 /// waiting for the database file to become available. This makes it
1080 /// impossible to successfully recover from a locked database when the
1081 /// transaction holding the device busy is in the same process on a
1082 /// different connection. As a result the busy handler has to time out and
1083 /// fail in order to make progress.
1084 ///
1085 /// Instead, we set the busy handler to None (return immediately). And catch
1086 /// Busy and Locked errors (the latter occur on in memory databases with
1087 /// shared cache, e.g., the per-boot database.) and restart the transaction
1088 /// after a grace period of half a millisecond.
1089 ///
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001090 /// Creates a transaction with the given behavior and executes f with the new transaction.
Janis Danisevskis66784c42021-01-27 08:40:25 -08001091 /// The transaction is committed only if f returns Ok and retried if DatabaseBusy
1092 /// or DatabaseLocked is encountered.
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001093 fn with_transaction<T, F>(&mut self, behavior: TransactionBehavior, f: F) -> Result<T>
1094 where
Janis Danisevskis66784c42021-01-27 08:40:25 -08001095 F: Fn(&Transaction) -> Result<T>,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001096 {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001097 loop {
1098 match self
1099 .conn
1100 .transaction_with_behavior(behavior)
1101 .context("In with_transaction.")
1102 .and_then(|tx| f(&tx).map(|result| (result, tx)))
1103 .and_then(|(result, tx)| {
1104 tx.commit().context("In with_transaction: Failed to commit transaction.")?;
1105 Ok(result)
1106 }) {
1107 Ok(result) => break Ok(result),
1108 Err(e) => {
1109 if Self::is_locked_error(&e) {
1110 std::thread::sleep(std::time::Duration::from_micros(500));
1111 continue;
1112 } else {
1113 return Err(e).context("In with_transaction.");
1114 }
1115 }
1116 }
1117 }
1118 }
1119
1120 fn is_locked_error(e: &anyhow::Error) -> bool {
1121 matches!(e.root_cause().downcast_ref::<rusqlite::ffi::Error>(),
1122 Some(rusqlite::ffi::Error {
1123 code: rusqlite::ErrorCode::DatabaseBusy,
1124 ..
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001125 })
Janis Danisevskis66784c42021-01-27 08:40:25 -08001126 | Some(rusqlite::ffi::Error {
1127 code: rusqlite::ErrorCode::DatabaseLocked,
1128 ..
1129 }))
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001130 }
1131
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001132 /// Creates a new key entry and allocates a new randomized id for the new key.
1133 /// The key id gets associated with a domain and namespace but not with an alias.
1134 /// To complete key generation `rebind_alias` should be called after all of the
1135 /// key artifacts, i.e., blobs and parameters have been associated with the new
1136 /// key id. Finalizing with `rebind_alias` makes the creation of a new key entry
1137 /// atomic even if key generation is not.
Max Bires8e93d2b2021-01-14 13:17:59 -08001138 pub fn create_key_entry(
1139 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001140 domain: &Domain,
1141 namespace: &i64,
Max Bires8e93d2b2021-01-14 13:17:59 -08001142 km_uuid: &Uuid,
1143 ) -> Result<KeyIdGuard> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001144 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Max Bires8e93d2b2021-01-14 13:17:59 -08001145 Self::create_key_entry_internal(tx, domain, namespace, km_uuid)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001146 })
1147 .context("In create_key_entry.")
1148 }
1149
1150 fn create_key_entry_internal(
1151 tx: &Transaction,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001152 domain: &Domain,
1153 namespace: &i64,
Max Bires8e93d2b2021-01-14 13:17:59 -08001154 km_uuid: &Uuid,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001155 ) -> Result<KeyIdGuard> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001156 match *domain {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001157 Domain::APP | Domain::SELINUX => {}
Joel Galenson0891bc12020-07-20 10:37:03 -07001158 _ => {
1159 return Err(KsError::sys())
1160 .context(format!("Domain {:?} must be either App or SELinux.", domain));
1161 }
1162 }
Janis Danisevskisaec14592020-11-12 09:41:49 -08001163 Ok(KEY_ID_LOCK.get(
1164 Self::insert_with_retry(|id| {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001165 tx.execute(
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001166 "INSERT into persistent.keyentry
Max Bires8e93d2b2021-01-14 13:17:59 -08001167 (id, key_type, domain, namespace, alias, state, km_uuid)
1168 VALUES(?, ?, ?, ?, NULL, ?, ?);",
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001169 params![
1170 id,
1171 KeyType::Client,
1172 domain.0 as u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001173 *namespace,
Max Bires8e93d2b2021-01-14 13:17:59 -08001174 KeyLifeCycle::Existing,
1175 km_uuid,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001176 ],
Janis Danisevskisaec14592020-11-12 09:41:49 -08001177 )
1178 })
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001179 .context("In create_key_entry_internal")?,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001180 ))
Joel Galenson26f4d012020-07-17 14:57:21 -07001181 }
Joel Galenson33c04ad2020-08-03 11:04:38 -07001182
Max Bires2b2e6562020-09-22 11:22:36 -07001183 /// Creates a new attestation key entry and allocates a new randomized id for the new key.
1184 /// The key id gets associated with a domain and namespace later but not with an alias. The
1185 /// alias will be used to denote if a key has been signed as each key can only be bound to one
1186 /// domain and namespace pairing so there is no need to use them as a value for indexing into
1187 /// a key.
1188 pub fn create_attestation_key_entry(
1189 &mut self,
1190 maced_public_key: &[u8],
1191 raw_public_key: &[u8],
1192 private_key: &[u8],
1193 km_uuid: &Uuid,
1194 ) -> Result<()> {
1195 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1196 let key_id = KEY_ID_LOCK.get(
1197 Self::insert_with_retry(|id| {
1198 tx.execute(
1199 "INSERT into persistent.keyentry
1200 (id, key_type, domain, namespace, alias, state, km_uuid)
1201 VALUES(?, ?, NULL, NULL, NULL, ?, ?);",
1202 params![id, KeyType::Attestation, KeyLifeCycle::Live, km_uuid],
1203 )
1204 })
1205 .context("In create_key_entry")?,
1206 );
1207 Self::set_blob_internal(&tx, key_id.0, SubComponentType::KEY_BLOB, Some(private_key))?;
1208 let mut metadata = KeyMetaData::new();
1209 metadata.add(KeyMetaEntry::AttestationMacedPublicKey(maced_public_key.to_vec()));
1210 metadata.add(KeyMetaEntry::AttestationRawPubKey(raw_public_key.to_vec()));
1211 metadata.store_in_db(key_id.0, &tx)?;
1212 Ok(())
1213 })
1214 .context("In create_attestation_key_entry")
1215 }
1216
Janis Danisevskis377d1002021-01-27 19:07:48 -08001217 /// Set a new blob and associates it with the given key id. Each blob
1218 /// has a sub component type.
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001219 /// Each key can have one of each sub component type associated. If more
1220 /// are added only the most recent can be retrieved, and superseded blobs
Janis Danisevskis377d1002021-01-27 19:07:48 -08001221 /// will get garbage collected.
1222 /// Components SubComponentType::CERT and SubComponentType::CERT_CHAIN can be
1223 /// removed by setting blob to None.
1224 pub fn set_blob(
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001225 &mut self,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001226 key_id: &KeyIdGuard,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001227 sc_type: SubComponentType,
Janis Danisevskis377d1002021-01-27 19:07:48 -08001228 blob: Option<&[u8]>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001229 ) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001230 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis377d1002021-01-27 19:07:48 -08001231 Self::set_blob_internal(&tx, key_id.0, sc_type, blob)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001232 })
Janis Danisevskis377d1002021-01-27 19:07:48 -08001233 .context("In set_blob.")
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001234 }
1235
Janis Danisevskis377d1002021-01-27 19:07:48 -08001236 fn set_blob_internal(
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001237 tx: &Transaction,
1238 key_id: i64,
1239 sc_type: SubComponentType,
Janis Danisevskis377d1002021-01-27 19:07:48 -08001240 blob: Option<&[u8]>,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001241 ) -> Result<()> {
Janis Danisevskis377d1002021-01-27 19:07:48 -08001242 match (blob, sc_type) {
1243 (Some(blob), _) => {
1244 tx.execute(
1245 "INSERT INTO persistent.blobentry
1246 (subcomponent_type, keyentryid, blob) VALUES (?, ?, ?);",
1247 params![sc_type, key_id, blob],
1248 )
1249 .context("In set_blob_internal: Failed to insert blob.")?;
1250 }
1251 (None, SubComponentType::CERT) | (None, SubComponentType::CERT_CHAIN) => {
1252 tx.execute(
1253 "DELETE FROM persistent.blobentry
1254 WHERE subcomponent_type = ? AND keyentryid = ?;",
1255 params![sc_type, key_id],
1256 )
1257 .context("In set_blob_internal: Failed to delete blob.")?;
1258 }
1259 (None, _) => {
1260 return Err(KsError::sys())
1261 .context("In set_blob_internal: Other blobs cannot be deleted in this way.");
1262 }
1263 }
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001264 Ok(())
1265 }
1266
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001267 /// Inserts a collection of key parameters into the `persistent.keyparameter` table
1268 /// and associates them with the given `key_id`.
Janis Danisevskis66784c42021-01-27 08:40:25 -08001269 pub fn insert_keyparameter(
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001270 &mut self,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001271 key_id: &KeyIdGuard,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001272 params: &[KeyParameter],
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001273 ) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001274 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1275 Self::insert_keyparameter_internal(tx, key_id, params)
1276 })
1277 .context("In insert_keyparameter.")
1278 }
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001279
Janis Danisevskis66784c42021-01-27 08:40:25 -08001280 fn insert_keyparameter_internal(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001281 tx: &Transaction,
1282 key_id: &KeyIdGuard,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001283 params: &[KeyParameter],
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001284 ) -> Result<()> {
1285 let mut stmt = tx
1286 .prepare(
1287 "INSERT into persistent.keyparameter (keyentryid, tag, data, security_level)
1288 VALUES (?, ?, ?, ?);",
1289 )
1290 .context("In insert_keyparameter_internal: Failed to prepare statement.")?;
1291
Janis Danisevskis66784c42021-01-27 08:40:25 -08001292 for p in params.iter() {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001293 stmt.insert(params![
1294 key_id.0,
1295 p.get_tag().0,
1296 p.key_parameter_value(),
1297 p.security_level().0
1298 ])
1299 .with_context(|| {
1300 format!("In insert_keyparameter_internal: Failed to insert {:?}", p)
1301 })?;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001302 }
1303 Ok(())
1304 }
1305
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001306 /// Insert a set of key entry specific metadata into the database.
1307 pub fn insert_key_metadata(
1308 &mut self,
1309 key_id: &KeyIdGuard,
1310 metadata: &KeyMetaData,
1311 ) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001312 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1313 metadata.store_in_db(key_id.0, &tx)
1314 })
1315 .context("In insert_key_metadata.")
1316 }
1317
Max Bires2b2e6562020-09-22 11:22:36 -07001318 /// Stores a signed certificate chain signed by a remote provisioning server, keyed
1319 /// on the public key.
1320 pub fn store_signed_attestation_certificate_chain(
1321 &mut self,
1322 raw_public_key: &[u8],
1323 cert_chain: &[u8],
1324 expiration_date: i64,
1325 km_uuid: &Uuid,
1326 ) -> Result<()> {
1327 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1328 let mut stmt = tx
1329 .prepare(
1330 "SELECT keyentryid
1331 FROM persistent.keymetadata
1332 WHERE tag = ? AND data = ? AND keyentryid IN
1333 (SELECT id
1334 FROM persistent.keyentry
1335 WHERE
1336 alias IS NULL AND
1337 domain IS NULL AND
1338 namespace IS NULL AND
1339 key_type = ? AND
1340 km_uuid = ?);",
1341 )
1342 .context("Failed to store attestation certificate chain.")?;
1343 let mut rows = stmt
1344 .query(params![
1345 KeyMetaData::AttestationRawPubKey,
1346 raw_public_key,
1347 KeyType::Attestation,
1348 km_uuid
1349 ])
1350 .context("Failed to fetch keyid")?;
1351 let key_id = db_utils::with_rows_extract_one(&mut rows, |row| {
1352 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?
1353 .get(0)
1354 .context("Failed to unpack id.")
1355 })
1356 .context("Failed to get key_id.")?;
1357 let num_updated = tx
1358 .execute(
1359 "UPDATE persistent.keyentry
1360 SET alias = ?
1361 WHERE id = ?;",
1362 params!["signed", key_id],
1363 )
1364 .context("Failed to update alias.")?;
1365 if num_updated != 1 {
1366 return Err(KsError::sys()).context("Alias not updated for the key.");
1367 }
1368 let mut metadata = KeyMetaData::new();
1369 metadata.add(KeyMetaEntry::AttestationExpirationDate(DateTime::from_millis_epoch(
1370 expiration_date,
1371 )));
1372 metadata.store_in_db(key_id, &tx).context("Failed to insert key metadata.")?;
1373 Self::set_blob_internal(&tx, key_id, SubComponentType::CERT_CHAIN, Some(cert_chain))
1374 .context("Failed to insert cert chain")?;
1375 Ok(())
1376 })
1377 .context("In store_signed_attestation_certificate_chain: ")
1378 }
1379
1380 /// Assigns the next unassigned attestation key to a domain/namespace combo that does not
1381 /// currently have a key assigned to it.
1382 pub fn assign_attestation_key(
1383 &mut self,
1384 domain: Domain,
1385 namespace: i64,
1386 km_uuid: &Uuid,
1387 ) -> Result<()> {
1388 match domain {
1389 Domain::APP | Domain::SELINUX => {}
1390 _ => {
1391 return Err(KsError::sys()).context(format!(
1392 concat!(
1393 "In assign_attestation_key: Domain {:?} ",
1394 "must be either App or SELinux.",
1395 ),
1396 domain
1397 ));
1398 }
1399 }
1400 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1401 let result = tx
1402 .execute(
1403 "UPDATE persistent.keyentry
1404 SET domain=?1, namespace=?2
1405 WHERE
1406 id =
1407 (SELECT MIN(id)
1408 FROM persistent.keyentry
1409 WHERE ALIAS IS NOT NULL
1410 AND domain IS NULL
1411 AND key_type IS ?3
1412 AND state IS ?4
1413 AND km_uuid IS ?5)
1414 AND
1415 (SELECT COUNT(*)
1416 FROM persistent.keyentry
1417 WHERE domain=?1
1418 AND namespace=?2
1419 AND key_type IS ?3
1420 AND state IS ?4
1421 AND km_uuid IS ?5) = 0;",
1422 params![
1423 domain.0 as u32,
1424 namespace,
1425 KeyType::Attestation,
1426 KeyLifeCycle::Live,
1427 km_uuid,
1428 ],
1429 )
1430 .context("Failed to assign attestation key")?;
1431 if result != 1 {
1432 return Err(KsError::sys()).context(format!(
1433 "Expected to update a single entry but instead updated {}.",
1434 result
1435 ));
1436 }
1437 Ok(())
1438 })
1439 .context("In assign_attestation_key: ")
1440 }
1441
1442 /// Retrieves num_keys number of attestation keys that have not yet been signed by a remote
1443 /// provisioning server, or the maximum number available if there are not num_keys number of
1444 /// entries in the table.
1445 pub fn fetch_unsigned_attestation_keys(
1446 &mut self,
1447 num_keys: i32,
1448 km_uuid: &Uuid,
1449 ) -> Result<Vec<Vec<u8>>> {
1450 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1451 let mut stmt = tx
1452 .prepare(
1453 "SELECT data
1454 FROM persistent.keymetadata
1455 WHERE tag = ? AND keyentryid IN
1456 (SELECT id
1457 FROM persistent.keyentry
1458 WHERE
1459 alias IS NULL AND
1460 domain IS NULL AND
1461 namespace IS NULL AND
1462 key_type = ? AND
1463 km_uuid = ?
1464 LIMIT ?);",
1465 )
1466 .context("Failed to prepare statement")?;
1467 let rows = stmt
1468 .query_map(
1469 params![
1470 KeyMetaData::AttestationMacedPublicKey,
1471 KeyType::Attestation,
1472 km_uuid,
1473 num_keys
1474 ],
1475 |row| Ok(row.get(0)?),
1476 )?
1477 .collect::<rusqlite::Result<Vec<Vec<u8>>>>()
1478 .context("Failed to execute statement")?;
1479 Ok(rows)
1480 })
1481 .context("In fetch_unsigned_attestation_keys")
1482 }
1483
1484 /// Removes any keys that have expired as of the current time. Returns the number of keys
1485 /// marked unreferenced that are bound to be garbage collected.
1486 pub fn delete_expired_attestation_keys(&mut self) -> Result<i32> {
1487 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1488 let mut stmt = tx
1489 .prepare(
1490 "SELECT keyentryid, data
1491 FROM persistent.keymetadata
1492 WHERE tag = ? AND keyentryid IN
1493 (SELECT id
1494 FROM persistent.keyentry
1495 WHERE key_type = ?);",
1496 )
1497 .context("Failed to prepare query")?;
1498 let key_ids_to_check = stmt
1499 .query_map(
1500 params![KeyMetaData::AttestationExpirationDate, KeyType::Attestation],
1501 |row| Ok((row.get(0)?, row.get(1)?)),
1502 )?
1503 .collect::<rusqlite::Result<Vec<(i64, DateTime)>>>()
1504 .context("Failed to get date metadata")?;
1505 let curr_time = DateTime::from_millis_epoch(
1506 SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_millis() as i64,
1507 );
1508 let mut num_deleted = 0;
1509 for id in key_ids_to_check.iter().filter(|kt| kt.1 < curr_time).map(|kt| kt.0) {
1510 if Self::mark_unreferenced(&tx, id)? {
1511 num_deleted += 1;
1512 }
1513 }
1514 Ok(num_deleted)
1515 })
1516 .context("In delete_expired_attestation_keys: ")
1517 }
1518
1519 /// Counts the number of keys that will expire by the provided epoch date and the number of
1520 /// keys not currently assigned to a domain.
1521 pub fn get_attestation_pool_status(
1522 &mut self,
1523 date: i64,
1524 km_uuid: &Uuid,
1525 ) -> Result<AttestationPoolStatus> {
1526 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1527 let mut stmt = tx.prepare(
1528 "SELECT data
1529 FROM persistent.keymetadata
1530 WHERE tag = ? AND keyentryid IN
1531 (SELECT id
1532 FROM persistent.keyentry
1533 WHERE alias IS NOT NULL
1534 AND key_type = ?
1535 AND km_uuid = ?
1536 AND state = ?);",
1537 )?;
1538 let times = stmt
1539 .query_map(
1540 params![
1541 KeyMetaData::AttestationExpirationDate,
1542 KeyType::Attestation,
1543 km_uuid,
1544 KeyLifeCycle::Live
1545 ],
1546 |row| Ok(row.get(0)?),
1547 )?
1548 .collect::<rusqlite::Result<Vec<DateTime>>>()
1549 .context("Failed to execute metadata statement")?;
1550 let expiring =
1551 times.iter().filter(|time| time < &&DateTime::from_millis_epoch(date)).count()
1552 as i32;
1553 stmt = tx.prepare(
1554 "SELECT alias, domain
1555 FROM persistent.keyentry
1556 WHERE key_type = ? AND km_uuid = ? AND state = ?;",
1557 )?;
1558 let rows = stmt
1559 .query_map(params![KeyType::Attestation, km_uuid, KeyLifeCycle::Live], |row| {
1560 Ok((row.get(0)?, row.get(1)?))
1561 })?
1562 .collect::<rusqlite::Result<Vec<(Option<String>, Option<u32>)>>>()
1563 .context("Failed to execute keyentry statement")?;
1564 let mut unassigned = 0i32;
1565 let mut attested = 0i32;
1566 let total = rows.len() as i32;
1567 for (alias, domain) in rows {
1568 match (alias, domain) {
1569 (Some(_alias), None) => {
1570 attested += 1;
1571 unassigned += 1;
1572 }
1573 (Some(_alias), Some(_domain)) => {
1574 attested += 1;
1575 }
1576 _ => {}
1577 }
1578 }
1579 Ok(AttestationPoolStatus { expiring, unassigned, attested, total })
1580 })
1581 .context("In get_attestation_pool_status: ")
1582 }
1583
1584 /// Fetches the private key and corresponding certificate chain assigned to a
1585 /// domain/namespace pair. Will either return nothing if the domain/namespace is
1586 /// not assigned, or one CertificateChain.
1587 pub fn retrieve_attestation_key_and_cert_chain(
1588 &mut self,
1589 domain: Domain,
1590 namespace: i64,
1591 km_uuid: &Uuid,
1592 ) -> Result<Option<CertificateChain>> {
1593 match domain {
1594 Domain::APP | Domain::SELINUX => {}
1595 _ => {
1596 return Err(KsError::sys())
1597 .context(format!("Domain {:?} must be either App or SELinux.", domain));
1598 }
1599 }
1600 let mut stmt = self.conn.prepare(
1601 "SELECT subcomponent_type, blob
1602 FROM persistent.blobentry
1603 WHERE keyentryid IN
1604 (SELECT id
1605 FROM persistent.keyentry
1606 WHERE key_type = ?
1607 AND domain = ?
1608 AND namespace = ?
1609 AND state = ?
1610 AND km_uuid = ?);",
1611 )?;
1612 let rows = stmt
1613 .query_map(
1614 params![
1615 KeyType::Attestation,
1616 domain.0 as u32,
1617 namespace,
1618 KeyLifeCycle::Live,
1619 km_uuid
1620 ],
1621 |row| Ok((row.get(0)?, row.get(1)?)),
1622 )?
1623 .collect::<rusqlite::Result<Vec<(SubComponentType, Vec<u8>)>>>()
1624 .context("In retrieve_attestation_key_and_cert_chain: query failed.")?;
1625 if rows.is_empty() {
1626 return Ok(None);
1627 } else if rows.len() != 2 {
1628 return Err(KsError::sys()).context(format!(
1629 concat!(
1630 "In retrieve_attestation_key_and_cert_chain: Expected to get a single attestation",
1631 "key chain but instead got {}."),
1632 rows.len()
1633 ));
1634 }
1635 let mut km_blob: Vec<u8> = Vec::new();
1636 let mut cert_chain_blob: Vec<u8> = Vec::new();
1637 for row in rows {
1638 let sub_type: SubComponentType = row.0;
1639 match sub_type {
1640 SubComponentType::KEY_BLOB => {
1641 km_blob = row.1;
1642 }
1643 SubComponentType::CERT_CHAIN => {
1644 cert_chain_blob = row.1;
1645 }
1646 _ => Err(KsError::sys()).context("Unknown or incorrect subcomponent type.")?,
1647 }
1648 }
1649 Ok(Some(CertificateChain {
1650 private_key: ZVec::try_from(km_blob)?,
1651 cert_chain: ZVec::try_from(cert_chain_blob)?,
1652 }))
1653 }
1654
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001655 /// Updates the alias column of the given key id `newid` with the given alias,
1656 /// and atomically, removes the alias, domain, and namespace from another row
1657 /// with the same alias-domain-namespace tuple if such row exits.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001658 /// Returns Ok(true) if an old key was marked unreferenced as a hint to the garbage
1659 /// collector.
1660 fn rebind_alias(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001661 tx: &Transaction,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001662 newid: &KeyIdGuard,
Joel Galenson33c04ad2020-08-03 11:04:38 -07001663 alias: &str,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001664 domain: &Domain,
1665 namespace: &i64,
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001666 ) -> Result<bool> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001667 match *domain {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001668 Domain::APP | Domain::SELINUX => {}
Joel Galenson33c04ad2020-08-03 11:04:38 -07001669 _ => {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001670 return Err(KsError::sys()).context(format!(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001671 "In rebind_alias: Domain {:?} must be either App or SELinux.",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001672 domain
1673 ));
Joel Galenson33c04ad2020-08-03 11:04:38 -07001674 }
1675 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001676 let updated = tx
1677 .execute(
1678 "UPDATE persistent.keyentry
1679 SET alias = NULL, domain = NULL, namespace = NULL, state = ?
Joel Galenson33c04ad2020-08-03 11:04:38 -07001680 WHERE alias = ? AND domain = ? AND namespace = ?;",
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001681 params![KeyLifeCycle::Unreferenced, alias, domain.0 as u32, namespace],
1682 )
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001683 .context("In rebind_alias: Failed to rebind existing entry.")?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07001684 let result = tx
1685 .execute(
1686 "UPDATE persistent.keyentry
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001687 SET alias = ?, state = ?
1688 WHERE id = ? AND domain = ? AND namespace = ? AND state = ?;",
1689 params![
1690 alias,
1691 KeyLifeCycle::Live,
1692 newid.0,
1693 domain.0 as u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001694 *namespace,
Max Bires8e93d2b2021-01-14 13:17:59 -08001695 KeyLifeCycle::Existing,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001696 ],
Joel Galenson33c04ad2020-08-03 11:04:38 -07001697 )
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001698 .context("In rebind_alias: Failed to set alias.")?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07001699 if result != 1 {
Joel Galenson33c04ad2020-08-03 11:04:38 -07001700 return Err(KsError::sys()).context(format!(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001701 "In rebind_alias: Expected to update a single entry but instead updated {}.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07001702 result
1703 ));
1704 }
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001705 Ok(updated != 0)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001706 }
1707
1708 /// Store a new key in a single transaction.
1709 /// The function creates a new key entry, populates the blob, key parameter, and metadata
1710 /// fields, and rebinds the given alias to the new key.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001711 /// The boolean returned is a hint for the garbage collector. If true, a key was replaced,
1712 /// is now unreferenced and needs to be collected.
Janis Danisevskis66784c42021-01-27 08:40:25 -08001713 pub fn store_new_key(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001714 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001715 key: &KeyDescriptor,
1716 params: &[KeyParameter],
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001717 blob: &[u8],
Max Bires8e93d2b2021-01-14 13:17:59 -08001718 cert_info: &CertificateInfo,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001719 metadata: &KeyMetaData,
Max Bires8e93d2b2021-01-14 13:17:59 -08001720 km_uuid: &Uuid,
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001721 ) -> Result<(bool, KeyIdGuard)> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001722 let (alias, domain, namespace) = match key {
1723 KeyDescriptor { alias: Some(alias), domain: Domain::APP, nspace, blob: None }
1724 | KeyDescriptor { alias: Some(alias), domain: Domain::SELINUX, nspace, blob: None } => {
1725 (alias, key.domain, nspace)
1726 }
1727 _ => {
1728 return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT))
1729 .context("In store_new_key: Need alias and domain must be APP or SELINUX.")
1730 }
1731 };
1732 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001733 let key_id = Self::create_key_entry_internal(tx, &domain, namespace, km_uuid)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001734 .context("Trying to create new key entry.")?;
Janis Danisevskis377d1002021-01-27 19:07:48 -08001735 Self::set_blob_internal(tx, key_id.id(), SubComponentType::KEY_BLOB, Some(blob))
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001736 .context("Trying to insert the key blob.")?;
Max Bires8e93d2b2021-01-14 13:17:59 -08001737 if let Some(cert) = &cert_info.cert {
Janis Danisevskis377d1002021-01-27 19:07:48 -08001738 Self::set_blob_internal(tx, key_id.id(), SubComponentType::CERT, Some(&cert))
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001739 .context("Trying to insert the certificate.")?;
1740 }
Max Bires8e93d2b2021-01-14 13:17:59 -08001741 if let Some(cert_chain) = &cert_info.cert_chain {
Janis Danisevskis377d1002021-01-27 19:07:48 -08001742 Self::set_blob_internal(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001743 tx,
1744 key_id.id(),
1745 SubComponentType::CERT_CHAIN,
Janis Danisevskis377d1002021-01-27 19:07:48 -08001746 Some(&cert_chain),
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001747 )
1748 .context("Trying to insert the certificate chain.")?;
1749 }
1750 Self::insert_keyparameter_internal(tx, &key_id, params)
1751 .context("Trying to insert key parameters.")?;
Janis Danisevskis377d1002021-01-27 19:07:48 -08001752 metadata.store_in_db(key_id.id(), tx).context("Trying to insert key metadata.")?;
Janis Danisevskis66784c42021-01-27 08:40:25 -08001753 let need_gc = Self::rebind_alias(tx, &key_id, &alias, &domain, namespace)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001754 .context("Trying to rebind alias.")?;
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001755 Ok((need_gc, key_id))
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001756 })
1757 .context("In store_new_key.")
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001758 }
1759
Janis Danisevskis377d1002021-01-27 19:07:48 -08001760 /// Store a new certificate
1761 /// The function creates a new key entry, populates the blob field and metadata, and rebinds
1762 /// the given alias to the new cert.
Max Bires8e93d2b2021-01-14 13:17:59 -08001763 pub fn store_new_certificate(
1764 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001765 key: &KeyDescriptor,
Max Bires8e93d2b2021-01-14 13:17:59 -08001766 cert: &[u8],
1767 km_uuid: &Uuid,
1768 ) -> Result<KeyIdGuard> {
Janis Danisevskis377d1002021-01-27 19:07:48 -08001769 let (alias, domain, namespace) = match key {
1770 KeyDescriptor { alias: Some(alias), domain: Domain::APP, nspace, blob: None }
1771 | KeyDescriptor { alias: Some(alias), domain: Domain::SELINUX, nspace, blob: None } => {
1772 (alias, key.domain, nspace)
1773 }
1774 _ => {
1775 return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT)).context(
1776 "In store_new_certificate: Need alias and domain must be APP or SELINUX.",
1777 )
1778 }
1779 };
1780 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001781 let key_id = Self::create_key_entry_internal(tx, &domain, namespace, km_uuid)
Janis Danisevskis377d1002021-01-27 19:07:48 -08001782 .context("Trying to create new key entry.")?;
1783
1784 Self::set_blob_internal(tx, key_id.id(), SubComponentType::CERT_CHAIN, Some(cert))
1785 .context("Trying to insert certificate.")?;
1786
1787 let mut metadata = KeyMetaData::new();
1788 metadata.add(KeyMetaEntry::CreationDate(
1789 DateTime::now().context("Trying to make creation time.")?,
1790 ));
1791
1792 metadata.store_in_db(key_id.id(), tx).context("Trying to insert key metadata.")?;
1793
Janis Danisevskis66784c42021-01-27 08:40:25 -08001794 Self::rebind_alias(tx, &key_id, &alias, &domain, namespace)
Janis Danisevskis377d1002021-01-27 19:07:48 -08001795 .context("Trying to rebind alias.")?;
1796 Ok(key_id)
1797 })
1798 .context("In store_new_certificate.")
1799 }
1800
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001801 // Helper function loading the key_id given the key descriptor
1802 // tuple comprising domain, namespace, and alias.
1803 // Requires a valid transaction.
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001804 fn load_key_entry_id(tx: &Transaction, key: &KeyDescriptor, key_type: KeyType) -> Result<i64> {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001805 let alias = key
1806 .alias
1807 .as_ref()
1808 .map_or_else(|| Err(KsError::sys()), Ok)
1809 .context("In load_key_entry_id: Alias must be specified.")?;
1810 let mut stmt = tx
1811 .prepare(
1812 "SELECT id FROM persistent.keyentry
1813 WHERE
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001814 key_type = ?
1815 AND domain = ?
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001816 AND namespace = ?
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001817 AND alias = ?
1818 AND state = ?;",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001819 )
1820 .context("In load_key_entry_id: Failed to select from keyentry table.")?;
1821 let mut rows = stmt
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001822 .query(params![key_type, key.domain.0 as u32, key.nspace, alias, KeyLifeCycle::Live])
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001823 .context("In load_key_entry_id: Failed to read from keyentry table.")?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08001824 db_utils::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001825 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001826 .get(0)
1827 .context("Failed to unpack id.")
1828 })
1829 .context("In load_key_entry_id.")
1830 }
1831
1832 /// This helper function completes the access tuple of a key, which is required
1833 /// to perform access control. The strategy depends on the `domain` field in the
1834 /// key descriptor.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001835 /// * Domain::SELINUX: The access tuple is complete and this function only loads
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001836 /// the key_id for further processing.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001837 /// * Domain::APP: Like Domain::SELINUX, but the tuple is completed by `caller_uid`
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001838 /// which serves as the namespace.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001839 /// * Domain::GRANT: The grant table is queried for the `key_id` and the
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001840 /// `access_vector`.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001841 /// * Domain::KEY_ID: The keyentry table is queried for the owning `domain` and
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001842 /// `namespace`.
1843 /// In each case the information returned is sufficient to perform the access
1844 /// check and the key id can be used to load further key artifacts.
1845 fn load_access_tuple(
1846 tx: &Transaction,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001847 key: &KeyDescriptor,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001848 key_type: KeyType,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001849 caller_uid: u32,
1850 ) -> Result<(i64, KeyDescriptor, Option<KeyPermSet>)> {
1851 match key.domain {
1852 // Domain App or SELinux. In this case we load the key_id from
1853 // the keyentry database for further loading of key components.
1854 // We already have the full access tuple to perform access control.
1855 // The only distinction is that we use the caller_uid instead
1856 // of the caller supplied namespace if the domain field is
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001857 // Domain::APP.
1858 Domain::APP | Domain::SELINUX => {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001859 let mut access_key = key.clone();
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001860 if access_key.domain == Domain::APP {
1861 access_key.nspace = caller_uid as i64;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001862 }
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001863 let key_id = Self::load_key_entry_id(&tx, &access_key, key_type)
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001864 .with_context(|| format!("With key.domain = {:?}.", access_key.domain))?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001865
1866 Ok((key_id, access_key, None))
1867 }
1868
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001869 // Domain::GRANT. In this case we load the key_id and the access_vector
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001870 // from the grant table.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001871 Domain::GRANT => {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001872 let mut stmt = tx
1873 .prepare(
Janis Danisevskisbf15d732020-12-08 10:35:26 -08001874 "SELECT keyentryid, access_vector FROM persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001875 WHERE grantee = ? AND id = ?;",
1876 )
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001877 .context("Domain::GRANT prepare statement failed")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001878 let mut rows = stmt
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001879 .query(params![caller_uid as i64, key.nspace])
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001880 .context("Domain:Grant: query failed.")?;
1881 let (key_id, access_vector): (i64, i32) =
Janis Danisevskisbf15d732020-12-08 10:35:26 -08001882 db_utils::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001883 let r =
1884 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001885 Ok((
1886 r.get(0).context("Failed to unpack key_id.")?,
1887 r.get(1).context("Failed to unpack access_vector.")?,
1888 ))
1889 })
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001890 .context("Domain::GRANT.")?;
Janis Danisevskis66784c42021-01-27 08:40:25 -08001891 Ok((key_id, key.clone(), Some(access_vector.into())))
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001892 }
1893
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001894 // Domain::KEY_ID. In this case we load the domain and namespace from the
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001895 // keyentry database because we need them for access control.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001896 Domain::KEY_ID => {
Janis Danisevskis45760022021-01-19 16:34:10 -08001897 let (domain, namespace): (Domain, i64) = {
1898 let mut stmt = tx
1899 .prepare(
1900 "SELECT domain, namespace FROM persistent.keyentry
1901 WHERE
1902 id = ?
1903 AND state = ?;",
1904 )
1905 .context("Domain::KEY_ID: prepare statement failed")?;
1906 let mut rows = stmt
1907 .query(params![key.nspace, KeyLifeCycle::Live])
1908 .context("Domain::KEY_ID: query failed.")?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08001909 db_utils::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001910 let r =
1911 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001912 Ok((
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001913 Domain(r.get(0).context("Failed to unpack domain.")?),
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001914 r.get(1).context("Failed to unpack namespace.")?,
1915 ))
1916 })
Janis Danisevskis45760022021-01-19 16:34:10 -08001917 .context("Domain::KEY_ID.")?
1918 };
1919
1920 // We may use a key by id after loading it by grant.
1921 // In this case we have to check if the caller has a grant for this particular
1922 // key. We can skip this if we already know that the caller is the owner.
1923 // But we cannot know this if domain is anything but App. E.g. in the case
1924 // of Domain::SELINUX we have to speculatively check for grants because we have to
1925 // consult the SEPolicy before we know if the caller is the owner.
1926 let access_vector: Option<KeyPermSet> =
1927 if domain != Domain::APP || namespace != caller_uid as i64 {
1928 let access_vector: Option<i32> = tx
1929 .query_row(
1930 "SELECT access_vector FROM persistent.grant
1931 WHERE grantee = ? AND keyentryid = ?;",
1932 params![caller_uid as i64, key.nspace],
1933 |row| row.get(0),
1934 )
1935 .optional()
1936 .context("Domain::KEY_ID: query grant failed.")?;
1937 access_vector.map(|p| p.into())
1938 } else {
1939 None
1940 };
1941
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001942 let key_id = key.nspace;
Janis Danisevskis66784c42021-01-27 08:40:25 -08001943 let mut access_key: KeyDescriptor = key.clone();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001944 access_key.domain = domain;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001945 access_key.nspace = namespace;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001946
Janis Danisevskis45760022021-01-19 16:34:10 -08001947 Ok((key_id, access_key, access_vector))
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001948 }
1949 _ => Err(anyhow!(KsError::sys())),
1950 }
1951 }
1952
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001953 fn load_blob_components(
1954 key_id: i64,
1955 load_bits: KeyEntryLoadBits,
1956 tx: &Transaction,
Janis Danisevskis377d1002021-01-27 19:07:48 -08001957 ) -> Result<(bool, Option<Vec<u8>>, Option<Vec<u8>>, Option<Vec<u8>>)> {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001958 let mut stmt = tx
1959 .prepare(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001960 "SELECT MAX(id), subcomponent_type, blob FROM persistent.blobentry
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001961 WHERE keyentryid = ? GROUP BY subcomponent_type;",
1962 )
1963 .context("In load_blob_components: prepare statement failed.")?;
1964
1965 let mut rows =
1966 stmt.query(params![key_id]).context("In load_blob_components: query failed.")?;
1967
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001968 let mut km_blob: Option<Vec<u8>> = None;
1969 let mut cert_blob: Option<Vec<u8>> = None;
1970 let mut cert_chain_blob: Option<Vec<u8>> = None;
Janis Danisevskis377d1002021-01-27 19:07:48 -08001971 let mut has_km_blob: bool = false;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08001972 db_utils::with_rows_extract_all(&mut rows, |row| {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001973 let sub_type: SubComponentType =
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001974 row.get(1).context("Failed to extract subcomponent_type.")?;
Janis Danisevskis377d1002021-01-27 19:07:48 -08001975 has_km_blob = has_km_blob || sub_type == SubComponentType::KEY_BLOB;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001976 match (sub_type, load_bits.load_public(), load_bits.load_km()) {
1977 (SubComponentType::KEY_BLOB, _, true) => {
1978 km_blob = Some(row.get(2).context("Failed to extract KM blob.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001979 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001980 (SubComponentType::CERT, true, _) => {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001981 cert_blob =
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001982 Some(row.get(2).context("Failed to extract public certificate blob.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001983 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001984 (SubComponentType::CERT_CHAIN, true, _) => {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001985 cert_chain_blob =
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001986 Some(row.get(2).context("Failed to extract certificate chain blob.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001987 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001988 (SubComponentType::CERT, _, _)
1989 | (SubComponentType::CERT_CHAIN, _, _)
1990 | (SubComponentType::KEY_BLOB, _, _) => {}
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001991 _ => Err(KsError::sys()).context("Unknown subcomponent type.")?,
1992 }
1993 Ok(())
1994 })
1995 .context("In load_blob_components.")?;
1996
Janis Danisevskis377d1002021-01-27 19:07:48 -08001997 Ok((has_km_blob, km_blob, cert_blob, cert_chain_blob))
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001998 }
1999
2000 fn load_key_parameters(key_id: i64, tx: &Transaction) -> Result<Vec<KeyParameter>> {
2001 let mut stmt = tx
2002 .prepare(
2003 "SELECT tag, data, security_level from persistent.keyparameter
2004 WHERE keyentryid = ?;",
2005 )
2006 .context("In load_key_parameters: prepare statement failed.")?;
2007
2008 let mut parameters: Vec<KeyParameter> = Vec::new();
2009
2010 let mut rows =
2011 stmt.query(params![key_id]).context("In load_key_parameters: query failed.")?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002012 db_utils::with_rows_extract_all(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002013 let tag = Tag(row.get(0).context("Failed to read tag.")?);
2014 let sec_level = SecurityLevel(row.get(2).context("Failed to read sec_level.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002015 parameters.push(
2016 KeyParameter::new_from_sql(tag, &SqlField::new(1, &row), sec_level)
2017 .context("Failed to read KeyParameter.")?,
2018 );
2019 Ok(())
2020 })
2021 .context("In load_key_parameters.")?;
2022
2023 Ok(parameters)
2024 }
2025
Qi Wub9433b52020-12-01 14:52:46 +08002026 /// Decrements the usage count of a limited use key. This function first checks whether the
2027 /// usage has been exhausted, if not, decreases the usage count. If the usage count reaches
2028 /// zero, the key also gets marked unreferenced and scheduled for deletion.
2029 /// Returns Ok(true) if the key was marked unreferenced as a hint to the garbage collector.
2030 pub fn check_and_update_key_usage_count(&mut self, key_id: i64) -> Result<bool> {
2031 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2032 let limit: Option<i32> = tx
2033 .query_row(
2034 "SELECT data FROM persistent.keyparameter WHERE keyentryid = ? AND tag = ?;",
2035 params![key_id, Tag::USAGE_COUNT_LIMIT.0],
2036 |row| row.get(0),
2037 )
2038 .optional()
2039 .context("Trying to load usage count")?;
2040
2041 let limit = limit
2042 .ok_or(KsError::Km(ErrorCode::INVALID_KEY_BLOB))
2043 .context("The Key no longer exists. Key is exhausted.")?;
2044
2045 tx.execute(
2046 "UPDATE persistent.keyparameter
2047 SET data = data - 1
2048 WHERE keyentryid = ? AND tag = ? AND data > 0;",
2049 params![key_id, Tag::USAGE_COUNT_LIMIT.0],
2050 )
2051 .context("Failed to update key usage count.")?;
2052
2053 match limit {
2054 1 => Self::mark_unreferenced(tx, key_id)
2055 .context("Trying to mark limited use key for deletion."),
2056 0 => Err(KsError::Km(ErrorCode::INVALID_KEY_BLOB)).context("Key is exhausted."),
2057 _ => Ok(false),
2058 }
2059 })
2060 .context("In check_and_update_key_usage_count.")
2061 }
2062
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002063 /// Load a key entry by the given key descriptor.
2064 /// It uses the `check_permission` callback to verify if the access is allowed
2065 /// given the key access tuple read from the database using `load_access_tuple`.
2066 /// With `load_bits` the caller may specify which blobs shall be loaded from
2067 /// the blob database.
2068 pub fn load_key_entry(
2069 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002070 key: &KeyDescriptor,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002071 key_type: KeyType,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002072 load_bits: KeyEntryLoadBits,
2073 caller_uid: u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002074 check_permission: impl Fn(&KeyDescriptor, Option<KeyPermSet>) -> Result<()>,
2075 ) -> Result<(KeyIdGuard, KeyEntry)> {
2076 loop {
2077 match self.load_key_entry_internal(
2078 key,
2079 key_type,
2080 load_bits,
2081 caller_uid,
2082 &check_permission,
2083 ) {
2084 Ok(result) => break Ok(result),
2085 Err(e) => {
2086 if Self::is_locked_error(&e) {
2087 std::thread::sleep(std::time::Duration::from_micros(500));
2088 continue;
2089 } else {
2090 return Err(e).context("In load_key_entry.");
2091 }
2092 }
2093 }
2094 }
2095 }
2096
2097 fn load_key_entry_internal(
2098 &mut self,
2099 key: &KeyDescriptor,
2100 key_type: KeyType,
2101 load_bits: KeyEntryLoadBits,
2102 caller_uid: u32,
2103 check_permission: &impl Fn(&KeyDescriptor, Option<KeyPermSet>) -> Result<()>,
Janis Danisevskisaec14592020-11-12 09:41:49 -08002104 ) -> Result<(KeyIdGuard, KeyEntry)> {
2105 // KEY ID LOCK 1/2
2106 // If we got a key descriptor with a key id we can get the lock right away.
2107 // Otherwise we have to defer it until we know the key id.
2108 let key_id_guard = match key.domain {
2109 Domain::KEY_ID => Some(KEY_ID_LOCK.get(key.nspace)),
2110 _ => None,
2111 };
2112
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002113 let tx = self
2114 .conn
Janis Danisevskisaec14592020-11-12 09:41:49 -08002115 .unchecked_transaction()
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002116 .context("In load_key_entry: Failed to initialize transaction.")?;
2117
2118 // Load the key_id and complete the access control tuple.
2119 let (key_id, access_key_descriptor, access_vector) =
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002120 Self::load_access_tuple(&tx, key, key_type, caller_uid)
2121 .context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002122
2123 // Perform access control. It is vital that we return here if the permission is denied.
2124 // So do not touch that '?' at the end.
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002125 check_permission(&access_key_descriptor, access_vector).context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002126
Janis Danisevskisaec14592020-11-12 09:41:49 -08002127 // KEY ID LOCK 2/2
2128 // If we did not get a key id lock by now, it was because we got a key descriptor
2129 // without a key id. At this point we got the key id, so we can try and get a lock.
2130 // However, we cannot block here, because we are in the middle of the transaction.
2131 // So first we try to get the lock non blocking. If that fails, we roll back the
2132 // transaction and block until we get the lock. After we successfully got the lock,
2133 // we start a new transaction and load the access tuple again.
2134 //
2135 // We don't need to perform access control again, because we already established
2136 // that the caller had access to the given key. But we need to make sure that the
2137 // key id still exists. So we have to load the key entry by key id this time.
2138 let (key_id_guard, tx) = match key_id_guard {
2139 None => match KEY_ID_LOCK.try_get(key_id) {
2140 None => {
2141 // Roll back the transaction.
2142 tx.rollback().context("In load_key_entry: Failed to roll back transaction.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002143
Janis Danisevskisaec14592020-11-12 09:41:49 -08002144 // Block until we have a key id lock.
2145 let key_id_guard = KEY_ID_LOCK.get(key_id);
2146
2147 // Create a new transaction.
Janis Danisevskis66784c42021-01-27 08:40:25 -08002148 let tx = self
2149 .conn
2150 .unchecked_transaction()
2151 .context("In load_key_entry: Failed to initialize transaction.")?;
Janis Danisevskisaec14592020-11-12 09:41:49 -08002152
2153 Self::load_access_tuple(
2154 &tx,
2155 // This time we have to load the key by the retrieved key id, because the
2156 // alias may have been rebound after we rolled back the transaction.
Janis Danisevskis66784c42021-01-27 08:40:25 -08002157 &KeyDescriptor {
Janis Danisevskisaec14592020-11-12 09:41:49 -08002158 domain: Domain::KEY_ID,
2159 nspace: key_id,
2160 ..Default::default()
2161 },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002162 key_type,
Janis Danisevskisaec14592020-11-12 09:41:49 -08002163 caller_uid,
2164 )
2165 .context("In load_key_entry. (deferred key lock)")?;
2166 (key_id_guard, tx)
2167 }
2168 Some(l) => (l, tx),
2169 },
2170 Some(key_id_guard) => (key_id_guard, tx),
2171 };
2172
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002173 let key_entry = Self::load_key_components(&tx, load_bits, key_id_guard.id())
2174 .context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002175
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002176 tx.commit().context("In load_key_entry: Failed to commit transaction.")?;
2177
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002178 Ok((key_id_guard, key_entry))
2179 }
2180
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002181 fn mark_unreferenced(tx: &Transaction, key_id: i64) -> Result<bool> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002182 let updated = tx
2183 .execute(
2184 "UPDATE persistent.keyentry SET state = ? WHERE id = ?;",
2185 params![KeyLifeCycle::Unreferenced, key_id],
2186 )
2187 .context("In mark_unreferenced: Failed to update state of key entry.")?;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002188 tx.execute("DELETE from persistent.grant WHERE keyentryid = ?;", params![key_id])
2189 .context("In mark_unreferenced: Failed to drop grants.")?;
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002190 Ok(updated != 0)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002191 }
2192
2193 /// Marks the given key as unreferenced and removes all of the grants to this key.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002194 /// Returns Ok(true) if a key was marked unreferenced as a hint for the garbage collector.
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002195 pub fn unbind_key(
2196 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002197 key: &KeyDescriptor,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002198 key_type: KeyType,
2199 caller_uid: u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002200 check_permission: impl Fn(&KeyDescriptor, Option<KeyPermSet>) -> Result<()>,
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002201 ) -> Result<bool> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002202 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2203 let (key_id, access_key_descriptor, access_vector) =
2204 Self::load_access_tuple(tx, key, key_type, caller_uid)
2205 .context("Trying to get access tuple.")?;
2206
2207 // Perform access control. It is vital that we return here if the permission is denied.
2208 // So do not touch that '?' at the end.
2209 check_permission(&access_key_descriptor, access_vector)
2210 .context("While checking permission.")?;
2211
2212 Self::mark_unreferenced(tx, key_id).context("Trying to mark the key unreferenced.")
2213 })
2214 .context("In unbind_key.")
2215 }
2216
Max Bires8e93d2b2021-01-14 13:17:59 -08002217 fn get_key_km_uuid(tx: &Transaction, key_id: i64) -> Result<Uuid> {
2218 tx.query_row(
2219 "SELECT km_uuid FROM persistent.keyentry WHERE id = ?",
2220 params![key_id],
2221 |row| row.get(0),
2222 )
2223 .context("In get_key_km_uuid.")
2224 }
2225
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002226 fn load_key_components(
2227 tx: &Transaction,
2228 load_bits: KeyEntryLoadBits,
2229 key_id: i64,
2230 ) -> Result<KeyEntry> {
2231 let metadata = KeyMetaData::load_from_db(key_id, &tx).context("In load_key_components.")?;
2232
Janis Danisevskis377d1002021-01-27 19:07:48 -08002233 let (has_km_blob, km_blob, cert_blob, cert_chain_blob) =
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002234 Self::load_blob_components(key_id, load_bits, &tx)
2235 .context("In load_key_components.")?;
2236
Max Bires8e93d2b2021-01-14 13:17:59 -08002237 let parameters = Self::load_key_parameters(key_id, &tx)
2238 .context("In load_key_components: Trying to load key parameters.")?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002239
Max Bires8e93d2b2021-01-14 13:17:59 -08002240 let km_uuid = Self::get_key_km_uuid(&tx, key_id)
2241 .context("In load_key_components: Trying to get KM uuid.")?;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002242
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002243 Ok(KeyEntry {
2244 id: key_id,
2245 km_blob,
2246 cert: cert_blob,
2247 cert_chain: cert_chain_blob,
Max Bires8e93d2b2021-01-14 13:17:59 -08002248 km_uuid,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002249 parameters,
2250 metadata,
Janis Danisevskis377d1002021-01-27 19:07:48 -08002251 pure_cert: !has_km_blob,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002252 })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002253 }
2254
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002255 /// Returns a list of KeyDescriptors in the selected domain/namespace.
2256 /// The key descriptors will have the domain, nspace, and alias field set.
2257 /// Domain must be APP or SELINUX, the caller must make sure of that.
2258 pub fn list(&mut self, domain: Domain, namespace: i64) -> Result<Vec<KeyDescriptor>> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002259 self.with_transaction(TransactionBehavior::Deferred, |tx| {
2260 let mut stmt = tx
2261 .prepare(
2262 "SELECT alias FROM persistent.keyentry
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002263 WHERE domain = ? AND namespace = ? AND alias IS NOT NULL AND state = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08002264 )
2265 .context("In list: Failed to prepare.")?;
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002266
Janis Danisevskis66784c42021-01-27 08:40:25 -08002267 let mut rows = stmt
2268 .query(params![domain.0 as u32, namespace, KeyLifeCycle::Live])
2269 .context("In list: Failed to query.")?;
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002270
Janis Danisevskis66784c42021-01-27 08:40:25 -08002271 let mut descriptors: Vec<KeyDescriptor> = Vec::new();
2272 db_utils::with_rows_extract_all(&mut rows, |row| {
2273 descriptors.push(KeyDescriptor {
2274 domain,
2275 nspace: namespace,
2276 alias: Some(row.get(0).context("Trying to extract alias.")?),
2277 blob: None,
2278 });
2279 Ok(())
2280 })
2281 .context("In list: Failed to extract rows.")?;
2282 Ok(descriptors)
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002283 })
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002284 }
2285
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002286 /// Adds a grant to the grant table.
2287 /// Like `load_key_entry` this function loads the access tuple before
2288 /// it uses the callback for a permission check. Upon success,
2289 /// it inserts the `grantee_uid`, `key_id`, and `access_vector` into the
2290 /// grant table. The new row will have a randomized id, which is used as
2291 /// grant id in the namespace field of the resulting KeyDescriptor.
2292 pub fn grant(
2293 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002294 key: &KeyDescriptor,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002295 caller_uid: u32,
2296 grantee_uid: u32,
2297 access_vector: KeyPermSet,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002298 check_permission: impl Fn(&KeyDescriptor, &KeyPermSet) -> Result<()>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002299 ) -> Result<KeyDescriptor> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002300 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2301 // Load the key_id and complete the access control tuple.
2302 // We ignore the access vector here because grants cannot be granted.
2303 // The access vector returned here expresses the permissions the
2304 // grantee has if key.domain == Domain::GRANT. But this vector
2305 // cannot include the grant permission by design, so there is no way the
2306 // subsequent permission check can pass.
2307 // We could check key.domain == Domain::GRANT and fail early.
2308 // But even if we load the access tuple by grant here, the permission
2309 // check denies the attempt to create a grant by grant descriptor.
2310 let (key_id, access_key_descriptor, _) =
2311 Self::load_access_tuple(&tx, key, KeyType::Client, caller_uid)
2312 .context("In grant")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002313
Janis Danisevskis66784c42021-01-27 08:40:25 -08002314 // Perform access control. It is vital that we return here if the permission
2315 // was denied. So do not touch that '?' at the end of the line.
2316 // This permission check checks if the caller has the grant permission
2317 // for the given key and in addition to all of the permissions
2318 // expressed in `access_vector`.
2319 check_permission(&access_key_descriptor, &access_vector)
2320 .context("In grant: check_permission failed.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002321
Janis Danisevskis66784c42021-01-27 08:40:25 -08002322 let grant_id = if let Some(grant_id) = tx
2323 .query_row(
2324 "SELECT id FROM persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002325 WHERE keyentryid = ? AND grantee = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08002326 params![key_id, grantee_uid],
2327 |row| row.get(0),
2328 )
2329 .optional()
2330 .context("In grant: Failed get optional existing grant id.")?
2331 {
2332 tx.execute(
2333 "UPDATE persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002334 SET access_vector = ?
2335 WHERE id = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08002336 params![i32::from(access_vector), grant_id],
Joel Galenson845f74b2020-09-09 14:11:55 -07002337 )
Janis Danisevskis66784c42021-01-27 08:40:25 -08002338 .context("In grant: Failed to update existing grant.")?;
2339 grant_id
2340 } else {
2341 Self::insert_with_retry(|id| {
2342 tx.execute(
2343 "INSERT INTO persistent.grant (id, grantee, keyentryid, access_vector)
2344 VALUES (?, ?, ?, ?);",
2345 params![id, grantee_uid, key_id, i32::from(access_vector)],
2346 )
2347 })
2348 .context("In grant")?
2349 };
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002350
Janis Danisevskis66784c42021-01-27 08:40:25 -08002351 Ok(KeyDescriptor { domain: Domain::GRANT, nspace: grant_id, alias: None, blob: None })
2352 })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002353 }
2354
2355 /// This function checks permissions like `grant` and `load_key_entry`
2356 /// before removing a grant from the grant table.
2357 pub fn ungrant(
2358 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002359 key: &KeyDescriptor,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002360 caller_uid: u32,
2361 grantee_uid: u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002362 check_permission: impl Fn(&KeyDescriptor) -> Result<()>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002363 ) -> Result<()> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002364 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2365 // Load the key_id and complete the access control tuple.
2366 // We ignore the access vector here because grants cannot be granted.
2367 let (key_id, access_key_descriptor, _) =
2368 Self::load_access_tuple(&tx, key, KeyType::Client, caller_uid)
2369 .context("In ungrant.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002370
Janis Danisevskis66784c42021-01-27 08:40:25 -08002371 // Perform access control. We must return here if the permission
2372 // was denied. So do not touch the '?' at the end of this line.
2373 check_permission(&access_key_descriptor)
2374 .context("In grant: check_permission failed.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002375
Janis Danisevskis66784c42021-01-27 08:40:25 -08002376 tx.execute(
2377 "DELETE FROM persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002378 WHERE keyentryid = ? AND grantee = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08002379 params![key_id, grantee_uid],
2380 )
2381 .context("Failed to delete grant.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002382
Janis Danisevskis66784c42021-01-27 08:40:25 -08002383 Ok(())
2384 })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002385 }
2386
Joel Galenson845f74b2020-09-09 14:11:55 -07002387 // Generates a random id and passes it to the given function, which will
2388 // try to insert it into a database. If that insertion fails, retry;
2389 // otherwise return the id.
2390 fn insert_with_retry(inserter: impl Fn(i64) -> rusqlite::Result<usize>) -> Result<i64> {
2391 loop {
2392 let newid: i64 = random();
2393 match inserter(newid) {
2394 // If the id already existed, try again.
2395 Err(rusqlite::Error::SqliteFailure(
2396 libsqlite3_sys::Error {
2397 code: libsqlite3_sys::ErrorCode::ConstraintViolation,
2398 extended_code: libsqlite3_sys::SQLITE_CONSTRAINT_UNIQUE,
2399 },
2400 _,
2401 )) => (),
2402 Err(e) => {
2403 return Err(e).context("In insert_with_retry: failed to insert into database.")
2404 }
2405 _ => return Ok(newid),
2406 }
2407 }
2408 }
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002409
2410 /// Insert or replace the auth token based on the UNIQUE constraint of the auth token table
2411 pub fn insert_auth_token(&mut self, auth_token: &HardwareAuthToken) -> Result<()> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002412 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2413 tx.execute(
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002414 "INSERT OR REPLACE INTO perboot.authtoken (challenge, user_id, auth_id,
2415 authenticator_type, timestamp, mac, time_received) VALUES(?, ?, ?, ?, ?, ?, ?);",
2416 params![
2417 auth_token.challenge,
2418 auth_token.userId,
2419 auth_token.authenticatorId,
2420 auth_token.authenticatorType.0 as i32,
2421 auth_token.timestamp.milliSeconds as i64,
2422 auth_token.mac,
2423 MonotonicRawTime::now(),
2424 ],
2425 )
2426 .context("In insert_auth_token: failed to insert auth token into the database")?;
Janis Danisevskis66784c42021-01-27 08:40:25 -08002427 Ok(())
2428 })
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002429 }
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002430
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002431 /// Find the newest auth token matching the given predicate.
2432 pub fn find_auth_token_entry<F>(
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002433 &mut self,
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002434 p: F,
2435 ) -> Result<Option<(AuthTokenEntry, MonotonicRawTime)>>
2436 where
2437 F: Fn(&AuthTokenEntry) -> bool,
2438 {
2439 self.with_transaction(TransactionBehavior::Deferred, |tx| {
2440 let mut stmt = tx
2441 .prepare("SELECT * from perboot.authtoken ORDER BY time_received DESC;")
2442 .context("Prepare statement failed.")?;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002443
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002444 let mut rows = stmt.query(NO_PARAMS).context("Failed to query.")?;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002445
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002446 while let Some(row) = rows.next().context("Failed to get next row.")? {
2447 let entry = AuthTokenEntry::new(
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002448 HardwareAuthToken {
2449 challenge: row.get(1)?,
2450 userId: row.get(2)?,
2451 authenticatorId: row.get(3)?,
2452 authenticatorType: HardwareAuthenticatorType(row.get(4)?),
2453 timestamp: Timestamp { milliSeconds: row.get(5)? },
2454 mac: row.get(6)?,
2455 },
2456 row.get(7)?,
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002457 );
2458 if p(&entry) {
2459 return Ok(Some((
2460 entry,
2461 Self::get_last_off_body(tx)
2462 .context("In find_auth_token_entry: Trying to get last off body")?,
2463 )));
2464 }
2465 }
2466 Ok(None)
2467 })
2468 .context("In find_auth_token_entry.")
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002469 }
2470
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002471 /// Insert last_off_body into the metadata table at the initialization of auth token table
Janis Danisevskis66784c42021-01-27 08:40:25 -08002472 pub fn insert_last_off_body(&mut self, last_off_body: MonotonicRawTime) -> Result<()> {
2473 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2474 tx.execute(
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002475 "INSERT OR REPLACE INTO perboot.metadata (key, value) VALUES (?, ?);",
2476 params!["last_off_body", last_off_body],
2477 )
2478 .context("In insert_last_off_body: failed to insert.")?;
Janis Danisevskis66784c42021-01-27 08:40:25 -08002479 Ok(())
2480 })
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002481 }
2482
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002483 /// Update last_off_body when on_device_off_body is called
Janis Danisevskis66784c42021-01-27 08:40:25 -08002484 pub fn update_last_off_body(&mut self, last_off_body: MonotonicRawTime) -> Result<()> {
2485 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2486 tx.execute(
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002487 "UPDATE perboot.metadata SET value = ? WHERE key = ?;",
2488 params![last_off_body, "last_off_body"],
2489 )
2490 .context("In update_last_off_body: failed to update.")?;
Janis Danisevskis66784c42021-01-27 08:40:25 -08002491 Ok(())
2492 })
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002493 }
2494
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002495 /// Get last_off_body time when finding auth tokens
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002496 fn get_last_off_body(tx: &Transaction) -> Result<MonotonicRawTime> {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002497 tx.query_row(
2498 "SELECT value from perboot.metadata WHERE key = ?;",
2499 params!["last_off_body"],
2500 |row| Ok(row.get(0)?),
2501 )
2502 .context("In get_last_off_body: query_row failed.")
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002503 }
Joel Galenson26f4d012020-07-17 14:57:21 -07002504}
2505
2506#[cfg(test)]
2507mod tests {
2508
2509 use super::*;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002510 use crate::key_parameter::{
2511 Algorithm, BlockMode, Digest, EcCurve, HardwareAuthenticatorType, KeyOrigin, KeyParameter,
2512 KeyParameterValue, KeyPurpose, PaddingMode, SecurityLevel,
2513 };
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002514 use crate::key_perm_set;
2515 use crate::permission::{KeyPerm, KeyPermSet};
Janis Danisevskis2a8330a2021-01-20 15:34:26 -08002516 use keystore2_test_utils::TempDir;
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002517 use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
2518 HardwareAuthToken::HardwareAuthToken,
2519 HardwareAuthenticatorType::HardwareAuthenticatorType as kmhw_authenticator_type,
Janis Danisevskisc3a496b2021-01-05 10:37:22 -08002520 };
2521 use android_hardware_security_secureclock::aidl::android::hardware::security::secureclock::{
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002522 Timestamp::Timestamp,
2523 };
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002524 use rusqlite::NO_PARAMS;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002525 use rusqlite::{Error, TransactionBehavior};
Joel Galenson0891bc12020-07-20 10:37:03 -07002526 use std::cell::RefCell;
Janis Danisevskisaec14592020-11-12 09:41:49 -08002527 use std::sync::atomic::{AtomicU8, Ordering};
2528 use std::sync::Arc;
2529 use std::thread;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002530 use std::time::{Duration, SystemTime};
Janis Danisevskis66784c42021-01-27 08:40:25 -08002531 #[cfg(disabled)]
2532 use std::time::Instant;
Joel Galenson0891bc12020-07-20 10:37:03 -07002533
Janis Danisevskis4df44f42020-08-26 14:40:03 -07002534 fn new_test_db() -> Result<KeystoreDB> {
2535 let conn = KeystoreDB::make_connection("file::memory:", "file::memory:")?;
2536
Janis Danisevskis66784c42021-01-27 08:40:25 -08002537 let mut db = KeystoreDB { conn };
2538 db.with_transaction(TransactionBehavior::Immediate, |tx| {
2539 KeystoreDB::init_tables(tx).context("Failed to initialize tables.")
2540 })?;
2541 Ok(db)
Janis Danisevskis4df44f42020-08-26 14:40:03 -07002542 }
2543
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002544 fn rebind_alias(
2545 db: &mut KeystoreDB,
2546 newid: &KeyIdGuard,
2547 alias: &str,
2548 domain: Domain,
2549 namespace: i64,
2550 ) -> Result<bool> {
2551 db.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002552 KeystoreDB::rebind_alias(tx, newid, alias, &domain, &namespace)
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002553 })
2554 .context("In rebind_alias.")
2555 }
2556
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002557 #[test]
2558 fn datetime() -> Result<()> {
2559 let conn = Connection::open_in_memory()?;
2560 conn.execute("CREATE TABLE test (ts DATETIME);", NO_PARAMS)?;
2561 let now = SystemTime::now();
2562 let duration = Duration::from_secs(1000);
2563 let then = now.checked_sub(duration).unwrap();
2564 let soon = now.checked_add(duration).unwrap();
2565 conn.execute(
2566 "INSERT INTO test (ts) VALUES (?), (?), (?);",
2567 params![DateTime::try_from(now)?, DateTime::try_from(then)?, DateTime::try_from(soon)?],
2568 )?;
2569 let mut stmt = conn.prepare("SELECT ts FROM test ORDER BY ts ASC;")?;
2570 let mut rows = stmt.query(NO_PARAMS)?;
2571 assert_eq!(DateTime::try_from(then)?, rows.next()?.unwrap().get(0)?);
2572 assert_eq!(DateTime::try_from(now)?, rows.next()?.unwrap().get(0)?);
2573 assert_eq!(DateTime::try_from(soon)?, rows.next()?.unwrap().get(0)?);
2574 assert!(rows.next()?.is_none());
2575 assert!(DateTime::try_from(then)? < DateTime::try_from(now)?);
2576 assert!(DateTime::try_from(then)? < DateTime::try_from(soon)?);
2577 assert!(DateTime::try_from(now)? < DateTime::try_from(soon)?);
2578 Ok(())
2579 }
2580
Joel Galenson0891bc12020-07-20 10:37:03 -07002581 // Ensure that we're using the "injected" random function, not the real one.
2582 #[test]
2583 fn test_mocked_random() {
2584 let rand1 = random();
2585 let rand2 = random();
2586 let rand3 = random();
2587 if rand1 == rand2 {
2588 assert_eq!(rand2 + 1, rand3);
2589 } else {
2590 assert_eq!(rand1 + 1, rand2);
2591 assert_eq!(rand2, rand3);
2592 }
2593 }
Joel Galenson26f4d012020-07-17 14:57:21 -07002594
Joel Galenson26f4d012020-07-17 14:57:21 -07002595 // Test that we have the correct tables.
2596 #[test]
2597 fn test_tables() -> Result<()> {
Janis Danisevskis4df44f42020-08-26 14:40:03 -07002598 let db = new_test_db()?;
Joel Galenson26f4d012020-07-17 14:57:21 -07002599 let tables = db
2600 .conn
Joel Galenson2aab4432020-07-22 15:27:57 -07002601 .prepare("SELECT name from persistent.sqlite_master WHERE type='table' ORDER BY name;")?
Joel Galenson26f4d012020-07-17 14:57:21 -07002602 .query_map(params![], |row| row.get(0))?
2603 .collect::<rusqlite::Result<Vec<String>>>()?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002604 assert_eq!(tables.len(), 5);
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002605 assert_eq!(tables[0], "blobentry");
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002606 assert_eq!(tables[1], "grant");
2607 assert_eq!(tables[2], "keyentry");
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002608 assert_eq!(tables[3], "keymetadata");
2609 assert_eq!(tables[4], "keyparameter");
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002610 let tables = db
2611 .conn
2612 .prepare("SELECT name from perboot.sqlite_master WHERE type='table' ORDER BY name;")?
2613 .query_map(params![], |row| row.get(0))?
2614 .collect::<rusqlite::Result<Vec<String>>>()?;
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002615
2616 assert_eq!(tables.len(), 2);
2617 assert_eq!(tables[0], "authtoken");
2618 assert_eq!(tables[1], "metadata");
Joel Galenson2aab4432020-07-22 15:27:57 -07002619 Ok(())
2620 }
2621
2622 #[test]
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002623 fn test_auth_token_table_invariant() -> Result<()> {
2624 let mut db = new_test_db()?;
2625 let auth_token1 = HardwareAuthToken {
2626 challenge: i64::MAX,
2627 userId: 200,
2628 authenticatorId: 200,
2629 authenticatorType: kmhw_authenticator_type(kmhw_authenticator_type::PASSWORD.0),
2630 timestamp: Timestamp { milliSeconds: 500 },
2631 mac: String::from("mac").into_bytes(),
2632 };
2633 db.insert_auth_token(&auth_token1)?;
2634 let auth_tokens_returned = get_auth_tokens(&mut db)?;
2635 assert_eq!(auth_tokens_returned.len(), 1);
2636
2637 // insert another auth token with the same values for the columns in the UNIQUE constraint
2638 // of the auth token table and different value for timestamp
2639 let auth_token2 = HardwareAuthToken {
2640 challenge: i64::MAX,
2641 userId: 200,
2642 authenticatorId: 200,
2643 authenticatorType: kmhw_authenticator_type(kmhw_authenticator_type::PASSWORD.0),
2644 timestamp: Timestamp { milliSeconds: 600 },
2645 mac: String::from("mac").into_bytes(),
2646 };
2647
2648 db.insert_auth_token(&auth_token2)?;
2649 let mut auth_tokens_returned = get_auth_tokens(&mut db)?;
2650 assert_eq!(auth_tokens_returned.len(), 1);
2651
2652 if let Some(auth_token) = auth_tokens_returned.pop() {
2653 assert_eq!(auth_token.auth_token.timestamp.milliSeconds, 600);
2654 }
2655
2656 // insert another auth token with the different values for the columns in the UNIQUE
2657 // constraint of the auth token table
2658 let auth_token3 = HardwareAuthToken {
2659 challenge: i64::MAX,
2660 userId: 201,
2661 authenticatorId: 200,
2662 authenticatorType: kmhw_authenticator_type(kmhw_authenticator_type::PASSWORD.0),
2663 timestamp: Timestamp { milliSeconds: 600 },
2664 mac: String::from("mac").into_bytes(),
2665 };
2666
2667 db.insert_auth_token(&auth_token3)?;
2668 let auth_tokens_returned = get_auth_tokens(&mut db)?;
2669 assert_eq!(auth_tokens_returned.len(), 2);
2670
2671 Ok(())
2672 }
2673
2674 // utility function for test_auth_token_table_invariant()
2675 fn get_auth_tokens(db: &mut KeystoreDB) -> Result<Vec<AuthTokenEntry>> {
2676 let mut stmt = db.conn.prepare("SELECT * from perboot.authtoken;")?;
2677
2678 let auth_token_entries: Vec<AuthTokenEntry> = stmt
2679 .query_map(NO_PARAMS, |row| {
2680 Ok(AuthTokenEntry::new(
2681 HardwareAuthToken {
2682 challenge: row.get(1)?,
2683 userId: row.get(2)?,
2684 authenticatorId: row.get(3)?,
2685 authenticatorType: HardwareAuthenticatorType(row.get(4)?),
2686 timestamp: Timestamp { milliSeconds: row.get(5)? },
2687 mac: row.get(6)?,
2688 },
2689 row.get(7)?,
2690 ))
2691 })?
2692 .collect::<Result<Vec<AuthTokenEntry>, Error>>()?;
2693 Ok(auth_token_entries)
2694 }
2695
2696 #[test]
Joel Galenson2aab4432020-07-22 15:27:57 -07002697 fn test_persistence_for_files() -> Result<()> {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002698 let temp_dir = TempDir::new("persistent_db_test")?;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002699 let mut db = KeystoreDB::new(temp_dir.path())?;
Joel Galenson2aab4432020-07-22 15:27:57 -07002700
Janis Danisevskis66784c42021-01-27 08:40:25 -08002701 db.create_key_entry(&Domain::APP, &100, &KEYSTORE_UUID)?;
Joel Galenson2aab4432020-07-22 15:27:57 -07002702 let entries = get_keyentry(&db)?;
2703 assert_eq!(entries.len(), 1);
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002704
2705 let db = KeystoreDB::new(temp_dir.path())?;
Joel Galenson2aab4432020-07-22 15:27:57 -07002706
2707 let entries_new = get_keyentry(&db)?;
2708 assert_eq!(entries, entries_new);
2709 Ok(())
2710 }
2711
2712 #[test]
Joel Galenson0891bc12020-07-20 10:37:03 -07002713 fn test_create_key_entry() -> Result<()> {
Max Bires8e93d2b2021-01-14 13:17:59 -08002714 fn extractor(ke: &KeyEntryRow) -> (Domain, i64, Option<&str>, Uuid) {
2715 (ke.domain.unwrap(), ke.namespace.unwrap(), ke.alias.as_deref(), ke.km_uuid.unwrap())
Joel Galenson0891bc12020-07-20 10:37:03 -07002716 }
2717
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002718 let mut db = new_test_db()?;
Joel Galenson0891bc12020-07-20 10:37:03 -07002719
Janis Danisevskis66784c42021-01-27 08:40:25 -08002720 db.create_key_entry(&Domain::APP, &100, &KEYSTORE_UUID)?;
2721 db.create_key_entry(&Domain::SELINUX, &101, &KEYSTORE_UUID)?;
Joel Galenson0891bc12020-07-20 10:37:03 -07002722
2723 let entries = get_keyentry(&db)?;
2724 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08002725 assert_eq!(extractor(&entries[0]), (Domain::APP, 100, None, KEYSTORE_UUID));
2726 assert_eq!(extractor(&entries[1]), (Domain::SELINUX, 101, None, KEYSTORE_UUID));
Joel Galenson0891bc12020-07-20 10:37:03 -07002727
2728 // Test that we must pass in a valid Domain.
2729 check_result_is_error_containing_string(
Janis Danisevskis66784c42021-01-27 08:40:25 -08002730 db.create_key_entry(&Domain::GRANT, &102, &KEYSTORE_UUID),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002731 "Domain Domain(1) must be either App or SELinux.",
Joel Galenson0891bc12020-07-20 10:37:03 -07002732 );
2733 check_result_is_error_containing_string(
Janis Danisevskis66784c42021-01-27 08:40:25 -08002734 db.create_key_entry(&Domain::BLOB, &103, &KEYSTORE_UUID),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002735 "Domain Domain(3) must be either App or SELinux.",
Joel Galenson0891bc12020-07-20 10:37:03 -07002736 );
2737 check_result_is_error_containing_string(
Janis Danisevskis66784c42021-01-27 08:40:25 -08002738 db.create_key_entry(&Domain::KEY_ID, &104, &KEYSTORE_UUID),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002739 "Domain Domain(4) must be either App or SELinux.",
Joel Galenson0891bc12020-07-20 10:37:03 -07002740 );
2741
2742 Ok(())
2743 }
2744
Joel Galenson33c04ad2020-08-03 11:04:38 -07002745 #[test]
Max Bires2b2e6562020-09-22 11:22:36 -07002746 fn test_add_unsigned_key() -> Result<()> {
2747 let mut db = new_test_db()?;
2748 let public_key: Vec<u8> = vec![0x01, 0x02, 0x03];
2749 let private_key: Vec<u8> = vec![0x04, 0x05, 0x06];
2750 let raw_public_key: Vec<u8> = vec![0x07, 0x08, 0x09];
2751 db.create_attestation_key_entry(
2752 &public_key,
2753 &raw_public_key,
2754 &private_key,
2755 &KEYSTORE_UUID,
2756 )?;
2757 let keys = db.fetch_unsigned_attestation_keys(5, &KEYSTORE_UUID)?;
2758 assert_eq!(keys.len(), 1);
2759 assert_eq!(keys[0], public_key);
2760 Ok(())
2761 }
2762
2763 #[test]
2764 fn test_store_signed_attestation_certificate_chain() -> Result<()> {
2765 let mut db = new_test_db()?;
2766 let expiration_date: i64 = 20;
2767 let namespace: i64 = 30;
2768 let base_byte: u8 = 1;
2769 let loaded_values =
2770 load_attestation_key_pool(&mut db, expiration_date, namespace, base_byte)?;
2771 let chain =
2772 db.retrieve_attestation_key_and_cert_chain(Domain::APP, namespace, &KEYSTORE_UUID)?;
2773 assert_eq!(true, chain.is_some());
2774 let cert_chain = chain.unwrap();
2775 assert_eq!(cert_chain.private_key.to_vec(), loaded_values[2]);
2776 assert_eq!(cert_chain.cert_chain.to_vec(), loaded_values[1]);
2777 Ok(())
2778 }
2779
2780 #[test]
2781 fn test_get_attestation_pool_status() -> Result<()> {
2782 let mut db = new_test_db()?;
2783 let namespace: i64 = 30;
2784 load_attestation_key_pool(
2785 &mut db, 10, /* expiration */
2786 namespace, 0x01, /* base_byte */
2787 )?;
2788 load_attestation_key_pool(&mut db, 20 /* expiration */, namespace + 1, 0x02)?;
2789 load_attestation_key_pool(&mut db, 40 /* expiration */, namespace + 2, 0x03)?;
2790 let mut status = db.get_attestation_pool_status(9 /* expiration */, &KEYSTORE_UUID)?;
2791 assert_eq!(status.expiring, 0);
2792 assert_eq!(status.attested, 3);
2793 assert_eq!(status.unassigned, 0);
2794 assert_eq!(status.total, 3);
2795 assert_eq!(
2796 db.get_attestation_pool_status(15 /* expiration */, &KEYSTORE_UUID)?.expiring,
2797 1
2798 );
2799 assert_eq!(
2800 db.get_attestation_pool_status(25 /* expiration */, &KEYSTORE_UUID)?.expiring,
2801 2
2802 );
2803 assert_eq!(
2804 db.get_attestation_pool_status(60 /* expiration */, &KEYSTORE_UUID)?.expiring,
2805 3
2806 );
2807 let public_key: Vec<u8> = vec![0x01, 0x02, 0x03];
2808 let private_key: Vec<u8> = vec![0x04, 0x05, 0x06];
2809 let raw_public_key: Vec<u8> = vec![0x07, 0x08, 0x09];
2810 let cert_chain: Vec<u8> = vec![0x0a, 0x0b, 0x0c];
2811 db.create_attestation_key_entry(
2812 &public_key,
2813 &raw_public_key,
2814 &private_key,
2815 &KEYSTORE_UUID,
2816 )?;
2817 status = db.get_attestation_pool_status(0 /* expiration */, &KEYSTORE_UUID)?;
2818 assert_eq!(status.attested, 3);
2819 assert_eq!(status.unassigned, 0);
2820 assert_eq!(status.total, 4);
2821 db.store_signed_attestation_certificate_chain(
2822 &raw_public_key,
2823 &cert_chain,
2824 20,
2825 &KEYSTORE_UUID,
2826 )?;
2827 status = db.get_attestation_pool_status(0 /* expiration */, &KEYSTORE_UUID)?;
2828 assert_eq!(status.attested, 4);
2829 assert_eq!(status.unassigned, 1);
2830 assert_eq!(status.total, 4);
2831 Ok(())
2832 }
2833
2834 #[test]
2835 fn test_remove_expired_certs() -> Result<()> {
2836 let mut db = new_test_db()?;
2837 let expiration_date: i64 =
2838 SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_millis() as i64 + 10000;
2839 let namespace: i64 = 30;
2840 let namespace_del1: i64 = 45;
2841 let namespace_del2: i64 = 60;
2842 let entry_values = load_attestation_key_pool(
2843 &mut db,
2844 expiration_date,
2845 namespace,
2846 0x01, /* base_byte */
2847 )?;
2848 load_attestation_key_pool(&mut db, 45, namespace_del1, 0x02)?;
2849 load_attestation_key_pool(&mut db, 60, namespace_del2, 0x03)?;
2850 assert_eq!(db.delete_expired_attestation_keys()?, 2);
2851
2852 let mut cert_chain =
2853 db.retrieve_attestation_key_and_cert_chain(Domain::APP, namespace, &KEYSTORE_UUID)?;
2854 assert_eq!(true, cert_chain.is_some());
2855 let value = cert_chain.unwrap();
2856 assert_eq!(entry_values[1], value.cert_chain.to_vec());
2857 assert_eq!(entry_values[2], value.private_key.to_vec());
2858
2859 cert_chain = db.retrieve_attestation_key_and_cert_chain(
2860 Domain::APP,
2861 namespace_del1,
2862 &KEYSTORE_UUID,
2863 )?;
2864 assert_eq!(false, cert_chain.is_some());
2865 cert_chain = db.retrieve_attestation_key_and_cert_chain(
2866 Domain::APP,
2867 namespace_del2,
2868 &KEYSTORE_UUID,
2869 )?;
2870 assert_eq!(false, cert_chain.is_some());
2871
2872 let mut option_entry = db.get_unreferenced_key()?;
2873 assert_eq!(true, option_entry.is_some());
2874 let (key_guard, _) = option_entry.unwrap();
2875 db.purge_key_entry(key_guard)?;
2876
2877 option_entry = db.get_unreferenced_key()?;
2878 assert_eq!(true, option_entry.is_some());
2879 let (key_guard, _) = option_entry.unwrap();
2880 db.purge_key_entry(key_guard)?;
2881
2882 option_entry = db.get_unreferenced_key()?;
2883 assert_eq!(false, option_entry.is_some());
2884 Ok(())
2885 }
2886
2887 #[test]
Joel Galenson33c04ad2020-08-03 11:04:38 -07002888 fn test_rebind_alias() -> Result<()> {
Max Bires8e93d2b2021-01-14 13:17:59 -08002889 fn extractor(
2890 ke: &KeyEntryRow,
2891 ) -> (Option<Domain>, Option<i64>, Option<&str>, Option<Uuid>) {
2892 (ke.domain, ke.namespace, ke.alias.as_deref(), ke.km_uuid)
Joel Galenson33c04ad2020-08-03 11:04:38 -07002893 }
2894
Janis Danisevskis4df44f42020-08-26 14:40:03 -07002895 let mut db = new_test_db()?;
Janis Danisevskis66784c42021-01-27 08:40:25 -08002896 db.create_key_entry(&Domain::APP, &42, &KEYSTORE_UUID)?;
2897 db.create_key_entry(&Domain::APP, &42, &KEYSTORE_UUID)?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07002898 let entries = get_keyentry(&db)?;
2899 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08002900 assert_eq!(
2901 extractor(&entries[0]),
2902 (Some(Domain::APP), Some(42), None, Some(KEYSTORE_UUID))
2903 );
2904 assert_eq!(
2905 extractor(&entries[1]),
2906 (Some(Domain::APP), Some(42), None, Some(KEYSTORE_UUID))
2907 );
Joel Galenson33c04ad2020-08-03 11:04:38 -07002908
2909 // Test that the first call to rebind_alias sets the alias.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002910 rebind_alias(&mut db, &KEY_ID_LOCK.get(entries[0].id), "foo", Domain::APP, 42)?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07002911 let entries = get_keyentry(&db)?;
2912 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08002913 assert_eq!(
2914 extractor(&entries[0]),
2915 (Some(Domain::APP), Some(42), Some("foo"), Some(KEYSTORE_UUID))
2916 );
2917 assert_eq!(
2918 extractor(&entries[1]),
2919 (Some(Domain::APP), Some(42), None, Some(KEYSTORE_UUID))
2920 );
Joel Galenson33c04ad2020-08-03 11:04:38 -07002921
2922 // Test that the second call to rebind_alias also empties the old one.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002923 rebind_alias(&mut db, &KEY_ID_LOCK.get(entries[1].id), "foo", Domain::APP, 42)?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07002924 let entries = get_keyentry(&db)?;
2925 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08002926 assert_eq!(extractor(&entries[0]), (None, None, None, Some(KEYSTORE_UUID)));
2927 assert_eq!(
2928 extractor(&entries[1]),
2929 (Some(Domain::APP), Some(42), Some("foo"), Some(KEYSTORE_UUID))
2930 );
Joel Galenson33c04ad2020-08-03 11:04:38 -07002931
2932 // Test that we must pass in a valid Domain.
2933 check_result_is_error_containing_string(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002934 rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::GRANT, 42),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002935 "Domain Domain(1) must be either App or SELinux.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07002936 );
2937 check_result_is_error_containing_string(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002938 rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::BLOB, 42),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002939 "Domain Domain(3) must be either App or SELinux.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07002940 );
2941 check_result_is_error_containing_string(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002942 rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::KEY_ID, 42),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002943 "Domain Domain(4) must be either App or SELinux.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07002944 );
2945
2946 // Test that we correctly handle setting an alias for something that does not exist.
2947 check_result_is_error_containing_string(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002948 rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::SELINUX, 42),
Joel Galenson33c04ad2020-08-03 11:04:38 -07002949 "Expected to update a single entry but instead updated 0",
2950 );
2951 // Test that we correctly abort the transaction in this case.
2952 let entries = get_keyentry(&db)?;
2953 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08002954 assert_eq!(extractor(&entries[0]), (None, None, None, Some(KEYSTORE_UUID)));
2955 assert_eq!(
2956 extractor(&entries[1]),
2957 (Some(Domain::APP), Some(42), Some("foo"), Some(KEYSTORE_UUID))
2958 );
Joel Galenson33c04ad2020-08-03 11:04:38 -07002959
2960 Ok(())
2961 }
2962
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002963 #[test]
2964 fn test_grant_ungrant() -> Result<()> {
2965 const CALLER_UID: u32 = 15;
2966 const GRANTEE_UID: u32 = 12;
2967 const SELINUX_NAMESPACE: i64 = 7;
2968
2969 let mut db = new_test_db()?;
2970 db.conn.execute(
Max Bires8e93d2b2021-01-14 13:17:59 -08002971 "INSERT INTO persistent.keyentry (id, key_type, domain, namespace, alias, state, km_uuid)
2972 VALUES (1, 0, 0, 15, 'key', 1, ?), (2, 0, 2, 7, 'yek', 1, ?);",
2973 params![KEYSTORE_UUID, KEYSTORE_UUID],
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002974 )?;
2975 let app_key = KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002976 domain: super::Domain::APP,
2977 nspace: 0,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002978 alias: Some("key".to_string()),
2979 blob: None,
2980 };
2981 const PVEC1: KeyPermSet = key_perm_set![KeyPerm::use_(), KeyPerm::get_info()];
2982 const PVEC2: KeyPermSet = key_perm_set![KeyPerm::use_()];
2983
2984 // Reset totally predictable random number generator in case we
2985 // are not the first test running on this thread.
2986 reset_random();
2987 let next_random = 0i64;
2988
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002989 let app_granted_key = db
Janis Danisevskis66784c42021-01-27 08:40:25 -08002990 .grant(&app_key, CALLER_UID, GRANTEE_UID, PVEC1, |k, a| {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002991 assert_eq!(*a, PVEC1);
2992 assert_eq!(
2993 *k,
2994 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002995 domain: super::Domain::APP,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002996 // namespace must be set to the caller_uid.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002997 nspace: CALLER_UID as i64,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002998 alias: Some("key".to_string()),
2999 blob: None,
3000 }
3001 );
3002 Ok(())
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003003 })
3004 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003005
3006 assert_eq!(
3007 app_granted_key,
3008 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003009 domain: super::Domain::GRANT,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003010 // The grantid is next_random due to the mock random number generator.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003011 nspace: next_random,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003012 alias: None,
3013 blob: None,
3014 }
3015 );
3016
3017 let selinux_key = KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003018 domain: super::Domain::SELINUX,
3019 nspace: SELINUX_NAMESPACE,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003020 alias: Some("yek".to_string()),
3021 blob: None,
3022 };
3023
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003024 let selinux_granted_key = db
Janis Danisevskis66784c42021-01-27 08:40:25 -08003025 .grant(&selinux_key, CALLER_UID, 12, PVEC1, |k, a| {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003026 assert_eq!(*a, PVEC1);
3027 assert_eq!(
3028 *k,
3029 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003030 domain: super::Domain::SELINUX,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003031 // namespace must be the supplied SELinux
3032 // namespace.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003033 nspace: SELINUX_NAMESPACE,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003034 alias: Some("yek".to_string()),
3035 blob: None,
3036 }
3037 );
3038 Ok(())
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003039 })
3040 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003041
3042 assert_eq!(
3043 selinux_granted_key,
3044 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003045 domain: super::Domain::GRANT,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003046 // The grantid is next_random + 1 due to the mock random number generator.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003047 nspace: next_random + 1,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003048 alias: None,
3049 blob: None,
3050 }
3051 );
3052
3053 // This should update the existing grant with PVEC2.
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003054 let selinux_granted_key = db
Janis Danisevskis66784c42021-01-27 08:40:25 -08003055 .grant(&selinux_key, CALLER_UID, 12, PVEC2, |k, a| {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003056 assert_eq!(*a, PVEC2);
3057 assert_eq!(
3058 *k,
3059 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003060 domain: super::Domain::SELINUX,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003061 // namespace must be the supplied SELinux
3062 // namespace.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003063 nspace: SELINUX_NAMESPACE,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003064 alias: Some("yek".to_string()),
3065 blob: None,
3066 }
3067 );
3068 Ok(())
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003069 })
3070 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003071
3072 assert_eq!(
3073 selinux_granted_key,
3074 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003075 domain: super::Domain::GRANT,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003076 // Same grant id as before. The entry was only updated.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003077 nspace: next_random + 1,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003078 alias: None,
3079 blob: None,
3080 }
3081 );
3082
3083 {
3084 // Limiting scope of stmt, because it borrows db.
3085 let mut stmt = db
3086 .conn
Janis Danisevskisbf15d732020-12-08 10:35:26 -08003087 .prepare("SELECT id, grantee, keyentryid, access_vector FROM persistent.grant;")?;
Janis Danisevskisee10b5f2020-09-22 16:42:35 -07003088 let mut rows =
3089 stmt.query_map::<(i64, u32, i64, KeyPermSet), _, _>(NO_PARAMS, |row| {
3090 Ok((
3091 row.get(0)?,
3092 row.get(1)?,
3093 row.get(2)?,
3094 KeyPermSet::from(row.get::<_, i32>(3)?),
3095 ))
3096 })?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003097
3098 let r = rows.next().unwrap().unwrap();
Janis Danisevskisee10b5f2020-09-22 16:42:35 -07003099 assert_eq!(r, (next_random, GRANTEE_UID, 1, PVEC1));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003100 let r = rows.next().unwrap().unwrap();
Janis Danisevskisee10b5f2020-09-22 16:42:35 -07003101 assert_eq!(r, (next_random + 1, GRANTEE_UID, 2, PVEC2));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003102 assert!(rows.next().is_none());
3103 }
3104
3105 debug_dump_keyentry_table(&mut db)?;
3106 println!("app_key {:?}", app_key);
3107 println!("selinux_key {:?}", selinux_key);
3108
Janis Danisevskis66784c42021-01-27 08:40:25 -08003109 db.ungrant(&app_key, CALLER_UID, GRANTEE_UID, |_| Ok(()))?;
3110 db.ungrant(&selinux_key, CALLER_UID, GRANTEE_UID, |_| Ok(()))?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003111
3112 Ok(())
3113 }
3114
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003115 static TEST_KEY_BLOB: &[u8] = b"my test blob";
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003116 static TEST_CERT_BLOB: &[u8] = b"my test cert";
3117 static TEST_CERT_CHAIN_BLOB: &[u8] = b"my test cert_chain";
3118
3119 #[test]
Janis Danisevskis377d1002021-01-27 19:07:48 -08003120 fn test_set_blob() -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003121 let key_id = KEY_ID_LOCK.get(3000);
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003122 let mut db = new_test_db()?;
Janis Danisevskis377d1002021-01-27 19:07:48 -08003123 db.set_blob(&key_id, SubComponentType::KEY_BLOB, Some(TEST_KEY_BLOB))?;
3124 db.set_blob(&key_id, SubComponentType::CERT, Some(TEST_CERT_BLOB))?;
3125 db.set_blob(&key_id, SubComponentType::CERT_CHAIN, Some(TEST_CERT_CHAIN_BLOB))?;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003126 drop(key_id);
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003127
3128 let mut stmt = db.conn.prepare(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003129 "SELECT subcomponent_type, keyentryid, blob FROM persistent.blobentry
3130 ORDER BY subcomponent_type ASC;",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003131 )?;
3132 let mut rows = stmt
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003133 .query_map::<(SubComponentType, i64, Vec<u8>), _, _>(NO_PARAMS, |row| {
3134 Ok((row.get(0)?, row.get(1)?, row.get(2)?))
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003135 })?;
3136 let r = rows.next().unwrap().unwrap();
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003137 assert_eq!(r, (SubComponentType::KEY_BLOB, 3000, TEST_KEY_BLOB.to_vec()));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003138 let r = rows.next().unwrap().unwrap();
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003139 assert_eq!(r, (SubComponentType::CERT, 3000, TEST_CERT_BLOB.to_vec()));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003140 let r = rows.next().unwrap().unwrap();
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003141 assert_eq!(r, (SubComponentType::CERT_CHAIN, 3000, TEST_CERT_CHAIN_BLOB.to_vec()));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003142
3143 Ok(())
3144 }
3145
3146 static TEST_ALIAS: &str = "my super duper key";
3147
3148 #[test]
3149 fn test_insert_and_load_full_keyentry_domain_app() -> Result<()> {
3150 let mut db = new_test_db()?;
Qi Wub9433b52020-12-01 14:52:46 +08003151 let key_id = make_test_key_entry(&mut db, Domain::APP, 1, TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08003152 .context("test_insert_and_load_full_keyentry_domain_app")?
3153 .0;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003154 let (_key_guard, key_entry) = db
3155 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003156 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003157 domain: Domain::APP,
3158 nspace: 0,
3159 alias: Some(TEST_ALIAS.to_string()),
3160 blob: None,
3161 },
3162 KeyType::Client,
3163 KeyEntryLoadBits::BOTH,
3164 1,
3165 |_k, _av| Ok(()),
3166 )
3167 .unwrap();
Qi Wub9433b52020-12-01 14:52:46 +08003168 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003169
3170 db.unbind_key(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003171 &KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003172 domain: Domain::APP,
3173 nspace: 0,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003174 alias: Some(TEST_ALIAS.to_string()),
3175 blob: None,
3176 },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003177 KeyType::Client,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003178 1,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003179 |_, _| Ok(()),
3180 )
3181 .unwrap();
3182
3183 assert_eq!(
3184 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
3185 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003186 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003187 domain: Domain::APP,
3188 nspace: 0,
3189 alias: Some(TEST_ALIAS.to_string()),
3190 blob: None,
3191 },
3192 KeyType::Client,
3193 KeyEntryLoadBits::NONE,
3194 1,
3195 |_k, _av| Ok(()),
3196 )
3197 .unwrap_err()
3198 .root_cause()
3199 .downcast_ref::<KsError>()
3200 );
3201
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003202 Ok(())
3203 }
3204
3205 #[test]
Janis Danisevskis377d1002021-01-27 19:07:48 -08003206 fn test_insert_and_load_certificate_entry_domain_app() -> Result<()> {
3207 let mut db = new_test_db()?;
3208
3209 db.store_new_certificate(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003210 &KeyDescriptor {
Janis Danisevskis377d1002021-01-27 19:07:48 -08003211 domain: Domain::APP,
3212 nspace: 1,
3213 alias: Some(TEST_ALIAS.to_string()),
3214 blob: None,
3215 },
3216 TEST_CERT_BLOB,
Max Bires8e93d2b2021-01-14 13:17:59 -08003217 &KEYSTORE_UUID,
Janis Danisevskis377d1002021-01-27 19:07:48 -08003218 )
3219 .expect("Trying to insert cert.");
3220
3221 let (_key_guard, mut key_entry) = db
3222 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003223 &KeyDescriptor {
Janis Danisevskis377d1002021-01-27 19:07:48 -08003224 domain: Domain::APP,
3225 nspace: 1,
3226 alias: Some(TEST_ALIAS.to_string()),
3227 blob: None,
3228 },
3229 KeyType::Client,
3230 KeyEntryLoadBits::PUBLIC,
3231 1,
3232 |_k, _av| Ok(()),
3233 )
3234 .expect("Trying to read certificate entry.");
3235
3236 assert!(key_entry.pure_cert());
3237 assert!(key_entry.cert().is_none());
3238 assert_eq!(key_entry.take_cert_chain(), Some(TEST_CERT_BLOB.to_vec()));
3239
3240 db.unbind_key(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003241 &KeyDescriptor {
Janis Danisevskis377d1002021-01-27 19:07:48 -08003242 domain: Domain::APP,
3243 nspace: 1,
3244 alias: Some(TEST_ALIAS.to_string()),
3245 blob: None,
3246 },
3247 KeyType::Client,
3248 1,
3249 |_, _| Ok(()),
3250 )
3251 .unwrap();
3252
3253 assert_eq!(
3254 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
3255 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003256 &KeyDescriptor {
Janis Danisevskis377d1002021-01-27 19:07:48 -08003257 domain: Domain::APP,
3258 nspace: 1,
3259 alias: Some(TEST_ALIAS.to_string()),
3260 blob: None,
3261 },
3262 KeyType::Client,
3263 KeyEntryLoadBits::NONE,
3264 1,
3265 |_k, _av| Ok(()),
3266 )
3267 .unwrap_err()
3268 .root_cause()
3269 .downcast_ref::<KsError>()
3270 );
3271
3272 Ok(())
3273 }
3274
3275 #[test]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003276 fn test_insert_and_load_full_keyentry_domain_selinux() -> Result<()> {
3277 let mut db = new_test_db()?;
Qi Wub9433b52020-12-01 14:52:46 +08003278 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08003279 .context("test_insert_and_load_full_keyentry_domain_selinux")?
3280 .0;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003281 let (_key_guard, key_entry) = db
3282 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003283 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003284 domain: Domain::SELINUX,
3285 nspace: 1,
3286 alias: Some(TEST_ALIAS.to_string()),
3287 blob: None,
3288 },
3289 KeyType::Client,
3290 KeyEntryLoadBits::BOTH,
3291 1,
3292 |_k, _av| Ok(()),
3293 )
3294 .unwrap();
Qi Wub9433b52020-12-01 14:52:46 +08003295 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003296
3297 db.unbind_key(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003298 &KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003299 domain: Domain::SELINUX,
3300 nspace: 1,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003301 alias: Some(TEST_ALIAS.to_string()),
3302 blob: None,
3303 },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003304 KeyType::Client,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003305 1,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003306 |_, _| Ok(()),
3307 )
3308 .unwrap();
3309
3310 assert_eq!(
3311 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
3312 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003313 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003314 domain: Domain::SELINUX,
3315 nspace: 1,
3316 alias: Some(TEST_ALIAS.to_string()),
3317 blob: None,
3318 },
3319 KeyType::Client,
3320 KeyEntryLoadBits::NONE,
3321 1,
3322 |_k, _av| Ok(()),
3323 )
3324 .unwrap_err()
3325 .root_cause()
3326 .downcast_ref::<KsError>()
3327 );
3328
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003329 Ok(())
3330 }
3331
3332 #[test]
3333 fn test_insert_and_load_full_keyentry_domain_key_id() -> Result<()> {
3334 let mut db = new_test_db()?;
Qi Wub9433b52020-12-01 14:52:46 +08003335 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08003336 .context("test_insert_and_load_full_keyentry_domain_key_id")?
3337 .0;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003338 let (_, key_entry) = db
3339 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003340 &KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003341 KeyType::Client,
3342 KeyEntryLoadBits::BOTH,
3343 1,
3344 |_k, _av| Ok(()),
3345 )
3346 .unwrap();
3347
Qi Wub9433b52020-12-01 14:52:46 +08003348 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003349
3350 db.unbind_key(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003351 &KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003352 KeyType::Client,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003353 1,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003354 |_, _| Ok(()),
3355 )
3356 .unwrap();
3357
3358 assert_eq!(
3359 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
3360 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003361 &KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003362 KeyType::Client,
3363 KeyEntryLoadBits::NONE,
3364 1,
3365 |_k, _av| Ok(()),
3366 )
3367 .unwrap_err()
3368 .root_cause()
3369 .downcast_ref::<KsError>()
3370 );
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003371
3372 Ok(())
3373 }
3374
3375 #[test]
Qi Wub9433b52020-12-01 14:52:46 +08003376 fn test_check_and_update_key_usage_count_with_limited_use_key() -> Result<()> {
3377 let mut db = new_test_db()?;
3378 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, Some(123))
3379 .context("test_check_and_update_key_usage_count_with_limited_use_key")?
3380 .0;
3381 // Update the usage count of the limited use key.
3382 db.check_and_update_key_usage_count(key_id)?;
3383
3384 let (_key_guard, key_entry) = db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003385 &KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
Qi Wub9433b52020-12-01 14:52:46 +08003386 KeyType::Client,
3387 KeyEntryLoadBits::BOTH,
3388 1,
3389 |_k, _av| Ok(()),
3390 )?;
3391
3392 // The usage count is decremented now.
3393 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, Some(122)));
3394
3395 Ok(())
3396 }
3397
3398 #[test]
3399 fn test_check_and_update_key_usage_count_with_exhausted_limited_use_key() -> Result<()> {
3400 let mut db = new_test_db()?;
3401 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, Some(1))
3402 .context("test_check_and_update_key_usage_count_with_exhausted_limited_use_key")?
3403 .0;
3404 // Update the usage count of the limited use key.
3405 db.check_and_update_key_usage_count(key_id).expect(concat!(
3406 "In test_check_and_update_key_usage_count_with_exhausted_limited_use_key: ",
3407 "This should succeed."
3408 ));
3409
3410 // Try to update the exhausted limited use key.
3411 let e = db.check_and_update_key_usage_count(key_id).expect_err(concat!(
3412 "In test_check_and_update_key_usage_count_with_exhausted_limited_use_key: ",
3413 "This should fail."
3414 ));
3415 assert_eq!(
3416 &KsError::Km(ErrorCode::INVALID_KEY_BLOB),
3417 e.root_cause().downcast_ref::<KsError>().unwrap()
3418 );
3419
3420 Ok(())
3421 }
3422
3423 #[test]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003424 fn test_insert_and_load_full_keyentry_from_grant() -> Result<()> {
3425 let mut db = new_test_db()?;
Qi Wub9433b52020-12-01 14:52:46 +08003426 let key_id = make_test_key_entry(&mut db, Domain::APP, 1, TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08003427 .context("test_insert_and_load_full_keyentry_from_grant")?
3428 .0;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003429
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003430 let granted_key = db
3431 .grant(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003432 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003433 domain: Domain::APP,
3434 nspace: 0,
3435 alias: Some(TEST_ALIAS.to_string()),
3436 blob: None,
3437 },
3438 1,
3439 2,
3440 key_perm_set![KeyPerm::use_()],
3441 |_k, _av| Ok(()),
3442 )
3443 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003444
3445 debug_dump_grant_table(&mut db)?;
3446
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003447 let (_key_guard, key_entry) = db
Janis Danisevskis66784c42021-01-27 08:40:25 -08003448 .load_key_entry(&granted_key, KeyType::Client, KeyEntryLoadBits::BOTH, 2, |k, av| {
3449 assert_eq!(Domain::GRANT, k.domain);
3450 assert!(av.unwrap().includes(KeyPerm::use_()));
3451 Ok(())
3452 })
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003453 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003454
Qi Wub9433b52020-12-01 14:52:46 +08003455 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003456
Janis Danisevskis66784c42021-01-27 08:40:25 -08003457 db.unbind_key(&granted_key, KeyType::Client, 2, |_, _| Ok(())).unwrap();
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003458
3459 assert_eq!(
3460 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
3461 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003462 &granted_key,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003463 KeyType::Client,
3464 KeyEntryLoadBits::NONE,
3465 2,
3466 |_k, _av| Ok(()),
3467 )
3468 .unwrap_err()
3469 .root_cause()
3470 .downcast_ref::<KsError>()
3471 );
3472
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003473 Ok(())
3474 }
3475
Janis Danisevskis45760022021-01-19 16:34:10 -08003476 // This test attempts to load a key by key id while the caller is not the owner
3477 // but a grant exists for the given key and the caller.
3478 #[test]
3479 fn test_insert_and_load_full_keyentry_from_grant_by_key_id() -> Result<()> {
3480 let mut db = new_test_db()?;
3481 const OWNER_UID: u32 = 1u32;
3482 const GRANTEE_UID: u32 = 2u32;
3483 const SOMEONE_ELSE_UID: u32 = 3u32;
3484 let key_id = make_test_key_entry(&mut db, Domain::APP, OWNER_UID as i64, TEST_ALIAS, None)
3485 .context("test_insert_and_load_full_keyentry_from_grant_by_key_id")?
3486 .0;
3487
3488 db.grant(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003489 &KeyDescriptor {
Janis Danisevskis45760022021-01-19 16:34:10 -08003490 domain: Domain::APP,
3491 nspace: 0,
3492 alias: Some(TEST_ALIAS.to_string()),
3493 blob: None,
3494 },
3495 OWNER_UID,
3496 GRANTEE_UID,
3497 key_perm_set![KeyPerm::use_()],
3498 |_k, _av| Ok(()),
3499 )
3500 .unwrap();
3501
3502 debug_dump_grant_table(&mut db)?;
3503
3504 let id_descriptor =
3505 KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, ..Default::default() };
3506
3507 let (_, key_entry) = db
3508 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003509 &id_descriptor,
Janis Danisevskis45760022021-01-19 16:34:10 -08003510 KeyType::Client,
3511 KeyEntryLoadBits::BOTH,
3512 GRANTEE_UID,
3513 |k, av| {
3514 assert_eq!(Domain::APP, k.domain);
3515 assert_eq!(OWNER_UID as i64, k.nspace);
3516 assert!(av.unwrap().includes(KeyPerm::use_()));
3517 Ok(())
3518 },
3519 )
3520 .unwrap();
3521
3522 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
3523
3524 let (_, key_entry) = db
3525 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003526 &id_descriptor,
Janis Danisevskis45760022021-01-19 16:34:10 -08003527 KeyType::Client,
3528 KeyEntryLoadBits::BOTH,
3529 SOMEONE_ELSE_UID,
3530 |k, av| {
3531 assert_eq!(Domain::APP, k.domain);
3532 assert_eq!(OWNER_UID as i64, k.nspace);
3533 assert!(av.is_none());
3534 Ok(())
3535 },
3536 )
3537 .unwrap();
3538
3539 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
3540
Janis Danisevskis66784c42021-01-27 08:40:25 -08003541 db.unbind_key(&id_descriptor, KeyType::Client, OWNER_UID, |_, _| Ok(())).unwrap();
Janis Danisevskis45760022021-01-19 16:34:10 -08003542
3543 assert_eq!(
3544 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
3545 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003546 &id_descriptor,
Janis Danisevskis45760022021-01-19 16:34:10 -08003547 KeyType::Client,
3548 KeyEntryLoadBits::NONE,
3549 GRANTEE_UID,
3550 |_k, _av| Ok(()),
3551 )
3552 .unwrap_err()
3553 .root_cause()
3554 .downcast_ref::<KsError>()
3555 );
3556
3557 Ok(())
3558 }
3559
Janis Danisevskisaec14592020-11-12 09:41:49 -08003560 static KEY_LOCK_TEST_ALIAS: &str = "my super duper locked key";
3561
Janis Danisevskisaec14592020-11-12 09:41:49 -08003562 #[test]
3563 fn test_insert_and_load_full_keyentry_domain_app_concurrently() -> Result<()> {
3564 let handle = {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08003565 let temp_dir = Arc::new(TempDir::new("id_lock_test")?);
3566 let temp_dir_clone = temp_dir.clone();
3567 let mut db = KeystoreDB::new(temp_dir.path())?;
Qi Wub9433b52020-12-01 14:52:46 +08003568 let key_id = make_test_key_entry(&mut db, Domain::APP, 33, KEY_LOCK_TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08003569 .context("test_insert_and_load_full_keyentry_domain_app")?
3570 .0;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003571 let (_key_guard, key_entry) = db
3572 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003573 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003574 domain: Domain::APP,
3575 nspace: 0,
3576 alias: Some(KEY_LOCK_TEST_ALIAS.to_string()),
3577 blob: None,
3578 },
3579 KeyType::Client,
3580 KeyEntryLoadBits::BOTH,
3581 33,
3582 |_k, _av| Ok(()),
3583 )
3584 .unwrap();
Qi Wub9433b52020-12-01 14:52:46 +08003585 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskisaec14592020-11-12 09:41:49 -08003586 let state = Arc::new(AtomicU8::new(1));
3587 let state2 = state.clone();
3588
3589 // Spawning a second thread that attempts to acquire the key id lock
3590 // for the same key as the primary thread. The primary thread then
3591 // waits, thereby forcing the secondary thread into the second stage
3592 // of acquiring the lock (see KEY ID LOCK 2/2 above).
3593 // The test succeeds if the secondary thread observes the transition
3594 // of `state` from 1 to 2, despite having a whole second to overtake
3595 // the primary thread.
3596 let handle = thread::spawn(move || {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08003597 let temp_dir = temp_dir_clone;
3598 let mut db = KeystoreDB::new(temp_dir.path()).unwrap();
Janis Danisevskisaec14592020-11-12 09:41:49 -08003599 assert!(db
3600 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003601 &KeyDescriptor {
Janis Danisevskisaec14592020-11-12 09:41:49 -08003602 domain: Domain::APP,
3603 nspace: 0,
3604 alias: Some(KEY_LOCK_TEST_ALIAS.to_string()),
3605 blob: None,
3606 },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003607 KeyType::Client,
Janis Danisevskisaec14592020-11-12 09:41:49 -08003608 KeyEntryLoadBits::BOTH,
3609 33,
3610 |_k, _av| Ok(()),
3611 )
3612 .is_ok());
3613 // We should only see a 2 here because we can only return
3614 // from load_key_entry when the `_key_guard` expires,
3615 // which happens at the end of the scope.
3616 assert_eq!(2, state2.load(Ordering::Relaxed));
3617 });
3618
3619 thread::sleep(std::time::Duration::from_millis(1000));
3620
3621 assert_eq!(Ok(1), state.compare_exchange(1, 2, Ordering::Relaxed, Ordering::Relaxed));
3622
3623 // Return the handle from this scope so we can join with the
3624 // secondary thread after the key id lock has expired.
3625 handle
3626 // This is where the `_key_guard` goes out of scope,
3627 // which is the reason for concurrent load_key_entry on the same key
3628 // to unblock.
3629 };
3630 // Join with the secondary thread and unwrap, to propagate failing asserts to the
3631 // main test thread. We will not see failing asserts in secondary threads otherwise.
3632 handle.join().unwrap();
3633 Ok(())
3634 }
3635
Janis Danisevskise92a5e62020-12-02 12:57:41 -08003636 #[test]
Janis Danisevskis66784c42021-01-27 08:40:25 -08003637 fn teset_database_busy_error_code() {
3638 let temp_dir =
3639 TempDir::new("test_database_busy_error_code_").expect("Failed to create temp dir.");
3640
3641 let mut db1 = KeystoreDB::new(temp_dir.path()).expect("Failed to open database1.");
3642 let mut db2 = KeystoreDB::new(temp_dir.path()).expect("Failed to open database2.");
3643
3644 let _tx1 = db1
3645 .conn
3646 .transaction_with_behavior(TransactionBehavior::Immediate)
3647 .expect("Failed to create first transaction.");
3648
3649 let error = db2
3650 .conn
3651 .transaction_with_behavior(TransactionBehavior::Immediate)
3652 .context("Transaction begin failed.")
3653 .expect_err("This should fail.");
3654 let root_cause = error.root_cause();
3655 if let Some(rusqlite::ffi::Error { code: rusqlite::ErrorCode::DatabaseBusy, .. }) =
3656 root_cause.downcast_ref::<rusqlite::ffi::Error>()
3657 {
3658 return;
3659 }
3660 panic!(
3661 "Unexpected error {:?} \n{:?} \n{:?}",
3662 error,
3663 root_cause,
3664 root_cause.downcast_ref::<rusqlite::ffi::Error>()
3665 )
3666 }
3667
3668 #[cfg(disabled)]
3669 #[test]
3670 fn test_large_number_of_concurrent_db_manipulations() -> Result<()> {
3671 let temp_dir = Arc::new(
3672 TempDir::new("test_large_number_of_concurrent_db_manipulations_")
3673 .expect("Failed to create temp dir."),
3674 );
3675
3676 let test_begin = Instant::now();
3677
3678 let mut db = KeystoreDB::new(temp_dir.path()).expect("Failed to open database.");
3679 const KEY_COUNT: u32 = 500u32;
3680 const OPEN_DB_COUNT: u32 = 50u32;
3681
3682 let mut actual_key_count = KEY_COUNT;
3683 // First insert KEY_COUNT keys.
3684 for count in 0..KEY_COUNT {
3685 if Instant::now().duration_since(test_begin) >= Duration::from_secs(15) {
3686 actual_key_count = count;
3687 break;
3688 }
3689 let alias = format!("test_alias_{}", count);
3690 make_test_key_entry(&mut db, Domain::APP, 1, &alias, None)
3691 .expect("Failed to make key entry.");
3692 }
3693
3694 // Insert more keys from a different thread and into a different namespace.
3695 let temp_dir1 = temp_dir.clone();
3696 let handle1 = thread::spawn(move || {
3697 let mut db = KeystoreDB::new(temp_dir1.path()).expect("Failed to open database.");
3698
3699 for count in 0..actual_key_count {
3700 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
3701 return;
3702 }
3703 let alias = format!("test_alias_{}", count);
3704 make_test_key_entry(&mut db, Domain::APP, 2, &alias, None)
3705 .expect("Failed to make key entry.");
3706 }
3707
3708 // then unbind them again.
3709 for count in 0..actual_key_count {
3710 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
3711 return;
3712 }
3713 let key = KeyDescriptor {
3714 domain: Domain::APP,
3715 nspace: -1,
3716 alias: Some(format!("test_alias_{}", count)),
3717 blob: None,
3718 };
3719 db.unbind_key(&key, KeyType::Client, 2, |_, _| Ok(())).expect("Unbind Failed.");
3720 }
3721 });
3722
3723 // And start unbinding the first set of keys.
3724 let temp_dir2 = temp_dir.clone();
3725 let handle2 = thread::spawn(move || {
3726 let mut db = KeystoreDB::new(temp_dir2.path()).expect("Failed to open database.");
3727
3728 for count in 0..actual_key_count {
3729 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
3730 return;
3731 }
3732 let key = KeyDescriptor {
3733 domain: Domain::APP,
3734 nspace: -1,
3735 alias: Some(format!("test_alias_{}", count)),
3736 blob: None,
3737 };
3738 db.unbind_key(&key, KeyType::Client, 1, |_, _| Ok(())).expect("Unbind Failed.");
3739 }
3740 });
3741
3742 let stop_deleting = Arc::new(AtomicU8::new(0));
3743 let stop_deleting2 = stop_deleting.clone();
3744
3745 // And delete anything that is unreferenced keys.
3746 let temp_dir3 = temp_dir.clone();
3747 let handle3 = thread::spawn(move || {
3748 let mut db = KeystoreDB::new(temp_dir3.path()).expect("Failed to open database.");
3749
3750 while stop_deleting2.load(Ordering::Relaxed) != 1 {
3751 while let Some((key_guard, _key)) =
3752 db.get_unreferenced_key().expect("Failed to get unreferenced Key.")
3753 {
3754 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
3755 return;
3756 }
3757 db.purge_key_entry(key_guard).expect("Failed to purge key.");
3758 }
3759 std::thread::sleep(std::time::Duration::from_millis(100));
3760 }
3761 });
3762
3763 // While a lot of inserting and deleting is going on we have to open database connections
3764 // successfully and use them.
3765 // This clone is not redundant, because temp_dir needs to be kept alive until db goes
3766 // out of scope.
3767 #[allow(clippy::redundant_clone)]
3768 let temp_dir4 = temp_dir.clone();
3769 let handle4 = thread::spawn(move || {
3770 for count in 0..OPEN_DB_COUNT {
3771 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
3772 return;
3773 }
3774 let mut db = KeystoreDB::new(temp_dir4.path()).expect("Failed to open database.");
3775
3776 let alias = format!("test_alias_{}", count);
3777 make_test_key_entry(&mut db, Domain::APP, 3, &alias, None)
3778 .expect("Failed to make key entry.");
3779 let key = KeyDescriptor {
3780 domain: Domain::APP,
3781 nspace: -1,
3782 alias: Some(alias),
3783 blob: None,
3784 };
3785 db.unbind_key(&key, KeyType::Client, 3, |_, _| Ok(())).expect("Unbind Failed.");
3786 }
3787 });
3788
3789 handle1.join().expect("Thread 1 panicked.");
3790 handle2.join().expect("Thread 2 panicked.");
3791 handle4.join().expect("Thread 4 panicked.");
3792
3793 stop_deleting.store(1, Ordering::Relaxed);
3794 handle3.join().expect("Thread 3 panicked.");
3795
3796 Ok(())
3797 }
3798
3799 #[test]
Janis Danisevskise92a5e62020-12-02 12:57:41 -08003800 fn list() -> Result<()> {
3801 let temp_dir = TempDir::new("list_test")?;
3802 let mut db = KeystoreDB::new(temp_dir.path())?;
3803 static LIST_O_ENTRIES: &[(Domain, i64, &str)] = &[
3804 (Domain::APP, 1, "test1"),
3805 (Domain::APP, 1, "test2"),
3806 (Domain::APP, 1, "test3"),
3807 (Domain::APP, 1, "test4"),
3808 (Domain::APP, 1, "test5"),
3809 (Domain::APP, 1, "test6"),
3810 (Domain::APP, 1, "test7"),
3811 (Domain::APP, 2, "test1"),
3812 (Domain::APP, 2, "test2"),
3813 (Domain::APP, 2, "test3"),
3814 (Domain::APP, 2, "test4"),
3815 (Domain::APP, 2, "test5"),
3816 (Domain::APP, 2, "test6"),
3817 (Domain::APP, 2, "test8"),
3818 (Domain::SELINUX, 100, "test1"),
3819 (Domain::SELINUX, 100, "test2"),
3820 (Domain::SELINUX, 100, "test3"),
3821 (Domain::SELINUX, 100, "test4"),
3822 (Domain::SELINUX, 100, "test5"),
3823 (Domain::SELINUX, 100, "test6"),
3824 (Domain::SELINUX, 100, "test9"),
3825 ];
3826
3827 let list_o_keys: Vec<(i64, i64)> = LIST_O_ENTRIES
3828 .iter()
3829 .map(|(domain, ns, alias)| {
Qi Wub9433b52020-12-01 14:52:46 +08003830 let entry = make_test_key_entry(&mut db, *domain, *ns, *alias, None)
3831 .unwrap_or_else(|e| {
Janis Danisevskise92a5e62020-12-02 12:57:41 -08003832 panic!("Failed to insert {:?} {} {}. Error {:?}", domain, ns, alias, e)
3833 });
3834 (entry.id(), *ns)
3835 })
3836 .collect();
3837
3838 for (domain, namespace) in
3839 &[(Domain::APP, 1i64), (Domain::APP, 2i64), (Domain::SELINUX, 100i64)]
3840 {
3841 let mut list_o_descriptors: Vec<KeyDescriptor> = LIST_O_ENTRIES
3842 .iter()
3843 .filter_map(|(domain, ns, alias)| match ns {
3844 ns if *ns == *namespace => Some(KeyDescriptor {
3845 domain: *domain,
3846 nspace: *ns,
3847 alias: Some(alias.to_string()),
3848 blob: None,
3849 }),
3850 _ => None,
3851 })
3852 .collect();
3853 list_o_descriptors.sort();
3854 let mut list_result = db.list(*domain, *namespace)?;
3855 list_result.sort();
3856 assert_eq!(list_o_descriptors, list_result);
3857
3858 let mut list_o_ids: Vec<i64> = list_o_descriptors
3859 .into_iter()
3860 .map(|d| {
3861 let (_, entry) = db
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003862 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003863 &d,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003864 KeyType::Client,
3865 KeyEntryLoadBits::NONE,
3866 *namespace as u32,
3867 |_, _| Ok(()),
3868 )
Janis Danisevskise92a5e62020-12-02 12:57:41 -08003869 .unwrap();
3870 entry.id()
3871 })
3872 .collect();
3873 list_o_ids.sort_unstable();
3874 let mut loaded_entries: Vec<i64> = list_o_keys
3875 .iter()
3876 .filter_map(|(id, ns)| match ns {
3877 ns if *ns == *namespace => Some(*id),
3878 _ => None,
3879 })
3880 .collect();
3881 loaded_entries.sort_unstable();
3882 assert_eq!(list_o_ids, loaded_entries);
3883 }
3884 assert_eq!(Vec::<KeyDescriptor>::new(), db.list(Domain::SELINUX, 101)?);
3885
3886 Ok(())
3887 }
3888
Joel Galenson0891bc12020-07-20 10:37:03 -07003889 // Helpers
3890
3891 // Checks that the given result is an error containing the given string.
3892 fn check_result_is_error_containing_string<T>(result: Result<T>, target: &str) {
3893 let error_str = format!(
3894 "{:#?}",
3895 result.err().unwrap_or_else(|| panic!("Expected the error: {}", target))
3896 );
3897 assert!(
3898 error_str.contains(target),
3899 "The string \"{}\" should contain \"{}\"",
3900 error_str,
3901 target
3902 );
3903 }
3904
Joel Galenson2aab4432020-07-22 15:27:57 -07003905 #[derive(Debug, PartialEq)]
Joel Galenson0891bc12020-07-20 10:37:03 -07003906 #[allow(dead_code)]
3907 struct KeyEntryRow {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003908 id: i64,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003909 key_type: KeyType,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003910 domain: Option<Domain>,
Joel Galenson0891bc12020-07-20 10:37:03 -07003911 namespace: Option<i64>,
3912 alias: Option<String>,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003913 state: KeyLifeCycle,
Max Bires8e93d2b2021-01-14 13:17:59 -08003914 km_uuid: Option<Uuid>,
Joel Galenson0891bc12020-07-20 10:37:03 -07003915 }
3916
3917 fn get_keyentry(db: &KeystoreDB) -> Result<Vec<KeyEntryRow>> {
3918 db.conn
Joel Galenson2aab4432020-07-22 15:27:57 -07003919 .prepare("SELECT * FROM persistent.keyentry;")?
Joel Galenson0891bc12020-07-20 10:37:03 -07003920 .query_map(NO_PARAMS, |row| {
Joel Galenson0891bc12020-07-20 10:37:03 -07003921 Ok(KeyEntryRow {
3922 id: row.get(0)?,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003923 key_type: row.get(1)?,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003924 domain: match row.get(2)? {
3925 Some(i) => Some(Domain(i)),
3926 None => None,
3927 },
Joel Galenson0891bc12020-07-20 10:37:03 -07003928 namespace: row.get(3)?,
3929 alias: row.get(4)?,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003930 state: row.get(5)?,
Max Bires8e93d2b2021-01-14 13:17:59 -08003931 km_uuid: row.get(6)?,
Joel Galenson0891bc12020-07-20 10:37:03 -07003932 })
3933 })?
3934 .map(|r| r.context("Could not read keyentry row."))
3935 .collect::<Result<Vec<_>>>()
3936 }
3937
Max Bires2b2e6562020-09-22 11:22:36 -07003938 fn load_attestation_key_pool(
3939 db: &mut KeystoreDB,
3940 expiration_date: i64,
3941 namespace: i64,
3942 base_byte: u8,
3943 ) -> Result<Vec<Vec<u8>>> {
3944 let mut chain: Vec<Vec<u8>> = Vec::new();
3945 let public_key: Vec<u8> = vec![base_byte, 0x02 * base_byte];
3946 let cert_chain: Vec<u8> = vec![0x03 * base_byte, 0x04 * base_byte];
3947 let priv_key: Vec<u8> = vec![0x05 * base_byte, 0x06 * base_byte];
3948 let raw_public_key: Vec<u8> = vec![0x0b * base_byte, 0x0c * base_byte];
3949 db.create_attestation_key_entry(&public_key, &raw_public_key, &priv_key, &KEYSTORE_UUID)?;
3950 db.store_signed_attestation_certificate_chain(
3951 &raw_public_key,
3952 &cert_chain,
3953 expiration_date,
3954 &KEYSTORE_UUID,
3955 )?;
3956 db.assign_attestation_key(Domain::APP, namespace, &KEYSTORE_UUID)?;
3957 chain.push(public_key);
3958 chain.push(cert_chain);
3959 chain.push(priv_key);
3960 chain.push(raw_public_key);
3961 Ok(chain)
3962 }
3963
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07003964 // Note: The parameters and SecurityLevel associations are nonsensical. This
3965 // collection is only used to check if the parameters are preserved as expected by the
3966 // database.
Qi Wub9433b52020-12-01 14:52:46 +08003967 fn make_test_params(max_usage_count: Option<i32>) -> Vec<KeyParameter> {
3968 let mut params = vec![
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07003969 KeyParameter::new(KeyParameterValue::Invalid, SecurityLevel::TRUSTED_ENVIRONMENT),
3970 KeyParameter::new(
3971 KeyParameterValue::KeyPurpose(KeyPurpose::SIGN),
3972 SecurityLevel::TRUSTED_ENVIRONMENT,
3973 ),
3974 KeyParameter::new(
3975 KeyParameterValue::KeyPurpose(KeyPurpose::DECRYPT),
3976 SecurityLevel::TRUSTED_ENVIRONMENT,
3977 ),
3978 KeyParameter::new(
3979 KeyParameterValue::Algorithm(Algorithm::RSA),
3980 SecurityLevel::TRUSTED_ENVIRONMENT,
3981 ),
3982 KeyParameter::new(KeyParameterValue::KeySize(1024), SecurityLevel::TRUSTED_ENVIRONMENT),
3983 KeyParameter::new(
3984 KeyParameterValue::BlockMode(BlockMode::ECB),
3985 SecurityLevel::TRUSTED_ENVIRONMENT,
3986 ),
3987 KeyParameter::new(
3988 KeyParameterValue::BlockMode(BlockMode::GCM),
3989 SecurityLevel::TRUSTED_ENVIRONMENT,
3990 ),
3991 KeyParameter::new(KeyParameterValue::Digest(Digest::NONE), SecurityLevel::STRONGBOX),
3992 KeyParameter::new(
3993 KeyParameterValue::Digest(Digest::MD5),
3994 SecurityLevel::TRUSTED_ENVIRONMENT,
3995 ),
3996 KeyParameter::new(
3997 KeyParameterValue::Digest(Digest::SHA_2_224),
3998 SecurityLevel::TRUSTED_ENVIRONMENT,
3999 ),
4000 KeyParameter::new(
4001 KeyParameterValue::Digest(Digest::SHA_2_256),
4002 SecurityLevel::STRONGBOX,
4003 ),
4004 KeyParameter::new(
4005 KeyParameterValue::PaddingMode(PaddingMode::NONE),
4006 SecurityLevel::TRUSTED_ENVIRONMENT,
4007 ),
4008 KeyParameter::new(
4009 KeyParameterValue::PaddingMode(PaddingMode::RSA_OAEP),
4010 SecurityLevel::TRUSTED_ENVIRONMENT,
4011 ),
4012 KeyParameter::new(
4013 KeyParameterValue::PaddingMode(PaddingMode::RSA_PSS),
4014 SecurityLevel::STRONGBOX,
4015 ),
4016 KeyParameter::new(
4017 KeyParameterValue::PaddingMode(PaddingMode::RSA_PKCS1_1_5_SIGN),
4018 SecurityLevel::TRUSTED_ENVIRONMENT,
4019 ),
4020 KeyParameter::new(KeyParameterValue::CallerNonce, SecurityLevel::TRUSTED_ENVIRONMENT),
4021 KeyParameter::new(KeyParameterValue::MinMacLength(256), SecurityLevel::STRONGBOX),
4022 KeyParameter::new(
4023 KeyParameterValue::EcCurve(EcCurve::P_224),
4024 SecurityLevel::TRUSTED_ENVIRONMENT,
4025 ),
4026 KeyParameter::new(KeyParameterValue::EcCurve(EcCurve::P_256), SecurityLevel::STRONGBOX),
4027 KeyParameter::new(
4028 KeyParameterValue::EcCurve(EcCurve::P_384),
4029 SecurityLevel::TRUSTED_ENVIRONMENT,
4030 ),
4031 KeyParameter::new(
4032 KeyParameterValue::EcCurve(EcCurve::P_521),
4033 SecurityLevel::TRUSTED_ENVIRONMENT,
4034 ),
4035 KeyParameter::new(
4036 KeyParameterValue::RSAPublicExponent(3),
4037 SecurityLevel::TRUSTED_ENVIRONMENT,
4038 ),
4039 KeyParameter::new(
4040 KeyParameterValue::IncludeUniqueID,
4041 SecurityLevel::TRUSTED_ENVIRONMENT,
4042 ),
4043 KeyParameter::new(KeyParameterValue::BootLoaderOnly, SecurityLevel::STRONGBOX),
4044 KeyParameter::new(KeyParameterValue::RollbackResistance, SecurityLevel::STRONGBOX),
4045 KeyParameter::new(
4046 KeyParameterValue::ActiveDateTime(1234567890),
4047 SecurityLevel::STRONGBOX,
4048 ),
4049 KeyParameter::new(
4050 KeyParameterValue::OriginationExpireDateTime(1234567890),
4051 SecurityLevel::TRUSTED_ENVIRONMENT,
4052 ),
4053 KeyParameter::new(
4054 KeyParameterValue::UsageExpireDateTime(1234567890),
4055 SecurityLevel::TRUSTED_ENVIRONMENT,
4056 ),
4057 KeyParameter::new(
4058 KeyParameterValue::MinSecondsBetweenOps(1234567890),
4059 SecurityLevel::TRUSTED_ENVIRONMENT,
4060 ),
4061 KeyParameter::new(
4062 KeyParameterValue::MaxUsesPerBoot(1234567890),
4063 SecurityLevel::TRUSTED_ENVIRONMENT,
4064 ),
4065 KeyParameter::new(KeyParameterValue::UserID(1), SecurityLevel::STRONGBOX),
4066 KeyParameter::new(KeyParameterValue::UserSecureID(42), SecurityLevel::STRONGBOX),
4067 KeyParameter::new(
4068 KeyParameterValue::NoAuthRequired,
4069 SecurityLevel::TRUSTED_ENVIRONMENT,
4070 ),
4071 KeyParameter::new(
4072 KeyParameterValue::HardwareAuthenticatorType(HardwareAuthenticatorType::PASSWORD),
4073 SecurityLevel::TRUSTED_ENVIRONMENT,
4074 ),
4075 KeyParameter::new(KeyParameterValue::AuthTimeout(1234567890), SecurityLevel::SOFTWARE),
4076 KeyParameter::new(KeyParameterValue::AllowWhileOnBody, SecurityLevel::SOFTWARE),
4077 KeyParameter::new(
4078 KeyParameterValue::TrustedUserPresenceRequired,
4079 SecurityLevel::TRUSTED_ENVIRONMENT,
4080 ),
4081 KeyParameter::new(
4082 KeyParameterValue::TrustedConfirmationRequired,
4083 SecurityLevel::TRUSTED_ENVIRONMENT,
4084 ),
4085 KeyParameter::new(
4086 KeyParameterValue::UnlockedDeviceRequired,
4087 SecurityLevel::TRUSTED_ENVIRONMENT,
4088 ),
4089 KeyParameter::new(
4090 KeyParameterValue::ApplicationID(vec![1u8, 2u8, 3u8, 4u8]),
4091 SecurityLevel::SOFTWARE,
4092 ),
4093 KeyParameter::new(
4094 KeyParameterValue::ApplicationData(vec![4u8, 3u8, 2u8, 1u8]),
4095 SecurityLevel::SOFTWARE,
4096 ),
4097 KeyParameter::new(
4098 KeyParameterValue::CreationDateTime(12345677890),
4099 SecurityLevel::SOFTWARE,
4100 ),
4101 KeyParameter::new(
4102 KeyParameterValue::KeyOrigin(KeyOrigin::GENERATED),
4103 SecurityLevel::TRUSTED_ENVIRONMENT,
4104 ),
4105 KeyParameter::new(
4106 KeyParameterValue::RootOfTrust(vec![3u8, 2u8, 1u8, 4u8]),
4107 SecurityLevel::TRUSTED_ENVIRONMENT,
4108 ),
4109 KeyParameter::new(KeyParameterValue::OSVersion(1), SecurityLevel::TRUSTED_ENVIRONMENT),
4110 KeyParameter::new(KeyParameterValue::OSPatchLevel(2), SecurityLevel::SOFTWARE),
4111 KeyParameter::new(
4112 KeyParameterValue::UniqueID(vec![4u8, 3u8, 1u8, 2u8]),
4113 SecurityLevel::SOFTWARE,
4114 ),
4115 KeyParameter::new(
4116 KeyParameterValue::AttestationChallenge(vec![4u8, 3u8, 1u8, 2u8]),
4117 SecurityLevel::TRUSTED_ENVIRONMENT,
4118 ),
4119 KeyParameter::new(
4120 KeyParameterValue::AttestationApplicationID(vec![4u8, 3u8, 1u8, 2u8]),
4121 SecurityLevel::TRUSTED_ENVIRONMENT,
4122 ),
4123 KeyParameter::new(
4124 KeyParameterValue::AttestationIdBrand(vec![4u8, 3u8, 1u8, 2u8]),
4125 SecurityLevel::TRUSTED_ENVIRONMENT,
4126 ),
4127 KeyParameter::new(
4128 KeyParameterValue::AttestationIdDevice(vec![4u8, 3u8, 1u8, 2u8]),
4129 SecurityLevel::TRUSTED_ENVIRONMENT,
4130 ),
4131 KeyParameter::new(
4132 KeyParameterValue::AttestationIdProduct(vec![4u8, 3u8, 1u8, 2u8]),
4133 SecurityLevel::TRUSTED_ENVIRONMENT,
4134 ),
4135 KeyParameter::new(
4136 KeyParameterValue::AttestationIdSerial(vec![4u8, 3u8, 1u8, 2u8]),
4137 SecurityLevel::TRUSTED_ENVIRONMENT,
4138 ),
4139 KeyParameter::new(
4140 KeyParameterValue::AttestationIdIMEI(vec![4u8, 3u8, 1u8, 2u8]),
4141 SecurityLevel::TRUSTED_ENVIRONMENT,
4142 ),
4143 KeyParameter::new(
4144 KeyParameterValue::AttestationIdMEID(vec![4u8, 3u8, 1u8, 2u8]),
4145 SecurityLevel::TRUSTED_ENVIRONMENT,
4146 ),
4147 KeyParameter::new(
4148 KeyParameterValue::AttestationIdManufacturer(vec![4u8, 3u8, 1u8, 2u8]),
4149 SecurityLevel::TRUSTED_ENVIRONMENT,
4150 ),
4151 KeyParameter::new(
4152 KeyParameterValue::AttestationIdModel(vec![4u8, 3u8, 1u8, 2u8]),
4153 SecurityLevel::TRUSTED_ENVIRONMENT,
4154 ),
4155 KeyParameter::new(
4156 KeyParameterValue::VendorPatchLevel(3),
4157 SecurityLevel::TRUSTED_ENVIRONMENT,
4158 ),
4159 KeyParameter::new(
4160 KeyParameterValue::BootPatchLevel(4),
4161 SecurityLevel::TRUSTED_ENVIRONMENT,
4162 ),
4163 KeyParameter::new(
4164 KeyParameterValue::AssociatedData(vec![4u8, 3u8, 1u8, 2u8]),
4165 SecurityLevel::TRUSTED_ENVIRONMENT,
4166 ),
4167 KeyParameter::new(
4168 KeyParameterValue::Nonce(vec![4u8, 3u8, 1u8, 2u8]),
4169 SecurityLevel::TRUSTED_ENVIRONMENT,
4170 ),
4171 KeyParameter::new(
4172 KeyParameterValue::MacLength(256),
4173 SecurityLevel::TRUSTED_ENVIRONMENT,
4174 ),
4175 KeyParameter::new(
4176 KeyParameterValue::ResetSinceIdRotation,
4177 SecurityLevel::TRUSTED_ENVIRONMENT,
4178 ),
4179 KeyParameter::new(
4180 KeyParameterValue::ConfirmationToken(vec![5u8, 5u8, 5u8, 5u8]),
4181 SecurityLevel::TRUSTED_ENVIRONMENT,
4182 ),
Qi Wub9433b52020-12-01 14:52:46 +08004183 ];
4184 if let Some(value) = max_usage_count {
4185 params.push(KeyParameter::new(
4186 KeyParameterValue::UsageCountLimit(value),
4187 SecurityLevel::SOFTWARE,
4188 ));
4189 }
4190 params
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07004191 }
4192
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004193 fn make_test_key_entry(
4194 db: &mut KeystoreDB,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07004195 domain: Domain,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004196 namespace: i64,
4197 alias: &str,
Qi Wub9433b52020-12-01 14:52:46 +08004198 max_usage_count: Option<i32>,
Janis Danisevskisaec14592020-11-12 09:41:49 -08004199 ) -> Result<KeyIdGuard> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08004200 let key_id = db.create_key_entry(&domain, &namespace, &KEYSTORE_UUID)?;
Janis Danisevskis377d1002021-01-27 19:07:48 -08004201 db.set_blob(&key_id, SubComponentType::KEY_BLOB, Some(TEST_KEY_BLOB))?;
4202 db.set_blob(&key_id, SubComponentType::CERT, Some(TEST_CERT_BLOB))?;
4203 db.set_blob(&key_id, SubComponentType::CERT_CHAIN, Some(TEST_CERT_CHAIN_BLOB))?;
Qi Wub9433b52020-12-01 14:52:46 +08004204
4205 let params = make_test_params(max_usage_count);
4206 db.insert_keyparameter(&key_id, &params)?;
4207
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004208 let mut metadata = KeyMetaData::new();
4209 metadata.add(KeyMetaEntry::EncryptedBy(EncryptedBy::Password));
4210 metadata.add(KeyMetaEntry::Salt(vec![1, 2, 3]));
4211 metadata.add(KeyMetaEntry::Iv(vec![2, 3, 1]));
4212 metadata.add(KeyMetaEntry::AeadTag(vec![3, 1, 2]));
4213 db.insert_key_metadata(&key_id, &metadata)?;
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08004214 rebind_alias(db, &key_id, alias, domain, namespace)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004215 Ok(key_id)
4216 }
4217
Qi Wub9433b52020-12-01 14:52:46 +08004218 fn make_test_key_entry_test_vector(key_id: i64, max_usage_count: Option<i32>) -> KeyEntry {
4219 let params = make_test_params(max_usage_count);
4220
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004221 let mut metadata = KeyMetaData::new();
4222 metadata.add(KeyMetaEntry::EncryptedBy(EncryptedBy::Password));
4223 metadata.add(KeyMetaEntry::Salt(vec![1, 2, 3]));
4224 metadata.add(KeyMetaEntry::Iv(vec![2, 3, 1]));
4225 metadata.add(KeyMetaEntry::AeadTag(vec![3, 1, 2]));
4226
4227 KeyEntry {
4228 id: key_id,
4229 km_blob: Some(TEST_KEY_BLOB.to_vec()),
4230 cert: Some(TEST_CERT_BLOB.to_vec()),
4231 cert_chain: Some(TEST_CERT_CHAIN_BLOB.to_vec()),
Max Bires8e93d2b2021-01-14 13:17:59 -08004232 km_uuid: KEYSTORE_UUID,
Qi Wub9433b52020-12-01 14:52:46 +08004233 parameters: params,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004234 metadata,
Janis Danisevskis377d1002021-01-27 19:07:48 -08004235 pure_cert: false,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004236 }
4237 }
4238
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004239 fn debug_dump_keyentry_table(db: &mut KeystoreDB) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004240 let mut stmt = db.conn.prepare(
Max Bires8e93d2b2021-01-14 13:17:59 -08004241 "SELECT id, key_type, domain, namespace, alias, state, km_uuid FROM persistent.keyentry;",
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004242 )?;
Max Bires8e93d2b2021-01-14 13:17:59 -08004243 let rows = stmt.query_map::<(i64, KeyType, i32, i64, String, KeyLifeCycle, Uuid), _, _>(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004244 NO_PARAMS,
4245 |row| {
Max Bires8e93d2b2021-01-14 13:17:59 -08004246 Ok((
4247 row.get(0)?,
4248 row.get(1)?,
4249 row.get(2)?,
4250 row.get(3)?,
4251 row.get(4)?,
4252 row.get(5)?,
4253 row.get(6)?,
4254 ))
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004255 },
4256 )?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004257
4258 println!("Key entry table rows:");
4259 for r in rows {
Max Bires8e93d2b2021-01-14 13:17:59 -08004260 let (id, key_type, domain, namespace, alias, state, km_uuid) = r.unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004261 println!(
Max Bires8e93d2b2021-01-14 13:17:59 -08004262 " id: {} KeyType: {:?} Domain: {} Namespace: {} Alias: {} State: {:?} KmUuid: {:?}",
4263 id, key_type, domain, namespace, alias, state, km_uuid
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004264 );
4265 }
4266 Ok(())
4267 }
4268
4269 fn debug_dump_grant_table(db: &mut KeystoreDB) -> Result<()> {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08004270 let mut stmt = db
4271 .conn
4272 .prepare("SELECT id, grantee, keyentryid, access_vector FROM persistent.grant;")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004273 let rows = stmt.query_map::<(i64, i64, i64, i64), _, _>(NO_PARAMS, |row| {
4274 Ok((row.get(0)?, row.get(1)?, row.get(2)?, row.get(3)?))
4275 })?;
4276
4277 println!("Grant table rows:");
4278 for r in rows {
4279 let (id, gt, ki, av) = r.unwrap();
4280 println!(" id: {} grantee: {} key_id: {} access_vector: {}", id, gt, ki, av);
4281 }
4282 Ok(())
4283 }
4284
Joel Galenson0891bc12020-07-20 10:37:03 -07004285 // Use a custom random number generator that repeats each number once.
4286 // This allows us to test repeated elements.
4287
4288 thread_local! {
4289 static RANDOM_COUNTER: RefCell<i64> = RefCell::new(0);
4290 }
4291
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004292 fn reset_random() {
4293 RANDOM_COUNTER.with(|counter| {
4294 *counter.borrow_mut() = 0;
4295 })
4296 }
4297
Joel Galenson0891bc12020-07-20 10:37:03 -07004298 pub fn random() -> i64 {
4299 RANDOM_COUNTER.with(|counter| {
4300 let result = *counter.borrow() / 2;
4301 *counter.borrow_mut() += 1;
4302 result
4303 })
4304 }
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00004305
4306 #[test]
4307 fn test_last_off_body() -> Result<()> {
4308 let mut db = new_test_db()?;
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08004309 db.insert_last_off_body(MonotonicRawTime::now())?;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00004310 let tx = db.conn.transaction_with_behavior(TransactionBehavior::Immediate)?;
4311 let last_off_body_1 = KeystoreDB::get_last_off_body(&tx)?;
4312 tx.commit()?;
4313 let one_second = Duration::from_secs(1);
4314 thread::sleep(one_second);
4315 db.update_last_off_body(MonotonicRawTime::now())?;
4316 let tx2 = db.conn.transaction_with_behavior(TransactionBehavior::Immediate)?;
4317 let last_off_body_2 = KeystoreDB::get_last_off_body(&tx2)?;
4318 tx2.commit()?;
4319 assert!(last_off_body_1.seconds() < last_off_body_2.seconds());
4320 Ok(())
4321 }
Joel Galenson26f4d012020-07-17 14:57:21 -07004322}