blob: 97624b2d35f8e30a2f41c8f0971923c20dc9782d [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.
409#[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
410pub 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
Joel Galenson26f4d012020-07-17 14:57:21 -0700695impl KeystoreDB {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700696 /// This will create a new database connection connecting the two
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800697 /// files persistent.sqlite and perboot.sqlite in the given directory.
698 /// It also attempts to initialize all of the tables.
699 /// KeystoreDB cannot be used by multiple threads.
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700700 /// Each thread should open their own connection using `thread_local!`.
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800701 pub fn new(db_root: &Path) -> Result<Self> {
702 // Build the path to the sqlite files.
703 let mut persistent_path = db_root.to_path_buf();
704 persistent_path.push("persistent.sqlite");
705 let mut perboot_path = db_root.to_path_buf();
706 perboot_path.push("perboot.sqlite");
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700707
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800708 // Now convert them to strings prefixed with "file:"
709 let mut persistent_path_str = "file:".to_owned();
710 persistent_path_str.push_str(&persistent_path.to_string_lossy());
711 let mut perboot_path_str = "file:".to_owned();
712 perboot_path_str.push_str(&perboot_path.to_string_lossy());
713
714 let conn = Self::make_connection(&persistent_path_str, &perboot_path_str)?;
Janis Danisevskisaea27342021-01-29 08:38:11 -0800715 conn.busy_handler(Some(|_| {
716 std::thread::sleep(std::time::Duration::from_micros(50));
717 true
718 }))
719 .context("In KeystoreDB::new: Failed to set busy handler.")?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800720
721 Self::init_tables(&conn)?;
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700722 Ok(Self { conn })
Joel Galenson2aab4432020-07-22 15:27:57 -0700723 }
724
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700725 fn init_tables(conn: &Connection) -> Result<()> {
726 conn.execute(
727 "CREATE TABLE IF NOT EXISTS persistent.keyentry (
Joel Galenson0891bc12020-07-20 10:37:03 -0700728 id INTEGER UNIQUE,
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800729 key_type INTEGER,
Joel Galenson0891bc12020-07-20 10:37:03 -0700730 domain INTEGER,
731 namespace INTEGER,
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800732 alias BLOB,
Max Bires8e93d2b2021-01-14 13:17:59 -0800733 state INTEGER,
734 km_uuid BLOB);",
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700735 NO_PARAMS,
736 )
737 .context("Failed to initialize \"keyentry\" table.")?;
738
739 conn.execute(
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700740 "CREATE TABLE IF NOT EXISTS persistent.blobentry (
741 id INTEGER PRIMARY KEY,
742 subcomponent_type INTEGER,
743 keyentryid INTEGER,
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800744 blob BLOB);",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700745 NO_PARAMS,
746 )
747 .context("Failed to initialize \"blobentry\" table.")?;
748
749 conn.execute(
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700750 "CREATE TABLE IF NOT EXISTS persistent.keyparameter (
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000751 keyentryid INTEGER,
752 tag INTEGER,
753 data ANY,
754 security_level INTEGER);",
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700755 NO_PARAMS,
756 )
757 .context("Failed to initialize \"keyparameter\" table.")?;
758
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700759 conn.execute(
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800760 "CREATE TABLE IF NOT EXISTS persistent.keymetadata (
761 keyentryid INTEGER,
762 tag INTEGER,
763 data ANY);",
764 NO_PARAMS,
765 )
766 .context("Failed to initialize \"keymetadata\" table.")?;
767
768 conn.execute(
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800769 "CREATE TABLE IF NOT EXISTS persistent.grant (
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700770 id INTEGER UNIQUE,
771 grantee INTEGER,
772 keyentryid INTEGER,
773 access_vector INTEGER);",
774 NO_PARAMS,
775 )
776 .context("Failed to initialize \"grant\" table.")?;
777
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000778 //TODO: only drop the following two perboot tables if this is the first start up
779 //during the boot (b/175716626).
780 // conn.execute("DROP TABLE IF EXISTS perboot.authtoken;", NO_PARAMS)
781 // .context("Failed to drop perboot.authtoken table")?;
782 conn.execute(
783 "CREATE TABLE IF NOT EXISTS perboot.authtoken (
784 id INTEGER PRIMARY KEY,
785 challenge INTEGER,
786 user_id INTEGER,
787 auth_id INTEGER,
788 authenticator_type INTEGER,
789 timestamp INTEGER,
790 mac BLOB,
791 time_received INTEGER,
792 UNIQUE(user_id, auth_id, authenticator_type));",
793 NO_PARAMS,
794 )
795 .context("Failed to initialize \"authtoken\" table.")?;
796
797 // conn.execute("DROP TABLE IF EXISTS perboot.metadata;", NO_PARAMS)
798 // .context("Failed to drop perboot.metadata table")?;
799 // metadata table stores certain miscellaneous information required for keystore functioning
800 // during a boot cycle, as key-value pairs.
801 conn.execute(
802 "CREATE TABLE IF NOT EXISTS perboot.metadata (
803 key TEXT,
804 value BLOB,
805 UNIQUE(key));",
806 NO_PARAMS,
807 )
808 .context("Failed to initialize \"metadata\" table.")?;
Joel Galenson0891bc12020-07-20 10:37:03 -0700809 Ok(())
810 }
811
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700812 fn make_connection(persistent_file: &str, perboot_file: &str) -> Result<Connection> {
813 let conn =
814 Connection::open_in_memory().context("Failed to initialize SQLite connection.")?;
815
816 conn.execute("ATTACH DATABASE ? as persistent;", params![persistent_file])
817 .context("Failed to attach database persistent.")?;
818 conn.execute("ATTACH DATABASE ? as perboot;", params![perboot_file])
819 .context("Failed to attach database perboot.")?;
820
821 Ok(conn)
822 }
823
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800824 /// Get one unreferenced key. There is no particular order in which the keys are returned.
825 fn get_unreferenced_key_id(tx: &Transaction) -> Result<Option<i64>> {
826 tx.query_row(
827 "SELECT id FROM persistent.keyentry WHERE state = ?",
828 params![KeyLifeCycle::Unreferenced],
829 |row| row.get(0),
830 )
831 .optional()
832 .context("In get_unreferenced_key_id: Trying to get unreferenced key id.")
833 }
834
835 /// Returns a key id guard and key entry for one unreferenced key entry. Of the optional
836 /// fields of the key entry only the km_blob field will be populated. This is required
837 /// to subject the blob to its KeyMint instance for deletion.
838 pub fn get_unreferenced_key(&mut self) -> Result<Option<(KeyIdGuard, KeyEntry)>> {
839 self.with_transaction(TransactionBehavior::Deferred, |tx| {
840 let key_id = match Self::get_unreferenced_key_id(tx)
841 .context("Trying to get unreferenced key id")?
842 {
843 None => return Ok(None),
844 Some(id) => KEY_ID_LOCK.try_get(id).ok_or_else(KsError::sys).context(concat!(
845 "A key id lock was held for an unreferenced key. ",
846 "This should never happen."
847 ))?,
848 };
849 let key_entry = Self::load_key_components(tx, KeyEntryLoadBits::KM, key_id.id())
850 .context("Trying to get key components.")?;
851 Ok(Some((key_id, key_entry)))
852 })
853 .context("In get_unreferenced_key.")
854 }
855
856 /// This function purges all remnants of a key entry from the database.
857 /// Important: This does not check if the key was unreferenced, nor does it
858 /// subject the key to its KeyMint instance for permanent invalidation.
859 /// This function should only be called by the garbage collector.
860 /// To delete a key call `mark_unreferenced`, which transitions the key to the unreferenced
861 /// state, deletes all grants to the key, and notifies the garbage collector.
862 /// The garbage collector will:
863 /// 1. Call get_unreferenced_key.
864 /// 2. Determine the proper way to dispose of sensitive key material, e.g., call
865 /// `KeyMintDevice::delete()`.
866 /// 3. Call `purge_key_entry`.
867 pub fn purge_key_entry(&mut self, key_id: KeyIdGuard) -> Result<()> {
868 self.with_transaction(TransactionBehavior::Immediate, |tx| {
869 tx.execute("DELETE FROM persistent.keyentry WHERE id = ?;", params![key_id.id()])
870 .context("Trying to delete keyentry.")?;
871 tx.execute(
872 "DELETE FROM persistent.blobentry WHERE keyentryid = ?;",
873 params![key_id.id()],
874 )
875 .context("Trying to delete blobentries.")?;
876 tx.execute(
877 "DELETE FROM persistent.keymetadata WHERE keyentryid = ?;",
878 params![key_id.id()],
879 )
880 .context("Trying to delete keymetadata.")?;
881 tx.execute(
882 "DELETE FROM persistent.keyparameter WHERE keyentryid = ?;",
883 params![key_id.id()],
884 )
885 .context("Trying to delete keyparameters.")?;
886 let grants_deleted = tx
887 .execute("DELETE FROM persistent.grant WHERE keyentryid = ?;", params![key_id.id()])
888 .context("Trying to delete grants.")?;
889 if grants_deleted != 0 {
890 log::error!("Purged key that still had grants. This should not happen.");
891 }
892 Ok(())
893 })
894 .context("In purge_key_entry.")
895 }
896
897 /// This maintenance function should be called only once before the database is used for the
898 /// first time. It restores the invariant that `KeyLifeCycle::Existing` is a transient state.
899 /// The function transitions all key entries from Existing to Unreferenced unconditionally and
900 /// returns the number of rows affected. If this returns a value greater than 0, it means that
901 /// Keystore crashed at some point during key generation. Callers may want to log such
902 /// occurrences.
903 /// Unlike with `mark_unreferenced`, we don't need to purge grants, because only keys that made
904 /// it to `KeyLifeCycle::Live` may have grants.
905 pub fn cleanup_leftovers(&mut self) -> Result<usize> {
906 self.conn
907 .execute(
908 "UPDATE persistent.keyentry SET state = ? WHERE state = ?;",
909 params![KeyLifeCycle::Unreferenced, KeyLifeCycle::Existing],
910 )
911 .context("In cleanup_leftovers.")
912 }
913
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800914 /// Atomically loads a key entry and associated metadata or creates it using the
915 /// callback create_new_key callback. The callback is called during a database
916 /// transaction. This means that implementers should be mindful about using
917 /// blocking operations such as IPC or grabbing mutexes.
918 pub fn get_or_create_key_with<F>(
919 &mut self,
920 domain: Domain,
921 namespace: i64,
922 alias: &str,
Max Bires8e93d2b2021-01-14 13:17:59 -0800923 km_uuid: Uuid,
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800924 create_new_key: F,
925 ) -> Result<(KeyIdGuard, KeyEntry)>
926 where
927 F: FnOnce() -> Result<(Vec<u8>, KeyMetaData)>,
928 {
929 let tx = self
930 .conn
931 .transaction_with_behavior(TransactionBehavior::Immediate)
932 .context("In get_or_create_key_with: Failed to initialize transaction.")?;
933
934 let id = {
935 let mut stmt = tx
936 .prepare(
937 "SELECT id FROM persistent.keyentry
938 WHERE
939 key_type = ?
940 AND domain = ?
941 AND namespace = ?
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800942 AND alias = ?
943 AND state = ?;",
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800944 )
945 .context("In get_or_create_key_with: Failed to select from keyentry table.")?;
946 let mut rows = stmt
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800947 .query(params![KeyType::Super, domain.0, namespace, alias, KeyLifeCycle::Live])
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800948 .context("In get_or_create_key_with: Failed to query from keyentry table.")?;
949
950 db_utils::with_rows_extract_one(&mut rows, |row| {
951 Ok(match row {
952 Some(r) => r.get(0).context("Failed to unpack id.")?,
953 None => None,
954 })
955 })
956 .context("In get_or_create_key_with.")?
957 };
958
959 let (id, entry) = match id {
960 Some(id) => (
961 id,
962 Self::load_key_components(&tx, KeyEntryLoadBits::KM, id)
963 .context("In get_or_create_key_with.")?,
964 ),
965
966 None => {
967 let id = Self::insert_with_retry(|id| {
968 tx.execute(
969 "INSERT into persistent.keyentry
Max Bires8e93d2b2021-01-14 13:17:59 -0800970 (id, key_type, domain, namespace, alias, state, km_uuid)
971 VALUES(?, ?, ?, ?, ?, ?, ?);",
972 params![
973 id,
974 KeyType::Super,
975 domain.0,
976 namespace,
977 alias,
978 KeyLifeCycle::Live,
979 km_uuid,
980 ],
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800981 )
982 })
983 .context("In get_or_create_key_with.")?;
984
985 let (blob, metadata) = create_new_key().context("In get_or_create_key_with.")?;
Janis Danisevskis377d1002021-01-27 19:07:48 -0800986 Self::set_blob_internal(&tx, id, SubComponentType::KEY_BLOB, Some(&blob))
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800987 .context("In get_of_create_key_with.")?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800988 metadata.store_in_db(id, &tx).context("In get_or_create_key_with.")?;
Janis Danisevskis377d1002021-01-27 19:07:48 -0800989 (
990 id,
991 KeyEntry {
992 id,
993 km_blob: Some(blob),
994 metadata,
995 pure_cert: false,
996 ..Default::default()
997 },
998 )
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800999 }
1000 };
1001 tx.commit().context("In get_or_create_key_with: Failed to commit transaction.")?;
1002 Ok((KEY_ID_LOCK.get(id), entry))
1003 }
1004
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001005 /// Creates a transaction with the given behavior and executes f with the new transaction.
1006 /// The transaction is committed only if f returns Ok.
1007 fn with_transaction<T, F>(&mut self, behavior: TransactionBehavior, f: F) -> Result<T>
1008 where
1009 F: FnOnce(&Transaction) -> Result<T>,
1010 {
1011 let tx = self
1012 .conn
1013 .transaction_with_behavior(behavior)
1014 .context("In with_transaction: Failed to initialize transaction.")?;
1015 f(&tx).and_then(|result| {
1016 tx.commit().context("In with_transaction: Failed to commit transaction.")?;
1017 Ok(result)
1018 })
1019 }
1020
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001021 /// Creates a new key entry and allocates a new randomized id for the new key.
1022 /// The key id gets associated with a domain and namespace but not with an alias.
1023 /// To complete key generation `rebind_alias` should be called after all of the
1024 /// key artifacts, i.e., blobs and parameters have been associated with the new
1025 /// key id. Finalizing with `rebind_alias` makes the creation of a new key entry
1026 /// atomic even if key generation is not.
Max Bires8e93d2b2021-01-14 13:17:59 -08001027 pub fn create_key_entry(
1028 &mut self,
1029 domain: Domain,
1030 namespace: i64,
1031 km_uuid: &Uuid,
1032 ) -> Result<KeyIdGuard> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001033 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Max Bires8e93d2b2021-01-14 13:17:59 -08001034 Self::create_key_entry_internal(tx, domain, namespace, km_uuid)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001035 })
1036 .context("In create_key_entry.")
1037 }
1038
1039 fn create_key_entry_internal(
1040 tx: &Transaction,
1041 domain: Domain,
1042 namespace: i64,
Max Bires8e93d2b2021-01-14 13:17:59 -08001043 km_uuid: &Uuid,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001044 ) -> Result<KeyIdGuard> {
Joel Galenson0891bc12020-07-20 10:37:03 -07001045 match domain {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001046 Domain::APP | Domain::SELINUX => {}
Joel Galenson0891bc12020-07-20 10:37:03 -07001047 _ => {
1048 return Err(KsError::sys())
1049 .context(format!("Domain {:?} must be either App or SELinux.", domain));
1050 }
1051 }
Janis Danisevskisaec14592020-11-12 09:41:49 -08001052 Ok(KEY_ID_LOCK.get(
1053 Self::insert_with_retry(|id| {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001054 tx.execute(
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001055 "INSERT into persistent.keyentry
Max Bires8e93d2b2021-01-14 13:17:59 -08001056 (id, key_type, domain, namespace, alias, state, km_uuid)
1057 VALUES(?, ?, ?, ?, NULL, ?, ?);",
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001058 params![
1059 id,
1060 KeyType::Client,
1061 domain.0 as u32,
1062 namespace,
Max Bires8e93d2b2021-01-14 13:17:59 -08001063 KeyLifeCycle::Existing,
1064 km_uuid,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001065 ],
Janis Danisevskisaec14592020-11-12 09:41:49 -08001066 )
1067 })
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001068 .context("In create_key_entry_internal")?,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001069 ))
Joel Galenson26f4d012020-07-17 14:57:21 -07001070 }
Joel Galenson33c04ad2020-08-03 11:04:38 -07001071
Max Bires2b2e6562020-09-22 11:22:36 -07001072 /// Creates a new attestation key entry and allocates a new randomized id for the new key.
1073 /// The key id gets associated with a domain and namespace later but not with an alias. The
1074 /// alias will be used to denote if a key has been signed as each key can only be bound to one
1075 /// domain and namespace pairing so there is no need to use them as a value for indexing into
1076 /// a key.
1077 pub fn create_attestation_key_entry(
1078 &mut self,
1079 maced_public_key: &[u8],
1080 raw_public_key: &[u8],
1081 private_key: &[u8],
1082 km_uuid: &Uuid,
1083 ) -> Result<()> {
1084 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1085 let key_id = KEY_ID_LOCK.get(
1086 Self::insert_with_retry(|id| {
1087 tx.execute(
1088 "INSERT into persistent.keyentry
1089 (id, key_type, domain, namespace, alias, state, km_uuid)
1090 VALUES(?, ?, NULL, NULL, NULL, ?, ?);",
1091 params![id, KeyType::Attestation, KeyLifeCycle::Live, km_uuid],
1092 )
1093 })
1094 .context("In create_key_entry")?,
1095 );
1096 Self::set_blob_internal(&tx, key_id.0, SubComponentType::KEY_BLOB, Some(private_key))?;
1097 let mut metadata = KeyMetaData::new();
1098 metadata.add(KeyMetaEntry::AttestationMacedPublicKey(maced_public_key.to_vec()));
1099 metadata.add(KeyMetaEntry::AttestationRawPubKey(raw_public_key.to_vec()));
1100 metadata.store_in_db(key_id.0, &tx)?;
1101 Ok(())
1102 })
1103 .context("In create_attestation_key_entry")
1104 }
1105
Janis Danisevskis377d1002021-01-27 19:07:48 -08001106 /// Set a new blob and associates it with the given key id. Each blob
1107 /// has a sub component type.
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001108 /// Each key can have one of each sub component type associated. If more
1109 /// are added only the most recent can be retrieved, and superseded blobs
Janis Danisevskis377d1002021-01-27 19:07:48 -08001110 /// will get garbage collected.
1111 /// Components SubComponentType::CERT and SubComponentType::CERT_CHAIN can be
1112 /// removed by setting blob to None.
1113 pub fn set_blob(
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001114 &mut self,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001115 key_id: &KeyIdGuard,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001116 sc_type: SubComponentType,
Janis Danisevskis377d1002021-01-27 19:07:48 -08001117 blob: Option<&[u8]>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001118 ) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001119 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis377d1002021-01-27 19:07:48 -08001120 Self::set_blob_internal(&tx, key_id.0, sc_type, blob)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001121 })
Janis Danisevskis377d1002021-01-27 19:07:48 -08001122 .context("In set_blob.")
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001123 }
1124
Janis Danisevskis377d1002021-01-27 19:07:48 -08001125 fn set_blob_internal(
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001126 tx: &Transaction,
1127 key_id: i64,
1128 sc_type: SubComponentType,
Janis Danisevskis377d1002021-01-27 19:07:48 -08001129 blob: Option<&[u8]>,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001130 ) -> Result<()> {
Janis Danisevskis377d1002021-01-27 19:07:48 -08001131 match (blob, sc_type) {
1132 (Some(blob), _) => {
1133 tx.execute(
1134 "INSERT INTO persistent.blobentry
1135 (subcomponent_type, keyentryid, blob) VALUES (?, ?, ?);",
1136 params![sc_type, key_id, blob],
1137 )
1138 .context("In set_blob_internal: Failed to insert blob.")?;
1139 }
1140 (None, SubComponentType::CERT) | (None, SubComponentType::CERT_CHAIN) => {
1141 tx.execute(
1142 "DELETE FROM persistent.blobentry
1143 WHERE subcomponent_type = ? AND keyentryid = ?;",
1144 params![sc_type, key_id],
1145 )
1146 .context("In set_blob_internal: Failed to delete blob.")?;
1147 }
1148 (None, _) => {
1149 return Err(KsError::sys())
1150 .context("In set_blob_internal: Other blobs cannot be deleted in this way.");
1151 }
1152 }
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001153 Ok(())
1154 }
1155
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001156 /// Inserts a collection of key parameters into the `persistent.keyparameter` table
1157 /// and associates them with the given `key_id`.
1158 pub fn insert_keyparameter<'a>(
1159 &mut self,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001160 key_id: &KeyIdGuard,
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001161 params: impl IntoIterator<Item = &'a KeyParameter>,
1162 ) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001163 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1164 Self::insert_keyparameter_internal(tx, key_id, params)
1165 })
1166 .context("In insert_keyparameter.")
1167 }
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001168
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001169 fn insert_keyparameter_internal<'a>(
1170 tx: &Transaction,
1171 key_id: &KeyIdGuard,
1172 params: impl IntoIterator<Item = &'a KeyParameter>,
1173 ) -> Result<()> {
1174 let mut stmt = tx
1175 .prepare(
1176 "INSERT into persistent.keyparameter (keyentryid, tag, data, security_level)
1177 VALUES (?, ?, ?, ?);",
1178 )
1179 .context("In insert_keyparameter_internal: Failed to prepare statement.")?;
1180
1181 let iter = params.into_iter();
1182 for p in iter {
1183 stmt.insert(params![
1184 key_id.0,
1185 p.get_tag().0,
1186 p.key_parameter_value(),
1187 p.security_level().0
1188 ])
1189 .with_context(|| {
1190 format!("In insert_keyparameter_internal: Failed to insert {:?}", p)
1191 })?;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001192 }
1193 Ok(())
1194 }
1195
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001196 /// Insert a set of key entry specific metadata into the database.
1197 pub fn insert_key_metadata(
1198 &mut self,
1199 key_id: &KeyIdGuard,
1200 metadata: &KeyMetaData,
1201 ) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001202 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1203 metadata.store_in_db(key_id.0, &tx)
1204 })
1205 .context("In insert_key_metadata.")
1206 }
1207
Max Bires2b2e6562020-09-22 11:22:36 -07001208 /// Stores a signed certificate chain signed by a remote provisioning server, keyed
1209 /// on the public key.
1210 pub fn store_signed_attestation_certificate_chain(
1211 &mut self,
1212 raw_public_key: &[u8],
1213 cert_chain: &[u8],
1214 expiration_date: i64,
1215 km_uuid: &Uuid,
1216 ) -> Result<()> {
1217 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1218 let mut stmt = tx
1219 .prepare(
1220 "SELECT keyentryid
1221 FROM persistent.keymetadata
1222 WHERE tag = ? AND data = ? AND keyentryid IN
1223 (SELECT id
1224 FROM persistent.keyentry
1225 WHERE
1226 alias IS NULL AND
1227 domain IS NULL AND
1228 namespace IS NULL AND
1229 key_type = ? AND
1230 km_uuid = ?);",
1231 )
1232 .context("Failed to store attestation certificate chain.")?;
1233 let mut rows = stmt
1234 .query(params![
1235 KeyMetaData::AttestationRawPubKey,
1236 raw_public_key,
1237 KeyType::Attestation,
1238 km_uuid
1239 ])
1240 .context("Failed to fetch keyid")?;
1241 let key_id = db_utils::with_rows_extract_one(&mut rows, |row| {
1242 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?
1243 .get(0)
1244 .context("Failed to unpack id.")
1245 })
1246 .context("Failed to get key_id.")?;
1247 let num_updated = tx
1248 .execute(
1249 "UPDATE persistent.keyentry
1250 SET alias = ?
1251 WHERE id = ?;",
1252 params!["signed", key_id],
1253 )
1254 .context("Failed to update alias.")?;
1255 if num_updated != 1 {
1256 return Err(KsError::sys()).context("Alias not updated for the key.");
1257 }
1258 let mut metadata = KeyMetaData::new();
1259 metadata.add(KeyMetaEntry::AttestationExpirationDate(DateTime::from_millis_epoch(
1260 expiration_date,
1261 )));
1262 metadata.store_in_db(key_id, &tx).context("Failed to insert key metadata.")?;
1263 Self::set_blob_internal(&tx, key_id, SubComponentType::CERT_CHAIN, Some(cert_chain))
1264 .context("Failed to insert cert chain")?;
1265 Ok(())
1266 })
1267 .context("In store_signed_attestation_certificate_chain: ")
1268 }
1269
1270 /// Assigns the next unassigned attestation key to a domain/namespace combo that does not
1271 /// currently have a key assigned to it.
1272 pub fn assign_attestation_key(
1273 &mut self,
1274 domain: Domain,
1275 namespace: i64,
1276 km_uuid: &Uuid,
1277 ) -> Result<()> {
1278 match domain {
1279 Domain::APP | Domain::SELINUX => {}
1280 _ => {
1281 return Err(KsError::sys()).context(format!(
1282 concat!(
1283 "In assign_attestation_key: Domain {:?} ",
1284 "must be either App or SELinux.",
1285 ),
1286 domain
1287 ));
1288 }
1289 }
1290 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1291 let result = tx
1292 .execute(
1293 "UPDATE persistent.keyentry
1294 SET domain=?1, namespace=?2
1295 WHERE
1296 id =
1297 (SELECT MIN(id)
1298 FROM persistent.keyentry
1299 WHERE ALIAS IS NOT NULL
1300 AND domain IS NULL
1301 AND key_type IS ?3
1302 AND state IS ?4
1303 AND km_uuid IS ?5)
1304 AND
1305 (SELECT COUNT(*)
1306 FROM persistent.keyentry
1307 WHERE domain=?1
1308 AND namespace=?2
1309 AND key_type IS ?3
1310 AND state IS ?4
1311 AND km_uuid IS ?5) = 0;",
1312 params![
1313 domain.0 as u32,
1314 namespace,
1315 KeyType::Attestation,
1316 KeyLifeCycle::Live,
1317 km_uuid,
1318 ],
1319 )
1320 .context("Failed to assign attestation key")?;
1321 if result != 1 {
1322 return Err(KsError::sys()).context(format!(
1323 "Expected to update a single entry but instead updated {}.",
1324 result
1325 ));
1326 }
1327 Ok(())
1328 })
1329 .context("In assign_attestation_key: ")
1330 }
1331
1332 /// Retrieves num_keys number of attestation keys that have not yet been signed by a remote
1333 /// provisioning server, or the maximum number available if there are not num_keys number of
1334 /// entries in the table.
1335 pub fn fetch_unsigned_attestation_keys(
1336 &mut self,
1337 num_keys: i32,
1338 km_uuid: &Uuid,
1339 ) -> Result<Vec<Vec<u8>>> {
1340 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1341 let mut stmt = tx
1342 .prepare(
1343 "SELECT data
1344 FROM persistent.keymetadata
1345 WHERE tag = ? AND keyentryid IN
1346 (SELECT id
1347 FROM persistent.keyentry
1348 WHERE
1349 alias IS NULL AND
1350 domain IS NULL AND
1351 namespace IS NULL AND
1352 key_type = ? AND
1353 km_uuid = ?
1354 LIMIT ?);",
1355 )
1356 .context("Failed to prepare statement")?;
1357 let rows = stmt
1358 .query_map(
1359 params![
1360 KeyMetaData::AttestationMacedPublicKey,
1361 KeyType::Attestation,
1362 km_uuid,
1363 num_keys
1364 ],
1365 |row| Ok(row.get(0)?),
1366 )?
1367 .collect::<rusqlite::Result<Vec<Vec<u8>>>>()
1368 .context("Failed to execute statement")?;
1369 Ok(rows)
1370 })
1371 .context("In fetch_unsigned_attestation_keys")
1372 }
1373
1374 /// Removes any keys that have expired as of the current time. Returns the number of keys
1375 /// marked unreferenced that are bound to be garbage collected.
1376 pub fn delete_expired_attestation_keys(&mut self) -> Result<i32> {
1377 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1378 let mut stmt = tx
1379 .prepare(
1380 "SELECT keyentryid, data
1381 FROM persistent.keymetadata
1382 WHERE tag = ? AND keyentryid IN
1383 (SELECT id
1384 FROM persistent.keyentry
1385 WHERE key_type = ?);",
1386 )
1387 .context("Failed to prepare query")?;
1388 let key_ids_to_check = stmt
1389 .query_map(
1390 params![KeyMetaData::AttestationExpirationDate, KeyType::Attestation],
1391 |row| Ok((row.get(0)?, row.get(1)?)),
1392 )?
1393 .collect::<rusqlite::Result<Vec<(i64, DateTime)>>>()
1394 .context("Failed to get date metadata")?;
1395 let curr_time = DateTime::from_millis_epoch(
1396 SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_millis() as i64,
1397 );
1398 let mut num_deleted = 0;
1399 for id in key_ids_to_check.iter().filter(|kt| kt.1 < curr_time).map(|kt| kt.0) {
1400 if Self::mark_unreferenced(&tx, id)? {
1401 num_deleted += 1;
1402 }
1403 }
1404 Ok(num_deleted)
1405 })
1406 .context("In delete_expired_attestation_keys: ")
1407 }
1408
1409 /// Counts the number of keys that will expire by the provided epoch date and the number of
1410 /// keys not currently assigned to a domain.
1411 pub fn get_attestation_pool_status(
1412 &mut self,
1413 date: i64,
1414 km_uuid: &Uuid,
1415 ) -> Result<AttestationPoolStatus> {
1416 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1417 let mut stmt = tx.prepare(
1418 "SELECT data
1419 FROM persistent.keymetadata
1420 WHERE tag = ? AND keyentryid IN
1421 (SELECT id
1422 FROM persistent.keyentry
1423 WHERE alias IS NOT NULL
1424 AND key_type = ?
1425 AND km_uuid = ?
1426 AND state = ?);",
1427 )?;
1428 let times = stmt
1429 .query_map(
1430 params![
1431 KeyMetaData::AttestationExpirationDate,
1432 KeyType::Attestation,
1433 km_uuid,
1434 KeyLifeCycle::Live
1435 ],
1436 |row| Ok(row.get(0)?),
1437 )?
1438 .collect::<rusqlite::Result<Vec<DateTime>>>()
1439 .context("Failed to execute metadata statement")?;
1440 let expiring =
1441 times.iter().filter(|time| time < &&DateTime::from_millis_epoch(date)).count()
1442 as i32;
1443 stmt = tx.prepare(
1444 "SELECT alias, domain
1445 FROM persistent.keyentry
1446 WHERE key_type = ? AND km_uuid = ? AND state = ?;",
1447 )?;
1448 let rows = stmt
1449 .query_map(params![KeyType::Attestation, km_uuid, KeyLifeCycle::Live], |row| {
1450 Ok((row.get(0)?, row.get(1)?))
1451 })?
1452 .collect::<rusqlite::Result<Vec<(Option<String>, Option<u32>)>>>()
1453 .context("Failed to execute keyentry statement")?;
1454 let mut unassigned = 0i32;
1455 let mut attested = 0i32;
1456 let total = rows.len() as i32;
1457 for (alias, domain) in rows {
1458 match (alias, domain) {
1459 (Some(_alias), None) => {
1460 attested += 1;
1461 unassigned += 1;
1462 }
1463 (Some(_alias), Some(_domain)) => {
1464 attested += 1;
1465 }
1466 _ => {}
1467 }
1468 }
1469 Ok(AttestationPoolStatus { expiring, unassigned, attested, total })
1470 })
1471 .context("In get_attestation_pool_status: ")
1472 }
1473
1474 /// Fetches the private key and corresponding certificate chain assigned to a
1475 /// domain/namespace pair. Will either return nothing if the domain/namespace is
1476 /// not assigned, or one CertificateChain.
1477 pub fn retrieve_attestation_key_and_cert_chain(
1478 &mut self,
1479 domain: Domain,
1480 namespace: i64,
1481 km_uuid: &Uuid,
1482 ) -> Result<Option<CertificateChain>> {
1483 match domain {
1484 Domain::APP | Domain::SELINUX => {}
1485 _ => {
1486 return Err(KsError::sys())
1487 .context(format!("Domain {:?} must be either App or SELinux.", domain));
1488 }
1489 }
1490 let mut stmt = self.conn.prepare(
1491 "SELECT subcomponent_type, blob
1492 FROM persistent.blobentry
1493 WHERE keyentryid IN
1494 (SELECT id
1495 FROM persistent.keyentry
1496 WHERE key_type = ?
1497 AND domain = ?
1498 AND namespace = ?
1499 AND state = ?
1500 AND km_uuid = ?);",
1501 )?;
1502 let rows = stmt
1503 .query_map(
1504 params![
1505 KeyType::Attestation,
1506 domain.0 as u32,
1507 namespace,
1508 KeyLifeCycle::Live,
1509 km_uuid
1510 ],
1511 |row| Ok((row.get(0)?, row.get(1)?)),
1512 )?
1513 .collect::<rusqlite::Result<Vec<(SubComponentType, Vec<u8>)>>>()
1514 .context("In retrieve_attestation_key_and_cert_chain: query failed.")?;
1515 if rows.is_empty() {
1516 return Ok(None);
1517 } else if rows.len() != 2 {
1518 return Err(KsError::sys()).context(format!(
1519 concat!(
1520 "In retrieve_attestation_key_and_cert_chain: Expected to get a single attestation",
1521 "key chain but instead got {}."),
1522 rows.len()
1523 ));
1524 }
1525 let mut km_blob: Vec<u8> = Vec::new();
1526 let mut cert_chain_blob: Vec<u8> = Vec::new();
1527 for row in rows {
1528 let sub_type: SubComponentType = row.0;
1529 match sub_type {
1530 SubComponentType::KEY_BLOB => {
1531 km_blob = row.1;
1532 }
1533 SubComponentType::CERT_CHAIN => {
1534 cert_chain_blob = row.1;
1535 }
1536 _ => Err(KsError::sys()).context("Unknown or incorrect subcomponent type.")?,
1537 }
1538 }
1539 Ok(Some(CertificateChain {
1540 private_key: ZVec::try_from(km_blob)?,
1541 cert_chain: ZVec::try_from(cert_chain_blob)?,
1542 }))
1543 }
1544
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001545 /// Updates the alias column of the given key id `newid` with the given alias,
1546 /// and atomically, removes the alias, domain, and namespace from another row
1547 /// with the same alias-domain-namespace tuple if such row exits.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001548 /// Returns Ok(true) if an old key was marked unreferenced as a hint to the garbage
1549 /// collector.
1550 fn rebind_alias(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001551 tx: &Transaction,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001552 newid: &KeyIdGuard,
Joel Galenson33c04ad2020-08-03 11:04:38 -07001553 alias: &str,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001554 domain: Domain,
Joel Galenson33c04ad2020-08-03 11:04:38 -07001555 namespace: i64,
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001556 ) -> Result<bool> {
Joel Galenson33c04ad2020-08-03 11:04:38 -07001557 match domain {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001558 Domain::APP | Domain::SELINUX => {}
Joel Galenson33c04ad2020-08-03 11:04:38 -07001559 _ => {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001560 return Err(KsError::sys()).context(format!(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001561 "In rebind_alias: Domain {:?} must be either App or SELinux.",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001562 domain
1563 ));
Joel Galenson33c04ad2020-08-03 11:04:38 -07001564 }
1565 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001566 let updated = tx
1567 .execute(
1568 "UPDATE persistent.keyentry
1569 SET alias = NULL, domain = NULL, namespace = NULL, state = ?
Joel Galenson33c04ad2020-08-03 11:04:38 -07001570 WHERE alias = ? AND domain = ? AND namespace = ?;",
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001571 params![KeyLifeCycle::Unreferenced, alias, domain.0 as u32, namespace],
1572 )
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001573 .context("In rebind_alias: Failed to rebind existing entry.")?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07001574 let result = tx
1575 .execute(
1576 "UPDATE persistent.keyentry
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001577 SET alias = ?, state = ?
1578 WHERE id = ? AND domain = ? AND namespace = ? AND state = ?;",
1579 params![
1580 alias,
1581 KeyLifeCycle::Live,
1582 newid.0,
1583 domain.0 as u32,
1584 namespace,
Max Bires8e93d2b2021-01-14 13:17:59 -08001585 KeyLifeCycle::Existing,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001586 ],
Joel Galenson33c04ad2020-08-03 11:04:38 -07001587 )
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001588 .context("In rebind_alias: Failed to set alias.")?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07001589 if result != 1 {
Joel Galenson33c04ad2020-08-03 11:04:38 -07001590 return Err(KsError::sys()).context(format!(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001591 "In rebind_alias: Expected to update a single entry but instead updated {}.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07001592 result
1593 ));
1594 }
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001595 Ok(updated != 0)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001596 }
1597
1598 /// Store a new key in a single transaction.
1599 /// The function creates a new key entry, populates the blob, key parameter, and metadata
1600 /// fields, and rebinds the given alias to the new key.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001601 /// The boolean returned is a hint for the garbage collector. If true, a key was replaced,
1602 /// is now unreferenced and needs to be collected.
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001603 pub fn store_new_key<'a>(
1604 &mut self,
1605 key: KeyDescriptor,
1606 params: impl IntoIterator<Item = &'a KeyParameter>,
1607 blob: &[u8],
Max Bires8e93d2b2021-01-14 13:17:59 -08001608 cert_info: &CertificateInfo,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001609 metadata: &KeyMetaData,
Max Bires8e93d2b2021-01-14 13:17:59 -08001610 km_uuid: &Uuid,
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001611 ) -> Result<(bool, KeyIdGuard)> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001612 let (alias, domain, namespace) = match key {
1613 KeyDescriptor { alias: Some(alias), domain: Domain::APP, nspace, blob: None }
1614 | KeyDescriptor { alias: Some(alias), domain: Domain::SELINUX, nspace, blob: None } => {
1615 (alias, key.domain, nspace)
1616 }
1617 _ => {
1618 return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT))
1619 .context("In store_new_key: Need alias and domain must be APP or SELINUX.")
1620 }
1621 };
1622 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Max Bires8e93d2b2021-01-14 13:17:59 -08001623 let key_id = Self::create_key_entry_internal(tx, domain, namespace, km_uuid)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001624 .context("Trying to create new key entry.")?;
Janis Danisevskis377d1002021-01-27 19:07:48 -08001625 Self::set_blob_internal(tx, key_id.id(), SubComponentType::KEY_BLOB, Some(blob))
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001626 .context("Trying to insert the key blob.")?;
Max Bires8e93d2b2021-01-14 13:17:59 -08001627 if let Some(cert) = &cert_info.cert {
Janis Danisevskis377d1002021-01-27 19:07:48 -08001628 Self::set_blob_internal(tx, key_id.id(), SubComponentType::CERT, Some(&cert))
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001629 .context("Trying to insert the certificate.")?;
1630 }
Max Bires8e93d2b2021-01-14 13:17:59 -08001631 if let Some(cert_chain) = &cert_info.cert_chain {
Janis Danisevskis377d1002021-01-27 19:07:48 -08001632 Self::set_blob_internal(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001633 tx,
1634 key_id.id(),
1635 SubComponentType::CERT_CHAIN,
Janis Danisevskis377d1002021-01-27 19:07:48 -08001636 Some(&cert_chain),
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001637 )
1638 .context("Trying to insert the certificate chain.")?;
1639 }
1640 Self::insert_keyparameter_internal(tx, &key_id, params)
1641 .context("Trying to insert key parameters.")?;
Janis Danisevskis377d1002021-01-27 19:07:48 -08001642 metadata.store_in_db(key_id.id(), tx).context("Trying to insert key metadata.")?;
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001643 let need_gc = Self::rebind_alias(tx, &key_id, &alias, domain, namespace)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001644 .context("Trying to rebind alias.")?;
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001645 Ok((need_gc, key_id))
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001646 })
1647 .context("In store_new_key.")
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001648 }
1649
Janis Danisevskis377d1002021-01-27 19:07:48 -08001650 /// Store a new certificate
1651 /// The function creates a new key entry, populates the blob field and metadata, and rebinds
1652 /// the given alias to the new cert.
Max Bires8e93d2b2021-01-14 13:17:59 -08001653 pub fn store_new_certificate(
1654 &mut self,
1655 key: KeyDescriptor,
1656 cert: &[u8],
1657 km_uuid: &Uuid,
1658 ) -> Result<KeyIdGuard> {
Janis Danisevskis377d1002021-01-27 19:07:48 -08001659 let (alias, domain, namespace) = match key {
1660 KeyDescriptor { alias: Some(alias), domain: Domain::APP, nspace, blob: None }
1661 | KeyDescriptor { alias: Some(alias), domain: Domain::SELINUX, nspace, blob: None } => {
1662 (alias, key.domain, nspace)
1663 }
1664 _ => {
1665 return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT)).context(
1666 "In store_new_certificate: Need alias and domain must be APP or SELINUX.",
1667 )
1668 }
1669 };
1670 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Max Bires8e93d2b2021-01-14 13:17:59 -08001671 let key_id = Self::create_key_entry_internal(tx, domain, namespace, km_uuid)
Janis Danisevskis377d1002021-01-27 19:07:48 -08001672 .context("Trying to create new key entry.")?;
1673
1674 Self::set_blob_internal(tx, key_id.id(), SubComponentType::CERT_CHAIN, Some(cert))
1675 .context("Trying to insert certificate.")?;
1676
1677 let mut metadata = KeyMetaData::new();
1678 metadata.add(KeyMetaEntry::CreationDate(
1679 DateTime::now().context("Trying to make creation time.")?,
1680 ));
1681
1682 metadata.store_in_db(key_id.id(), tx).context("Trying to insert key metadata.")?;
1683
1684 Self::rebind_alias(tx, &key_id, &alias, domain, namespace)
1685 .context("Trying to rebind alias.")?;
1686 Ok(key_id)
1687 })
1688 .context("In store_new_certificate.")
1689 }
1690
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001691 // Helper function loading the key_id given the key descriptor
1692 // tuple comprising domain, namespace, and alias.
1693 // Requires a valid transaction.
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001694 fn load_key_entry_id(tx: &Transaction, key: &KeyDescriptor, key_type: KeyType) -> Result<i64> {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001695 let alias = key
1696 .alias
1697 .as_ref()
1698 .map_or_else(|| Err(KsError::sys()), Ok)
1699 .context("In load_key_entry_id: Alias must be specified.")?;
1700 let mut stmt = tx
1701 .prepare(
1702 "SELECT id FROM persistent.keyentry
1703 WHERE
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001704 key_type = ?
1705 AND domain = ?
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001706 AND namespace = ?
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001707 AND alias = ?
1708 AND state = ?;",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001709 )
1710 .context("In load_key_entry_id: Failed to select from keyentry table.")?;
1711 let mut rows = stmt
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001712 .query(params![key_type, key.domain.0 as u32, key.nspace, alias, KeyLifeCycle::Live])
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001713 .context("In load_key_entry_id: Failed to read from keyentry table.")?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08001714 db_utils::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001715 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001716 .get(0)
1717 .context("Failed to unpack id.")
1718 })
1719 .context("In load_key_entry_id.")
1720 }
1721
1722 /// This helper function completes the access tuple of a key, which is required
1723 /// to perform access control. The strategy depends on the `domain` field in the
1724 /// key descriptor.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001725 /// * Domain::SELINUX: The access tuple is complete and this function only loads
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001726 /// the key_id for further processing.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001727 /// * Domain::APP: Like Domain::SELINUX, but the tuple is completed by `caller_uid`
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001728 /// which serves as the namespace.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001729 /// * Domain::GRANT: The grant table is queried for the `key_id` and the
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001730 /// `access_vector`.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001731 /// * Domain::KEY_ID: The keyentry table is queried for the owning `domain` and
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001732 /// `namespace`.
1733 /// In each case the information returned is sufficient to perform the access
1734 /// check and the key id can be used to load further key artifacts.
1735 fn load_access_tuple(
1736 tx: &Transaction,
1737 key: KeyDescriptor,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001738 key_type: KeyType,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001739 caller_uid: u32,
1740 ) -> Result<(i64, KeyDescriptor, Option<KeyPermSet>)> {
1741 match key.domain {
1742 // Domain App or SELinux. In this case we load the key_id from
1743 // the keyentry database for further loading of key components.
1744 // We already have the full access tuple to perform access control.
1745 // The only distinction is that we use the caller_uid instead
1746 // of the caller supplied namespace if the domain field is
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001747 // Domain::APP.
1748 Domain::APP | Domain::SELINUX => {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001749 let mut access_key = key;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001750 if access_key.domain == Domain::APP {
1751 access_key.nspace = caller_uid as i64;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001752 }
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001753 let key_id = Self::load_key_entry_id(&tx, &access_key, key_type)
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001754 .with_context(|| format!("With key.domain = {:?}.", access_key.domain))?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001755
1756 Ok((key_id, access_key, None))
1757 }
1758
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001759 // Domain::GRANT. In this case we load the key_id and the access_vector
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001760 // from the grant table.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001761 Domain::GRANT => {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001762 let mut stmt = tx
1763 .prepare(
Janis Danisevskisbf15d732020-12-08 10:35:26 -08001764 "SELECT keyentryid, access_vector FROM persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001765 WHERE grantee = ? AND id = ?;",
1766 )
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001767 .context("Domain::GRANT prepare statement failed")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001768 let mut rows = stmt
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001769 .query(params![caller_uid as i64, key.nspace])
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001770 .context("Domain:Grant: query failed.")?;
1771 let (key_id, access_vector): (i64, i32) =
Janis Danisevskisbf15d732020-12-08 10:35:26 -08001772 db_utils::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001773 let r =
1774 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001775 Ok((
1776 r.get(0).context("Failed to unpack key_id.")?,
1777 r.get(1).context("Failed to unpack access_vector.")?,
1778 ))
1779 })
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001780 .context("Domain::GRANT.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001781 Ok((key_id, key, Some(access_vector.into())))
1782 }
1783
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001784 // Domain::KEY_ID. In this case we load the domain and namespace from the
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001785 // keyentry database because we need them for access control.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001786 Domain::KEY_ID => {
Janis Danisevskis45760022021-01-19 16:34:10 -08001787 let (domain, namespace): (Domain, i64) = {
1788 let mut stmt = tx
1789 .prepare(
1790 "SELECT domain, namespace FROM persistent.keyentry
1791 WHERE
1792 id = ?
1793 AND state = ?;",
1794 )
1795 .context("Domain::KEY_ID: prepare statement failed")?;
1796 let mut rows = stmt
1797 .query(params![key.nspace, KeyLifeCycle::Live])
1798 .context("Domain::KEY_ID: query failed.")?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08001799 db_utils::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001800 let r =
1801 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001802 Ok((
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001803 Domain(r.get(0).context("Failed to unpack domain.")?),
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001804 r.get(1).context("Failed to unpack namespace.")?,
1805 ))
1806 })
Janis Danisevskis45760022021-01-19 16:34:10 -08001807 .context("Domain::KEY_ID.")?
1808 };
1809
1810 // We may use a key by id after loading it by grant.
1811 // In this case we have to check if the caller has a grant for this particular
1812 // key. We can skip this if we already know that the caller is the owner.
1813 // But we cannot know this if domain is anything but App. E.g. in the case
1814 // of Domain::SELINUX we have to speculatively check for grants because we have to
1815 // consult the SEPolicy before we know if the caller is the owner.
1816 let access_vector: Option<KeyPermSet> =
1817 if domain != Domain::APP || namespace != caller_uid as i64 {
1818 let access_vector: Option<i32> = tx
1819 .query_row(
1820 "SELECT access_vector FROM persistent.grant
1821 WHERE grantee = ? AND keyentryid = ?;",
1822 params![caller_uid as i64, key.nspace],
1823 |row| row.get(0),
1824 )
1825 .optional()
1826 .context("Domain::KEY_ID: query grant failed.")?;
1827 access_vector.map(|p| p.into())
1828 } else {
1829 None
1830 };
1831
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001832 let key_id = key.nspace;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001833 let mut access_key = key;
1834 access_key.domain = domain;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001835 access_key.nspace = namespace;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001836
Janis Danisevskis45760022021-01-19 16:34:10 -08001837 Ok((key_id, access_key, access_vector))
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001838 }
1839 _ => Err(anyhow!(KsError::sys())),
1840 }
1841 }
1842
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001843 fn load_blob_components(
1844 key_id: i64,
1845 load_bits: KeyEntryLoadBits,
1846 tx: &Transaction,
Janis Danisevskis377d1002021-01-27 19:07:48 -08001847 ) -> Result<(bool, Option<Vec<u8>>, Option<Vec<u8>>, Option<Vec<u8>>)> {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001848 let mut stmt = tx
1849 .prepare(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001850 "SELECT MAX(id), subcomponent_type, blob FROM persistent.blobentry
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001851 WHERE keyentryid = ? GROUP BY subcomponent_type;",
1852 )
1853 .context("In load_blob_components: prepare statement failed.")?;
1854
1855 let mut rows =
1856 stmt.query(params![key_id]).context("In load_blob_components: query failed.")?;
1857
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001858 let mut km_blob: Option<Vec<u8>> = None;
1859 let mut cert_blob: Option<Vec<u8>> = None;
1860 let mut cert_chain_blob: Option<Vec<u8>> = None;
Janis Danisevskis377d1002021-01-27 19:07:48 -08001861 let mut has_km_blob: bool = false;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08001862 db_utils::with_rows_extract_all(&mut rows, |row| {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001863 let sub_type: SubComponentType =
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001864 row.get(1).context("Failed to extract subcomponent_type.")?;
Janis Danisevskis377d1002021-01-27 19:07:48 -08001865 has_km_blob = has_km_blob || sub_type == SubComponentType::KEY_BLOB;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001866 match (sub_type, load_bits.load_public(), load_bits.load_km()) {
1867 (SubComponentType::KEY_BLOB, _, true) => {
1868 km_blob = Some(row.get(2).context("Failed to extract KM blob.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001869 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001870 (SubComponentType::CERT, true, _) => {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001871 cert_blob =
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001872 Some(row.get(2).context("Failed to extract public certificate blob.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001873 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001874 (SubComponentType::CERT_CHAIN, true, _) => {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001875 cert_chain_blob =
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001876 Some(row.get(2).context("Failed to extract certificate chain blob.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001877 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001878 (SubComponentType::CERT, _, _)
1879 | (SubComponentType::CERT_CHAIN, _, _)
1880 | (SubComponentType::KEY_BLOB, _, _) => {}
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001881 _ => Err(KsError::sys()).context("Unknown subcomponent type.")?,
1882 }
1883 Ok(())
1884 })
1885 .context("In load_blob_components.")?;
1886
Janis Danisevskis377d1002021-01-27 19:07:48 -08001887 Ok((has_km_blob, km_blob, cert_blob, cert_chain_blob))
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001888 }
1889
1890 fn load_key_parameters(key_id: i64, tx: &Transaction) -> Result<Vec<KeyParameter>> {
1891 let mut stmt = tx
1892 .prepare(
1893 "SELECT tag, data, security_level from persistent.keyparameter
1894 WHERE keyentryid = ?;",
1895 )
1896 .context("In load_key_parameters: prepare statement failed.")?;
1897
1898 let mut parameters: Vec<KeyParameter> = Vec::new();
1899
1900 let mut rows =
1901 stmt.query(params![key_id]).context("In load_key_parameters: query failed.")?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08001902 db_utils::with_rows_extract_all(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001903 let tag = Tag(row.get(0).context("Failed to read tag.")?);
1904 let sec_level = SecurityLevel(row.get(2).context("Failed to read sec_level.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001905 parameters.push(
1906 KeyParameter::new_from_sql(tag, &SqlField::new(1, &row), sec_level)
1907 .context("Failed to read KeyParameter.")?,
1908 );
1909 Ok(())
1910 })
1911 .context("In load_key_parameters.")?;
1912
1913 Ok(parameters)
1914 }
1915
Qi Wub9433b52020-12-01 14:52:46 +08001916 /// Decrements the usage count of a limited use key. This function first checks whether the
1917 /// usage has been exhausted, if not, decreases the usage count. If the usage count reaches
1918 /// zero, the key also gets marked unreferenced and scheduled for deletion.
1919 /// Returns Ok(true) if the key was marked unreferenced as a hint to the garbage collector.
1920 pub fn check_and_update_key_usage_count(&mut self, key_id: i64) -> Result<bool> {
1921 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1922 let limit: Option<i32> = tx
1923 .query_row(
1924 "SELECT data FROM persistent.keyparameter WHERE keyentryid = ? AND tag = ?;",
1925 params![key_id, Tag::USAGE_COUNT_LIMIT.0],
1926 |row| row.get(0),
1927 )
1928 .optional()
1929 .context("Trying to load usage count")?;
1930
1931 let limit = limit
1932 .ok_or(KsError::Km(ErrorCode::INVALID_KEY_BLOB))
1933 .context("The Key no longer exists. Key is exhausted.")?;
1934
1935 tx.execute(
1936 "UPDATE persistent.keyparameter
1937 SET data = data - 1
1938 WHERE keyentryid = ? AND tag = ? AND data > 0;",
1939 params![key_id, Tag::USAGE_COUNT_LIMIT.0],
1940 )
1941 .context("Failed to update key usage count.")?;
1942
1943 match limit {
1944 1 => Self::mark_unreferenced(tx, key_id)
1945 .context("Trying to mark limited use key for deletion."),
1946 0 => Err(KsError::Km(ErrorCode::INVALID_KEY_BLOB)).context("Key is exhausted."),
1947 _ => Ok(false),
1948 }
1949 })
1950 .context("In check_and_update_key_usage_count.")
1951 }
1952
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001953 /// Load a key entry by the given key descriptor.
1954 /// It uses the `check_permission` callback to verify if the access is allowed
1955 /// given the key access tuple read from the database using `load_access_tuple`.
1956 /// With `load_bits` the caller may specify which blobs shall be loaded from
1957 /// the blob database.
1958 pub fn load_key_entry(
1959 &mut self,
1960 key: KeyDescriptor,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001961 key_type: KeyType,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001962 load_bits: KeyEntryLoadBits,
1963 caller_uid: u32,
1964 check_permission: impl FnOnce(&KeyDescriptor, Option<KeyPermSet>) -> Result<()>,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001965 ) -> Result<(KeyIdGuard, KeyEntry)> {
1966 // KEY ID LOCK 1/2
1967 // If we got a key descriptor with a key id we can get the lock right away.
1968 // Otherwise we have to defer it until we know the key id.
1969 let key_id_guard = match key.domain {
1970 Domain::KEY_ID => Some(KEY_ID_LOCK.get(key.nspace)),
1971 _ => None,
1972 };
1973
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001974 let tx = self
1975 .conn
Janis Danisevskisaec14592020-11-12 09:41:49 -08001976 .unchecked_transaction()
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001977 .context("In load_key_entry: Failed to initialize transaction.")?;
1978
1979 // Load the key_id and complete the access control tuple.
1980 let (key_id, access_key_descriptor, access_vector) =
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001981 Self::load_access_tuple(&tx, key, key_type, caller_uid)
1982 .context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001983
1984 // Perform access control. It is vital that we return here if the permission is denied.
1985 // So do not touch that '?' at the end.
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001986 check_permission(&access_key_descriptor, access_vector).context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001987
Janis Danisevskisaec14592020-11-12 09:41:49 -08001988 // KEY ID LOCK 2/2
1989 // If we did not get a key id lock by now, it was because we got a key descriptor
1990 // without a key id. At this point we got the key id, so we can try and get a lock.
1991 // However, we cannot block here, because we are in the middle of the transaction.
1992 // So first we try to get the lock non blocking. If that fails, we roll back the
1993 // transaction and block until we get the lock. After we successfully got the lock,
1994 // we start a new transaction and load the access tuple again.
1995 //
1996 // We don't need to perform access control again, because we already established
1997 // that the caller had access to the given key. But we need to make sure that the
1998 // key id still exists. So we have to load the key entry by key id this time.
1999 let (key_id_guard, tx) = match key_id_guard {
2000 None => match KEY_ID_LOCK.try_get(key_id) {
2001 None => {
2002 // Roll back the transaction.
2003 tx.rollback().context("In load_key_entry: Failed to roll back transaction.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002004
Janis Danisevskisaec14592020-11-12 09:41:49 -08002005 // Block until we have a key id lock.
2006 let key_id_guard = KEY_ID_LOCK.get(key_id);
2007
2008 // Create a new transaction.
2009 let tx = self.conn.unchecked_transaction().context(
2010 "In load_key_entry: Failed to initialize transaction. (deferred key lock)",
2011 )?;
2012
2013 Self::load_access_tuple(
2014 &tx,
2015 // This time we have to load the key by the retrieved key id, because the
2016 // alias may have been rebound after we rolled back the transaction.
2017 KeyDescriptor {
2018 domain: Domain::KEY_ID,
2019 nspace: key_id,
2020 ..Default::default()
2021 },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002022 key_type,
Janis Danisevskisaec14592020-11-12 09:41:49 -08002023 caller_uid,
2024 )
2025 .context("In load_key_entry. (deferred key lock)")?;
2026 (key_id_guard, tx)
2027 }
2028 Some(l) => (l, tx),
2029 },
2030 Some(key_id_guard) => (key_id_guard, tx),
2031 };
2032
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002033 let key_entry = Self::load_key_components(&tx, load_bits, key_id_guard.id())
2034 .context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002035
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002036 tx.commit().context("In load_key_entry: Failed to commit transaction.")?;
2037
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002038 Ok((key_id_guard, key_entry))
2039 }
2040
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002041 fn mark_unreferenced(tx: &Transaction, key_id: i64) -> Result<bool> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002042 let updated = tx
2043 .execute(
2044 "UPDATE persistent.keyentry SET state = ? WHERE id = ?;",
2045 params![KeyLifeCycle::Unreferenced, key_id],
2046 )
2047 .context("In mark_unreferenced: Failed to update state of key entry.")?;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002048 tx.execute("DELETE from persistent.grant WHERE keyentryid = ?;", params![key_id])
2049 .context("In mark_unreferenced: Failed to drop grants.")?;
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002050 Ok(updated != 0)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002051 }
2052
2053 /// Marks the given key as unreferenced and removes all of the grants to this key.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002054 /// Returns Ok(true) if a key was marked unreferenced as a hint for the garbage collector.
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002055 pub fn unbind_key(
2056 &mut self,
2057 key: KeyDescriptor,
2058 key_type: KeyType,
2059 caller_uid: u32,
2060 check_permission: impl FnOnce(&KeyDescriptor, Option<KeyPermSet>) -> Result<()>,
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002061 ) -> Result<bool> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002062 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2063 let (key_id, access_key_descriptor, access_vector) =
2064 Self::load_access_tuple(tx, key, key_type, caller_uid)
2065 .context("Trying to get access tuple.")?;
2066
2067 // Perform access control. It is vital that we return here if the permission is denied.
2068 // So do not touch that '?' at the end.
2069 check_permission(&access_key_descriptor, access_vector)
2070 .context("While checking permission.")?;
2071
2072 Self::mark_unreferenced(tx, key_id).context("Trying to mark the key unreferenced.")
2073 })
2074 .context("In unbind_key.")
2075 }
2076
Max Bires8e93d2b2021-01-14 13:17:59 -08002077 fn get_key_km_uuid(tx: &Transaction, key_id: i64) -> Result<Uuid> {
2078 tx.query_row(
2079 "SELECT km_uuid FROM persistent.keyentry WHERE id = ?",
2080 params![key_id],
2081 |row| row.get(0),
2082 )
2083 .context("In get_key_km_uuid.")
2084 }
2085
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002086 fn load_key_components(
2087 tx: &Transaction,
2088 load_bits: KeyEntryLoadBits,
2089 key_id: i64,
2090 ) -> Result<KeyEntry> {
2091 let metadata = KeyMetaData::load_from_db(key_id, &tx).context("In load_key_components.")?;
2092
Janis Danisevskis377d1002021-01-27 19:07:48 -08002093 let (has_km_blob, km_blob, cert_blob, cert_chain_blob) =
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002094 Self::load_blob_components(key_id, load_bits, &tx)
2095 .context("In load_key_components.")?;
2096
Max Bires8e93d2b2021-01-14 13:17:59 -08002097 let parameters = Self::load_key_parameters(key_id, &tx)
2098 .context("In load_key_components: Trying to load key parameters.")?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002099
Max Bires8e93d2b2021-01-14 13:17:59 -08002100 let km_uuid = Self::get_key_km_uuid(&tx, key_id)
2101 .context("In load_key_components: Trying to get KM uuid.")?;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002102
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002103 Ok(KeyEntry {
2104 id: key_id,
2105 km_blob,
2106 cert: cert_blob,
2107 cert_chain: cert_chain_blob,
Max Bires8e93d2b2021-01-14 13:17:59 -08002108 km_uuid,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002109 parameters,
2110 metadata,
Janis Danisevskis377d1002021-01-27 19:07:48 -08002111 pure_cert: !has_km_blob,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002112 })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002113 }
2114
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002115 /// Returns a list of KeyDescriptors in the selected domain/namespace.
2116 /// The key descriptors will have the domain, nspace, and alias field set.
2117 /// Domain must be APP or SELINUX, the caller must make sure of that.
2118 pub fn list(&mut self, domain: Domain, namespace: i64) -> Result<Vec<KeyDescriptor>> {
2119 let mut stmt = self
2120 .conn
2121 .prepare(
2122 "SELECT alias FROM persistent.keyentry
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002123 WHERE domain = ? AND namespace = ? AND alias IS NOT NULL AND state = ?;",
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002124 )
2125 .context("In list: Failed to prepare.")?;
2126
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002127 let mut rows = stmt
2128 .query(params![domain.0 as u32, namespace, KeyLifeCycle::Live])
2129 .context("In list: Failed to query.")?;
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002130
2131 let mut descriptors: Vec<KeyDescriptor> = Vec::new();
2132 db_utils::with_rows_extract_all(&mut rows, |row| {
2133 descriptors.push(KeyDescriptor {
2134 domain,
2135 nspace: namespace,
2136 alias: Some(row.get(0).context("Trying to extract alias.")?),
2137 blob: None,
2138 });
2139 Ok(())
2140 })
2141 .context("In list.")?;
2142 Ok(descriptors)
2143 }
2144
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002145 /// Adds a grant to the grant table.
2146 /// Like `load_key_entry` this function loads the access tuple before
2147 /// it uses the callback for a permission check. Upon success,
2148 /// it inserts the `grantee_uid`, `key_id`, and `access_vector` into the
2149 /// grant table. The new row will have a randomized id, which is used as
2150 /// grant id in the namespace field of the resulting KeyDescriptor.
2151 pub fn grant(
2152 &mut self,
2153 key: KeyDescriptor,
2154 caller_uid: u32,
2155 grantee_uid: u32,
2156 access_vector: KeyPermSet,
2157 check_permission: impl FnOnce(&KeyDescriptor, &KeyPermSet) -> Result<()>,
2158 ) -> Result<KeyDescriptor> {
2159 let tx = self
2160 .conn
2161 .transaction_with_behavior(TransactionBehavior::Immediate)
2162 .context("In grant: Failed to initialize transaction.")?;
2163
2164 // Load the key_id and complete the access control tuple.
2165 // We ignore the access vector here because grants cannot be granted.
2166 // The access vector returned here expresses the permissions the
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002167 // grantee has if key.domain == Domain::GRANT. But this vector
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002168 // cannot include the grant permission by design, so there is no way the
2169 // subsequent permission check can pass.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002170 // We could check key.domain == Domain::GRANT and fail early.
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002171 // But even if we load the access tuple by grant here, the permission
2172 // check denies the attempt to create a grant by grant descriptor.
2173 let (key_id, access_key_descriptor, _) =
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002174 Self::load_access_tuple(&tx, key, KeyType::Client, caller_uid).context("In grant")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002175
2176 // Perform access control. It is vital that we return here if the permission
2177 // was denied. So do not touch that '?' at the end of the line.
2178 // This permission check checks if the caller has the grant permission
2179 // for the given key and in addition to all of the permissions
2180 // expressed in `access_vector`.
2181 check_permission(&access_key_descriptor, &access_vector)
2182 .context("In grant: check_permission failed.")?;
2183
2184 let grant_id = if let Some(grant_id) = tx
2185 .query_row(
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002186 "SELECT id FROM persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002187 WHERE keyentryid = ? AND grantee = ?;",
2188 params![key_id, grantee_uid],
2189 |row| row.get(0),
2190 )
2191 .optional()
2192 .context("In grant: Failed get optional existing grant id.")?
2193 {
2194 tx.execute(
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002195 "UPDATE persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002196 SET access_vector = ?
2197 WHERE id = ?;",
2198 params![i32::from(access_vector), grant_id],
2199 )
2200 .context("In grant: Failed to update existing grant.")?;
2201 grant_id
2202 } else {
Joel Galenson845f74b2020-09-09 14:11:55 -07002203 Self::insert_with_retry(|id| {
2204 tx.execute(
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002205 "INSERT INTO persistent.grant (id, grantee, keyentryid, access_vector)
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002206 VALUES (?, ?, ?, ?);",
Joel Galenson845f74b2020-09-09 14:11:55 -07002207 params![id, grantee_uid, key_id, i32::from(access_vector)],
2208 )
2209 })
2210 .context("In grant")?
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002211 };
2212 tx.commit().context("In grant: failed to commit transaction.")?;
2213
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002214 Ok(KeyDescriptor { domain: Domain::GRANT, nspace: grant_id, alias: None, blob: None })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002215 }
2216
2217 /// This function checks permissions like `grant` and `load_key_entry`
2218 /// before removing a grant from the grant table.
2219 pub fn ungrant(
2220 &mut self,
2221 key: KeyDescriptor,
2222 caller_uid: u32,
2223 grantee_uid: u32,
2224 check_permission: impl FnOnce(&KeyDescriptor) -> Result<()>,
2225 ) -> Result<()> {
2226 let tx = self
2227 .conn
2228 .transaction_with_behavior(TransactionBehavior::Immediate)
2229 .context("In ungrant: Failed to initialize transaction.")?;
2230
2231 // Load the key_id and complete the access control tuple.
2232 // We ignore the access vector here because grants cannot be granted.
2233 let (key_id, access_key_descriptor, _) =
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002234 Self::load_access_tuple(&tx, key, KeyType::Client, caller_uid)
2235 .context("In ungrant.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002236
2237 // Perform access control. We must return here if the permission
2238 // was denied. So do not touch the '?' at the end of this line.
2239 check_permission(&access_key_descriptor).context("In grant: check_permission failed.")?;
2240
2241 tx.execute(
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002242 "DELETE FROM persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002243 WHERE keyentryid = ? AND grantee = ?;",
2244 params![key_id, grantee_uid],
2245 )
2246 .context("Failed to delete grant.")?;
2247
2248 tx.commit().context("In ungrant: failed to commit transaction.")?;
2249
2250 Ok(())
2251 }
2252
Joel Galenson845f74b2020-09-09 14:11:55 -07002253 // Generates a random id and passes it to the given function, which will
2254 // try to insert it into a database. If that insertion fails, retry;
2255 // otherwise return the id.
2256 fn insert_with_retry(inserter: impl Fn(i64) -> rusqlite::Result<usize>) -> Result<i64> {
2257 loop {
2258 let newid: i64 = random();
2259 match inserter(newid) {
2260 // If the id already existed, try again.
2261 Err(rusqlite::Error::SqliteFailure(
2262 libsqlite3_sys::Error {
2263 code: libsqlite3_sys::ErrorCode::ConstraintViolation,
2264 extended_code: libsqlite3_sys::SQLITE_CONSTRAINT_UNIQUE,
2265 },
2266 _,
2267 )) => (),
2268 Err(e) => {
2269 return Err(e).context("In insert_with_retry: failed to insert into database.")
2270 }
2271 _ => return Ok(newid),
2272 }
2273 }
2274 }
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002275
2276 /// Insert or replace the auth token based on the UNIQUE constraint of the auth token table
2277 pub fn insert_auth_token(&mut self, auth_token: &HardwareAuthToken) -> Result<()> {
2278 self.conn
2279 .execute(
2280 "INSERT OR REPLACE INTO perboot.authtoken (challenge, user_id, auth_id,
2281 authenticator_type, timestamp, mac, time_received) VALUES(?, ?, ?, ?, ?, ?, ?);",
2282 params![
2283 auth_token.challenge,
2284 auth_token.userId,
2285 auth_token.authenticatorId,
2286 auth_token.authenticatorType.0 as i32,
2287 auth_token.timestamp.milliSeconds as i64,
2288 auth_token.mac,
2289 MonotonicRawTime::now(),
2290 ],
2291 )
2292 .context("In insert_auth_token: failed to insert auth token into the database")?;
2293 Ok(())
2294 }
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002295
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002296 /// Find the newest auth token matching the given predicate.
2297 pub fn find_auth_token_entry<F>(
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002298 &mut self,
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002299 p: F,
2300 ) -> Result<Option<(AuthTokenEntry, MonotonicRawTime)>>
2301 where
2302 F: Fn(&AuthTokenEntry) -> bool,
2303 {
2304 self.with_transaction(TransactionBehavior::Deferred, |tx| {
2305 let mut stmt = tx
2306 .prepare("SELECT * from perboot.authtoken ORDER BY time_received DESC;")
2307 .context("Prepare statement failed.")?;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002308
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002309 let mut rows = stmt.query(NO_PARAMS).context("Failed to query.")?;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002310
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002311 while let Some(row) = rows.next().context("Failed to get next row.")? {
2312 let entry = AuthTokenEntry::new(
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002313 HardwareAuthToken {
2314 challenge: row.get(1)?,
2315 userId: row.get(2)?,
2316 authenticatorId: row.get(3)?,
2317 authenticatorType: HardwareAuthenticatorType(row.get(4)?),
2318 timestamp: Timestamp { milliSeconds: row.get(5)? },
2319 mac: row.get(6)?,
2320 },
2321 row.get(7)?,
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002322 );
2323 if p(&entry) {
2324 return Ok(Some((
2325 entry,
2326 Self::get_last_off_body(tx)
2327 .context("In find_auth_token_entry: Trying to get last off body")?,
2328 )));
2329 }
2330 }
2331 Ok(None)
2332 })
2333 .context("In find_auth_token_entry.")
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002334 }
2335
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002336 /// Insert last_off_body into the metadata table at the initialization of auth token table
2337 pub fn insert_last_off_body(&self, last_off_body: MonotonicRawTime) -> Result<()> {
2338 self.conn
2339 .execute(
2340 "INSERT OR REPLACE INTO perboot.metadata (key, value) VALUES (?, ?);",
2341 params!["last_off_body", last_off_body],
2342 )
2343 .context("In insert_last_off_body: failed to insert.")?;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002344 Ok(())
2345 }
2346
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002347 /// Update last_off_body when on_device_off_body is called
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002348 pub fn update_last_off_body(&self, last_off_body: MonotonicRawTime) -> Result<()> {
2349 self.conn
2350 .execute(
2351 "UPDATE perboot.metadata SET value = ? WHERE key = ?;",
2352 params![last_off_body, "last_off_body"],
2353 )
2354 .context("In update_last_off_body: failed to update.")?;
2355 Ok(())
2356 }
2357
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002358 /// Get last_off_body time when finding auth tokens
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002359 fn get_last_off_body(tx: &Transaction) -> Result<MonotonicRawTime> {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002360 tx.query_row(
2361 "SELECT value from perboot.metadata WHERE key = ?;",
2362 params!["last_off_body"],
2363 |row| Ok(row.get(0)?),
2364 )
2365 .context("In get_last_off_body: query_row failed.")
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002366 }
Joel Galenson26f4d012020-07-17 14:57:21 -07002367}
2368
2369#[cfg(test)]
2370mod tests {
2371
2372 use super::*;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002373 use crate::key_parameter::{
2374 Algorithm, BlockMode, Digest, EcCurve, HardwareAuthenticatorType, KeyOrigin, KeyParameter,
2375 KeyParameterValue, KeyPurpose, PaddingMode, SecurityLevel,
2376 };
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002377 use crate::key_perm_set;
2378 use crate::permission::{KeyPerm, KeyPermSet};
Janis Danisevskis2a8330a2021-01-20 15:34:26 -08002379 use keystore2_test_utils::TempDir;
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002380 use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
2381 HardwareAuthToken::HardwareAuthToken,
2382 HardwareAuthenticatorType::HardwareAuthenticatorType as kmhw_authenticator_type,
Janis Danisevskisc3a496b2021-01-05 10:37:22 -08002383 };
2384 use android_hardware_security_secureclock::aidl::android::hardware::security::secureclock::{
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002385 Timestamp::Timestamp,
2386 };
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002387 use rusqlite::NO_PARAMS;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002388 use rusqlite::{Error, TransactionBehavior};
Joel Galenson0891bc12020-07-20 10:37:03 -07002389 use std::cell::RefCell;
Janis Danisevskisaec14592020-11-12 09:41:49 -08002390 use std::sync::atomic::{AtomicU8, Ordering};
2391 use std::sync::Arc;
2392 use std::thread;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002393 use std::time::{Duration, SystemTime};
Joel Galenson0891bc12020-07-20 10:37:03 -07002394
Janis Danisevskis4df44f42020-08-26 14:40:03 -07002395 fn new_test_db() -> Result<KeystoreDB> {
2396 let conn = KeystoreDB::make_connection("file::memory:", "file::memory:")?;
2397
2398 KeystoreDB::init_tables(&conn).context("Failed to initialize tables.")?;
2399 Ok(KeystoreDB { conn })
2400 }
2401
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002402 fn rebind_alias(
2403 db: &mut KeystoreDB,
2404 newid: &KeyIdGuard,
2405 alias: &str,
2406 domain: Domain,
2407 namespace: i64,
2408 ) -> Result<bool> {
2409 db.with_transaction(TransactionBehavior::Immediate, |tx| {
2410 KeystoreDB::rebind_alias(tx, newid, alias, domain, namespace)
2411 })
2412 .context("In rebind_alias.")
2413 }
2414
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002415 #[test]
2416 fn datetime() -> Result<()> {
2417 let conn = Connection::open_in_memory()?;
2418 conn.execute("CREATE TABLE test (ts DATETIME);", NO_PARAMS)?;
2419 let now = SystemTime::now();
2420 let duration = Duration::from_secs(1000);
2421 let then = now.checked_sub(duration).unwrap();
2422 let soon = now.checked_add(duration).unwrap();
2423 conn.execute(
2424 "INSERT INTO test (ts) VALUES (?), (?), (?);",
2425 params![DateTime::try_from(now)?, DateTime::try_from(then)?, DateTime::try_from(soon)?],
2426 )?;
2427 let mut stmt = conn.prepare("SELECT ts FROM test ORDER BY ts ASC;")?;
2428 let mut rows = stmt.query(NO_PARAMS)?;
2429 assert_eq!(DateTime::try_from(then)?, rows.next()?.unwrap().get(0)?);
2430 assert_eq!(DateTime::try_from(now)?, rows.next()?.unwrap().get(0)?);
2431 assert_eq!(DateTime::try_from(soon)?, rows.next()?.unwrap().get(0)?);
2432 assert!(rows.next()?.is_none());
2433 assert!(DateTime::try_from(then)? < DateTime::try_from(now)?);
2434 assert!(DateTime::try_from(then)? < DateTime::try_from(soon)?);
2435 assert!(DateTime::try_from(now)? < DateTime::try_from(soon)?);
2436 Ok(())
2437 }
2438
Joel Galenson0891bc12020-07-20 10:37:03 -07002439 // Ensure that we're using the "injected" random function, not the real one.
2440 #[test]
2441 fn test_mocked_random() {
2442 let rand1 = random();
2443 let rand2 = random();
2444 let rand3 = random();
2445 if rand1 == rand2 {
2446 assert_eq!(rand2 + 1, rand3);
2447 } else {
2448 assert_eq!(rand1 + 1, rand2);
2449 assert_eq!(rand2, rand3);
2450 }
2451 }
Joel Galenson26f4d012020-07-17 14:57:21 -07002452
Joel Galenson26f4d012020-07-17 14:57:21 -07002453 // Test that we have the correct tables.
2454 #[test]
2455 fn test_tables() -> Result<()> {
Janis Danisevskis4df44f42020-08-26 14:40:03 -07002456 let db = new_test_db()?;
Joel Galenson26f4d012020-07-17 14:57:21 -07002457 let tables = db
2458 .conn
Joel Galenson2aab4432020-07-22 15:27:57 -07002459 .prepare("SELECT name from persistent.sqlite_master WHERE type='table' ORDER BY name;")?
Joel Galenson26f4d012020-07-17 14:57:21 -07002460 .query_map(params![], |row| row.get(0))?
2461 .collect::<rusqlite::Result<Vec<String>>>()?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002462 assert_eq!(tables.len(), 5);
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002463 assert_eq!(tables[0], "blobentry");
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002464 assert_eq!(tables[1], "grant");
2465 assert_eq!(tables[2], "keyentry");
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002466 assert_eq!(tables[3], "keymetadata");
2467 assert_eq!(tables[4], "keyparameter");
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002468 let tables = db
2469 .conn
2470 .prepare("SELECT name from perboot.sqlite_master WHERE type='table' ORDER BY name;")?
2471 .query_map(params![], |row| row.get(0))?
2472 .collect::<rusqlite::Result<Vec<String>>>()?;
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002473
2474 assert_eq!(tables.len(), 2);
2475 assert_eq!(tables[0], "authtoken");
2476 assert_eq!(tables[1], "metadata");
Joel Galenson2aab4432020-07-22 15:27:57 -07002477 Ok(())
2478 }
2479
2480 #[test]
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002481 fn test_auth_token_table_invariant() -> Result<()> {
2482 let mut db = new_test_db()?;
2483 let auth_token1 = HardwareAuthToken {
2484 challenge: i64::MAX,
2485 userId: 200,
2486 authenticatorId: 200,
2487 authenticatorType: kmhw_authenticator_type(kmhw_authenticator_type::PASSWORD.0),
2488 timestamp: Timestamp { milliSeconds: 500 },
2489 mac: String::from("mac").into_bytes(),
2490 };
2491 db.insert_auth_token(&auth_token1)?;
2492 let auth_tokens_returned = get_auth_tokens(&mut db)?;
2493 assert_eq!(auth_tokens_returned.len(), 1);
2494
2495 // insert another auth token with the same values for the columns in the UNIQUE constraint
2496 // of the auth token table and different value for timestamp
2497 let auth_token2 = HardwareAuthToken {
2498 challenge: i64::MAX,
2499 userId: 200,
2500 authenticatorId: 200,
2501 authenticatorType: kmhw_authenticator_type(kmhw_authenticator_type::PASSWORD.0),
2502 timestamp: Timestamp { milliSeconds: 600 },
2503 mac: String::from("mac").into_bytes(),
2504 };
2505
2506 db.insert_auth_token(&auth_token2)?;
2507 let mut auth_tokens_returned = get_auth_tokens(&mut db)?;
2508 assert_eq!(auth_tokens_returned.len(), 1);
2509
2510 if let Some(auth_token) = auth_tokens_returned.pop() {
2511 assert_eq!(auth_token.auth_token.timestamp.milliSeconds, 600);
2512 }
2513
2514 // insert another auth token with the different values for the columns in the UNIQUE
2515 // constraint of the auth token table
2516 let auth_token3 = HardwareAuthToken {
2517 challenge: i64::MAX,
2518 userId: 201,
2519 authenticatorId: 200,
2520 authenticatorType: kmhw_authenticator_type(kmhw_authenticator_type::PASSWORD.0),
2521 timestamp: Timestamp { milliSeconds: 600 },
2522 mac: String::from("mac").into_bytes(),
2523 };
2524
2525 db.insert_auth_token(&auth_token3)?;
2526 let auth_tokens_returned = get_auth_tokens(&mut db)?;
2527 assert_eq!(auth_tokens_returned.len(), 2);
2528
2529 Ok(())
2530 }
2531
2532 // utility function for test_auth_token_table_invariant()
2533 fn get_auth_tokens(db: &mut KeystoreDB) -> Result<Vec<AuthTokenEntry>> {
2534 let mut stmt = db.conn.prepare("SELECT * from perboot.authtoken;")?;
2535
2536 let auth_token_entries: Vec<AuthTokenEntry> = stmt
2537 .query_map(NO_PARAMS, |row| {
2538 Ok(AuthTokenEntry::new(
2539 HardwareAuthToken {
2540 challenge: row.get(1)?,
2541 userId: row.get(2)?,
2542 authenticatorId: row.get(3)?,
2543 authenticatorType: HardwareAuthenticatorType(row.get(4)?),
2544 timestamp: Timestamp { milliSeconds: row.get(5)? },
2545 mac: row.get(6)?,
2546 },
2547 row.get(7)?,
2548 ))
2549 })?
2550 .collect::<Result<Vec<AuthTokenEntry>, Error>>()?;
2551 Ok(auth_token_entries)
2552 }
2553
2554 #[test]
Joel Galenson2aab4432020-07-22 15:27:57 -07002555 fn test_persistence_for_files() -> Result<()> {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002556 let temp_dir = TempDir::new("persistent_db_test")?;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002557 let mut db = KeystoreDB::new(temp_dir.path())?;
Joel Galenson2aab4432020-07-22 15:27:57 -07002558
Max Bires8e93d2b2021-01-14 13:17:59 -08002559 db.create_key_entry(Domain::APP, 100, &KEYSTORE_UUID)?;
Joel Galenson2aab4432020-07-22 15:27:57 -07002560 let entries = get_keyentry(&db)?;
2561 assert_eq!(entries.len(), 1);
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002562
2563 let db = KeystoreDB::new(temp_dir.path())?;
Joel Galenson2aab4432020-07-22 15:27:57 -07002564
2565 let entries_new = get_keyentry(&db)?;
2566 assert_eq!(entries, entries_new);
2567 Ok(())
2568 }
2569
2570 #[test]
Joel Galenson0891bc12020-07-20 10:37:03 -07002571 fn test_create_key_entry() -> Result<()> {
Max Bires8e93d2b2021-01-14 13:17:59 -08002572 fn extractor(ke: &KeyEntryRow) -> (Domain, i64, Option<&str>, Uuid) {
2573 (ke.domain.unwrap(), ke.namespace.unwrap(), ke.alias.as_deref(), ke.km_uuid.unwrap())
Joel Galenson0891bc12020-07-20 10:37:03 -07002574 }
2575
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002576 let mut db = new_test_db()?;
Joel Galenson0891bc12020-07-20 10:37:03 -07002577
Max Bires8e93d2b2021-01-14 13:17:59 -08002578 db.create_key_entry(Domain::APP, 100, &KEYSTORE_UUID)?;
2579 db.create_key_entry(Domain::SELINUX, 101, &KEYSTORE_UUID)?;
Joel Galenson0891bc12020-07-20 10:37:03 -07002580
2581 let entries = get_keyentry(&db)?;
2582 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08002583 assert_eq!(extractor(&entries[0]), (Domain::APP, 100, None, KEYSTORE_UUID));
2584 assert_eq!(extractor(&entries[1]), (Domain::SELINUX, 101, None, KEYSTORE_UUID));
Joel Galenson0891bc12020-07-20 10:37:03 -07002585
2586 // Test that we must pass in a valid Domain.
2587 check_result_is_error_containing_string(
Max Bires8e93d2b2021-01-14 13:17:59 -08002588 db.create_key_entry(Domain::GRANT, 102, &KEYSTORE_UUID),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002589 "Domain Domain(1) must be either App or SELinux.",
Joel Galenson0891bc12020-07-20 10:37:03 -07002590 );
2591 check_result_is_error_containing_string(
Max Bires8e93d2b2021-01-14 13:17:59 -08002592 db.create_key_entry(Domain::BLOB, 103, &KEYSTORE_UUID),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002593 "Domain Domain(3) must be either App or SELinux.",
Joel Galenson0891bc12020-07-20 10:37:03 -07002594 );
2595 check_result_is_error_containing_string(
Max Bires8e93d2b2021-01-14 13:17:59 -08002596 db.create_key_entry(Domain::KEY_ID, 104, &KEYSTORE_UUID),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002597 "Domain Domain(4) must be either App or SELinux.",
Joel Galenson0891bc12020-07-20 10:37:03 -07002598 );
2599
2600 Ok(())
2601 }
2602
Joel Galenson33c04ad2020-08-03 11:04:38 -07002603 #[test]
Max Bires2b2e6562020-09-22 11:22:36 -07002604 fn test_add_unsigned_key() -> Result<()> {
2605 let mut db = new_test_db()?;
2606 let public_key: Vec<u8> = vec![0x01, 0x02, 0x03];
2607 let private_key: Vec<u8> = vec![0x04, 0x05, 0x06];
2608 let raw_public_key: Vec<u8> = vec![0x07, 0x08, 0x09];
2609 db.create_attestation_key_entry(
2610 &public_key,
2611 &raw_public_key,
2612 &private_key,
2613 &KEYSTORE_UUID,
2614 )?;
2615 let keys = db.fetch_unsigned_attestation_keys(5, &KEYSTORE_UUID)?;
2616 assert_eq!(keys.len(), 1);
2617 assert_eq!(keys[0], public_key);
2618 Ok(())
2619 }
2620
2621 #[test]
2622 fn test_store_signed_attestation_certificate_chain() -> Result<()> {
2623 let mut db = new_test_db()?;
2624 let expiration_date: i64 = 20;
2625 let namespace: i64 = 30;
2626 let base_byte: u8 = 1;
2627 let loaded_values =
2628 load_attestation_key_pool(&mut db, expiration_date, namespace, base_byte)?;
2629 let chain =
2630 db.retrieve_attestation_key_and_cert_chain(Domain::APP, namespace, &KEYSTORE_UUID)?;
2631 assert_eq!(true, chain.is_some());
2632 let cert_chain = chain.unwrap();
2633 assert_eq!(cert_chain.private_key.to_vec(), loaded_values[2]);
2634 assert_eq!(cert_chain.cert_chain.to_vec(), loaded_values[1]);
2635 Ok(())
2636 }
2637
2638 #[test]
2639 fn test_get_attestation_pool_status() -> Result<()> {
2640 let mut db = new_test_db()?;
2641 let namespace: i64 = 30;
2642 load_attestation_key_pool(
2643 &mut db, 10, /* expiration */
2644 namespace, 0x01, /* base_byte */
2645 )?;
2646 load_attestation_key_pool(&mut db, 20 /* expiration */, namespace + 1, 0x02)?;
2647 load_attestation_key_pool(&mut db, 40 /* expiration */, namespace + 2, 0x03)?;
2648 let mut status = db.get_attestation_pool_status(9 /* expiration */, &KEYSTORE_UUID)?;
2649 assert_eq!(status.expiring, 0);
2650 assert_eq!(status.attested, 3);
2651 assert_eq!(status.unassigned, 0);
2652 assert_eq!(status.total, 3);
2653 assert_eq!(
2654 db.get_attestation_pool_status(15 /* expiration */, &KEYSTORE_UUID)?.expiring,
2655 1
2656 );
2657 assert_eq!(
2658 db.get_attestation_pool_status(25 /* expiration */, &KEYSTORE_UUID)?.expiring,
2659 2
2660 );
2661 assert_eq!(
2662 db.get_attestation_pool_status(60 /* expiration */, &KEYSTORE_UUID)?.expiring,
2663 3
2664 );
2665 let public_key: Vec<u8> = vec![0x01, 0x02, 0x03];
2666 let private_key: Vec<u8> = vec![0x04, 0x05, 0x06];
2667 let raw_public_key: Vec<u8> = vec![0x07, 0x08, 0x09];
2668 let cert_chain: Vec<u8> = vec![0x0a, 0x0b, 0x0c];
2669 db.create_attestation_key_entry(
2670 &public_key,
2671 &raw_public_key,
2672 &private_key,
2673 &KEYSTORE_UUID,
2674 )?;
2675 status = db.get_attestation_pool_status(0 /* expiration */, &KEYSTORE_UUID)?;
2676 assert_eq!(status.attested, 3);
2677 assert_eq!(status.unassigned, 0);
2678 assert_eq!(status.total, 4);
2679 db.store_signed_attestation_certificate_chain(
2680 &raw_public_key,
2681 &cert_chain,
2682 20,
2683 &KEYSTORE_UUID,
2684 )?;
2685 status = db.get_attestation_pool_status(0 /* expiration */, &KEYSTORE_UUID)?;
2686 assert_eq!(status.attested, 4);
2687 assert_eq!(status.unassigned, 1);
2688 assert_eq!(status.total, 4);
2689 Ok(())
2690 }
2691
2692 #[test]
2693 fn test_remove_expired_certs() -> Result<()> {
2694 let mut db = new_test_db()?;
2695 let expiration_date: i64 =
2696 SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_millis() as i64 + 10000;
2697 let namespace: i64 = 30;
2698 let namespace_del1: i64 = 45;
2699 let namespace_del2: i64 = 60;
2700 let entry_values = load_attestation_key_pool(
2701 &mut db,
2702 expiration_date,
2703 namespace,
2704 0x01, /* base_byte */
2705 )?;
2706 load_attestation_key_pool(&mut db, 45, namespace_del1, 0x02)?;
2707 load_attestation_key_pool(&mut db, 60, namespace_del2, 0x03)?;
2708 assert_eq!(db.delete_expired_attestation_keys()?, 2);
2709
2710 let mut cert_chain =
2711 db.retrieve_attestation_key_and_cert_chain(Domain::APP, namespace, &KEYSTORE_UUID)?;
2712 assert_eq!(true, cert_chain.is_some());
2713 let value = cert_chain.unwrap();
2714 assert_eq!(entry_values[1], value.cert_chain.to_vec());
2715 assert_eq!(entry_values[2], value.private_key.to_vec());
2716
2717 cert_chain = db.retrieve_attestation_key_and_cert_chain(
2718 Domain::APP,
2719 namespace_del1,
2720 &KEYSTORE_UUID,
2721 )?;
2722 assert_eq!(false, cert_chain.is_some());
2723 cert_chain = db.retrieve_attestation_key_and_cert_chain(
2724 Domain::APP,
2725 namespace_del2,
2726 &KEYSTORE_UUID,
2727 )?;
2728 assert_eq!(false, cert_chain.is_some());
2729
2730 let mut option_entry = db.get_unreferenced_key()?;
2731 assert_eq!(true, option_entry.is_some());
2732 let (key_guard, _) = option_entry.unwrap();
2733 db.purge_key_entry(key_guard)?;
2734
2735 option_entry = db.get_unreferenced_key()?;
2736 assert_eq!(true, option_entry.is_some());
2737 let (key_guard, _) = option_entry.unwrap();
2738 db.purge_key_entry(key_guard)?;
2739
2740 option_entry = db.get_unreferenced_key()?;
2741 assert_eq!(false, option_entry.is_some());
2742 Ok(())
2743 }
2744
2745 #[test]
Joel Galenson33c04ad2020-08-03 11:04:38 -07002746 fn test_rebind_alias() -> Result<()> {
Max Bires8e93d2b2021-01-14 13:17:59 -08002747 fn extractor(
2748 ke: &KeyEntryRow,
2749 ) -> (Option<Domain>, Option<i64>, Option<&str>, Option<Uuid>) {
2750 (ke.domain, ke.namespace, ke.alias.as_deref(), ke.km_uuid)
Joel Galenson33c04ad2020-08-03 11:04:38 -07002751 }
2752
Janis Danisevskis4df44f42020-08-26 14:40:03 -07002753 let mut db = new_test_db()?;
Max Bires8e93d2b2021-01-14 13:17:59 -08002754 db.create_key_entry(Domain::APP, 42, &KEYSTORE_UUID)?;
2755 db.create_key_entry(Domain::APP, 42, &KEYSTORE_UUID)?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07002756 let entries = get_keyentry(&db)?;
2757 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08002758 assert_eq!(
2759 extractor(&entries[0]),
2760 (Some(Domain::APP), Some(42), None, Some(KEYSTORE_UUID))
2761 );
2762 assert_eq!(
2763 extractor(&entries[1]),
2764 (Some(Domain::APP), Some(42), None, Some(KEYSTORE_UUID))
2765 );
Joel Galenson33c04ad2020-08-03 11:04:38 -07002766
2767 // Test that the first call to rebind_alias sets the alias.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002768 rebind_alias(&mut db, &KEY_ID_LOCK.get(entries[0].id), "foo", Domain::APP, 42)?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07002769 let entries = get_keyentry(&db)?;
2770 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08002771 assert_eq!(
2772 extractor(&entries[0]),
2773 (Some(Domain::APP), Some(42), Some("foo"), Some(KEYSTORE_UUID))
2774 );
2775 assert_eq!(
2776 extractor(&entries[1]),
2777 (Some(Domain::APP), Some(42), None, Some(KEYSTORE_UUID))
2778 );
Joel Galenson33c04ad2020-08-03 11:04:38 -07002779
2780 // Test that the second call to rebind_alias also empties the old one.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002781 rebind_alias(&mut db, &KEY_ID_LOCK.get(entries[1].id), "foo", Domain::APP, 42)?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07002782 let entries = get_keyentry(&db)?;
2783 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08002784 assert_eq!(extractor(&entries[0]), (None, None, None, Some(KEYSTORE_UUID)));
2785 assert_eq!(
2786 extractor(&entries[1]),
2787 (Some(Domain::APP), Some(42), Some("foo"), Some(KEYSTORE_UUID))
2788 );
Joel Galenson33c04ad2020-08-03 11:04:38 -07002789
2790 // Test that we must pass in a valid Domain.
2791 check_result_is_error_containing_string(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002792 rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::GRANT, 42),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002793 "Domain Domain(1) must be either App or SELinux.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07002794 );
2795 check_result_is_error_containing_string(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002796 rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::BLOB, 42),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002797 "Domain Domain(3) must be either App or SELinux.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07002798 );
2799 check_result_is_error_containing_string(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002800 rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::KEY_ID, 42),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002801 "Domain Domain(4) must be either App or SELinux.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07002802 );
2803
2804 // Test that we correctly handle setting an alias for something that does not exist.
2805 check_result_is_error_containing_string(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002806 rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::SELINUX, 42),
Joel Galenson33c04ad2020-08-03 11:04:38 -07002807 "Expected to update a single entry but instead updated 0",
2808 );
2809 // Test that we correctly abort the transaction in this case.
2810 let entries = get_keyentry(&db)?;
2811 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08002812 assert_eq!(extractor(&entries[0]), (None, None, None, Some(KEYSTORE_UUID)));
2813 assert_eq!(
2814 extractor(&entries[1]),
2815 (Some(Domain::APP), Some(42), Some("foo"), Some(KEYSTORE_UUID))
2816 );
Joel Galenson33c04ad2020-08-03 11:04:38 -07002817
2818 Ok(())
2819 }
2820
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002821 #[test]
2822 fn test_grant_ungrant() -> Result<()> {
2823 const CALLER_UID: u32 = 15;
2824 const GRANTEE_UID: u32 = 12;
2825 const SELINUX_NAMESPACE: i64 = 7;
2826
2827 let mut db = new_test_db()?;
2828 db.conn.execute(
Max Bires8e93d2b2021-01-14 13:17:59 -08002829 "INSERT INTO persistent.keyentry (id, key_type, domain, namespace, alias, state, km_uuid)
2830 VALUES (1, 0, 0, 15, 'key', 1, ?), (2, 0, 2, 7, 'yek', 1, ?);",
2831 params![KEYSTORE_UUID, KEYSTORE_UUID],
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002832 )?;
2833 let app_key = KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002834 domain: super::Domain::APP,
2835 nspace: 0,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002836 alias: Some("key".to_string()),
2837 blob: None,
2838 };
2839 const PVEC1: KeyPermSet = key_perm_set![KeyPerm::use_(), KeyPerm::get_info()];
2840 const PVEC2: KeyPermSet = key_perm_set![KeyPerm::use_()];
2841
2842 // Reset totally predictable random number generator in case we
2843 // are not the first test running on this thread.
2844 reset_random();
2845 let next_random = 0i64;
2846
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002847 let app_granted_key = db
2848 .grant(app_key.clone(), CALLER_UID, GRANTEE_UID, PVEC1, |k, a| {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002849 assert_eq!(*a, PVEC1);
2850 assert_eq!(
2851 *k,
2852 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002853 domain: super::Domain::APP,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002854 // namespace must be set to the caller_uid.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002855 nspace: CALLER_UID as i64,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002856 alias: Some("key".to_string()),
2857 blob: None,
2858 }
2859 );
2860 Ok(())
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002861 })
2862 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002863
2864 assert_eq!(
2865 app_granted_key,
2866 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002867 domain: super::Domain::GRANT,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002868 // The grantid is next_random due to the mock random number generator.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002869 nspace: next_random,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002870 alias: None,
2871 blob: None,
2872 }
2873 );
2874
2875 let selinux_key = KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002876 domain: super::Domain::SELINUX,
2877 nspace: SELINUX_NAMESPACE,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002878 alias: Some("yek".to_string()),
2879 blob: None,
2880 };
2881
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002882 let selinux_granted_key = db
2883 .grant(selinux_key.clone(), CALLER_UID, 12, PVEC1, |k, a| {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002884 assert_eq!(*a, PVEC1);
2885 assert_eq!(
2886 *k,
2887 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002888 domain: super::Domain::SELINUX,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002889 // namespace must be the supplied SELinux
2890 // namespace.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002891 nspace: SELINUX_NAMESPACE,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002892 alias: Some("yek".to_string()),
2893 blob: None,
2894 }
2895 );
2896 Ok(())
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002897 })
2898 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002899
2900 assert_eq!(
2901 selinux_granted_key,
2902 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002903 domain: super::Domain::GRANT,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002904 // The grantid is next_random + 1 due to the mock random number generator.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002905 nspace: next_random + 1,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002906 alias: None,
2907 blob: None,
2908 }
2909 );
2910
2911 // This should update the existing grant with PVEC2.
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002912 let selinux_granted_key = db
2913 .grant(selinux_key.clone(), CALLER_UID, 12, PVEC2, |k, a| {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002914 assert_eq!(*a, PVEC2);
2915 assert_eq!(
2916 *k,
2917 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002918 domain: super::Domain::SELINUX,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002919 // namespace must be the supplied SELinux
2920 // namespace.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002921 nspace: SELINUX_NAMESPACE,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002922 alias: Some("yek".to_string()),
2923 blob: None,
2924 }
2925 );
2926 Ok(())
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002927 })
2928 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002929
2930 assert_eq!(
2931 selinux_granted_key,
2932 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002933 domain: super::Domain::GRANT,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002934 // Same grant id as before. The entry was only updated.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002935 nspace: next_random + 1,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002936 alias: None,
2937 blob: None,
2938 }
2939 );
2940
2941 {
2942 // Limiting scope of stmt, because it borrows db.
2943 let mut stmt = db
2944 .conn
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002945 .prepare("SELECT id, grantee, keyentryid, access_vector FROM persistent.grant;")?;
Janis Danisevskisee10b5f2020-09-22 16:42:35 -07002946 let mut rows =
2947 stmt.query_map::<(i64, u32, i64, KeyPermSet), _, _>(NO_PARAMS, |row| {
2948 Ok((
2949 row.get(0)?,
2950 row.get(1)?,
2951 row.get(2)?,
2952 KeyPermSet::from(row.get::<_, i32>(3)?),
2953 ))
2954 })?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002955
2956 let r = rows.next().unwrap().unwrap();
Janis Danisevskisee10b5f2020-09-22 16:42:35 -07002957 assert_eq!(r, (next_random, GRANTEE_UID, 1, PVEC1));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002958 let r = rows.next().unwrap().unwrap();
Janis Danisevskisee10b5f2020-09-22 16:42:35 -07002959 assert_eq!(r, (next_random + 1, GRANTEE_UID, 2, PVEC2));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002960 assert!(rows.next().is_none());
2961 }
2962
2963 debug_dump_keyentry_table(&mut db)?;
2964 println!("app_key {:?}", app_key);
2965 println!("selinux_key {:?}", selinux_key);
2966
2967 db.ungrant(app_key, CALLER_UID, GRANTEE_UID, |_| Ok(()))?;
2968 db.ungrant(selinux_key, CALLER_UID, GRANTEE_UID, |_| Ok(()))?;
2969
2970 Ok(())
2971 }
2972
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002973 static TEST_KEY_BLOB: &[u8] = b"my test blob";
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002974 static TEST_CERT_BLOB: &[u8] = b"my test cert";
2975 static TEST_CERT_CHAIN_BLOB: &[u8] = b"my test cert_chain";
2976
2977 #[test]
Janis Danisevskis377d1002021-01-27 19:07:48 -08002978 fn test_set_blob() -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002979 let key_id = KEY_ID_LOCK.get(3000);
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002980 let mut db = new_test_db()?;
Janis Danisevskis377d1002021-01-27 19:07:48 -08002981 db.set_blob(&key_id, SubComponentType::KEY_BLOB, Some(TEST_KEY_BLOB))?;
2982 db.set_blob(&key_id, SubComponentType::CERT, Some(TEST_CERT_BLOB))?;
2983 db.set_blob(&key_id, SubComponentType::CERT_CHAIN, Some(TEST_CERT_CHAIN_BLOB))?;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002984 drop(key_id);
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002985
2986 let mut stmt = db.conn.prepare(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002987 "SELECT subcomponent_type, keyentryid, blob FROM persistent.blobentry
2988 ORDER BY subcomponent_type ASC;",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002989 )?;
2990 let mut rows = stmt
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002991 .query_map::<(SubComponentType, i64, Vec<u8>), _, _>(NO_PARAMS, |row| {
2992 Ok((row.get(0)?, row.get(1)?, row.get(2)?))
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002993 })?;
2994 let r = rows.next().unwrap().unwrap();
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002995 assert_eq!(r, (SubComponentType::KEY_BLOB, 3000, TEST_KEY_BLOB.to_vec()));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002996 let r = rows.next().unwrap().unwrap();
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002997 assert_eq!(r, (SubComponentType::CERT, 3000, TEST_CERT_BLOB.to_vec()));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002998 let r = rows.next().unwrap().unwrap();
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002999 assert_eq!(r, (SubComponentType::CERT_CHAIN, 3000, TEST_CERT_CHAIN_BLOB.to_vec()));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003000
3001 Ok(())
3002 }
3003
3004 static TEST_ALIAS: &str = "my super duper key";
3005
3006 #[test]
3007 fn test_insert_and_load_full_keyentry_domain_app() -> Result<()> {
3008 let mut db = new_test_db()?;
Qi Wub9433b52020-12-01 14:52:46 +08003009 let key_id = make_test_key_entry(&mut db, Domain::APP, 1, TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08003010 .context("test_insert_and_load_full_keyentry_domain_app")?
3011 .0;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003012 let (_key_guard, key_entry) = db
3013 .load_key_entry(
3014 KeyDescriptor {
3015 domain: Domain::APP,
3016 nspace: 0,
3017 alias: Some(TEST_ALIAS.to_string()),
3018 blob: None,
3019 },
3020 KeyType::Client,
3021 KeyEntryLoadBits::BOTH,
3022 1,
3023 |_k, _av| Ok(()),
3024 )
3025 .unwrap();
Qi Wub9433b52020-12-01 14:52:46 +08003026 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003027
3028 db.unbind_key(
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003029 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003030 domain: Domain::APP,
3031 nspace: 0,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003032 alias: Some(TEST_ALIAS.to_string()),
3033 blob: None,
3034 },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003035 KeyType::Client,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003036 1,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003037 |_, _| Ok(()),
3038 )
3039 .unwrap();
3040
3041 assert_eq!(
3042 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
3043 db.load_key_entry(
3044 KeyDescriptor {
3045 domain: Domain::APP,
3046 nspace: 0,
3047 alias: Some(TEST_ALIAS.to_string()),
3048 blob: None,
3049 },
3050 KeyType::Client,
3051 KeyEntryLoadBits::NONE,
3052 1,
3053 |_k, _av| Ok(()),
3054 )
3055 .unwrap_err()
3056 .root_cause()
3057 .downcast_ref::<KsError>()
3058 );
3059
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003060 Ok(())
3061 }
3062
3063 #[test]
Janis Danisevskis377d1002021-01-27 19:07:48 -08003064 fn test_insert_and_load_certificate_entry_domain_app() -> Result<()> {
3065 let mut db = new_test_db()?;
3066
3067 db.store_new_certificate(
3068 KeyDescriptor {
3069 domain: Domain::APP,
3070 nspace: 1,
3071 alias: Some(TEST_ALIAS.to_string()),
3072 blob: None,
3073 },
3074 TEST_CERT_BLOB,
Max Bires8e93d2b2021-01-14 13:17:59 -08003075 &KEYSTORE_UUID,
Janis Danisevskis377d1002021-01-27 19:07:48 -08003076 )
3077 .expect("Trying to insert cert.");
3078
3079 let (_key_guard, mut key_entry) = db
3080 .load_key_entry(
3081 KeyDescriptor {
3082 domain: Domain::APP,
3083 nspace: 1,
3084 alias: Some(TEST_ALIAS.to_string()),
3085 blob: None,
3086 },
3087 KeyType::Client,
3088 KeyEntryLoadBits::PUBLIC,
3089 1,
3090 |_k, _av| Ok(()),
3091 )
3092 .expect("Trying to read certificate entry.");
3093
3094 assert!(key_entry.pure_cert());
3095 assert!(key_entry.cert().is_none());
3096 assert_eq!(key_entry.take_cert_chain(), Some(TEST_CERT_BLOB.to_vec()));
3097
3098 db.unbind_key(
3099 KeyDescriptor {
3100 domain: Domain::APP,
3101 nspace: 1,
3102 alias: Some(TEST_ALIAS.to_string()),
3103 blob: None,
3104 },
3105 KeyType::Client,
3106 1,
3107 |_, _| Ok(()),
3108 )
3109 .unwrap();
3110
3111 assert_eq!(
3112 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
3113 db.load_key_entry(
3114 KeyDescriptor {
3115 domain: Domain::APP,
3116 nspace: 1,
3117 alias: Some(TEST_ALIAS.to_string()),
3118 blob: None,
3119 },
3120 KeyType::Client,
3121 KeyEntryLoadBits::NONE,
3122 1,
3123 |_k, _av| Ok(()),
3124 )
3125 .unwrap_err()
3126 .root_cause()
3127 .downcast_ref::<KsError>()
3128 );
3129
3130 Ok(())
3131 }
3132
3133 #[test]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003134 fn test_insert_and_load_full_keyentry_domain_selinux() -> Result<()> {
3135 let mut db = new_test_db()?;
Qi Wub9433b52020-12-01 14:52:46 +08003136 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08003137 .context("test_insert_and_load_full_keyentry_domain_selinux")?
3138 .0;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003139 let (_key_guard, key_entry) = db
3140 .load_key_entry(
3141 KeyDescriptor {
3142 domain: Domain::SELINUX,
3143 nspace: 1,
3144 alias: Some(TEST_ALIAS.to_string()),
3145 blob: None,
3146 },
3147 KeyType::Client,
3148 KeyEntryLoadBits::BOTH,
3149 1,
3150 |_k, _av| Ok(()),
3151 )
3152 .unwrap();
Qi Wub9433b52020-12-01 14:52:46 +08003153 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003154
3155 db.unbind_key(
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003156 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003157 domain: Domain::SELINUX,
3158 nspace: 1,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003159 alias: Some(TEST_ALIAS.to_string()),
3160 blob: None,
3161 },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003162 KeyType::Client,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003163 1,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003164 |_, _| Ok(()),
3165 )
3166 .unwrap();
3167
3168 assert_eq!(
3169 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
3170 db.load_key_entry(
3171 KeyDescriptor {
3172 domain: Domain::SELINUX,
3173 nspace: 1,
3174 alias: Some(TEST_ALIAS.to_string()),
3175 blob: None,
3176 },
3177 KeyType::Client,
3178 KeyEntryLoadBits::NONE,
3179 1,
3180 |_k, _av| Ok(()),
3181 )
3182 .unwrap_err()
3183 .root_cause()
3184 .downcast_ref::<KsError>()
3185 );
3186
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003187 Ok(())
3188 }
3189
3190 #[test]
3191 fn test_insert_and_load_full_keyentry_domain_key_id() -> Result<()> {
3192 let mut db = new_test_db()?;
Qi Wub9433b52020-12-01 14:52:46 +08003193 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08003194 .context("test_insert_and_load_full_keyentry_domain_key_id")?
3195 .0;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003196 let (_, key_entry) = db
3197 .load_key_entry(
3198 KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
3199 KeyType::Client,
3200 KeyEntryLoadBits::BOTH,
3201 1,
3202 |_k, _av| Ok(()),
3203 )
3204 .unwrap();
3205
Qi Wub9433b52020-12-01 14:52:46 +08003206 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003207
3208 db.unbind_key(
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003209 KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003210 KeyType::Client,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003211 1,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003212 |_, _| Ok(()),
3213 )
3214 .unwrap();
3215
3216 assert_eq!(
3217 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
3218 db.load_key_entry(
3219 KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
3220 KeyType::Client,
3221 KeyEntryLoadBits::NONE,
3222 1,
3223 |_k, _av| Ok(()),
3224 )
3225 .unwrap_err()
3226 .root_cause()
3227 .downcast_ref::<KsError>()
3228 );
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003229
3230 Ok(())
3231 }
3232
3233 #[test]
Qi Wub9433b52020-12-01 14:52:46 +08003234 fn test_check_and_update_key_usage_count_with_limited_use_key() -> Result<()> {
3235 let mut db = new_test_db()?;
3236 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, Some(123))
3237 .context("test_check_and_update_key_usage_count_with_limited_use_key")?
3238 .0;
3239 // Update the usage count of the limited use key.
3240 db.check_and_update_key_usage_count(key_id)?;
3241
3242 let (_key_guard, key_entry) = db.load_key_entry(
3243 KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
3244 KeyType::Client,
3245 KeyEntryLoadBits::BOTH,
3246 1,
3247 |_k, _av| Ok(()),
3248 )?;
3249
3250 // The usage count is decremented now.
3251 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, Some(122)));
3252
3253 Ok(())
3254 }
3255
3256 #[test]
3257 fn test_check_and_update_key_usage_count_with_exhausted_limited_use_key() -> Result<()> {
3258 let mut db = new_test_db()?;
3259 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, Some(1))
3260 .context("test_check_and_update_key_usage_count_with_exhausted_limited_use_key")?
3261 .0;
3262 // Update the usage count of the limited use key.
3263 db.check_and_update_key_usage_count(key_id).expect(concat!(
3264 "In test_check_and_update_key_usage_count_with_exhausted_limited_use_key: ",
3265 "This should succeed."
3266 ));
3267
3268 // Try to update the exhausted limited use key.
3269 let e = db.check_and_update_key_usage_count(key_id).expect_err(concat!(
3270 "In test_check_and_update_key_usage_count_with_exhausted_limited_use_key: ",
3271 "This should fail."
3272 ));
3273 assert_eq!(
3274 &KsError::Km(ErrorCode::INVALID_KEY_BLOB),
3275 e.root_cause().downcast_ref::<KsError>().unwrap()
3276 );
3277
3278 Ok(())
3279 }
3280
3281 #[test]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003282 fn test_insert_and_load_full_keyentry_from_grant() -> Result<()> {
3283 let mut db = new_test_db()?;
Qi Wub9433b52020-12-01 14:52:46 +08003284 let key_id = make_test_key_entry(&mut db, Domain::APP, 1, TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08003285 .context("test_insert_and_load_full_keyentry_from_grant")?
3286 .0;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003287
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003288 let granted_key = db
3289 .grant(
3290 KeyDescriptor {
3291 domain: Domain::APP,
3292 nspace: 0,
3293 alias: Some(TEST_ALIAS.to_string()),
3294 blob: None,
3295 },
3296 1,
3297 2,
3298 key_perm_set![KeyPerm::use_()],
3299 |_k, _av| Ok(()),
3300 )
3301 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003302
3303 debug_dump_grant_table(&mut db)?;
3304
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003305 let (_key_guard, key_entry) = db
3306 .load_key_entry(
3307 granted_key.clone(),
3308 KeyType::Client,
3309 KeyEntryLoadBits::BOTH,
3310 2,
3311 |k, av| {
3312 assert_eq!(Domain::GRANT, k.domain);
3313 assert!(av.unwrap().includes(KeyPerm::use_()));
3314 Ok(())
3315 },
3316 )
3317 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003318
Qi Wub9433b52020-12-01 14:52:46 +08003319 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003320
3321 db.unbind_key(granted_key.clone(), KeyType::Client, 2, |_, _| Ok(())).unwrap();
3322
3323 assert_eq!(
3324 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
3325 db.load_key_entry(
3326 granted_key,
3327 KeyType::Client,
3328 KeyEntryLoadBits::NONE,
3329 2,
3330 |_k, _av| Ok(()),
3331 )
3332 .unwrap_err()
3333 .root_cause()
3334 .downcast_ref::<KsError>()
3335 );
3336
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003337 Ok(())
3338 }
3339
Janis Danisevskis45760022021-01-19 16:34:10 -08003340 // This test attempts to load a key by key id while the caller is not the owner
3341 // but a grant exists for the given key and the caller.
3342 #[test]
3343 fn test_insert_and_load_full_keyentry_from_grant_by_key_id() -> Result<()> {
3344 let mut db = new_test_db()?;
3345 const OWNER_UID: u32 = 1u32;
3346 const GRANTEE_UID: u32 = 2u32;
3347 const SOMEONE_ELSE_UID: u32 = 3u32;
3348 let key_id = make_test_key_entry(&mut db, Domain::APP, OWNER_UID as i64, TEST_ALIAS, None)
3349 .context("test_insert_and_load_full_keyentry_from_grant_by_key_id")?
3350 .0;
3351
3352 db.grant(
3353 KeyDescriptor {
3354 domain: Domain::APP,
3355 nspace: 0,
3356 alias: Some(TEST_ALIAS.to_string()),
3357 blob: None,
3358 },
3359 OWNER_UID,
3360 GRANTEE_UID,
3361 key_perm_set![KeyPerm::use_()],
3362 |_k, _av| Ok(()),
3363 )
3364 .unwrap();
3365
3366 debug_dump_grant_table(&mut db)?;
3367
3368 let id_descriptor =
3369 KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, ..Default::default() };
3370
3371 let (_, key_entry) = db
3372 .load_key_entry(
3373 id_descriptor.clone(),
3374 KeyType::Client,
3375 KeyEntryLoadBits::BOTH,
3376 GRANTEE_UID,
3377 |k, av| {
3378 assert_eq!(Domain::APP, k.domain);
3379 assert_eq!(OWNER_UID as i64, k.nspace);
3380 assert!(av.unwrap().includes(KeyPerm::use_()));
3381 Ok(())
3382 },
3383 )
3384 .unwrap();
3385
3386 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
3387
3388 let (_, key_entry) = db
3389 .load_key_entry(
3390 id_descriptor.clone(),
3391 KeyType::Client,
3392 KeyEntryLoadBits::BOTH,
3393 SOMEONE_ELSE_UID,
3394 |k, av| {
3395 assert_eq!(Domain::APP, k.domain);
3396 assert_eq!(OWNER_UID as i64, k.nspace);
3397 assert!(av.is_none());
3398 Ok(())
3399 },
3400 )
3401 .unwrap();
3402
3403 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
3404
3405 db.unbind_key(id_descriptor.clone(), KeyType::Client, OWNER_UID, |_, _| Ok(())).unwrap();
3406
3407 assert_eq!(
3408 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
3409 db.load_key_entry(
3410 id_descriptor,
3411 KeyType::Client,
3412 KeyEntryLoadBits::NONE,
3413 GRANTEE_UID,
3414 |_k, _av| Ok(()),
3415 )
3416 .unwrap_err()
3417 .root_cause()
3418 .downcast_ref::<KsError>()
3419 );
3420
3421 Ok(())
3422 }
3423
Janis Danisevskisaec14592020-11-12 09:41:49 -08003424 static KEY_LOCK_TEST_ALIAS: &str = "my super duper locked key";
3425
Janis Danisevskisaec14592020-11-12 09:41:49 -08003426 #[test]
3427 fn test_insert_and_load_full_keyentry_domain_app_concurrently() -> Result<()> {
3428 let handle = {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08003429 let temp_dir = Arc::new(TempDir::new("id_lock_test")?);
3430 let temp_dir_clone = temp_dir.clone();
3431 let mut db = KeystoreDB::new(temp_dir.path())?;
Qi Wub9433b52020-12-01 14:52:46 +08003432 let key_id = make_test_key_entry(&mut db, Domain::APP, 33, KEY_LOCK_TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08003433 .context("test_insert_and_load_full_keyentry_domain_app")?
3434 .0;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003435 let (_key_guard, key_entry) = db
3436 .load_key_entry(
3437 KeyDescriptor {
3438 domain: Domain::APP,
3439 nspace: 0,
3440 alias: Some(KEY_LOCK_TEST_ALIAS.to_string()),
3441 blob: None,
3442 },
3443 KeyType::Client,
3444 KeyEntryLoadBits::BOTH,
3445 33,
3446 |_k, _av| Ok(()),
3447 )
3448 .unwrap();
Qi Wub9433b52020-12-01 14:52:46 +08003449 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskisaec14592020-11-12 09:41:49 -08003450 let state = Arc::new(AtomicU8::new(1));
3451 let state2 = state.clone();
3452
3453 // Spawning a second thread that attempts to acquire the key id lock
3454 // for the same key as the primary thread. The primary thread then
3455 // waits, thereby forcing the secondary thread into the second stage
3456 // of acquiring the lock (see KEY ID LOCK 2/2 above).
3457 // The test succeeds if the secondary thread observes the transition
3458 // of `state` from 1 to 2, despite having a whole second to overtake
3459 // the primary thread.
3460 let handle = thread::spawn(move || {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08003461 let temp_dir = temp_dir_clone;
3462 let mut db = KeystoreDB::new(temp_dir.path()).unwrap();
Janis Danisevskisaec14592020-11-12 09:41:49 -08003463 assert!(db
3464 .load_key_entry(
3465 KeyDescriptor {
3466 domain: Domain::APP,
3467 nspace: 0,
3468 alias: Some(KEY_LOCK_TEST_ALIAS.to_string()),
3469 blob: None,
3470 },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003471 KeyType::Client,
Janis Danisevskisaec14592020-11-12 09:41:49 -08003472 KeyEntryLoadBits::BOTH,
3473 33,
3474 |_k, _av| Ok(()),
3475 )
3476 .is_ok());
3477 // We should only see a 2 here because we can only return
3478 // from load_key_entry when the `_key_guard` expires,
3479 // which happens at the end of the scope.
3480 assert_eq!(2, state2.load(Ordering::Relaxed));
3481 });
3482
3483 thread::sleep(std::time::Duration::from_millis(1000));
3484
3485 assert_eq!(Ok(1), state.compare_exchange(1, 2, Ordering::Relaxed, Ordering::Relaxed));
3486
3487 // Return the handle from this scope so we can join with the
3488 // secondary thread after the key id lock has expired.
3489 handle
3490 // This is where the `_key_guard` goes out of scope,
3491 // which is the reason for concurrent load_key_entry on the same key
3492 // to unblock.
3493 };
3494 // Join with the secondary thread and unwrap, to propagate failing asserts to the
3495 // main test thread. We will not see failing asserts in secondary threads otherwise.
3496 handle.join().unwrap();
3497 Ok(())
3498 }
3499
Janis Danisevskise92a5e62020-12-02 12:57:41 -08003500 #[test]
3501 fn list() -> Result<()> {
3502 let temp_dir = TempDir::new("list_test")?;
3503 let mut db = KeystoreDB::new(temp_dir.path())?;
3504 static LIST_O_ENTRIES: &[(Domain, i64, &str)] = &[
3505 (Domain::APP, 1, "test1"),
3506 (Domain::APP, 1, "test2"),
3507 (Domain::APP, 1, "test3"),
3508 (Domain::APP, 1, "test4"),
3509 (Domain::APP, 1, "test5"),
3510 (Domain::APP, 1, "test6"),
3511 (Domain::APP, 1, "test7"),
3512 (Domain::APP, 2, "test1"),
3513 (Domain::APP, 2, "test2"),
3514 (Domain::APP, 2, "test3"),
3515 (Domain::APP, 2, "test4"),
3516 (Domain::APP, 2, "test5"),
3517 (Domain::APP, 2, "test6"),
3518 (Domain::APP, 2, "test8"),
3519 (Domain::SELINUX, 100, "test1"),
3520 (Domain::SELINUX, 100, "test2"),
3521 (Domain::SELINUX, 100, "test3"),
3522 (Domain::SELINUX, 100, "test4"),
3523 (Domain::SELINUX, 100, "test5"),
3524 (Domain::SELINUX, 100, "test6"),
3525 (Domain::SELINUX, 100, "test9"),
3526 ];
3527
3528 let list_o_keys: Vec<(i64, i64)> = LIST_O_ENTRIES
3529 .iter()
3530 .map(|(domain, ns, alias)| {
Qi Wub9433b52020-12-01 14:52:46 +08003531 let entry = make_test_key_entry(&mut db, *domain, *ns, *alias, None)
3532 .unwrap_or_else(|e| {
Janis Danisevskise92a5e62020-12-02 12:57:41 -08003533 panic!("Failed to insert {:?} {} {}. Error {:?}", domain, ns, alias, e)
3534 });
3535 (entry.id(), *ns)
3536 })
3537 .collect();
3538
3539 for (domain, namespace) in
3540 &[(Domain::APP, 1i64), (Domain::APP, 2i64), (Domain::SELINUX, 100i64)]
3541 {
3542 let mut list_o_descriptors: Vec<KeyDescriptor> = LIST_O_ENTRIES
3543 .iter()
3544 .filter_map(|(domain, ns, alias)| match ns {
3545 ns if *ns == *namespace => Some(KeyDescriptor {
3546 domain: *domain,
3547 nspace: *ns,
3548 alias: Some(alias.to_string()),
3549 blob: None,
3550 }),
3551 _ => None,
3552 })
3553 .collect();
3554 list_o_descriptors.sort();
3555 let mut list_result = db.list(*domain, *namespace)?;
3556 list_result.sort();
3557 assert_eq!(list_o_descriptors, list_result);
3558
3559 let mut list_o_ids: Vec<i64> = list_o_descriptors
3560 .into_iter()
3561 .map(|d| {
3562 let (_, entry) = db
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003563 .load_key_entry(
3564 d,
3565 KeyType::Client,
3566 KeyEntryLoadBits::NONE,
3567 *namespace as u32,
3568 |_, _| Ok(()),
3569 )
Janis Danisevskise92a5e62020-12-02 12:57:41 -08003570 .unwrap();
3571 entry.id()
3572 })
3573 .collect();
3574 list_o_ids.sort_unstable();
3575 let mut loaded_entries: Vec<i64> = list_o_keys
3576 .iter()
3577 .filter_map(|(id, ns)| match ns {
3578 ns if *ns == *namespace => Some(*id),
3579 _ => None,
3580 })
3581 .collect();
3582 loaded_entries.sort_unstable();
3583 assert_eq!(list_o_ids, loaded_entries);
3584 }
3585 assert_eq!(Vec::<KeyDescriptor>::new(), db.list(Domain::SELINUX, 101)?);
3586
3587 Ok(())
3588 }
3589
Joel Galenson0891bc12020-07-20 10:37:03 -07003590 // Helpers
3591
3592 // Checks that the given result is an error containing the given string.
3593 fn check_result_is_error_containing_string<T>(result: Result<T>, target: &str) {
3594 let error_str = format!(
3595 "{:#?}",
3596 result.err().unwrap_or_else(|| panic!("Expected the error: {}", target))
3597 );
3598 assert!(
3599 error_str.contains(target),
3600 "The string \"{}\" should contain \"{}\"",
3601 error_str,
3602 target
3603 );
3604 }
3605
Joel Galenson2aab4432020-07-22 15:27:57 -07003606 #[derive(Debug, PartialEq)]
Joel Galenson0891bc12020-07-20 10:37:03 -07003607 #[allow(dead_code)]
3608 struct KeyEntryRow {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003609 id: i64,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003610 key_type: KeyType,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003611 domain: Option<Domain>,
Joel Galenson0891bc12020-07-20 10:37:03 -07003612 namespace: Option<i64>,
3613 alias: Option<String>,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003614 state: KeyLifeCycle,
Max Bires8e93d2b2021-01-14 13:17:59 -08003615 km_uuid: Option<Uuid>,
Joel Galenson0891bc12020-07-20 10:37:03 -07003616 }
3617
3618 fn get_keyentry(db: &KeystoreDB) -> Result<Vec<KeyEntryRow>> {
3619 db.conn
Joel Galenson2aab4432020-07-22 15:27:57 -07003620 .prepare("SELECT * FROM persistent.keyentry;")?
Joel Galenson0891bc12020-07-20 10:37:03 -07003621 .query_map(NO_PARAMS, |row| {
Joel Galenson0891bc12020-07-20 10:37:03 -07003622 Ok(KeyEntryRow {
3623 id: row.get(0)?,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003624 key_type: row.get(1)?,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003625 domain: match row.get(2)? {
3626 Some(i) => Some(Domain(i)),
3627 None => None,
3628 },
Joel Galenson0891bc12020-07-20 10:37:03 -07003629 namespace: row.get(3)?,
3630 alias: row.get(4)?,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003631 state: row.get(5)?,
Max Bires8e93d2b2021-01-14 13:17:59 -08003632 km_uuid: row.get(6)?,
Joel Galenson0891bc12020-07-20 10:37:03 -07003633 })
3634 })?
3635 .map(|r| r.context("Could not read keyentry row."))
3636 .collect::<Result<Vec<_>>>()
3637 }
3638
Max Bires2b2e6562020-09-22 11:22:36 -07003639 fn load_attestation_key_pool(
3640 db: &mut KeystoreDB,
3641 expiration_date: i64,
3642 namespace: i64,
3643 base_byte: u8,
3644 ) -> Result<Vec<Vec<u8>>> {
3645 let mut chain: Vec<Vec<u8>> = Vec::new();
3646 let public_key: Vec<u8> = vec![base_byte, 0x02 * base_byte];
3647 let cert_chain: Vec<u8> = vec![0x03 * base_byte, 0x04 * base_byte];
3648 let priv_key: Vec<u8> = vec![0x05 * base_byte, 0x06 * base_byte];
3649 let raw_public_key: Vec<u8> = vec![0x0b * base_byte, 0x0c * base_byte];
3650 db.create_attestation_key_entry(&public_key, &raw_public_key, &priv_key, &KEYSTORE_UUID)?;
3651 db.store_signed_attestation_certificate_chain(
3652 &raw_public_key,
3653 &cert_chain,
3654 expiration_date,
3655 &KEYSTORE_UUID,
3656 )?;
3657 db.assign_attestation_key(Domain::APP, namespace, &KEYSTORE_UUID)?;
3658 chain.push(public_key);
3659 chain.push(cert_chain);
3660 chain.push(priv_key);
3661 chain.push(raw_public_key);
3662 Ok(chain)
3663 }
3664
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07003665 // Note: The parameters and SecurityLevel associations are nonsensical. This
3666 // collection is only used to check if the parameters are preserved as expected by the
3667 // database.
Qi Wub9433b52020-12-01 14:52:46 +08003668 fn make_test_params(max_usage_count: Option<i32>) -> Vec<KeyParameter> {
3669 let mut params = vec![
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07003670 KeyParameter::new(KeyParameterValue::Invalid, SecurityLevel::TRUSTED_ENVIRONMENT),
3671 KeyParameter::new(
3672 KeyParameterValue::KeyPurpose(KeyPurpose::SIGN),
3673 SecurityLevel::TRUSTED_ENVIRONMENT,
3674 ),
3675 KeyParameter::new(
3676 KeyParameterValue::KeyPurpose(KeyPurpose::DECRYPT),
3677 SecurityLevel::TRUSTED_ENVIRONMENT,
3678 ),
3679 KeyParameter::new(
3680 KeyParameterValue::Algorithm(Algorithm::RSA),
3681 SecurityLevel::TRUSTED_ENVIRONMENT,
3682 ),
3683 KeyParameter::new(KeyParameterValue::KeySize(1024), SecurityLevel::TRUSTED_ENVIRONMENT),
3684 KeyParameter::new(
3685 KeyParameterValue::BlockMode(BlockMode::ECB),
3686 SecurityLevel::TRUSTED_ENVIRONMENT,
3687 ),
3688 KeyParameter::new(
3689 KeyParameterValue::BlockMode(BlockMode::GCM),
3690 SecurityLevel::TRUSTED_ENVIRONMENT,
3691 ),
3692 KeyParameter::new(KeyParameterValue::Digest(Digest::NONE), SecurityLevel::STRONGBOX),
3693 KeyParameter::new(
3694 KeyParameterValue::Digest(Digest::MD5),
3695 SecurityLevel::TRUSTED_ENVIRONMENT,
3696 ),
3697 KeyParameter::new(
3698 KeyParameterValue::Digest(Digest::SHA_2_224),
3699 SecurityLevel::TRUSTED_ENVIRONMENT,
3700 ),
3701 KeyParameter::new(
3702 KeyParameterValue::Digest(Digest::SHA_2_256),
3703 SecurityLevel::STRONGBOX,
3704 ),
3705 KeyParameter::new(
3706 KeyParameterValue::PaddingMode(PaddingMode::NONE),
3707 SecurityLevel::TRUSTED_ENVIRONMENT,
3708 ),
3709 KeyParameter::new(
3710 KeyParameterValue::PaddingMode(PaddingMode::RSA_OAEP),
3711 SecurityLevel::TRUSTED_ENVIRONMENT,
3712 ),
3713 KeyParameter::new(
3714 KeyParameterValue::PaddingMode(PaddingMode::RSA_PSS),
3715 SecurityLevel::STRONGBOX,
3716 ),
3717 KeyParameter::new(
3718 KeyParameterValue::PaddingMode(PaddingMode::RSA_PKCS1_1_5_SIGN),
3719 SecurityLevel::TRUSTED_ENVIRONMENT,
3720 ),
3721 KeyParameter::new(KeyParameterValue::CallerNonce, SecurityLevel::TRUSTED_ENVIRONMENT),
3722 KeyParameter::new(KeyParameterValue::MinMacLength(256), SecurityLevel::STRONGBOX),
3723 KeyParameter::new(
3724 KeyParameterValue::EcCurve(EcCurve::P_224),
3725 SecurityLevel::TRUSTED_ENVIRONMENT,
3726 ),
3727 KeyParameter::new(KeyParameterValue::EcCurve(EcCurve::P_256), SecurityLevel::STRONGBOX),
3728 KeyParameter::new(
3729 KeyParameterValue::EcCurve(EcCurve::P_384),
3730 SecurityLevel::TRUSTED_ENVIRONMENT,
3731 ),
3732 KeyParameter::new(
3733 KeyParameterValue::EcCurve(EcCurve::P_521),
3734 SecurityLevel::TRUSTED_ENVIRONMENT,
3735 ),
3736 KeyParameter::new(
3737 KeyParameterValue::RSAPublicExponent(3),
3738 SecurityLevel::TRUSTED_ENVIRONMENT,
3739 ),
3740 KeyParameter::new(
3741 KeyParameterValue::IncludeUniqueID,
3742 SecurityLevel::TRUSTED_ENVIRONMENT,
3743 ),
3744 KeyParameter::new(KeyParameterValue::BootLoaderOnly, SecurityLevel::STRONGBOX),
3745 KeyParameter::new(KeyParameterValue::RollbackResistance, SecurityLevel::STRONGBOX),
3746 KeyParameter::new(
3747 KeyParameterValue::ActiveDateTime(1234567890),
3748 SecurityLevel::STRONGBOX,
3749 ),
3750 KeyParameter::new(
3751 KeyParameterValue::OriginationExpireDateTime(1234567890),
3752 SecurityLevel::TRUSTED_ENVIRONMENT,
3753 ),
3754 KeyParameter::new(
3755 KeyParameterValue::UsageExpireDateTime(1234567890),
3756 SecurityLevel::TRUSTED_ENVIRONMENT,
3757 ),
3758 KeyParameter::new(
3759 KeyParameterValue::MinSecondsBetweenOps(1234567890),
3760 SecurityLevel::TRUSTED_ENVIRONMENT,
3761 ),
3762 KeyParameter::new(
3763 KeyParameterValue::MaxUsesPerBoot(1234567890),
3764 SecurityLevel::TRUSTED_ENVIRONMENT,
3765 ),
3766 KeyParameter::new(KeyParameterValue::UserID(1), SecurityLevel::STRONGBOX),
3767 KeyParameter::new(KeyParameterValue::UserSecureID(42), SecurityLevel::STRONGBOX),
3768 KeyParameter::new(
3769 KeyParameterValue::NoAuthRequired,
3770 SecurityLevel::TRUSTED_ENVIRONMENT,
3771 ),
3772 KeyParameter::new(
3773 KeyParameterValue::HardwareAuthenticatorType(HardwareAuthenticatorType::PASSWORD),
3774 SecurityLevel::TRUSTED_ENVIRONMENT,
3775 ),
3776 KeyParameter::new(KeyParameterValue::AuthTimeout(1234567890), SecurityLevel::SOFTWARE),
3777 KeyParameter::new(KeyParameterValue::AllowWhileOnBody, SecurityLevel::SOFTWARE),
3778 KeyParameter::new(
3779 KeyParameterValue::TrustedUserPresenceRequired,
3780 SecurityLevel::TRUSTED_ENVIRONMENT,
3781 ),
3782 KeyParameter::new(
3783 KeyParameterValue::TrustedConfirmationRequired,
3784 SecurityLevel::TRUSTED_ENVIRONMENT,
3785 ),
3786 KeyParameter::new(
3787 KeyParameterValue::UnlockedDeviceRequired,
3788 SecurityLevel::TRUSTED_ENVIRONMENT,
3789 ),
3790 KeyParameter::new(
3791 KeyParameterValue::ApplicationID(vec![1u8, 2u8, 3u8, 4u8]),
3792 SecurityLevel::SOFTWARE,
3793 ),
3794 KeyParameter::new(
3795 KeyParameterValue::ApplicationData(vec![4u8, 3u8, 2u8, 1u8]),
3796 SecurityLevel::SOFTWARE,
3797 ),
3798 KeyParameter::new(
3799 KeyParameterValue::CreationDateTime(12345677890),
3800 SecurityLevel::SOFTWARE,
3801 ),
3802 KeyParameter::new(
3803 KeyParameterValue::KeyOrigin(KeyOrigin::GENERATED),
3804 SecurityLevel::TRUSTED_ENVIRONMENT,
3805 ),
3806 KeyParameter::new(
3807 KeyParameterValue::RootOfTrust(vec![3u8, 2u8, 1u8, 4u8]),
3808 SecurityLevel::TRUSTED_ENVIRONMENT,
3809 ),
3810 KeyParameter::new(KeyParameterValue::OSVersion(1), SecurityLevel::TRUSTED_ENVIRONMENT),
3811 KeyParameter::new(KeyParameterValue::OSPatchLevel(2), SecurityLevel::SOFTWARE),
3812 KeyParameter::new(
3813 KeyParameterValue::UniqueID(vec![4u8, 3u8, 1u8, 2u8]),
3814 SecurityLevel::SOFTWARE,
3815 ),
3816 KeyParameter::new(
3817 KeyParameterValue::AttestationChallenge(vec![4u8, 3u8, 1u8, 2u8]),
3818 SecurityLevel::TRUSTED_ENVIRONMENT,
3819 ),
3820 KeyParameter::new(
3821 KeyParameterValue::AttestationApplicationID(vec![4u8, 3u8, 1u8, 2u8]),
3822 SecurityLevel::TRUSTED_ENVIRONMENT,
3823 ),
3824 KeyParameter::new(
3825 KeyParameterValue::AttestationIdBrand(vec![4u8, 3u8, 1u8, 2u8]),
3826 SecurityLevel::TRUSTED_ENVIRONMENT,
3827 ),
3828 KeyParameter::new(
3829 KeyParameterValue::AttestationIdDevice(vec![4u8, 3u8, 1u8, 2u8]),
3830 SecurityLevel::TRUSTED_ENVIRONMENT,
3831 ),
3832 KeyParameter::new(
3833 KeyParameterValue::AttestationIdProduct(vec![4u8, 3u8, 1u8, 2u8]),
3834 SecurityLevel::TRUSTED_ENVIRONMENT,
3835 ),
3836 KeyParameter::new(
3837 KeyParameterValue::AttestationIdSerial(vec![4u8, 3u8, 1u8, 2u8]),
3838 SecurityLevel::TRUSTED_ENVIRONMENT,
3839 ),
3840 KeyParameter::new(
3841 KeyParameterValue::AttestationIdIMEI(vec![4u8, 3u8, 1u8, 2u8]),
3842 SecurityLevel::TRUSTED_ENVIRONMENT,
3843 ),
3844 KeyParameter::new(
3845 KeyParameterValue::AttestationIdMEID(vec![4u8, 3u8, 1u8, 2u8]),
3846 SecurityLevel::TRUSTED_ENVIRONMENT,
3847 ),
3848 KeyParameter::new(
3849 KeyParameterValue::AttestationIdManufacturer(vec![4u8, 3u8, 1u8, 2u8]),
3850 SecurityLevel::TRUSTED_ENVIRONMENT,
3851 ),
3852 KeyParameter::new(
3853 KeyParameterValue::AttestationIdModel(vec![4u8, 3u8, 1u8, 2u8]),
3854 SecurityLevel::TRUSTED_ENVIRONMENT,
3855 ),
3856 KeyParameter::new(
3857 KeyParameterValue::VendorPatchLevel(3),
3858 SecurityLevel::TRUSTED_ENVIRONMENT,
3859 ),
3860 KeyParameter::new(
3861 KeyParameterValue::BootPatchLevel(4),
3862 SecurityLevel::TRUSTED_ENVIRONMENT,
3863 ),
3864 KeyParameter::new(
3865 KeyParameterValue::AssociatedData(vec![4u8, 3u8, 1u8, 2u8]),
3866 SecurityLevel::TRUSTED_ENVIRONMENT,
3867 ),
3868 KeyParameter::new(
3869 KeyParameterValue::Nonce(vec![4u8, 3u8, 1u8, 2u8]),
3870 SecurityLevel::TRUSTED_ENVIRONMENT,
3871 ),
3872 KeyParameter::new(
3873 KeyParameterValue::MacLength(256),
3874 SecurityLevel::TRUSTED_ENVIRONMENT,
3875 ),
3876 KeyParameter::new(
3877 KeyParameterValue::ResetSinceIdRotation,
3878 SecurityLevel::TRUSTED_ENVIRONMENT,
3879 ),
3880 KeyParameter::new(
3881 KeyParameterValue::ConfirmationToken(vec![5u8, 5u8, 5u8, 5u8]),
3882 SecurityLevel::TRUSTED_ENVIRONMENT,
3883 ),
Qi Wub9433b52020-12-01 14:52:46 +08003884 ];
3885 if let Some(value) = max_usage_count {
3886 params.push(KeyParameter::new(
3887 KeyParameterValue::UsageCountLimit(value),
3888 SecurityLevel::SOFTWARE,
3889 ));
3890 }
3891 params
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07003892 }
3893
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003894 fn make_test_key_entry(
3895 db: &mut KeystoreDB,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003896 domain: Domain,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003897 namespace: i64,
3898 alias: &str,
Qi Wub9433b52020-12-01 14:52:46 +08003899 max_usage_count: Option<i32>,
Janis Danisevskisaec14592020-11-12 09:41:49 -08003900 ) -> Result<KeyIdGuard> {
Max Bires8e93d2b2021-01-14 13:17:59 -08003901 let key_id = db.create_key_entry(domain, namespace, &KEYSTORE_UUID)?;
Janis Danisevskis377d1002021-01-27 19:07:48 -08003902 db.set_blob(&key_id, SubComponentType::KEY_BLOB, Some(TEST_KEY_BLOB))?;
3903 db.set_blob(&key_id, SubComponentType::CERT, Some(TEST_CERT_BLOB))?;
3904 db.set_blob(&key_id, SubComponentType::CERT_CHAIN, Some(TEST_CERT_CHAIN_BLOB))?;
Qi Wub9433b52020-12-01 14:52:46 +08003905
3906 let params = make_test_params(max_usage_count);
3907 db.insert_keyparameter(&key_id, &params)?;
3908
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003909 let mut metadata = KeyMetaData::new();
3910 metadata.add(KeyMetaEntry::EncryptedBy(EncryptedBy::Password));
3911 metadata.add(KeyMetaEntry::Salt(vec![1, 2, 3]));
3912 metadata.add(KeyMetaEntry::Iv(vec![2, 3, 1]));
3913 metadata.add(KeyMetaEntry::AeadTag(vec![3, 1, 2]));
3914 db.insert_key_metadata(&key_id, &metadata)?;
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003915 rebind_alias(db, &key_id, alias, domain, namespace)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003916 Ok(key_id)
3917 }
3918
Qi Wub9433b52020-12-01 14:52:46 +08003919 fn make_test_key_entry_test_vector(key_id: i64, max_usage_count: Option<i32>) -> KeyEntry {
3920 let params = make_test_params(max_usage_count);
3921
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003922 let mut metadata = KeyMetaData::new();
3923 metadata.add(KeyMetaEntry::EncryptedBy(EncryptedBy::Password));
3924 metadata.add(KeyMetaEntry::Salt(vec![1, 2, 3]));
3925 metadata.add(KeyMetaEntry::Iv(vec![2, 3, 1]));
3926 metadata.add(KeyMetaEntry::AeadTag(vec![3, 1, 2]));
3927
3928 KeyEntry {
3929 id: key_id,
3930 km_blob: Some(TEST_KEY_BLOB.to_vec()),
3931 cert: Some(TEST_CERT_BLOB.to_vec()),
3932 cert_chain: Some(TEST_CERT_CHAIN_BLOB.to_vec()),
Max Bires8e93d2b2021-01-14 13:17:59 -08003933 km_uuid: KEYSTORE_UUID,
Qi Wub9433b52020-12-01 14:52:46 +08003934 parameters: params,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003935 metadata,
Janis Danisevskis377d1002021-01-27 19:07:48 -08003936 pure_cert: false,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003937 }
3938 }
3939
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003940 fn debug_dump_keyentry_table(db: &mut KeystoreDB) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003941 let mut stmt = db.conn.prepare(
Max Bires8e93d2b2021-01-14 13:17:59 -08003942 "SELECT id, key_type, domain, namespace, alias, state, km_uuid FROM persistent.keyentry;",
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003943 )?;
Max Bires8e93d2b2021-01-14 13:17:59 -08003944 let rows = stmt.query_map::<(i64, KeyType, i32, i64, String, KeyLifeCycle, Uuid), _, _>(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003945 NO_PARAMS,
3946 |row| {
Max Bires8e93d2b2021-01-14 13:17:59 -08003947 Ok((
3948 row.get(0)?,
3949 row.get(1)?,
3950 row.get(2)?,
3951 row.get(3)?,
3952 row.get(4)?,
3953 row.get(5)?,
3954 row.get(6)?,
3955 ))
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003956 },
3957 )?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003958
3959 println!("Key entry table rows:");
3960 for r in rows {
Max Bires8e93d2b2021-01-14 13:17:59 -08003961 let (id, key_type, domain, namespace, alias, state, km_uuid) = r.unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003962 println!(
Max Bires8e93d2b2021-01-14 13:17:59 -08003963 " id: {} KeyType: {:?} Domain: {} Namespace: {} Alias: {} State: {:?} KmUuid: {:?}",
3964 id, key_type, domain, namespace, alias, state, km_uuid
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003965 );
3966 }
3967 Ok(())
3968 }
3969
3970 fn debug_dump_grant_table(db: &mut KeystoreDB) -> Result<()> {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08003971 let mut stmt = db
3972 .conn
3973 .prepare("SELECT id, grantee, keyentryid, access_vector FROM persistent.grant;")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003974 let rows = stmt.query_map::<(i64, i64, i64, i64), _, _>(NO_PARAMS, |row| {
3975 Ok((row.get(0)?, row.get(1)?, row.get(2)?, row.get(3)?))
3976 })?;
3977
3978 println!("Grant table rows:");
3979 for r in rows {
3980 let (id, gt, ki, av) = r.unwrap();
3981 println!(" id: {} grantee: {} key_id: {} access_vector: {}", id, gt, ki, av);
3982 }
3983 Ok(())
3984 }
3985
Joel Galenson0891bc12020-07-20 10:37:03 -07003986 // Use a custom random number generator that repeats each number once.
3987 // This allows us to test repeated elements.
3988
3989 thread_local! {
3990 static RANDOM_COUNTER: RefCell<i64> = RefCell::new(0);
3991 }
3992
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003993 fn reset_random() {
3994 RANDOM_COUNTER.with(|counter| {
3995 *counter.borrow_mut() = 0;
3996 })
3997 }
3998
Joel Galenson0891bc12020-07-20 10:37:03 -07003999 pub fn random() -> i64 {
4000 RANDOM_COUNTER.with(|counter| {
4001 let result = *counter.borrow() / 2;
4002 *counter.borrow_mut() += 1;
4003 result
4004 })
4005 }
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00004006
4007 #[test]
4008 fn test_last_off_body() -> Result<()> {
4009 let mut db = new_test_db()?;
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08004010 db.insert_last_off_body(MonotonicRawTime::now())?;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00004011 let tx = db.conn.transaction_with_behavior(TransactionBehavior::Immediate)?;
4012 let last_off_body_1 = KeystoreDB::get_last_off_body(&tx)?;
4013 tx.commit()?;
4014 let one_second = Duration::from_secs(1);
4015 thread::sleep(one_second);
4016 db.update_last_off_body(MonotonicRawTime::now())?;
4017 let tx2 = db.conn.transaction_with_behavior(TransactionBehavior::Immediate)?;
4018 let last_off_body_2 = KeystoreDB::get_last_off_body(&tx2)?;
4019 tx2.commit()?;
4020 assert!(last_off_body_1.seconds() < last_off_body_2.seconds());
4021 Ok(())
4022 }
Joel Galenson26f4d012020-07-17 14:57:21 -07004023}