blob: 2e7fca850017a0cc50dad4a2a65268bb28009249 [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 Danisevskis63f7bc82020-09-03 10:12:56 -0700754 "CREATE TABLE IF NOT EXISTS persistent.blobentry (
755 id INTEGER PRIMARY KEY,
756 subcomponent_type INTEGER,
757 keyentryid INTEGER,
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800758 blob BLOB);",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700759 NO_PARAMS,
760 )
761 .context("Failed to initialize \"blobentry\" table.")?;
762
Janis Danisevskis66784c42021-01-27 08:40:25 -0800763 tx.execute(
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700764 "CREATE TABLE IF NOT EXISTS persistent.keyparameter (
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000765 keyentryid INTEGER,
766 tag INTEGER,
767 data ANY,
768 security_level INTEGER);",
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700769 NO_PARAMS,
770 )
771 .context("Failed to initialize \"keyparameter\" table.")?;
772
Janis Danisevskis66784c42021-01-27 08:40:25 -0800773 tx.execute(
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800774 "CREATE TABLE IF NOT EXISTS persistent.keymetadata (
775 keyentryid INTEGER,
776 tag INTEGER,
777 data ANY);",
778 NO_PARAMS,
779 )
780 .context("Failed to initialize \"keymetadata\" table.")?;
781
Janis Danisevskis66784c42021-01-27 08:40:25 -0800782 tx.execute(
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800783 "CREATE TABLE IF NOT EXISTS persistent.grant (
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700784 id INTEGER UNIQUE,
785 grantee INTEGER,
786 keyentryid INTEGER,
787 access_vector INTEGER);",
788 NO_PARAMS,
789 )
790 .context("Failed to initialize \"grant\" table.")?;
791
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000792 //TODO: only drop the following two perboot tables if this is the first start up
793 //during the boot (b/175716626).
Janis Danisevskis66784c42021-01-27 08:40:25 -0800794 // tx.execute("DROP TABLE IF EXISTS perboot.authtoken;", NO_PARAMS)
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000795 // .context("Failed to drop perboot.authtoken table")?;
Janis Danisevskis66784c42021-01-27 08:40:25 -0800796 tx.execute(
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000797 "CREATE TABLE IF NOT EXISTS perboot.authtoken (
798 id INTEGER PRIMARY KEY,
799 challenge INTEGER,
800 user_id INTEGER,
801 auth_id INTEGER,
802 authenticator_type INTEGER,
803 timestamp INTEGER,
804 mac BLOB,
805 time_received INTEGER,
806 UNIQUE(user_id, auth_id, authenticator_type));",
807 NO_PARAMS,
808 )
809 .context("Failed to initialize \"authtoken\" table.")?;
810
Janis Danisevskis66784c42021-01-27 08:40:25 -0800811 // tx.execute("DROP TABLE IF EXISTS perboot.metadata;", NO_PARAMS)
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000812 // .context("Failed to drop perboot.metadata table")?;
813 // metadata table stores certain miscellaneous information required for keystore functioning
814 // during a boot cycle, as key-value pairs.
Janis Danisevskis66784c42021-01-27 08:40:25 -0800815 tx.execute(
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000816 "CREATE TABLE IF NOT EXISTS perboot.metadata (
817 key TEXT,
818 value BLOB,
819 UNIQUE(key));",
820 NO_PARAMS,
821 )
822 .context("Failed to initialize \"metadata\" table.")?;
Joel Galenson0891bc12020-07-20 10:37:03 -0700823 Ok(())
824 }
825
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700826 fn make_connection(persistent_file: &str, perboot_file: &str) -> Result<Connection> {
827 let conn =
828 Connection::open_in_memory().context("Failed to initialize SQLite connection.")?;
829
Janis Danisevskis66784c42021-01-27 08:40:25 -0800830 loop {
831 if let Err(e) = conn
832 .execute("ATTACH DATABASE ? as persistent;", params![persistent_file])
833 .context("Failed to attach database persistent.")
834 {
835 if Self::is_locked_error(&e) {
836 std::thread::sleep(std::time::Duration::from_micros(500));
837 continue;
838 } else {
839 return Err(e);
840 }
841 }
842 break;
843 }
844 loop {
845 if let Err(e) = conn
846 .execute("ATTACH DATABASE ? as perboot;", params![perboot_file])
847 .context("Failed to attach database perboot.")
848 {
849 if Self::is_locked_error(&e) {
850 std::thread::sleep(std::time::Duration::from_micros(500));
851 continue;
852 } else {
853 return Err(e);
854 }
855 }
856 break;
857 }
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700858
859 Ok(conn)
860 }
861
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800862 /// Get one unreferenced key. There is no particular order in which the keys are returned.
863 fn get_unreferenced_key_id(tx: &Transaction) -> Result<Option<i64>> {
864 tx.query_row(
865 "SELECT id FROM persistent.keyentry WHERE state = ?",
866 params![KeyLifeCycle::Unreferenced],
867 |row| row.get(0),
868 )
869 .optional()
870 .context("In get_unreferenced_key_id: Trying to get unreferenced key id.")
871 }
872
873 /// Returns a key id guard and key entry for one unreferenced key entry. Of the optional
874 /// fields of the key entry only the km_blob field will be populated. This is required
875 /// to subject the blob to its KeyMint instance for deletion.
876 pub fn get_unreferenced_key(&mut self) -> Result<Option<(KeyIdGuard, KeyEntry)>> {
877 self.with_transaction(TransactionBehavior::Deferred, |tx| {
878 let key_id = match Self::get_unreferenced_key_id(tx)
879 .context("Trying to get unreferenced key id")?
880 {
881 None => return Ok(None),
882 Some(id) => KEY_ID_LOCK.try_get(id).ok_or_else(KsError::sys).context(concat!(
883 "A key id lock was held for an unreferenced key. ",
884 "This should never happen."
885 ))?,
886 };
887 let key_entry = Self::load_key_components(tx, KeyEntryLoadBits::KM, key_id.id())
888 .context("Trying to get key components.")?;
889 Ok(Some((key_id, key_entry)))
890 })
891 .context("In get_unreferenced_key.")
892 }
893
894 /// This function purges all remnants of a key entry from the database.
895 /// Important: This does not check if the key was unreferenced, nor does it
896 /// subject the key to its KeyMint instance for permanent invalidation.
897 /// This function should only be called by the garbage collector.
898 /// To delete a key call `mark_unreferenced`, which transitions the key to the unreferenced
899 /// state, deletes all grants to the key, and notifies the garbage collector.
900 /// The garbage collector will:
901 /// 1. Call get_unreferenced_key.
902 /// 2. Determine the proper way to dispose of sensitive key material, e.g., call
903 /// `KeyMintDevice::delete()`.
904 /// 3. Call `purge_key_entry`.
905 pub fn purge_key_entry(&mut self, key_id: KeyIdGuard) -> Result<()> {
906 self.with_transaction(TransactionBehavior::Immediate, |tx| {
907 tx.execute("DELETE FROM persistent.keyentry WHERE id = ?;", params![key_id.id()])
908 .context("Trying to delete keyentry.")?;
909 tx.execute(
910 "DELETE FROM persistent.blobentry WHERE keyentryid = ?;",
911 params![key_id.id()],
912 )
913 .context("Trying to delete blobentries.")?;
914 tx.execute(
915 "DELETE FROM persistent.keymetadata WHERE keyentryid = ?;",
916 params![key_id.id()],
917 )
918 .context("Trying to delete keymetadata.")?;
919 tx.execute(
920 "DELETE FROM persistent.keyparameter WHERE keyentryid = ?;",
921 params![key_id.id()],
922 )
923 .context("Trying to delete keyparameters.")?;
924 let grants_deleted = tx
925 .execute("DELETE FROM persistent.grant WHERE keyentryid = ?;", params![key_id.id()])
926 .context("Trying to delete grants.")?;
927 if grants_deleted != 0 {
928 log::error!("Purged key that still had grants. This should not happen.");
929 }
930 Ok(())
931 })
932 .context("In purge_key_entry.")
933 }
934
935 /// This maintenance function should be called only once before the database is used for the
936 /// first time. It restores the invariant that `KeyLifeCycle::Existing` is a transient state.
937 /// The function transitions all key entries from Existing to Unreferenced unconditionally and
938 /// returns the number of rows affected. If this returns a value greater than 0, it means that
939 /// Keystore crashed at some point during key generation. Callers may want to log such
940 /// occurrences.
941 /// Unlike with `mark_unreferenced`, we don't need to purge grants, because only keys that made
942 /// it to `KeyLifeCycle::Live` may have grants.
943 pub fn cleanup_leftovers(&mut self) -> Result<usize> {
Janis Danisevskis66784c42021-01-27 08:40:25 -0800944 self.with_transaction(TransactionBehavior::Immediate, |tx| {
945 tx.execute(
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800946 "UPDATE persistent.keyentry SET state = ? WHERE state = ?;",
947 params![KeyLifeCycle::Unreferenced, KeyLifeCycle::Existing],
948 )
Janis Danisevskis66784c42021-01-27 08:40:25 -0800949 .context("Failed to execute query.")
950 })
951 .context("In cleanup_leftovers.")
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800952 }
953
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800954 /// Atomically loads a key entry and associated metadata or creates it using the
955 /// callback create_new_key callback. The callback is called during a database
956 /// transaction. This means that implementers should be mindful about using
957 /// blocking operations such as IPC or grabbing mutexes.
958 pub fn get_or_create_key_with<F>(
959 &mut self,
960 domain: Domain,
961 namespace: i64,
962 alias: &str,
Max Bires8e93d2b2021-01-14 13:17:59 -0800963 km_uuid: Uuid,
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800964 create_new_key: F,
965 ) -> Result<(KeyIdGuard, KeyEntry)>
966 where
Janis Danisevskis66784c42021-01-27 08:40:25 -0800967 F: Fn() -> Result<(Vec<u8>, KeyMetaData)>,
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800968 {
Janis Danisevskis66784c42021-01-27 08:40:25 -0800969 self.with_transaction(TransactionBehavior::Immediate, |tx| {
970 let id = {
971 let mut stmt = tx
972 .prepare(
973 "SELECT id FROM persistent.keyentry
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800974 WHERE
975 key_type = ?
976 AND domain = ?
977 AND namespace = ?
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800978 AND alias = ?
979 AND state = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -0800980 )
981 .context("In get_or_create_key_with: Failed to select from keyentry table.")?;
982 let mut rows = stmt
983 .query(params![KeyType::Super, domain.0, namespace, alias, KeyLifeCycle::Live])
984 .context("In get_or_create_key_with: Failed to query from keyentry table.")?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800985
Janis Danisevskis66784c42021-01-27 08:40:25 -0800986 db_utils::with_rows_extract_one(&mut rows, |row| {
987 Ok(match row {
988 Some(r) => r.get(0).context("Failed to unpack id.")?,
989 None => None,
990 })
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800991 })
Janis Danisevskis66784c42021-01-27 08:40:25 -0800992 .context("In get_or_create_key_with.")?
993 };
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800994
Janis Danisevskis66784c42021-01-27 08:40:25 -0800995 let (id, entry) = match id {
996 Some(id) => (
997 id,
998 Self::load_key_components(&tx, KeyEntryLoadBits::KM, id)
999 .context("In get_or_create_key_with.")?,
1000 ),
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001001
Janis Danisevskis66784c42021-01-27 08:40:25 -08001002 None => {
1003 let id = Self::insert_with_retry(|id| {
1004 tx.execute(
1005 "INSERT into persistent.keyentry
Max Bires8e93d2b2021-01-14 13:17:59 -08001006 (id, key_type, domain, namespace, alias, state, km_uuid)
1007 VALUES(?, ?, ?, ?, ?, ?, ?);",
Janis Danisevskis66784c42021-01-27 08:40:25 -08001008 params![
1009 id,
1010 KeyType::Super,
1011 domain.0,
1012 namespace,
1013 alias,
1014 KeyLifeCycle::Live,
1015 km_uuid,
1016 ],
1017 )
1018 })
1019 .context("In get_or_create_key_with.")?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001020
Janis Danisevskis66784c42021-01-27 08:40:25 -08001021 let (blob, metadata) =
1022 create_new_key().context("In get_or_create_key_with.")?;
1023 Self::set_blob_internal(&tx, id, SubComponentType::KEY_BLOB, Some(&blob))
1024 .context("In get_of_create_key_with.")?;
1025 metadata.store_in_db(id, &tx).context("In get_or_create_key_with.")?;
1026 (
Janis Danisevskis377d1002021-01-27 19:07:48 -08001027 id,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001028 KeyEntry {
1029 id,
1030 km_blob: Some(blob),
1031 metadata,
1032 pure_cert: false,
1033 ..Default::default()
1034 },
1035 )
1036 }
1037 };
1038 Ok((KEY_ID_LOCK.get(id), entry))
1039 })
1040 .context("In get_or_create_key_with.")
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001041 }
1042
Janis Danisevskis66784c42021-01-27 08:40:25 -08001043 /// SQLite3 seems to hold a shared mutex while running the busy handler when
1044 /// waiting for the database file to become available. This makes it
1045 /// impossible to successfully recover from a locked database when the
1046 /// transaction holding the device busy is in the same process on a
1047 /// different connection. As a result the busy handler has to time out and
1048 /// fail in order to make progress.
1049 ///
1050 /// Instead, we set the busy handler to None (return immediately). And catch
1051 /// Busy and Locked errors (the latter occur on in memory databases with
1052 /// shared cache, e.g., the per-boot database.) and restart the transaction
1053 /// after a grace period of half a millisecond.
1054 ///
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001055 /// Creates a transaction with the given behavior and executes f with the new transaction.
Janis Danisevskis66784c42021-01-27 08:40:25 -08001056 /// The transaction is committed only if f returns Ok and retried if DatabaseBusy
1057 /// or DatabaseLocked is encountered.
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001058 fn with_transaction<T, F>(&mut self, behavior: TransactionBehavior, f: F) -> Result<T>
1059 where
Janis Danisevskis66784c42021-01-27 08:40:25 -08001060 F: Fn(&Transaction) -> Result<T>,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001061 {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001062 loop {
1063 match self
1064 .conn
1065 .transaction_with_behavior(behavior)
1066 .context("In with_transaction.")
1067 .and_then(|tx| f(&tx).map(|result| (result, tx)))
1068 .and_then(|(result, tx)| {
1069 tx.commit().context("In with_transaction: Failed to commit transaction.")?;
1070 Ok(result)
1071 }) {
1072 Ok(result) => break Ok(result),
1073 Err(e) => {
1074 if Self::is_locked_error(&e) {
1075 std::thread::sleep(std::time::Duration::from_micros(500));
1076 continue;
1077 } else {
1078 return Err(e).context("In with_transaction.");
1079 }
1080 }
1081 }
1082 }
1083 }
1084
1085 fn is_locked_error(e: &anyhow::Error) -> bool {
1086 matches!(e.root_cause().downcast_ref::<rusqlite::ffi::Error>(),
1087 Some(rusqlite::ffi::Error {
1088 code: rusqlite::ErrorCode::DatabaseBusy,
1089 ..
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001090 })
Janis Danisevskis66784c42021-01-27 08:40:25 -08001091 | Some(rusqlite::ffi::Error {
1092 code: rusqlite::ErrorCode::DatabaseLocked,
1093 ..
1094 }))
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001095 }
1096
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001097 /// Creates a new key entry and allocates a new randomized id for the new key.
1098 /// The key id gets associated with a domain and namespace but not with an alias.
1099 /// To complete key generation `rebind_alias` should be called after all of the
1100 /// key artifacts, i.e., blobs and parameters have been associated with the new
1101 /// key id. Finalizing with `rebind_alias` makes the creation of a new key entry
1102 /// atomic even if key generation is not.
Max Bires8e93d2b2021-01-14 13:17:59 -08001103 pub fn create_key_entry(
1104 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001105 domain: &Domain,
1106 namespace: &i64,
Max Bires8e93d2b2021-01-14 13:17:59 -08001107 km_uuid: &Uuid,
1108 ) -> Result<KeyIdGuard> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001109 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Max Bires8e93d2b2021-01-14 13:17:59 -08001110 Self::create_key_entry_internal(tx, domain, namespace, km_uuid)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001111 })
1112 .context("In create_key_entry.")
1113 }
1114
1115 fn create_key_entry_internal(
1116 tx: &Transaction,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001117 domain: &Domain,
1118 namespace: &i64,
Max Bires8e93d2b2021-01-14 13:17:59 -08001119 km_uuid: &Uuid,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001120 ) -> Result<KeyIdGuard> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001121 match *domain {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001122 Domain::APP | Domain::SELINUX => {}
Joel Galenson0891bc12020-07-20 10:37:03 -07001123 _ => {
1124 return Err(KsError::sys())
1125 .context(format!("Domain {:?} must be either App or SELinux.", domain));
1126 }
1127 }
Janis Danisevskisaec14592020-11-12 09:41:49 -08001128 Ok(KEY_ID_LOCK.get(
1129 Self::insert_with_retry(|id| {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001130 tx.execute(
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001131 "INSERT into persistent.keyentry
Max Bires8e93d2b2021-01-14 13:17:59 -08001132 (id, key_type, domain, namespace, alias, state, km_uuid)
1133 VALUES(?, ?, ?, ?, NULL, ?, ?);",
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001134 params![
1135 id,
1136 KeyType::Client,
1137 domain.0 as u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001138 *namespace,
Max Bires8e93d2b2021-01-14 13:17:59 -08001139 KeyLifeCycle::Existing,
1140 km_uuid,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001141 ],
Janis Danisevskisaec14592020-11-12 09:41:49 -08001142 )
1143 })
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001144 .context("In create_key_entry_internal")?,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001145 ))
Joel Galenson26f4d012020-07-17 14:57:21 -07001146 }
Joel Galenson33c04ad2020-08-03 11:04:38 -07001147
Max Bires2b2e6562020-09-22 11:22:36 -07001148 /// Creates a new attestation key entry and allocates a new randomized id for the new key.
1149 /// The key id gets associated with a domain and namespace later but not with an alias. The
1150 /// alias will be used to denote if a key has been signed as each key can only be bound to one
1151 /// domain and namespace pairing so there is no need to use them as a value for indexing into
1152 /// a key.
1153 pub fn create_attestation_key_entry(
1154 &mut self,
1155 maced_public_key: &[u8],
1156 raw_public_key: &[u8],
1157 private_key: &[u8],
1158 km_uuid: &Uuid,
1159 ) -> Result<()> {
1160 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1161 let key_id = KEY_ID_LOCK.get(
1162 Self::insert_with_retry(|id| {
1163 tx.execute(
1164 "INSERT into persistent.keyentry
1165 (id, key_type, domain, namespace, alias, state, km_uuid)
1166 VALUES(?, ?, NULL, NULL, NULL, ?, ?);",
1167 params![id, KeyType::Attestation, KeyLifeCycle::Live, km_uuid],
1168 )
1169 })
1170 .context("In create_key_entry")?,
1171 );
1172 Self::set_blob_internal(&tx, key_id.0, SubComponentType::KEY_BLOB, Some(private_key))?;
1173 let mut metadata = KeyMetaData::new();
1174 metadata.add(KeyMetaEntry::AttestationMacedPublicKey(maced_public_key.to_vec()));
1175 metadata.add(KeyMetaEntry::AttestationRawPubKey(raw_public_key.to_vec()));
1176 metadata.store_in_db(key_id.0, &tx)?;
1177 Ok(())
1178 })
1179 .context("In create_attestation_key_entry")
1180 }
1181
Janis Danisevskis377d1002021-01-27 19:07:48 -08001182 /// Set a new blob and associates it with the given key id. Each blob
1183 /// has a sub component type.
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001184 /// Each key can have one of each sub component type associated. If more
1185 /// are added only the most recent can be retrieved, and superseded blobs
Janis Danisevskis377d1002021-01-27 19:07:48 -08001186 /// will get garbage collected.
1187 /// Components SubComponentType::CERT and SubComponentType::CERT_CHAIN can be
1188 /// removed by setting blob to None.
1189 pub fn set_blob(
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001190 &mut self,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001191 key_id: &KeyIdGuard,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001192 sc_type: SubComponentType,
Janis Danisevskis377d1002021-01-27 19:07:48 -08001193 blob: Option<&[u8]>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001194 ) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001195 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis377d1002021-01-27 19:07:48 -08001196 Self::set_blob_internal(&tx, key_id.0, sc_type, blob)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001197 })
Janis Danisevskis377d1002021-01-27 19:07:48 -08001198 .context("In set_blob.")
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001199 }
1200
Janis Danisevskis377d1002021-01-27 19:07:48 -08001201 fn set_blob_internal(
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001202 tx: &Transaction,
1203 key_id: i64,
1204 sc_type: SubComponentType,
Janis Danisevskis377d1002021-01-27 19:07:48 -08001205 blob: Option<&[u8]>,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001206 ) -> Result<()> {
Janis Danisevskis377d1002021-01-27 19:07:48 -08001207 match (blob, sc_type) {
1208 (Some(blob), _) => {
1209 tx.execute(
1210 "INSERT INTO persistent.blobentry
1211 (subcomponent_type, keyentryid, blob) VALUES (?, ?, ?);",
1212 params![sc_type, key_id, blob],
1213 )
1214 .context("In set_blob_internal: Failed to insert blob.")?;
1215 }
1216 (None, SubComponentType::CERT) | (None, SubComponentType::CERT_CHAIN) => {
1217 tx.execute(
1218 "DELETE FROM persistent.blobentry
1219 WHERE subcomponent_type = ? AND keyentryid = ?;",
1220 params![sc_type, key_id],
1221 )
1222 .context("In set_blob_internal: Failed to delete blob.")?;
1223 }
1224 (None, _) => {
1225 return Err(KsError::sys())
1226 .context("In set_blob_internal: Other blobs cannot be deleted in this way.");
1227 }
1228 }
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001229 Ok(())
1230 }
1231
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001232 /// Inserts a collection of key parameters into the `persistent.keyparameter` table
1233 /// and associates them with the given `key_id`.
Janis Danisevskis66784c42021-01-27 08:40:25 -08001234 pub fn insert_keyparameter(
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001235 &mut self,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001236 key_id: &KeyIdGuard,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001237 params: &[KeyParameter],
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001238 ) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001239 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1240 Self::insert_keyparameter_internal(tx, key_id, params)
1241 })
1242 .context("In insert_keyparameter.")
1243 }
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001244
Janis Danisevskis66784c42021-01-27 08:40:25 -08001245 fn insert_keyparameter_internal(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001246 tx: &Transaction,
1247 key_id: &KeyIdGuard,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001248 params: &[KeyParameter],
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001249 ) -> Result<()> {
1250 let mut stmt = tx
1251 .prepare(
1252 "INSERT into persistent.keyparameter (keyentryid, tag, data, security_level)
1253 VALUES (?, ?, ?, ?);",
1254 )
1255 .context("In insert_keyparameter_internal: Failed to prepare statement.")?;
1256
Janis Danisevskis66784c42021-01-27 08:40:25 -08001257 for p in params.iter() {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001258 stmt.insert(params![
1259 key_id.0,
1260 p.get_tag().0,
1261 p.key_parameter_value(),
1262 p.security_level().0
1263 ])
1264 .with_context(|| {
1265 format!("In insert_keyparameter_internal: Failed to insert {:?}", p)
1266 })?;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001267 }
1268 Ok(())
1269 }
1270
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001271 /// Insert a set of key entry specific metadata into the database.
1272 pub fn insert_key_metadata(
1273 &mut self,
1274 key_id: &KeyIdGuard,
1275 metadata: &KeyMetaData,
1276 ) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001277 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1278 metadata.store_in_db(key_id.0, &tx)
1279 })
1280 .context("In insert_key_metadata.")
1281 }
1282
Max Bires2b2e6562020-09-22 11:22:36 -07001283 /// Stores a signed certificate chain signed by a remote provisioning server, keyed
1284 /// on the public key.
1285 pub fn store_signed_attestation_certificate_chain(
1286 &mut self,
1287 raw_public_key: &[u8],
1288 cert_chain: &[u8],
1289 expiration_date: i64,
1290 km_uuid: &Uuid,
1291 ) -> Result<()> {
1292 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1293 let mut stmt = tx
1294 .prepare(
1295 "SELECT keyentryid
1296 FROM persistent.keymetadata
1297 WHERE tag = ? AND data = ? AND keyentryid IN
1298 (SELECT id
1299 FROM persistent.keyentry
1300 WHERE
1301 alias IS NULL AND
1302 domain IS NULL AND
1303 namespace IS NULL AND
1304 key_type = ? AND
1305 km_uuid = ?);",
1306 )
1307 .context("Failed to store attestation certificate chain.")?;
1308 let mut rows = stmt
1309 .query(params![
1310 KeyMetaData::AttestationRawPubKey,
1311 raw_public_key,
1312 KeyType::Attestation,
1313 km_uuid
1314 ])
1315 .context("Failed to fetch keyid")?;
1316 let key_id = db_utils::with_rows_extract_one(&mut rows, |row| {
1317 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?
1318 .get(0)
1319 .context("Failed to unpack id.")
1320 })
1321 .context("Failed to get key_id.")?;
1322 let num_updated = tx
1323 .execute(
1324 "UPDATE persistent.keyentry
1325 SET alias = ?
1326 WHERE id = ?;",
1327 params!["signed", key_id],
1328 )
1329 .context("Failed to update alias.")?;
1330 if num_updated != 1 {
1331 return Err(KsError::sys()).context("Alias not updated for the key.");
1332 }
1333 let mut metadata = KeyMetaData::new();
1334 metadata.add(KeyMetaEntry::AttestationExpirationDate(DateTime::from_millis_epoch(
1335 expiration_date,
1336 )));
1337 metadata.store_in_db(key_id, &tx).context("Failed to insert key metadata.")?;
1338 Self::set_blob_internal(&tx, key_id, SubComponentType::CERT_CHAIN, Some(cert_chain))
1339 .context("Failed to insert cert chain")?;
1340 Ok(())
1341 })
1342 .context("In store_signed_attestation_certificate_chain: ")
1343 }
1344
1345 /// Assigns the next unassigned attestation key to a domain/namespace combo that does not
1346 /// currently have a key assigned to it.
1347 pub fn assign_attestation_key(
1348 &mut self,
1349 domain: Domain,
1350 namespace: i64,
1351 km_uuid: &Uuid,
1352 ) -> Result<()> {
1353 match domain {
1354 Domain::APP | Domain::SELINUX => {}
1355 _ => {
1356 return Err(KsError::sys()).context(format!(
1357 concat!(
1358 "In assign_attestation_key: Domain {:?} ",
1359 "must be either App or SELinux.",
1360 ),
1361 domain
1362 ));
1363 }
1364 }
1365 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1366 let result = tx
1367 .execute(
1368 "UPDATE persistent.keyentry
1369 SET domain=?1, namespace=?2
1370 WHERE
1371 id =
1372 (SELECT MIN(id)
1373 FROM persistent.keyentry
1374 WHERE ALIAS IS NOT NULL
1375 AND domain IS NULL
1376 AND key_type IS ?3
1377 AND state IS ?4
1378 AND km_uuid IS ?5)
1379 AND
1380 (SELECT COUNT(*)
1381 FROM persistent.keyentry
1382 WHERE domain=?1
1383 AND namespace=?2
1384 AND key_type IS ?3
1385 AND state IS ?4
1386 AND km_uuid IS ?5) = 0;",
1387 params![
1388 domain.0 as u32,
1389 namespace,
1390 KeyType::Attestation,
1391 KeyLifeCycle::Live,
1392 km_uuid,
1393 ],
1394 )
1395 .context("Failed to assign attestation key")?;
1396 if result != 1 {
1397 return Err(KsError::sys()).context(format!(
1398 "Expected to update a single entry but instead updated {}.",
1399 result
1400 ));
1401 }
1402 Ok(())
1403 })
1404 .context("In assign_attestation_key: ")
1405 }
1406
1407 /// Retrieves num_keys number of attestation keys that have not yet been signed by a remote
1408 /// provisioning server, or the maximum number available if there are not num_keys number of
1409 /// entries in the table.
1410 pub fn fetch_unsigned_attestation_keys(
1411 &mut self,
1412 num_keys: i32,
1413 km_uuid: &Uuid,
1414 ) -> Result<Vec<Vec<u8>>> {
1415 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1416 let mut stmt = tx
1417 .prepare(
1418 "SELECT data
1419 FROM persistent.keymetadata
1420 WHERE tag = ? AND keyentryid IN
1421 (SELECT id
1422 FROM persistent.keyentry
1423 WHERE
1424 alias IS NULL AND
1425 domain IS NULL AND
1426 namespace IS NULL AND
1427 key_type = ? AND
1428 km_uuid = ?
1429 LIMIT ?);",
1430 )
1431 .context("Failed to prepare statement")?;
1432 let rows = stmt
1433 .query_map(
1434 params![
1435 KeyMetaData::AttestationMacedPublicKey,
1436 KeyType::Attestation,
1437 km_uuid,
1438 num_keys
1439 ],
1440 |row| Ok(row.get(0)?),
1441 )?
1442 .collect::<rusqlite::Result<Vec<Vec<u8>>>>()
1443 .context("Failed to execute statement")?;
1444 Ok(rows)
1445 })
1446 .context("In fetch_unsigned_attestation_keys")
1447 }
1448
1449 /// Removes any keys that have expired as of the current time. Returns the number of keys
1450 /// marked unreferenced that are bound to be garbage collected.
1451 pub fn delete_expired_attestation_keys(&mut self) -> Result<i32> {
1452 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1453 let mut stmt = tx
1454 .prepare(
1455 "SELECT keyentryid, data
1456 FROM persistent.keymetadata
1457 WHERE tag = ? AND keyentryid IN
1458 (SELECT id
1459 FROM persistent.keyentry
1460 WHERE key_type = ?);",
1461 )
1462 .context("Failed to prepare query")?;
1463 let key_ids_to_check = stmt
1464 .query_map(
1465 params![KeyMetaData::AttestationExpirationDate, KeyType::Attestation],
1466 |row| Ok((row.get(0)?, row.get(1)?)),
1467 )?
1468 .collect::<rusqlite::Result<Vec<(i64, DateTime)>>>()
1469 .context("Failed to get date metadata")?;
1470 let curr_time = DateTime::from_millis_epoch(
1471 SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_millis() as i64,
1472 );
1473 let mut num_deleted = 0;
1474 for id in key_ids_to_check.iter().filter(|kt| kt.1 < curr_time).map(|kt| kt.0) {
1475 if Self::mark_unreferenced(&tx, id)? {
1476 num_deleted += 1;
1477 }
1478 }
1479 Ok(num_deleted)
1480 })
1481 .context("In delete_expired_attestation_keys: ")
1482 }
1483
1484 /// Counts the number of keys that will expire by the provided epoch date and the number of
1485 /// keys not currently assigned to a domain.
1486 pub fn get_attestation_pool_status(
1487 &mut self,
1488 date: i64,
1489 km_uuid: &Uuid,
1490 ) -> Result<AttestationPoolStatus> {
1491 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1492 let mut stmt = tx.prepare(
1493 "SELECT data
1494 FROM persistent.keymetadata
1495 WHERE tag = ? AND keyentryid IN
1496 (SELECT id
1497 FROM persistent.keyentry
1498 WHERE alias IS NOT NULL
1499 AND key_type = ?
1500 AND km_uuid = ?
1501 AND state = ?);",
1502 )?;
1503 let times = stmt
1504 .query_map(
1505 params![
1506 KeyMetaData::AttestationExpirationDate,
1507 KeyType::Attestation,
1508 km_uuid,
1509 KeyLifeCycle::Live
1510 ],
1511 |row| Ok(row.get(0)?),
1512 )?
1513 .collect::<rusqlite::Result<Vec<DateTime>>>()
1514 .context("Failed to execute metadata statement")?;
1515 let expiring =
1516 times.iter().filter(|time| time < &&DateTime::from_millis_epoch(date)).count()
1517 as i32;
1518 stmt = tx.prepare(
1519 "SELECT alias, domain
1520 FROM persistent.keyentry
1521 WHERE key_type = ? AND km_uuid = ? AND state = ?;",
1522 )?;
1523 let rows = stmt
1524 .query_map(params![KeyType::Attestation, km_uuid, KeyLifeCycle::Live], |row| {
1525 Ok((row.get(0)?, row.get(1)?))
1526 })?
1527 .collect::<rusqlite::Result<Vec<(Option<String>, Option<u32>)>>>()
1528 .context("Failed to execute keyentry statement")?;
1529 let mut unassigned = 0i32;
1530 let mut attested = 0i32;
1531 let total = rows.len() as i32;
1532 for (alias, domain) in rows {
1533 match (alias, domain) {
1534 (Some(_alias), None) => {
1535 attested += 1;
1536 unassigned += 1;
1537 }
1538 (Some(_alias), Some(_domain)) => {
1539 attested += 1;
1540 }
1541 _ => {}
1542 }
1543 }
1544 Ok(AttestationPoolStatus { expiring, unassigned, attested, total })
1545 })
1546 .context("In get_attestation_pool_status: ")
1547 }
1548
1549 /// Fetches the private key and corresponding certificate chain assigned to a
1550 /// domain/namespace pair. Will either return nothing if the domain/namespace is
1551 /// not assigned, or one CertificateChain.
1552 pub fn retrieve_attestation_key_and_cert_chain(
1553 &mut self,
1554 domain: Domain,
1555 namespace: i64,
1556 km_uuid: &Uuid,
1557 ) -> Result<Option<CertificateChain>> {
1558 match domain {
1559 Domain::APP | Domain::SELINUX => {}
1560 _ => {
1561 return Err(KsError::sys())
1562 .context(format!("Domain {:?} must be either App or SELinux.", domain));
1563 }
1564 }
1565 let mut stmt = self.conn.prepare(
1566 "SELECT subcomponent_type, blob
1567 FROM persistent.blobentry
1568 WHERE keyentryid IN
1569 (SELECT id
1570 FROM persistent.keyentry
1571 WHERE key_type = ?
1572 AND domain = ?
1573 AND namespace = ?
1574 AND state = ?
1575 AND km_uuid = ?);",
1576 )?;
1577 let rows = stmt
1578 .query_map(
1579 params![
1580 KeyType::Attestation,
1581 domain.0 as u32,
1582 namespace,
1583 KeyLifeCycle::Live,
1584 km_uuid
1585 ],
1586 |row| Ok((row.get(0)?, row.get(1)?)),
1587 )?
1588 .collect::<rusqlite::Result<Vec<(SubComponentType, Vec<u8>)>>>()
1589 .context("In retrieve_attestation_key_and_cert_chain: query failed.")?;
1590 if rows.is_empty() {
1591 return Ok(None);
1592 } else if rows.len() != 2 {
1593 return Err(KsError::sys()).context(format!(
1594 concat!(
1595 "In retrieve_attestation_key_and_cert_chain: Expected to get a single attestation",
1596 "key chain but instead got {}."),
1597 rows.len()
1598 ));
1599 }
1600 let mut km_blob: Vec<u8> = Vec::new();
1601 let mut cert_chain_blob: Vec<u8> = Vec::new();
1602 for row in rows {
1603 let sub_type: SubComponentType = row.0;
1604 match sub_type {
1605 SubComponentType::KEY_BLOB => {
1606 km_blob = row.1;
1607 }
1608 SubComponentType::CERT_CHAIN => {
1609 cert_chain_blob = row.1;
1610 }
1611 _ => Err(KsError::sys()).context("Unknown or incorrect subcomponent type.")?,
1612 }
1613 }
1614 Ok(Some(CertificateChain {
1615 private_key: ZVec::try_from(km_blob)?,
1616 cert_chain: ZVec::try_from(cert_chain_blob)?,
1617 }))
1618 }
1619
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001620 /// Updates the alias column of the given key id `newid` with the given alias,
1621 /// and atomically, removes the alias, domain, and namespace from another row
1622 /// with the same alias-domain-namespace tuple if such row exits.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001623 /// Returns Ok(true) if an old key was marked unreferenced as a hint to the garbage
1624 /// collector.
1625 fn rebind_alias(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001626 tx: &Transaction,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001627 newid: &KeyIdGuard,
Joel Galenson33c04ad2020-08-03 11:04:38 -07001628 alias: &str,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001629 domain: &Domain,
1630 namespace: &i64,
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001631 ) -> Result<bool> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001632 match *domain {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001633 Domain::APP | Domain::SELINUX => {}
Joel Galenson33c04ad2020-08-03 11:04:38 -07001634 _ => {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001635 return Err(KsError::sys()).context(format!(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001636 "In rebind_alias: Domain {:?} must be either App or SELinux.",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001637 domain
1638 ));
Joel Galenson33c04ad2020-08-03 11:04:38 -07001639 }
1640 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001641 let updated = tx
1642 .execute(
1643 "UPDATE persistent.keyentry
1644 SET alias = NULL, domain = NULL, namespace = NULL, state = ?
Joel Galenson33c04ad2020-08-03 11:04:38 -07001645 WHERE alias = ? AND domain = ? AND namespace = ?;",
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001646 params![KeyLifeCycle::Unreferenced, alias, domain.0 as u32, namespace],
1647 )
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001648 .context("In rebind_alias: Failed to rebind existing entry.")?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07001649 let result = tx
1650 .execute(
1651 "UPDATE persistent.keyentry
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001652 SET alias = ?, state = ?
1653 WHERE id = ? AND domain = ? AND namespace = ? AND state = ?;",
1654 params![
1655 alias,
1656 KeyLifeCycle::Live,
1657 newid.0,
1658 domain.0 as u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001659 *namespace,
Max Bires8e93d2b2021-01-14 13:17:59 -08001660 KeyLifeCycle::Existing,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001661 ],
Joel Galenson33c04ad2020-08-03 11:04:38 -07001662 )
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001663 .context("In rebind_alias: Failed to set alias.")?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07001664 if result != 1 {
Joel Galenson33c04ad2020-08-03 11:04:38 -07001665 return Err(KsError::sys()).context(format!(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001666 "In rebind_alias: Expected to update a single entry but instead updated {}.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07001667 result
1668 ));
1669 }
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001670 Ok(updated != 0)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001671 }
1672
1673 /// Store a new key in a single transaction.
1674 /// The function creates a new key entry, populates the blob, key parameter, and metadata
1675 /// fields, and rebinds the given alias to the new key.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001676 /// The boolean returned is a hint for the garbage collector. If true, a key was replaced,
1677 /// is now unreferenced and needs to be collected.
Janis Danisevskis66784c42021-01-27 08:40:25 -08001678 pub fn store_new_key(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001679 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001680 key: &KeyDescriptor,
1681 params: &[KeyParameter],
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001682 blob: &[u8],
Max Bires8e93d2b2021-01-14 13:17:59 -08001683 cert_info: &CertificateInfo,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001684 metadata: &KeyMetaData,
Max Bires8e93d2b2021-01-14 13:17:59 -08001685 km_uuid: &Uuid,
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001686 ) -> Result<(bool, KeyIdGuard)> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001687 let (alias, domain, namespace) = match key {
1688 KeyDescriptor { alias: Some(alias), domain: Domain::APP, nspace, blob: None }
1689 | KeyDescriptor { alias: Some(alias), domain: Domain::SELINUX, nspace, blob: None } => {
1690 (alias, key.domain, nspace)
1691 }
1692 _ => {
1693 return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT))
1694 .context("In store_new_key: Need alias and domain must be APP or SELINUX.")
1695 }
1696 };
1697 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001698 let key_id = Self::create_key_entry_internal(tx, &domain, namespace, km_uuid)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001699 .context("Trying to create new key entry.")?;
Janis Danisevskis377d1002021-01-27 19:07:48 -08001700 Self::set_blob_internal(tx, key_id.id(), SubComponentType::KEY_BLOB, Some(blob))
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001701 .context("Trying to insert the key blob.")?;
Max Bires8e93d2b2021-01-14 13:17:59 -08001702 if let Some(cert) = &cert_info.cert {
Janis Danisevskis377d1002021-01-27 19:07:48 -08001703 Self::set_blob_internal(tx, key_id.id(), SubComponentType::CERT, Some(&cert))
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001704 .context("Trying to insert the certificate.")?;
1705 }
Max Bires8e93d2b2021-01-14 13:17:59 -08001706 if let Some(cert_chain) = &cert_info.cert_chain {
Janis Danisevskis377d1002021-01-27 19:07:48 -08001707 Self::set_blob_internal(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001708 tx,
1709 key_id.id(),
1710 SubComponentType::CERT_CHAIN,
Janis Danisevskis377d1002021-01-27 19:07:48 -08001711 Some(&cert_chain),
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001712 )
1713 .context("Trying to insert the certificate chain.")?;
1714 }
1715 Self::insert_keyparameter_internal(tx, &key_id, params)
1716 .context("Trying to insert key parameters.")?;
Janis Danisevskis377d1002021-01-27 19:07:48 -08001717 metadata.store_in_db(key_id.id(), tx).context("Trying to insert key metadata.")?;
Janis Danisevskis66784c42021-01-27 08:40:25 -08001718 let need_gc = Self::rebind_alias(tx, &key_id, &alias, &domain, namespace)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001719 .context("Trying to rebind alias.")?;
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001720 Ok((need_gc, key_id))
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001721 })
1722 .context("In store_new_key.")
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001723 }
1724
Janis Danisevskis377d1002021-01-27 19:07:48 -08001725 /// Store a new certificate
1726 /// The function creates a new key entry, populates the blob field and metadata, and rebinds
1727 /// the given alias to the new cert.
Max Bires8e93d2b2021-01-14 13:17:59 -08001728 pub fn store_new_certificate(
1729 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001730 key: &KeyDescriptor,
Max Bires8e93d2b2021-01-14 13:17:59 -08001731 cert: &[u8],
1732 km_uuid: &Uuid,
1733 ) -> Result<KeyIdGuard> {
Janis Danisevskis377d1002021-01-27 19:07:48 -08001734 let (alias, domain, namespace) = match key {
1735 KeyDescriptor { alias: Some(alias), domain: Domain::APP, nspace, blob: None }
1736 | KeyDescriptor { alias: Some(alias), domain: Domain::SELINUX, nspace, blob: None } => {
1737 (alias, key.domain, nspace)
1738 }
1739 _ => {
1740 return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT)).context(
1741 "In store_new_certificate: Need alias and domain must be APP or SELINUX.",
1742 )
1743 }
1744 };
1745 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001746 let key_id = Self::create_key_entry_internal(tx, &domain, namespace, km_uuid)
Janis Danisevskis377d1002021-01-27 19:07:48 -08001747 .context("Trying to create new key entry.")?;
1748
1749 Self::set_blob_internal(tx, key_id.id(), SubComponentType::CERT_CHAIN, Some(cert))
1750 .context("Trying to insert certificate.")?;
1751
1752 let mut metadata = KeyMetaData::new();
1753 metadata.add(KeyMetaEntry::CreationDate(
1754 DateTime::now().context("Trying to make creation time.")?,
1755 ));
1756
1757 metadata.store_in_db(key_id.id(), tx).context("Trying to insert key metadata.")?;
1758
Janis Danisevskis66784c42021-01-27 08:40:25 -08001759 Self::rebind_alias(tx, &key_id, &alias, &domain, namespace)
Janis Danisevskis377d1002021-01-27 19:07:48 -08001760 .context("Trying to rebind alias.")?;
1761 Ok(key_id)
1762 })
1763 .context("In store_new_certificate.")
1764 }
1765
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001766 // Helper function loading the key_id given the key descriptor
1767 // tuple comprising domain, namespace, and alias.
1768 // Requires a valid transaction.
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001769 fn load_key_entry_id(tx: &Transaction, key: &KeyDescriptor, key_type: KeyType) -> Result<i64> {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001770 let alias = key
1771 .alias
1772 .as_ref()
1773 .map_or_else(|| Err(KsError::sys()), Ok)
1774 .context("In load_key_entry_id: Alias must be specified.")?;
1775 let mut stmt = tx
1776 .prepare(
1777 "SELECT id FROM persistent.keyentry
1778 WHERE
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001779 key_type = ?
1780 AND domain = ?
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001781 AND namespace = ?
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001782 AND alias = ?
1783 AND state = ?;",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001784 )
1785 .context("In load_key_entry_id: Failed to select from keyentry table.")?;
1786 let mut rows = stmt
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001787 .query(params![key_type, key.domain.0 as u32, key.nspace, alias, KeyLifeCycle::Live])
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001788 .context("In load_key_entry_id: Failed to read from keyentry table.")?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08001789 db_utils::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001790 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001791 .get(0)
1792 .context("Failed to unpack id.")
1793 })
1794 .context("In load_key_entry_id.")
1795 }
1796
1797 /// This helper function completes the access tuple of a key, which is required
1798 /// to perform access control. The strategy depends on the `domain` field in the
1799 /// key descriptor.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001800 /// * Domain::SELINUX: The access tuple is complete and this function only loads
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001801 /// the key_id for further processing.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001802 /// * Domain::APP: Like Domain::SELINUX, but the tuple is completed by `caller_uid`
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001803 /// which serves as the namespace.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001804 /// * Domain::GRANT: The grant table is queried for the `key_id` and the
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001805 /// `access_vector`.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001806 /// * Domain::KEY_ID: The keyentry table is queried for the owning `domain` and
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001807 /// `namespace`.
1808 /// In each case the information returned is sufficient to perform the access
1809 /// check and the key id can be used to load further key artifacts.
1810 fn load_access_tuple(
1811 tx: &Transaction,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001812 key: &KeyDescriptor,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001813 key_type: KeyType,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001814 caller_uid: u32,
1815 ) -> Result<(i64, KeyDescriptor, Option<KeyPermSet>)> {
1816 match key.domain {
1817 // Domain App or SELinux. In this case we load the key_id from
1818 // the keyentry database for further loading of key components.
1819 // We already have the full access tuple to perform access control.
1820 // The only distinction is that we use the caller_uid instead
1821 // of the caller supplied namespace if the domain field is
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001822 // Domain::APP.
1823 Domain::APP | Domain::SELINUX => {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001824 let mut access_key = key.clone();
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001825 if access_key.domain == Domain::APP {
1826 access_key.nspace = caller_uid as i64;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001827 }
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001828 let key_id = Self::load_key_entry_id(&tx, &access_key, key_type)
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001829 .with_context(|| format!("With key.domain = {:?}.", access_key.domain))?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001830
1831 Ok((key_id, access_key, None))
1832 }
1833
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001834 // Domain::GRANT. In this case we load the key_id and the access_vector
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001835 // from the grant table.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001836 Domain::GRANT => {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001837 let mut stmt = tx
1838 .prepare(
Janis Danisevskisbf15d732020-12-08 10:35:26 -08001839 "SELECT keyentryid, access_vector FROM persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001840 WHERE grantee = ? AND id = ?;",
1841 )
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001842 .context("Domain::GRANT prepare statement failed")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001843 let mut rows = stmt
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001844 .query(params![caller_uid as i64, key.nspace])
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001845 .context("Domain:Grant: query failed.")?;
1846 let (key_id, access_vector): (i64, i32) =
Janis Danisevskisbf15d732020-12-08 10:35:26 -08001847 db_utils::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001848 let r =
1849 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001850 Ok((
1851 r.get(0).context("Failed to unpack key_id.")?,
1852 r.get(1).context("Failed to unpack access_vector.")?,
1853 ))
1854 })
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001855 .context("Domain::GRANT.")?;
Janis Danisevskis66784c42021-01-27 08:40:25 -08001856 Ok((key_id, key.clone(), Some(access_vector.into())))
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001857 }
1858
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001859 // Domain::KEY_ID. In this case we load the domain and namespace from the
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001860 // keyentry database because we need them for access control.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001861 Domain::KEY_ID => {
Janis Danisevskis45760022021-01-19 16:34:10 -08001862 let (domain, namespace): (Domain, i64) = {
1863 let mut stmt = tx
1864 .prepare(
1865 "SELECT domain, namespace FROM persistent.keyentry
1866 WHERE
1867 id = ?
1868 AND state = ?;",
1869 )
1870 .context("Domain::KEY_ID: prepare statement failed")?;
1871 let mut rows = stmt
1872 .query(params![key.nspace, KeyLifeCycle::Live])
1873 .context("Domain::KEY_ID: query failed.")?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08001874 db_utils::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001875 let r =
1876 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001877 Ok((
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001878 Domain(r.get(0).context("Failed to unpack domain.")?),
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001879 r.get(1).context("Failed to unpack namespace.")?,
1880 ))
1881 })
Janis Danisevskis45760022021-01-19 16:34:10 -08001882 .context("Domain::KEY_ID.")?
1883 };
1884
1885 // We may use a key by id after loading it by grant.
1886 // In this case we have to check if the caller has a grant for this particular
1887 // key. We can skip this if we already know that the caller is the owner.
1888 // But we cannot know this if domain is anything but App. E.g. in the case
1889 // of Domain::SELINUX we have to speculatively check for grants because we have to
1890 // consult the SEPolicy before we know if the caller is the owner.
1891 let access_vector: Option<KeyPermSet> =
1892 if domain != Domain::APP || namespace != caller_uid as i64 {
1893 let access_vector: Option<i32> = tx
1894 .query_row(
1895 "SELECT access_vector FROM persistent.grant
1896 WHERE grantee = ? AND keyentryid = ?;",
1897 params![caller_uid as i64, key.nspace],
1898 |row| row.get(0),
1899 )
1900 .optional()
1901 .context("Domain::KEY_ID: query grant failed.")?;
1902 access_vector.map(|p| p.into())
1903 } else {
1904 None
1905 };
1906
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001907 let key_id = key.nspace;
Janis Danisevskis66784c42021-01-27 08:40:25 -08001908 let mut access_key: KeyDescriptor = key.clone();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001909 access_key.domain = domain;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001910 access_key.nspace = namespace;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001911
Janis Danisevskis45760022021-01-19 16:34:10 -08001912 Ok((key_id, access_key, access_vector))
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001913 }
1914 _ => Err(anyhow!(KsError::sys())),
1915 }
1916 }
1917
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001918 fn load_blob_components(
1919 key_id: i64,
1920 load_bits: KeyEntryLoadBits,
1921 tx: &Transaction,
Janis Danisevskis377d1002021-01-27 19:07:48 -08001922 ) -> Result<(bool, Option<Vec<u8>>, Option<Vec<u8>>, Option<Vec<u8>>)> {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001923 let mut stmt = tx
1924 .prepare(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001925 "SELECT MAX(id), subcomponent_type, blob FROM persistent.blobentry
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001926 WHERE keyentryid = ? GROUP BY subcomponent_type;",
1927 )
1928 .context("In load_blob_components: prepare statement failed.")?;
1929
1930 let mut rows =
1931 stmt.query(params![key_id]).context("In load_blob_components: query failed.")?;
1932
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001933 let mut km_blob: Option<Vec<u8>> = None;
1934 let mut cert_blob: Option<Vec<u8>> = None;
1935 let mut cert_chain_blob: Option<Vec<u8>> = None;
Janis Danisevskis377d1002021-01-27 19:07:48 -08001936 let mut has_km_blob: bool = false;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08001937 db_utils::with_rows_extract_all(&mut rows, |row| {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001938 let sub_type: SubComponentType =
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001939 row.get(1).context("Failed to extract subcomponent_type.")?;
Janis Danisevskis377d1002021-01-27 19:07:48 -08001940 has_km_blob = has_km_blob || sub_type == SubComponentType::KEY_BLOB;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001941 match (sub_type, load_bits.load_public(), load_bits.load_km()) {
1942 (SubComponentType::KEY_BLOB, _, true) => {
1943 km_blob = Some(row.get(2).context("Failed to extract KM blob.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001944 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001945 (SubComponentType::CERT, true, _) => {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001946 cert_blob =
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001947 Some(row.get(2).context("Failed to extract public certificate blob.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001948 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001949 (SubComponentType::CERT_CHAIN, true, _) => {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001950 cert_chain_blob =
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001951 Some(row.get(2).context("Failed to extract certificate chain blob.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001952 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001953 (SubComponentType::CERT, _, _)
1954 | (SubComponentType::CERT_CHAIN, _, _)
1955 | (SubComponentType::KEY_BLOB, _, _) => {}
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001956 _ => Err(KsError::sys()).context("Unknown subcomponent type.")?,
1957 }
1958 Ok(())
1959 })
1960 .context("In load_blob_components.")?;
1961
Janis Danisevskis377d1002021-01-27 19:07:48 -08001962 Ok((has_km_blob, km_blob, cert_blob, cert_chain_blob))
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001963 }
1964
1965 fn load_key_parameters(key_id: i64, tx: &Transaction) -> Result<Vec<KeyParameter>> {
1966 let mut stmt = tx
1967 .prepare(
1968 "SELECT tag, data, security_level from persistent.keyparameter
1969 WHERE keyentryid = ?;",
1970 )
1971 .context("In load_key_parameters: prepare statement failed.")?;
1972
1973 let mut parameters: Vec<KeyParameter> = Vec::new();
1974
1975 let mut rows =
1976 stmt.query(params![key_id]).context("In load_key_parameters: query failed.")?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08001977 db_utils::with_rows_extract_all(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001978 let tag = Tag(row.get(0).context("Failed to read tag.")?);
1979 let sec_level = SecurityLevel(row.get(2).context("Failed to read sec_level.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001980 parameters.push(
1981 KeyParameter::new_from_sql(tag, &SqlField::new(1, &row), sec_level)
1982 .context("Failed to read KeyParameter.")?,
1983 );
1984 Ok(())
1985 })
1986 .context("In load_key_parameters.")?;
1987
1988 Ok(parameters)
1989 }
1990
Qi Wub9433b52020-12-01 14:52:46 +08001991 /// Decrements the usage count of a limited use key. This function first checks whether the
1992 /// usage has been exhausted, if not, decreases the usage count. If the usage count reaches
1993 /// zero, the key also gets marked unreferenced and scheduled for deletion.
1994 /// Returns Ok(true) if the key was marked unreferenced as a hint to the garbage collector.
1995 pub fn check_and_update_key_usage_count(&mut self, key_id: i64) -> Result<bool> {
1996 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1997 let limit: Option<i32> = tx
1998 .query_row(
1999 "SELECT data FROM persistent.keyparameter WHERE keyentryid = ? AND tag = ?;",
2000 params![key_id, Tag::USAGE_COUNT_LIMIT.0],
2001 |row| row.get(0),
2002 )
2003 .optional()
2004 .context("Trying to load usage count")?;
2005
2006 let limit = limit
2007 .ok_or(KsError::Km(ErrorCode::INVALID_KEY_BLOB))
2008 .context("The Key no longer exists. Key is exhausted.")?;
2009
2010 tx.execute(
2011 "UPDATE persistent.keyparameter
2012 SET data = data - 1
2013 WHERE keyentryid = ? AND tag = ? AND data > 0;",
2014 params![key_id, Tag::USAGE_COUNT_LIMIT.0],
2015 )
2016 .context("Failed to update key usage count.")?;
2017
2018 match limit {
2019 1 => Self::mark_unreferenced(tx, key_id)
2020 .context("Trying to mark limited use key for deletion."),
2021 0 => Err(KsError::Km(ErrorCode::INVALID_KEY_BLOB)).context("Key is exhausted."),
2022 _ => Ok(false),
2023 }
2024 })
2025 .context("In check_and_update_key_usage_count.")
2026 }
2027
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002028 /// Load a key entry by the given key descriptor.
2029 /// It uses the `check_permission` callback to verify if the access is allowed
2030 /// given the key access tuple read from the database using `load_access_tuple`.
2031 /// With `load_bits` the caller may specify which blobs shall be loaded from
2032 /// the blob database.
2033 pub fn load_key_entry(
2034 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002035 key: &KeyDescriptor,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002036 key_type: KeyType,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002037 load_bits: KeyEntryLoadBits,
2038 caller_uid: u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002039 check_permission: impl Fn(&KeyDescriptor, Option<KeyPermSet>) -> Result<()>,
2040 ) -> Result<(KeyIdGuard, KeyEntry)> {
2041 loop {
2042 match self.load_key_entry_internal(
2043 key,
2044 key_type,
2045 load_bits,
2046 caller_uid,
2047 &check_permission,
2048 ) {
2049 Ok(result) => break Ok(result),
2050 Err(e) => {
2051 if Self::is_locked_error(&e) {
2052 std::thread::sleep(std::time::Duration::from_micros(500));
2053 continue;
2054 } else {
2055 return Err(e).context("In load_key_entry.");
2056 }
2057 }
2058 }
2059 }
2060 }
2061
2062 fn load_key_entry_internal(
2063 &mut self,
2064 key: &KeyDescriptor,
2065 key_type: KeyType,
2066 load_bits: KeyEntryLoadBits,
2067 caller_uid: u32,
2068 check_permission: &impl Fn(&KeyDescriptor, Option<KeyPermSet>) -> Result<()>,
Janis Danisevskisaec14592020-11-12 09:41:49 -08002069 ) -> Result<(KeyIdGuard, KeyEntry)> {
2070 // KEY ID LOCK 1/2
2071 // If we got a key descriptor with a key id we can get the lock right away.
2072 // Otherwise we have to defer it until we know the key id.
2073 let key_id_guard = match key.domain {
2074 Domain::KEY_ID => Some(KEY_ID_LOCK.get(key.nspace)),
2075 _ => None,
2076 };
2077
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002078 let tx = self
2079 .conn
Janis Danisevskisaec14592020-11-12 09:41:49 -08002080 .unchecked_transaction()
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002081 .context("In load_key_entry: Failed to initialize transaction.")?;
2082
2083 // Load the key_id and complete the access control tuple.
2084 let (key_id, access_key_descriptor, access_vector) =
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002085 Self::load_access_tuple(&tx, key, key_type, caller_uid)
2086 .context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002087
2088 // Perform access control. It is vital that we return here if the permission is denied.
2089 // So do not touch that '?' at the end.
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002090 check_permission(&access_key_descriptor, access_vector).context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002091
Janis Danisevskisaec14592020-11-12 09:41:49 -08002092 // KEY ID LOCK 2/2
2093 // If we did not get a key id lock by now, it was because we got a key descriptor
2094 // without a key id. At this point we got the key id, so we can try and get a lock.
2095 // However, we cannot block here, because we are in the middle of the transaction.
2096 // So first we try to get the lock non blocking. If that fails, we roll back the
2097 // transaction and block until we get the lock. After we successfully got the lock,
2098 // we start a new transaction and load the access tuple again.
2099 //
2100 // We don't need to perform access control again, because we already established
2101 // that the caller had access to the given key. But we need to make sure that the
2102 // key id still exists. So we have to load the key entry by key id this time.
2103 let (key_id_guard, tx) = match key_id_guard {
2104 None => match KEY_ID_LOCK.try_get(key_id) {
2105 None => {
2106 // Roll back the transaction.
2107 tx.rollback().context("In load_key_entry: Failed to roll back transaction.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002108
Janis Danisevskisaec14592020-11-12 09:41:49 -08002109 // Block until we have a key id lock.
2110 let key_id_guard = KEY_ID_LOCK.get(key_id);
2111
2112 // Create a new transaction.
Janis Danisevskis66784c42021-01-27 08:40:25 -08002113 let tx = self
2114 .conn
2115 .unchecked_transaction()
2116 .context("In load_key_entry: Failed to initialize transaction.")?;
Janis Danisevskisaec14592020-11-12 09:41:49 -08002117
2118 Self::load_access_tuple(
2119 &tx,
2120 // This time we have to load the key by the retrieved key id, because the
2121 // alias may have been rebound after we rolled back the transaction.
Janis Danisevskis66784c42021-01-27 08:40:25 -08002122 &KeyDescriptor {
Janis Danisevskisaec14592020-11-12 09:41:49 -08002123 domain: Domain::KEY_ID,
2124 nspace: key_id,
2125 ..Default::default()
2126 },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002127 key_type,
Janis Danisevskisaec14592020-11-12 09:41:49 -08002128 caller_uid,
2129 )
2130 .context("In load_key_entry. (deferred key lock)")?;
2131 (key_id_guard, tx)
2132 }
2133 Some(l) => (l, tx),
2134 },
2135 Some(key_id_guard) => (key_id_guard, tx),
2136 };
2137
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002138 let key_entry = Self::load_key_components(&tx, load_bits, key_id_guard.id())
2139 .context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002140
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002141 tx.commit().context("In load_key_entry: Failed to commit transaction.")?;
2142
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002143 Ok((key_id_guard, key_entry))
2144 }
2145
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002146 fn mark_unreferenced(tx: &Transaction, key_id: i64) -> Result<bool> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002147 let updated = tx
2148 .execute(
2149 "UPDATE persistent.keyentry SET state = ? WHERE id = ?;",
2150 params![KeyLifeCycle::Unreferenced, key_id],
2151 )
2152 .context("In mark_unreferenced: Failed to update state of key entry.")?;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002153 tx.execute("DELETE from persistent.grant WHERE keyentryid = ?;", params![key_id])
2154 .context("In mark_unreferenced: Failed to drop grants.")?;
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002155 Ok(updated != 0)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002156 }
2157
2158 /// Marks the given key as unreferenced and removes all of the grants to this key.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002159 /// Returns Ok(true) if a key was marked unreferenced as a hint for the garbage collector.
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002160 pub fn unbind_key(
2161 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002162 key: &KeyDescriptor,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002163 key_type: KeyType,
2164 caller_uid: u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002165 check_permission: impl Fn(&KeyDescriptor, Option<KeyPermSet>) -> Result<()>,
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002166 ) -> Result<bool> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002167 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2168 let (key_id, access_key_descriptor, access_vector) =
2169 Self::load_access_tuple(tx, key, key_type, caller_uid)
2170 .context("Trying to get access tuple.")?;
2171
2172 // Perform access control. It is vital that we return here if the permission is denied.
2173 // So do not touch that '?' at the end.
2174 check_permission(&access_key_descriptor, access_vector)
2175 .context("While checking permission.")?;
2176
2177 Self::mark_unreferenced(tx, key_id).context("Trying to mark the key unreferenced.")
2178 })
2179 .context("In unbind_key.")
2180 }
2181
Max Bires8e93d2b2021-01-14 13:17:59 -08002182 fn get_key_km_uuid(tx: &Transaction, key_id: i64) -> Result<Uuid> {
2183 tx.query_row(
2184 "SELECT km_uuid FROM persistent.keyentry WHERE id = ?",
2185 params![key_id],
2186 |row| row.get(0),
2187 )
2188 .context("In get_key_km_uuid.")
2189 }
2190
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002191 fn load_key_components(
2192 tx: &Transaction,
2193 load_bits: KeyEntryLoadBits,
2194 key_id: i64,
2195 ) -> Result<KeyEntry> {
2196 let metadata = KeyMetaData::load_from_db(key_id, &tx).context("In load_key_components.")?;
2197
Janis Danisevskis377d1002021-01-27 19:07:48 -08002198 let (has_km_blob, km_blob, cert_blob, cert_chain_blob) =
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002199 Self::load_blob_components(key_id, load_bits, &tx)
2200 .context("In load_key_components.")?;
2201
Max Bires8e93d2b2021-01-14 13:17:59 -08002202 let parameters = Self::load_key_parameters(key_id, &tx)
2203 .context("In load_key_components: Trying to load key parameters.")?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002204
Max Bires8e93d2b2021-01-14 13:17:59 -08002205 let km_uuid = Self::get_key_km_uuid(&tx, key_id)
2206 .context("In load_key_components: Trying to get KM uuid.")?;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002207
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002208 Ok(KeyEntry {
2209 id: key_id,
2210 km_blob,
2211 cert: cert_blob,
2212 cert_chain: cert_chain_blob,
Max Bires8e93d2b2021-01-14 13:17:59 -08002213 km_uuid,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002214 parameters,
2215 metadata,
Janis Danisevskis377d1002021-01-27 19:07:48 -08002216 pure_cert: !has_km_blob,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002217 })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002218 }
2219
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002220 /// Returns a list of KeyDescriptors in the selected domain/namespace.
2221 /// The key descriptors will have the domain, nspace, and alias field set.
2222 /// Domain must be APP or SELINUX, the caller must make sure of that.
2223 pub fn list(&mut self, domain: Domain, namespace: i64) -> Result<Vec<KeyDescriptor>> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002224 self.with_transaction(TransactionBehavior::Deferred, |tx| {
2225 let mut stmt = tx
2226 .prepare(
2227 "SELECT alias FROM persistent.keyentry
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002228 WHERE domain = ? AND namespace = ? AND alias IS NOT NULL AND state = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08002229 )
2230 .context("In list: Failed to prepare.")?;
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002231
Janis Danisevskis66784c42021-01-27 08:40:25 -08002232 let mut rows = stmt
2233 .query(params![domain.0 as u32, namespace, KeyLifeCycle::Live])
2234 .context("In list: Failed to query.")?;
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002235
Janis Danisevskis66784c42021-01-27 08:40:25 -08002236 let mut descriptors: Vec<KeyDescriptor> = Vec::new();
2237 db_utils::with_rows_extract_all(&mut rows, |row| {
2238 descriptors.push(KeyDescriptor {
2239 domain,
2240 nspace: namespace,
2241 alias: Some(row.get(0).context("Trying to extract alias.")?),
2242 blob: None,
2243 });
2244 Ok(())
2245 })
2246 .context("In list: Failed to extract rows.")?;
2247 Ok(descriptors)
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002248 })
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002249 }
2250
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002251 /// Adds a grant to the grant table.
2252 /// Like `load_key_entry` this function loads the access tuple before
2253 /// it uses the callback for a permission check. Upon success,
2254 /// it inserts the `grantee_uid`, `key_id`, and `access_vector` into the
2255 /// grant table. The new row will have a randomized id, which is used as
2256 /// grant id in the namespace field of the resulting KeyDescriptor.
2257 pub fn grant(
2258 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002259 key: &KeyDescriptor,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002260 caller_uid: u32,
2261 grantee_uid: u32,
2262 access_vector: KeyPermSet,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002263 check_permission: impl Fn(&KeyDescriptor, &KeyPermSet) -> Result<()>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002264 ) -> Result<KeyDescriptor> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002265 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2266 // Load the key_id and complete the access control tuple.
2267 // We ignore the access vector here because grants cannot be granted.
2268 // The access vector returned here expresses the permissions the
2269 // grantee has if key.domain == Domain::GRANT. But this vector
2270 // cannot include the grant permission by design, so there is no way the
2271 // subsequent permission check can pass.
2272 // We could check key.domain == Domain::GRANT and fail early.
2273 // But even if we load the access tuple by grant here, the permission
2274 // check denies the attempt to create a grant by grant descriptor.
2275 let (key_id, access_key_descriptor, _) =
2276 Self::load_access_tuple(&tx, key, KeyType::Client, caller_uid)
2277 .context("In grant")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002278
Janis Danisevskis66784c42021-01-27 08:40:25 -08002279 // Perform access control. It is vital that we return here if the permission
2280 // was denied. So do not touch that '?' at the end of the line.
2281 // This permission check checks if the caller has the grant permission
2282 // for the given key and in addition to all of the permissions
2283 // expressed in `access_vector`.
2284 check_permission(&access_key_descriptor, &access_vector)
2285 .context("In grant: check_permission failed.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002286
Janis Danisevskis66784c42021-01-27 08:40:25 -08002287 let grant_id = if let Some(grant_id) = tx
2288 .query_row(
2289 "SELECT id FROM persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002290 WHERE keyentryid = ? AND grantee = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08002291 params![key_id, grantee_uid],
2292 |row| row.get(0),
2293 )
2294 .optional()
2295 .context("In grant: Failed get optional existing grant id.")?
2296 {
2297 tx.execute(
2298 "UPDATE persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002299 SET access_vector = ?
2300 WHERE id = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08002301 params![i32::from(access_vector), grant_id],
Joel Galenson845f74b2020-09-09 14:11:55 -07002302 )
Janis Danisevskis66784c42021-01-27 08:40:25 -08002303 .context("In grant: Failed to update existing grant.")?;
2304 grant_id
2305 } else {
2306 Self::insert_with_retry(|id| {
2307 tx.execute(
2308 "INSERT INTO persistent.grant (id, grantee, keyentryid, access_vector)
2309 VALUES (?, ?, ?, ?);",
2310 params![id, grantee_uid, key_id, i32::from(access_vector)],
2311 )
2312 })
2313 .context("In grant")?
2314 };
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002315
Janis Danisevskis66784c42021-01-27 08:40:25 -08002316 Ok(KeyDescriptor { domain: Domain::GRANT, nspace: grant_id, alias: None, blob: None })
2317 })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002318 }
2319
2320 /// This function checks permissions like `grant` and `load_key_entry`
2321 /// before removing a grant from the grant table.
2322 pub fn ungrant(
2323 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002324 key: &KeyDescriptor,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002325 caller_uid: u32,
2326 grantee_uid: u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002327 check_permission: impl Fn(&KeyDescriptor) -> Result<()>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002328 ) -> Result<()> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002329 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2330 // Load the key_id and complete the access control tuple.
2331 // We ignore the access vector here because grants cannot be granted.
2332 let (key_id, access_key_descriptor, _) =
2333 Self::load_access_tuple(&tx, key, KeyType::Client, caller_uid)
2334 .context("In ungrant.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002335
Janis Danisevskis66784c42021-01-27 08:40:25 -08002336 // Perform access control. We must return here if the permission
2337 // was denied. So do not touch the '?' at the end of this line.
2338 check_permission(&access_key_descriptor)
2339 .context("In grant: check_permission failed.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002340
Janis Danisevskis66784c42021-01-27 08:40:25 -08002341 tx.execute(
2342 "DELETE FROM persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002343 WHERE keyentryid = ? AND grantee = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08002344 params![key_id, grantee_uid],
2345 )
2346 .context("Failed to delete grant.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002347
Janis Danisevskis66784c42021-01-27 08:40:25 -08002348 Ok(())
2349 })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002350 }
2351
Joel Galenson845f74b2020-09-09 14:11:55 -07002352 // Generates a random id and passes it to the given function, which will
2353 // try to insert it into a database. If that insertion fails, retry;
2354 // otherwise return the id.
2355 fn insert_with_retry(inserter: impl Fn(i64) -> rusqlite::Result<usize>) -> Result<i64> {
2356 loop {
2357 let newid: i64 = random();
2358 match inserter(newid) {
2359 // If the id already existed, try again.
2360 Err(rusqlite::Error::SqliteFailure(
2361 libsqlite3_sys::Error {
2362 code: libsqlite3_sys::ErrorCode::ConstraintViolation,
2363 extended_code: libsqlite3_sys::SQLITE_CONSTRAINT_UNIQUE,
2364 },
2365 _,
2366 )) => (),
2367 Err(e) => {
2368 return Err(e).context("In insert_with_retry: failed to insert into database.")
2369 }
2370 _ => return Ok(newid),
2371 }
2372 }
2373 }
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002374
2375 /// Insert or replace the auth token based on the UNIQUE constraint of the auth token table
2376 pub fn insert_auth_token(&mut self, auth_token: &HardwareAuthToken) -> Result<()> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002377 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2378 tx.execute(
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002379 "INSERT OR REPLACE INTO perboot.authtoken (challenge, user_id, auth_id,
2380 authenticator_type, timestamp, mac, time_received) VALUES(?, ?, ?, ?, ?, ?, ?);",
2381 params![
2382 auth_token.challenge,
2383 auth_token.userId,
2384 auth_token.authenticatorId,
2385 auth_token.authenticatorType.0 as i32,
2386 auth_token.timestamp.milliSeconds as i64,
2387 auth_token.mac,
2388 MonotonicRawTime::now(),
2389 ],
2390 )
2391 .context("In insert_auth_token: failed to insert auth token into the database")?;
Janis Danisevskis66784c42021-01-27 08:40:25 -08002392 Ok(())
2393 })
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002394 }
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002395
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002396 /// Find the newest auth token matching the given predicate.
2397 pub fn find_auth_token_entry<F>(
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002398 &mut self,
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002399 p: F,
2400 ) -> Result<Option<(AuthTokenEntry, MonotonicRawTime)>>
2401 where
2402 F: Fn(&AuthTokenEntry) -> bool,
2403 {
2404 self.with_transaction(TransactionBehavior::Deferred, |tx| {
2405 let mut stmt = tx
2406 .prepare("SELECT * from perboot.authtoken ORDER BY time_received DESC;")
2407 .context("Prepare statement failed.")?;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002408
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002409 let mut rows = stmt.query(NO_PARAMS).context("Failed to query.")?;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002410
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002411 while let Some(row) = rows.next().context("Failed to get next row.")? {
2412 let entry = AuthTokenEntry::new(
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002413 HardwareAuthToken {
2414 challenge: row.get(1)?,
2415 userId: row.get(2)?,
2416 authenticatorId: row.get(3)?,
2417 authenticatorType: HardwareAuthenticatorType(row.get(4)?),
2418 timestamp: Timestamp { milliSeconds: row.get(5)? },
2419 mac: row.get(6)?,
2420 },
2421 row.get(7)?,
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002422 );
2423 if p(&entry) {
2424 return Ok(Some((
2425 entry,
2426 Self::get_last_off_body(tx)
2427 .context("In find_auth_token_entry: Trying to get last off body")?,
2428 )));
2429 }
2430 }
2431 Ok(None)
2432 })
2433 .context("In find_auth_token_entry.")
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002434 }
2435
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002436 /// Insert last_off_body into the metadata table at the initialization of auth token table
Janis Danisevskis66784c42021-01-27 08:40:25 -08002437 pub fn insert_last_off_body(&mut self, last_off_body: MonotonicRawTime) -> Result<()> {
2438 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2439 tx.execute(
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002440 "INSERT OR REPLACE INTO perboot.metadata (key, value) VALUES (?, ?);",
2441 params!["last_off_body", last_off_body],
2442 )
2443 .context("In insert_last_off_body: failed to insert.")?;
Janis Danisevskis66784c42021-01-27 08:40:25 -08002444 Ok(())
2445 })
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002446 }
2447
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002448 /// Update last_off_body when on_device_off_body is called
Janis Danisevskis66784c42021-01-27 08:40:25 -08002449 pub fn update_last_off_body(&mut self, last_off_body: MonotonicRawTime) -> Result<()> {
2450 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2451 tx.execute(
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002452 "UPDATE perboot.metadata SET value = ? WHERE key = ?;",
2453 params![last_off_body, "last_off_body"],
2454 )
2455 .context("In update_last_off_body: failed to update.")?;
Janis Danisevskis66784c42021-01-27 08:40:25 -08002456 Ok(())
2457 })
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002458 }
2459
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002460 /// Get last_off_body time when finding auth tokens
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002461 fn get_last_off_body(tx: &Transaction) -> Result<MonotonicRawTime> {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002462 tx.query_row(
2463 "SELECT value from perboot.metadata WHERE key = ?;",
2464 params!["last_off_body"],
2465 |row| Ok(row.get(0)?),
2466 )
2467 .context("In get_last_off_body: query_row failed.")
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002468 }
Joel Galenson26f4d012020-07-17 14:57:21 -07002469}
2470
2471#[cfg(test)]
2472mod tests {
2473
2474 use super::*;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002475 use crate::key_parameter::{
2476 Algorithm, BlockMode, Digest, EcCurve, HardwareAuthenticatorType, KeyOrigin, KeyParameter,
2477 KeyParameterValue, KeyPurpose, PaddingMode, SecurityLevel,
2478 };
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002479 use crate::key_perm_set;
2480 use crate::permission::{KeyPerm, KeyPermSet};
Janis Danisevskis2a8330a2021-01-20 15:34:26 -08002481 use keystore2_test_utils::TempDir;
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002482 use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
2483 HardwareAuthToken::HardwareAuthToken,
2484 HardwareAuthenticatorType::HardwareAuthenticatorType as kmhw_authenticator_type,
Janis Danisevskisc3a496b2021-01-05 10:37:22 -08002485 };
2486 use android_hardware_security_secureclock::aidl::android::hardware::security::secureclock::{
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002487 Timestamp::Timestamp,
2488 };
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002489 use rusqlite::NO_PARAMS;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002490 use rusqlite::{Error, TransactionBehavior};
Joel Galenson0891bc12020-07-20 10:37:03 -07002491 use std::cell::RefCell;
Janis Danisevskisaec14592020-11-12 09:41:49 -08002492 use std::sync::atomic::{AtomicU8, Ordering};
2493 use std::sync::Arc;
2494 use std::thread;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002495 use std::time::{Duration, SystemTime};
Janis Danisevskis66784c42021-01-27 08:40:25 -08002496 #[cfg(disabled)]
2497 use std::time::Instant;
Joel Galenson0891bc12020-07-20 10:37:03 -07002498
Janis Danisevskis4df44f42020-08-26 14:40:03 -07002499 fn new_test_db() -> Result<KeystoreDB> {
2500 let conn = KeystoreDB::make_connection("file::memory:", "file::memory:")?;
2501
Janis Danisevskis66784c42021-01-27 08:40:25 -08002502 let mut db = KeystoreDB { conn };
2503 db.with_transaction(TransactionBehavior::Immediate, |tx| {
2504 KeystoreDB::init_tables(tx).context("Failed to initialize tables.")
2505 })?;
2506 Ok(db)
Janis Danisevskis4df44f42020-08-26 14:40:03 -07002507 }
2508
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002509 fn rebind_alias(
2510 db: &mut KeystoreDB,
2511 newid: &KeyIdGuard,
2512 alias: &str,
2513 domain: Domain,
2514 namespace: i64,
2515 ) -> Result<bool> {
2516 db.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002517 KeystoreDB::rebind_alias(tx, newid, alias, &domain, &namespace)
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002518 })
2519 .context("In rebind_alias.")
2520 }
2521
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002522 #[test]
2523 fn datetime() -> Result<()> {
2524 let conn = Connection::open_in_memory()?;
2525 conn.execute("CREATE TABLE test (ts DATETIME);", NO_PARAMS)?;
2526 let now = SystemTime::now();
2527 let duration = Duration::from_secs(1000);
2528 let then = now.checked_sub(duration).unwrap();
2529 let soon = now.checked_add(duration).unwrap();
2530 conn.execute(
2531 "INSERT INTO test (ts) VALUES (?), (?), (?);",
2532 params![DateTime::try_from(now)?, DateTime::try_from(then)?, DateTime::try_from(soon)?],
2533 )?;
2534 let mut stmt = conn.prepare("SELECT ts FROM test ORDER BY ts ASC;")?;
2535 let mut rows = stmt.query(NO_PARAMS)?;
2536 assert_eq!(DateTime::try_from(then)?, rows.next()?.unwrap().get(0)?);
2537 assert_eq!(DateTime::try_from(now)?, rows.next()?.unwrap().get(0)?);
2538 assert_eq!(DateTime::try_from(soon)?, rows.next()?.unwrap().get(0)?);
2539 assert!(rows.next()?.is_none());
2540 assert!(DateTime::try_from(then)? < DateTime::try_from(now)?);
2541 assert!(DateTime::try_from(then)? < DateTime::try_from(soon)?);
2542 assert!(DateTime::try_from(now)? < DateTime::try_from(soon)?);
2543 Ok(())
2544 }
2545
Joel Galenson0891bc12020-07-20 10:37:03 -07002546 // Ensure that we're using the "injected" random function, not the real one.
2547 #[test]
2548 fn test_mocked_random() {
2549 let rand1 = random();
2550 let rand2 = random();
2551 let rand3 = random();
2552 if rand1 == rand2 {
2553 assert_eq!(rand2 + 1, rand3);
2554 } else {
2555 assert_eq!(rand1 + 1, rand2);
2556 assert_eq!(rand2, rand3);
2557 }
2558 }
Joel Galenson26f4d012020-07-17 14:57:21 -07002559
Joel Galenson26f4d012020-07-17 14:57:21 -07002560 // Test that we have the correct tables.
2561 #[test]
2562 fn test_tables() -> Result<()> {
Janis Danisevskis4df44f42020-08-26 14:40:03 -07002563 let db = new_test_db()?;
Joel Galenson26f4d012020-07-17 14:57:21 -07002564 let tables = db
2565 .conn
Joel Galenson2aab4432020-07-22 15:27:57 -07002566 .prepare("SELECT name from persistent.sqlite_master WHERE type='table' ORDER BY name;")?
Joel Galenson26f4d012020-07-17 14:57:21 -07002567 .query_map(params![], |row| row.get(0))?
2568 .collect::<rusqlite::Result<Vec<String>>>()?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002569 assert_eq!(tables.len(), 5);
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002570 assert_eq!(tables[0], "blobentry");
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002571 assert_eq!(tables[1], "grant");
2572 assert_eq!(tables[2], "keyentry");
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002573 assert_eq!(tables[3], "keymetadata");
2574 assert_eq!(tables[4], "keyparameter");
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002575 let tables = db
2576 .conn
2577 .prepare("SELECT name from perboot.sqlite_master WHERE type='table' ORDER BY name;")?
2578 .query_map(params![], |row| row.get(0))?
2579 .collect::<rusqlite::Result<Vec<String>>>()?;
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002580
2581 assert_eq!(tables.len(), 2);
2582 assert_eq!(tables[0], "authtoken");
2583 assert_eq!(tables[1], "metadata");
Joel Galenson2aab4432020-07-22 15:27:57 -07002584 Ok(())
2585 }
2586
2587 #[test]
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002588 fn test_auth_token_table_invariant() -> Result<()> {
2589 let mut db = new_test_db()?;
2590 let auth_token1 = HardwareAuthToken {
2591 challenge: i64::MAX,
2592 userId: 200,
2593 authenticatorId: 200,
2594 authenticatorType: kmhw_authenticator_type(kmhw_authenticator_type::PASSWORD.0),
2595 timestamp: Timestamp { milliSeconds: 500 },
2596 mac: String::from("mac").into_bytes(),
2597 };
2598 db.insert_auth_token(&auth_token1)?;
2599 let auth_tokens_returned = get_auth_tokens(&mut db)?;
2600 assert_eq!(auth_tokens_returned.len(), 1);
2601
2602 // insert another auth token with the same values for the columns in the UNIQUE constraint
2603 // of the auth token table and different value for timestamp
2604 let auth_token2 = HardwareAuthToken {
2605 challenge: i64::MAX,
2606 userId: 200,
2607 authenticatorId: 200,
2608 authenticatorType: kmhw_authenticator_type(kmhw_authenticator_type::PASSWORD.0),
2609 timestamp: Timestamp { milliSeconds: 600 },
2610 mac: String::from("mac").into_bytes(),
2611 };
2612
2613 db.insert_auth_token(&auth_token2)?;
2614 let mut auth_tokens_returned = get_auth_tokens(&mut db)?;
2615 assert_eq!(auth_tokens_returned.len(), 1);
2616
2617 if let Some(auth_token) = auth_tokens_returned.pop() {
2618 assert_eq!(auth_token.auth_token.timestamp.milliSeconds, 600);
2619 }
2620
2621 // insert another auth token with the different values for the columns in the UNIQUE
2622 // constraint of the auth token table
2623 let auth_token3 = HardwareAuthToken {
2624 challenge: i64::MAX,
2625 userId: 201,
2626 authenticatorId: 200,
2627 authenticatorType: kmhw_authenticator_type(kmhw_authenticator_type::PASSWORD.0),
2628 timestamp: Timestamp { milliSeconds: 600 },
2629 mac: String::from("mac").into_bytes(),
2630 };
2631
2632 db.insert_auth_token(&auth_token3)?;
2633 let auth_tokens_returned = get_auth_tokens(&mut db)?;
2634 assert_eq!(auth_tokens_returned.len(), 2);
2635
2636 Ok(())
2637 }
2638
2639 // utility function for test_auth_token_table_invariant()
2640 fn get_auth_tokens(db: &mut KeystoreDB) -> Result<Vec<AuthTokenEntry>> {
2641 let mut stmt = db.conn.prepare("SELECT * from perboot.authtoken;")?;
2642
2643 let auth_token_entries: Vec<AuthTokenEntry> = stmt
2644 .query_map(NO_PARAMS, |row| {
2645 Ok(AuthTokenEntry::new(
2646 HardwareAuthToken {
2647 challenge: row.get(1)?,
2648 userId: row.get(2)?,
2649 authenticatorId: row.get(3)?,
2650 authenticatorType: HardwareAuthenticatorType(row.get(4)?),
2651 timestamp: Timestamp { milliSeconds: row.get(5)? },
2652 mac: row.get(6)?,
2653 },
2654 row.get(7)?,
2655 ))
2656 })?
2657 .collect::<Result<Vec<AuthTokenEntry>, Error>>()?;
2658 Ok(auth_token_entries)
2659 }
2660
2661 #[test]
Joel Galenson2aab4432020-07-22 15:27:57 -07002662 fn test_persistence_for_files() -> Result<()> {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002663 let temp_dir = TempDir::new("persistent_db_test")?;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002664 let mut db = KeystoreDB::new(temp_dir.path())?;
Joel Galenson2aab4432020-07-22 15:27:57 -07002665
Janis Danisevskis66784c42021-01-27 08:40:25 -08002666 db.create_key_entry(&Domain::APP, &100, &KEYSTORE_UUID)?;
Joel Galenson2aab4432020-07-22 15:27:57 -07002667 let entries = get_keyentry(&db)?;
2668 assert_eq!(entries.len(), 1);
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002669
2670 let db = KeystoreDB::new(temp_dir.path())?;
Joel Galenson2aab4432020-07-22 15:27:57 -07002671
2672 let entries_new = get_keyentry(&db)?;
2673 assert_eq!(entries, entries_new);
2674 Ok(())
2675 }
2676
2677 #[test]
Joel Galenson0891bc12020-07-20 10:37:03 -07002678 fn test_create_key_entry() -> Result<()> {
Max Bires8e93d2b2021-01-14 13:17:59 -08002679 fn extractor(ke: &KeyEntryRow) -> (Domain, i64, Option<&str>, Uuid) {
2680 (ke.domain.unwrap(), ke.namespace.unwrap(), ke.alias.as_deref(), ke.km_uuid.unwrap())
Joel Galenson0891bc12020-07-20 10:37:03 -07002681 }
2682
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002683 let mut db = new_test_db()?;
Joel Galenson0891bc12020-07-20 10:37:03 -07002684
Janis Danisevskis66784c42021-01-27 08:40:25 -08002685 db.create_key_entry(&Domain::APP, &100, &KEYSTORE_UUID)?;
2686 db.create_key_entry(&Domain::SELINUX, &101, &KEYSTORE_UUID)?;
Joel Galenson0891bc12020-07-20 10:37:03 -07002687
2688 let entries = get_keyentry(&db)?;
2689 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08002690 assert_eq!(extractor(&entries[0]), (Domain::APP, 100, None, KEYSTORE_UUID));
2691 assert_eq!(extractor(&entries[1]), (Domain::SELINUX, 101, None, KEYSTORE_UUID));
Joel Galenson0891bc12020-07-20 10:37:03 -07002692
2693 // Test that we must pass in a valid Domain.
2694 check_result_is_error_containing_string(
Janis Danisevskis66784c42021-01-27 08:40:25 -08002695 db.create_key_entry(&Domain::GRANT, &102, &KEYSTORE_UUID),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002696 "Domain Domain(1) must be either App or SELinux.",
Joel Galenson0891bc12020-07-20 10:37:03 -07002697 );
2698 check_result_is_error_containing_string(
Janis Danisevskis66784c42021-01-27 08:40:25 -08002699 db.create_key_entry(&Domain::BLOB, &103, &KEYSTORE_UUID),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002700 "Domain Domain(3) must be either App or SELinux.",
Joel Galenson0891bc12020-07-20 10:37:03 -07002701 );
2702 check_result_is_error_containing_string(
Janis Danisevskis66784c42021-01-27 08:40:25 -08002703 db.create_key_entry(&Domain::KEY_ID, &104, &KEYSTORE_UUID),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002704 "Domain Domain(4) must be either App or SELinux.",
Joel Galenson0891bc12020-07-20 10:37:03 -07002705 );
2706
2707 Ok(())
2708 }
2709
Joel Galenson33c04ad2020-08-03 11:04:38 -07002710 #[test]
Max Bires2b2e6562020-09-22 11:22:36 -07002711 fn test_add_unsigned_key() -> Result<()> {
2712 let mut db = new_test_db()?;
2713 let public_key: Vec<u8> = vec![0x01, 0x02, 0x03];
2714 let private_key: Vec<u8> = vec![0x04, 0x05, 0x06];
2715 let raw_public_key: Vec<u8> = vec![0x07, 0x08, 0x09];
2716 db.create_attestation_key_entry(
2717 &public_key,
2718 &raw_public_key,
2719 &private_key,
2720 &KEYSTORE_UUID,
2721 )?;
2722 let keys = db.fetch_unsigned_attestation_keys(5, &KEYSTORE_UUID)?;
2723 assert_eq!(keys.len(), 1);
2724 assert_eq!(keys[0], public_key);
2725 Ok(())
2726 }
2727
2728 #[test]
2729 fn test_store_signed_attestation_certificate_chain() -> Result<()> {
2730 let mut db = new_test_db()?;
2731 let expiration_date: i64 = 20;
2732 let namespace: i64 = 30;
2733 let base_byte: u8 = 1;
2734 let loaded_values =
2735 load_attestation_key_pool(&mut db, expiration_date, namespace, base_byte)?;
2736 let chain =
2737 db.retrieve_attestation_key_and_cert_chain(Domain::APP, namespace, &KEYSTORE_UUID)?;
2738 assert_eq!(true, chain.is_some());
2739 let cert_chain = chain.unwrap();
2740 assert_eq!(cert_chain.private_key.to_vec(), loaded_values[2]);
2741 assert_eq!(cert_chain.cert_chain.to_vec(), loaded_values[1]);
2742 Ok(())
2743 }
2744
2745 #[test]
2746 fn test_get_attestation_pool_status() -> Result<()> {
2747 let mut db = new_test_db()?;
2748 let namespace: i64 = 30;
2749 load_attestation_key_pool(
2750 &mut db, 10, /* expiration */
2751 namespace, 0x01, /* base_byte */
2752 )?;
2753 load_attestation_key_pool(&mut db, 20 /* expiration */, namespace + 1, 0x02)?;
2754 load_attestation_key_pool(&mut db, 40 /* expiration */, namespace + 2, 0x03)?;
2755 let mut status = db.get_attestation_pool_status(9 /* expiration */, &KEYSTORE_UUID)?;
2756 assert_eq!(status.expiring, 0);
2757 assert_eq!(status.attested, 3);
2758 assert_eq!(status.unassigned, 0);
2759 assert_eq!(status.total, 3);
2760 assert_eq!(
2761 db.get_attestation_pool_status(15 /* expiration */, &KEYSTORE_UUID)?.expiring,
2762 1
2763 );
2764 assert_eq!(
2765 db.get_attestation_pool_status(25 /* expiration */, &KEYSTORE_UUID)?.expiring,
2766 2
2767 );
2768 assert_eq!(
2769 db.get_attestation_pool_status(60 /* expiration */, &KEYSTORE_UUID)?.expiring,
2770 3
2771 );
2772 let public_key: Vec<u8> = vec![0x01, 0x02, 0x03];
2773 let private_key: Vec<u8> = vec![0x04, 0x05, 0x06];
2774 let raw_public_key: Vec<u8> = vec![0x07, 0x08, 0x09];
2775 let cert_chain: Vec<u8> = vec![0x0a, 0x0b, 0x0c];
2776 db.create_attestation_key_entry(
2777 &public_key,
2778 &raw_public_key,
2779 &private_key,
2780 &KEYSTORE_UUID,
2781 )?;
2782 status = db.get_attestation_pool_status(0 /* expiration */, &KEYSTORE_UUID)?;
2783 assert_eq!(status.attested, 3);
2784 assert_eq!(status.unassigned, 0);
2785 assert_eq!(status.total, 4);
2786 db.store_signed_attestation_certificate_chain(
2787 &raw_public_key,
2788 &cert_chain,
2789 20,
2790 &KEYSTORE_UUID,
2791 )?;
2792 status = db.get_attestation_pool_status(0 /* expiration */, &KEYSTORE_UUID)?;
2793 assert_eq!(status.attested, 4);
2794 assert_eq!(status.unassigned, 1);
2795 assert_eq!(status.total, 4);
2796 Ok(())
2797 }
2798
2799 #[test]
2800 fn test_remove_expired_certs() -> Result<()> {
2801 let mut db = new_test_db()?;
2802 let expiration_date: i64 =
2803 SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_millis() as i64 + 10000;
2804 let namespace: i64 = 30;
2805 let namespace_del1: i64 = 45;
2806 let namespace_del2: i64 = 60;
2807 let entry_values = load_attestation_key_pool(
2808 &mut db,
2809 expiration_date,
2810 namespace,
2811 0x01, /* base_byte */
2812 )?;
2813 load_attestation_key_pool(&mut db, 45, namespace_del1, 0x02)?;
2814 load_attestation_key_pool(&mut db, 60, namespace_del2, 0x03)?;
2815 assert_eq!(db.delete_expired_attestation_keys()?, 2);
2816
2817 let mut cert_chain =
2818 db.retrieve_attestation_key_and_cert_chain(Domain::APP, namespace, &KEYSTORE_UUID)?;
2819 assert_eq!(true, cert_chain.is_some());
2820 let value = cert_chain.unwrap();
2821 assert_eq!(entry_values[1], value.cert_chain.to_vec());
2822 assert_eq!(entry_values[2], value.private_key.to_vec());
2823
2824 cert_chain = db.retrieve_attestation_key_and_cert_chain(
2825 Domain::APP,
2826 namespace_del1,
2827 &KEYSTORE_UUID,
2828 )?;
2829 assert_eq!(false, cert_chain.is_some());
2830 cert_chain = db.retrieve_attestation_key_and_cert_chain(
2831 Domain::APP,
2832 namespace_del2,
2833 &KEYSTORE_UUID,
2834 )?;
2835 assert_eq!(false, cert_chain.is_some());
2836
2837 let mut option_entry = db.get_unreferenced_key()?;
2838 assert_eq!(true, option_entry.is_some());
2839 let (key_guard, _) = option_entry.unwrap();
2840 db.purge_key_entry(key_guard)?;
2841
2842 option_entry = db.get_unreferenced_key()?;
2843 assert_eq!(true, option_entry.is_some());
2844 let (key_guard, _) = option_entry.unwrap();
2845 db.purge_key_entry(key_guard)?;
2846
2847 option_entry = db.get_unreferenced_key()?;
2848 assert_eq!(false, option_entry.is_some());
2849 Ok(())
2850 }
2851
2852 #[test]
Joel Galenson33c04ad2020-08-03 11:04:38 -07002853 fn test_rebind_alias() -> Result<()> {
Max Bires8e93d2b2021-01-14 13:17:59 -08002854 fn extractor(
2855 ke: &KeyEntryRow,
2856 ) -> (Option<Domain>, Option<i64>, Option<&str>, Option<Uuid>) {
2857 (ke.domain, ke.namespace, ke.alias.as_deref(), ke.km_uuid)
Joel Galenson33c04ad2020-08-03 11:04:38 -07002858 }
2859
Janis Danisevskis4df44f42020-08-26 14:40:03 -07002860 let mut db = new_test_db()?;
Janis Danisevskis66784c42021-01-27 08:40:25 -08002861 db.create_key_entry(&Domain::APP, &42, &KEYSTORE_UUID)?;
2862 db.create_key_entry(&Domain::APP, &42, &KEYSTORE_UUID)?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07002863 let entries = get_keyentry(&db)?;
2864 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08002865 assert_eq!(
2866 extractor(&entries[0]),
2867 (Some(Domain::APP), Some(42), None, Some(KEYSTORE_UUID))
2868 );
2869 assert_eq!(
2870 extractor(&entries[1]),
2871 (Some(Domain::APP), Some(42), None, Some(KEYSTORE_UUID))
2872 );
Joel Galenson33c04ad2020-08-03 11:04:38 -07002873
2874 // Test that the first call to rebind_alias sets the alias.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002875 rebind_alias(&mut db, &KEY_ID_LOCK.get(entries[0].id), "foo", Domain::APP, 42)?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07002876 let entries = get_keyentry(&db)?;
2877 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08002878 assert_eq!(
2879 extractor(&entries[0]),
2880 (Some(Domain::APP), Some(42), Some("foo"), Some(KEYSTORE_UUID))
2881 );
2882 assert_eq!(
2883 extractor(&entries[1]),
2884 (Some(Domain::APP), Some(42), None, Some(KEYSTORE_UUID))
2885 );
Joel Galenson33c04ad2020-08-03 11:04:38 -07002886
2887 // Test that the second call to rebind_alias also empties the old one.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002888 rebind_alias(&mut db, &KEY_ID_LOCK.get(entries[1].id), "foo", Domain::APP, 42)?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07002889 let entries = get_keyentry(&db)?;
2890 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08002891 assert_eq!(extractor(&entries[0]), (None, None, None, Some(KEYSTORE_UUID)));
2892 assert_eq!(
2893 extractor(&entries[1]),
2894 (Some(Domain::APP), Some(42), Some("foo"), Some(KEYSTORE_UUID))
2895 );
Joel Galenson33c04ad2020-08-03 11:04:38 -07002896
2897 // Test that we must pass in a valid Domain.
2898 check_result_is_error_containing_string(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002899 rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::GRANT, 42),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002900 "Domain Domain(1) must be either App or SELinux.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07002901 );
2902 check_result_is_error_containing_string(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002903 rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::BLOB, 42),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002904 "Domain Domain(3) must be either App or SELinux.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07002905 );
2906 check_result_is_error_containing_string(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002907 rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::KEY_ID, 42),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002908 "Domain Domain(4) must be either App or SELinux.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07002909 );
2910
2911 // Test that we correctly handle setting an alias for something that does not exist.
2912 check_result_is_error_containing_string(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002913 rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::SELINUX, 42),
Joel Galenson33c04ad2020-08-03 11:04:38 -07002914 "Expected to update a single entry but instead updated 0",
2915 );
2916 // Test that we correctly abort the transaction in this case.
2917 let entries = get_keyentry(&db)?;
2918 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08002919 assert_eq!(extractor(&entries[0]), (None, None, None, Some(KEYSTORE_UUID)));
2920 assert_eq!(
2921 extractor(&entries[1]),
2922 (Some(Domain::APP), Some(42), Some("foo"), Some(KEYSTORE_UUID))
2923 );
Joel Galenson33c04ad2020-08-03 11:04:38 -07002924
2925 Ok(())
2926 }
2927
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002928 #[test]
2929 fn test_grant_ungrant() -> Result<()> {
2930 const CALLER_UID: u32 = 15;
2931 const GRANTEE_UID: u32 = 12;
2932 const SELINUX_NAMESPACE: i64 = 7;
2933
2934 let mut db = new_test_db()?;
2935 db.conn.execute(
Max Bires8e93d2b2021-01-14 13:17:59 -08002936 "INSERT INTO persistent.keyentry (id, key_type, domain, namespace, alias, state, km_uuid)
2937 VALUES (1, 0, 0, 15, 'key', 1, ?), (2, 0, 2, 7, 'yek', 1, ?);",
2938 params![KEYSTORE_UUID, KEYSTORE_UUID],
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002939 )?;
2940 let app_key = KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002941 domain: super::Domain::APP,
2942 nspace: 0,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002943 alias: Some("key".to_string()),
2944 blob: None,
2945 };
2946 const PVEC1: KeyPermSet = key_perm_set![KeyPerm::use_(), KeyPerm::get_info()];
2947 const PVEC2: KeyPermSet = key_perm_set![KeyPerm::use_()];
2948
2949 // Reset totally predictable random number generator in case we
2950 // are not the first test running on this thread.
2951 reset_random();
2952 let next_random = 0i64;
2953
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002954 let app_granted_key = db
Janis Danisevskis66784c42021-01-27 08:40:25 -08002955 .grant(&app_key, CALLER_UID, GRANTEE_UID, PVEC1, |k, a| {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002956 assert_eq!(*a, PVEC1);
2957 assert_eq!(
2958 *k,
2959 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002960 domain: super::Domain::APP,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002961 // namespace must be set to the caller_uid.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002962 nspace: CALLER_UID as i64,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002963 alias: Some("key".to_string()),
2964 blob: None,
2965 }
2966 );
2967 Ok(())
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002968 })
2969 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002970
2971 assert_eq!(
2972 app_granted_key,
2973 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002974 domain: super::Domain::GRANT,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002975 // The grantid is next_random due to the mock random number generator.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002976 nspace: next_random,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002977 alias: None,
2978 blob: None,
2979 }
2980 );
2981
2982 let selinux_key = KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002983 domain: super::Domain::SELINUX,
2984 nspace: SELINUX_NAMESPACE,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002985 alias: Some("yek".to_string()),
2986 blob: None,
2987 };
2988
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002989 let selinux_granted_key = db
Janis Danisevskis66784c42021-01-27 08:40:25 -08002990 .grant(&selinux_key, CALLER_UID, 12, 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::SELINUX,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002996 // namespace must be the supplied SELinux
2997 // namespace.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002998 nspace: SELINUX_NAMESPACE,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002999 alias: Some("yek".to_string()),
3000 blob: None,
3001 }
3002 );
3003 Ok(())
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003004 })
3005 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003006
3007 assert_eq!(
3008 selinux_granted_key,
3009 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003010 domain: super::Domain::GRANT,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003011 // The grantid is next_random + 1 due to the mock random number generator.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003012 nspace: next_random + 1,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003013 alias: None,
3014 blob: None,
3015 }
3016 );
3017
3018 // This should update the existing grant with PVEC2.
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003019 let selinux_granted_key = db
Janis Danisevskis66784c42021-01-27 08:40:25 -08003020 .grant(&selinux_key, CALLER_UID, 12, PVEC2, |k, a| {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003021 assert_eq!(*a, PVEC2);
3022 assert_eq!(
3023 *k,
3024 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003025 domain: super::Domain::SELINUX,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003026 // namespace must be the supplied SELinux
3027 // namespace.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003028 nspace: SELINUX_NAMESPACE,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003029 alias: Some("yek".to_string()),
3030 blob: None,
3031 }
3032 );
3033 Ok(())
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003034 })
3035 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003036
3037 assert_eq!(
3038 selinux_granted_key,
3039 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003040 domain: super::Domain::GRANT,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003041 // Same grant id as before. The entry was only updated.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003042 nspace: next_random + 1,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003043 alias: None,
3044 blob: None,
3045 }
3046 );
3047
3048 {
3049 // Limiting scope of stmt, because it borrows db.
3050 let mut stmt = db
3051 .conn
Janis Danisevskisbf15d732020-12-08 10:35:26 -08003052 .prepare("SELECT id, grantee, keyentryid, access_vector FROM persistent.grant;")?;
Janis Danisevskisee10b5f2020-09-22 16:42:35 -07003053 let mut rows =
3054 stmt.query_map::<(i64, u32, i64, KeyPermSet), _, _>(NO_PARAMS, |row| {
3055 Ok((
3056 row.get(0)?,
3057 row.get(1)?,
3058 row.get(2)?,
3059 KeyPermSet::from(row.get::<_, i32>(3)?),
3060 ))
3061 })?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003062
3063 let r = rows.next().unwrap().unwrap();
Janis Danisevskisee10b5f2020-09-22 16:42:35 -07003064 assert_eq!(r, (next_random, GRANTEE_UID, 1, PVEC1));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003065 let r = rows.next().unwrap().unwrap();
Janis Danisevskisee10b5f2020-09-22 16:42:35 -07003066 assert_eq!(r, (next_random + 1, GRANTEE_UID, 2, PVEC2));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003067 assert!(rows.next().is_none());
3068 }
3069
3070 debug_dump_keyentry_table(&mut db)?;
3071 println!("app_key {:?}", app_key);
3072 println!("selinux_key {:?}", selinux_key);
3073
Janis Danisevskis66784c42021-01-27 08:40:25 -08003074 db.ungrant(&app_key, CALLER_UID, GRANTEE_UID, |_| Ok(()))?;
3075 db.ungrant(&selinux_key, CALLER_UID, GRANTEE_UID, |_| Ok(()))?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003076
3077 Ok(())
3078 }
3079
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003080 static TEST_KEY_BLOB: &[u8] = b"my test blob";
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003081 static TEST_CERT_BLOB: &[u8] = b"my test cert";
3082 static TEST_CERT_CHAIN_BLOB: &[u8] = b"my test cert_chain";
3083
3084 #[test]
Janis Danisevskis377d1002021-01-27 19:07:48 -08003085 fn test_set_blob() -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003086 let key_id = KEY_ID_LOCK.get(3000);
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003087 let mut db = new_test_db()?;
Janis Danisevskis377d1002021-01-27 19:07:48 -08003088 db.set_blob(&key_id, SubComponentType::KEY_BLOB, Some(TEST_KEY_BLOB))?;
3089 db.set_blob(&key_id, SubComponentType::CERT, Some(TEST_CERT_BLOB))?;
3090 db.set_blob(&key_id, SubComponentType::CERT_CHAIN, Some(TEST_CERT_CHAIN_BLOB))?;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003091 drop(key_id);
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003092
3093 let mut stmt = db.conn.prepare(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003094 "SELECT subcomponent_type, keyentryid, blob FROM persistent.blobentry
3095 ORDER BY subcomponent_type ASC;",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003096 )?;
3097 let mut rows = stmt
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003098 .query_map::<(SubComponentType, i64, Vec<u8>), _, _>(NO_PARAMS, |row| {
3099 Ok((row.get(0)?, row.get(1)?, row.get(2)?))
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003100 })?;
3101 let r = rows.next().unwrap().unwrap();
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003102 assert_eq!(r, (SubComponentType::KEY_BLOB, 3000, TEST_KEY_BLOB.to_vec()));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003103 let r = rows.next().unwrap().unwrap();
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003104 assert_eq!(r, (SubComponentType::CERT, 3000, TEST_CERT_BLOB.to_vec()));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003105 let r = rows.next().unwrap().unwrap();
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003106 assert_eq!(r, (SubComponentType::CERT_CHAIN, 3000, TEST_CERT_CHAIN_BLOB.to_vec()));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003107
3108 Ok(())
3109 }
3110
3111 static TEST_ALIAS: &str = "my super duper key";
3112
3113 #[test]
3114 fn test_insert_and_load_full_keyentry_domain_app() -> Result<()> {
3115 let mut db = new_test_db()?;
Qi Wub9433b52020-12-01 14:52:46 +08003116 let key_id = make_test_key_entry(&mut db, Domain::APP, 1, TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08003117 .context("test_insert_and_load_full_keyentry_domain_app")?
3118 .0;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003119 let (_key_guard, key_entry) = db
3120 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003121 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003122 domain: Domain::APP,
3123 nspace: 0,
3124 alias: Some(TEST_ALIAS.to_string()),
3125 blob: None,
3126 },
3127 KeyType::Client,
3128 KeyEntryLoadBits::BOTH,
3129 1,
3130 |_k, _av| Ok(()),
3131 )
3132 .unwrap();
Qi Wub9433b52020-12-01 14:52:46 +08003133 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003134
3135 db.unbind_key(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003136 &KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003137 domain: Domain::APP,
3138 nspace: 0,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003139 alias: Some(TEST_ALIAS.to_string()),
3140 blob: None,
3141 },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003142 KeyType::Client,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003143 1,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003144 |_, _| Ok(()),
3145 )
3146 .unwrap();
3147
3148 assert_eq!(
3149 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
3150 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003151 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003152 domain: Domain::APP,
3153 nspace: 0,
3154 alias: Some(TEST_ALIAS.to_string()),
3155 blob: None,
3156 },
3157 KeyType::Client,
3158 KeyEntryLoadBits::NONE,
3159 1,
3160 |_k, _av| Ok(()),
3161 )
3162 .unwrap_err()
3163 .root_cause()
3164 .downcast_ref::<KsError>()
3165 );
3166
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003167 Ok(())
3168 }
3169
3170 #[test]
Janis Danisevskis377d1002021-01-27 19:07:48 -08003171 fn test_insert_and_load_certificate_entry_domain_app() -> Result<()> {
3172 let mut db = new_test_db()?;
3173
3174 db.store_new_certificate(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003175 &KeyDescriptor {
Janis Danisevskis377d1002021-01-27 19:07:48 -08003176 domain: Domain::APP,
3177 nspace: 1,
3178 alias: Some(TEST_ALIAS.to_string()),
3179 blob: None,
3180 },
3181 TEST_CERT_BLOB,
Max Bires8e93d2b2021-01-14 13:17:59 -08003182 &KEYSTORE_UUID,
Janis Danisevskis377d1002021-01-27 19:07:48 -08003183 )
3184 .expect("Trying to insert cert.");
3185
3186 let (_key_guard, mut key_entry) = db
3187 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003188 &KeyDescriptor {
Janis Danisevskis377d1002021-01-27 19:07:48 -08003189 domain: Domain::APP,
3190 nspace: 1,
3191 alias: Some(TEST_ALIAS.to_string()),
3192 blob: None,
3193 },
3194 KeyType::Client,
3195 KeyEntryLoadBits::PUBLIC,
3196 1,
3197 |_k, _av| Ok(()),
3198 )
3199 .expect("Trying to read certificate entry.");
3200
3201 assert!(key_entry.pure_cert());
3202 assert!(key_entry.cert().is_none());
3203 assert_eq!(key_entry.take_cert_chain(), Some(TEST_CERT_BLOB.to_vec()));
3204
3205 db.unbind_key(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003206 &KeyDescriptor {
Janis Danisevskis377d1002021-01-27 19:07:48 -08003207 domain: Domain::APP,
3208 nspace: 1,
3209 alias: Some(TEST_ALIAS.to_string()),
3210 blob: None,
3211 },
3212 KeyType::Client,
3213 1,
3214 |_, _| Ok(()),
3215 )
3216 .unwrap();
3217
3218 assert_eq!(
3219 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
3220 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003221 &KeyDescriptor {
Janis Danisevskis377d1002021-01-27 19:07:48 -08003222 domain: Domain::APP,
3223 nspace: 1,
3224 alias: Some(TEST_ALIAS.to_string()),
3225 blob: None,
3226 },
3227 KeyType::Client,
3228 KeyEntryLoadBits::NONE,
3229 1,
3230 |_k, _av| Ok(()),
3231 )
3232 .unwrap_err()
3233 .root_cause()
3234 .downcast_ref::<KsError>()
3235 );
3236
3237 Ok(())
3238 }
3239
3240 #[test]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003241 fn test_insert_and_load_full_keyentry_domain_selinux() -> Result<()> {
3242 let mut db = new_test_db()?;
Qi Wub9433b52020-12-01 14:52:46 +08003243 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08003244 .context("test_insert_and_load_full_keyentry_domain_selinux")?
3245 .0;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003246 let (_key_guard, key_entry) = db
3247 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003248 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003249 domain: Domain::SELINUX,
3250 nspace: 1,
3251 alias: Some(TEST_ALIAS.to_string()),
3252 blob: None,
3253 },
3254 KeyType::Client,
3255 KeyEntryLoadBits::BOTH,
3256 1,
3257 |_k, _av| Ok(()),
3258 )
3259 .unwrap();
Qi Wub9433b52020-12-01 14:52:46 +08003260 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003261
3262 db.unbind_key(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003263 &KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003264 domain: Domain::SELINUX,
3265 nspace: 1,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003266 alias: Some(TEST_ALIAS.to_string()),
3267 blob: None,
3268 },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003269 KeyType::Client,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003270 1,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003271 |_, _| Ok(()),
3272 )
3273 .unwrap();
3274
3275 assert_eq!(
3276 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
3277 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003278 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003279 domain: Domain::SELINUX,
3280 nspace: 1,
3281 alias: Some(TEST_ALIAS.to_string()),
3282 blob: None,
3283 },
3284 KeyType::Client,
3285 KeyEntryLoadBits::NONE,
3286 1,
3287 |_k, _av| Ok(()),
3288 )
3289 .unwrap_err()
3290 .root_cause()
3291 .downcast_ref::<KsError>()
3292 );
3293
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003294 Ok(())
3295 }
3296
3297 #[test]
3298 fn test_insert_and_load_full_keyentry_domain_key_id() -> Result<()> {
3299 let mut db = new_test_db()?;
Qi Wub9433b52020-12-01 14:52:46 +08003300 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08003301 .context("test_insert_and_load_full_keyentry_domain_key_id")?
3302 .0;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003303 let (_, key_entry) = db
3304 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003305 &KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003306 KeyType::Client,
3307 KeyEntryLoadBits::BOTH,
3308 1,
3309 |_k, _av| Ok(()),
3310 )
3311 .unwrap();
3312
Qi Wub9433b52020-12-01 14:52:46 +08003313 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003314
3315 db.unbind_key(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003316 &KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003317 KeyType::Client,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003318 1,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003319 |_, _| Ok(()),
3320 )
3321 .unwrap();
3322
3323 assert_eq!(
3324 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
3325 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003326 &KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003327 KeyType::Client,
3328 KeyEntryLoadBits::NONE,
3329 1,
3330 |_k, _av| Ok(()),
3331 )
3332 .unwrap_err()
3333 .root_cause()
3334 .downcast_ref::<KsError>()
3335 );
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003336
3337 Ok(())
3338 }
3339
3340 #[test]
Qi Wub9433b52020-12-01 14:52:46 +08003341 fn test_check_and_update_key_usage_count_with_limited_use_key() -> Result<()> {
3342 let mut db = new_test_db()?;
3343 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, Some(123))
3344 .context("test_check_and_update_key_usage_count_with_limited_use_key")?
3345 .0;
3346 // Update the usage count of the limited use key.
3347 db.check_and_update_key_usage_count(key_id)?;
3348
3349 let (_key_guard, key_entry) = db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003350 &KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
Qi Wub9433b52020-12-01 14:52:46 +08003351 KeyType::Client,
3352 KeyEntryLoadBits::BOTH,
3353 1,
3354 |_k, _av| Ok(()),
3355 )?;
3356
3357 // The usage count is decremented now.
3358 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, Some(122)));
3359
3360 Ok(())
3361 }
3362
3363 #[test]
3364 fn test_check_and_update_key_usage_count_with_exhausted_limited_use_key() -> Result<()> {
3365 let mut db = new_test_db()?;
3366 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, Some(1))
3367 .context("test_check_and_update_key_usage_count_with_exhausted_limited_use_key")?
3368 .0;
3369 // Update the usage count of the limited use key.
3370 db.check_and_update_key_usage_count(key_id).expect(concat!(
3371 "In test_check_and_update_key_usage_count_with_exhausted_limited_use_key: ",
3372 "This should succeed."
3373 ));
3374
3375 // Try to update the exhausted limited use key.
3376 let e = db.check_and_update_key_usage_count(key_id).expect_err(concat!(
3377 "In test_check_and_update_key_usage_count_with_exhausted_limited_use_key: ",
3378 "This should fail."
3379 ));
3380 assert_eq!(
3381 &KsError::Km(ErrorCode::INVALID_KEY_BLOB),
3382 e.root_cause().downcast_ref::<KsError>().unwrap()
3383 );
3384
3385 Ok(())
3386 }
3387
3388 #[test]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003389 fn test_insert_and_load_full_keyentry_from_grant() -> Result<()> {
3390 let mut db = new_test_db()?;
Qi Wub9433b52020-12-01 14:52:46 +08003391 let key_id = make_test_key_entry(&mut db, Domain::APP, 1, TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08003392 .context("test_insert_and_load_full_keyentry_from_grant")?
3393 .0;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003394
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003395 let granted_key = db
3396 .grant(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003397 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003398 domain: Domain::APP,
3399 nspace: 0,
3400 alias: Some(TEST_ALIAS.to_string()),
3401 blob: None,
3402 },
3403 1,
3404 2,
3405 key_perm_set![KeyPerm::use_()],
3406 |_k, _av| Ok(()),
3407 )
3408 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003409
3410 debug_dump_grant_table(&mut db)?;
3411
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003412 let (_key_guard, key_entry) = db
Janis Danisevskis66784c42021-01-27 08:40:25 -08003413 .load_key_entry(&granted_key, KeyType::Client, KeyEntryLoadBits::BOTH, 2, |k, av| {
3414 assert_eq!(Domain::GRANT, k.domain);
3415 assert!(av.unwrap().includes(KeyPerm::use_()));
3416 Ok(())
3417 })
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003418 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003419
Qi Wub9433b52020-12-01 14:52:46 +08003420 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003421
Janis Danisevskis66784c42021-01-27 08:40:25 -08003422 db.unbind_key(&granted_key, KeyType::Client, 2, |_, _| Ok(())).unwrap();
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003423
3424 assert_eq!(
3425 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
3426 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003427 &granted_key,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003428 KeyType::Client,
3429 KeyEntryLoadBits::NONE,
3430 2,
3431 |_k, _av| Ok(()),
3432 )
3433 .unwrap_err()
3434 .root_cause()
3435 .downcast_ref::<KsError>()
3436 );
3437
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003438 Ok(())
3439 }
3440
Janis Danisevskis45760022021-01-19 16:34:10 -08003441 // This test attempts to load a key by key id while the caller is not the owner
3442 // but a grant exists for the given key and the caller.
3443 #[test]
3444 fn test_insert_and_load_full_keyentry_from_grant_by_key_id() -> Result<()> {
3445 let mut db = new_test_db()?;
3446 const OWNER_UID: u32 = 1u32;
3447 const GRANTEE_UID: u32 = 2u32;
3448 const SOMEONE_ELSE_UID: u32 = 3u32;
3449 let key_id = make_test_key_entry(&mut db, Domain::APP, OWNER_UID as i64, TEST_ALIAS, None)
3450 .context("test_insert_and_load_full_keyentry_from_grant_by_key_id")?
3451 .0;
3452
3453 db.grant(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003454 &KeyDescriptor {
Janis Danisevskis45760022021-01-19 16:34:10 -08003455 domain: Domain::APP,
3456 nspace: 0,
3457 alias: Some(TEST_ALIAS.to_string()),
3458 blob: None,
3459 },
3460 OWNER_UID,
3461 GRANTEE_UID,
3462 key_perm_set![KeyPerm::use_()],
3463 |_k, _av| Ok(()),
3464 )
3465 .unwrap();
3466
3467 debug_dump_grant_table(&mut db)?;
3468
3469 let id_descriptor =
3470 KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, ..Default::default() };
3471
3472 let (_, key_entry) = db
3473 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003474 &id_descriptor,
Janis Danisevskis45760022021-01-19 16:34:10 -08003475 KeyType::Client,
3476 KeyEntryLoadBits::BOTH,
3477 GRANTEE_UID,
3478 |k, av| {
3479 assert_eq!(Domain::APP, k.domain);
3480 assert_eq!(OWNER_UID as i64, k.nspace);
3481 assert!(av.unwrap().includes(KeyPerm::use_()));
3482 Ok(())
3483 },
3484 )
3485 .unwrap();
3486
3487 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
3488
3489 let (_, key_entry) = db
3490 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003491 &id_descriptor,
Janis Danisevskis45760022021-01-19 16:34:10 -08003492 KeyType::Client,
3493 KeyEntryLoadBits::BOTH,
3494 SOMEONE_ELSE_UID,
3495 |k, av| {
3496 assert_eq!(Domain::APP, k.domain);
3497 assert_eq!(OWNER_UID as i64, k.nspace);
3498 assert!(av.is_none());
3499 Ok(())
3500 },
3501 )
3502 .unwrap();
3503
3504 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
3505
Janis Danisevskis66784c42021-01-27 08:40:25 -08003506 db.unbind_key(&id_descriptor, KeyType::Client, OWNER_UID, |_, _| Ok(())).unwrap();
Janis Danisevskis45760022021-01-19 16:34:10 -08003507
3508 assert_eq!(
3509 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
3510 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003511 &id_descriptor,
Janis Danisevskis45760022021-01-19 16:34:10 -08003512 KeyType::Client,
3513 KeyEntryLoadBits::NONE,
3514 GRANTEE_UID,
3515 |_k, _av| Ok(()),
3516 )
3517 .unwrap_err()
3518 .root_cause()
3519 .downcast_ref::<KsError>()
3520 );
3521
3522 Ok(())
3523 }
3524
Janis Danisevskisaec14592020-11-12 09:41:49 -08003525 static KEY_LOCK_TEST_ALIAS: &str = "my super duper locked key";
3526
Janis Danisevskisaec14592020-11-12 09:41:49 -08003527 #[test]
3528 fn test_insert_and_load_full_keyentry_domain_app_concurrently() -> Result<()> {
3529 let handle = {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08003530 let temp_dir = Arc::new(TempDir::new("id_lock_test")?);
3531 let temp_dir_clone = temp_dir.clone();
3532 let mut db = KeystoreDB::new(temp_dir.path())?;
Qi Wub9433b52020-12-01 14:52:46 +08003533 let key_id = make_test_key_entry(&mut db, Domain::APP, 33, KEY_LOCK_TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08003534 .context("test_insert_and_load_full_keyentry_domain_app")?
3535 .0;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003536 let (_key_guard, key_entry) = db
3537 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003538 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003539 domain: Domain::APP,
3540 nspace: 0,
3541 alias: Some(KEY_LOCK_TEST_ALIAS.to_string()),
3542 blob: None,
3543 },
3544 KeyType::Client,
3545 KeyEntryLoadBits::BOTH,
3546 33,
3547 |_k, _av| Ok(()),
3548 )
3549 .unwrap();
Qi Wub9433b52020-12-01 14:52:46 +08003550 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskisaec14592020-11-12 09:41:49 -08003551 let state = Arc::new(AtomicU8::new(1));
3552 let state2 = state.clone();
3553
3554 // Spawning a second thread that attempts to acquire the key id lock
3555 // for the same key as the primary thread. The primary thread then
3556 // waits, thereby forcing the secondary thread into the second stage
3557 // of acquiring the lock (see KEY ID LOCK 2/2 above).
3558 // The test succeeds if the secondary thread observes the transition
3559 // of `state` from 1 to 2, despite having a whole second to overtake
3560 // the primary thread.
3561 let handle = thread::spawn(move || {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08003562 let temp_dir = temp_dir_clone;
3563 let mut db = KeystoreDB::new(temp_dir.path()).unwrap();
Janis Danisevskisaec14592020-11-12 09:41:49 -08003564 assert!(db
3565 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003566 &KeyDescriptor {
Janis Danisevskisaec14592020-11-12 09:41:49 -08003567 domain: Domain::APP,
3568 nspace: 0,
3569 alias: Some(KEY_LOCK_TEST_ALIAS.to_string()),
3570 blob: None,
3571 },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003572 KeyType::Client,
Janis Danisevskisaec14592020-11-12 09:41:49 -08003573 KeyEntryLoadBits::BOTH,
3574 33,
3575 |_k, _av| Ok(()),
3576 )
3577 .is_ok());
3578 // We should only see a 2 here because we can only return
3579 // from load_key_entry when the `_key_guard` expires,
3580 // which happens at the end of the scope.
3581 assert_eq!(2, state2.load(Ordering::Relaxed));
3582 });
3583
3584 thread::sleep(std::time::Duration::from_millis(1000));
3585
3586 assert_eq!(Ok(1), state.compare_exchange(1, 2, Ordering::Relaxed, Ordering::Relaxed));
3587
3588 // Return the handle from this scope so we can join with the
3589 // secondary thread after the key id lock has expired.
3590 handle
3591 // This is where the `_key_guard` goes out of scope,
3592 // which is the reason for concurrent load_key_entry on the same key
3593 // to unblock.
3594 };
3595 // Join with the secondary thread and unwrap, to propagate failing asserts to the
3596 // main test thread. We will not see failing asserts in secondary threads otherwise.
3597 handle.join().unwrap();
3598 Ok(())
3599 }
3600
Janis Danisevskise92a5e62020-12-02 12:57:41 -08003601 #[test]
Janis Danisevskis66784c42021-01-27 08:40:25 -08003602 fn teset_database_busy_error_code() {
3603 let temp_dir =
3604 TempDir::new("test_database_busy_error_code_").expect("Failed to create temp dir.");
3605
3606 let mut db1 = KeystoreDB::new(temp_dir.path()).expect("Failed to open database1.");
3607 let mut db2 = KeystoreDB::new(temp_dir.path()).expect("Failed to open database2.");
3608
3609 let _tx1 = db1
3610 .conn
3611 .transaction_with_behavior(TransactionBehavior::Immediate)
3612 .expect("Failed to create first transaction.");
3613
3614 let error = db2
3615 .conn
3616 .transaction_with_behavior(TransactionBehavior::Immediate)
3617 .context("Transaction begin failed.")
3618 .expect_err("This should fail.");
3619 let root_cause = error.root_cause();
3620 if let Some(rusqlite::ffi::Error { code: rusqlite::ErrorCode::DatabaseBusy, .. }) =
3621 root_cause.downcast_ref::<rusqlite::ffi::Error>()
3622 {
3623 return;
3624 }
3625 panic!(
3626 "Unexpected error {:?} \n{:?} \n{:?}",
3627 error,
3628 root_cause,
3629 root_cause.downcast_ref::<rusqlite::ffi::Error>()
3630 )
3631 }
3632
3633 #[cfg(disabled)]
3634 #[test]
3635 fn test_large_number_of_concurrent_db_manipulations() -> Result<()> {
3636 let temp_dir = Arc::new(
3637 TempDir::new("test_large_number_of_concurrent_db_manipulations_")
3638 .expect("Failed to create temp dir."),
3639 );
3640
3641 let test_begin = Instant::now();
3642
3643 let mut db = KeystoreDB::new(temp_dir.path()).expect("Failed to open database.");
3644 const KEY_COUNT: u32 = 500u32;
3645 const OPEN_DB_COUNT: u32 = 50u32;
3646
3647 let mut actual_key_count = KEY_COUNT;
3648 // First insert KEY_COUNT keys.
3649 for count in 0..KEY_COUNT {
3650 if Instant::now().duration_since(test_begin) >= Duration::from_secs(15) {
3651 actual_key_count = count;
3652 break;
3653 }
3654 let alias = format!("test_alias_{}", count);
3655 make_test_key_entry(&mut db, Domain::APP, 1, &alias, None)
3656 .expect("Failed to make key entry.");
3657 }
3658
3659 // Insert more keys from a different thread and into a different namespace.
3660 let temp_dir1 = temp_dir.clone();
3661 let handle1 = thread::spawn(move || {
3662 let mut db = KeystoreDB::new(temp_dir1.path()).expect("Failed to open database.");
3663
3664 for count in 0..actual_key_count {
3665 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
3666 return;
3667 }
3668 let alias = format!("test_alias_{}", count);
3669 make_test_key_entry(&mut db, Domain::APP, 2, &alias, None)
3670 .expect("Failed to make key entry.");
3671 }
3672
3673 // then unbind them again.
3674 for count in 0..actual_key_count {
3675 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
3676 return;
3677 }
3678 let key = KeyDescriptor {
3679 domain: Domain::APP,
3680 nspace: -1,
3681 alias: Some(format!("test_alias_{}", count)),
3682 blob: None,
3683 };
3684 db.unbind_key(&key, KeyType::Client, 2, |_, _| Ok(())).expect("Unbind Failed.");
3685 }
3686 });
3687
3688 // And start unbinding the first set of keys.
3689 let temp_dir2 = temp_dir.clone();
3690 let handle2 = thread::spawn(move || {
3691 let mut db = KeystoreDB::new(temp_dir2.path()).expect("Failed to open database.");
3692
3693 for count in 0..actual_key_count {
3694 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
3695 return;
3696 }
3697 let key = KeyDescriptor {
3698 domain: Domain::APP,
3699 nspace: -1,
3700 alias: Some(format!("test_alias_{}", count)),
3701 blob: None,
3702 };
3703 db.unbind_key(&key, KeyType::Client, 1, |_, _| Ok(())).expect("Unbind Failed.");
3704 }
3705 });
3706
3707 let stop_deleting = Arc::new(AtomicU8::new(0));
3708 let stop_deleting2 = stop_deleting.clone();
3709
3710 // And delete anything that is unreferenced keys.
3711 let temp_dir3 = temp_dir.clone();
3712 let handle3 = thread::spawn(move || {
3713 let mut db = KeystoreDB::new(temp_dir3.path()).expect("Failed to open database.");
3714
3715 while stop_deleting2.load(Ordering::Relaxed) != 1 {
3716 while let Some((key_guard, _key)) =
3717 db.get_unreferenced_key().expect("Failed to get unreferenced Key.")
3718 {
3719 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
3720 return;
3721 }
3722 db.purge_key_entry(key_guard).expect("Failed to purge key.");
3723 }
3724 std::thread::sleep(std::time::Duration::from_millis(100));
3725 }
3726 });
3727
3728 // While a lot of inserting and deleting is going on we have to open database connections
3729 // successfully and use them.
3730 // This clone is not redundant, because temp_dir needs to be kept alive until db goes
3731 // out of scope.
3732 #[allow(clippy::redundant_clone)]
3733 let temp_dir4 = temp_dir.clone();
3734 let handle4 = thread::spawn(move || {
3735 for count in 0..OPEN_DB_COUNT {
3736 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
3737 return;
3738 }
3739 let mut db = KeystoreDB::new(temp_dir4.path()).expect("Failed to open database.");
3740
3741 let alias = format!("test_alias_{}", count);
3742 make_test_key_entry(&mut db, Domain::APP, 3, &alias, None)
3743 .expect("Failed to make key entry.");
3744 let key = KeyDescriptor {
3745 domain: Domain::APP,
3746 nspace: -1,
3747 alias: Some(alias),
3748 blob: None,
3749 };
3750 db.unbind_key(&key, KeyType::Client, 3, |_, _| Ok(())).expect("Unbind Failed.");
3751 }
3752 });
3753
3754 handle1.join().expect("Thread 1 panicked.");
3755 handle2.join().expect("Thread 2 panicked.");
3756 handle4.join().expect("Thread 4 panicked.");
3757
3758 stop_deleting.store(1, Ordering::Relaxed);
3759 handle3.join().expect("Thread 3 panicked.");
3760
3761 Ok(())
3762 }
3763
3764 #[test]
Janis Danisevskise92a5e62020-12-02 12:57:41 -08003765 fn list() -> Result<()> {
3766 let temp_dir = TempDir::new("list_test")?;
3767 let mut db = KeystoreDB::new(temp_dir.path())?;
3768 static LIST_O_ENTRIES: &[(Domain, i64, &str)] = &[
3769 (Domain::APP, 1, "test1"),
3770 (Domain::APP, 1, "test2"),
3771 (Domain::APP, 1, "test3"),
3772 (Domain::APP, 1, "test4"),
3773 (Domain::APP, 1, "test5"),
3774 (Domain::APP, 1, "test6"),
3775 (Domain::APP, 1, "test7"),
3776 (Domain::APP, 2, "test1"),
3777 (Domain::APP, 2, "test2"),
3778 (Domain::APP, 2, "test3"),
3779 (Domain::APP, 2, "test4"),
3780 (Domain::APP, 2, "test5"),
3781 (Domain::APP, 2, "test6"),
3782 (Domain::APP, 2, "test8"),
3783 (Domain::SELINUX, 100, "test1"),
3784 (Domain::SELINUX, 100, "test2"),
3785 (Domain::SELINUX, 100, "test3"),
3786 (Domain::SELINUX, 100, "test4"),
3787 (Domain::SELINUX, 100, "test5"),
3788 (Domain::SELINUX, 100, "test6"),
3789 (Domain::SELINUX, 100, "test9"),
3790 ];
3791
3792 let list_o_keys: Vec<(i64, i64)> = LIST_O_ENTRIES
3793 .iter()
3794 .map(|(domain, ns, alias)| {
Qi Wub9433b52020-12-01 14:52:46 +08003795 let entry = make_test_key_entry(&mut db, *domain, *ns, *alias, None)
3796 .unwrap_or_else(|e| {
Janis Danisevskise92a5e62020-12-02 12:57:41 -08003797 panic!("Failed to insert {:?} {} {}. Error {:?}", domain, ns, alias, e)
3798 });
3799 (entry.id(), *ns)
3800 })
3801 .collect();
3802
3803 for (domain, namespace) in
3804 &[(Domain::APP, 1i64), (Domain::APP, 2i64), (Domain::SELINUX, 100i64)]
3805 {
3806 let mut list_o_descriptors: Vec<KeyDescriptor> = LIST_O_ENTRIES
3807 .iter()
3808 .filter_map(|(domain, ns, alias)| match ns {
3809 ns if *ns == *namespace => Some(KeyDescriptor {
3810 domain: *domain,
3811 nspace: *ns,
3812 alias: Some(alias.to_string()),
3813 blob: None,
3814 }),
3815 _ => None,
3816 })
3817 .collect();
3818 list_o_descriptors.sort();
3819 let mut list_result = db.list(*domain, *namespace)?;
3820 list_result.sort();
3821 assert_eq!(list_o_descriptors, list_result);
3822
3823 let mut list_o_ids: Vec<i64> = list_o_descriptors
3824 .into_iter()
3825 .map(|d| {
3826 let (_, entry) = db
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003827 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003828 &d,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003829 KeyType::Client,
3830 KeyEntryLoadBits::NONE,
3831 *namespace as u32,
3832 |_, _| Ok(()),
3833 )
Janis Danisevskise92a5e62020-12-02 12:57:41 -08003834 .unwrap();
3835 entry.id()
3836 })
3837 .collect();
3838 list_o_ids.sort_unstable();
3839 let mut loaded_entries: Vec<i64> = list_o_keys
3840 .iter()
3841 .filter_map(|(id, ns)| match ns {
3842 ns if *ns == *namespace => Some(*id),
3843 _ => None,
3844 })
3845 .collect();
3846 loaded_entries.sort_unstable();
3847 assert_eq!(list_o_ids, loaded_entries);
3848 }
3849 assert_eq!(Vec::<KeyDescriptor>::new(), db.list(Domain::SELINUX, 101)?);
3850
3851 Ok(())
3852 }
3853
Joel Galenson0891bc12020-07-20 10:37:03 -07003854 // Helpers
3855
3856 // Checks that the given result is an error containing the given string.
3857 fn check_result_is_error_containing_string<T>(result: Result<T>, target: &str) {
3858 let error_str = format!(
3859 "{:#?}",
3860 result.err().unwrap_or_else(|| panic!("Expected the error: {}", target))
3861 );
3862 assert!(
3863 error_str.contains(target),
3864 "The string \"{}\" should contain \"{}\"",
3865 error_str,
3866 target
3867 );
3868 }
3869
Joel Galenson2aab4432020-07-22 15:27:57 -07003870 #[derive(Debug, PartialEq)]
Joel Galenson0891bc12020-07-20 10:37:03 -07003871 #[allow(dead_code)]
3872 struct KeyEntryRow {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003873 id: i64,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003874 key_type: KeyType,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003875 domain: Option<Domain>,
Joel Galenson0891bc12020-07-20 10:37:03 -07003876 namespace: Option<i64>,
3877 alias: Option<String>,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003878 state: KeyLifeCycle,
Max Bires8e93d2b2021-01-14 13:17:59 -08003879 km_uuid: Option<Uuid>,
Joel Galenson0891bc12020-07-20 10:37:03 -07003880 }
3881
3882 fn get_keyentry(db: &KeystoreDB) -> Result<Vec<KeyEntryRow>> {
3883 db.conn
Joel Galenson2aab4432020-07-22 15:27:57 -07003884 .prepare("SELECT * FROM persistent.keyentry;")?
Joel Galenson0891bc12020-07-20 10:37:03 -07003885 .query_map(NO_PARAMS, |row| {
Joel Galenson0891bc12020-07-20 10:37:03 -07003886 Ok(KeyEntryRow {
3887 id: row.get(0)?,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003888 key_type: row.get(1)?,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003889 domain: match row.get(2)? {
3890 Some(i) => Some(Domain(i)),
3891 None => None,
3892 },
Joel Galenson0891bc12020-07-20 10:37:03 -07003893 namespace: row.get(3)?,
3894 alias: row.get(4)?,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003895 state: row.get(5)?,
Max Bires8e93d2b2021-01-14 13:17:59 -08003896 km_uuid: row.get(6)?,
Joel Galenson0891bc12020-07-20 10:37:03 -07003897 })
3898 })?
3899 .map(|r| r.context("Could not read keyentry row."))
3900 .collect::<Result<Vec<_>>>()
3901 }
3902
Max Bires2b2e6562020-09-22 11:22:36 -07003903 fn load_attestation_key_pool(
3904 db: &mut KeystoreDB,
3905 expiration_date: i64,
3906 namespace: i64,
3907 base_byte: u8,
3908 ) -> Result<Vec<Vec<u8>>> {
3909 let mut chain: Vec<Vec<u8>> = Vec::new();
3910 let public_key: Vec<u8> = vec![base_byte, 0x02 * base_byte];
3911 let cert_chain: Vec<u8> = vec![0x03 * base_byte, 0x04 * base_byte];
3912 let priv_key: Vec<u8> = vec![0x05 * base_byte, 0x06 * base_byte];
3913 let raw_public_key: Vec<u8> = vec![0x0b * base_byte, 0x0c * base_byte];
3914 db.create_attestation_key_entry(&public_key, &raw_public_key, &priv_key, &KEYSTORE_UUID)?;
3915 db.store_signed_attestation_certificate_chain(
3916 &raw_public_key,
3917 &cert_chain,
3918 expiration_date,
3919 &KEYSTORE_UUID,
3920 )?;
3921 db.assign_attestation_key(Domain::APP, namespace, &KEYSTORE_UUID)?;
3922 chain.push(public_key);
3923 chain.push(cert_chain);
3924 chain.push(priv_key);
3925 chain.push(raw_public_key);
3926 Ok(chain)
3927 }
3928
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07003929 // Note: The parameters and SecurityLevel associations are nonsensical. This
3930 // collection is only used to check if the parameters are preserved as expected by the
3931 // database.
Qi Wub9433b52020-12-01 14:52:46 +08003932 fn make_test_params(max_usage_count: Option<i32>) -> Vec<KeyParameter> {
3933 let mut params = vec![
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07003934 KeyParameter::new(KeyParameterValue::Invalid, SecurityLevel::TRUSTED_ENVIRONMENT),
3935 KeyParameter::new(
3936 KeyParameterValue::KeyPurpose(KeyPurpose::SIGN),
3937 SecurityLevel::TRUSTED_ENVIRONMENT,
3938 ),
3939 KeyParameter::new(
3940 KeyParameterValue::KeyPurpose(KeyPurpose::DECRYPT),
3941 SecurityLevel::TRUSTED_ENVIRONMENT,
3942 ),
3943 KeyParameter::new(
3944 KeyParameterValue::Algorithm(Algorithm::RSA),
3945 SecurityLevel::TRUSTED_ENVIRONMENT,
3946 ),
3947 KeyParameter::new(KeyParameterValue::KeySize(1024), SecurityLevel::TRUSTED_ENVIRONMENT),
3948 KeyParameter::new(
3949 KeyParameterValue::BlockMode(BlockMode::ECB),
3950 SecurityLevel::TRUSTED_ENVIRONMENT,
3951 ),
3952 KeyParameter::new(
3953 KeyParameterValue::BlockMode(BlockMode::GCM),
3954 SecurityLevel::TRUSTED_ENVIRONMENT,
3955 ),
3956 KeyParameter::new(KeyParameterValue::Digest(Digest::NONE), SecurityLevel::STRONGBOX),
3957 KeyParameter::new(
3958 KeyParameterValue::Digest(Digest::MD5),
3959 SecurityLevel::TRUSTED_ENVIRONMENT,
3960 ),
3961 KeyParameter::new(
3962 KeyParameterValue::Digest(Digest::SHA_2_224),
3963 SecurityLevel::TRUSTED_ENVIRONMENT,
3964 ),
3965 KeyParameter::new(
3966 KeyParameterValue::Digest(Digest::SHA_2_256),
3967 SecurityLevel::STRONGBOX,
3968 ),
3969 KeyParameter::new(
3970 KeyParameterValue::PaddingMode(PaddingMode::NONE),
3971 SecurityLevel::TRUSTED_ENVIRONMENT,
3972 ),
3973 KeyParameter::new(
3974 KeyParameterValue::PaddingMode(PaddingMode::RSA_OAEP),
3975 SecurityLevel::TRUSTED_ENVIRONMENT,
3976 ),
3977 KeyParameter::new(
3978 KeyParameterValue::PaddingMode(PaddingMode::RSA_PSS),
3979 SecurityLevel::STRONGBOX,
3980 ),
3981 KeyParameter::new(
3982 KeyParameterValue::PaddingMode(PaddingMode::RSA_PKCS1_1_5_SIGN),
3983 SecurityLevel::TRUSTED_ENVIRONMENT,
3984 ),
3985 KeyParameter::new(KeyParameterValue::CallerNonce, SecurityLevel::TRUSTED_ENVIRONMENT),
3986 KeyParameter::new(KeyParameterValue::MinMacLength(256), SecurityLevel::STRONGBOX),
3987 KeyParameter::new(
3988 KeyParameterValue::EcCurve(EcCurve::P_224),
3989 SecurityLevel::TRUSTED_ENVIRONMENT,
3990 ),
3991 KeyParameter::new(KeyParameterValue::EcCurve(EcCurve::P_256), SecurityLevel::STRONGBOX),
3992 KeyParameter::new(
3993 KeyParameterValue::EcCurve(EcCurve::P_384),
3994 SecurityLevel::TRUSTED_ENVIRONMENT,
3995 ),
3996 KeyParameter::new(
3997 KeyParameterValue::EcCurve(EcCurve::P_521),
3998 SecurityLevel::TRUSTED_ENVIRONMENT,
3999 ),
4000 KeyParameter::new(
4001 KeyParameterValue::RSAPublicExponent(3),
4002 SecurityLevel::TRUSTED_ENVIRONMENT,
4003 ),
4004 KeyParameter::new(
4005 KeyParameterValue::IncludeUniqueID,
4006 SecurityLevel::TRUSTED_ENVIRONMENT,
4007 ),
4008 KeyParameter::new(KeyParameterValue::BootLoaderOnly, SecurityLevel::STRONGBOX),
4009 KeyParameter::new(KeyParameterValue::RollbackResistance, SecurityLevel::STRONGBOX),
4010 KeyParameter::new(
4011 KeyParameterValue::ActiveDateTime(1234567890),
4012 SecurityLevel::STRONGBOX,
4013 ),
4014 KeyParameter::new(
4015 KeyParameterValue::OriginationExpireDateTime(1234567890),
4016 SecurityLevel::TRUSTED_ENVIRONMENT,
4017 ),
4018 KeyParameter::new(
4019 KeyParameterValue::UsageExpireDateTime(1234567890),
4020 SecurityLevel::TRUSTED_ENVIRONMENT,
4021 ),
4022 KeyParameter::new(
4023 KeyParameterValue::MinSecondsBetweenOps(1234567890),
4024 SecurityLevel::TRUSTED_ENVIRONMENT,
4025 ),
4026 KeyParameter::new(
4027 KeyParameterValue::MaxUsesPerBoot(1234567890),
4028 SecurityLevel::TRUSTED_ENVIRONMENT,
4029 ),
4030 KeyParameter::new(KeyParameterValue::UserID(1), SecurityLevel::STRONGBOX),
4031 KeyParameter::new(KeyParameterValue::UserSecureID(42), SecurityLevel::STRONGBOX),
4032 KeyParameter::new(
4033 KeyParameterValue::NoAuthRequired,
4034 SecurityLevel::TRUSTED_ENVIRONMENT,
4035 ),
4036 KeyParameter::new(
4037 KeyParameterValue::HardwareAuthenticatorType(HardwareAuthenticatorType::PASSWORD),
4038 SecurityLevel::TRUSTED_ENVIRONMENT,
4039 ),
4040 KeyParameter::new(KeyParameterValue::AuthTimeout(1234567890), SecurityLevel::SOFTWARE),
4041 KeyParameter::new(KeyParameterValue::AllowWhileOnBody, SecurityLevel::SOFTWARE),
4042 KeyParameter::new(
4043 KeyParameterValue::TrustedUserPresenceRequired,
4044 SecurityLevel::TRUSTED_ENVIRONMENT,
4045 ),
4046 KeyParameter::new(
4047 KeyParameterValue::TrustedConfirmationRequired,
4048 SecurityLevel::TRUSTED_ENVIRONMENT,
4049 ),
4050 KeyParameter::new(
4051 KeyParameterValue::UnlockedDeviceRequired,
4052 SecurityLevel::TRUSTED_ENVIRONMENT,
4053 ),
4054 KeyParameter::new(
4055 KeyParameterValue::ApplicationID(vec![1u8, 2u8, 3u8, 4u8]),
4056 SecurityLevel::SOFTWARE,
4057 ),
4058 KeyParameter::new(
4059 KeyParameterValue::ApplicationData(vec![4u8, 3u8, 2u8, 1u8]),
4060 SecurityLevel::SOFTWARE,
4061 ),
4062 KeyParameter::new(
4063 KeyParameterValue::CreationDateTime(12345677890),
4064 SecurityLevel::SOFTWARE,
4065 ),
4066 KeyParameter::new(
4067 KeyParameterValue::KeyOrigin(KeyOrigin::GENERATED),
4068 SecurityLevel::TRUSTED_ENVIRONMENT,
4069 ),
4070 KeyParameter::new(
4071 KeyParameterValue::RootOfTrust(vec![3u8, 2u8, 1u8, 4u8]),
4072 SecurityLevel::TRUSTED_ENVIRONMENT,
4073 ),
4074 KeyParameter::new(KeyParameterValue::OSVersion(1), SecurityLevel::TRUSTED_ENVIRONMENT),
4075 KeyParameter::new(KeyParameterValue::OSPatchLevel(2), SecurityLevel::SOFTWARE),
4076 KeyParameter::new(
4077 KeyParameterValue::UniqueID(vec![4u8, 3u8, 1u8, 2u8]),
4078 SecurityLevel::SOFTWARE,
4079 ),
4080 KeyParameter::new(
4081 KeyParameterValue::AttestationChallenge(vec![4u8, 3u8, 1u8, 2u8]),
4082 SecurityLevel::TRUSTED_ENVIRONMENT,
4083 ),
4084 KeyParameter::new(
4085 KeyParameterValue::AttestationApplicationID(vec![4u8, 3u8, 1u8, 2u8]),
4086 SecurityLevel::TRUSTED_ENVIRONMENT,
4087 ),
4088 KeyParameter::new(
4089 KeyParameterValue::AttestationIdBrand(vec![4u8, 3u8, 1u8, 2u8]),
4090 SecurityLevel::TRUSTED_ENVIRONMENT,
4091 ),
4092 KeyParameter::new(
4093 KeyParameterValue::AttestationIdDevice(vec![4u8, 3u8, 1u8, 2u8]),
4094 SecurityLevel::TRUSTED_ENVIRONMENT,
4095 ),
4096 KeyParameter::new(
4097 KeyParameterValue::AttestationIdProduct(vec![4u8, 3u8, 1u8, 2u8]),
4098 SecurityLevel::TRUSTED_ENVIRONMENT,
4099 ),
4100 KeyParameter::new(
4101 KeyParameterValue::AttestationIdSerial(vec![4u8, 3u8, 1u8, 2u8]),
4102 SecurityLevel::TRUSTED_ENVIRONMENT,
4103 ),
4104 KeyParameter::new(
4105 KeyParameterValue::AttestationIdIMEI(vec![4u8, 3u8, 1u8, 2u8]),
4106 SecurityLevel::TRUSTED_ENVIRONMENT,
4107 ),
4108 KeyParameter::new(
4109 KeyParameterValue::AttestationIdMEID(vec![4u8, 3u8, 1u8, 2u8]),
4110 SecurityLevel::TRUSTED_ENVIRONMENT,
4111 ),
4112 KeyParameter::new(
4113 KeyParameterValue::AttestationIdManufacturer(vec![4u8, 3u8, 1u8, 2u8]),
4114 SecurityLevel::TRUSTED_ENVIRONMENT,
4115 ),
4116 KeyParameter::new(
4117 KeyParameterValue::AttestationIdModel(vec![4u8, 3u8, 1u8, 2u8]),
4118 SecurityLevel::TRUSTED_ENVIRONMENT,
4119 ),
4120 KeyParameter::new(
4121 KeyParameterValue::VendorPatchLevel(3),
4122 SecurityLevel::TRUSTED_ENVIRONMENT,
4123 ),
4124 KeyParameter::new(
4125 KeyParameterValue::BootPatchLevel(4),
4126 SecurityLevel::TRUSTED_ENVIRONMENT,
4127 ),
4128 KeyParameter::new(
4129 KeyParameterValue::AssociatedData(vec![4u8, 3u8, 1u8, 2u8]),
4130 SecurityLevel::TRUSTED_ENVIRONMENT,
4131 ),
4132 KeyParameter::new(
4133 KeyParameterValue::Nonce(vec![4u8, 3u8, 1u8, 2u8]),
4134 SecurityLevel::TRUSTED_ENVIRONMENT,
4135 ),
4136 KeyParameter::new(
4137 KeyParameterValue::MacLength(256),
4138 SecurityLevel::TRUSTED_ENVIRONMENT,
4139 ),
4140 KeyParameter::new(
4141 KeyParameterValue::ResetSinceIdRotation,
4142 SecurityLevel::TRUSTED_ENVIRONMENT,
4143 ),
4144 KeyParameter::new(
4145 KeyParameterValue::ConfirmationToken(vec![5u8, 5u8, 5u8, 5u8]),
4146 SecurityLevel::TRUSTED_ENVIRONMENT,
4147 ),
Qi Wub9433b52020-12-01 14:52:46 +08004148 ];
4149 if let Some(value) = max_usage_count {
4150 params.push(KeyParameter::new(
4151 KeyParameterValue::UsageCountLimit(value),
4152 SecurityLevel::SOFTWARE,
4153 ));
4154 }
4155 params
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07004156 }
4157
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004158 fn make_test_key_entry(
4159 db: &mut KeystoreDB,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07004160 domain: Domain,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004161 namespace: i64,
4162 alias: &str,
Qi Wub9433b52020-12-01 14:52:46 +08004163 max_usage_count: Option<i32>,
Janis Danisevskisaec14592020-11-12 09:41:49 -08004164 ) -> Result<KeyIdGuard> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08004165 let key_id = db.create_key_entry(&domain, &namespace, &KEYSTORE_UUID)?;
Janis Danisevskis377d1002021-01-27 19:07:48 -08004166 db.set_blob(&key_id, SubComponentType::KEY_BLOB, Some(TEST_KEY_BLOB))?;
4167 db.set_blob(&key_id, SubComponentType::CERT, Some(TEST_CERT_BLOB))?;
4168 db.set_blob(&key_id, SubComponentType::CERT_CHAIN, Some(TEST_CERT_CHAIN_BLOB))?;
Qi Wub9433b52020-12-01 14:52:46 +08004169
4170 let params = make_test_params(max_usage_count);
4171 db.insert_keyparameter(&key_id, &params)?;
4172
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004173 let mut metadata = KeyMetaData::new();
4174 metadata.add(KeyMetaEntry::EncryptedBy(EncryptedBy::Password));
4175 metadata.add(KeyMetaEntry::Salt(vec![1, 2, 3]));
4176 metadata.add(KeyMetaEntry::Iv(vec![2, 3, 1]));
4177 metadata.add(KeyMetaEntry::AeadTag(vec![3, 1, 2]));
4178 db.insert_key_metadata(&key_id, &metadata)?;
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08004179 rebind_alias(db, &key_id, alias, domain, namespace)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004180 Ok(key_id)
4181 }
4182
Qi Wub9433b52020-12-01 14:52:46 +08004183 fn make_test_key_entry_test_vector(key_id: i64, max_usage_count: Option<i32>) -> KeyEntry {
4184 let params = make_test_params(max_usage_count);
4185
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004186 let mut metadata = KeyMetaData::new();
4187 metadata.add(KeyMetaEntry::EncryptedBy(EncryptedBy::Password));
4188 metadata.add(KeyMetaEntry::Salt(vec![1, 2, 3]));
4189 metadata.add(KeyMetaEntry::Iv(vec![2, 3, 1]));
4190 metadata.add(KeyMetaEntry::AeadTag(vec![3, 1, 2]));
4191
4192 KeyEntry {
4193 id: key_id,
4194 km_blob: Some(TEST_KEY_BLOB.to_vec()),
4195 cert: Some(TEST_CERT_BLOB.to_vec()),
4196 cert_chain: Some(TEST_CERT_CHAIN_BLOB.to_vec()),
Max Bires8e93d2b2021-01-14 13:17:59 -08004197 km_uuid: KEYSTORE_UUID,
Qi Wub9433b52020-12-01 14:52:46 +08004198 parameters: params,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004199 metadata,
Janis Danisevskis377d1002021-01-27 19:07:48 -08004200 pure_cert: false,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004201 }
4202 }
4203
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004204 fn debug_dump_keyentry_table(db: &mut KeystoreDB) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004205 let mut stmt = db.conn.prepare(
Max Bires8e93d2b2021-01-14 13:17:59 -08004206 "SELECT id, key_type, domain, namespace, alias, state, km_uuid FROM persistent.keyentry;",
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004207 )?;
Max Bires8e93d2b2021-01-14 13:17:59 -08004208 let rows = stmt.query_map::<(i64, KeyType, i32, i64, String, KeyLifeCycle, Uuid), _, _>(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004209 NO_PARAMS,
4210 |row| {
Max Bires8e93d2b2021-01-14 13:17:59 -08004211 Ok((
4212 row.get(0)?,
4213 row.get(1)?,
4214 row.get(2)?,
4215 row.get(3)?,
4216 row.get(4)?,
4217 row.get(5)?,
4218 row.get(6)?,
4219 ))
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004220 },
4221 )?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004222
4223 println!("Key entry table rows:");
4224 for r in rows {
Max Bires8e93d2b2021-01-14 13:17:59 -08004225 let (id, key_type, domain, namespace, alias, state, km_uuid) = r.unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004226 println!(
Max Bires8e93d2b2021-01-14 13:17:59 -08004227 " id: {} KeyType: {:?} Domain: {} Namespace: {} Alias: {} State: {:?} KmUuid: {:?}",
4228 id, key_type, domain, namespace, alias, state, km_uuid
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004229 );
4230 }
4231 Ok(())
4232 }
4233
4234 fn debug_dump_grant_table(db: &mut KeystoreDB) -> Result<()> {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08004235 let mut stmt = db
4236 .conn
4237 .prepare("SELECT id, grantee, keyentryid, access_vector FROM persistent.grant;")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004238 let rows = stmt.query_map::<(i64, i64, i64, i64), _, _>(NO_PARAMS, |row| {
4239 Ok((row.get(0)?, row.get(1)?, row.get(2)?, row.get(3)?))
4240 })?;
4241
4242 println!("Grant table rows:");
4243 for r in rows {
4244 let (id, gt, ki, av) = r.unwrap();
4245 println!(" id: {} grantee: {} key_id: {} access_vector: {}", id, gt, ki, av);
4246 }
4247 Ok(())
4248 }
4249
Joel Galenson0891bc12020-07-20 10:37:03 -07004250 // Use a custom random number generator that repeats each number once.
4251 // This allows us to test repeated elements.
4252
4253 thread_local! {
4254 static RANDOM_COUNTER: RefCell<i64> = RefCell::new(0);
4255 }
4256
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004257 fn reset_random() {
4258 RANDOM_COUNTER.with(|counter| {
4259 *counter.borrow_mut() = 0;
4260 })
4261 }
4262
Joel Galenson0891bc12020-07-20 10:37:03 -07004263 pub fn random() -> i64 {
4264 RANDOM_COUNTER.with(|counter| {
4265 let result = *counter.borrow() / 2;
4266 *counter.borrow_mut() += 1;
4267 result
4268 })
4269 }
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00004270
4271 #[test]
4272 fn test_last_off_body() -> Result<()> {
4273 let mut db = new_test_db()?;
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08004274 db.insert_last_off_body(MonotonicRawTime::now())?;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00004275 let tx = db.conn.transaction_with_behavior(TransactionBehavior::Immediate)?;
4276 let last_off_body_1 = KeystoreDB::get_last_off_body(&tx)?;
4277 tx.commit()?;
4278 let one_second = Duration::from_secs(1);
4279 thread::sleep(one_second);
4280 db.update_last_off_body(MonotonicRawTime::now())?;
4281 let tx2 = db.conn.transaction_with_behavior(TransactionBehavior::Immediate)?;
4282 let last_off_body_2 = KeystoreDB::get_last_off_body(&tx2)?;
4283 tx2.commit()?;
4284 assert!(last_off_body_1.seconds() < last_off_body_2.seconds());
4285 Ok(())
4286 }
Joel Galenson26f4d012020-07-17 14:57:21 -07004287}