blob: c896d1b7cee1dc8c07129afb80d1742dcc8fdeb4 [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
Janis Danisevskisb00ebd02021-02-02 21:52:24 -0800695/// Shared in-memory databases get destroyed as soon as the last connection to them gets closed.
696/// This object does not allow access to the database connection. But it keeps a database
697/// connection alive in order to keep the in memory per boot database alive.
698pub struct PerBootDbKeepAlive(Connection);
699
Joel Galenson26f4d012020-07-17 14:57:21 -0700700impl KeystoreDB {
Janis Danisevskisb00ebd02021-02-02 21:52:24 -0800701 const PERBOOT_DB_FILE_NAME: &'static str = &"file:perboot.sqlite?mode=memory&cache=shared";
702
703 /// This creates a PerBootDbKeepAlive object to keep the per boot database alive.
704 pub fn keep_perboot_db_alive() -> Result<PerBootDbKeepAlive> {
705 let conn = Connection::open_in_memory()
706 .context("In keep_perboot_db_alive: Failed to initialize SQLite connection.")?;
707
708 conn.execute("ATTACH DATABASE ? as perboot;", params![Self::PERBOOT_DB_FILE_NAME])
709 .context("In keep_perboot_db_alive: Failed to attach database perboot.")?;
710 Ok(PerBootDbKeepAlive(conn))
711 }
712
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700713 /// This will create a new database connection connecting the two
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800714 /// files persistent.sqlite and perboot.sqlite in the given directory.
715 /// It also attempts to initialize all of the tables.
716 /// KeystoreDB cannot be used by multiple threads.
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700717 /// Each thread should open their own connection using `thread_local!`.
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800718 pub fn new(db_root: &Path) -> Result<Self> {
Janis Danisevskisb00ebd02021-02-02 21:52:24 -0800719 // Build the path to the sqlite file.
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800720 let mut persistent_path = db_root.to_path_buf();
721 persistent_path.push("persistent.sqlite");
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700722
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800723 // Now convert them to strings prefixed with "file:"
724 let mut persistent_path_str = "file:".to_owned();
725 persistent_path_str.push_str(&persistent_path.to_string_lossy());
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800726
Janis Danisevskisb00ebd02021-02-02 21:52:24 -0800727 let conn = Self::make_connection(&persistent_path_str, &Self::PERBOOT_DB_FILE_NAME)?;
Janis Danisevskisaea27342021-01-29 08:38:11 -0800728 conn.busy_handler(Some(|_| {
729 std::thread::sleep(std::time::Duration::from_micros(50));
730 true
731 }))
732 .context("In KeystoreDB::new: Failed to set busy handler.")?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800733
734 Self::init_tables(&conn)?;
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700735 Ok(Self { conn })
Joel Galenson2aab4432020-07-22 15:27:57 -0700736 }
737
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700738 fn init_tables(conn: &Connection) -> Result<()> {
739 conn.execute(
740 "CREATE TABLE IF NOT EXISTS persistent.keyentry (
Joel Galenson0891bc12020-07-20 10:37:03 -0700741 id INTEGER UNIQUE,
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800742 key_type INTEGER,
Joel Galenson0891bc12020-07-20 10:37:03 -0700743 domain INTEGER,
744 namespace INTEGER,
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800745 alias BLOB,
Max Bires8e93d2b2021-01-14 13:17:59 -0800746 state INTEGER,
747 km_uuid BLOB);",
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700748 NO_PARAMS,
749 )
750 .context("Failed to initialize \"keyentry\" table.")?;
751
752 conn.execute(
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700753 "CREATE TABLE IF NOT EXISTS persistent.blobentry (
754 id INTEGER PRIMARY KEY,
755 subcomponent_type INTEGER,
756 keyentryid INTEGER,
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800757 blob BLOB);",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700758 NO_PARAMS,
759 )
760 .context("Failed to initialize \"blobentry\" table.")?;
761
762 conn.execute(
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700763 "CREATE TABLE IF NOT EXISTS persistent.keyparameter (
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000764 keyentryid INTEGER,
765 tag INTEGER,
766 data ANY,
767 security_level INTEGER);",
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700768 NO_PARAMS,
769 )
770 .context("Failed to initialize \"keyparameter\" table.")?;
771
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700772 conn.execute(
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800773 "CREATE TABLE IF NOT EXISTS persistent.keymetadata (
774 keyentryid INTEGER,
775 tag INTEGER,
776 data ANY);",
777 NO_PARAMS,
778 )
779 .context("Failed to initialize \"keymetadata\" table.")?;
780
781 conn.execute(
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800782 "CREATE TABLE IF NOT EXISTS persistent.grant (
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700783 id INTEGER UNIQUE,
784 grantee INTEGER,
785 keyentryid INTEGER,
786 access_vector INTEGER);",
787 NO_PARAMS,
788 )
789 .context("Failed to initialize \"grant\" table.")?;
790
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000791 //TODO: only drop the following two perboot tables if this is the first start up
792 //during the boot (b/175716626).
793 // conn.execute("DROP TABLE IF EXISTS perboot.authtoken;", NO_PARAMS)
794 // .context("Failed to drop perboot.authtoken table")?;
795 conn.execute(
796 "CREATE TABLE IF NOT EXISTS perboot.authtoken (
797 id INTEGER PRIMARY KEY,
798 challenge INTEGER,
799 user_id INTEGER,
800 auth_id INTEGER,
801 authenticator_type INTEGER,
802 timestamp INTEGER,
803 mac BLOB,
804 time_received INTEGER,
805 UNIQUE(user_id, auth_id, authenticator_type));",
806 NO_PARAMS,
807 )
808 .context("Failed to initialize \"authtoken\" table.")?;
809
810 // conn.execute("DROP TABLE IF EXISTS perboot.metadata;", NO_PARAMS)
811 // .context("Failed to drop perboot.metadata table")?;
812 // metadata table stores certain miscellaneous information required for keystore functioning
813 // during a boot cycle, as key-value pairs.
814 conn.execute(
815 "CREATE TABLE IF NOT EXISTS perboot.metadata (
816 key TEXT,
817 value BLOB,
818 UNIQUE(key));",
819 NO_PARAMS,
820 )
821 .context("Failed to initialize \"metadata\" table.")?;
Joel Galenson0891bc12020-07-20 10:37:03 -0700822 Ok(())
823 }
824
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700825 fn make_connection(persistent_file: &str, perboot_file: &str) -> Result<Connection> {
826 let conn =
827 Connection::open_in_memory().context("Failed to initialize SQLite connection.")?;
828
829 conn.execute("ATTACH DATABASE ? as persistent;", params![persistent_file])
830 .context("Failed to attach database persistent.")?;
831 conn.execute("ATTACH DATABASE ? as perboot;", params![perboot_file])
832 .context("Failed to attach database perboot.")?;
833
834 Ok(conn)
835 }
836
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800837 /// Get one unreferenced key. There is no particular order in which the keys are returned.
838 fn get_unreferenced_key_id(tx: &Transaction) -> Result<Option<i64>> {
839 tx.query_row(
840 "SELECT id FROM persistent.keyentry WHERE state = ?",
841 params![KeyLifeCycle::Unreferenced],
842 |row| row.get(0),
843 )
844 .optional()
845 .context("In get_unreferenced_key_id: Trying to get unreferenced key id.")
846 }
847
848 /// Returns a key id guard and key entry for one unreferenced key entry. Of the optional
849 /// fields of the key entry only the km_blob field will be populated. This is required
850 /// to subject the blob to its KeyMint instance for deletion.
851 pub fn get_unreferenced_key(&mut self) -> Result<Option<(KeyIdGuard, KeyEntry)>> {
852 self.with_transaction(TransactionBehavior::Deferred, |tx| {
853 let key_id = match Self::get_unreferenced_key_id(tx)
854 .context("Trying to get unreferenced key id")?
855 {
856 None => return Ok(None),
857 Some(id) => KEY_ID_LOCK.try_get(id).ok_or_else(KsError::sys).context(concat!(
858 "A key id lock was held for an unreferenced key. ",
859 "This should never happen."
860 ))?,
861 };
862 let key_entry = Self::load_key_components(tx, KeyEntryLoadBits::KM, key_id.id())
863 .context("Trying to get key components.")?;
864 Ok(Some((key_id, key_entry)))
865 })
866 .context("In get_unreferenced_key.")
867 }
868
869 /// This function purges all remnants of a key entry from the database.
870 /// Important: This does not check if the key was unreferenced, nor does it
871 /// subject the key to its KeyMint instance for permanent invalidation.
872 /// This function should only be called by the garbage collector.
873 /// To delete a key call `mark_unreferenced`, which transitions the key to the unreferenced
874 /// state, deletes all grants to the key, and notifies the garbage collector.
875 /// The garbage collector will:
876 /// 1. Call get_unreferenced_key.
877 /// 2. Determine the proper way to dispose of sensitive key material, e.g., call
878 /// `KeyMintDevice::delete()`.
879 /// 3. Call `purge_key_entry`.
880 pub fn purge_key_entry(&mut self, key_id: KeyIdGuard) -> Result<()> {
881 self.with_transaction(TransactionBehavior::Immediate, |tx| {
882 tx.execute("DELETE FROM persistent.keyentry WHERE id = ?;", params![key_id.id()])
883 .context("Trying to delete keyentry.")?;
884 tx.execute(
885 "DELETE FROM persistent.blobentry WHERE keyentryid = ?;",
886 params![key_id.id()],
887 )
888 .context("Trying to delete blobentries.")?;
889 tx.execute(
890 "DELETE FROM persistent.keymetadata WHERE keyentryid = ?;",
891 params![key_id.id()],
892 )
893 .context("Trying to delete keymetadata.")?;
894 tx.execute(
895 "DELETE FROM persistent.keyparameter WHERE keyentryid = ?;",
896 params![key_id.id()],
897 )
898 .context("Trying to delete keyparameters.")?;
899 let grants_deleted = tx
900 .execute("DELETE FROM persistent.grant WHERE keyentryid = ?;", params![key_id.id()])
901 .context("Trying to delete grants.")?;
902 if grants_deleted != 0 {
903 log::error!("Purged key that still had grants. This should not happen.");
904 }
905 Ok(())
906 })
907 .context("In purge_key_entry.")
908 }
909
910 /// This maintenance function should be called only once before the database is used for the
911 /// first time. It restores the invariant that `KeyLifeCycle::Existing` is a transient state.
912 /// The function transitions all key entries from Existing to Unreferenced unconditionally and
913 /// returns the number of rows affected. If this returns a value greater than 0, it means that
914 /// Keystore crashed at some point during key generation. Callers may want to log such
915 /// occurrences.
916 /// Unlike with `mark_unreferenced`, we don't need to purge grants, because only keys that made
917 /// it to `KeyLifeCycle::Live` may have grants.
918 pub fn cleanup_leftovers(&mut self) -> Result<usize> {
919 self.conn
920 .execute(
921 "UPDATE persistent.keyentry SET state = ? WHERE state = ?;",
922 params![KeyLifeCycle::Unreferenced, KeyLifeCycle::Existing],
923 )
924 .context("In cleanup_leftovers.")
925 }
926
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800927 /// Atomically loads a key entry and associated metadata or creates it using the
928 /// callback create_new_key callback. The callback is called during a database
929 /// transaction. This means that implementers should be mindful about using
930 /// blocking operations such as IPC or grabbing mutexes.
931 pub fn get_or_create_key_with<F>(
932 &mut self,
933 domain: Domain,
934 namespace: i64,
935 alias: &str,
Max Bires8e93d2b2021-01-14 13:17:59 -0800936 km_uuid: Uuid,
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800937 create_new_key: F,
938 ) -> Result<(KeyIdGuard, KeyEntry)>
939 where
940 F: FnOnce() -> Result<(Vec<u8>, KeyMetaData)>,
941 {
942 let tx = self
943 .conn
944 .transaction_with_behavior(TransactionBehavior::Immediate)
945 .context("In get_or_create_key_with: Failed to initialize transaction.")?;
946
947 let id = {
948 let mut stmt = tx
949 .prepare(
950 "SELECT id FROM persistent.keyentry
951 WHERE
952 key_type = ?
953 AND domain = ?
954 AND namespace = ?
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800955 AND alias = ?
956 AND state = ?;",
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800957 )
958 .context("In get_or_create_key_with: Failed to select from keyentry table.")?;
959 let mut rows = stmt
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800960 .query(params![KeyType::Super, domain.0, namespace, alias, KeyLifeCycle::Live])
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800961 .context("In get_or_create_key_with: Failed to query from keyentry table.")?;
962
963 db_utils::with_rows_extract_one(&mut rows, |row| {
964 Ok(match row {
965 Some(r) => r.get(0).context("Failed to unpack id.")?,
966 None => None,
967 })
968 })
969 .context("In get_or_create_key_with.")?
970 };
971
972 let (id, entry) = match id {
973 Some(id) => (
974 id,
975 Self::load_key_components(&tx, KeyEntryLoadBits::KM, id)
976 .context("In get_or_create_key_with.")?,
977 ),
978
979 None => {
980 let id = Self::insert_with_retry(|id| {
981 tx.execute(
982 "INSERT into persistent.keyentry
Max Bires8e93d2b2021-01-14 13:17:59 -0800983 (id, key_type, domain, namespace, alias, state, km_uuid)
984 VALUES(?, ?, ?, ?, ?, ?, ?);",
985 params![
986 id,
987 KeyType::Super,
988 domain.0,
989 namespace,
990 alias,
991 KeyLifeCycle::Live,
992 km_uuid,
993 ],
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800994 )
995 })
996 .context("In get_or_create_key_with.")?;
997
998 let (blob, metadata) = create_new_key().context("In get_or_create_key_with.")?;
Janis Danisevskis377d1002021-01-27 19:07:48 -0800999 Self::set_blob_internal(&tx, id, SubComponentType::KEY_BLOB, Some(&blob))
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001000 .context("In get_of_create_key_with.")?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001001 metadata.store_in_db(id, &tx).context("In get_or_create_key_with.")?;
Janis Danisevskis377d1002021-01-27 19:07:48 -08001002 (
1003 id,
1004 KeyEntry {
1005 id,
1006 km_blob: Some(blob),
1007 metadata,
1008 pure_cert: false,
1009 ..Default::default()
1010 },
1011 )
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001012 }
1013 };
1014 tx.commit().context("In get_or_create_key_with: Failed to commit transaction.")?;
1015 Ok((KEY_ID_LOCK.get(id), entry))
1016 }
1017
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001018 /// Creates a transaction with the given behavior and executes f with the new transaction.
1019 /// The transaction is committed only if f returns Ok.
1020 fn with_transaction<T, F>(&mut self, behavior: TransactionBehavior, f: F) -> Result<T>
1021 where
1022 F: FnOnce(&Transaction) -> Result<T>,
1023 {
1024 let tx = self
1025 .conn
1026 .transaction_with_behavior(behavior)
1027 .context("In with_transaction: Failed to initialize transaction.")?;
1028 f(&tx).and_then(|result| {
1029 tx.commit().context("In with_transaction: Failed to commit transaction.")?;
1030 Ok(result)
1031 })
1032 }
1033
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001034 /// Creates a new key entry and allocates a new randomized id for the new key.
1035 /// The key id gets associated with a domain and namespace but not with an alias.
1036 /// To complete key generation `rebind_alias` should be called after all of the
1037 /// key artifacts, i.e., blobs and parameters have been associated with the new
1038 /// key id. Finalizing with `rebind_alias` makes the creation of a new key entry
1039 /// atomic even if key generation is not.
Max Bires8e93d2b2021-01-14 13:17:59 -08001040 pub fn create_key_entry(
1041 &mut self,
1042 domain: Domain,
1043 namespace: i64,
1044 km_uuid: &Uuid,
1045 ) -> Result<KeyIdGuard> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001046 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Max Bires8e93d2b2021-01-14 13:17:59 -08001047 Self::create_key_entry_internal(tx, domain, namespace, km_uuid)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001048 })
1049 .context("In create_key_entry.")
1050 }
1051
1052 fn create_key_entry_internal(
1053 tx: &Transaction,
1054 domain: Domain,
1055 namespace: i64,
Max Bires8e93d2b2021-01-14 13:17:59 -08001056 km_uuid: &Uuid,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001057 ) -> Result<KeyIdGuard> {
Joel Galenson0891bc12020-07-20 10:37:03 -07001058 match domain {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001059 Domain::APP | Domain::SELINUX => {}
Joel Galenson0891bc12020-07-20 10:37:03 -07001060 _ => {
1061 return Err(KsError::sys())
1062 .context(format!("Domain {:?} must be either App or SELinux.", domain));
1063 }
1064 }
Janis Danisevskisaec14592020-11-12 09:41:49 -08001065 Ok(KEY_ID_LOCK.get(
1066 Self::insert_with_retry(|id| {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001067 tx.execute(
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001068 "INSERT into persistent.keyentry
Max Bires8e93d2b2021-01-14 13:17:59 -08001069 (id, key_type, domain, namespace, alias, state, km_uuid)
1070 VALUES(?, ?, ?, ?, NULL, ?, ?);",
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001071 params![
1072 id,
1073 KeyType::Client,
1074 domain.0 as u32,
1075 namespace,
Max Bires8e93d2b2021-01-14 13:17:59 -08001076 KeyLifeCycle::Existing,
1077 km_uuid,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001078 ],
Janis Danisevskisaec14592020-11-12 09:41:49 -08001079 )
1080 })
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001081 .context("In create_key_entry_internal")?,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001082 ))
Joel Galenson26f4d012020-07-17 14:57:21 -07001083 }
Joel Galenson33c04ad2020-08-03 11:04:38 -07001084
Max Bires2b2e6562020-09-22 11:22:36 -07001085 /// Creates a new attestation key entry and allocates a new randomized id for the new key.
1086 /// The key id gets associated with a domain and namespace later but not with an alias. The
1087 /// alias will be used to denote if a key has been signed as each key can only be bound to one
1088 /// domain and namespace pairing so there is no need to use them as a value for indexing into
1089 /// a key.
1090 pub fn create_attestation_key_entry(
1091 &mut self,
1092 maced_public_key: &[u8],
1093 raw_public_key: &[u8],
1094 private_key: &[u8],
1095 km_uuid: &Uuid,
1096 ) -> Result<()> {
1097 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1098 let key_id = KEY_ID_LOCK.get(
1099 Self::insert_with_retry(|id| {
1100 tx.execute(
1101 "INSERT into persistent.keyentry
1102 (id, key_type, domain, namespace, alias, state, km_uuid)
1103 VALUES(?, ?, NULL, NULL, NULL, ?, ?);",
1104 params![id, KeyType::Attestation, KeyLifeCycle::Live, km_uuid],
1105 )
1106 })
1107 .context("In create_key_entry")?,
1108 );
1109 Self::set_blob_internal(&tx, key_id.0, SubComponentType::KEY_BLOB, Some(private_key))?;
1110 let mut metadata = KeyMetaData::new();
1111 metadata.add(KeyMetaEntry::AttestationMacedPublicKey(maced_public_key.to_vec()));
1112 metadata.add(KeyMetaEntry::AttestationRawPubKey(raw_public_key.to_vec()));
1113 metadata.store_in_db(key_id.0, &tx)?;
1114 Ok(())
1115 })
1116 .context("In create_attestation_key_entry")
1117 }
1118
Janis Danisevskis377d1002021-01-27 19:07:48 -08001119 /// Set a new blob and associates it with the given key id. Each blob
1120 /// has a sub component type.
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001121 /// Each key can have one of each sub component type associated. If more
1122 /// are added only the most recent can be retrieved, and superseded blobs
Janis Danisevskis377d1002021-01-27 19:07:48 -08001123 /// will get garbage collected.
1124 /// Components SubComponentType::CERT and SubComponentType::CERT_CHAIN can be
1125 /// removed by setting blob to None.
1126 pub fn set_blob(
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001127 &mut self,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001128 key_id: &KeyIdGuard,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001129 sc_type: SubComponentType,
Janis Danisevskis377d1002021-01-27 19:07:48 -08001130 blob: Option<&[u8]>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001131 ) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001132 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis377d1002021-01-27 19:07:48 -08001133 Self::set_blob_internal(&tx, key_id.0, sc_type, blob)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001134 })
Janis Danisevskis377d1002021-01-27 19:07:48 -08001135 .context("In set_blob.")
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001136 }
1137
Janis Danisevskis377d1002021-01-27 19:07:48 -08001138 fn set_blob_internal(
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001139 tx: &Transaction,
1140 key_id: i64,
1141 sc_type: SubComponentType,
Janis Danisevskis377d1002021-01-27 19:07:48 -08001142 blob: Option<&[u8]>,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001143 ) -> Result<()> {
Janis Danisevskis377d1002021-01-27 19:07:48 -08001144 match (blob, sc_type) {
1145 (Some(blob), _) => {
1146 tx.execute(
1147 "INSERT INTO persistent.blobentry
1148 (subcomponent_type, keyentryid, blob) VALUES (?, ?, ?);",
1149 params![sc_type, key_id, blob],
1150 )
1151 .context("In set_blob_internal: Failed to insert blob.")?;
1152 }
1153 (None, SubComponentType::CERT) | (None, SubComponentType::CERT_CHAIN) => {
1154 tx.execute(
1155 "DELETE FROM persistent.blobentry
1156 WHERE subcomponent_type = ? AND keyentryid = ?;",
1157 params![sc_type, key_id],
1158 )
1159 .context("In set_blob_internal: Failed to delete blob.")?;
1160 }
1161 (None, _) => {
1162 return Err(KsError::sys())
1163 .context("In set_blob_internal: Other blobs cannot be deleted in this way.");
1164 }
1165 }
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001166 Ok(())
1167 }
1168
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001169 /// Inserts a collection of key parameters into the `persistent.keyparameter` table
1170 /// and associates them with the given `key_id`.
1171 pub fn insert_keyparameter<'a>(
1172 &mut self,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001173 key_id: &KeyIdGuard,
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001174 params: impl IntoIterator<Item = &'a KeyParameter>,
1175 ) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001176 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1177 Self::insert_keyparameter_internal(tx, key_id, params)
1178 })
1179 .context("In insert_keyparameter.")
1180 }
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001181
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001182 fn insert_keyparameter_internal<'a>(
1183 tx: &Transaction,
1184 key_id: &KeyIdGuard,
1185 params: impl IntoIterator<Item = &'a KeyParameter>,
1186 ) -> Result<()> {
1187 let mut stmt = tx
1188 .prepare(
1189 "INSERT into persistent.keyparameter (keyentryid, tag, data, security_level)
1190 VALUES (?, ?, ?, ?);",
1191 )
1192 .context("In insert_keyparameter_internal: Failed to prepare statement.")?;
1193
1194 let iter = params.into_iter();
1195 for p in iter {
1196 stmt.insert(params![
1197 key_id.0,
1198 p.get_tag().0,
1199 p.key_parameter_value(),
1200 p.security_level().0
1201 ])
1202 .with_context(|| {
1203 format!("In insert_keyparameter_internal: Failed to insert {:?}", p)
1204 })?;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001205 }
1206 Ok(())
1207 }
1208
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001209 /// Insert a set of key entry specific metadata into the database.
1210 pub fn insert_key_metadata(
1211 &mut self,
1212 key_id: &KeyIdGuard,
1213 metadata: &KeyMetaData,
1214 ) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001215 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1216 metadata.store_in_db(key_id.0, &tx)
1217 })
1218 .context("In insert_key_metadata.")
1219 }
1220
Max Bires2b2e6562020-09-22 11:22:36 -07001221 /// Stores a signed certificate chain signed by a remote provisioning server, keyed
1222 /// on the public key.
1223 pub fn store_signed_attestation_certificate_chain(
1224 &mut self,
1225 raw_public_key: &[u8],
1226 cert_chain: &[u8],
1227 expiration_date: i64,
1228 km_uuid: &Uuid,
1229 ) -> Result<()> {
1230 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1231 let mut stmt = tx
1232 .prepare(
1233 "SELECT keyentryid
1234 FROM persistent.keymetadata
1235 WHERE tag = ? AND data = ? AND keyentryid IN
1236 (SELECT id
1237 FROM persistent.keyentry
1238 WHERE
1239 alias IS NULL AND
1240 domain IS NULL AND
1241 namespace IS NULL AND
1242 key_type = ? AND
1243 km_uuid = ?);",
1244 )
1245 .context("Failed to store attestation certificate chain.")?;
1246 let mut rows = stmt
1247 .query(params![
1248 KeyMetaData::AttestationRawPubKey,
1249 raw_public_key,
1250 KeyType::Attestation,
1251 km_uuid
1252 ])
1253 .context("Failed to fetch keyid")?;
1254 let key_id = db_utils::with_rows_extract_one(&mut rows, |row| {
1255 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?
1256 .get(0)
1257 .context("Failed to unpack id.")
1258 })
1259 .context("Failed to get key_id.")?;
1260 let num_updated = tx
1261 .execute(
1262 "UPDATE persistent.keyentry
1263 SET alias = ?
1264 WHERE id = ?;",
1265 params!["signed", key_id],
1266 )
1267 .context("Failed to update alias.")?;
1268 if num_updated != 1 {
1269 return Err(KsError::sys()).context("Alias not updated for the key.");
1270 }
1271 let mut metadata = KeyMetaData::new();
1272 metadata.add(KeyMetaEntry::AttestationExpirationDate(DateTime::from_millis_epoch(
1273 expiration_date,
1274 )));
1275 metadata.store_in_db(key_id, &tx).context("Failed to insert key metadata.")?;
1276 Self::set_blob_internal(&tx, key_id, SubComponentType::CERT_CHAIN, Some(cert_chain))
1277 .context("Failed to insert cert chain")?;
1278 Ok(())
1279 })
1280 .context("In store_signed_attestation_certificate_chain: ")
1281 }
1282
1283 /// Assigns the next unassigned attestation key to a domain/namespace combo that does not
1284 /// currently have a key assigned to it.
1285 pub fn assign_attestation_key(
1286 &mut self,
1287 domain: Domain,
1288 namespace: i64,
1289 km_uuid: &Uuid,
1290 ) -> Result<()> {
1291 match domain {
1292 Domain::APP | Domain::SELINUX => {}
1293 _ => {
1294 return Err(KsError::sys()).context(format!(
1295 concat!(
1296 "In assign_attestation_key: Domain {:?} ",
1297 "must be either App or SELinux.",
1298 ),
1299 domain
1300 ));
1301 }
1302 }
1303 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1304 let result = tx
1305 .execute(
1306 "UPDATE persistent.keyentry
1307 SET domain=?1, namespace=?2
1308 WHERE
1309 id =
1310 (SELECT MIN(id)
1311 FROM persistent.keyentry
1312 WHERE ALIAS IS NOT NULL
1313 AND domain IS NULL
1314 AND key_type IS ?3
1315 AND state IS ?4
1316 AND km_uuid IS ?5)
1317 AND
1318 (SELECT COUNT(*)
1319 FROM persistent.keyentry
1320 WHERE domain=?1
1321 AND namespace=?2
1322 AND key_type IS ?3
1323 AND state IS ?4
1324 AND km_uuid IS ?5) = 0;",
1325 params![
1326 domain.0 as u32,
1327 namespace,
1328 KeyType::Attestation,
1329 KeyLifeCycle::Live,
1330 km_uuid,
1331 ],
1332 )
1333 .context("Failed to assign attestation key")?;
1334 if result != 1 {
1335 return Err(KsError::sys()).context(format!(
1336 "Expected to update a single entry but instead updated {}.",
1337 result
1338 ));
1339 }
1340 Ok(())
1341 })
1342 .context("In assign_attestation_key: ")
1343 }
1344
1345 /// Retrieves num_keys number of attestation keys that have not yet been signed by a remote
1346 /// provisioning server, or the maximum number available if there are not num_keys number of
1347 /// entries in the table.
1348 pub fn fetch_unsigned_attestation_keys(
1349 &mut self,
1350 num_keys: i32,
1351 km_uuid: &Uuid,
1352 ) -> Result<Vec<Vec<u8>>> {
1353 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1354 let mut stmt = tx
1355 .prepare(
1356 "SELECT data
1357 FROM persistent.keymetadata
1358 WHERE tag = ? AND keyentryid IN
1359 (SELECT id
1360 FROM persistent.keyentry
1361 WHERE
1362 alias IS NULL AND
1363 domain IS NULL AND
1364 namespace IS NULL AND
1365 key_type = ? AND
1366 km_uuid = ?
1367 LIMIT ?);",
1368 )
1369 .context("Failed to prepare statement")?;
1370 let rows = stmt
1371 .query_map(
1372 params![
1373 KeyMetaData::AttestationMacedPublicKey,
1374 KeyType::Attestation,
1375 km_uuid,
1376 num_keys
1377 ],
1378 |row| Ok(row.get(0)?),
1379 )?
1380 .collect::<rusqlite::Result<Vec<Vec<u8>>>>()
1381 .context("Failed to execute statement")?;
1382 Ok(rows)
1383 })
1384 .context("In fetch_unsigned_attestation_keys")
1385 }
1386
1387 /// Removes any keys that have expired as of the current time. Returns the number of keys
1388 /// marked unreferenced that are bound to be garbage collected.
1389 pub fn delete_expired_attestation_keys(&mut self) -> Result<i32> {
1390 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1391 let mut stmt = tx
1392 .prepare(
1393 "SELECT keyentryid, data
1394 FROM persistent.keymetadata
1395 WHERE tag = ? AND keyentryid IN
1396 (SELECT id
1397 FROM persistent.keyentry
1398 WHERE key_type = ?);",
1399 )
1400 .context("Failed to prepare query")?;
1401 let key_ids_to_check = stmt
1402 .query_map(
1403 params![KeyMetaData::AttestationExpirationDate, KeyType::Attestation],
1404 |row| Ok((row.get(0)?, row.get(1)?)),
1405 )?
1406 .collect::<rusqlite::Result<Vec<(i64, DateTime)>>>()
1407 .context("Failed to get date metadata")?;
1408 let curr_time = DateTime::from_millis_epoch(
1409 SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_millis() as i64,
1410 );
1411 let mut num_deleted = 0;
1412 for id in key_ids_to_check.iter().filter(|kt| kt.1 < curr_time).map(|kt| kt.0) {
1413 if Self::mark_unreferenced(&tx, id)? {
1414 num_deleted += 1;
1415 }
1416 }
1417 Ok(num_deleted)
1418 })
1419 .context("In delete_expired_attestation_keys: ")
1420 }
1421
1422 /// Counts the number of keys that will expire by the provided epoch date and the number of
1423 /// keys not currently assigned to a domain.
1424 pub fn get_attestation_pool_status(
1425 &mut self,
1426 date: i64,
1427 km_uuid: &Uuid,
1428 ) -> Result<AttestationPoolStatus> {
1429 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1430 let mut stmt = tx.prepare(
1431 "SELECT data
1432 FROM persistent.keymetadata
1433 WHERE tag = ? AND keyentryid IN
1434 (SELECT id
1435 FROM persistent.keyentry
1436 WHERE alias IS NOT NULL
1437 AND key_type = ?
1438 AND km_uuid = ?
1439 AND state = ?);",
1440 )?;
1441 let times = stmt
1442 .query_map(
1443 params![
1444 KeyMetaData::AttestationExpirationDate,
1445 KeyType::Attestation,
1446 km_uuid,
1447 KeyLifeCycle::Live
1448 ],
1449 |row| Ok(row.get(0)?),
1450 )?
1451 .collect::<rusqlite::Result<Vec<DateTime>>>()
1452 .context("Failed to execute metadata statement")?;
1453 let expiring =
1454 times.iter().filter(|time| time < &&DateTime::from_millis_epoch(date)).count()
1455 as i32;
1456 stmt = tx.prepare(
1457 "SELECT alias, domain
1458 FROM persistent.keyentry
1459 WHERE key_type = ? AND km_uuid = ? AND state = ?;",
1460 )?;
1461 let rows = stmt
1462 .query_map(params![KeyType::Attestation, km_uuid, KeyLifeCycle::Live], |row| {
1463 Ok((row.get(0)?, row.get(1)?))
1464 })?
1465 .collect::<rusqlite::Result<Vec<(Option<String>, Option<u32>)>>>()
1466 .context("Failed to execute keyentry statement")?;
1467 let mut unassigned = 0i32;
1468 let mut attested = 0i32;
1469 let total = rows.len() as i32;
1470 for (alias, domain) in rows {
1471 match (alias, domain) {
1472 (Some(_alias), None) => {
1473 attested += 1;
1474 unassigned += 1;
1475 }
1476 (Some(_alias), Some(_domain)) => {
1477 attested += 1;
1478 }
1479 _ => {}
1480 }
1481 }
1482 Ok(AttestationPoolStatus { expiring, unassigned, attested, total })
1483 })
1484 .context("In get_attestation_pool_status: ")
1485 }
1486
1487 /// Fetches the private key and corresponding certificate chain assigned to a
1488 /// domain/namespace pair. Will either return nothing if the domain/namespace is
1489 /// not assigned, or one CertificateChain.
1490 pub fn retrieve_attestation_key_and_cert_chain(
1491 &mut self,
1492 domain: Domain,
1493 namespace: i64,
1494 km_uuid: &Uuid,
1495 ) -> Result<Option<CertificateChain>> {
1496 match domain {
1497 Domain::APP | Domain::SELINUX => {}
1498 _ => {
1499 return Err(KsError::sys())
1500 .context(format!("Domain {:?} must be either App or SELinux.", domain));
1501 }
1502 }
1503 let mut stmt = self.conn.prepare(
1504 "SELECT subcomponent_type, blob
1505 FROM persistent.blobentry
1506 WHERE keyentryid IN
1507 (SELECT id
1508 FROM persistent.keyentry
1509 WHERE key_type = ?
1510 AND domain = ?
1511 AND namespace = ?
1512 AND state = ?
1513 AND km_uuid = ?);",
1514 )?;
1515 let rows = stmt
1516 .query_map(
1517 params![
1518 KeyType::Attestation,
1519 domain.0 as u32,
1520 namespace,
1521 KeyLifeCycle::Live,
1522 km_uuid
1523 ],
1524 |row| Ok((row.get(0)?, row.get(1)?)),
1525 )?
1526 .collect::<rusqlite::Result<Vec<(SubComponentType, Vec<u8>)>>>()
1527 .context("In retrieve_attestation_key_and_cert_chain: query failed.")?;
1528 if rows.is_empty() {
1529 return Ok(None);
1530 } else if rows.len() != 2 {
1531 return Err(KsError::sys()).context(format!(
1532 concat!(
1533 "In retrieve_attestation_key_and_cert_chain: Expected to get a single attestation",
1534 "key chain but instead got {}."),
1535 rows.len()
1536 ));
1537 }
1538 let mut km_blob: Vec<u8> = Vec::new();
1539 let mut cert_chain_blob: Vec<u8> = Vec::new();
1540 for row in rows {
1541 let sub_type: SubComponentType = row.0;
1542 match sub_type {
1543 SubComponentType::KEY_BLOB => {
1544 km_blob = row.1;
1545 }
1546 SubComponentType::CERT_CHAIN => {
1547 cert_chain_blob = row.1;
1548 }
1549 _ => Err(KsError::sys()).context("Unknown or incorrect subcomponent type.")?,
1550 }
1551 }
1552 Ok(Some(CertificateChain {
1553 private_key: ZVec::try_from(km_blob)?,
1554 cert_chain: ZVec::try_from(cert_chain_blob)?,
1555 }))
1556 }
1557
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001558 /// Updates the alias column of the given key id `newid` with the given alias,
1559 /// and atomically, removes the alias, domain, and namespace from another row
1560 /// with the same alias-domain-namespace tuple if such row exits.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001561 /// Returns Ok(true) if an old key was marked unreferenced as a hint to the garbage
1562 /// collector.
1563 fn rebind_alias(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001564 tx: &Transaction,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001565 newid: &KeyIdGuard,
Joel Galenson33c04ad2020-08-03 11:04:38 -07001566 alias: &str,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001567 domain: Domain,
Joel Galenson33c04ad2020-08-03 11:04:38 -07001568 namespace: i64,
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001569 ) -> Result<bool> {
Joel Galenson33c04ad2020-08-03 11:04:38 -07001570 match domain {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001571 Domain::APP | Domain::SELINUX => {}
Joel Galenson33c04ad2020-08-03 11:04:38 -07001572 _ => {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001573 return Err(KsError::sys()).context(format!(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001574 "In rebind_alias: Domain {:?} must be either App or SELinux.",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001575 domain
1576 ));
Joel Galenson33c04ad2020-08-03 11:04:38 -07001577 }
1578 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001579 let updated = tx
1580 .execute(
1581 "UPDATE persistent.keyentry
1582 SET alias = NULL, domain = NULL, namespace = NULL, state = ?
Joel Galenson33c04ad2020-08-03 11:04:38 -07001583 WHERE alias = ? AND domain = ? AND namespace = ?;",
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001584 params![KeyLifeCycle::Unreferenced, alias, domain.0 as u32, namespace],
1585 )
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001586 .context("In rebind_alias: Failed to rebind existing entry.")?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07001587 let result = tx
1588 .execute(
1589 "UPDATE persistent.keyentry
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001590 SET alias = ?, state = ?
1591 WHERE id = ? AND domain = ? AND namespace = ? AND state = ?;",
1592 params![
1593 alias,
1594 KeyLifeCycle::Live,
1595 newid.0,
1596 domain.0 as u32,
1597 namespace,
Max Bires8e93d2b2021-01-14 13:17:59 -08001598 KeyLifeCycle::Existing,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001599 ],
Joel Galenson33c04ad2020-08-03 11:04:38 -07001600 )
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001601 .context("In rebind_alias: Failed to set alias.")?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07001602 if result != 1 {
Joel Galenson33c04ad2020-08-03 11:04:38 -07001603 return Err(KsError::sys()).context(format!(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001604 "In rebind_alias: Expected to update a single entry but instead updated {}.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07001605 result
1606 ));
1607 }
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001608 Ok(updated != 0)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001609 }
1610
1611 /// Store a new key in a single transaction.
1612 /// The function creates a new key entry, populates the blob, key parameter, and metadata
1613 /// fields, and rebinds the given alias to the new key.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001614 /// The boolean returned is a hint for the garbage collector. If true, a key was replaced,
1615 /// is now unreferenced and needs to be collected.
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001616 pub fn store_new_key<'a>(
1617 &mut self,
1618 key: KeyDescriptor,
1619 params: impl IntoIterator<Item = &'a KeyParameter>,
1620 blob: &[u8],
Max Bires8e93d2b2021-01-14 13:17:59 -08001621 cert_info: &CertificateInfo,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001622 metadata: &KeyMetaData,
Max Bires8e93d2b2021-01-14 13:17:59 -08001623 km_uuid: &Uuid,
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001624 ) -> Result<(bool, KeyIdGuard)> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001625 let (alias, domain, namespace) = match key {
1626 KeyDescriptor { alias: Some(alias), domain: Domain::APP, nspace, blob: None }
1627 | KeyDescriptor { alias: Some(alias), domain: Domain::SELINUX, nspace, blob: None } => {
1628 (alias, key.domain, nspace)
1629 }
1630 _ => {
1631 return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT))
1632 .context("In store_new_key: Need alias and domain must be APP or SELINUX.")
1633 }
1634 };
1635 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Max Bires8e93d2b2021-01-14 13:17:59 -08001636 let key_id = Self::create_key_entry_internal(tx, domain, namespace, km_uuid)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001637 .context("Trying to create new key entry.")?;
Janis Danisevskis377d1002021-01-27 19:07:48 -08001638 Self::set_blob_internal(tx, key_id.id(), SubComponentType::KEY_BLOB, Some(blob))
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001639 .context("Trying to insert the key blob.")?;
Max Bires8e93d2b2021-01-14 13:17:59 -08001640 if let Some(cert) = &cert_info.cert {
Janis Danisevskis377d1002021-01-27 19:07:48 -08001641 Self::set_blob_internal(tx, key_id.id(), SubComponentType::CERT, Some(&cert))
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001642 .context("Trying to insert the certificate.")?;
1643 }
Max Bires8e93d2b2021-01-14 13:17:59 -08001644 if let Some(cert_chain) = &cert_info.cert_chain {
Janis Danisevskis377d1002021-01-27 19:07:48 -08001645 Self::set_blob_internal(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001646 tx,
1647 key_id.id(),
1648 SubComponentType::CERT_CHAIN,
Janis Danisevskis377d1002021-01-27 19:07:48 -08001649 Some(&cert_chain),
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001650 )
1651 .context("Trying to insert the certificate chain.")?;
1652 }
1653 Self::insert_keyparameter_internal(tx, &key_id, params)
1654 .context("Trying to insert key parameters.")?;
Janis Danisevskis377d1002021-01-27 19:07:48 -08001655 metadata.store_in_db(key_id.id(), tx).context("Trying to insert key metadata.")?;
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001656 let need_gc = Self::rebind_alias(tx, &key_id, &alias, domain, namespace)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001657 .context("Trying to rebind alias.")?;
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001658 Ok((need_gc, key_id))
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001659 })
1660 .context("In store_new_key.")
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001661 }
1662
Janis Danisevskis377d1002021-01-27 19:07:48 -08001663 /// Store a new certificate
1664 /// The function creates a new key entry, populates the blob field and metadata, and rebinds
1665 /// the given alias to the new cert.
Max Bires8e93d2b2021-01-14 13:17:59 -08001666 pub fn store_new_certificate(
1667 &mut self,
1668 key: KeyDescriptor,
1669 cert: &[u8],
1670 km_uuid: &Uuid,
1671 ) -> Result<KeyIdGuard> {
Janis Danisevskis377d1002021-01-27 19:07:48 -08001672 let (alias, domain, namespace) = match key {
1673 KeyDescriptor { alias: Some(alias), domain: Domain::APP, nspace, blob: None }
1674 | KeyDescriptor { alias: Some(alias), domain: Domain::SELINUX, nspace, blob: None } => {
1675 (alias, key.domain, nspace)
1676 }
1677 _ => {
1678 return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT)).context(
1679 "In store_new_certificate: Need alias and domain must be APP or SELINUX.",
1680 )
1681 }
1682 };
1683 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Max Bires8e93d2b2021-01-14 13:17:59 -08001684 let key_id = Self::create_key_entry_internal(tx, domain, namespace, km_uuid)
Janis Danisevskis377d1002021-01-27 19:07:48 -08001685 .context("Trying to create new key entry.")?;
1686
1687 Self::set_blob_internal(tx, key_id.id(), SubComponentType::CERT_CHAIN, Some(cert))
1688 .context("Trying to insert certificate.")?;
1689
1690 let mut metadata = KeyMetaData::new();
1691 metadata.add(KeyMetaEntry::CreationDate(
1692 DateTime::now().context("Trying to make creation time.")?,
1693 ));
1694
1695 metadata.store_in_db(key_id.id(), tx).context("Trying to insert key metadata.")?;
1696
1697 Self::rebind_alias(tx, &key_id, &alias, domain, namespace)
1698 .context("Trying to rebind alias.")?;
1699 Ok(key_id)
1700 })
1701 .context("In store_new_certificate.")
1702 }
1703
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001704 // Helper function loading the key_id given the key descriptor
1705 // tuple comprising domain, namespace, and alias.
1706 // Requires a valid transaction.
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001707 fn load_key_entry_id(tx: &Transaction, key: &KeyDescriptor, key_type: KeyType) -> Result<i64> {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001708 let alias = key
1709 .alias
1710 .as_ref()
1711 .map_or_else(|| Err(KsError::sys()), Ok)
1712 .context("In load_key_entry_id: Alias must be specified.")?;
1713 let mut stmt = tx
1714 .prepare(
1715 "SELECT id FROM persistent.keyentry
1716 WHERE
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001717 key_type = ?
1718 AND domain = ?
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001719 AND namespace = ?
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001720 AND alias = ?
1721 AND state = ?;",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001722 )
1723 .context("In load_key_entry_id: Failed to select from keyentry table.")?;
1724 let mut rows = stmt
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001725 .query(params![key_type, key.domain.0 as u32, key.nspace, alias, KeyLifeCycle::Live])
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001726 .context("In load_key_entry_id: Failed to read from keyentry table.")?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08001727 db_utils::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001728 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001729 .get(0)
1730 .context("Failed to unpack id.")
1731 })
1732 .context("In load_key_entry_id.")
1733 }
1734
1735 /// This helper function completes the access tuple of a key, which is required
1736 /// to perform access control. The strategy depends on the `domain` field in the
1737 /// key descriptor.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001738 /// * Domain::SELINUX: The access tuple is complete and this function only loads
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001739 /// the key_id for further processing.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001740 /// * Domain::APP: Like Domain::SELINUX, but the tuple is completed by `caller_uid`
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001741 /// which serves as the namespace.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001742 /// * Domain::GRANT: The grant table is queried for the `key_id` and the
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001743 /// `access_vector`.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001744 /// * Domain::KEY_ID: The keyentry table is queried for the owning `domain` and
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001745 /// `namespace`.
1746 /// In each case the information returned is sufficient to perform the access
1747 /// check and the key id can be used to load further key artifacts.
1748 fn load_access_tuple(
1749 tx: &Transaction,
1750 key: KeyDescriptor,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001751 key_type: KeyType,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001752 caller_uid: u32,
1753 ) -> Result<(i64, KeyDescriptor, Option<KeyPermSet>)> {
1754 match key.domain {
1755 // Domain App or SELinux. In this case we load the key_id from
1756 // the keyentry database for further loading of key components.
1757 // We already have the full access tuple to perform access control.
1758 // The only distinction is that we use the caller_uid instead
1759 // of the caller supplied namespace if the domain field is
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001760 // Domain::APP.
1761 Domain::APP | Domain::SELINUX => {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001762 let mut access_key = key;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001763 if access_key.domain == Domain::APP {
1764 access_key.nspace = caller_uid as i64;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001765 }
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001766 let key_id = Self::load_key_entry_id(&tx, &access_key, key_type)
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001767 .with_context(|| format!("With key.domain = {:?}.", access_key.domain))?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001768
1769 Ok((key_id, access_key, None))
1770 }
1771
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001772 // Domain::GRANT. In this case we load the key_id and the access_vector
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001773 // from the grant table.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001774 Domain::GRANT => {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001775 let mut stmt = tx
1776 .prepare(
Janis Danisevskisbf15d732020-12-08 10:35:26 -08001777 "SELECT keyentryid, access_vector FROM persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001778 WHERE grantee = ? AND id = ?;",
1779 )
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001780 .context("Domain::GRANT prepare statement failed")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001781 let mut rows = stmt
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001782 .query(params![caller_uid as i64, key.nspace])
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001783 .context("Domain:Grant: query failed.")?;
1784 let (key_id, access_vector): (i64, i32) =
Janis Danisevskisbf15d732020-12-08 10:35:26 -08001785 db_utils::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001786 let r =
1787 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001788 Ok((
1789 r.get(0).context("Failed to unpack key_id.")?,
1790 r.get(1).context("Failed to unpack access_vector.")?,
1791 ))
1792 })
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001793 .context("Domain::GRANT.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001794 Ok((key_id, key, Some(access_vector.into())))
1795 }
1796
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001797 // Domain::KEY_ID. In this case we load the domain and namespace from the
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001798 // keyentry database because we need them for access control.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001799 Domain::KEY_ID => {
Janis Danisevskis45760022021-01-19 16:34:10 -08001800 let (domain, namespace): (Domain, i64) = {
1801 let mut stmt = tx
1802 .prepare(
1803 "SELECT domain, namespace FROM persistent.keyentry
1804 WHERE
1805 id = ?
1806 AND state = ?;",
1807 )
1808 .context("Domain::KEY_ID: prepare statement failed")?;
1809 let mut rows = stmt
1810 .query(params![key.nspace, KeyLifeCycle::Live])
1811 .context("Domain::KEY_ID: query failed.")?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08001812 db_utils::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001813 let r =
1814 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001815 Ok((
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001816 Domain(r.get(0).context("Failed to unpack domain.")?),
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001817 r.get(1).context("Failed to unpack namespace.")?,
1818 ))
1819 })
Janis Danisevskis45760022021-01-19 16:34:10 -08001820 .context("Domain::KEY_ID.")?
1821 };
1822
1823 // We may use a key by id after loading it by grant.
1824 // In this case we have to check if the caller has a grant for this particular
1825 // key. We can skip this if we already know that the caller is the owner.
1826 // But we cannot know this if domain is anything but App. E.g. in the case
1827 // of Domain::SELINUX we have to speculatively check for grants because we have to
1828 // consult the SEPolicy before we know if the caller is the owner.
1829 let access_vector: Option<KeyPermSet> =
1830 if domain != Domain::APP || namespace != caller_uid as i64 {
1831 let access_vector: Option<i32> = tx
1832 .query_row(
1833 "SELECT access_vector FROM persistent.grant
1834 WHERE grantee = ? AND keyentryid = ?;",
1835 params![caller_uid as i64, key.nspace],
1836 |row| row.get(0),
1837 )
1838 .optional()
1839 .context("Domain::KEY_ID: query grant failed.")?;
1840 access_vector.map(|p| p.into())
1841 } else {
1842 None
1843 };
1844
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001845 let key_id = key.nspace;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001846 let mut access_key = key;
1847 access_key.domain = domain;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001848 access_key.nspace = namespace;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001849
Janis Danisevskis45760022021-01-19 16:34:10 -08001850 Ok((key_id, access_key, access_vector))
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001851 }
1852 _ => Err(anyhow!(KsError::sys())),
1853 }
1854 }
1855
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001856 fn load_blob_components(
1857 key_id: i64,
1858 load_bits: KeyEntryLoadBits,
1859 tx: &Transaction,
Janis Danisevskis377d1002021-01-27 19:07:48 -08001860 ) -> Result<(bool, Option<Vec<u8>>, Option<Vec<u8>>, Option<Vec<u8>>)> {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001861 let mut stmt = tx
1862 .prepare(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001863 "SELECT MAX(id), subcomponent_type, blob FROM persistent.blobentry
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001864 WHERE keyentryid = ? GROUP BY subcomponent_type;",
1865 )
1866 .context("In load_blob_components: prepare statement failed.")?;
1867
1868 let mut rows =
1869 stmt.query(params![key_id]).context("In load_blob_components: query failed.")?;
1870
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001871 let mut km_blob: Option<Vec<u8>> = None;
1872 let mut cert_blob: Option<Vec<u8>> = None;
1873 let mut cert_chain_blob: Option<Vec<u8>> = None;
Janis Danisevskis377d1002021-01-27 19:07:48 -08001874 let mut has_km_blob: bool = false;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08001875 db_utils::with_rows_extract_all(&mut rows, |row| {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001876 let sub_type: SubComponentType =
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001877 row.get(1).context("Failed to extract subcomponent_type.")?;
Janis Danisevskis377d1002021-01-27 19:07:48 -08001878 has_km_blob = has_km_blob || sub_type == SubComponentType::KEY_BLOB;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001879 match (sub_type, load_bits.load_public(), load_bits.load_km()) {
1880 (SubComponentType::KEY_BLOB, _, true) => {
1881 km_blob = Some(row.get(2).context("Failed to extract KM blob.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001882 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001883 (SubComponentType::CERT, true, _) => {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001884 cert_blob =
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001885 Some(row.get(2).context("Failed to extract public certificate blob.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001886 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001887 (SubComponentType::CERT_CHAIN, true, _) => {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001888 cert_chain_blob =
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001889 Some(row.get(2).context("Failed to extract certificate chain blob.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001890 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001891 (SubComponentType::CERT, _, _)
1892 | (SubComponentType::CERT_CHAIN, _, _)
1893 | (SubComponentType::KEY_BLOB, _, _) => {}
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001894 _ => Err(KsError::sys()).context("Unknown subcomponent type.")?,
1895 }
1896 Ok(())
1897 })
1898 .context("In load_blob_components.")?;
1899
Janis Danisevskis377d1002021-01-27 19:07:48 -08001900 Ok((has_km_blob, km_blob, cert_blob, cert_chain_blob))
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001901 }
1902
1903 fn load_key_parameters(key_id: i64, tx: &Transaction) -> Result<Vec<KeyParameter>> {
1904 let mut stmt = tx
1905 .prepare(
1906 "SELECT tag, data, security_level from persistent.keyparameter
1907 WHERE keyentryid = ?;",
1908 )
1909 .context("In load_key_parameters: prepare statement failed.")?;
1910
1911 let mut parameters: Vec<KeyParameter> = Vec::new();
1912
1913 let mut rows =
1914 stmt.query(params![key_id]).context("In load_key_parameters: query failed.")?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08001915 db_utils::with_rows_extract_all(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001916 let tag = Tag(row.get(0).context("Failed to read tag.")?);
1917 let sec_level = SecurityLevel(row.get(2).context("Failed to read sec_level.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001918 parameters.push(
1919 KeyParameter::new_from_sql(tag, &SqlField::new(1, &row), sec_level)
1920 .context("Failed to read KeyParameter.")?,
1921 );
1922 Ok(())
1923 })
1924 .context("In load_key_parameters.")?;
1925
1926 Ok(parameters)
1927 }
1928
Qi Wub9433b52020-12-01 14:52:46 +08001929 /// Decrements the usage count of a limited use key. This function first checks whether the
1930 /// usage has been exhausted, if not, decreases the usage count. If the usage count reaches
1931 /// zero, the key also gets marked unreferenced and scheduled for deletion.
1932 /// Returns Ok(true) if the key was marked unreferenced as a hint to the garbage collector.
1933 pub fn check_and_update_key_usage_count(&mut self, key_id: i64) -> Result<bool> {
1934 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1935 let limit: Option<i32> = tx
1936 .query_row(
1937 "SELECT data FROM persistent.keyparameter WHERE keyentryid = ? AND tag = ?;",
1938 params![key_id, Tag::USAGE_COUNT_LIMIT.0],
1939 |row| row.get(0),
1940 )
1941 .optional()
1942 .context("Trying to load usage count")?;
1943
1944 let limit = limit
1945 .ok_or(KsError::Km(ErrorCode::INVALID_KEY_BLOB))
1946 .context("The Key no longer exists. Key is exhausted.")?;
1947
1948 tx.execute(
1949 "UPDATE persistent.keyparameter
1950 SET data = data - 1
1951 WHERE keyentryid = ? AND tag = ? AND data > 0;",
1952 params![key_id, Tag::USAGE_COUNT_LIMIT.0],
1953 )
1954 .context("Failed to update key usage count.")?;
1955
1956 match limit {
1957 1 => Self::mark_unreferenced(tx, key_id)
1958 .context("Trying to mark limited use key for deletion."),
1959 0 => Err(KsError::Km(ErrorCode::INVALID_KEY_BLOB)).context("Key is exhausted."),
1960 _ => Ok(false),
1961 }
1962 })
1963 .context("In check_and_update_key_usage_count.")
1964 }
1965
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001966 /// Load a key entry by the given key descriptor.
1967 /// It uses the `check_permission` callback to verify if the access is allowed
1968 /// given the key access tuple read from the database using `load_access_tuple`.
1969 /// With `load_bits` the caller may specify which blobs shall be loaded from
1970 /// the blob database.
1971 pub fn load_key_entry(
1972 &mut self,
1973 key: KeyDescriptor,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001974 key_type: KeyType,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001975 load_bits: KeyEntryLoadBits,
1976 caller_uid: u32,
1977 check_permission: impl FnOnce(&KeyDescriptor, Option<KeyPermSet>) -> Result<()>,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001978 ) -> Result<(KeyIdGuard, KeyEntry)> {
1979 // KEY ID LOCK 1/2
1980 // If we got a key descriptor with a key id we can get the lock right away.
1981 // Otherwise we have to defer it until we know the key id.
1982 let key_id_guard = match key.domain {
1983 Domain::KEY_ID => Some(KEY_ID_LOCK.get(key.nspace)),
1984 _ => None,
1985 };
1986
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001987 let tx = self
1988 .conn
Janis Danisevskisaec14592020-11-12 09:41:49 -08001989 .unchecked_transaction()
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001990 .context("In load_key_entry: Failed to initialize transaction.")?;
1991
1992 // Load the key_id and complete the access control tuple.
1993 let (key_id, access_key_descriptor, access_vector) =
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001994 Self::load_access_tuple(&tx, key, key_type, caller_uid)
1995 .context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001996
1997 // Perform access control. It is vital that we return here if the permission is denied.
1998 // So do not touch that '?' at the end.
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001999 check_permission(&access_key_descriptor, access_vector).context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002000
Janis Danisevskisaec14592020-11-12 09:41:49 -08002001 // KEY ID LOCK 2/2
2002 // If we did not get a key id lock by now, it was because we got a key descriptor
2003 // without a key id. At this point we got the key id, so we can try and get a lock.
2004 // However, we cannot block here, because we are in the middle of the transaction.
2005 // So first we try to get the lock non blocking. If that fails, we roll back the
2006 // transaction and block until we get the lock. After we successfully got the lock,
2007 // we start a new transaction and load the access tuple again.
2008 //
2009 // We don't need to perform access control again, because we already established
2010 // that the caller had access to the given key. But we need to make sure that the
2011 // key id still exists. So we have to load the key entry by key id this time.
2012 let (key_id_guard, tx) = match key_id_guard {
2013 None => match KEY_ID_LOCK.try_get(key_id) {
2014 None => {
2015 // Roll back the transaction.
2016 tx.rollback().context("In load_key_entry: Failed to roll back transaction.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002017
Janis Danisevskisaec14592020-11-12 09:41:49 -08002018 // Block until we have a key id lock.
2019 let key_id_guard = KEY_ID_LOCK.get(key_id);
2020
2021 // Create a new transaction.
2022 let tx = self.conn.unchecked_transaction().context(
2023 "In load_key_entry: Failed to initialize transaction. (deferred key lock)",
2024 )?;
2025
2026 Self::load_access_tuple(
2027 &tx,
2028 // This time we have to load the key by the retrieved key id, because the
2029 // alias may have been rebound after we rolled back the transaction.
2030 KeyDescriptor {
2031 domain: Domain::KEY_ID,
2032 nspace: key_id,
2033 ..Default::default()
2034 },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002035 key_type,
Janis Danisevskisaec14592020-11-12 09:41:49 -08002036 caller_uid,
2037 )
2038 .context("In load_key_entry. (deferred key lock)")?;
2039 (key_id_guard, tx)
2040 }
2041 Some(l) => (l, tx),
2042 },
2043 Some(key_id_guard) => (key_id_guard, tx),
2044 };
2045
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002046 let key_entry = Self::load_key_components(&tx, load_bits, key_id_guard.id())
2047 .context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002048
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002049 tx.commit().context("In load_key_entry: Failed to commit transaction.")?;
2050
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002051 Ok((key_id_guard, key_entry))
2052 }
2053
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002054 fn mark_unreferenced(tx: &Transaction, key_id: i64) -> Result<bool> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002055 let updated = tx
2056 .execute(
2057 "UPDATE persistent.keyentry SET state = ? WHERE id = ?;",
2058 params![KeyLifeCycle::Unreferenced, key_id],
2059 )
2060 .context("In mark_unreferenced: Failed to update state of key entry.")?;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002061 tx.execute("DELETE from persistent.grant WHERE keyentryid = ?;", params![key_id])
2062 .context("In mark_unreferenced: Failed to drop grants.")?;
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002063 Ok(updated != 0)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002064 }
2065
2066 /// Marks the given key as unreferenced and removes all of the grants to this key.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002067 /// Returns Ok(true) if a key was marked unreferenced as a hint for the garbage collector.
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002068 pub fn unbind_key(
2069 &mut self,
2070 key: KeyDescriptor,
2071 key_type: KeyType,
2072 caller_uid: u32,
2073 check_permission: impl FnOnce(&KeyDescriptor, Option<KeyPermSet>) -> Result<()>,
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002074 ) -> Result<bool> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002075 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2076 let (key_id, access_key_descriptor, access_vector) =
2077 Self::load_access_tuple(tx, key, key_type, caller_uid)
2078 .context("Trying to get access tuple.")?;
2079
2080 // Perform access control. It is vital that we return here if the permission is denied.
2081 // So do not touch that '?' at the end.
2082 check_permission(&access_key_descriptor, access_vector)
2083 .context("While checking permission.")?;
2084
2085 Self::mark_unreferenced(tx, key_id).context("Trying to mark the key unreferenced.")
2086 })
2087 .context("In unbind_key.")
2088 }
2089
Max Bires8e93d2b2021-01-14 13:17:59 -08002090 fn get_key_km_uuid(tx: &Transaction, key_id: i64) -> Result<Uuid> {
2091 tx.query_row(
2092 "SELECT km_uuid FROM persistent.keyentry WHERE id = ?",
2093 params![key_id],
2094 |row| row.get(0),
2095 )
2096 .context("In get_key_km_uuid.")
2097 }
2098
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002099 fn load_key_components(
2100 tx: &Transaction,
2101 load_bits: KeyEntryLoadBits,
2102 key_id: i64,
2103 ) -> Result<KeyEntry> {
2104 let metadata = KeyMetaData::load_from_db(key_id, &tx).context("In load_key_components.")?;
2105
Janis Danisevskis377d1002021-01-27 19:07:48 -08002106 let (has_km_blob, km_blob, cert_blob, cert_chain_blob) =
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002107 Self::load_blob_components(key_id, load_bits, &tx)
2108 .context("In load_key_components.")?;
2109
Max Bires8e93d2b2021-01-14 13:17:59 -08002110 let parameters = Self::load_key_parameters(key_id, &tx)
2111 .context("In load_key_components: Trying to load key parameters.")?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002112
Max Bires8e93d2b2021-01-14 13:17:59 -08002113 let km_uuid = Self::get_key_km_uuid(&tx, key_id)
2114 .context("In load_key_components: Trying to get KM uuid.")?;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002115
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002116 Ok(KeyEntry {
2117 id: key_id,
2118 km_blob,
2119 cert: cert_blob,
2120 cert_chain: cert_chain_blob,
Max Bires8e93d2b2021-01-14 13:17:59 -08002121 km_uuid,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002122 parameters,
2123 metadata,
Janis Danisevskis377d1002021-01-27 19:07:48 -08002124 pure_cert: !has_km_blob,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002125 })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002126 }
2127
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002128 /// Returns a list of KeyDescriptors in the selected domain/namespace.
2129 /// The key descriptors will have the domain, nspace, and alias field set.
2130 /// Domain must be APP or SELINUX, the caller must make sure of that.
2131 pub fn list(&mut self, domain: Domain, namespace: i64) -> Result<Vec<KeyDescriptor>> {
2132 let mut stmt = self
2133 .conn
2134 .prepare(
2135 "SELECT alias FROM persistent.keyentry
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002136 WHERE domain = ? AND namespace = ? AND alias IS NOT NULL AND state = ?;",
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002137 )
2138 .context("In list: Failed to prepare.")?;
2139
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002140 let mut rows = stmt
2141 .query(params![domain.0 as u32, namespace, KeyLifeCycle::Live])
2142 .context("In list: Failed to query.")?;
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002143
2144 let mut descriptors: Vec<KeyDescriptor> = Vec::new();
2145 db_utils::with_rows_extract_all(&mut rows, |row| {
2146 descriptors.push(KeyDescriptor {
2147 domain,
2148 nspace: namespace,
2149 alias: Some(row.get(0).context("Trying to extract alias.")?),
2150 blob: None,
2151 });
2152 Ok(())
2153 })
2154 .context("In list.")?;
2155 Ok(descriptors)
2156 }
2157
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002158 /// Adds a grant to the grant table.
2159 /// Like `load_key_entry` this function loads the access tuple before
2160 /// it uses the callback for a permission check. Upon success,
2161 /// it inserts the `grantee_uid`, `key_id`, and `access_vector` into the
2162 /// grant table. The new row will have a randomized id, which is used as
2163 /// grant id in the namespace field of the resulting KeyDescriptor.
2164 pub fn grant(
2165 &mut self,
2166 key: KeyDescriptor,
2167 caller_uid: u32,
2168 grantee_uid: u32,
2169 access_vector: KeyPermSet,
2170 check_permission: impl FnOnce(&KeyDescriptor, &KeyPermSet) -> Result<()>,
2171 ) -> Result<KeyDescriptor> {
2172 let tx = self
2173 .conn
2174 .transaction_with_behavior(TransactionBehavior::Immediate)
2175 .context("In grant: Failed to initialize transaction.")?;
2176
2177 // Load the key_id and complete the access control tuple.
2178 // We ignore the access vector here because grants cannot be granted.
2179 // The access vector returned here expresses the permissions the
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002180 // grantee has if key.domain == Domain::GRANT. But this vector
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002181 // cannot include the grant permission by design, so there is no way the
2182 // subsequent permission check can pass.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002183 // We could check key.domain == Domain::GRANT and fail early.
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002184 // But even if we load the access tuple by grant here, the permission
2185 // check denies the attempt to create a grant by grant descriptor.
2186 let (key_id, access_key_descriptor, _) =
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002187 Self::load_access_tuple(&tx, key, KeyType::Client, caller_uid).context("In grant")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002188
2189 // Perform access control. It is vital that we return here if the permission
2190 // was denied. So do not touch that '?' at the end of the line.
2191 // This permission check checks if the caller has the grant permission
2192 // for the given key and in addition to all of the permissions
2193 // expressed in `access_vector`.
2194 check_permission(&access_key_descriptor, &access_vector)
2195 .context("In grant: check_permission failed.")?;
2196
2197 let grant_id = if let Some(grant_id) = tx
2198 .query_row(
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002199 "SELECT id FROM persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002200 WHERE keyentryid = ? AND grantee = ?;",
2201 params![key_id, grantee_uid],
2202 |row| row.get(0),
2203 )
2204 .optional()
2205 .context("In grant: Failed get optional existing grant id.")?
2206 {
2207 tx.execute(
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002208 "UPDATE persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002209 SET access_vector = ?
2210 WHERE id = ?;",
2211 params![i32::from(access_vector), grant_id],
2212 )
2213 .context("In grant: Failed to update existing grant.")?;
2214 grant_id
2215 } else {
Joel Galenson845f74b2020-09-09 14:11:55 -07002216 Self::insert_with_retry(|id| {
2217 tx.execute(
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002218 "INSERT INTO persistent.grant (id, grantee, keyentryid, access_vector)
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002219 VALUES (?, ?, ?, ?);",
Joel Galenson845f74b2020-09-09 14:11:55 -07002220 params![id, grantee_uid, key_id, i32::from(access_vector)],
2221 )
2222 })
2223 .context("In grant")?
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002224 };
2225 tx.commit().context("In grant: failed to commit transaction.")?;
2226
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002227 Ok(KeyDescriptor { domain: Domain::GRANT, nspace: grant_id, alias: None, blob: None })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002228 }
2229
2230 /// This function checks permissions like `grant` and `load_key_entry`
2231 /// before removing a grant from the grant table.
2232 pub fn ungrant(
2233 &mut self,
2234 key: KeyDescriptor,
2235 caller_uid: u32,
2236 grantee_uid: u32,
2237 check_permission: impl FnOnce(&KeyDescriptor) -> Result<()>,
2238 ) -> Result<()> {
2239 let tx = self
2240 .conn
2241 .transaction_with_behavior(TransactionBehavior::Immediate)
2242 .context("In ungrant: Failed to initialize transaction.")?;
2243
2244 // Load the key_id and complete the access control tuple.
2245 // We ignore the access vector here because grants cannot be granted.
2246 let (key_id, access_key_descriptor, _) =
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002247 Self::load_access_tuple(&tx, key, KeyType::Client, caller_uid)
2248 .context("In ungrant.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002249
2250 // Perform access control. We must return here if the permission
2251 // was denied. So do not touch the '?' at the end of this line.
2252 check_permission(&access_key_descriptor).context("In grant: check_permission failed.")?;
2253
2254 tx.execute(
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002255 "DELETE FROM persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002256 WHERE keyentryid = ? AND grantee = ?;",
2257 params![key_id, grantee_uid],
2258 )
2259 .context("Failed to delete grant.")?;
2260
2261 tx.commit().context("In ungrant: failed to commit transaction.")?;
2262
2263 Ok(())
2264 }
2265
Joel Galenson845f74b2020-09-09 14:11:55 -07002266 // Generates a random id and passes it to the given function, which will
2267 // try to insert it into a database. If that insertion fails, retry;
2268 // otherwise return the id.
2269 fn insert_with_retry(inserter: impl Fn(i64) -> rusqlite::Result<usize>) -> Result<i64> {
2270 loop {
2271 let newid: i64 = random();
2272 match inserter(newid) {
2273 // If the id already existed, try again.
2274 Err(rusqlite::Error::SqliteFailure(
2275 libsqlite3_sys::Error {
2276 code: libsqlite3_sys::ErrorCode::ConstraintViolation,
2277 extended_code: libsqlite3_sys::SQLITE_CONSTRAINT_UNIQUE,
2278 },
2279 _,
2280 )) => (),
2281 Err(e) => {
2282 return Err(e).context("In insert_with_retry: failed to insert into database.")
2283 }
2284 _ => return Ok(newid),
2285 }
2286 }
2287 }
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002288
2289 /// Insert or replace the auth token based on the UNIQUE constraint of the auth token table
2290 pub fn insert_auth_token(&mut self, auth_token: &HardwareAuthToken) -> Result<()> {
2291 self.conn
2292 .execute(
2293 "INSERT OR REPLACE INTO perboot.authtoken (challenge, user_id, auth_id,
2294 authenticator_type, timestamp, mac, time_received) VALUES(?, ?, ?, ?, ?, ?, ?);",
2295 params![
2296 auth_token.challenge,
2297 auth_token.userId,
2298 auth_token.authenticatorId,
2299 auth_token.authenticatorType.0 as i32,
2300 auth_token.timestamp.milliSeconds as i64,
2301 auth_token.mac,
2302 MonotonicRawTime::now(),
2303 ],
2304 )
2305 .context("In insert_auth_token: failed to insert auth token into the database")?;
2306 Ok(())
2307 }
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002308
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002309 /// Find the newest auth token matching the given predicate.
2310 pub fn find_auth_token_entry<F>(
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002311 &mut self,
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002312 p: F,
2313 ) -> Result<Option<(AuthTokenEntry, MonotonicRawTime)>>
2314 where
2315 F: Fn(&AuthTokenEntry) -> bool,
2316 {
2317 self.with_transaction(TransactionBehavior::Deferred, |tx| {
2318 let mut stmt = tx
2319 .prepare("SELECT * from perboot.authtoken ORDER BY time_received DESC;")
2320 .context("Prepare statement failed.")?;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002321
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002322 let mut rows = stmt.query(NO_PARAMS).context("Failed to query.")?;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002323
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002324 while let Some(row) = rows.next().context("Failed to get next row.")? {
2325 let entry = AuthTokenEntry::new(
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002326 HardwareAuthToken {
2327 challenge: row.get(1)?,
2328 userId: row.get(2)?,
2329 authenticatorId: row.get(3)?,
2330 authenticatorType: HardwareAuthenticatorType(row.get(4)?),
2331 timestamp: Timestamp { milliSeconds: row.get(5)? },
2332 mac: row.get(6)?,
2333 },
2334 row.get(7)?,
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002335 );
2336 if p(&entry) {
2337 return Ok(Some((
2338 entry,
2339 Self::get_last_off_body(tx)
2340 .context("In find_auth_token_entry: Trying to get last off body")?,
2341 )));
2342 }
2343 }
2344 Ok(None)
2345 })
2346 .context("In find_auth_token_entry.")
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002347 }
2348
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002349 /// Insert last_off_body into the metadata table at the initialization of auth token table
2350 pub fn insert_last_off_body(&self, last_off_body: MonotonicRawTime) -> Result<()> {
2351 self.conn
2352 .execute(
2353 "INSERT OR REPLACE INTO perboot.metadata (key, value) VALUES (?, ?);",
2354 params!["last_off_body", last_off_body],
2355 )
2356 .context("In insert_last_off_body: failed to insert.")?;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002357 Ok(())
2358 }
2359
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002360 /// Update last_off_body when on_device_off_body is called
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002361 pub fn update_last_off_body(&self, last_off_body: MonotonicRawTime) -> Result<()> {
2362 self.conn
2363 .execute(
2364 "UPDATE perboot.metadata SET value = ? WHERE key = ?;",
2365 params![last_off_body, "last_off_body"],
2366 )
2367 .context("In update_last_off_body: failed to update.")?;
2368 Ok(())
2369 }
2370
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002371 /// Get last_off_body time when finding auth tokens
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002372 fn get_last_off_body(tx: &Transaction) -> Result<MonotonicRawTime> {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002373 tx.query_row(
2374 "SELECT value from perboot.metadata WHERE key = ?;",
2375 params!["last_off_body"],
2376 |row| Ok(row.get(0)?),
2377 )
2378 .context("In get_last_off_body: query_row failed.")
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002379 }
Joel Galenson26f4d012020-07-17 14:57:21 -07002380}
2381
2382#[cfg(test)]
2383mod tests {
2384
2385 use super::*;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002386 use crate::key_parameter::{
2387 Algorithm, BlockMode, Digest, EcCurve, HardwareAuthenticatorType, KeyOrigin, KeyParameter,
2388 KeyParameterValue, KeyPurpose, PaddingMode, SecurityLevel,
2389 };
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002390 use crate::key_perm_set;
2391 use crate::permission::{KeyPerm, KeyPermSet};
Janis Danisevskis2a8330a2021-01-20 15:34:26 -08002392 use keystore2_test_utils::TempDir;
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002393 use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
2394 HardwareAuthToken::HardwareAuthToken,
2395 HardwareAuthenticatorType::HardwareAuthenticatorType as kmhw_authenticator_type,
Janis Danisevskisc3a496b2021-01-05 10:37:22 -08002396 };
2397 use android_hardware_security_secureclock::aidl::android::hardware::security::secureclock::{
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002398 Timestamp::Timestamp,
2399 };
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002400 use rusqlite::NO_PARAMS;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002401 use rusqlite::{Error, TransactionBehavior};
Joel Galenson0891bc12020-07-20 10:37:03 -07002402 use std::cell::RefCell;
Janis Danisevskisaec14592020-11-12 09:41:49 -08002403 use std::sync::atomic::{AtomicU8, Ordering};
2404 use std::sync::Arc;
2405 use std::thread;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002406 use std::time::{Duration, SystemTime};
Joel Galenson0891bc12020-07-20 10:37:03 -07002407
Janis Danisevskis4df44f42020-08-26 14:40:03 -07002408 fn new_test_db() -> Result<KeystoreDB> {
2409 let conn = KeystoreDB::make_connection("file::memory:", "file::memory:")?;
2410
2411 KeystoreDB::init_tables(&conn).context("Failed to initialize tables.")?;
2412 Ok(KeystoreDB { conn })
2413 }
2414
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002415 fn rebind_alias(
2416 db: &mut KeystoreDB,
2417 newid: &KeyIdGuard,
2418 alias: &str,
2419 domain: Domain,
2420 namespace: i64,
2421 ) -> Result<bool> {
2422 db.with_transaction(TransactionBehavior::Immediate, |tx| {
2423 KeystoreDB::rebind_alias(tx, newid, alias, domain, namespace)
2424 })
2425 .context("In rebind_alias.")
2426 }
2427
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002428 #[test]
2429 fn datetime() -> Result<()> {
2430 let conn = Connection::open_in_memory()?;
2431 conn.execute("CREATE TABLE test (ts DATETIME);", NO_PARAMS)?;
2432 let now = SystemTime::now();
2433 let duration = Duration::from_secs(1000);
2434 let then = now.checked_sub(duration).unwrap();
2435 let soon = now.checked_add(duration).unwrap();
2436 conn.execute(
2437 "INSERT INTO test (ts) VALUES (?), (?), (?);",
2438 params![DateTime::try_from(now)?, DateTime::try_from(then)?, DateTime::try_from(soon)?],
2439 )?;
2440 let mut stmt = conn.prepare("SELECT ts FROM test ORDER BY ts ASC;")?;
2441 let mut rows = stmt.query(NO_PARAMS)?;
2442 assert_eq!(DateTime::try_from(then)?, rows.next()?.unwrap().get(0)?);
2443 assert_eq!(DateTime::try_from(now)?, rows.next()?.unwrap().get(0)?);
2444 assert_eq!(DateTime::try_from(soon)?, rows.next()?.unwrap().get(0)?);
2445 assert!(rows.next()?.is_none());
2446 assert!(DateTime::try_from(then)? < DateTime::try_from(now)?);
2447 assert!(DateTime::try_from(then)? < DateTime::try_from(soon)?);
2448 assert!(DateTime::try_from(now)? < DateTime::try_from(soon)?);
2449 Ok(())
2450 }
2451
Joel Galenson0891bc12020-07-20 10:37:03 -07002452 // Ensure that we're using the "injected" random function, not the real one.
2453 #[test]
2454 fn test_mocked_random() {
2455 let rand1 = random();
2456 let rand2 = random();
2457 let rand3 = random();
2458 if rand1 == rand2 {
2459 assert_eq!(rand2 + 1, rand3);
2460 } else {
2461 assert_eq!(rand1 + 1, rand2);
2462 assert_eq!(rand2, rand3);
2463 }
2464 }
Joel Galenson26f4d012020-07-17 14:57:21 -07002465
Joel Galenson26f4d012020-07-17 14:57:21 -07002466 // Test that we have the correct tables.
2467 #[test]
2468 fn test_tables() -> Result<()> {
Janis Danisevskis4df44f42020-08-26 14:40:03 -07002469 let db = new_test_db()?;
Joel Galenson26f4d012020-07-17 14:57:21 -07002470 let tables = db
2471 .conn
Joel Galenson2aab4432020-07-22 15:27:57 -07002472 .prepare("SELECT name from persistent.sqlite_master WHERE type='table' ORDER BY name;")?
Joel Galenson26f4d012020-07-17 14:57:21 -07002473 .query_map(params![], |row| row.get(0))?
2474 .collect::<rusqlite::Result<Vec<String>>>()?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002475 assert_eq!(tables.len(), 5);
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002476 assert_eq!(tables[0], "blobentry");
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002477 assert_eq!(tables[1], "grant");
2478 assert_eq!(tables[2], "keyentry");
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002479 assert_eq!(tables[3], "keymetadata");
2480 assert_eq!(tables[4], "keyparameter");
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002481 let tables = db
2482 .conn
2483 .prepare("SELECT name from perboot.sqlite_master WHERE type='table' ORDER BY name;")?
2484 .query_map(params![], |row| row.get(0))?
2485 .collect::<rusqlite::Result<Vec<String>>>()?;
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002486
2487 assert_eq!(tables.len(), 2);
2488 assert_eq!(tables[0], "authtoken");
2489 assert_eq!(tables[1], "metadata");
Joel Galenson2aab4432020-07-22 15:27:57 -07002490 Ok(())
2491 }
2492
2493 #[test]
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002494 fn test_auth_token_table_invariant() -> Result<()> {
2495 let mut db = new_test_db()?;
2496 let auth_token1 = HardwareAuthToken {
2497 challenge: i64::MAX,
2498 userId: 200,
2499 authenticatorId: 200,
2500 authenticatorType: kmhw_authenticator_type(kmhw_authenticator_type::PASSWORD.0),
2501 timestamp: Timestamp { milliSeconds: 500 },
2502 mac: String::from("mac").into_bytes(),
2503 };
2504 db.insert_auth_token(&auth_token1)?;
2505 let auth_tokens_returned = get_auth_tokens(&mut db)?;
2506 assert_eq!(auth_tokens_returned.len(), 1);
2507
2508 // insert another auth token with the same values for the columns in the UNIQUE constraint
2509 // of the auth token table and different value for timestamp
2510 let auth_token2 = HardwareAuthToken {
2511 challenge: i64::MAX,
2512 userId: 200,
2513 authenticatorId: 200,
2514 authenticatorType: kmhw_authenticator_type(kmhw_authenticator_type::PASSWORD.0),
2515 timestamp: Timestamp { milliSeconds: 600 },
2516 mac: String::from("mac").into_bytes(),
2517 };
2518
2519 db.insert_auth_token(&auth_token2)?;
2520 let mut auth_tokens_returned = get_auth_tokens(&mut db)?;
2521 assert_eq!(auth_tokens_returned.len(), 1);
2522
2523 if let Some(auth_token) = auth_tokens_returned.pop() {
2524 assert_eq!(auth_token.auth_token.timestamp.milliSeconds, 600);
2525 }
2526
2527 // insert another auth token with the different values for the columns in the UNIQUE
2528 // constraint of the auth token table
2529 let auth_token3 = HardwareAuthToken {
2530 challenge: i64::MAX,
2531 userId: 201,
2532 authenticatorId: 200,
2533 authenticatorType: kmhw_authenticator_type(kmhw_authenticator_type::PASSWORD.0),
2534 timestamp: Timestamp { milliSeconds: 600 },
2535 mac: String::from("mac").into_bytes(),
2536 };
2537
2538 db.insert_auth_token(&auth_token3)?;
2539 let auth_tokens_returned = get_auth_tokens(&mut db)?;
2540 assert_eq!(auth_tokens_returned.len(), 2);
2541
2542 Ok(())
2543 }
2544
2545 // utility function for test_auth_token_table_invariant()
2546 fn get_auth_tokens(db: &mut KeystoreDB) -> Result<Vec<AuthTokenEntry>> {
2547 let mut stmt = db.conn.prepare("SELECT * from perboot.authtoken;")?;
2548
2549 let auth_token_entries: Vec<AuthTokenEntry> = stmt
2550 .query_map(NO_PARAMS, |row| {
2551 Ok(AuthTokenEntry::new(
2552 HardwareAuthToken {
2553 challenge: row.get(1)?,
2554 userId: row.get(2)?,
2555 authenticatorId: row.get(3)?,
2556 authenticatorType: HardwareAuthenticatorType(row.get(4)?),
2557 timestamp: Timestamp { milliSeconds: row.get(5)? },
2558 mac: row.get(6)?,
2559 },
2560 row.get(7)?,
2561 ))
2562 })?
2563 .collect::<Result<Vec<AuthTokenEntry>, Error>>()?;
2564 Ok(auth_token_entries)
2565 }
2566
2567 #[test]
Joel Galenson2aab4432020-07-22 15:27:57 -07002568 fn test_persistence_for_files() -> Result<()> {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002569 let temp_dir = TempDir::new("persistent_db_test")?;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002570 let mut db = KeystoreDB::new(temp_dir.path())?;
Joel Galenson2aab4432020-07-22 15:27:57 -07002571
Max Bires8e93d2b2021-01-14 13:17:59 -08002572 db.create_key_entry(Domain::APP, 100, &KEYSTORE_UUID)?;
Joel Galenson2aab4432020-07-22 15:27:57 -07002573 let entries = get_keyentry(&db)?;
2574 assert_eq!(entries.len(), 1);
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002575
2576 let db = KeystoreDB::new(temp_dir.path())?;
Joel Galenson2aab4432020-07-22 15:27:57 -07002577
2578 let entries_new = get_keyentry(&db)?;
2579 assert_eq!(entries, entries_new);
2580 Ok(())
2581 }
2582
2583 #[test]
Joel Galenson0891bc12020-07-20 10:37:03 -07002584 fn test_create_key_entry() -> Result<()> {
Max Bires8e93d2b2021-01-14 13:17:59 -08002585 fn extractor(ke: &KeyEntryRow) -> (Domain, i64, Option<&str>, Uuid) {
2586 (ke.domain.unwrap(), ke.namespace.unwrap(), ke.alias.as_deref(), ke.km_uuid.unwrap())
Joel Galenson0891bc12020-07-20 10:37:03 -07002587 }
2588
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002589 let mut db = new_test_db()?;
Joel Galenson0891bc12020-07-20 10:37:03 -07002590
Max Bires8e93d2b2021-01-14 13:17:59 -08002591 db.create_key_entry(Domain::APP, 100, &KEYSTORE_UUID)?;
2592 db.create_key_entry(Domain::SELINUX, 101, &KEYSTORE_UUID)?;
Joel Galenson0891bc12020-07-20 10:37:03 -07002593
2594 let entries = get_keyentry(&db)?;
2595 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08002596 assert_eq!(extractor(&entries[0]), (Domain::APP, 100, None, KEYSTORE_UUID));
2597 assert_eq!(extractor(&entries[1]), (Domain::SELINUX, 101, None, KEYSTORE_UUID));
Joel Galenson0891bc12020-07-20 10:37:03 -07002598
2599 // Test that we must pass in a valid Domain.
2600 check_result_is_error_containing_string(
Max Bires8e93d2b2021-01-14 13:17:59 -08002601 db.create_key_entry(Domain::GRANT, 102, &KEYSTORE_UUID),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002602 "Domain Domain(1) must be either App or SELinux.",
Joel Galenson0891bc12020-07-20 10:37:03 -07002603 );
2604 check_result_is_error_containing_string(
Max Bires8e93d2b2021-01-14 13:17:59 -08002605 db.create_key_entry(Domain::BLOB, 103, &KEYSTORE_UUID),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002606 "Domain Domain(3) must be either App or SELinux.",
Joel Galenson0891bc12020-07-20 10:37:03 -07002607 );
2608 check_result_is_error_containing_string(
Max Bires8e93d2b2021-01-14 13:17:59 -08002609 db.create_key_entry(Domain::KEY_ID, 104, &KEYSTORE_UUID),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002610 "Domain Domain(4) must be either App or SELinux.",
Joel Galenson0891bc12020-07-20 10:37:03 -07002611 );
2612
2613 Ok(())
2614 }
2615
Joel Galenson33c04ad2020-08-03 11:04:38 -07002616 #[test]
Max Bires2b2e6562020-09-22 11:22:36 -07002617 fn test_add_unsigned_key() -> Result<()> {
2618 let mut db = new_test_db()?;
2619 let public_key: Vec<u8> = vec![0x01, 0x02, 0x03];
2620 let private_key: Vec<u8> = vec![0x04, 0x05, 0x06];
2621 let raw_public_key: Vec<u8> = vec![0x07, 0x08, 0x09];
2622 db.create_attestation_key_entry(
2623 &public_key,
2624 &raw_public_key,
2625 &private_key,
2626 &KEYSTORE_UUID,
2627 )?;
2628 let keys = db.fetch_unsigned_attestation_keys(5, &KEYSTORE_UUID)?;
2629 assert_eq!(keys.len(), 1);
2630 assert_eq!(keys[0], public_key);
2631 Ok(())
2632 }
2633
2634 #[test]
2635 fn test_store_signed_attestation_certificate_chain() -> Result<()> {
2636 let mut db = new_test_db()?;
2637 let expiration_date: i64 = 20;
2638 let namespace: i64 = 30;
2639 let base_byte: u8 = 1;
2640 let loaded_values =
2641 load_attestation_key_pool(&mut db, expiration_date, namespace, base_byte)?;
2642 let chain =
2643 db.retrieve_attestation_key_and_cert_chain(Domain::APP, namespace, &KEYSTORE_UUID)?;
2644 assert_eq!(true, chain.is_some());
2645 let cert_chain = chain.unwrap();
2646 assert_eq!(cert_chain.private_key.to_vec(), loaded_values[2]);
2647 assert_eq!(cert_chain.cert_chain.to_vec(), loaded_values[1]);
2648 Ok(())
2649 }
2650
2651 #[test]
2652 fn test_get_attestation_pool_status() -> Result<()> {
2653 let mut db = new_test_db()?;
2654 let namespace: i64 = 30;
2655 load_attestation_key_pool(
2656 &mut db, 10, /* expiration */
2657 namespace, 0x01, /* base_byte */
2658 )?;
2659 load_attestation_key_pool(&mut db, 20 /* expiration */, namespace + 1, 0x02)?;
2660 load_attestation_key_pool(&mut db, 40 /* expiration */, namespace + 2, 0x03)?;
2661 let mut status = db.get_attestation_pool_status(9 /* expiration */, &KEYSTORE_UUID)?;
2662 assert_eq!(status.expiring, 0);
2663 assert_eq!(status.attested, 3);
2664 assert_eq!(status.unassigned, 0);
2665 assert_eq!(status.total, 3);
2666 assert_eq!(
2667 db.get_attestation_pool_status(15 /* expiration */, &KEYSTORE_UUID)?.expiring,
2668 1
2669 );
2670 assert_eq!(
2671 db.get_attestation_pool_status(25 /* expiration */, &KEYSTORE_UUID)?.expiring,
2672 2
2673 );
2674 assert_eq!(
2675 db.get_attestation_pool_status(60 /* expiration */, &KEYSTORE_UUID)?.expiring,
2676 3
2677 );
2678 let public_key: Vec<u8> = vec![0x01, 0x02, 0x03];
2679 let private_key: Vec<u8> = vec![0x04, 0x05, 0x06];
2680 let raw_public_key: Vec<u8> = vec![0x07, 0x08, 0x09];
2681 let cert_chain: Vec<u8> = vec![0x0a, 0x0b, 0x0c];
2682 db.create_attestation_key_entry(
2683 &public_key,
2684 &raw_public_key,
2685 &private_key,
2686 &KEYSTORE_UUID,
2687 )?;
2688 status = db.get_attestation_pool_status(0 /* expiration */, &KEYSTORE_UUID)?;
2689 assert_eq!(status.attested, 3);
2690 assert_eq!(status.unassigned, 0);
2691 assert_eq!(status.total, 4);
2692 db.store_signed_attestation_certificate_chain(
2693 &raw_public_key,
2694 &cert_chain,
2695 20,
2696 &KEYSTORE_UUID,
2697 )?;
2698 status = db.get_attestation_pool_status(0 /* expiration */, &KEYSTORE_UUID)?;
2699 assert_eq!(status.attested, 4);
2700 assert_eq!(status.unassigned, 1);
2701 assert_eq!(status.total, 4);
2702 Ok(())
2703 }
2704
2705 #[test]
2706 fn test_remove_expired_certs() -> Result<()> {
2707 let mut db = new_test_db()?;
2708 let expiration_date: i64 =
2709 SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_millis() as i64 + 10000;
2710 let namespace: i64 = 30;
2711 let namespace_del1: i64 = 45;
2712 let namespace_del2: i64 = 60;
2713 let entry_values = load_attestation_key_pool(
2714 &mut db,
2715 expiration_date,
2716 namespace,
2717 0x01, /* base_byte */
2718 )?;
2719 load_attestation_key_pool(&mut db, 45, namespace_del1, 0x02)?;
2720 load_attestation_key_pool(&mut db, 60, namespace_del2, 0x03)?;
2721 assert_eq!(db.delete_expired_attestation_keys()?, 2);
2722
2723 let mut cert_chain =
2724 db.retrieve_attestation_key_and_cert_chain(Domain::APP, namespace, &KEYSTORE_UUID)?;
2725 assert_eq!(true, cert_chain.is_some());
2726 let value = cert_chain.unwrap();
2727 assert_eq!(entry_values[1], value.cert_chain.to_vec());
2728 assert_eq!(entry_values[2], value.private_key.to_vec());
2729
2730 cert_chain = db.retrieve_attestation_key_and_cert_chain(
2731 Domain::APP,
2732 namespace_del1,
2733 &KEYSTORE_UUID,
2734 )?;
2735 assert_eq!(false, cert_chain.is_some());
2736 cert_chain = db.retrieve_attestation_key_and_cert_chain(
2737 Domain::APP,
2738 namespace_del2,
2739 &KEYSTORE_UUID,
2740 )?;
2741 assert_eq!(false, cert_chain.is_some());
2742
2743 let mut option_entry = db.get_unreferenced_key()?;
2744 assert_eq!(true, option_entry.is_some());
2745 let (key_guard, _) = option_entry.unwrap();
2746 db.purge_key_entry(key_guard)?;
2747
2748 option_entry = db.get_unreferenced_key()?;
2749 assert_eq!(true, option_entry.is_some());
2750 let (key_guard, _) = option_entry.unwrap();
2751 db.purge_key_entry(key_guard)?;
2752
2753 option_entry = db.get_unreferenced_key()?;
2754 assert_eq!(false, option_entry.is_some());
2755 Ok(())
2756 }
2757
2758 #[test]
Joel Galenson33c04ad2020-08-03 11:04:38 -07002759 fn test_rebind_alias() -> Result<()> {
Max Bires8e93d2b2021-01-14 13:17:59 -08002760 fn extractor(
2761 ke: &KeyEntryRow,
2762 ) -> (Option<Domain>, Option<i64>, Option<&str>, Option<Uuid>) {
2763 (ke.domain, ke.namespace, ke.alias.as_deref(), ke.km_uuid)
Joel Galenson33c04ad2020-08-03 11:04:38 -07002764 }
2765
Janis Danisevskis4df44f42020-08-26 14:40:03 -07002766 let mut db = new_test_db()?;
Max Bires8e93d2b2021-01-14 13:17:59 -08002767 db.create_key_entry(Domain::APP, 42, &KEYSTORE_UUID)?;
2768 db.create_key_entry(Domain::APP, 42, &KEYSTORE_UUID)?;
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), None, 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 first call to rebind_alias sets the alias.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002781 rebind_alias(&mut db, &KEY_ID_LOCK.get(entries[0].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!(
2785 extractor(&entries[0]),
2786 (Some(Domain::APP), Some(42), Some("foo"), Some(KEYSTORE_UUID))
2787 );
2788 assert_eq!(
2789 extractor(&entries[1]),
2790 (Some(Domain::APP), Some(42), None, Some(KEYSTORE_UUID))
2791 );
Joel Galenson33c04ad2020-08-03 11:04:38 -07002792
2793 // Test that the second call to rebind_alias also empties the old one.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002794 rebind_alias(&mut db, &KEY_ID_LOCK.get(entries[1].id), "foo", Domain::APP, 42)?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07002795 let entries = get_keyentry(&db)?;
2796 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08002797 assert_eq!(extractor(&entries[0]), (None, None, None, Some(KEYSTORE_UUID)));
2798 assert_eq!(
2799 extractor(&entries[1]),
2800 (Some(Domain::APP), Some(42), Some("foo"), Some(KEYSTORE_UUID))
2801 );
Joel Galenson33c04ad2020-08-03 11:04:38 -07002802
2803 // Test that we must pass in a valid Domain.
2804 check_result_is_error_containing_string(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002805 rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::GRANT, 42),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002806 "Domain Domain(1) must be either App or SELinux.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07002807 );
2808 check_result_is_error_containing_string(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002809 rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::BLOB, 42),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002810 "Domain Domain(3) must be either App or SELinux.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07002811 );
2812 check_result_is_error_containing_string(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002813 rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::KEY_ID, 42),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002814 "Domain Domain(4) must be either App or SELinux.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07002815 );
2816
2817 // Test that we correctly handle setting an alias for something that does not exist.
2818 check_result_is_error_containing_string(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002819 rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::SELINUX, 42),
Joel Galenson33c04ad2020-08-03 11:04:38 -07002820 "Expected to update a single entry but instead updated 0",
2821 );
2822 // Test that we correctly abort the transaction in this case.
2823 let entries = get_keyentry(&db)?;
2824 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08002825 assert_eq!(extractor(&entries[0]), (None, None, None, Some(KEYSTORE_UUID)));
2826 assert_eq!(
2827 extractor(&entries[1]),
2828 (Some(Domain::APP), Some(42), Some("foo"), Some(KEYSTORE_UUID))
2829 );
Joel Galenson33c04ad2020-08-03 11:04:38 -07002830
2831 Ok(())
2832 }
2833
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002834 #[test]
2835 fn test_grant_ungrant() -> Result<()> {
2836 const CALLER_UID: u32 = 15;
2837 const GRANTEE_UID: u32 = 12;
2838 const SELINUX_NAMESPACE: i64 = 7;
2839
2840 let mut db = new_test_db()?;
2841 db.conn.execute(
Max Bires8e93d2b2021-01-14 13:17:59 -08002842 "INSERT INTO persistent.keyentry (id, key_type, domain, namespace, alias, state, km_uuid)
2843 VALUES (1, 0, 0, 15, 'key', 1, ?), (2, 0, 2, 7, 'yek', 1, ?);",
2844 params![KEYSTORE_UUID, KEYSTORE_UUID],
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002845 )?;
2846 let app_key = KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002847 domain: super::Domain::APP,
2848 nspace: 0,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002849 alias: Some("key".to_string()),
2850 blob: None,
2851 };
2852 const PVEC1: KeyPermSet = key_perm_set![KeyPerm::use_(), KeyPerm::get_info()];
2853 const PVEC2: KeyPermSet = key_perm_set![KeyPerm::use_()];
2854
2855 // Reset totally predictable random number generator in case we
2856 // are not the first test running on this thread.
2857 reset_random();
2858 let next_random = 0i64;
2859
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002860 let app_granted_key = db
2861 .grant(app_key.clone(), CALLER_UID, GRANTEE_UID, PVEC1, |k, a| {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002862 assert_eq!(*a, PVEC1);
2863 assert_eq!(
2864 *k,
2865 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002866 domain: super::Domain::APP,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002867 // namespace must be set to the caller_uid.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002868 nspace: CALLER_UID as i64,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002869 alias: Some("key".to_string()),
2870 blob: None,
2871 }
2872 );
2873 Ok(())
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002874 })
2875 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002876
2877 assert_eq!(
2878 app_granted_key,
2879 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002880 domain: super::Domain::GRANT,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002881 // The grantid is next_random due to the mock random number generator.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002882 nspace: next_random,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002883 alias: None,
2884 blob: None,
2885 }
2886 );
2887
2888 let selinux_key = KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002889 domain: super::Domain::SELINUX,
2890 nspace: SELINUX_NAMESPACE,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002891 alias: Some("yek".to_string()),
2892 blob: None,
2893 };
2894
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002895 let selinux_granted_key = db
2896 .grant(selinux_key.clone(), CALLER_UID, 12, PVEC1, |k, a| {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002897 assert_eq!(*a, PVEC1);
2898 assert_eq!(
2899 *k,
2900 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002901 domain: super::Domain::SELINUX,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002902 // namespace must be the supplied SELinux
2903 // namespace.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002904 nspace: SELINUX_NAMESPACE,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002905 alias: Some("yek".to_string()),
2906 blob: None,
2907 }
2908 );
2909 Ok(())
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002910 })
2911 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002912
2913 assert_eq!(
2914 selinux_granted_key,
2915 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002916 domain: super::Domain::GRANT,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002917 // The grantid is next_random + 1 due to the mock random number generator.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002918 nspace: next_random + 1,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002919 alias: None,
2920 blob: None,
2921 }
2922 );
2923
2924 // This should update the existing grant with PVEC2.
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002925 let selinux_granted_key = db
2926 .grant(selinux_key.clone(), CALLER_UID, 12, PVEC2, |k, a| {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002927 assert_eq!(*a, PVEC2);
2928 assert_eq!(
2929 *k,
2930 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002931 domain: super::Domain::SELINUX,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002932 // namespace must be the supplied SELinux
2933 // namespace.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002934 nspace: SELINUX_NAMESPACE,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002935 alias: Some("yek".to_string()),
2936 blob: None,
2937 }
2938 );
2939 Ok(())
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002940 })
2941 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002942
2943 assert_eq!(
2944 selinux_granted_key,
2945 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002946 domain: super::Domain::GRANT,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002947 // Same grant id as before. The entry was only updated.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002948 nspace: next_random + 1,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002949 alias: None,
2950 blob: None,
2951 }
2952 );
2953
2954 {
2955 // Limiting scope of stmt, because it borrows db.
2956 let mut stmt = db
2957 .conn
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002958 .prepare("SELECT id, grantee, keyentryid, access_vector FROM persistent.grant;")?;
Janis Danisevskisee10b5f2020-09-22 16:42:35 -07002959 let mut rows =
2960 stmt.query_map::<(i64, u32, i64, KeyPermSet), _, _>(NO_PARAMS, |row| {
2961 Ok((
2962 row.get(0)?,
2963 row.get(1)?,
2964 row.get(2)?,
2965 KeyPermSet::from(row.get::<_, i32>(3)?),
2966 ))
2967 })?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002968
2969 let r = rows.next().unwrap().unwrap();
Janis Danisevskisee10b5f2020-09-22 16:42:35 -07002970 assert_eq!(r, (next_random, GRANTEE_UID, 1, PVEC1));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002971 let r = rows.next().unwrap().unwrap();
Janis Danisevskisee10b5f2020-09-22 16:42:35 -07002972 assert_eq!(r, (next_random + 1, GRANTEE_UID, 2, PVEC2));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002973 assert!(rows.next().is_none());
2974 }
2975
2976 debug_dump_keyentry_table(&mut db)?;
2977 println!("app_key {:?}", app_key);
2978 println!("selinux_key {:?}", selinux_key);
2979
2980 db.ungrant(app_key, CALLER_UID, GRANTEE_UID, |_| Ok(()))?;
2981 db.ungrant(selinux_key, CALLER_UID, GRANTEE_UID, |_| Ok(()))?;
2982
2983 Ok(())
2984 }
2985
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002986 static TEST_KEY_BLOB: &[u8] = b"my test blob";
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002987 static TEST_CERT_BLOB: &[u8] = b"my test cert";
2988 static TEST_CERT_CHAIN_BLOB: &[u8] = b"my test cert_chain";
2989
2990 #[test]
Janis Danisevskis377d1002021-01-27 19:07:48 -08002991 fn test_set_blob() -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002992 let key_id = KEY_ID_LOCK.get(3000);
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002993 let mut db = new_test_db()?;
Janis Danisevskis377d1002021-01-27 19:07:48 -08002994 db.set_blob(&key_id, SubComponentType::KEY_BLOB, Some(TEST_KEY_BLOB))?;
2995 db.set_blob(&key_id, SubComponentType::CERT, Some(TEST_CERT_BLOB))?;
2996 db.set_blob(&key_id, SubComponentType::CERT_CHAIN, Some(TEST_CERT_CHAIN_BLOB))?;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002997 drop(key_id);
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002998
2999 let mut stmt = db.conn.prepare(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003000 "SELECT subcomponent_type, keyentryid, blob FROM persistent.blobentry
3001 ORDER BY subcomponent_type ASC;",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003002 )?;
3003 let mut rows = stmt
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003004 .query_map::<(SubComponentType, i64, Vec<u8>), _, _>(NO_PARAMS, |row| {
3005 Ok((row.get(0)?, row.get(1)?, row.get(2)?))
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003006 })?;
3007 let r = rows.next().unwrap().unwrap();
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003008 assert_eq!(r, (SubComponentType::KEY_BLOB, 3000, TEST_KEY_BLOB.to_vec()));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003009 let r = rows.next().unwrap().unwrap();
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003010 assert_eq!(r, (SubComponentType::CERT, 3000, TEST_CERT_BLOB.to_vec()));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003011 let r = rows.next().unwrap().unwrap();
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003012 assert_eq!(r, (SubComponentType::CERT_CHAIN, 3000, TEST_CERT_CHAIN_BLOB.to_vec()));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003013
3014 Ok(())
3015 }
3016
3017 static TEST_ALIAS: &str = "my super duper key";
3018
3019 #[test]
3020 fn test_insert_and_load_full_keyentry_domain_app() -> Result<()> {
3021 let mut db = new_test_db()?;
Qi Wub9433b52020-12-01 14:52:46 +08003022 let key_id = make_test_key_entry(&mut db, Domain::APP, 1, TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08003023 .context("test_insert_and_load_full_keyentry_domain_app")?
3024 .0;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003025 let (_key_guard, key_entry) = db
3026 .load_key_entry(
3027 KeyDescriptor {
3028 domain: Domain::APP,
3029 nspace: 0,
3030 alias: Some(TEST_ALIAS.to_string()),
3031 blob: None,
3032 },
3033 KeyType::Client,
3034 KeyEntryLoadBits::BOTH,
3035 1,
3036 |_k, _av| Ok(()),
3037 )
3038 .unwrap();
Qi Wub9433b52020-12-01 14:52:46 +08003039 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003040
3041 db.unbind_key(
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003042 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003043 domain: Domain::APP,
3044 nspace: 0,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003045 alias: Some(TEST_ALIAS.to_string()),
3046 blob: None,
3047 },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003048 KeyType::Client,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003049 1,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003050 |_, _| Ok(()),
3051 )
3052 .unwrap();
3053
3054 assert_eq!(
3055 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
3056 db.load_key_entry(
3057 KeyDescriptor {
3058 domain: Domain::APP,
3059 nspace: 0,
3060 alias: Some(TEST_ALIAS.to_string()),
3061 blob: None,
3062 },
3063 KeyType::Client,
3064 KeyEntryLoadBits::NONE,
3065 1,
3066 |_k, _av| Ok(()),
3067 )
3068 .unwrap_err()
3069 .root_cause()
3070 .downcast_ref::<KsError>()
3071 );
3072
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003073 Ok(())
3074 }
3075
3076 #[test]
Janis Danisevskis377d1002021-01-27 19:07:48 -08003077 fn test_insert_and_load_certificate_entry_domain_app() -> Result<()> {
3078 let mut db = new_test_db()?;
3079
3080 db.store_new_certificate(
3081 KeyDescriptor {
3082 domain: Domain::APP,
3083 nspace: 1,
3084 alias: Some(TEST_ALIAS.to_string()),
3085 blob: None,
3086 },
3087 TEST_CERT_BLOB,
Max Bires8e93d2b2021-01-14 13:17:59 -08003088 &KEYSTORE_UUID,
Janis Danisevskis377d1002021-01-27 19:07:48 -08003089 )
3090 .expect("Trying to insert cert.");
3091
3092 let (_key_guard, mut key_entry) = db
3093 .load_key_entry(
3094 KeyDescriptor {
3095 domain: Domain::APP,
3096 nspace: 1,
3097 alias: Some(TEST_ALIAS.to_string()),
3098 blob: None,
3099 },
3100 KeyType::Client,
3101 KeyEntryLoadBits::PUBLIC,
3102 1,
3103 |_k, _av| Ok(()),
3104 )
3105 .expect("Trying to read certificate entry.");
3106
3107 assert!(key_entry.pure_cert());
3108 assert!(key_entry.cert().is_none());
3109 assert_eq!(key_entry.take_cert_chain(), Some(TEST_CERT_BLOB.to_vec()));
3110
3111 db.unbind_key(
3112 KeyDescriptor {
3113 domain: Domain::APP,
3114 nspace: 1,
3115 alias: Some(TEST_ALIAS.to_string()),
3116 blob: None,
3117 },
3118 KeyType::Client,
3119 1,
3120 |_, _| Ok(()),
3121 )
3122 .unwrap();
3123
3124 assert_eq!(
3125 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
3126 db.load_key_entry(
3127 KeyDescriptor {
3128 domain: Domain::APP,
3129 nspace: 1,
3130 alias: Some(TEST_ALIAS.to_string()),
3131 blob: None,
3132 },
3133 KeyType::Client,
3134 KeyEntryLoadBits::NONE,
3135 1,
3136 |_k, _av| Ok(()),
3137 )
3138 .unwrap_err()
3139 .root_cause()
3140 .downcast_ref::<KsError>()
3141 );
3142
3143 Ok(())
3144 }
3145
3146 #[test]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003147 fn test_insert_and_load_full_keyentry_domain_selinux() -> Result<()> {
3148 let mut db = new_test_db()?;
Qi Wub9433b52020-12-01 14:52:46 +08003149 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08003150 .context("test_insert_and_load_full_keyentry_domain_selinux")?
3151 .0;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003152 let (_key_guard, key_entry) = db
3153 .load_key_entry(
3154 KeyDescriptor {
3155 domain: Domain::SELINUX,
3156 nspace: 1,
3157 alias: Some(TEST_ALIAS.to_string()),
3158 blob: None,
3159 },
3160 KeyType::Client,
3161 KeyEntryLoadBits::BOTH,
3162 1,
3163 |_k, _av| Ok(()),
3164 )
3165 .unwrap();
Qi Wub9433b52020-12-01 14:52:46 +08003166 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003167
3168 db.unbind_key(
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003169 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003170 domain: Domain::SELINUX,
3171 nspace: 1,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003172 alias: Some(TEST_ALIAS.to_string()),
3173 blob: None,
3174 },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003175 KeyType::Client,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003176 1,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003177 |_, _| Ok(()),
3178 )
3179 .unwrap();
3180
3181 assert_eq!(
3182 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
3183 db.load_key_entry(
3184 KeyDescriptor {
3185 domain: Domain::SELINUX,
3186 nspace: 1,
3187 alias: Some(TEST_ALIAS.to_string()),
3188 blob: None,
3189 },
3190 KeyType::Client,
3191 KeyEntryLoadBits::NONE,
3192 1,
3193 |_k, _av| Ok(()),
3194 )
3195 .unwrap_err()
3196 .root_cause()
3197 .downcast_ref::<KsError>()
3198 );
3199
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003200 Ok(())
3201 }
3202
3203 #[test]
3204 fn test_insert_and_load_full_keyentry_domain_key_id() -> Result<()> {
3205 let mut db = new_test_db()?;
Qi Wub9433b52020-12-01 14:52:46 +08003206 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08003207 .context("test_insert_and_load_full_keyentry_domain_key_id")?
3208 .0;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003209 let (_, key_entry) = db
3210 .load_key_entry(
3211 KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
3212 KeyType::Client,
3213 KeyEntryLoadBits::BOTH,
3214 1,
3215 |_k, _av| Ok(()),
3216 )
3217 .unwrap();
3218
Qi Wub9433b52020-12-01 14:52:46 +08003219 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003220
3221 db.unbind_key(
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003222 KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003223 KeyType::Client,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003224 1,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003225 |_, _| Ok(()),
3226 )
3227 .unwrap();
3228
3229 assert_eq!(
3230 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
3231 db.load_key_entry(
3232 KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
3233 KeyType::Client,
3234 KeyEntryLoadBits::NONE,
3235 1,
3236 |_k, _av| Ok(()),
3237 )
3238 .unwrap_err()
3239 .root_cause()
3240 .downcast_ref::<KsError>()
3241 );
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003242
3243 Ok(())
3244 }
3245
3246 #[test]
Qi Wub9433b52020-12-01 14:52:46 +08003247 fn test_check_and_update_key_usage_count_with_limited_use_key() -> Result<()> {
3248 let mut db = new_test_db()?;
3249 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, Some(123))
3250 .context("test_check_and_update_key_usage_count_with_limited_use_key")?
3251 .0;
3252 // Update the usage count of the limited use key.
3253 db.check_and_update_key_usage_count(key_id)?;
3254
3255 let (_key_guard, key_entry) = db.load_key_entry(
3256 KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
3257 KeyType::Client,
3258 KeyEntryLoadBits::BOTH,
3259 1,
3260 |_k, _av| Ok(()),
3261 )?;
3262
3263 // The usage count is decremented now.
3264 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, Some(122)));
3265
3266 Ok(())
3267 }
3268
3269 #[test]
3270 fn test_check_and_update_key_usage_count_with_exhausted_limited_use_key() -> Result<()> {
3271 let mut db = new_test_db()?;
3272 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, Some(1))
3273 .context("test_check_and_update_key_usage_count_with_exhausted_limited_use_key")?
3274 .0;
3275 // Update the usage count of the limited use key.
3276 db.check_and_update_key_usage_count(key_id).expect(concat!(
3277 "In test_check_and_update_key_usage_count_with_exhausted_limited_use_key: ",
3278 "This should succeed."
3279 ));
3280
3281 // Try to update the exhausted limited use key.
3282 let e = db.check_and_update_key_usage_count(key_id).expect_err(concat!(
3283 "In test_check_and_update_key_usage_count_with_exhausted_limited_use_key: ",
3284 "This should fail."
3285 ));
3286 assert_eq!(
3287 &KsError::Km(ErrorCode::INVALID_KEY_BLOB),
3288 e.root_cause().downcast_ref::<KsError>().unwrap()
3289 );
3290
3291 Ok(())
3292 }
3293
3294 #[test]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003295 fn test_insert_and_load_full_keyentry_from_grant() -> Result<()> {
3296 let mut db = new_test_db()?;
Qi Wub9433b52020-12-01 14:52:46 +08003297 let key_id = make_test_key_entry(&mut db, Domain::APP, 1, TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08003298 .context("test_insert_and_load_full_keyentry_from_grant")?
3299 .0;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003300
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003301 let granted_key = db
3302 .grant(
3303 KeyDescriptor {
3304 domain: Domain::APP,
3305 nspace: 0,
3306 alias: Some(TEST_ALIAS.to_string()),
3307 blob: None,
3308 },
3309 1,
3310 2,
3311 key_perm_set![KeyPerm::use_()],
3312 |_k, _av| Ok(()),
3313 )
3314 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003315
3316 debug_dump_grant_table(&mut db)?;
3317
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003318 let (_key_guard, key_entry) = db
3319 .load_key_entry(
3320 granted_key.clone(),
3321 KeyType::Client,
3322 KeyEntryLoadBits::BOTH,
3323 2,
3324 |k, av| {
3325 assert_eq!(Domain::GRANT, k.domain);
3326 assert!(av.unwrap().includes(KeyPerm::use_()));
3327 Ok(())
3328 },
3329 )
3330 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003331
Qi Wub9433b52020-12-01 14:52:46 +08003332 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003333
3334 db.unbind_key(granted_key.clone(), KeyType::Client, 2, |_, _| Ok(())).unwrap();
3335
3336 assert_eq!(
3337 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
3338 db.load_key_entry(
3339 granted_key,
3340 KeyType::Client,
3341 KeyEntryLoadBits::NONE,
3342 2,
3343 |_k, _av| Ok(()),
3344 )
3345 .unwrap_err()
3346 .root_cause()
3347 .downcast_ref::<KsError>()
3348 );
3349
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003350 Ok(())
3351 }
3352
Janis Danisevskis45760022021-01-19 16:34:10 -08003353 // This test attempts to load a key by key id while the caller is not the owner
3354 // but a grant exists for the given key and the caller.
3355 #[test]
3356 fn test_insert_and_load_full_keyentry_from_grant_by_key_id() -> Result<()> {
3357 let mut db = new_test_db()?;
3358 const OWNER_UID: u32 = 1u32;
3359 const GRANTEE_UID: u32 = 2u32;
3360 const SOMEONE_ELSE_UID: u32 = 3u32;
3361 let key_id = make_test_key_entry(&mut db, Domain::APP, OWNER_UID as i64, TEST_ALIAS, None)
3362 .context("test_insert_and_load_full_keyentry_from_grant_by_key_id")?
3363 .0;
3364
3365 db.grant(
3366 KeyDescriptor {
3367 domain: Domain::APP,
3368 nspace: 0,
3369 alias: Some(TEST_ALIAS.to_string()),
3370 blob: None,
3371 },
3372 OWNER_UID,
3373 GRANTEE_UID,
3374 key_perm_set![KeyPerm::use_()],
3375 |_k, _av| Ok(()),
3376 )
3377 .unwrap();
3378
3379 debug_dump_grant_table(&mut db)?;
3380
3381 let id_descriptor =
3382 KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, ..Default::default() };
3383
3384 let (_, key_entry) = db
3385 .load_key_entry(
3386 id_descriptor.clone(),
3387 KeyType::Client,
3388 KeyEntryLoadBits::BOTH,
3389 GRANTEE_UID,
3390 |k, av| {
3391 assert_eq!(Domain::APP, k.domain);
3392 assert_eq!(OWNER_UID as i64, k.nspace);
3393 assert!(av.unwrap().includes(KeyPerm::use_()));
3394 Ok(())
3395 },
3396 )
3397 .unwrap();
3398
3399 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
3400
3401 let (_, key_entry) = db
3402 .load_key_entry(
3403 id_descriptor.clone(),
3404 KeyType::Client,
3405 KeyEntryLoadBits::BOTH,
3406 SOMEONE_ELSE_UID,
3407 |k, av| {
3408 assert_eq!(Domain::APP, k.domain);
3409 assert_eq!(OWNER_UID as i64, k.nspace);
3410 assert!(av.is_none());
3411 Ok(())
3412 },
3413 )
3414 .unwrap();
3415
3416 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
3417
3418 db.unbind_key(id_descriptor.clone(), KeyType::Client, OWNER_UID, |_, _| Ok(())).unwrap();
3419
3420 assert_eq!(
3421 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
3422 db.load_key_entry(
3423 id_descriptor,
3424 KeyType::Client,
3425 KeyEntryLoadBits::NONE,
3426 GRANTEE_UID,
3427 |_k, _av| Ok(()),
3428 )
3429 .unwrap_err()
3430 .root_cause()
3431 .downcast_ref::<KsError>()
3432 );
3433
3434 Ok(())
3435 }
3436
Janis Danisevskisaec14592020-11-12 09:41:49 -08003437 static KEY_LOCK_TEST_ALIAS: &str = "my super duper locked key";
3438
Janis Danisevskisaec14592020-11-12 09:41:49 -08003439 #[test]
3440 fn test_insert_and_load_full_keyentry_domain_app_concurrently() -> Result<()> {
3441 let handle = {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08003442 let temp_dir = Arc::new(TempDir::new("id_lock_test")?);
3443 let temp_dir_clone = temp_dir.clone();
3444 let mut db = KeystoreDB::new(temp_dir.path())?;
Qi Wub9433b52020-12-01 14:52:46 +08003445 let key_id = make_test_key_entry(&mut db, Domain::APP, 33, KEY_LOCK_TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08003446 .context("test_insert_and_load_full_keyentry_domain_app")?
3447 .0;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003448 let (_key_guard, key_entry) = db
3449 .load_key_entry(
3450 KeyDescriptor {
3451 domain: Domain::APP,
3452 nspace: 0,
3453 alias: Some(KEY_LOCK_TEST_ALIAS.to_string()),
3454 blob: None,
3455 },
3456 KeyType::Client,
3457 KeyEntryLoadBits::BOTH,
3458 33,
3459 |_k, _av| Ok(()),
3460 )
3461 .unwrap();
Qi Wub9433b52020-12-01 14:52:46 +08003462 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskisaec14592020-11-12 09:41:49 -08003463 let state = Arc::new(AtomicU8::new(1));
3464 let state2 = state.clone();
3465
3466 // Spawning a second thread that attempts to acquire the key id lock
3467 // for the same key as the primary thread. The primary thread then
3468 // waits, thereby forcing the secondary thread into the second stage
3469 // of acquiring the lock (see KEY ID LOCK 2/2 above).
3470 // The test succeeds if the secondary thread observes the transition
3471 // of `state` from 1 to 2, despite having a whole second to overtake
3472 // the primary thread.
3473 let handle = thread::spawn(move || {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08003474 let temp_dir = temp_dir_clone;
3475 let mut db = KeystoreDB::new(temp_dir.path()).unwrap();
Janis Danisevskisaec14592020-11-12 09:41:49 -08003476 assert!(db
3477 .load_key_entry(
3478 KeyDescriptor {
3479 domain: Domain::APP,
3480 nspace: 0,
3481 alias: Some(KEY_LOCK_TEST_ALIAS.to_string()),
3482 blob: None,
3483 },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003484 KeyType::Client,
Janis Danisevskisaec14592020-11-12 09:41:49 -08003485 KeyEntryLoadBits::BOTH,
3486 33,
3487 |_k, _av| Ok(()),
3488 )
3489 .is_ok());
3490 // We should only see a 2 here because we can only return
3491 // from load_key_entry when the `_key_guard` expires,
3492 // which happens at the end of the scope.
3493 assert_eq!(2, state2.load(Ordering::Relaxed));
3494 });
3495
3496 thread::sleep(std::time::Duration::from_millis(1000));
3497
3498 assert_eq!(Ok(1), state.compare_exchange(1, 2, Ordering::Relaxed, Ordering::Relaxed));
3499
3500 // Return the handle from this scope so we can join with the
3501 // secondary thread after the key id lock has expired.
3502 handle
3503 // This is where the `_key_guard` goes out of scope,
3504 // which is the reason for concurrent load_key_entry on the same key
3505 // to unblock.
3506 };
3507 // Join with the secondary thread and unwrap, to propagate failing asserts to the
3508 // main test thread. We will not see failing asserts in secondary threads otherwise.
3509 handle.join().unwrap();
3510 Ok(())
3511 }
3512
Janis Danisevskise92a5e62020-12-02 12:57:41 -08003513 #[test]
3514 fn list() -> Result<()> {
3515 let temp_dir = TempDir::new("list_test")?;
3516 let mut db = KeystoreDB::new(temp_dir.path())?;
3517 static LIST_O_ENTRIES: &[(Domain, i64, &str)] = &[
3518 (Domain::APP, 1, "test1"),
3519 (Domain::APP, 1, "test2"),
3520 (Domain::APP, 1, "test3"),
3521 (Domain::APP, 1, "test4"),
3522 (Domain::APP, 1, "test5"),
3523 (Domain::APP, 1, "test6"),
3524 (Domain::APP, 1, "test7"),
3525 (Domain::APP, 2, "test1"),
3526 (Domain::APP, 2, "test2"),
3527 (Domain::APP, 2, "test3"),
3528 (Domain::APP, 2, "test4"),
3529 (Domain::APP, 2, "test5"),
3530 (Domain::APP, 2, "test6"),
3531 (Domain::APP, 2, "test8"),
3532 (Domain::SELINUX, 100, "test1"),
3533 (Domain::SELINUX, 100, "test2"),
3534 (Domain::SELINUX, 100, "test3"),
3535 (Domain::SELINUX, 100, "test4"),
3536 (Domain::SELINUX, 100, "test5"),
3537 (Domain::SELINUX, 100, "test6"),
3538 (Domain::SELINUX, 100, "test9"),
3539 ];
3540
3541 let list_o_keys: Vec<(i64, i64)> = LIST_O_ENTRIES
3542 .iter()
3543 .map(|(domain, ns, alias)| {
Qi Wub9433b52020-12-01 14:52:46 +08003544 let entry = make_test_key_entry(&mut db, *domain, *ns, *alias, None)
3545 .unwrap_or_else(|e| {
Janis Danisevskise92a5e62020-12-02 12:57:41 -08003546 panic!("Failed to insert {:?} {} {}. Error {:?}", domain, ns, alias, e)
3547 });
3548 (entry.id(), *ns)
3549 })
3550 .collect();
3551
3552 for (domain, namespace) in
3553 &[(Domain::APP, 1i64), (Domain::APP, 2i64), (Domain::SELINUX, 100i64)]
3554 {
3555 let mut list_o_descriptors: Vec<KeyDescriptor> = LIST_O_ENTRIES
3556 .iter()
3557 .filter_map(|(domain, ns, alias)| match ns {
3558 ns if *ns == *namespace => Some(KeyDescriptor {
3559 domain: *domain,
3560 nspace: *ns,
3561 alias: Some(alias.to_string()),
3562 blob: None,
3563 }),
3564 _ => None,
3565 })
3566 .collect();
3567 list_o_descriptors.sort();
3568 let mut list_result = db.list(*domain, *namespace)?;
3569 list_result.sort();
3570 assert_eq!(list_o_descriptors, list_result);
3571
3572 let mut list_o_ids: Vec<i64> = list_o_descriptors
3573 .into_iter()
3574 .map(|d| {
3575 let (_, entry) = db
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003576 .load_key_entry(
3577 d,
3578 KeyType::Client,
3579 KeyEntryLoadBits::NONE,
3580 *namespace as u32,
3581 |_, _| Ok(()),
3582 )
Janis Danisevskise92a5e62020-12-02 12:57:41 -08003583 .unwrap();
3584 entry.id()
3585 })
3586 .collect();
3587 list_o_ids.sort_unstable();
3588 let mut loaded_entries: Vec<i64> = list_o_keys
3589 .iter()
3590 .filter_map(|(id, ns)| match ns {
3591 ns if *ns == *namespace => Some(*id),
3592 _ => None,
3593 })
3594 .collect();
3595 loaded_entries.sort_unstable();
3596 assert_eq!(list_o_ids, loaded_entries);
3597 }
3598 assert_eq!(Vec::<KeyDescriptor>::new(), db.list(Domain::SELINUX, 101)?);
3599
3600 Ok(())
3601 }
3602
Joel Galenson0891bc12020-07-20 10:37:03 -07003603 // Helpers
3604
3605 // Checks that the given result is an error containing the given string.
3606 fn check_result_is_error_containing_string<T>(result: Result<T>, target: &str) {
3607 let error_str = format!(
3608 "{:#?}",
3609 result.err().unwrap_or_else(|| panic!("Expected the error: {}", target))
3610 );
3611 assert!(
3612 error_str.contains(target),
3613 "The string \"{}\" should contain \"{}\"",
3614 error_str,
3615 target
3616 );
3617 }
3618
Joel Galenson2aab4432020-07-22 15:27:57 -07003619 #[derive(Debug, PartialEq)]
Joel Galenson0891bc12020-07-20 10:37:03 -07003620 #[allow(dead_code)]
3621 struct KeyEntryRow {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003622 id: i64,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003623 key_type: KeyType,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003624 domain: Option<Domain>,
Joel Galenson0891bc12020-07-20 10:37:03 -07003625 namespace: Option<i64>,
3626 alias: Option<String>,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003627 state: KeyLifeCycle,
Max Bires8e93d2b2021-01-14 13:17:59 -08003628 km_uuid: Option<Uuid>,
Joel Galenson0891bc12020-07-20 10:37:03 -07003629 }
3630
3631 fn get_keyentry(db: &KeystoreDB) -> Result<Vec<KeyEntryRow>> {
3632 db.conn
Joel Galenson2aab4432020-07-22 15:27:57 -07003633 .prepare("SELECT * FROM persistent.keyentry;")?
Joel Galenson0891bc12020-07-20 10:37:03 -07003634 .query_map(NO_PARAMS, |row| {
Joel Galenson0891bc12020-07-20 10:37:03 -07003635 Ok(KeyEntryRow {
3636 id: row.get(0)?,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003637 key_type: row.get(1)?,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003638 domain: match row.get(2)? {
3639 Some(i) => Some(Domain(i)),
3640 None => None,
3641 },
Joel Galenson0891bc12020-07-20 10:37:03 -07003642 namespace: row.get(3)?,
3643 alias: row.get(4)?,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003644 state: row.get(5)?,
Max Bires8e93d2b2021-01-14 13:17:59 -08003645 km_uuid: row.get(6)?,
Joel Galenson0891bc12020-07-20 10:37:03 -07003646 })
3647 })?
3648 .map(|r| r.context("Could not read keyentry row."))
3649 .collect::<Result<Vec<_>>>()
3650 }
3651
Max Bires2b2e6562020-09-22 11:22:36 -07003652 fn load_attestation_key_pool(
3653 db: &mut KeystoreDB,
3654 expiration_date: i64,
3655 namespace: i64,
3656 base_byte: u8,
3657 ) -> Result<Vec<Vec<u8>>> {
3658 let mut chain: Vec<Vec<u8>> = Vec::new();
3659 let public_key: Vec<u8> = vec![base_byte, 0x02 * base_byte];
3660 let cert_chain: Vec<u8> = vec![0x03 * base_byte, 0x04 * base_byte];
3661 let priv_key: Vec<u8> = vec![0x05 * base_byte, 0x06 * base_byte];
3662 let raw_public_key: Vec<u8> = vec![0x0b * base_byte, 0x0c * base_byte];
3663 db.create_attestation_key_entry(&public_key, &raw_public_key, &priv_key, &KEYSTORE_UUID)?;
3664 db.store_signed_attestation_certificate_chain(
3665 &raw_public_key,
3666 &cert_chain,
3667 expiration_date,
3668 &KEYSTORE_UUID,
3669 )?;
3670 db.assign_attestation_key(Domain::APP, namespace, &KEYSTORE_UUID)?;
3671 chain.push(public_key);
3672 chain.push(cert_chain);
3673 chain.push(priv_key);
3674 chain.push(raw_public_key);
3675 Ok(chain)
3676 }
3677
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07003678 // Note: The parameters and SecurityLevel associations are nonsensical. This
3679 // collection is only used to check if the parameters are preserved as expected by the
3680 // database.
Qi Wub9433b52020-12-01 14:52:46 +08003681 fn make_test_params(max_usage_count: Option<i32>) -> Vec<KeyParameter> {
3682 let mut params = vec![
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07003683 KeyParameter::new(KeyParameterValue::Invalid, SecurityLevel::TRUSTED_ENVIRONMENT),
3684 KeyParameter::new(
3685 KeyParameterValue::KeyPurpose(KeyPurpose::SIGN),
3686 SecurityLevel::TRUSTED_ENVIRONMENT,
3687 ),
3688 KeyParameter::new(
3689 KeyParameterValue::KeyPurpose(KeyPurpose::DECRYPT),
3690 SecurityLevel::TRUSTED_ENVIRONMENT,
3691 ),
3692 KeyParameter::new(
3693 KeyParameterValue::Algorithm(Algorithm::RSA),
3694 SecurityLevel::TRUSTED_ENVIRONMENT,
3695 ),
3696 KeyParameter::new(KeyParameterValue::KeySize(1024), SecurityLevel::TRUSTED_ENVIRONMENT),
3697 KeyParameter::new(
3698 KeyParameterValue::BlockMode(BlockMode::ECB),
3699 SecurityLevel::TRUSTED_ENVIRONMENT,
3700 ),
3701 KeyParameter::new(
3702 KeyParameterValue::BlockMode(BlockMode::GCM),
3703 SecurityLevel::TRUSTED_ENVIRONMENT,
3704 ),
3705 KeyParameter::new(KeyParameterValue::Digest(Digest::NONE), SecurityLevel::STRONGBOX),
3706 KeyParameter::new(
3707 KeyParameterValue::Digest(Digest::MD5),
3708 SecurityLevel::TRUSTED_ENVIRONMENT,
3709 ),
3710 KeyParameter::new(
3711 KeyParameterValue::Digest(Digest::SHA_2_224),
3712 SecurityLevel::TRUSTED_ENVIRONMENT,
3713 ),
3714 KeyParameter::new(
3715 KeyParameterValue::Digest(Digest::SHA_2_256),
3716 SecurityLevel::STRONGBOX,
3717 ),
3718 KeyParameter::new(
3719 KeyParameterValue::PaddingMode(PaddingMode::NONE),
3720 SecurityLevel::TRUSTED_ENVIRONMENT,
3721 ),
3722 KeyParameter::new(
3723 KeyParameterValue::PaddingMode(PaddingMode::RSA_OAEP),
3724 SecurityLevel::TRUSTED_ENVIRONMENT,
3725 ),
3726 KeyParameter::new(
3727 KeyParameterValue::PaddingMode(PaddingMode::RSA_PSS),
3728 SecurityLevel::STRONGBOX,
3729 ),
3730 KeyParameter::new(
3731 KeyParameterValue::PaddingMode(PaddingMode::RSA_PKCS1_1_5_SIGN),
3732 SecurityLevel::TRUSTED_ENVIRONMENT,
3733 ),
3734 KeyParameter::new(KeyParameterValue::CallerNonce, SecurityLevel::TRUSTED_ENVIRONMENT),
3735 KeyParameter::new(KeyParameterValue::MinMacLength(256), SecurityLevel::STRONGBOX),
3736 KeyParameter::new(
3737 KeyParameterValue::EcCurve(EcCurve::P_224),
3738 SecurityLevel::TRUSTED_ENVIRONMENT,
3739 ),
3740 KeyParameter::new(KeyParameterValue::EcCurve(EcCurve::P_256), SecurityLevel::STRONGBOX),
3741 KeyParameter::new(
3742 KeyParameterValue::EcCurve(EcCurve::P_384),
3743 SecurityLevel::TRUSTED_ENVIRONMENT,
3744 ),
3745 KeyParameter::new(
3746 KeyParameterValue::EcCurve(EcCurve::P_521),
3747 SecurityLevel::TRUSTED_ENVIRONMENT,
3748 ),
3749 KeyParameter::new(
3750 KeyParameterValue::RSAPublicExponent(3),
3751 SecurityLevel::TRUSTED_ENVIRONMENT,
3752 ),
3753 KeyParameter::new(
3754 KeyParameterValue::IncludeUniqueID,
3755 SecurityLevel::TRUSTED_ENVIRONMENT,
3756 ),
3757 KeyParameter::new(KeyParameterValue::BootLoaderOnly, SecurityLevel::STRONGBOX),
3758 KeyParameter::new(KeyParameterValue::RollbackResistance, SecurityLevel::STRONGBOX),
3759 KeyParameter::new(
3760 KeyParameterValue::ActiveDateTime(1234567890),
3761 SecurityLevel::STRONGBOX,
3762 ),
3763 KeyParameter::new(
3764 KeyParameterValue::OriginationExpireDateTime(1234567890),
3765 SecurityLevel::TRUSTED_ENVIRONMENT,
3766 ),
3767 KeyParameter::new(
3768 KeyParameterValue::UsageExpireDateTime(1234567890),
3769 SecurityLevel::TRUSTED_ENVIRONMENT,
3770 ),
3771 KeyParameter::new(
3772 KeyParameterValue::MinSecondsBetweenOps(1234567890),
3773 SecurityLevel::TRUSTED_ENVIRONMENT,
3774 ),
3775 KeyParameter::new(
3776 KeyParameterValue::MaxUsesPerBoot(1234567890),
3777 SecurityLevel::TRUSTED_ENVIRONMENT,
3778 ),
3779 KeyParameter::new(KeyParameterValue::UserID(1), SecurityLevel::STRONGBOX),
3780 KeyParameter::new(KeyParameterValue::UserSecureID(42), SecurityLevel::STRONGBOX),
3781 KeyParameter::new(
3782 KeyParameterValue::NoAuthRequired,
3783 SecurityLevel::TRUSTED_ENVIRONMENT,
3784 ),
3785 KeyParameter::new(
3786 KeyParameterValue::HardwareAuthenticatorType(HardwareAuthenticatorType::PASSWORD),
3787 SecurityLevel::TRUSTED_ENVIRONMENT,
3788 ),
3789 KeyParameter::new(KeyParameterValue::AuthTimeout(1234567890), SecurityLevel::SOFTWARE),
3790 KeyParameter::new(KeyParameterValue::AllowWhileOnBody, SecurityLevel::SOFTWARE),
3791 KeyParameter::new(
3792 KeyParameterValue::TrustedUserPresenceRequired,
3793 SecurityLevel::TRUSTED_ENVIRONMENT,
3794 ),
3795 KeyParameter::new(
3796 KeyParameterValue::TrustedConfirmationRequired,
3797 SecurityLevel::TRUSTED_ENVIRONMENT,
3798 ),
3799 KeyParameter::new(
3800 KeyParameterValue::UnlockedDeviceRequired,
3801 SecurityLevel::TRUSTED_ENVIRONMENT,
3802 ),
3803 KeyParameter::new(
3804 KeyParameterValue::ApplicationID(vec![1u8, 2u8, 3u8, 4u8]),
3805 SecurityLevel::SOFTWARE,
3806 ),
3807 KeyParameter::new(
3808 KeyParameterValue::ApplicationData(vec![4u8, 3u8, 2u8, 1u8]),
3809 SecurityLevel::SOFTWARE,
3810 ),
3811 KeyParameter::new(
3812 KeyParameterValue::CreationDateTime(12345677890),
3813 SecurityLevel::SOFTWARE,
3814 ),
3815 KeyParameter::new(
3816 KeyParameterValue::KeyOrigin(KeyOrigin::GENERATED),
3817 SecurityLevel::TRUSTED_ENVIRONMENT,
3818 ),
3819 KeyParameter::new(
3820 KeyParameterValue::RootOfTrust(vec![3u8, 2u8, 1u8, 4u8]),
3821 SecurityLevel::TRUSTED_ENVIRONMENT,
3822 ),
3823 KeyParameter::new(KeyParameterValue::OSVersion(1), SecurityLevel::TRUSTED_ENVIRONMENT),
3824 KeyParameter::new(KeyParameterValue::OSPatchLevel(2), SecurityLevel::SOFTWARE),
3825 KeyParameter::new(
3826 KeyParameterValue::UniqueID(vec![4u8, 3u8, 1u8, 2u8]),
3827 SecurityLevel::SOFTWARE,
3828 ),
3829 KeyParameter::new(
3830 KeyParameterValue::AttestationChallenge(vec![4u8, 3u8, 1u8, 2u8]),
3831 SecurityLevel::TRUSTED_ENVIRONMENT,
3832 ),
3833 KeyParameter::new(
3834 KeyParameterValue::AttestationApplicationID(vec![4u8, 3u8, 1u8, 2u8]),
3835 SecurityLevel::TRUSTED_ENVIRONMENT,
3836 ),
3837 KeyParameter::new(
3838 KeyParameterValue::AttestationIdBrand(vec![4u8, 3u8, 1u8, 2u8]),
3839 SecurityLevel::TRUSTED_ENVIRONMENT,
3840 ),
3841 KeyParameter::new(
3842 KeyParameterValue::AttestationIdDevice(vec![4u8, 3u8, 1u8, 2u8]),
3843 SecurityLevel::TRUSTED_ENVIRONMENT,
3844 ),
3845 KeyParameter::new(
3846 KeyParameterValue::AttestationIdProduct(vec![4u8, 3u8, 1u8, 2u8]),
3847 SecurityLevel::TRUSTED_ENVIRONMENT,
3848 ),
3849 KeyParameter::new(
3850 KeyParameterValue::AttestationIdSerial(vec![4u8, 3u8, 1u8, 2u8]),
3851 SecurityLevel::TRUSTED_ENVIRONMENT,
3852 ),
3853 KeyParameter::new(
3854 KeyParameterValue::AttestationIdIMEI(vec![4u8, 3u8, 1u8, 2u8]),
3855 SecurityLevel::TRUSTED_ENVIRONMENT,
3856 ),
3857 KeyParameter::new(
3858 KeyParameterValue::AttestationIdMEID(vec![4u8, 3u8, 1u8, 2u8]),
3859 SecurityLevel::TRUSTED_ENVIRONMENT,
3860 ),
3861 KeyParameter::new(
3862 KeyParameterValue::AttestationIdManufacturer(vec![4u8, 3u8, 1u8, 2u8]),
3863 SecurityLevel::TRUSTED_ENVIRONMENT,
3864 ),
3865 KeyParameter::new(
3866 KeyParameterValue::AttestationIdModel(vec![4u8, 3u8, 1u8, 2u8]),
3867 SecurityLevel::TRUSTED_ENVIRONMENT,
3868 ),
3869 KeyParameter::new(
3870 KeyParameterValue::VendorPatchLevel(3),
3871 SecurityLevel::TRUSTED_ENVIRONMENT,
3872 ),
3873 KeyParameter::new(
3874 KeyParameterValue::BootPatchLevel(4),
3875 SecurityLevel::TRUSTED_ENVIRONMENT,
3876 ),
3877 KeyParameter::new(
3878 KeyParameterValue::AssociatedData(vec![4u8, 3u8, 1u8, 2u8]),
3879 SecurityLevel::TRUSTED_ENVIRONMENT,
3880 ),
3881 KeyParameter::new(
3882 KeyParameterValue::Nonce(vec![4u8, 3u8, 1u8, 2u8]),
3883 SecurityLevel::TRUSTED_ENVIRONMENT,
3884 ),
3885 KeyParameter::new(
3886 KeyParameterValue::MacLength(256),
3887 SecurityLevel::TRUSTED_ENVIRONMENT,
3888 ),
3889 KeyParameter::new(
3890 KeyParameterValue::ResetSinceIdRotation,
3891 SecurityLevel::TRUSTED_ENVIRONMENT,
3892 ),
3893 KeyParameter::new(
3894 KeyParameterValue::ConfirmationToken(vec![5u8, 5u8, 5u8, 5u8]),
3895 SecurityLevel::TRUSTED_ENVIRONMENT,
3896 ),
Qi Wub9433b52020-12-01 14:52:46 +08003897 ];
3898 if let Some(value) = max_usage_count {
3899 params.push(KeyParameter::new(
3900 KeyParameterValue::UsageCountLimit(value),
3901 SecurityLevel::SOFTWARE,
3902 ));
3903 }
3904 params
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07003905 }
3906
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003907 fn make_test_key_entry(
3908 db: &mut KeystoreDB,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003909 domain: Domain,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003910 namespace: i64,
3911 alias: &str,
Qi Wub9433b52020-12-01 14:52:46 +08003912 max_usage_count: Option<i32>,
Janis Danisevskisaec14592020-11-12 09:41:49 -08003913 ) -> Result<KeyIdGuard> {
Max Bires8e93d2b2021-01-14 13:17:59 -08003914 let key_id = db.create_key_entry(domain, namespace, &KEYSTORE_UUID)?;
Janis Danisevskis377d1002021-01-27 19:07:48 -08003915 db.set_blob(&key_id, SubComponentType::KEY_BLOB, Some(TEST_KEY_BLOB))?;
3916 db.set_blob(&key_id, SubComponentType::CERT, Some(TEST_CERT_BLOB))?;
3917 db.set_blob(&key_id, SubComponentType::CERT_CHAIN, Some(TEST_CERT_CHAIN_BLOB))?;
Qi Wub9433b52020-12-01 14:52:46 +08003918
3919 let params = make_test_params(max_usage_count);
3920 db.insert_keyparameter(&key_id, &params)?;
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 db.insert_key_metadata(&key_id, &metadata)?;
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003928 rebind_alias(db, &key_id, alias, domain, namespace)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003929 Ok(key_id)
3930 }
3931
Qi Wub9433b52020-12-01 14:52:46 +08003932 fn make_test_key_entry_test_vector(key_id: i64, max_usage_count: Option<i32>) -> KeyEntry {
3933 let params = make_test_params(max_usage_count);
3934
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003935 let mut metadata = KeyMetaData::new();
3936 metadata.add(KeyMetaEntry::EncryptedBy(EncryptedBy::Password));
3937 metadata.add(KeyMetaEntry::Salt(vec![1, 2, 3]));
3938 metadata.add(KeyMetaEntry::Iv(vec![2, 3, 1]));
3939 metadata.add(KeyMetaEntry::AeadTag(vec![3, 1, 2]));
3940
3941 KeyEntry {
3942 id: key_id,
3943 km_blob: Some(TEST_KEY_BLOB.to_vec()),
3944 cert: Some(TEST_CERT_BLOB.to_vec()),
3945 cert_chain: Some(TEST_CERT_CHAIN_BLOB.to_vec()),
Max Bires8e93d2b2021-01-14 13:17:59 -08003946 km_uuid: KEYSTORE_UUID,
Qi Wub9433b52020-12-01 14:52:46 +08003947 parameters: params,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003948 metadata,
Janis Danisevskis377d1002021-01-27 19:07:48 -08003949 pure_cert: false,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003950 }
3951 }
3952
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003953 fn debug_dump_keyentry_table(db: &mut KeystoreDB) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003954 let mut stmt = db.conn.prepare(
Max Bires8e93d2b2021-01-14 13:17:59 -08003955 "SELECT id, key_type, domain, namespace, alias, state, km_uuid FROM persistent.keyentry;",
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003956 )?;
Max Bires8e93d2b2021-01-14 13:17:59 -08003957 let rows = stmt.query_map::<(i64, KeyType, i32, i64, String, KeyLifeCycle, Uuid), _, _>(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003958 NO_PARAMS,
3959 |row| {
Max Bires8e93d2b2021-01-14 13:17:59 -08003960 Ok((
3961 row.get(0)?,
3962 row.get(1)?,
3963 row.get(2)?,
3964 row.get(3)?,
3965 row.get(4)?,
3966 row.get(5)?,
3967 row.get(6)?,
3968 ))
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003969 },
3970 )?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003971
3972 println!("Key entry table rows:");
3973 for r in rows {
Max Bires8e93d2b2021-01-14 13:17:59 -08003974 let (id, key_type, domain, namespace, alias, state, km_uuid) = r.unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003975 println!(
Max Bires8e93d2b2021-01-14 13:17:59 -08003976 " id: {} KeyType: {:?} Domain: {} Namespace: {} Alias: {} State: {:?} KmUuid: {:?}",
3977 id, key_type, domain, namespace, alias, state, km_uuid
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003978 );
3979 }
3980 Ok(())
3981 }
3982
3983 fn debug_dump_grant_table(db: &mut KeystoreDB) -> Result<()> {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08003984 let mut stmt = db
3985 .conn
3986 .prepare("SELECT id, grantee, keyentryid, access_vector FROM persistent.grant;")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003987 let rows = stmt.query_map::<(i64, i64, i64, i64), _, _>(NO_PARAMS, |row| {
3988 Ok((row.get(0)?, row.get(1)?, row.get(2)?, row.get(3)?))
3989 })?;
3990
3991 println!("Grant table rows:");
3992 for r in rows {
3993 let (id, gt, ki, av) = r.unwrap();
3994 println!(" id: {} grantee: {} key_id: {} access_vector: {}", id, gt, ki, av);
3995 }
3996 Ok(())
3997 }
3998
Joel Galenson0891bc12020-07-20 10:37:03 -07003999 // Use a custom random number generator that repeats each number once.
4000 // This allows us to test repeated elements.
4001
4002 thread_local! {
4003 static RANDOM_COUNTER: RefCell<i64> = RefCell::new(0);
4004 }
4005
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004006 fn reset_random() {
4007 RANDOM_COUNTER.with(|counter| {
4008 *counter.borrow_mut() = 0;
4009 })
4010 }
4011
Joel Galenson0891bc12020-07-20 10:37:03 -07004012 pub fn random() -> i64 {
4013 RANDOM_COUNTER.with(|counter| {
4014 let result = *counter.borrow() / 2;
4015 *counter.borrow_mut() += 1;
4016 result
4017 })
4018 }
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00004019
4020 #[test]
4021 fn test_last_off_body() -> Result<()> {
4022 let mut db = new_test_db()?;
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08004023 db.insert_last_off_body(MonotonicRawTime::now())?;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00004024 let tx = db.conn.transaction_with_behavior(TransactionBehavior::Immediate)?;
4025 let last_off_body_1 = KeystoreDB::get_last_off_body(&tx)?;
4026 tx.commit()?;
4027 let one_second = Duration::from_secs(1);
4028 thread::sleep(one_second);
4029 db.update_last_off_body(MonotonicRawTime::now())?;
4030 let tx2 = db.conn.transaction_with_behavior(TransactionBehavior::Immediate)?;
4031 let last_off_body_2 = KeystoreDB::get_last_off_body(&tx2)?;
4032 tx2.commit()?;
4033 assert!(last_off_body_1.seconds() < last_off_body_2.seconds());
4034 Ok(())
4035 }
Joel Galenson26f4d012020-07-17 14:57:21 -07004036}