blob: 8e5507edbc8f31ae42aaad5ab37f09d7102129b1 [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};
Janis Danisevskisaec14592020-11-12 09:41:49 -080063use lazy_static::lazy_static;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +000064use log::error;
Joel Galenson0891bc12020-07-20 10:37:03 -070065#[cfg(not(test))]
66use rand::prelude::random;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -070067use rusqlite::{
Janis Danisevskisb42fc182020-12-15 08:41:27 -080068 params,
69 types::FromSql,
70 types::FromSqlResult,
71 types::ToSqlOutput,
72 types::{FromSqlError, Value, ValueRef},
Janis Danisevskis5ed8c532021-01-11 14:19:42 -080073 Connection, OptionalExtension, ToSql, Transaction, TransactionBehavior, NO_PARAMS,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -070074};
Janis Danisevskisaec14592020-11-12 09:41:49 -080075use std::{
Janis Danisevskisb42fc182020-12-15 08:41:27 -080076 collections::{HashMap, HashSet},
Janis Danisevskisbf15d732020-12-08 10:35:26 -080077 path::Path,
78 sync::{Condvar, Mutex},
Janis Danisevskisb42fc182020-12-15 08:41:27 -080079 time::{Duration, SystemTime},
Janis Danisevskisaec14592020-11-12 09:41:49 -080080};
Joel Galenson0891bc12020-07-20 10:37:03 -070081#[cfg(test)]
82use tests::random;
Joel Galenson26f4d012020-07-17 14:57:21 -070083
Janis Danisevskisb42fc182020-12-15 08:41:27 -080084impl_metadata!(
85 /// A set of metadata for key entries.
86 #[derive(Debug, Default, Eq, PartialEq)]
87 pub struct KeyMetaData;
88 /// A metadata entry for key entries.
89 #[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
90 pub enum KeyMetaEntry {
91 /// If present, indicates that the sensitive part of key
92 /// is encrypted with another key or a key derived from a password.
93 EncryptedBy(EncryptedBy) with accessor encrypted_by,
94 /// If the blob is password encrypted this field is set to the
95 /// salt used for the key derivation.
96 Salt(Vec<u8>) with accessor salt,
97 /// If the blob is encrypted, this field is set to the initialization vector.
98 Iv(Vec<u8>) with accessor iv,
99 /// If the blob is encrypted, this field holds the AEAD TAG.
100 AeadTag(Vec<u8>) with accessor aead_tag,
101 /// Creation date of a the key entry.
102 CreationDate(DateTime) with accessor creation_date,
103 /// Expiration date for attestation keys.
104 AttestationExpirationDate(DateTime) with accessor attestation_expiration_date,
105 // --- ADD NEW META DATA FIELDS HERE ---
106 // For backwards compatibility add new entries only to
107 // end of this list and above this comment.
108 };
109);
110
111impl KeyMetaData {
112 fn load_from_db(key_id: i64, tx: &Transaction) -> Result<Self> {
113 let mut stmt = tx
114 .prepare(
115 "SELECT tag, data from persistent.keymetadata
116 WHERE keyentryid = ?;",
117 )
118 .context("In KeyMetaData::load_from_db: prepare statement failed.")?;
119
120 let mut metadata: HashMap<i64, KeyMetaEntry> = Default::default();
121
122 let mut rows =
123 stmt.query(params![key_id]).context("In KeyMetaData::load_from_db: query failed.")?;
124 db_utils::with_rows_extract_all(&mut rows, |row| {
125 let db_tag: i64 = row.get(0).context("Failed to read tag.")?;
126 metadata.insert(
127 db_tag,
128 KeyMetaEntry::new_from_sql(db_tag, &SqlField::new(1, &row))
129 .context("Failed to read KeyMetaEntry.")?,
130 );
131 Ok(())
132 })
133 .context("In KeyMetaData::load_from_db.")?;
134
135 Ok(Self { data: metadata })
136 }
137
138 fn store_in_db(&self, key_id: i64, tx: &Transaction) -> Result<()> {
139 let mut stmt = tx
140 .prepare(
141 "INSERT into persistent.keymetadata (keyentryid, tag, data)
142 VALUES (?, ?, ?);",
143 )
144 .context("In KeyMetaData::store_in_db: Failed to prepare statement.")?;
145
146 let iter = self.data.iter();
147 for (tag, entry) in iter {
148 stmt.insert(params![key_id, tag, entry,]).with_context(|| {
149 format!("In KeyMetaData::store_in_db: Failed to insert {:?}", entry)
150 })?;
151 }
152 Ok(())
153 }
154}
155
156/// Indicates the type of the keyentry.
157#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
158pub enum KeyType {
159 /// This is a client key type. These keys are created or imported through the Keystore 2.0
160 /// AIDL interface android.system.keystore2.
161 Client,
162 /// This is a super key type. These keys are created by keystore itself and used to encrypt
163 /// other key blobs to provide LSKF binding.
164 Super,
165 /// This is an attestation key. These keys are created by the remote provisioning mechanism.
166 Attestation,
167}
168
169impl ToSql for KeyType {
170 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
171 Ok(ToSqlOutput::Owned(Value::Integer(match self {
172 KeyType::Client => 0,
173 KeyType::Super => 1,
174 KeyType::Attestation => 2,
175 })))
176 }
177}
178
179impl FromSql for KeyType {
180 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
181 match i64::column_result(value)? {
182 0 => Ok(KeyType::Client),
183 1 => Ok(KeyType::Super),
184 2 => Ok(KeyType::Attestation),
185 v => Err(FromSqlError::OutOfRange(v)),
186 }
187 }
188}
189
Max Bires8e93d2b2021-01-14 13:17:59 -0800190/// Uuid representation that can be stored in the database.
191/// Right now it can only be initialized from SecurityLevel.
192/// Once KeyMint provides a UUID type a corresponding From impl shall be added.
193#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
194pub struct Uuid([u8; 16]);
195
196impl Deref for Uuid {
197 type Target = [u8; 16];
198
199 fn deref(&self) -> &Self::Target {
200 &self.0
201 }
202}
203
204impl From<SecurityLevel> for Uuid {
205 fn from(sec_level: SecurityLevel) -> Self {
206 Self((sec_level.0 as u128).to_be_bytes())
207 }
208}
209
210impl ToSql for Uuid {
211 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
212 self.0.to_sql()
213 }
214}
215
216impl FromSql for Uuid {
217 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
218 let blob = Vec::<u8>::column_result(value)?;
219 if blob.len() != 16 {
220 return Err(FromSqlError::OutOfRange(blob.len() as i64));
221 }
222 let mut arr = [0u8; 16];
223 arr.copy_from_slice(&blob);
224 Ok(Self(arr))
225 }
226}
227
228/// Key entries that are not associated with any KeyMint instance, such as pure certificate
229/// entries are associated with this UUID.
230pub static KEYSTORE_UUID: Uuid = Uuid([
231 0x41, 0xe3, 0xb9, 0xce, 0x27, 0x58, 0x4e, 0x91, 0xbc, 0xfd, 0xa5, 0x5d, 0x91, 0x85, 0xab, 0x11,
232]);
233
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800234/// Indicates how the sensitive part of this key blob is encrypted.
235#[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
236pub enum EncryptedBy {
237 /// The keyblob is encrypted by a user password.
238 /// In the database this variant is represented as NULL.
239 Password,
240 /// The keyblob is encrypted by another key with wrapped key id.
241 /// In the database this variant is represented as non NULL value
242 /// that is convertible to i64, typically NUMERIC.
243 KeyId(i64),
244}
245
246impl ToSql for EncryptedBy {
247 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
248 match self {
249 Self::Password => Ok(ToSqlOutput::Owned(Value::Null)),
250 Self::KeyId(id) => id.to_sql(),
251 }
252 }
253}
254
255impl FromSql for EncryptedBy {
256 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
257 match value {
258 ValueRef::Null => Ok(Self::Password),
259 _ => Ok(Self::KeyId(i64::column_result(value)?)),
260 }
261 }
262}
263
264/// A database representation of wall clock time. DateTime stores unix epoch time as
265/// i64 in milliseconds.
266#[derive(Debug, Copy, Clone, Default, Eq, PartialEq, Ord, PartialOrd)]
267pub struct DateTime(i64);
268
269/// Error type returned when creating DateTime or converting it from and to
270/// SystemTime.
271#[derive(thiserror::Error, Debug)]
272pub enum DateTimeError {
273 /// This is returned when SystemTime and Duration computations fail.
274 #[error(transparent)]
275 SystemTimeError(#[from] SystemTimeError),
276
277 /// This is returned when type conversions fail.
278 #[error(transparent)]
279 TypeConversion(#[from] std::num::TryFromIntError),
280
281 /// This is returned when checked time arithmetic failed.
282 #[error("Time arithmetic failed.")]
283 TimeArithmetic,
284}
285
286impl DateTime {
287 /// Constructs a new DateTime object denoting the current time. This may fail during
288 /// conversion to unix epoch time and during conversion to the internal i64 representation.
289 pub fn now() -> Result<Self, DateTimeError> {
290 Ok(Self(SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_millis().try_into()?))
291 }
292
293 /// Constructs a new DateTime object from milliseconds.
294 pub fn from_millis_epoch(millis: i64) -> Self {
295 Self(millis)
296 }
297
298 /// Returns unix epoch time in milliseconds.
299 pub fn to_millis_epoch(&self) -> i64 {
300 self.0
301 }
302
303 /// Returns unix epoch time in seconds.
304 pub fn to_secs_epoch(&self) -> i64 {
305 self.0 / 1000
306 }
307}
308
309impl ToSql for DateTime {
310 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
311 Ok(ToSqlOutput::Owned(Value::Integer(self.0)))
312 }
313}
314
315impl FromSql for DateTime {
316 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
317 Ok(Self(i64::column_result(value)?))
318 }
319}
320
321impl TryInto<SystemTime> for DateTime {
322 type Error = DateTimeError;
323
324 fn try_into(self) -> Result<SystemTime, Self::Error> {
325 // We want to construct a SystemTime representation equivalent to self, denoting
326 // a point in time THEN, but we cannot set the time directly. We can only construct
327 // a SystemTime denoting NOW, and we can get the duration between EPOCH and NOW,
328 // and between EPOCH and THEN. With this common reference we can construct the
329 // duration between NOW and THEN which we can add to our SystemTime representation
330 // of NOW to get a SystemTime representation of THEN.
331 // Durations can only be positive, thus the if statement below.
332 let now = SystemTime::now();
333 let now_epoch = now.duration_since(SystemTime::UNIX_EPOCH)?;
334 let then_epoch = Duration::from_millis(self.0.try_into()?);
335 Ok(if now_epoch > then_epoch {
336 // then = now - (now_epoch - then_epoch)
337 now_epoch
338 .checked_sub(then_epoch)
339 .and_then(|d| now.checked_sub(d))
340 .ok_or(DateTimeError::TimeArithmetic)?
341 } else {
342 // then = now + (then_epoch - now_epoch)
343 then_epoch
344 .checked_sub(now_epoch)
345 .and_then(|d| now.checked_add(d))
346 .ok_or(DateTimeError::TimeArithmetic)?
347 })
348 }
349}
350
351impl TryFrom<SystemTime> for DateTime {
352 type Error = DateTimeError;
353
354 fn try_from(t: SystemTime) -> Result<Self, Self::Error> {
355 Ok(Self(t.duration_since(SystemTime::UNIX_EPOCH)?.as_millis().try_into()?))
356 }
357}
358
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800359#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone)]
360enum KeyLifeCycle {
361 /// Existing keys have a key ID but are not fully populated yet.
362 /// This is a transient state. If Keystore finds any such keys when it starts up, it must move
363 /// them to Unreferenced for garbage collection.
364 Existing,
365 /// A live key is fully populated and usable by clients.
366 Live,
367 /// An unreferenced key is scheduled for garbage collection.
368 Unreferenced,
369}
370
371impl ToSql for KeyLifeCycle {
372 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
373 match self {
374 Self::Existing => Ok(ToSqlOutput::Owned(Value::Integer(0))),
375 Self::Live => Ok(ToSqlOutput::Owned(Value::Integer(1))),
376 Self::Unreferenced => Ok(ToSqlOutput::Owned(Value::Integer(2))),
377 }
378 }
379}
380
381impl FromSql for KeyLifeCycle {
382 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
383 match i64::column_result(value)? {
384 0 => Ok(KeyLifeCycle::Existing),
385 1 => Ok(KeyLifeCycle::Live),
386 2 => Ok(KeyLifeCycle::Unreferenced),
387 v => Err(FromSqlError::OutOfRange(v)),
388 }
389 }
390}
391
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700392/// Keys have a KeyMint blob component and optional public certificate and
393/// certificate chain components.
394/// KeyEntryLoadBits is a bitmap that indicates to `KeystoreDB::load_key_entry`
395/// which components shall be loaded from the database if present.
396#[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
397pub struct KeyEntryLoadBits(u32);
398
399impl KeyEntryLoadBits {
400 /// Indicate to `KeystoreDB::load_key_entry` that no component shall be loaded.
401 pub const NONE: KeyEntryLoadBits = Self(0);
402 /// Indicate to `KeystoreDB::load_key_entry` that the KeyMint component shall be loaded.
403 pub const KM: KeyEntryLoadBits = Self(1);
404 /// Indicate to `KeystoreDB::load_key_entry` that the Public components shall be loaded.
405 pub const PUBLIC: KeyEntryLoadBits = Self(2);
406 /// Indicate to `KeystoreDB::load_key_entry` that both components shall be loaded.
407 pub const BOTH: KeyEntryLoadBits = Self(3);
408
409 /// Returns true if this object indicates that the public components shall be loaded.
410 pub const fn load_public(&self) -> bool {
411 self.0 & Self::PUBLIC.0 != 0
412 }
413
414 /// Returns true if the object indicates that the KeyMint component shall be loaded.
415 pub const fn load_km(&self) -> bool {
416 self.0 & Self::KM.0 != 0
417 }
418}
419
Janis Danisevskisaec14592020-11-12 09:41:49 -0800420lazy_static! {
421 static ref KEY_ID_LOCK: KeyIdLockDb = KeyIdLockDb::new();
422}
423
424struct KeyIdLockDb {
425 locked_keys: Mutex<HashSet<i64>>,
426 cond_var: Condvar,
427}
428
429/// A locked key. While a guard exists for a given key id, the same key cannot be loaded
430/// from the database a second time. Most functions manipulating the key blob database
431/// require a KeyIdGuard.
432#[derive(Debug)]
433pub struct KeyIdGuard(i64);
434
435impl KeyIdLockDb {
436 fn new() -> Self {
437 Self { locked_keys: Mutex::new(HashSet::new()), cond_var: Condvar::new() }
438 }
439
440 /// This function blocks until an exclusive lock for the given key entry id can
441 /// be acquired. It returns a guard object, that represents the lifecycle of the
442 /// acquired lock.
443 pub fn get(&self, key_id: i64) -> KeyIdGuard {
444 let mut locked_keys = self.locked_keys.lock().unwrap();
445 while locked_keys.contains(&key_id) {
446 locked_keys = self.cond_var.wait(locked_keys).unwrap();
447 }
448 locked_keys.insert(key_id);
449 KeyIdGuard(key_id)
450 }
451
452 /// This function attempts to acquire an exclusive lock on a given key id. If the
453 /// given key id is already taken the function returns None immediately. If a lock
454 /// can be acquired this function returns a guard object, that represents the
455 /// lifecycle of the acquired lock.
456 pub fn try_get(&self, key_id: i64) -> Option<KeyIdGuard> {
457 let mut locked_keys = self.locked_keys.lock().unwrap();
458 if locked_keys.insert(key_id) {
459 Some(KeyIdGuard(key_id))
460 } else {
461 None
462 }
463 }
464}
465
466impl KeyIdGuard {
467 /// Get the numeric key id of the locked key.
468 pub fn id(&self) -> i64 {
469 self.0
470 }
471}
472
473impl Drop for KeyIdGuard {
474 fn drop(&mut self) {
475 let mut locked_keys = KEY_ID_LOCK.locked_keys.lock().unwrap();
476 locked_keys.remove(&self.0);
Janis Danisevskis7fd53582020-11-23 13:40:34 -0800477 drop(locked_keys);
Janis Danisevskisaec14592020-11-12 09:41:49 -0800478 KEY_ID_LOCK.cond_var.notify_all();
479 }
480}
481
Max Bires8e93d2b2021-01-14 13:17:59 -0800482/// This type represents a certificate and certificate chain entry for a key.
483#[derive(Debug)]
484pub struct CertificateInfo {
485 cert: Option<Vec<u8>>,
486 cert_chain: Option<Vec<u8>>,
487}
488
489impl CertificateInfo {
490 /// Constructs a new CertificateInfo object from `cert` and `cert_chain`
491 pub fn new(cert: Option<Vec<u8>>, cert_chain: Option<Vec<u8>>) -> Self {
492 Self { cert, cert_chain }
493 }
494
495 /// Take the cert
496 pub fn take_cert(&mut self) -> Option<Vec<u8>> {
497 self.cert.take()
498 }
499
500 /// Take the cert chain
501 pub fn take_cert_chain(&mut self) -> Option<Vec<u8>> {
502 self.cert_chain.take()
503 }
504}
505
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700506/// This type represents a Keystore 2.0 key entry.
507/// An entry has a unique `id` by which it can be found in the database.
508/// It has a security level field, key parameters, and three optional fields
509/// for the KeyMint blob, public certificate and a public certificate chain.
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800510#[derive(Debug, Default, Eq, PartialEq)]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700511pub struct KeyEntry {
512 id: i64,
513 km_blob: Option<Vec<u8>>,
514 cert: Option<Vec<u8>>,
515 cert_chain: Option<Vec<u8>>,
Max Bires8e93d2b2021-01-14 13:17:59 -0800516 km_uuid: Uuid,
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700517 parameters: Vec<KeyParameter>,
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800518 metadata: KeyMetaData,
Janis Danisevskis377d1002021-01-27 19:07:48 -0800519 pure_cert: bool,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700520}
521
522impl KeyEntry {
523 /// Returns the unique id of the Key entry.
524 pub fn id(&self) -> i64 {
525 self.id
526 }
527 /// Exposes the optional KeyMint blob.
528 pub fn km_blob(&self) -> &Option<Vec<u8>> {
529 &self.km_blob
530 }
531 /// Extracts the Optional KeyMint blob.
532 pub fn take_km_blob(&mut self) -> Option<Vec<u8>> {
533 self.km_blob.take()
534 }
535 /// Exposes the optional public certificate.
536 pub fn cert(&self) -> &Option<Vec<u8>> {
537 &self.cert
538 }
539 /// Extracts the optional public certificate.
540 pub fn take_cert(&mut self) -> Option<Vec<u8>> {
541 self.cert.take()
542 }
543 /// Exposes the optional public certificate chain.
544 pub fn cert_chain(&self) -> &Option<Vec<u8>> {
545 &self.cert_chain
546 }
547 /// Extracts the optional public certificate_chain.
548 pub fn take_cert_chain(&mut self) -> Option<Vec<u8>> {
549 self.cert_chain.take()
550 }
Max Bires8e93d2b2021-01-14 13:17:59 -0800551 /// Returns the uuid of the owning KeyMint instance.
552 pub fn km_uuid(&self) -> &Uuid {
553 &self.km_uuid
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700554 }
Janis Danisevskis04b02832020-10-26 09:21:40 -0700555 /// Exposes the key parameters of this key entry.
556 pub fn key_parameters(&self) -> &Vec<KeyParameter> {
557 &self.parameters
558 }
559 /// Consumes this key entry and extracts the keyparameters from it.
560 pub fn into_key_parameters(self) -> Vec<KeyParameter> {
561 self.parameters
562 }
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800563 /// Exposes the key metadata of this key entry.
564 pub fn metadata(&self) -> &KeyMetaData {
565 &self.metadata
566 }
Janis Danisevskis377d1002021-01-27 19:07:48 -0800567 /// This returns true if the entry is a pure certificate entry with no
568 /// private key component.
569 pub fn pure_cert(&self) -> bool {
570 self.pure_cert
571 }
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700572}
573
574/// Indicates the sub component of a key entry for persistent storage.
Janis Danisevskis377d1002021-01-27 19:07:48 -0800575#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700576pub struct SubComponentType(u32);
577impl SubComponentType {
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800578 /// Persistent identifier for a key blob.
579 pub const KEY_BLOB: SubComponentType = Self(0);
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700580 /// Persistent identifier for a certificate blob.
581 pub const CERT: SubComponentType = Self(1);
582 /// Persistent identifier for a certificate chain blob.
583 pub const CERT_CHAIN: SubComponentType = Self(2);
584}
585
586impl ToSql for SubComponentType {
587 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
588 self.0.to_sql()
589 }
590}
591
592impl FromSql for SubComponentType {
593 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
594 Ok(Self(u32::column_result(value)?))
595 }
596}
597
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700598/// KeystoreDB wraps a connection to an SQLite database and tracks its
599/// ownership. It also implements all of Keystore 2.0's database functionality.
Joel Galenson26f4d012020-07-17 14:57:21 -0700600pub struct KeystoreDB {
Joel Galenson26f4d012020-07-17 14:57:21 -0700601 conn: Connection,
602}
603
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000604/// Database representation of the monotonic time retrieved from the system call clock_gettime with
605/// CLOCK_MONOTONIC_RAW. Stores monotonic time as i64 in seconds.
606#[derive(Debug, Copy, Clone, Default, Eq, PartialEq, Ord, PartialOrd)]
607pub struct MonotonicRawTime(i64);
608
609impl MonotonicRawTime {
610 /// Constructs a new MonotonicRawTime
611 pub fn now() -> Self {
612 Self(get_current_time_in_seconds())
613 }
614
615 /// Returns the integer value of MonotonicRawTime as i64
616 pub fn seconds(&self) -> i64 {
617 self.0
618 }
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800619
620 /// Like i64::checked_sub.
621 pub fn checked_sub(&self, other: &Self) -> Option<Self> {
622 self.0.checked_sub(other.0).map(Self)
623 }
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000624}
625
626impl ToSql for MonotonicRawTime {
627 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
628 Ok(ToSqlOutput::Owned(Value::Integer(self.0)))
629 }
630}
631
632impl FromSql for MonotonicRawTime {
633 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
634 Ok(Self(i64::column_result(value)?))
635 }
636}
637
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000638/// This struct encapsulates the information to be stored in the database about the auth tokens
639/// received by keystore.
640pub struct AuthTokenEntry {
641 auth_token: HardwareAuthToken,
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000642 time_received: MonotonicRawTime,
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000643}
644
645impl AuthTokenEntry {
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000646 fn new(auth_token: HardwareAuthToken, time_received: MonotonicRawTime) -> Self {
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000647 AuthTokenEntry { auth_token, time_received }
648 }
649
650 /// Checks if this auth token satisfies the given authentication information.
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800651 pub fn satisfies(&self, user_secure_ids: &[i64], auth_type: HardwareAuthenticatorType) -> bool {
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000652 user_secure_ids.iter().any(|&sid| {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800653 (sid == self.auth_token.userId || sid == self.auth_token.authenticatorId)
654 && (((auth_type.0 as i32) & (self.auth_token.authenticatorType.0 as i32)) != 0)
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000655 })
656 }
657
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000658 /// Returns the auth token wrapped by the AuthTokenEntry
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800659 pub fn auth_token(&self) -> &HardwareAuthToken {
660 &self.auth_token
661 }
662
663 /// Returns the auth token wrapped by the AuthTokenEntry
664 pub fn take_auth_token(self) -> HardwareAuthToken {
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000665 self.auth_token
666 }
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800667
668 /// Returns the time that this auth token was received.
669 pub fn time_received(&self) -> MonotonicRawTime {
670 self.time_received
671 }
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000672}
673
Joel Galenson26f4d012020-07-17 14:57:21 -0700674impl KeystoreDB {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700675 /// This will create a new database connection connecting the two
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800676 /// files persistent.sqlite and perboot.sqlite in the given directory.
677 /// It also attempts to initialize all of the tables.
678 /// KeystoreDB cannot be used by multiple threads.
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700679 /// Each thread should open their own connection using `thread_local!`.
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800680 pub fn new(db_root: &Path) -> Result<Self> {
681 // Build the path to the sqlite files.
682 let mut persistent_path = db_root.to_path_buf();
683 persistent_path.push("persistent.sqlite");
684 let mut perboot_path = db_root.to_path_buf();
685 perboot_path.push("perboot.sqlite");
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700686
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800687 // Now convert them to strings prefixed with "file:"
688 let mut persistent_path_str = "file:".to_owned();
689 persistent_path_str.push_str(&persistent_path.to_string_lossy());
690 let mut perboot_path_str = "file:".to_owned();
691 perboot_path_str.push_str(&perboot_path.to_string_lossy());
692
693 let conn = Self::make_connection(&persistent_path_str, &perboot_path_str)?;
Janis Danisevskisaea27342021-01-29 08:38:11 -0800694 conn.busy_handler(Some(|_| {
695 std::thread::sleep(std::time::Duration::from_micros(50));
696 true
697 }))
698 .context("In KeystoreDB::new: Failed to set busy handler.")?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800699
700 Self::init_tables(&conn)?;
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700701 Ok(Self { conn })
Joel Galenson2aab4432020-07-22 15:27:57 -0700702 }
703
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700704 fn init_tables(conn: &Connection) -> Result<()> {
705 conn.execute(
706 "CREATE TABLE IF NOT EXISTS persistent.keyentry (
Joel Galenson0891bc12020-07-20 10:37:03 -0700707 id INTEGER UNIQUE,
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800708 key_type INTEGER,
Joel Galenson0891bc12020-07-20 10:37:03 -0700709 domain INTEGER,
710 namespace INTEGER,
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800711 alias BLOB,
Max Bires8e93d2b2021-01-14 13:17:59 -0800712 state INTEGER,
713 km_uuid BLOB);",
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700714 NO_PARAMS,
715 )
716 .context("Failed to initialize \"keyentry\" table.")?;
717
718 conn.execute(
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700719 "CREATE TABLE IF NOT EXISTS persistent.blobentry (
720 id INTEGER PRIMARY KEY,
721 subcomponent_type INTEGER,
722 keyentryid INTEGER,
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800723 blob BLOB);",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700724 NO_PARAMS,
725 )
726 .context("Failed to initialize \"blobentry\" table.")?;
727
728 conn.execute(
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700729 "CREATE TABLE IF NOT EXISTS persistent.keyparameter (
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000730 keyentryid INTEGER,
731 tag INTEGER,
732 data ANY,
733 security_level INTEGER);",
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700734 NO_PARAMS,
735 )
736 .context("Failed to initialize \"keyparameter\" table.")?;
737
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700738 conn.execute(
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800739 "CREATE TABLE IF NOT EXISTS persistent.keymetadata (
740 keyentryid INTEGER,
741 tag INTEGER,
742 data ANY);",
743 NO_PARAMS,
744 )
745 .context("Failed to initialize \"keymetadata\" table.")?;
746
747 conn.execute(
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800748 "CREATE TABLE IF NOT EXISTS persistent.grant (
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700749 id INTEGER UNIQUE,
750 grantee INTEGER,
751 keyentryid INTEGER,
752 access_vector INTEGER);",
753 NO_PARAMS,
754 )
755 .context("Failed to initialize \"grant\" table.")?;
756
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000757 //TODO: only drop the following two perboot tables if this is the first start up
758 //during the boot (b/175716626).
759 // conn.execute("DROP TABLE IF EXISTS perboot.authtoken;", NO_PARAMS)
760 // .context("Failed to drop perboot.authtoken table")?;
761 conn.execute(
762 "CREATE TABLE IF NOT EXISTS perboot.authtoken (
763 id INTEGER PRIMARY KEY,
764 challenge INTEGER,
765 user_id INTEGER,
766 auth_id INTEGER,
767 authenticator_type INTEGER,
768 timestamp INTEGER,
769 mac BLOB,
770 time_received INTEGER,
771 UNIQUE(user_id, auth_id, authenticator_type));",
772 NO_PARAMS,
773 )
774 .context("Failed to initialize \"authtoken\" table.")?;
775
776 // conn.execute("DROP TABLE IF EXISTS perboot.metadata;", NO_PARAMS)
777 // .context("Failed to drop perboot.metadata table")?;
778 // metadata table stores certain miscellaneous information required for keystore functioning
779 // during a boot cycle, as key-value pairs.
780 conn.execute(
781 "CREATE TABLE IF NOT EXISTS perboot.metadata (
782 key TEXT,
783 value BLOB,
784 UNIQUE(key));",
785 NO_PARAMS,
786 )
787 .context("Failed to initialize \"metadata\" table.")?;
Joel Galenson0891bc12020-07-20 10:37:03 -0700788 Ok(())
789 }
790
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700791 fn make_connection(persistent_file: &str, perboot_file: &str) -> Result<Connection> {
792 let conn =
793 Connection::open_in_memory().context("Failed to initialize SQLite connection.")?;
794
795 conn.execute("ATTACH DATABASE ? as persistent;", params![persistent_file])
796 .context("Failed to attach database persistent.")?;
797 conn.execute("ATTACH DATABASE ? as perboot;", params![perboot_file])
798 .context("Failed to attach database perboot.")?;
799
800 Ok(conn)
801 }
802
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800803 /// Get one unreferenced key. There is no particular order in which the keys are returned.
804 fn get_unreferenced_key_id(tx: &Transaction) -> Result<Option<i64>> {
805 tx.query_row(
806 "SELECT id FROM persistent.keyentry WHERE state = ?",
807 params![KeyLifeCycle::Unreferenced],
808 |row| row.get(0),
809 )
810 .optional()
811 .context("In get_unreferenced_key_id: Trying to get unreferenced key id.")
812 }
813
814 /// Returns a key id guard and key entry for one unreferenced key entry. Of the optional
815 /// fields of the key entry only the km_blob field will be populated. This is required
816 /// to subject the blob to its KeyMint instance for deletion.
817 pub fn get_unreferenced_key(&mut self) -> Result<Option<(KeyIdGuard, KeyEntry)>> {
818 self.with_transaction(TransactionBehavior::Deferred, |tx| {
819 let key_id = match Self::get_unreferenced_key_id(tx)
820 .context("Trying to get unreferenced key id")?
821 {
822 None => return Ok(None),
823 Some(id) => KEY_ID_LOCK.try_get(id).ok_or_else(KsError::sys).context(concat!(
824 "A key id lock was held for an unreferenced key. ",
825 "This should never happen."
826 ))?,
827 };
828 let key_entry = Self::load_key_components(tx, KeyEntryLoadBits::KM, key_id.id())
829 .context("Trying to get key components.")?;
830 Ok(Some((key_id, key_entry)))
831 })
832 .context("In get_unreferenced_key.")
833 }
834
835 /// This function purges all remnants of a key entry from the database.
836 /// Important: This does not check if the key was unreferenced, nor does it
837 /// subject the key to its KeyMint instance for permanent invalidation.
838 /// This function should only be called by the garbage collector.
839 /// To delete a key call `mark_unreferenced`, which transitions the key to the unreferenced
840 /// state, deletes all grants to the key, and notifies the garbage collector.
841 /// The garbage collector will:
842 /// 1. Call get_unreferenced_key.
843 /// 2. Determine the proper way to dispose of sensitive key material, e.g., call
844 /// `KeyMintDevice::delete()`.
845 /// 3. Call `purge_key_entry`.
846 pub fn purge_key_entry(&mut self, key_id: KeyIdGuard) -> Result<()> {
847 self.with_transaction(TransactionBehavior::Immediate, |tx| {
848 tx.execute("DELETE FROM persistent.keyentry WHERE id = ?;", params![key_id.id()])
849 .context("Trying to delete keyentry.")?;
850 tx.execute(
851 "DELETE FROM persistent.blobentry WHERE keyentryid = ?;",
852 params![key_id.id()],
853 )
854 .context("Trying to delete blobentries.")?;
855 tx.execute(
856 "DELETE FROM persistent.keymetadata WHERE keyentryid = ?;",
857 params![key_id.id()],
858 )
859 .context("Trying to delete keymetadata.")?;
860 tx.execute(
861 "DELETE FROM persistent.keyparameter WHERE keyentryid = ?;",
862 params![key_id.id()],
863 )
864 .context("Trying to delete keyparameters.")?;
865 let grants_deleted = tx
866 .execute("DELETE FROM persistent.grant WHERE keyentryid = ?;", params![key_id.id()])
867 .context("Trying to delete grants.")?;
868 if grants_deleted != 0 {
869 log::error!("Purged key that still had grants. This should not happen.");
870 }
871 Ok(())
872 })
873 .context("In purge_key_entry.")
874 }
875
876 /// This maintenance function should be called only once before the database is used for the
877 /// first time. It restores the invariant that `KeyLifeCycle::Existing` is a transient state.
878 /// The function transitions all key entries from Existing to Unreferenced unconditionally and
879 /// returns the number of rows affected. If this returns a value greater than 0, it means that
880 /// Keystore crashed at some point during key generation. Callers may want to log such
881 /// occurrences.
882 /// Unlike with `mark_unreferenced`, we don't need to purge grants, because only keys that made
883 /// it to `KeyLifeCycle::Live` may have grants.
884 pub fn cleanup_leftovers(&mut self) -> Result<usize> {
885 self.conn
886 .execute(
887 "UPDATE persistent.keyentry SET state = ? WHERE state = ?;",
888 params![KeyLifeCycle::Unreferenced, KeyLifeCycle::Existing],
889 )
890 .context("In cleanup_leftovers.")
891 }
892
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800893 /// Atomically loads a key entry and associated metadata or creates it using the
894 /// callback create_new_key callback. The callback is called during a database
895 /// transaction. This means that implementers should be mindful about using
896 /// blocking operations such as IPC or grabbing mutexes.
897 pub fn get_or_create_key_with<F>(
898 &mut self,
899 domain: Domain,
900 namespace: i64,
901 alias: &str,
Max Bires8e93d2b2021-01-14 13:17:59 -0800902 km_uuid: Uuid,
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800903 create_new_key: F,
904 ) -> Result<(KeyIdGuard, KeyEntry)>
905 where
906 F: FnOnce() -> Result<(Vec<u8>, KeyMetaData)>,
907 {
908 let tx = self
909 .conn
910 .transaction_with_behavior(TransactionBehavior::Immediate)
911 .context("In get_or_create_key_with: Failed to initialize transaction.")?;
912
913 let id = {
914 let mut stmt = tx
915 .prepare(
916 "SELECT id FROM persistent.keyentry
917 WHERE
918 key_type = ?
919 AND domain = ?
920 AND namespace = ?
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800921 AND alias = ?
922 AND state = ?;",
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800923 )
924 .context("In get_or_create_key_with: Failed to select from keyentry table.")?;
925 let mut rows = stmt
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800926 .query(params![KeyType::Super, domain.0, namespace, alias, KeyLifeCycle::Live])
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800927 .context("In get_or_create_key_with: Failed to query from keyentry table.")?;
928
929 db_utils::with_rows_extract_one(&mut rows, |row| {
930 Ok(match row {
931 Some(r) => r.get(0).context("Failed to unpack id.")?,
932 None => None,
933 })
934 })
935 .context("In get_or_create_key_with.")?
936 };
937
938 let (id, entry) = match id {
939 Some(id) => (
940 id,
941 Self::load_key_components(&tx, KeyEntryLoadBits::KM, id)
942 .context("In get_or_create_key_with.")?,
943 ),
944
945 None => {
946 let id = Self::insert_with_retry(|id| {
947 tx.execute(
948 "INSERT into persistent.keyentry
Max Bires8e93d2b2021-01-14 13:17:59 -0800949 (id, key_type, domain, namespace, alias, state, km_uuid)
950 VALUES(?, ?, ?, ?, ?, ?, ?);",
951 params![
952 id,
953 KeyType::Super,
954 domain.0,
955 namespace,
956 alias,
957 KeyLifeCycle::Live,
958 km_uuid,
959 ],
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800960 )
961 })
962 .context("In get_or_create_key_with.")?;
963
964 let (blob, metadata) = create_new_key().context("In get_or_create_key_with.")?;
Janis Danisevskis377d1002021-01-27 19:07:48 -0800965 Self::set_blob_internal(&tx, id, SubComponentType::KEY_BLOB, Some(&blob))
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800966 .context("In get_of_create_key_with.")?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800967 metadata.store_in_db(id, &tx).context("In get_or_create_key_with.")?;
Janis Danisevskis377d1002021-01-27 19:07:48 -0800968 (
969 id,
970 KeyEntry {
971 id,
972 km_blob: Some(blob),
973 metadata,
974 pure_cert: false,
975 ..Default::default()
976 },
977 )
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800978 }
979 };
980 tx.commit().context("In get_or_create_key_with: Failed to commit transaction.")?;
981 Ok((KEY_ID_LOCK.get(id), entry))
982 }
983
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800984 /// Creates a transaction with the given behavior and executes f with the new transaction.
985 /// The transaction is committed only if f returns Ok.
986 fn with_transaction<T, F>(&mut self, behavior: TransactionBehavior, f: F) -> Result<T>
987 where
988 F: FnOnce(&Transaction) -> Result<T>,
989 {
990 let tx = self
991 .conn
992 .transaction_with_behavior(behavior)
993 .context("In with_transaction: Failed to initialize transaction.")?;
994 f(&tx).and_then(|result| {
995 tx.commit().context("In with_transaction: Failed to commit transaction.")?;
996 Ok(result)
997 })
998 }
999
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001000 /// Creates a new key entry and allocates a new randomized id for the new key.
1001 /// The key id gets associated with a domain and namespace but not with an alias.
1002 /// To complete key generation `rebind_alias` should be called after all of the
1003 /// key artifacts, i.e., blobs and parameters have been associated with the new
1004 /// key id. Finalizing with `rebind_alias` makes the creation of a new key entry
1005 /// atomic even if key generation is not.
Max Bires8e93d2b2021-01-14 13:17:59 -08001006 pub fn create_key_entry(
1007 &mut self,
1008 domain: Domain,
1009 namespace: i64,
1010 km_uuid: &Uuid,
1011 ) -> Result<KeyIdGuard> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001012 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Max Bires8e93d2b2021-01-14 13:17:59 -08001013 Self::create_key_entry_internal(tx, domain, namespace, km_uuid)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001014 })
1015 .context("In create_key_entry.")
1016 }
1017
1018 fn create_key_entry_internal(
1019 tx: &Transaction,
1020 domain: Domain,
1021 namespace: i64,
Max Bires8e93d2b2021-01-14 13:17:59 -08001022 km_uuid: &Uuid,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001023 ) -> Result<KeyIdGuard> {
Joel Galenson0891bc12020-07-20 10:37:03 -07001024 match domain {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001025 Domain::APP | Domain::SELINUX => {}
Joel Galenson0891bc12020-07-20 10:37:03 -07001026 _ => {
1027 return Err(KsError::sys())
1028 .context(format!("Domain {:?} must be either App or SELinux.", domain));
1029 }
1030 }
Janis Danisevskisaec14592020-11-12 09:41:49 -08001031 Ok(KEY_ID_LOCK.get(
1032 Self::insert_with_retry(|id| {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001033 tx.execute(
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001034 "INSERT into persistent.keyentry
Max Bires8e93d2b2021-01-14 13:17:59 -08001035 (id, key_type, domain, namespace, alias, state, km_uuid)
1036 VALUES(?, ?, ?, ?, NULL, ?, ?);",
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001037 params![
1038 id,
1039 KeyType::Client,
1040 domain.0 as u32,
1041 namespace,
Max Bires8e93d2b2021-01-14 13:17:59 -08001042 KeyLifeCycle::Existing,
1043 km_uuid,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001044 ],
Janis Danisevskisaec14592020-11-12 09:41:49 -08001045 )
1046 })
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001047 .context("In create_key_entry_internal")?,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001048 ))
Joel Galenson26f4d012020-07-17 14:57:21 -07001049 }
Joel Galenson33c04ad2020-08-03 11:04:38 -07001050
Janis Danisevskis377d1002021-01-27 19:07:48 -08001051 /// Set a new blob and associates it with the given key id. Each blob
1052 /// has a sub component type.
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001053 /// Each key can have one of each sub component type associated. If more
1054 /// are added only the most recent can be retrieved, and superseded blobs
Janis Danisevskis377d1002021-01-27 19:07:48 -08001055 /// will get garbage collected.
1056 /// Components SubComponentType::CERT and SubComponentType::CERT_CHAIN can be
1057 /// removed by setting blob to None.
1058 pub fn set_blob(
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001059 &mut self,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001060 key_id: &KeyIdGuard,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001061 sc_type: SubComponentType,
Janis Danisevskis377d1002021-01-27 19:07:48 -08001062 blob: Option<&[u8]>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001063 ) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001064 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis377d1002021-01-27 19:07:48 -08001065 Self::set_blob_internal(&tx, key_id.0, sc_type, blob)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001066 })
Janis Danisevskis377d1002021-01-27 19:07:48 -08001067 .context("In set_blob.")
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001068 }
1069
Janis Danisevskis377d1002021-01-27 19:07:48 -08001070 fn set_blob_internal(
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001071 tx: &Transaction,
1072 key_id: i64,
1073 sc_type: SubComponentType,
Janis Danisevskis377d1002021-01-27 19:07:48 -08001074 blob: Option<&[u8]>,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001075 ) -> Result<()> {
Janis Danisevskis377d1002021-01-27 19:07:48 -08001076 match (blob, sc_type) {
1077 (Some(blob), _) => {
1078 tx.execute(
1079 "INSERT INTO persistent.blobentry
1080 (subcomponent_type, keyentryid, blob) VALUES (?, ?, ?);",
1081 params![sc_type, key_id, blob],
1082 )
1083 .context("In set_blob_internal: Failed to insert blob.")?;
1084 }
1085 (None, SubComponentType::CERT) | (None, SubComponentType::CERT_CHAIN) => {
1086 tx.execute(
1087 "DELETE FROM persistent.blobentry
1088 WHERE subcomponent_type = ? AND keyentryid = ?;",
1089 params![sc_type, key_id],
1090 )
1091 .context("In set_blob_internal: Failed to delete blob.")?;
1092 }
1093 (None, _) => {
1094 return Err(KsError::sys())
1095 .context("In set_blob_internal: Other blobs cannot be deleted in this way.");
1096 }
1097 }
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001098 Ok(())
1099 }
1100
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001101 /// Inserts a collection of key parameters into the `persistent.keyparameter` table
1102 /// and associates them with the given `key_id`.
1103 pub fn insert_keyparameter<'a>(
1104 &mut self,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001105 key_id: &KeyIdGuard,
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001106 params: impl IntoIterator<Item = &'a KeyParameter>,
1107 ) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001108 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1109 Self::insert_keyparameter_internal(tx, key_id, params)
1110 })
1111 .context("In insert_keyparameter.")
1112 }
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001113
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001114 fn insert_keyparameter_internal<'a>(
1115 tx: &Transaction,
1116 key_id: &KeyIdGuard,
1117 params: impl IntoIterator<Item = &'a KeyParameter>,
1118 ) -> Result<()> {
1119 let mut stmt = tx
1120 .prepare(
1121 "INSERT into persistent.keyparameter (keyentryid, tag, data, security_level)
1122 VALUES (?, ?, ?, ?);",
1123 )
1124 .context("In insert_keyparameter_internal: Failed to prepare statement.")?;
1125
1126 let iter = params.into_iter();
1127 for p in iter {
1128 stmt.insert(params![
1129 key_id.0,
1130 p.get_tag().0,
1131 p.key_parameter_value(),
1132 p.security_level().0
1133 ])
1134 .with_context(|| {
1135 format!("In insert_keyparameter_internal: Failed to insert {:?}", p)
1136 })?;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001137 }
1138 Ok(())
1139 }
1140
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001141 /// Insert a set of key entry specific metadata into the database.
1142 pub fn insert_key_metadata(
1143 &mut self,
1144 key_id: &KeyIdGuard,
1145 metadata: &KeyMetaData,
1146 ) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001147 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1148 metadata.store_in_db(key_id.0, &tx)
1149 })
1150 .context("In insert_key_metadata.")
1151 }
1152
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001153 /// Updates the alias column of the given key id `newid` with the given alias,
1154 /// and atomically, removes the alias, domain, and namespace from another row
1155 /// with the same alias-domain-namespace tuple if such row exits.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001156 /// Returns Ok(true) if an old key was marked unreferenced as a hint to the garbage
1157 /// collector.
1158 fn rebind_alias(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001159 tx: &Transaction,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001160 newid: &KeyIdGuard,
Joel Galenson33c04ad2020-08-03 11:04:38 -07001161 alias: &str,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001162 domain: Domain,
Joel Galenson33c04ad2020-08-03 11:04:38 -07001163 namespace: i64,
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001164 ) -> Result<bool> {
Joel Galenson33c04ad2020-08-03 11:04:38 -07001165 match domain {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001166 Domain::APP | Domain::SELINUX => {}
Joel Galenson33c04ad2020-08-03 11:04:38 -07001167 _ => {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001168 return Err(KsError::sys()).context(format!(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001169 "In rebind_alias: Domain {:?} must be either App or SELinux.",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001170 domain
1171 ));
Joel Galenson33c04ad2020-08-03 11:04:38 -07001172 }
1173 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001174 let updated = tx
1175 .execute(
1176 "UPDATE persistent.keyentry
1177 SET alias = NULL, domain = NULL, namespace = NULL, state = ?
Joel Galenson33c04ad2020-08-03 11:04:38 -07001178 WHERE alias = ? AND domain = ? AND namespace = ?;",
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001179 params![KeyLifeCycle::Unreferenced, alias, domain.0 as u32, namespace],
1180 )
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001181 .context("In rebind_alias: Failed to rebind existing entry.")?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07001182 let result = tx
1183 .execute(
1184 "UPDATE persistent.keyentry
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001185 SET alias = ?, state = ?
1186 WHERE id = ? AND domain = ? AND namespace = ? AND state = ?;",
1187 params![
1188 alias,
1189 KeyLifeCycle::Live,
1190 newid.0,
1191 domain.0 as u32,
1192 namespace,
Max Bires8e93d2b2021-01-14 13:17:59 -08001193 KeyLifeCycle::Existing,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001194 ],
Joel Galenson33c04ad2020-08-03 11:04:38 -07001195 )
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001196 .context("In rebind_alias: Failed to set alias.")?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07001197 if result != 1 {
Joel Galenson33c04ad2020-08-03 11:04:38 -07001198 return Err(KsError::sys()).context(format!(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001199 "In rebind_alias: Expected to update a single entry but instead updated {}.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07001200 result
1201 ));
1202 }
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001203 Ok(updated != 0)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001204 }
1205
1206 /// Store a new key in a single transaction.
1207 /// The function creates a new key entry, populates the blob, key parameter, and metadata
1208 /// fields, and rebinds the given alias to the new key.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001209 /// The boolean returned is a hint for the garbage collector. If true, a key was replaced,
1210 /// is now unreferenced and needs to be collected.
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001211 pub fn store_new_key<'a>(
1212 &mut self,
1213 key: KeyDescriptor,
1214 params: impl IntoIterator<Item = &'a KeyParameter>,
1215 blob: &[u8],
Max Bires8e93d2b2021-01-14 13:17:59 -08001216 cert_info: &CertificateInfo,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001217 metadata: &KeyMetaData,
Max Bires8e93d2b2021-01-14 13:17:59 -08001218 km_uuid: &Uuid,
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001219 ) -> Result<(bool, KeyIdGuard)> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001220 let (alias, domain, namespace) = match key {
1221 KeyDescriptor { alias: Some(alias), domain: Domain::APP, nspace, blob: None }
1222 | KeyDescriptor { alias: Some(alias), domain: Domain::SELINUX, nspace, blob: None } => {
1223 (alias, key.domain, nspace)
1224 }
1225 _ => {
1226 return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT))
1227 .context("In store_new_key: Need alias and domain must be APP or SELINUX.")
1228 }
1229 };
1230 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Max Bires8e93d2b2021-01-14 13:17:59 -08001231 let key_id = Self::create_key_entry_internal(tx, domain, namespace, km_uuid)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001232 .context("Trying to create new key entry.")?;
Janis Danisevskis377d1002021-01-27 19:07:48 -08001233 Self::set_blob_internal(tx, key_id.id(), SubComponentType::KEY_BLOB, Some(blob))
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001234 .context("Trying to insert the key blob.")?;
Max Bires8e93d2b2021-01-14 13:17:59 -08001235 if let Some(cert) = &cert_info.cert {
Janis Danisevskis377d1002021-01-27 19:07:48 -08001236 Self::set_blob_internal(tx, key_id.id(), SubComponentType::CERT, Some(&cert))
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001237 .context("Trying to insert the certificate.")?;
1238 }
Max Bires8e93d2b2021-01-14 13:17:59 -08001239 if let Some(cert_chain) = &cert_info.cert_chain {
Janis Danisevskis377d1002021-01-27 19:07:48 -08001240 Self::set_blob_internal(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001241 tx,
1242 key_id.id(),
1243 SubComponentType::CERT_CHAIN,
Janis Danisevskis377d1002021-01-27 19:07:48 -08001244 Some(&cert_chain),
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001245 )
1246 .context("Trying to insert the certificate chain.")?;
1247 }
1248 Self::insert_keyparameter_internal(tx, &key_id, params)
1249 .context("Trying to insert key parameters.")?;
Janis Danisevskis377d1002021-01-27 19:07:48 -08001250 metadata.store_in_db(key_id.id(), tx).context("Trying to insert key metadata.")?;
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001251 let need_gc = Self::rebind_alias(tx, &key_id, &alias, domain, namespace)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001252 .context("Trying to rebind alias.")?;
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001253 Ok((need_gc, key_id))
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001254 })
1255 .context("In store_new_key.")
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001256 }
1257
Janis Danisevskis377d1002021-01-27 19:07:48 -08001258 /// Store a new certificate
1259 /// The function creates a new key entry, populates the blob field and metadata, and rebinds
1260 /// the given alias to the new cert.
Max Bires8e93d2b2021-01-14 13:17:59 -08001261 pub fn store_new_certificate(
1262 &mut self,
1263 key: KeyDescriptor,
1264 cert: &[u8],
1265 km_uuid: &Uuid,
1266 ) -> Result<KeyIdGuard> {
Janis Danisevskis377d1002021-01-27 19:07:48 -08001267 let (alias, domain, namespace) = match key {
1268 KeyDescriptor { alias: Some(alias), domain: Domain::APP, nspace, blob: None }
1269 | KeyDescriptor { alias: Some(alias), domain: Domain::SELINUX, nspace, blob: None } => {
1270 (alias, key.domain, nspace)
1271 }
1272 _ => {
1273 return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT)).context(
1274 "In store_new_certificate: Need alias and domain must be APP or SELINUX.",
1275 )
1276 }
1277 };
1278 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Max Bires8e93d2b2021-01-14 13:17:59 -08001279 let key_id = Self::create_key_entry_internal(tx, domain, namespace, km_uuid)
Janis Danisevskis377d1002021-01-27 19:07:48 -08001280 .context("Trying to create new key entry.")?;
1281
1282 Self::set_blob_internal(tx, key_id.id(), SubComponentType::CERT_CHAIN, Some(cert))
1283 .context("Trying to insert certificate.")?;
1284
1285 let mut metadata = KeyMetaData::new();
1286 metadata.add(KeyMetaEntry::CreationDate(
1287 DateTime::now().context("Trying to make creation time.")?,
1288 ));
1289
1290 metadata.store_in_db(key_id.id(), tx).context("Trying to insert key metadata.")?;
1291
1292 Self::rebind_alias(tx, &key_id, &alias, domain, namespace)
1293 .context("Trying to rebind alias.")?;
1294 Ok(key_id)
1295 })
1296 .context("In store_new_certificate.")
1297 }
1298
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001299 // Helper function loading the key_id given the key descriptor
1300 // tuple comprising domain, namespace, and alias.
1301 // Requires a valid transaction.
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001302 fn load_key_entry_id(tx: &Transaction, key: &KeyDescriptor, key_type: KeyType) -> Result<i64> {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001303 let alias = key
1304 .alias
1305 .as_ref()
1306 .map_or_else(|| Err(KsError::sys()), Ok)
1307 .context("In load_key_entry_id: Alias must be specified.")?;
1308 let mut stmt = tx
1309 .prepare(
1310 "SELECT id FROM persistent.keyentry
1311 WHERE
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001312 key_type = ?
1313 AND domain = ?
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001314 AND namespace = ?
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001315 AND alias = ?
1316 AND state = ?;",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001317 )
1318 .context("In load_key_entry_id: Failed to select from keyentry table.")?;
1319 let mut rows = stmt
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001320 .query(params![key_type, key.domain.0 as u32, key.nspace, alias, KeyLifeCycle::Live])
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001321 .context("In load_key_entry_id: Failed to read from keyentry table.")?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08001322 db_utils::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001323 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001324 .get(0)
1325 .context("Failed to unpack id.")
1326 })
1327 .context("In load_key_entry_id.")
1328 }
1329
1330 /// This helper function completes the access tuple of a key, which is required
1331 /// to perform access control. The strategy depends on the `domain` field in the
1332 /// key descriptor.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001333 /// * Domain::SELINUX: The access tuple is complete and this function only loads
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001334 /// the key_id for further processing.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001335 /// * Domain::APP: Like Domain::SELINUX, but the tuple is completed by `caller_uid`
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001336 /// which serves as the namespace.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001337 /// * Domain::GRANT: The grant table is queried for the `key_id` and the
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001338 /// `access_vector`.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001339 /// * Domain::KEY_ID: The keyentry table is queried for the owning `domain` and
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001340 /// `namespace`.
1341 /// In each case the information returned is sufficient to perform the access
1342 /// check and the key id can be used to load further key artifacts.
1343 fn load_access_tuple(
1344 tx: &Transaction,
1345 key: KeyDescriptor,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001346 key_type: KeyType,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001347 caller_uid: u32,
1348 ) -> Result<(i64, KeyDescriptor, Option<KeyPermSet>)> {
1349 match key.domain {
1350 // Domain App or SELinux. In this case we load the key_id from
1351 // the keyentry database for further loading of key components.
1352 // We already have the full access tuple to perform access control.
1353 // The only distinction is that we use the caller_uid instead
1354 // of the caller supplied namespace if the domain field is
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001355 // Domain::APP.
1356 Domain::APP | Domain::SELINUX => {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001357 let mut access_key = key;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001358 if access_key.domain == Domain::APP {
1359 access_key.nspace = caller_uid as i64;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001360 }
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001361 let key_id = Self::load_key_entry_id(&tx, &access_key, key_type)
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001362 .with_context(|| format!("With key.domain = {:?}.", access_key.domain))?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001363
1364 Ok((key_id, access_key, None))
1365 }
1366
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001367 // Domain::GRANT. In this case we load the key_id and the access_vector
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001368 // from the grant table.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001369 Domain::GRANT => {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001370 let mut stmt = tx
1371 .prepare(
Janis Danisevskisbf15d732020-12-08 10:35:26 -08001372 "SELECT keyentryid, access_vector FROM persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001373 WHERE grantee = ? AND id = ?;",
1374 )
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001375 .context("Domain::GRANT prepare statement failed")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001376 let mut rows = stmt
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001377 .query(params![caller_uid as i64, key.nspace])
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001378 .context("Domain:Grant: query failed.")?;
1379 let (key_id, access_vector): (i64, i32) =
Janis Danisevskisbf15d732020-12-08 10:35:26 -08001380 db_utils::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001381 let r =
1382 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001383 Ok((
1384 r.get(0).context("Failed to unpack key_id.")?,
1385 r.get(1).context("Failed to unpack access_vector.")?,
1386 ))
1387 })
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001388 .context("Domain::GRANT.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001389 Ok((key_id, key, Some(access_vector.into())))
1390 }
1391
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001392 // Domain::KEY_ID. In this case we load the domain and namespace from the
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001393 // keyentry database because we need them for access control.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001394 Domain::KEY_ID => {
Janis Danisevskis45760022021-01-19 16:34:10 -08001395 let (domain, namespace): (Domain, i64) = {
1396 let mut stmt = tx
1397 .prepare(
1398 "SELECT domain, namespace FROM persistent.keyentry
1399 WHERE
1400 id = ?
1401 AND state = ?;",
1402 )
1403 .context("Domain::KEY_ID: prepare statement failed")?;
1404 let mut rows = stmt
1405 .query(params![key.nspace, KeyLifeCycle::Live])
1406 .context("Domain::KEY_ID: query failed.")?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08001407 db_utils::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001408 let r =
1409 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001410 Ok((
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001411 Domain(r.get(0).context("Failed to unpack domain.")?),
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001412 r.get(1).context("Failed to unpack namespace.")?,
1413 ))
1414 })
Janis Danisevskis45760022021-01-19 16:34:10 -08001415 .context("Domain::KEY_ID.")?
1416 };
1417
1418 // We may use a key by id after loading it by grant.
1419 // In this case we have to check if the caller has a grant for this particular
1420 // key. We can skip this if we already know that the caller is the owner.
1421 // But we cannot know this if domain is anything but App. E.g. in the case
1422 // of Domain::SELINUX we have to speculatively check for grants because we have to
1423 // consult the SEPolicy before we know if the caller is the owner.
1424 let access_vector: Option<KeyPermSet> =
1425 if domain != Domain::APP || namespace != caller_uid as i64 {
1426 let access_vector: Option<i32> = tx
1427 .query_row(
1428 "SELECT access_vector FROM persistent.grant
1429 WHERE grantee = ? AND keyentryid = ?;",
1430 params![caller_uid as i64, key.nspace],
1431 |row| row.get(0),
1432 )
1433 .optional()
1434 .context("Domain::KEY_ID: query grant failed.")?;
1435 access_vector.map(|p| p.into())
1436 } else {
1437 None
1438 };
1439
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001440 let key_id = key.nspace;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001441 let mut access_key = key;
1442 access_key.domain = domain;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001443 access_key.nspace = namespace;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001444
Janis Danisevskis45760022021-01-19 16:34:10 -08001445 Ok((key_id, access_key, access_vector))
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001446 }
1447 _ => Err(anyhow!(KsError::sys())),
1448 }
1449 }
1450
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001451 fn load_blob_components(
1452 key_id: i64,
1453 load_bits: KeyEntryLoadBits,
1454 tx: &Transaction,
Janis Danisevskis377d1002021-01-27 19:07:48 -08001455 ) -> Result<(bool, Option<Vec<u8>>, Option<Vec<u8>>, Option<Vec<u8>>)> {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001456 let mut stmt = tx
1457 .prepare(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001458 "SELECT MAX(id), subcomponent_type, blob FROM persistent.blobentry
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001459 WHERE keyentryid = ? GROUP BY subcomponent_type;",
1460 )
1461 .context("In load_blob_components: prepare statement failed.")?;
1462
1463 let mut rows =
1464 stmt.query(params![key_id]).context("In load_blob_components: query failed.")?;
1465
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001466 let mut km_blob: Option<Vec<u8>> = None;
1467 let mut cert_blob: Option<Vec<u8>> = None;
1468 let mut cert_chain_blob: Option<Vec<u8>> = None;
Janis Danisevskis377d1002021-01-27 19:07:48 -08001469 let mut has_km_blob: bool = false;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08001470 db_utils::with_rows_extract_all(&mut rows, |row| {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001471 let sub_type: SubComponentType =
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001472 row.get(1).context("Failed to extract subcomponent_type.")?;
Janis Danisevskis377d1002021-01-27 19:07:48 -08001473 has_km_blob = has_km_blob || sub_type == SubComponentType::KEY_BLOB;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001474 match (sub_type, load_bits.load_public(), load_bits.load_km()) {
1475 (SubComponentType::KEY_BLOB, _, true) => {
1476 km_blob = Some(row.get(2).context("Failed to extract KM blob.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001477 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001478 (SubComponentType::CERT, true, _) => {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001479 cert_blob =
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001480 Some(row.get(2).context("Failed to extract public certificate blob.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001481 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001482 (SubComponentType::CERT_CHAIN, true, _) => {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001483 cert_chain_blob =
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001484 Some(row.get(2).context("Failed to extract certificate chain blob.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001485 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001486 (SubComponentType::CERT, _, _)
1487 | (SubComponentType::CERT_CHAIN, _, _)
1488 | (SubComponentType::KEY_BLOB, _, _) => {}
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001489 _ => Err(KsError::sys()).context("Unknown subcomponent type.")?,
1490 }
1491 Ok(())
1492 })
1493 .context("In load_blob_components.")?;
1494
Janis Danisevskis377d1002021-01-27 19:07:48 -08001495 Ok((has_km_blob, km_blob, cert_blob, cert_chain_blob))
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001496 }
1497
1498 fn load_key_parameters(key_id: i64, tx: &Transaction) -> Result<Vec<KeyParameter>> {
1499 let mut stmt = tx
1500 .prepare(
1501 "SELECT tag, data, security_level from persistent.keyparameter
1502 WHERE keyentryid = ?;",
1503 )
1504 .context("In load_key_parameters: prepare statement failed.")?;
1505
1506 let mut parameters: Vec<KeyParameter> = Vec::new();
1507
1508 let mut rows =
1509 stmt.query(params![key_id]).context("In load_key_parameters: query failed.")?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08001510 db_utils::with_rows_extract_all(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001511 let tag = Tag(row.get(0).context("Failed to read tag.")?);
1512 let sec_level = SecurityLevel(row.get(2).context("Failed to read sec_level.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001513 parameters.push(
1514 KeyParameter::new_from_sql(tag, &SqlField::new(1, &row), sec_level)
1515 .context("Failed to read KeyParameter.")?,
1516 );
1517 Ok(())
1518 })
1519 .context("In load_key_parameters.")?;
1520
1521 Ok(parameters)
1522 }
1523
Qi Wub9433b52020-12-01 14:52:46 +08001524 /// Decrements the usage count of a limited use key. This function first checks whether the
1525 /// usage has been exhausted, if not, decreases the usage count. If the usage count reaches
1526 /// zero, the key also gets marked unreferenced and scheduled for deletion.
1527 /// Returns Ok(true) if the key was marked unreferenced as a hint to the garbage collector.
1528 pub fn check_and_update_key_usage_count(&mut self, key_id: i64) -> Result<bool> {
1529 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1530 let limit: Option<i32> = tx
1531 .query_row(
1532 "SELECT data FROM persistent.keyparameter WHERE keyentryid = ? AND tag = ?;",
1533 params![key_id, Tag::USAGE_COUNT_LIMIT.0],
1534 |row| row.get(0),
1535 )
1536 .optional()
1537 .context("Trying to load usage count")?;
1538
1539 let limit = limit
1540 .ok_or(KsError::Km(ErrorCode::INVALID_KEY_BLOB))
1541 .context("The Key no longer exists. Key is exhausted.")?;
1542
1543 tx.execute(
1544 "UPDATE persistent.keyparameter
1545 SET data = data - 1
1546 WHERE keyentryid = ? AND tag = ? AND data > 0;",
1547 params![key_id, Tag::USAGE_COUNT_LIMIT.0],
1548 )
1549 .context("Failed to update key usage count.")?;
1550
1551 match limit {
1552 1 => Self::mark_unreferenced(tx, key_id)
1553 .context("Trying to mark limited use key for deletion."),
1554 0 => Err(KsError::Km(ErrorCode::INVALID_KEY_BLOB)).context("Key is exhausted."),
1555 _ => Ok(false),
1556 }
1557 })
1558 .context("In check_and_update_key_usage_count.")
1559 }
1560
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001561 /// Load a key entry by the given key descriptor.
1562 /// It uses the `check_permission` callback to verify if the access is allowed
1563 /// given the key access tuple read from the database using `load_access_tuple`.
1564 /// With `load_bits` the caller may specify which blobs shall be loaded from
1565 /// the blob database.
1566 pub fn load_key_entry(
1567 &mut self,
1568 key: KeyDescriptor,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001569 key_type: KeyType,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001570 load_bits: KeyEntryLoadBits,
1571 caller_uid: u32,
1572 check_permission: impl FnOnce(&KeyDescriptor, Option<KeyPermSet>) -> Result<()>,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001573 ) -> Result<(KeyIdGuard, KeyEntry)> {
1574 // KEY ID LOCK 1/2
1575 // If we got a key descriptor with a key id we can get the lock right away.
1576 // Otherwise we have to defer it until we know the key id.
1577 let key_id_guard = match key.domain {
1578 Domain::KEY_ID => Some(KEY_ID_LOCK.get(key.nspace)),
1579 _ => None,
1580 };
1581
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001582 let tx = self
1583 .conn
Janis Danisevskisaec14592020-11-12 09:41:49 -08001584 .unchecked_transaction()
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001585 .context("In load_key_entry: Failed to initialize transaction.")?;
1586
1587 // Load the key_id and complete the access control tuple.
1588 let (key_id, access_key_descriptor, access_vector) =
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001589 Self::load_access_tuple(&tx, key, key_type, caller_uid)
1590 .context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001591
1592 // Perform access control. It is vital that we return here if the permission is denied.
1593 // So do not touch that '?' at the end.
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001594 check_permission(&access_key_descriptor, access_vector).context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001595
Janis Danisevskisaec14592020-11-12 09:41:49 -08001596 // KEY ID LOCK 2/2
1597 // If we did not get a key id lock by now, it was because we got a key descriptor
1598 // without a key id. At this point we got the key id, so we can try and get a lock.
1599 // However, we cannot block here, because we are in the middle of the transaction.
1600 // So first we try to get the lock non blocking. If that fails, we roll back the
1601 // transaction and block until we get the lock. After we successfully got the lock,
1602 // we start a new transaction and load the access tuple again.
1603 //
1604 // We don't need to perform access control again, because we already established
1605 // that the caller had access to the given key. But we need to make sure that the
1606 // key id still exists. So we have to load the key entry by key id this time.
1607 let (key_id_guard, tx) = match key_id_guard {
1608 None => match KEY_ID_LOCK.try_get(key_id) {
1609 None => {
1610 // Roll back the transaction.
1611 tx.rollback().context("In load_key_entry: Failed to roll back transaction.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001612
Janis Danisevskisaec14592020-11-12 09:41:49 -08001613 // Block until we have a key id lock.
1614 let key_id_guard = KEY_ID_LOCK.get(key_id);
1615
1616 // Create a new transaction.
1617 let tx = self.conn.unchecked_transaction().context(
1618 "In load_key_entry: Failed to initialize transaction. (deferred key lock)",
1619 )?;
1620
1621 Self::load_access_tuple(
1622 &tx,
1623 // This time we have to load the key by the retrieved key id, because the
1624 // alias may have been rebound after we rolled back the transaction.
1625 KeyDescriptor {
1626 domain: Domain::KEY_ID,
1627 nspace: key_id,
1628 ..Default::default()
1629 },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001630 key_type,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001631 caller_uid,
1632 )
1633 .context("In load_key_entry. (deferred key lock)")?;
1634 (key_id_guard, tx)
1635 }
1636 Some(l) => (l, tx),
1637 },
1638 Some(key_id_guard) => (key_id_guard, tx),
1639 };
1640
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001641 let key_entry = Self::load_key_components(&tx, load_bits, key_id_guard.id())
1642 .context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001643
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001644 tx.commit().context("In load_key_entry: Failed to commit transaction.")?;
1645
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001646 Ok((key_id_guard, key_entry))
1647 }
1648
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001649 fn mark_unreferenced(tx: &Transaction, key_id: i64) -> Result<bool> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001650 let updated = tx
1651 .execute(
1652 "UPDATE persistent.keyentry SET state = ? WHERE id = ?;",
1653 params![KeyLifeCycle::Unreferenced, key_id],
1654 )
1655 .context("In mark_unreferenced: Failed to update state of key entry.")?;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001656 tx.execute("DELETE from persistent.grant WHERE keyentryid = ?;", params![key_id])
1657 .context("In mark_unreferenced: Failed to drop grants.")?;
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001658 Ok(updated != 0)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001659 }
1660
1661 /// Marks the given key as unreferenced and removes all of the grants to this key.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001662 /// Returns Ok(true) if a key was marked unreferenced as a hint for the garbage collector.
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001663 pub fn unbind_key(
1664 &mut self,
1665 key: KeyDescriptor,
1666 key_type: KeyType,
1667 caller_uid: u32,
1668 check_permission: impl FnOnce(&KeyDescriptor, Option<KeyPermSet>) -> Result<()>,
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001669 ) -> Result<bool> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001670 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1671 let (key_id, access_key_descriptor, access_vector) =
1672 Self::load_access_tuple(tx, key, key_type, caller_uid)
1673 .context("Trying to get access tuple.")?;
1674
1675 // Perform access control. It is vital that we return here if the permission is denied.
1676 // So do not touch that '?' at the end.
1677 check_permission(&access_key_descriptor, access_vector)
1678 .context("While checking permission.")?;
1679
1680 Self::mark_unreferenced(tx, key_id).context("Trying to mark the key unreferenced.")
1681 })
1682 .context("In unbind_key.")
1683 }
1684
Max Bires8e93d2b2021-01-14 13:17:59 -08001685 fn get_key_km_uuid(tx: &Transaction, key_id: i64) -> Result<Uuid> {
1686 tx.query_row(
1687 "SELECT km_uuid FROM persistent.keyentry WHERE id = ?",
1688 params![key_id],
1689 |row| row.get(0),
1690 )
1691 .context("In get_key_km_uuid.")
1692 }
1693
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001694 fn load_key_components(
1695 tx: &Transaction,
1696 load_bits: KeyEntryLoadBits,
1697 key_id: i64,
1698 ) -> Result<KeyEntry> {
1699 let metadata = KeyMetaData::load_from_db(key_id, &tx).context("In load_key_components.")?;
1700
Janis Danisevskis377d1002021-01-27 19:07:48 -08001701 let (has_km_blob, km_blob, cert_blob, cert_chain_blob) =
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001702 Self::load_blob_components(key_id, load_bits, &tx)
1703 .context("In load_key_components.")?;
1704
Max Bires8e93d2b2021-01-14 13:17:59 -08001705 let parameters = Self::load_key_parameters(key_id, &tx)
1706 .context("In load_key_components: Trying to load key parameters.")?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001707
Max Bires8e93d2b2021-01-14 13:17:59 -08001708 let km_uuid = Self::get_key_km_uuid(&tx, key_id)
1709 .context("In load_key_components: Trying to get KM uuid.")?;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001710
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001711 Ok(KeyEntry {
1712 id: key_id,
1713 km_blob,
1714 cert: cert_blob,
1715 cert_chain: cert_chain_blob,
Max Bires8e93d2b2021-01-14 13:17:59 -08001716 km_uuid,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001717 parameters,
1718 metadata,
Janis Danisevskis377d1002021-01-27 19:07:48 -08001719 pure_cert: !has_km_blob,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001720 })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001721 }
1722
Janis Danisevskise92a5e62020-12-02 12:57:41 -08001723 /// Returns a list of KeyDescriptors in the selected domain/namespace.
1724 /// The key descriptors will have the domain, nspace, and alias field set.
1725 /// Domain must be APP or SELINUX, the caller must make sure of that.
1726 pub fn list(&mut self, domain: Domain, namespace: i64) -> Result<Vec<KeyDescriptor>> {
1727 let mut stmt = self
1728 .conn
1729 .prepare(
1730 "SELECT alias FROM persistent.keyentry
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001731 WHERE domain = ? AND namespace = ? AND alias IS NOT NULL AND state = ?;",
Janis Danisevskise92a5e62020-12-02 12:57:41 -08001732 )
1733 .context("In list: Failed to prepare.")?;
1734
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001735 let mut rows = stmt
1736 .query(params![domain.0 as u32, namespace, KeyLifeCycle::Live])
1737 .context("In list: Failed to query.")?;
Janis Danisevskise92a5e62020-12-02 12:57:41 -08001738
1739 let mut descriptors: Vec<KeyDescriptor> = Vec::new();
1740 db_utils::with_rows_extract_all(&mut rows, |row| {
1741 descriptors.push(KeyDescriptor {
1742 domain,
1743 nspace: namespace,
1744 alias: Some(row.get(0).context("Trying to extract alias.")?),
1745 blob: None,
1746 });
1747 Ok(())
1748 })
1749 .context("In list.")?;
1750 Ok(descriptors)
1751 }
1752
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001753 /// Adds a grant to the grant table.
1754 /// Like `load_key_entry` this function loads the access tuple before
1755 /// it uses the callback for a permission check. Upon success,
1756 /// it inserts the `grantee_uid`, `key_id`, and `access_vector` into the
1757 /// grant table. The new row will have a randomized id, which is used as
1758 /// grant id in the namespace field of the resulting KeyDescriptor.
1759 pub fn grant(
1760 &mut self,
1761 key: KeyDescriptor,
1762 caller_uid: u32,
1763 grantee_uid: u32,
1764 access_vector: KeyPermSet,
1765 check_permission: impl FnOnce(&KeyDescriptor, &KeyPermSet) -> Result<()>,
1766 ) -> Result<KeyDescriptor> {
1767 let tx = self
1768 .conn
1769 .transaction_with_behavior(TransactionBehavior::Immediate)
1770 .context("In grant: Failed to initialize transaction.")?;
1771
1772 // Load the key_id and complete the access control tuple.
1773 // We ignore the access vector here because grants cannot be granted.
1774 // The access vector returned here expresses the permissions the
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001775 // grantee has if key.domain == Domain::GRANT. But this vector
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001776 // cannot include the grant permission by design, so there is no way the
1777 // subsequent permission check can pass.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001778 // We could check key.domain == Domain::GRANT and fail early.
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001779 // But even if we load the access tuple by grant here, the permission
1780 // check denies the attempt to create a grant by grant descriptor.
1781 let (key_id, access_key_descriptor, _) =
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001782 Self::load_access_tuple(&tx, key, KeyType::Client, caller_uid).context("In grant")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001783
1784 // Perform access control. It is vital that we return here if the permission
1785 // was denied. So do not touch that '?' at the end of the line.
1786 // This permission check checks if the caller has the grant permission
1787 // for the given key and in addition to all of the permissions
1788 // expressed in `access_vector`.
1789 check_permission(&access_key_descriptor, &access_vector)
1790 .context("In grant: check_permission failed.")?;
1791
1792 let grant_id = if let Some(grant_id) = tx
1793 .query_row(
Janis Danisevskisbf15d732020-12-08 10:35:26 -08001794 "SELECT id FROM persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001795 WHERE keyentryid = ? AND grantee = ?;",
1796 params![key_id, grantee_uid],
1797 |row| row.get(0),
1798 )
1799 .optional()
1800 .context("In grant: Failed get optional existing grant id.")?
1801 {
1802 tx.execute(
Janis Danisevskisbf15d732020-12-08 10:35:26 -08001803 "UPDATE persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001804 SET access_vector = ?
1805 WHERE id = ?;",
1806 params![i32::from(access_vector), grant_id],
1807 )
1808 .context("In grant: Failed to update existing grant.")?;
1809 grant_id
1810 } else {
Joel Galenson845f74b2020-09-09 14:11:55 -07001811 Self::insert_with_retry(|id| {
1812 tx.execute(
Janis Danisevskisbf15d732020-12-08 10:35:26 -08001813 "INSERT INTO persistent.grant (id, grantee, keyentryid, access_vector)
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001814 VALUES (?, ?, ?, ?);",
Joel Galenson845f74b2020-09-09 14:11:55 -07001815 params![id, grantee_uid, key_id, i32::from(access_vector)],
1816 )
1817 })
1818 .context("In grant")?
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001819 };
1820 tx.commit().context("In grant: failed to commit transaction.")?;
1821
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001822 Ok(KeyDescriptor { domain: Domain::GRANT, nspace: grant_id, alias: None, blob: None })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001823 }
1824
1825 /// This function checks permissions like `grant` and `load_key_entry`
1826 /// before removing a grant from the grant table.
1827 pub fn ungrant(
1828 &mut self,
1829 key: KeyDescriptor,
1830 caller_uid: u32,
1831 grantee_uid: u32,
1832 check_permission: impl FnOnce(&KeyDescriptor) -> Result<()>,
1833 ) -> Result<()> {
1834 let tx = self
1835 .conn
1836 .transaction_with_behavior(TransactionBehavior::Immediate)
1837 .context("In ungrant: Failed to initialize transaction.")?;
1838
1839 // Load the key_id and complete the access control tuple.
1840 // We ignore the access vector here because grants cannot be granted.
1841 let (key_id, access_key_descriptor, _) =
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001842 Self::load_access_tuple(&tx, key, KeyType::Client, caller_uid)
1843 .context("In ungrant.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001844
1845 // Perform access control. We must return here if the permission
1846 // was denied. So do not touch the '?' at the end of this line.
1847 check_permission(&access_key_descriptor).context("In grant: check_permission failed.")?;
1848
1849 tx.execute(
Janis Danisevskisbf15d732020-12-08 10:35:26 -08001850 "DELETE FROM persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001851 WHERE keyentryid = ? AND grantee = ?;",
1852 params![key_id, grantee_uid],
1853 )
1854 .context("Failed to delete grant.")?;
1855
1856 tx.commit().context("In ungrant: failed to commit transaction.")?;
1857
1858 Ok(())
1859 }
1860
Joel Galenson845f74b2020-09-09 14:11:55 -07001861 // Generates a random id and passes it to the given function, which will
1862 // try to insert it into a database. If that insertion fails, retry;
1863 // otherwise return the id.
1864 fn insert_with_retry(inserter: impl Fn(i64) -> rusqlite::Result<usize>) -> Result<i64> {
1865 loop {
1866 let newid: i64 = random();
1867 match inserter(newid) {
1868 // If the id already existed, try again.
1869 Err(rusqlite::Error::SqliteFailure(
1870 libsqlite3_sys::Error {
1871 code: libsqlite3_sys::ErrorCode::ConstraintViolation,
1872 extended_code: libsqlite3_sys::SQLITE_CONSTRAINT_UNIQUE,
1873 },
1874 _,
1875 )) => (),
1876 Err(e) => {
1877 return Err(e).context("In insert_with_retry: failed to insert into database.")
1878 }
1879 _ => return Ok(newid),
1880 }
1881 }
1882 }
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00001883
1884 /// Insert or replace the auth token based on the UNIQUE constraint of the auth token table
1885 pub fn insert_auth_token(&mut self, auth_token: &HardwareAuthToken) -> Result<()> {
1886 self.conn
1887 .execute(
1888 "INSERT OR REPLACE INTO perboot.authtoken (challenge, user_id, auth_id,
1889 authenticator_type, timestamp, mac, time_received) VALUES(?, ?, ?, ?, ?, ?, ?);",
1890 params![
1891 auth_token.challenge,
1892 auth_token.userId,
1893 auth_token.authenticatorId,
1894 auth_token.authenticatorType.0 as i32,
1895 auth_token.timestamp.milliSeconds as i64,
1896 auth_token.mac,
1897 MonotonicRawTime::now(),
1898 ],
1899 )
1900 .context("In insert_auth_token: failed to insert auth token into the database")?;
1901 Ok(())
1902 }
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00001903
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08001904 /// Find the newest auth token matching the given predicate.
1905 pub fn find_auth_token_entry<F>(
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00001906 &mut self,
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08001907 p: F,
1908 ) -> Result<Option<(AuthTokenEntry, MonotonicRawTime)>>
1909 where
1910 F: Fn(&AuthTokenEntry) -> bool,
1911 {
1912 self.with_transaction(TransactionBehavior::Deferred, |tx| {
1913 let mut stmt = tx
1914 .prepare("SELECT * from perboot.authtoken ORDER BY time_received DESC;")
1915 .context("Prepare statement failed.")?;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00001916
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08001917 let mut rows = stmt.query(NO_PARAMS).context("Failed to query.")?;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00001918
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08001919 while let Some(row) = rows.next().context("Failed to get next row.")? {
1920 let entry = AuthTokenEntry::new(
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00001921 HardwareAuthToken {
1922 challenge: row.get(1)?,
1923 userId: row.get(2)?,
1924 authenticatorId: row.get(3)?,
1925 authenticatorType: HardwareAuthenticatorType(row.get(4)?),
1926 timestamp: Timestamp { milliSeconds: row.get(5)? },
1927 mac: row.get(6)?,
1928 },
1929 row.get(7)?,
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08001930 );
1931 if p(&entry) {
1932 return Ok(Some((
1933 entry,
1934 Self::get_last_off_body(tx)
1935 .context("In find_auth_token_entry: Trying to get last off body")?,
1936 )));
1937 }
1938 }
1939 Ok(None)
1940 })
1941 .context("In find_auth_token_entry.")
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00001942 }
1943
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08001944 /// Insert last_off_body into the metadata table at the initialization of auth token table
1945 pub fn insert_last_off_body(&self, last_off_body: MonotonicRawTime) -> Result<()> {
1946 self.conn
1947 .execute(
1948 "INSERT OR REPLACE INTO perboot.metadata (key, value) VALUES (?, ?);",
1949 params!["last_off_body", last_off_body],
1950 )
1951 .context("In insert_last_off_body: failed to insert.")?;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00001952 Ok(())
1953 }
1954
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08001955 /// Update last_off_body when on_device_off_body is called
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00001956 pub fn update_last_off_body(&self, last_off_body: MonotonicRawTime) -> Result<()> {
1957 self.conn
1958 .execute(
1959 "UPDATE perboot.metadata SET value = ? WHERE key = ?;",
1960 params![last_off_body, "last_off_body"],
1961 )
1962 .context("In update_last_off_body: failed to update.")?;
1963 Ok(())
1964 }
1965
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08001966 /// Get last_off_body time when finding auth tokens
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00001967 fn get_last_off_body(tx: &Transaction) -> Result<MonotonicRawTime> {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08001968 tx.query_row(
1969 "SELECT value from perboot.metadata WHERE key = ?;",
1970 params!["last_off_body"],
1971 |row| Ok(row.get(0)?),
1972 )
1973 .context("In get_last_off_body: query_row failed.")
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00001974 }
Joel Galenson26f4d012020-07-17 14:57:21 -07001975}
1976
1977#[cfg(test)]
1978mod tests {
1979
1980 use super::*;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001981 use crate::key_parameter::{
1982 Algorithm, BlockMode, Digest, EcCurve, HardwareAuthenticatorType, KeyOrigin, KeyParameter,
1983 KeyParameterValue, KeyPurpose, PaddingMode, SecurityLevel,
1984 };
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001985 use crate::key_perm_set;
1986 use crate::permission::{KeyPerm, KeyPermSet};
Janis Danisevskis2a8330a2021-01-20 15:34:26 -08001987 use keystore2_test_utils::TempDir;
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00001988 use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
1989 HardwareAuthToken::HardwareAuthToken,
1990 HardwareAuthenticatorType::HardwareAuthenticatorType as kmhw_authenticator_type,
Janis Danisevskisc3a496b2021-01-05 10:37:22 -08001991 };
1992 use android_hardware_security_secureclock::aidl::android::hardware::security::secureclock::{
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00001993 Timestamp::Timestamp,
1994 };
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001995 use rusqlite::NO_PARAMS;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00001996 use rusqlite::{Error, TransactionBehavior};
Joel Galenson0891bc12020-07-20 10:37:03 -07001997 use std::cell::RefCell;
Janis Danisevskisaec14592020-11-12 09:41:49 -08001998 use std::sync::atomic::{AtomicU8, Ordering};
1999 use std::sync::Arc;
2000 use std::thread;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002001 use std::time::{Duration, SystemTime};
Joel Galenson0891bc12020-07-20 10:37:03 -07002002
Janis Danisevskis4df44f42020-08-26 14:40:03 -07002003 fn new_test_db() -> Result<KeystoreDB> {
2004 let conn = KeystoreDB::make_connection("file::memory:", "file::memory:")?;
2005
2006 KeystoreDB::init_tables(&conn).context("Failed to initialize tables.")?;
2007 Ok(KeystoreDB { conn })
2008 }
2009
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002010 fn rebind_alias(
2011 db: &mut KeystoreDB,
2012 newid: &KeyIdGuard,
2013 alias: &str,
2014 domain: Domain,
2015 namespace: i64,
2016 ) -> Result<bool> {
2017 db.with_transaction(TransactionBehavior::Immediate, |tx| {
2018 KeystoreDB::rebind_alias(tx, newid, alias, domain, namespace)
2019 })
2020 .context("In rebind_alias.")
2021 }
2022
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002023 #[test]
2024 fn datetime() -> Result<()> {
2025 let conn = Connection::open_in_memory()?;
2026 conn.execute("CREATE TABLE test (ts DATETIME);", NO_PARAMS)?;
2027 let now = SystemTime::now();
2028 let duration = Duration::from_secs(1000);
2029 let then = now.checked_sub(duration).unwrap();
2030 let soon = now.checked_add(duration).unwrap();
2031 conn.execute(
2032 "INSERT INTO test (ts) VALUES (?), (?), (?);",
2033 params![DateTime::try_from(now)?, DateTime::try_from(then)?, DateTime::try_from(soon)?],
2034 )?;
2035 let mut stmt = conn.prepare("SELECT ts FROM test ORDER BY ts ASC;")?;
2036 let mut rows = stmt.query(NO_PARAMS)?;
2037 assert_eq!(DateTime::try_from(then)?, rows.next()?.unwrap().get(0)?);
2038 assert_eq!(DateTime::try_from(now)?, rows.next()?.unwrap().get(0)?);
2039 assert_eq!(DateTime::try_from(soon)?, rows.next()?.unwrap().get(0)?);
2040 assert!(rows.next()?.is_none());
2041 assert!(DateTime::try_from(then)? < DateTime::try_from(now)?);
2042 assert!(DateTime::try_from(then)? < DateTime::try_from(soon)?);
2043 assert!(DateTime::try_from(now)? < DateTime::try_from(soon)?);
2044 Ok(())
2045 }
2046
Joel Galenson0891bc12020-07-20 10:37:03 -07002047 // Ensure that we're using the "injected" random function, not the real one.
2048 #[test]
2049 fn test_mocked_random() {
2050 let rand1 = random();
2051 let rand2 = random();
2052 let rand3 = random();
2053 if rand1 == rand2 {
2054 assert_eq!(rand2 + 1, rand3);
2055 } else {
2056 assert_eq!(rand1 + 1, rand2);
2057 assert_eq!(rand2, rand3);
2058 }
2059 }
Joel Galenson26f4d012020-07-17 14:57:21 -07002060
Joel Galenson26f4d012020-07-17 14:57:21 -07002061 // Test that we have the correct tables.
2062 #[test]
2063 fn test_tables() -> Result<()> {
Janis Danisevskis4df44f42020-08-26 14:40:03 -07002064 let db = new_test_db()?;
Joel Galenson26f4d012020-07-17 14:57:21 -07002065 let tables = db
2066 .conn
Joel Galenson2aab4432020-07-22 15:27:57 -07002067 .prepare("SELECT name from persistent.sqlite_master WHERE type='table' ORDER BY name;")?
Joel Galenson26f4d012020-07-17 14:57:21 -07002068 .query_map(params![], |row| row.get(0))?
2069 .collect::<rusqlite::Result<Vec<String>>>()?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002070 assert_eq!(tables.len(), 5);
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002071 assert_eq!(tables[0], "blobentry");
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002072 assert_eq!(tables[1], "grant");
2073 assert_eq!(tables[2], "keyentry");
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002074 assert_eq!(tables[3], "keymetadata");
2075 assert_eq!(tables[4], "keyparameter");
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002076 let tables = db
2077 .conn
2078 .prepare("SELECT name from perboot.sqlite_master WHERE type='table' ORDER BY name;")?
2079 .query_map(params![], |row| row.get(0))?
2080 .collect::<rusqlite::Result<Vec<String>>>()?;
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002081
2082 assert_eq!(tables.len(), 2);
2083 assert_eq!(tables[0], "authtoken");
2084 assert_eq!(tables[1], "metadata");
Joel Galenson2aab4432020-07-22 15:27:57 -07002085 Ok(())
2086 }
2087
2088 #[test]
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002089 fn test_auth_token_table_invariant() -> Result<()> {
2090 let mut db = new_test_db()?;
2091 let auth_token1 = HardwareAuthToken {
2092 challenge: i64::MAX,
2093 userId: 200,
2094 authenticatorId: 200,
2095 authenticatorType: kmhw_authenticator_type(kmhw_authenticator_type::PASSWORD.0),
2096 timestamp: Timestamp { milliSeconds: 500 },
2097 mac: String::from("mac").into_bytes(),
2098 };
2099 db.insert_auth_token(&auth_token1)?;
2100 let auth_tokens_returned = get_auth_tokens(&mut db)?;
2101 assert_eq!(auth_tokens_returned.len(), 1);
2102
2103 // insert another auth token with the same values for the columns in the UNIQUE constraint
2104 // of the auth token table and different value for timestamp
2105 let auth_token2 = HardwareAuthToken {
2106 challenge: i64::MAX,
2107 userId: 200,
2108 authenticatorId: 200,
2109 authenticatorType: kmhw_authenticator_type(kmhw_authenticator_type::PASSWORD.0),
2110 timestamp: Timestamp { milliSeconds: 600 },
2111 mac: String::from("mac").into_bytes(),
2112 };
2113
2114 db.insert_auth_token(&auth_token2)?;
2115 let mut auth_tokens_returned = get_auth_tokens(&mut db)?;
2116 assert_eq!(auth_tokens_returned.len(), 1);
2117
2118 if let Some(auth_token) = auth_tokens_returned.pop() {
2119 assert_eq!(auth_token.auth_token.timestamp.milliSeconds, 600);
2120 }
2121
2122 // insert another auth token with the different values for the columns in the UNIQUE
2123 // constraint of the auth token table
2124 let auth_token3 = HardwareAuthToken {
2125 challenge: i64::MAX,
2126 userId: 201,
2127 authenticatorId: 200,
2128 authenticatorType: kmhw_authenticator_type(kmhw_authenticator_type::PASSWORD.0),
2129 timestamp: Timestamp { milliSeconds: 600 },
2130 mac: String::from("mac").into_bytes(),
2131 };
2132
2133 db.insert_auth_token(&auth_token3)?;
2134 let auth_tokens_returned = get_auth_tokens(&mut db)?;
2135 assert_eq!(auth_tokens_returned.len(), 2);
2136
2137 Ok(())
2138 }
2139
2140 // utility function for test_auth_token_table_invariant()
2141 fn get_auth_tokens(db: &mut KeystoreDB) -> Result<Vec<AuthTokenEntry>> {
2142 let mut stmt = db.conn.prepare("SELECT * from perboot.authtoken;")?;
2143
2144 let auth_token_entries: Vec<AuthTokenEntry> = stmt
2145 .query_map(NO_PARAMS, |row| {
2146 Ok(AuthTokenEntry::new(
2147 HardwareAuthToken {
2148 challenge: row.get(1)?,
2149 userId: row.get(2)?,
2150 authenticatorId: row.get(3)?,
2151 authenticatorType: HardwareAuthenticatorType(row.get(4)?),
2152 timestamp: Timestamp { milliSeconds: row.get(5)? },
2153 mac: row.get(6)?,
2154 },
2155 row.get(7)?,
2156 ))
2157 })?
2158 .collect::<Result<Vec<AuthTokenEntry>, Error>>()?;
2159 Ok(auth_token_entries)
2160 }
2161
2162 #[test]
Joel Galenson2aab4432020-07-22 15:27:57 -07002163 fn test_persistence_for_files() -> Result<()> {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002164 let temp_dir = TempDir::new("persistent_db_test")?;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002165 let mut db = KeystoreDB::new(temp_dir.path())?;
Joel Galenson2aab4432020-07-22 15:27:57 -07002166
Max Bires8e93d2b2021-01-14 13:17:59 -08002167 db.create_key_entry(Domain::APP, 100, &KEYSTORE_UUID)?;
Joel Galenson2aab4432020-07-22 15:27:57 -07002168 let entries = get_keyentry(&db)?;
2169 assert_eq!(entries.len(), 1);
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002170
2171 let db = KeystoreDB::new(temp_dir.path())?;
Joel Galenson2aab4432020-07-22 15:27:57 -07002172
2173 let entries_new = get_keyentry(&db)?;
2174 assert_eq!(entries, entries_new);
2175 Ok(())
2176 }
2177
2178 #[test]
Joel Galenson0891bc12020-07-20 10:37:03 -07002179 fn test_create_key_entry() -> Result<()> {
Max Bires8e93d2b2021-01-14 13:17:59 -08002180 fn extractor(ke: &KeyEntryRow) -> (Domain, i64, Option<&str>, Uuid) {
2181 (ke.domain.unwrap(), ke.namespace.unwrap(), ke.alias.as_deref(), ke.km_uuid.unwrap())
Joel Galenson0891bc12020-07-20 10:37:03 -07002182 }
2183
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002184 let mut db = new_test_db()?;
Joel Galenson0891bc12020-07-20 10:37:03 -07002185
Max Bires8e93d2b2021-01-14 13:17:59 -08002186 db.create_key_entry(Domain::APP, 100, &KEYSTORE_UUID)?;
2187 db.create_key_entry(Domain::SELINUX, 101, &KEYSTORE_UUID)?;
Joel Galenson0891bc12020-07-20 10:37:03 -07002188
2189 let entries = get_keyentry(&db)?;
2190 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08002191 assert_eq!(extractor(&entries[0]), (Domain::APP, 100, None, KEYSTORE_UUID));
2192 assert_eq!(extractor(&entries[1]), (Domain::SELINUX, 101, None, KEYSTORE_UUID));
Joel Galenson0891bc12020-07-20 10:37:03 -07002193
2194 // Test that we must pass in a valid Domain.
2195 check_result_is_error_containing_string(
Max Bires8e93d2b2021-01-14 13:17:59 -08002196 db.create_key_entry(Domain::GRANT, 102, &KEYSTORE_UUID),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002197 "Domain Domain(1) must be either App or SELinux.",
Joel Galenson0891bc12020-07-20 10:37:03 -07002198 );
2199 check_result_is_error_containing_string(
Max Bires8e93d2b2021-01-14 13:17:59 -08002200 db.create_key_entry(Domain::BLOB, 103, &KEYSTORE_UUID),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002201 "Domain Domain(3) must be either App or SELinux.",
Joel Galenson0891bc12020-07-20 10:37:03 -07002202 );
2203 check_result_is_error_containing_string(
Max Bires8e93d2b2021-01-14 13:17:59 -08002204 db.create_key_entry(Domain::KEY_ID, 104, &KEYSTORE_UUID),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002205 "Domain Domain(4) must be either App or SELinux.",
Joel Galenson0891bc12020-07-20 10:37:03 -07002206 );
2207
2208 Ok(())
2209 }
2210
Joel Galenson33c04ad2020-08-03 11:04:38 -07002211 #[test]
2212 fn test_rebind_alias() -> Result<()> {
Max Bires8e93d2b2021-01-14 13:17:59 -08002213 fn extractor(
2214 ke: &KeyEntryRow,
2215 ) -> (Option<Domain>, Option<i64>, Option<&str>, Option<Uuid>) {
2216 (ke.domain, ke.namespace, ke.alias.as_deref(), ke.km_uuid)
Joel Galenson33c04ad2020-08-03 11:04:38 -07002217 }
2218
Janis Danisevskis4df44f42020-08-26 14:40:03 -07002219 let mut db = new_test_db()?;
Max Bires8e93d2b2021-01-14 13:17:59 -08002220 db.create_key_entry(Domain::APP, 42, &KEYSTORE_UUID)?;
2221 db.create_key_entry(Domain::APP, 42, &KEYSTORE_UUID)?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07002222 let entries = get_keyentry(&db)?;
2223 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08002224 assert_eq!(
2225 extractor(&entries[0]),
2226 (Some(Domain::APP), Some(42), None, Some(KEYSTORE_UUID))
2227 );
2228 assert_eq!(
2229 extractor(&entries[1]),
2230 (Some(Domain::APP), Some(42), None, Some(KEYSTORE_UUID))
2231 );
Joel Galenson33c04ad2020-08-03 11:04:38 -07002232
2233 // Test that the first call to rebind_alias sets the alias.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002234 rebind_alias(&mut db, &KEY_ID_LOCK.get(entries[0].id), "foo", Domain::APP, 42)?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07002235 let entries = get_keyentry(&db)?;
2236 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08002237 assert_eq!(
2238 extractor(&entries[0]),
2239 (Some(Domain::APP), Some(42), Some("foo"), Some(KEYSTORE_UUID))
2240 );
2241 assert_eq!(
2242 extractor(&entries[1]),
2243 (Some(Domain::APP), Some(42), None, Some(KEYSTORE_UUID))
2244 );
Joel Galenson33c04ad2020-08-03 11:04:38 -07002245
2246 // Test that the second call to rebind_alias also empties the old one.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002247 rebind_alias(&mut db, &KEY_ID_LOCK.get(entries[1].id), "foo", Domain::APP, 42)?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07002248 let entries = get_keyentry(&db)?;
2249 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08002250 assert_eq!(extractor(&entries[0]), (None, None, None, Some(KEYSTORE_UUID)));
2251 assert_eq!(
2252 extractor(&entries[1]),
2253 (Some(Domain::APP), Some(42), Some("foo"), Some(KEYSTORE_UUID))
2254 );
Joel Galenson33c04ad2020-08-03 11:04:38 -07002255
2256 // Test that we must pass in a valid Domain.
2257 check_result_is_error_containing_string(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002258 rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::GRANT, 42),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002259 "Domain Domain(1) must be either App or SELinux.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07002260 );
2261 check_result_is_error_containing_string(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002262 rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::BLOB, 42),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002263 "Domain Domain(3) must be either App or SELinux.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07002264 );
2265 check_result_is_error_containing_string(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002266 rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::KEY_ID, 42),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002267 "Domain Domain(4) must be either App or SELinux.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07002268 );
2269
2270 // Test that we correctly handle setting an alias for something that does not exist.
2271 check_result_is_error_containing_string(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002272 rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::SELINUX, 42),
Joel Galenson33c04ad2020-08-03 11:04:38 -07002273 "Expected to update a single entry but instead updated 0",
2274 );
2275 // Test that we correctly abort the transaction in this case.
2276 let entries = get_keyentry(&db)?;
2277 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08002278 assert_eq!(extractor(&entries[0]), (None, None, None, Some(KEYSTORE_UUID)));
2279 assert_eq!(
2280 extractor(&entries[1]),
2281 (Some(Domain::APP), Some(42), Some("foo"), Some(KEYSTORE_UUID))
2282 );
Joel Galenson33c04ad2020-08-03 11:04:38 -07002283
2284 Ok(())
2285 }
2286
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002287 #[test]
2288 fn test_grant_ungrant() -> Result<()> {
2289 const CALLER_UID: u32 = 15;
2290 const GRANTEE_UID: u32 = 12;
2291 const SELINUX_NAMESPACE: i64 = 7;
2292
2293 let mut db = new_test_db()?;
2294 db.conn.execute(
Max Bires8e93d2b2021-01-14 13:17:59 -08002295 "INSERT INTO persistent.keyentry (id, key_type, domain, namespace, alias, state, km_uuid)
2296 VALUES (1, 0, 0, 15, 'key', 1, ?), (2, 0, 2, 7, 'yek', 1, ?);",
2297 params![KEYSTORE_UUID, KEYSTORE_UUID],
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002298 )?;
2299 let app_key = KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002300 domain: super::Domain::APP,
2301 nspace: 0,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002302 alias: Some("key".to_string()),
2303 blob: None,
2304 };
2305 const PVEC1: KeyPermSet = key_perm_set![KeyPerm::use_(), KeyPerm::get_info()];
2306 const PVEC2: KeyPermSet = key_perm_set![KeyPerm::use_()];
2307
2308 // Reset totally predictable random number generator in case we
2309 // are not the first test running on this thread.
2310 reset_random();
2311 let next_random = 0i64;
2312
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002313 let app_granted_key = db
2314 .grant(app_key.clone(), CALLER_UID, GRANTEE_UID, PVEC1, |k, a| {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002315 assert_eq!(*a, PVEC1);
2316 assert_eq!(
2317 *k,
2318 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002319 domain: super::Domain::APP,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002320 // namespace must be set to the caller_uid.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002321 nspace: CALLER_UID as i64,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002322 alias: Some("key".to_string()),
2323 blob: None,
2324 }
2325 );
2326 Ok(())
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002327 })
2328 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002329
2330 assert_eq!(
2331 app_granted_key,
2332 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002333 domain: super::Domain::GRANT,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002334 // The grantid is next_random due to the mock random number generator.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002335 nspace: next_random,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002336 alias: None,
2337 blob: None,
2338 }
2339 );
2340
2341 let selinux_key = KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002342 domain: super::Domain::SELINUX,
2343 nspace: SELINUX_NAMESPACE,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002344 alias: Some("yek".to_string()),
2345 blob: None,
2346 };
2347
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002348 let selinux_granted_key = db
2349 .grant(selinux_key.clone(), CALLER_UID, 12, PVEC1, |k, a| {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002350 assert_eq!(*a, PVEC1);
2351 assert_eq!(
2352 *k,
2353 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002354 domain: super::Domain::SELINUX,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002355 // namespace must be the supplied SELinux
2356 // namespace.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002357 nspace: SELINUX_NAMESPACE,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002358 alias: Some("yek".to_string()),
2359 blob: None,
2360 }
2361 );
2362 Ok(())
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002363 })
2364 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002365
2366 assert_eq!(
2367 selinux_granted_key,
2368 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002369 domain: super::Domain::GRANT,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002370 // The grantid is next_random + 1 due to the mock random number generator.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002371 nspace: next_random + 1,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002372 alias: None,
2373 blob: None,
2374 }
2375 );
2376
2377 // This should update the existing grant with PVEC2.
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002378 let selinux_granted_key = db
2379 .grant(selinux_key.clone(), CALLER_UID, 12, PVEC2, |k, a| {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002380 assert_eq!(*a, PVEC2);
2381 assert_eq!(
2382 *k,
2383 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002384 domain: super::Domain::SELINUX,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002385 // namespace must be the supplied SELinux
2386 // namespace.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002387 nspace: SELINUX_NAMESPACE,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002388 alias: Some("yek".to_string()),
2389 blob: None,
2390 }
2391 );
2392 Ok(())
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002393 })
2394 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002395
2396 assert_eq!(
2397 selinux_granted_key,
2398 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002399 domain: super::Domain::GRANT,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002400 // Same grant id as before. The entry was only updated.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002401 nspace: next_random + 1,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002402 alias: None,
2403 blob: None,
2404 }
2405 );
2406
2407 {
2408 // Limiting scope of stmt, because it borrows db.
2409 let mut stmt = db
2410 .conn
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002411 .prepare("SELECT id, grantee, keyentryid, access_vector FROM persistent.grant;")?;
Janis Danisevskisee10b5f2020-09-22 16:42:35 -07002412 let mut rows =
2413 stmt.query_map::<(i64, u32, i64, KeyPermSet), _, _>(NO_PARAMS, |row| {
2414 Ok((
2415 row.get(0)?,
2416 row.get(1)?,
2417 row.get(2)?,
2418 KeyPermSet::from(row.get::<_, i32>(3)?),
2419 ))
2420 })?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002421
2422 let r = rows.next().unwrap().unwrap();
Janis Danisevskisee10b5f2020-09-22 16:42:35 -07002423 assert_eq!(r, (next_random, GRANTEE_UID, 1, PVEC1));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002424 let r = rows.next().unwrap().unwrap();
Janis Danisevskisee10b5f2020-09-22 16:42:35 -07002425 assert_eq!(r, (next_random + 1, GRANTEE_UID, 2, PVEC2));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002426 assert!(rows.next().is_none());
2427 }
2428
2429 debug_dump_keyentry_table(&mut db)?;
2430 println!("app_key {:?}", app_key);
2431 println!("selinux_key {:?}", selinux_key);
2432
2433 db.ungrant(app_key, CALLER_UID, GRANTEE_UID, |_| Ok(()))?;
2434 db.ungrant(selinux_key, CALLER_UID, GRANTEE_UID, |_| Ok(()))?;
2435
2436 Ok(())
2437 }
2438
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002439 static TEST_KEY_BLOB: &[u8] = b"my test blob";
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002440 static TEST_CERT_BLOB: &[u8] = b"my test cert";
2441 static TEST_CERT_CHAIN_BLOB: &[u8] = b"my test cert_chain";
2442
2443 #[test]
Janis Danisevskis377d1002021-01-27 19:07:48 -08002444 fn test_set_blob() -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002445 let key_id = KEY_ID_LOCK.get(3000);
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002446 let mut db = new_test_db()?;
Janis Danisevskis377d1002021-01-27 19:07:48 -08002447 db.set_blob(&key_id, SubComponentType::KEY_BLOB, Some(TEST_KEY_BLOB))?;
2448 db.set_blob(&key_id, SubComponentType::CERT, Some(TEST_CERT_BLOB))?;
2449 db.set_blob(&key_id, SubComponentType::CERT_CHAIN, Some(TEST_CERT_CHAIN_BLOB))?;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002450 drop(key_id);
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002451
2452 let mut stmt = db.conn.prepare(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002453 "SELECT subcomponent_type, keyentryid, blob FROM persistent.blobentry
2454 ORDER BY subcomponent_type ASC;",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002455 )?;
2456 let mut rows = stmt
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002457 .query_map::<(SubComponentType, i64, Vec<u8>), _, _>(NO_PARAMS, |row| {
2458 Ok((row.get(0)?, row.get(1)?, row.get(2)?))
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002459 })?;
2460 let r = rows.next().unwrap().unwrap();
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002461 assert_eq!(r, (SubComponentType::KEY_BLOB, 3000, TEST_KEY_BLOB.to_vec()));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002462 let r = rows.next().unwrap().unwrap();
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002463 assert_eq!(r, (SubComponentType::CERT, 3000, TEST_CERT_BLOB.to_vec()));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002464 let r = rows.next().unwrap().unwrap();
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002465 assert_eq!(r, (SubComponentType::CERT_CHAIN, 3000, TEST_CERT_CHAIN_BLOB.to_vec()));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002466
2467 Ok(())
2468 }
2469
2470 static TEST_ALIAS: &str = "my super duper key";
2471
2472 #[test]
2473 fn test_insert_and_load_full_keyentry_domain_app() -> Result<()> {
2474 let mut db = new_test_db()?;
Qi Wub9433b52020-12-01 14:52:46 +08002475 let key_id = make_test_key_entry(&mut db, Domain::APP, 1, TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08002476 .context("test_insert_and_load_full_keyentry_domain_app")?
2477 .0;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002478 let (_key_guard, key_entry) = db
2479 .load_key_entry(
2480 KeyDescriptor {
2481 domain: Domain::APP,
2482 nspace: 0,
2483 alias: Some(TEST_ALIAS.to_string()),
2484 blob: None,
2485 },
2486 KeyType::Client,
2487 KeyEntryLoadBits::BOTH,
2488 1,
2489 |_k, _av| Ok(()),
2490 )
2491 .unwrap();
Qi Wub9433b52020-12-01 14:52:46 +08002492 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002493
2494 db.unbind_key(
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002495 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002496 domain: Domain::APP,
2497 nspace: 0,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002498 alias: Some(TEST_ALIAS.to_string()),
2499 blob: None,
2500 },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002501 KeyType::Client,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002502 1,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002503 |_, _| Ok(()),
2504 )
2505 .unwrap();
2506
2507 assert_eq!(
2508 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
2509 db.load_key_entry(
2510 KeyDescriptor {
2511 domain: Domain::APP,
2512 nspace: 0,
2513 alias: Some(TEST_ALIAS.to_string()),
2514 blob: None,
2515 },
2516 KeyType::Client,
2517 KeyEntryLoadBits::NONE,
2518 1,
2519 |_k, _av| Ok(()),
2520 )
2521 .unwrap_err()
2522 .root_cause()
2523 .downcast_ref::<KsError>()
2524 );
2525
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002526 Ok(())
2527 }
2528
2529 #[test]
Janis Danisevskis377d1002021-01-27 19:07:48 -08002530 fn test_insert_and_load_certificate_entry_domain_app() -> Result<()> {
2531 let mut db = new_test_db()?;
2532
2533 db.store_new_certificate(
2534 KeyDescriptor {
2535 domain: Domain::APP,
2536 nspace: 1,
2537 alias: Some(TEST_ALIAS.to_string()),
2538 blob: None,
2539 },
2540 TEST_CERT_BLOB,
Max Bires8e93d2b2021-01-14 13:17:59 -08002541 &KEYSTORE_UUID,
Janis Danisevskis377d1002021-01-27 19:07:48 -08002542 )
2543 .expect("Trying to insert cert.");
2544
2545 let (_key_guard, mut key_entry) = db
2546 .load_key_entry(
2547 KeyDescriptor {
2548 domain: Domain::APP,
2549 nspace: 1,
2550 alias: Some(TEST_ALIAS.to_string()),
2551 blob: None,
2552 },
2553 KeyType::Client,
2554 KeyEntryLoadBits::PUBLIC,
2555 1,
2556 |_k, _av| Ok(()),
2557 )
2558 .expect("Trying to read certificate entry.");
2559
2560 assert!(key_entry.pure_cert());
2561 assert!(key_entry.cert().is_none());
2562 assert_eq!(key_entry.take_cert_chain(), Some(TEST_CERT_BLOB.to_vec()));
2563
2564 db.unbind_key(
2565 KeyDescriptor {
2566 domain: Domain::APP,
2567 nspace: 1,
2568 alias: Some(TEST_ALIAS.to_string()),
2569 blob: None,
2570 },
2571 KeyType::Client,
2572 1,
2573 |_, _| Ok(()),
2574 )
2575 .unwrap();
2576
2577 assert_eq!(
2578 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
2579 db.load_key_entry(
2580 KeyDescriptor {
2581 domain: Domain::APP,
2582 nspace: 1,
2583 alias: Some(TEST_ALIAS.to_string()),
2584 blob: None,
2585 },
2586 KeyType::Client,
2587 KeyEntryLoadBits::NONE,
2588 1,
2589 |_k, _av| Ok(()),
2590 )
2591 .unwrap_err()
2592 .root_cause()
2593 .downcast_ref::<KsError>()
2594 );
2595
2596 Ok(())
2597 }
2598
2599 #[test]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002600 fn test_insert_and_load_full_keyentry_domain_selinux() -> Result<()> {
2601 let mut db = new_test_db()?;
Qi Wub9433b52020-12-01 14:52:46 +08002602 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08002603 .context("test_insert_and_load_full_keyentry_domain_selinux")?
2604 .0;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002605 let (_key_guard, key_entry) = db
2606 .load_key_entry(
2607 KeyDescriptor {
2608 domain: Domain::SELINUX,
2609 nspace: 1,
2610 alias: Some(TEST_ALIAS.to_string()),
2611 blob: None,
2612 },
2613 KeyType::Client,
2614 KeyEntryLoadBits::BOTH,
2615 1,
2616 |_k, _av| Ok(()),
2617 )
2618 .unwrap();
Qi Wub9433b52020-12-01 14:52:46 +08002619 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002620
2621 db.unbind_key(
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002622 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002623 domain: Domain::SELINUX,
2624 nspace: 1,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002625 alias: Some(TEST_ALIAS.to_string()),
2626 blob: None,
2627 },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002628 KeyType::Client,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002629 1,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002630 |_, _| Ok(()),
2631 )
2632 .unwrap();
2633
2634 assert_eq!(
2635 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
2636 db.load_key_entry(
2637 KeyDescriptor {
2638 domain: Domain::SELINUX,
2639 nspace: 1,
2640 alias: Some(TEST_ALIAS.to_string()),
2641 blob: None,
2642 },
2643 KeyType::Client,
2644 KeyEntryLoadBits::NONE,
2645 1,
2646 |_k, _av| Ok(()),
2647 )
2648 .unwrap_err()
2649 .root_cause()
2650 .downcast_ref::<KsError>()
2651 );
2652
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002653 Ok(())
2654 }
2655
2656 #[test]
2657 fn test_insert_and_load_full_keyentry_domain_key_id() -> Result<()> {
2658 let mut db = new_test_db()?;
Qi Wub9433b52020-12-01 14:52:46 +08002659 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08002660 .context("test_insert_and_load_full_keyentry_domain_key_id")?
2661 .0;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002662 let (_, key_entry) = db
2663 .load_key_entry(
2664 KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
2665 KeyType::Client,
2666 KeyEntryLoadBits::BOTH,
2667 1,
2668 |_k, _av| Ok(()),
2669 )
2670 .unwrap();
2671
Qi Wub9433b52020-12-01 14:52:46 +08002672 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002673
2674 db.unbind_key(
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002675 KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002676 KeyType::Client,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002677 1,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002678 |_, _| Ok(()),
2679 )
2680 .unwrap();
2681
2682 assert_eq!(
2683 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
2684 db.load_key_entry(
2685 KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
2686 KeyType::Client,
2687 KeyEntryLoadBits::NONE,
2688 1,
2689 |_k, _av| Ok(()),
2690 )
2691 .unwrap_err()
2692 .root_cause()
2693 .downcast_ref::<KsError>()
2694 );
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002695
2696 Ok(())
2697 }
2698
2699 #[test]
Qi Wub9433b52020-12-01 14:52:46 +08002700 fn test_check_and_update_key_usage_count_with_limited_use_key() -> Result<()> {
2701 let mut db = new_test_db()?;
2702 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, Some(123))
2703 .context("test_check_and_update_key_usage_count_with_limited_use_key")?
2704 .0;
2705 // Update the usage count of the limited use key.
2706 db.check_and_update_key_usage_count(key_id)?;
2707
2708 let (_key_guard, key_entry) = db.load_key_entry(
2709 KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
2710 KeyType::Client,
2711 KeyEntryLoadBits::BOTH,
2712 1,
2713 |_k, _av| Ok(()),
2714 )?;
2715
2716 // The usage count is decremented now.
2717 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, Some(122)));
2718
2719 Ok(())
2720 }
2721
2722 #[test]
2723 fn test_check_and_update_key_usage_count_with_exhausted_limited_use_key() -> Result<()> {
2724 let mut db = new_test_db()?;
2725 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, Some(1))
2726 .context("test_check_and_update_key_usage_count_with_exhausted_limited_use_key")?
2727 .0;
2728 // Update the usage count of the limited use key.
2729 db.check_and_update_key_usage_count(key_id).expect(concat!(
2730 "In test_check_and_update_key_usage_count_with_exhausted_limited_use_key: ",
2731 "This should succeed."
2732 ));
2733
2734 // Try to update the exhausted limited use key.
2735 let e = db.check_and_update_key_usage_count(key_id).expect_err(concat!(
2736 "In test_check_and_update_key_usage_count_with_exhausted_limited_use_key: ",
2737 "This should fail."
2738 ));
2739 assert_eq!(
2740 &KsError::Km(ErrorCode::INVALID_KEY_BLOB),
2741 e.root_cause().downcast_ref::<KsError>().unwrap()
2742 );
2743
2744 Ok(())
2745 }
2746
2747 #[test]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002748 fn test_insert_and_load_full_keyentry_from_grant() -> Result<()> {
2749 let mut db = new_test_db()?;
Qi Wub9433b52020-12-01 14:52:46 +08002750 let key_id = make_test_key_entry(&mut db, Domain::APP, 1, TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08002751 .context("test_insert_and_load_full_keyentry_from_grant")?
2752 .0;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002753
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002754 let granted_key = db
2755 .grant(
2756 KeyDescriptor {
2757 domain: Domain::APP,
2758 nspace: 0,
2759 alias: Some(TEST_ALIAS.to_string()),
2760 blob: None,
2761 },
2762 1,
2763 2,
2764 key_perm_set![KeyPerm::use_()],
2765 |_k, _av| Ok(()),
2766 )
2767 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002768
2769 debug_dump_grant_table(&mut db)?;
2770
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002771 let (_key_guard, key_entry) = db
2772 .load_key_entry(
2773 granted_key.clone(),
2774 KeyType::Client,
2775 KeyEntryLoadBits::BOTH,
2776 2,
2777 |k, av| {
2778 assert_eq!(Domain::GRANT, k.domain);
2779 assert!(av.unwrap().includes(KeyPerm::use_()));
2780 Ok(())
2781 },
2782 )
2783 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002784
Qi Wub9433b52020-12-01 14:52:46 +08002785 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002786
2787 db.unbind_key(granted_key.clone(), KeyType::Client, 2, |_, _| Ok(())).unwrap();
2788
2789 assert_eq!(
2790 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
2791 db.load_key_entry(
2792 granted_key,
2793 KeyType::Client,
2794 KeyEntryLoadBits::NONE,
2795 2,
2796 |_k, _av| Ok(()),
2797 )
2798 .unwrap_err()
2799 .root_cause()
2800 .downcast_ref::<KsError>()
2801 );
2802
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002803 Ok(())
2804 }
2805
Janis Danisevskis45760022021-01-19 16:34:10 -08002806 // This test attempts to load a key by key id while the caller is not the owner
2807 // but a grant exists for the given key and the caller.
2808 #[test]
2809 fn test_insert_and_load_full_keyentry_from_grant_by_key_id() -> Result<()> {
2810 let mut db = new_test_db()?;
2811 const OWNER_UID: u32 = 1u32;
2812 const GRANTEE_UID: u32 = 2u32;
2813 const SOMEONE_ELSE_UID: u32 = 3u32;
2814 let key_id = make_test_key_entry(&mut db, Domain::APP, OWNER_UID as i64, TEST_ALIAS, None)
2815 .context("test_insert_and_load_full_keyentry_from_grant_by_key_id")?
2816 .0;
2817
2818 db.grant(
2819 KeyDescriptor {
2820 domain: Domain::APP,
2821 nspace: 0,
2822 alias: Some(TEST_ALIAS.to_string()),
2823 blob: None,
2824 },
2825 OWNER_UID,
2826 GRANTEE_UID,
2827 key_perm_set![KeyPerm::use_()],
2828 |_k, _av| Ok(()),
2829 )
2830 .unwrap();
2831
2832 debug_dump_grant_table(&mut db)?;
2833
2834 let id_descriptor =
2835 KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, ..Default::default() };
2836
2837 let (_, key_entry) = db
2838 .load_key_entry(
2839 id_descriptor.clone(),
2840 KeyType::Client,
2841 KeyEntryLoadBits::BOTH,
2842 GRANTEE_UID,
2843 |k, av| {
2844 assert_eq!(Domain::APP, k.domain);
2845 assert_eq!(OWNER_UID as i64, k.nspace);
2846 assert!(av.unwrap().includes(KeyPerm::use_()));
2847 Ok(())
2848 },
2849 )
2850 .unwrap();
2851
2852 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
2853
2854 let (_, key_entry) = db
2855 .load_key_entry(
2856 id_descriptor.clone(),
2857 KeyType::Client,
2858 KeyEntryLoadBits::BOTH,
2859 SOMEONE_ELSE_UID,
2860 |k, av| {
2861 assert_eq!(Domain::APP, k.domain);
2862 assert_eq!(OWNER_UID as i64, k.nspace);
2863 assert!(av.is_none());
2864 Ok(())
2865 },
2866 )
2867 .unwrap();
2868
2869 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
2870
2871 db.unbind_key(id_descriptor.clone(), KeyType::Client, OWNER_UID, |_, _| Ok(())).unwrap();
2872
2873 assert_eq!(
2874 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
2875 db.load_key_entry(
2876 id_descriptor,
2877 KeyType::Client,
2878 KeyEntryLoadBits::NONE,
2879 GRANTEE_UID,
2880 |_k, _av| Ok(()),
2881 )
2882 .unwrap_err()
2883 .root_cause()
2884 .downcast_ref::<KsError>()
2885 );
2886
2887 Ok(())
2888 }
2889
Janis Danisevskisaec14592020-11-12 09:41:49 -08002890 static KEY_LOCK_TEST_ALIAS: &str = "my super duper locked key";
2891
Janis Danisevskisaec14592020-11-12 09:41:49 -08002892 #[test]
2893 fn test_insert_and_load_full_keyentry_domain_app_concurrently() -> Result<()> {
2894 let handle = {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002895 let temp_dir = Arc::new(TempDir::new("id_lock_test")?);
2896 let temp_dir_clone = temp_dir.clone();
2897 let mut db = KeystoreDB::new(temp_dir.path())?;
Qi Wub9433b52020-12-01 14:52:46 +08002898 let key_id = make_test_key_entry(&mut db, Domain::APP, 33, KEY_LOCK_TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08002899 .context("test_insert_and_load_full_keyentry_domain_app")?
2900 .0;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002901 let (_key_guard, key_entry) = db
2902 .load_key_entry(
2903 KeyDescriptor {
2904 domain: Domain::APP,
2905 nspace: 0,
2906 alias: Some(KEY_LOCK_TEST_ALIAS.to_string()),
2907 blob: None,
2908 },
2909 KeyType::Client,
2910 KeyEntryLoadBits::BOTH,
2911 33,
2912 |_k, _av| Ok(()),
2913 )
2914 .unwrap();
Qi Wub9433b52020-12-01 14:52:46 +08002915 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskisaec14592020-11-12 09:41:49 -08002916 let state = Arc::new(AtomicU8::new(1));
2917 let state2 = state.clone();
2918
2919 // Spawning a second thread that attempts to acquire the key id lock
2920 // for the same key as the primary thread. The primary thread then
2921 // waits, thereby forcing the secondary thread into the second stage
2922 // of acquiring the lock (see KEY ID LOCK 2/2 above).
2923 // The test succeeds if the secondary thread observes the transition
2924 // of `state` from 1 to 2, despite having a whole second to overtake
2925 // the primary thread.
2926 let handle = thread::spawn(move || {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002927 let temp_dir = temp_dir_clone;
2928 let mut db = KeystoreDB::new(temp_dir.path()).unwrap();
Janis Danisevskisaec14592020-11-12 09:41:49 -08002929 assert!(db
2930 .load_key_entry(
2931 KeyDescriptor {
2932 domain: Domain::APP,
2933 nspace: 0,
2934 alias: Some(KEY_LOCK_TEST_ALIAS.to_string()),
2935 blob: None,
2936 },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002937 KeyType::Client,
Janis Danisevskisaec14592020-11-12 09:41:49 -08002938 KeyEntryLoadBits::BOTH,
2939 33,
2940 |_k, _av| Ok(()),
2941 )
2942 .is_ok());
2943 // We should only see a 2 here because we can only return
2944 // from load_key_entry when the `_key_guard` expires,
2945 // which happens at the end of the scope.
2946 assert_eq!(2, state2.load(Ordering::Relaxed));
2947 });
2948
2949 thread::sleep(std::time::Duration::from_millis(1000));
2950
2951 assert_eq!(Ok(1), state.compare_exchange(1, 2, Ordering::Relaxed, Ordering::Relaxed));
2952
2953 // Return the handle from this scope so we can join with the
2954 // secondary thread after the key id lock has expired.
2955 handle
2956 // This is where the `_key_guard` goes out of scope,
2957 // which is the reason for concurrent load_key_entry on the same key
2958 // to unblock.
2959 };
2960 // Join with the secondary thread and unwrap, to propagate failing asserts to the
2961 // main test thread. We will not see failing asserts in secondary threads otherwise.
2962 handle.join().unwrap();
2963 Ok(())
2964 }
2965
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002966 #[test]
2967 fn list() -> Result<()> {
2968 let temp_dir = TempDir::new("list_test")?;
2969 let mut db = KeystoreDB::new(temp_dir.path())?;
2970 static LIST_O_ENTRIES: &[(Domain, i64, &str)] = &[
2971 (Domain::APP, 1, "test1"),
2972 (Domain::APP, 1, "test2"),
2973 (Domain::APP, 1, "test3"),
2974 (Domain::APP, 1, "test4"),
2975 (Domain::APP, 1, "test5"),
2976 (Domain::APP, 1, "test6"),
2977 (Domain::APP, 1, "test7"),
2978 (Domain::APP, 2, "test1"),
2979 (Domain::APP, 2, "test2"),
2980 (Domain::APP, 2, "test3"),
2981 (Domain::APP, 2, "test4"),
2982 (Domain::APP, 2, "test5"),
2983 (Domain::APP, 2, "test6"),
2984 (Domain::APP, 2, "test8"),
2985 (Domain::SELINUX, 100, "test1"),
2986 (Domain::SELINUX, 100, "test2"),
2987 (Domain::SELINUX, 100, "test3"),
2988 (Domain::SELINUX, 100, "test4"),
2989 (Domain::SELINUX, 100, "test5"),
2990 (Domain::SELINUX, 100, "test6"),
2991 (Domain::SELINUX, 100, "test9"),
2992 ];
2993
2994 let list_o_keys: Vec<(i64, i64)> = LIST_O_ENTRIES
2995 .iter()
2996 .map(|(domain, ns, alias)| {
Qi Wub9433b52020-12-01 14:52:46 +08002997 let entry = make_test_key_entry(&mut db, *domain, *ns, *alias, None)
2998 .unwrap_or_else(|e| {
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002999 panic!("Failed to insert {:?} {} {}. Error {:?}", domain, ns, alias, e)
3000 });
3001 (entry.id(), *ns)
3002 })
3003 .collect();
3004
3005 for (domain, namespace) in
3006 &[(Domain::APP, 1i64), (Domain::APP, 2i64), (Domain::SELINUX, 100i64)]
3007 {
3008 let mut list_o_descriptors: Vec<KeyDescriptor> = LIST_O_ENTRIES
3009 .iter()
3010 .filter_map(|(domain, ns, alias)| match ns {
3011 ns if *ns == *namespace => Some(KeyDescriptor {
3012 domain: *domain,
3013 nspace: *ns,
3014 alias: Some(alias.to_string()),
3015 blob: None,
3016 }),
3017 _ => None,
3018 })
3019 .collect();
3020 list_o_descriptors.sort();
3021 let mut list_result = db.list(*domain, *namespace)?;
3022 list_result.sort();
3023 assert_eq!(list_o_descriptors, list_result);
3024
3025 let mut list_o_ids: Vec<i64> = list_o_descriptors
3026 .into_iter()
3027 .map(|d| {
3028 let (_, entry) = db
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003029 .load_key_entry(
3030 d,
3031 KeyType::Client,
3032 KeyEntryLoadBits::NONE,
3033 *namespace as u32,
3034 |_, _| Ok(()),
3035 )
Janis Danisevskise92a5e62020-12-02 12:57:41 -08003036 .unwrap();
3037 entry.id()
3038 })
3039 .collect();
3040 list_o_ids.sort_unstable();
3041 let mut loaded_entries: Vec<i64> = list_o_keys
3042 .iter()
3043 .filter_map(|(id, ns)| match ns {
3044 ns if *ns == *namespace => Some(*id),
3045 _ => None,
3046 })
3047 .collect();
3048 loaded_entries.sort_unstable();
3049 assert_eq!(list_o_ids, loaded_entries);
3050 }
3051 assert_eq!(Vec::<KeyDescriptor>::new(), db.list(Domain::SELINUX, 101)?);
3052
3053 Ok(())
3054 }
3055
Joel Galenson0891bc12020-07-20 10:37:03 -07003056 // Helpers
3057
3058 // Checks that the given result is an error containing the given string.
3059 fn check_result_is_error_containing_string<T>(result: Result<T>, target: &str) {
3060 let error_str = format!(
3061 "{:#?}",
3062 result.err().unwrap_or_else(|| panic!("Expected the error: {}", target))
3063 );
3064 assert!(
3065 error_str.contains(target),
3066 "The string \"{}\" should contain \"{}\"",
3067 error_str,
3068 target
3069 );
3070 }
3071
Joel Galenson2aab4432020-07-22 15:27:57 -07003072 #[derive(Debug, PartialEq)]
Joel Galenson0891bc12020-07-20 10:37:03 -07003073 #[allow(dead_code)]
3074 struct KeyEntryRow {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003075 id: i64,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003076 key_type: KeyType,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003077 domain: Option<Domain>,
Joel Galenson0891bc12020-07-20 10:37:03 -07003078 namespace: Option<i64>,
3079 alias: Option<String>,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003080 state: KeyLifeCycle,
Max Bires8e93d2b2021-01-14 13:17:59 -08003081 km_uuid: Option<Uuid>,
Joel Galenson0891bc12020-07-20 10:37:03 -07003082 }
3083
3084 fn get_keyentry(db: &KeystoreDB) -> Result<Vec<KeyEntryRow>> {
3085 db.conn
Joel Galenson2aab4432020-07-22 15:27:57 -07003086 .prepare("SELECT * FROM persistent.keyentry;")?
Joel Galenson0891bc12020-07-20 10:37:03 -07003087 .query_map(NO_PARAMS, |row| {
Joel Galenson0891bc12020-07-20 10:37:03 -07003088 Ok(KeyEntryRow {
3089 id: row.get(0)?,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003090 key_type: row.get(1)?,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003091 domain: match row.get(2)? {
3092 Some(i) => Some(Domain(i)),
3093 None => None,
3094 },
Joel Galenson0891bc12020-07-20 10:37:03 -07003095 namespace: row.get(3)?,
3096 alias: row.get(4)?,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003097 state: row.get(5)?,
Max Bires8e93d2b2021-01-14 13:17:59 -08003098 km_uuid: row.get(6)?,
Joel Galenson0891bc12020-07-20 10:37:03 -07003099 })
3100 })?
3101 .map(|r| r.context("Could not read keyentry row."))
3102 .collect::<Result<Vec<_>>>()
3103 }
3104
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07003105 // Note: The parameters and SecurityLevel associations are nonsensical. This
3106 // collection is only used to check if the parameters are preserved as expected by the
3107 // database.
Qi Wub9433b52020-12-01 14:52:46 +08003108 fn make_test_params(max_usage_count: Option<i32>) -> Vec<KeyParameter> {
3109 let mut params = vec![
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07003110 KeyParameter::new(KeyParameterValue::Invalid, SecurityLevel::TRUSTED_ENVIRONMENT),
3111 KeyParameter::new(
3112 KeyParameterValue::KeyPurpose(KeyPurpose::SIGN),
3113 SecurityLevel::TRUSTED_ENVIRONMENT,
3114 ),
3115 KeyParameter::new(
3116 KeyParameterValue::KeyPurpose(KeyPurpose::DECRYPT),
3117 SecurityLevel::TRUSTED_ENVIRONMENT,
3118 ),
3119 KeyParameter::new(
3120 KeyParameterValue::Algorithm(Algorithm::RSA),
3121 SecurityLevel::TRUSTED_ENVIRONMENT,
3122 ),
3123 KeyParameter::new(KeyParameterValue::KeySize(1024), SecurityLevel::TRUSTED_ENVIRONMENT),
3124 KeyParameter::new(
3125 KeyParameterValue::BlockMode(BlockMode::ECB),
3126 SecurityLevel::TRUSTED_ENVIRONMENT,
3127 ),
3128 KeyParameter::new(
3129 KeyParameterValue::BlockMode(BlockMode::GCM),
3130 SecurityLevel::TRUSTED_ENVIRONMENT,
3131 ),
3132 KeyParameter::new(KeyParameterValue::Digest(Digest::NONE), SecurityLevel::STRONGBOX),
3133 KeyParameter::new(
3134 KeyParameterValue::Digest(Digest::MD5),
3135 SecurityLevel::TRUSTED_ENVIRONMENT,
3136 ),
3137 KeyParameter::new(
3138 KeyParameterValue::Digest(Digest::SHA_2_224),
3139 SecurityLevel::TRUSTED_ENVIRONMENT,
3140 ),
3141 KeyParameter::new(
3142 KeyParameterValue::Digest(Digest::SHA_2_256),
3143 SecurityLevel::STRONGBOX,
3144 ),
3145 KeyParameter::new(
3146 KeyParameterValue::PaddingMode(PaddingMode::NONE),
3147 SecurityLevel::TRUSTED_ENVIRONMENT,
3148 ),
3149 KeyParameter::new(
3150 KeyParameterValue::PaddingMode(PaddingMode::RSA_OAEP),
3151 SecurityLevel::TRUSTED_ENVIRONMENT,
3152 ),
3153 KeyParameter::new(
3154 KeyParameterValue::PaddingMode(PaddingMode::RSA_PSS),
3155 SecurityLevel::STRONGBOX,
3156 ),
3157 KeyParameter::new(
3158 KeyParameterValue::PaddingMode(PaddingMode::RSA_PKCS1_1_5_SIGN),
3159 SecurityLevel::TRUSTED_ENVIRONMENT,
3160 ),
3161 KeyParameter::new(KeyParameterValue::CallerNonce, SecurityLevel::TRUSTED_ENVIRONMENT),
3162 KeyParameter::new(KeyParameterValue::MinMacLength(256), SecurityLevel::STRONGBOX),
3163 KeyParameter::new(
3164 KeyParameterValue::EcCurve(EcCurve::P_224),
3165 SecurityLevel::TRUSTED_ENVIRONMENT,
3166 ),
3167 KeyParameter::new(KeyParameterValue::EcCurve(EcCurve::P_256), SecurityLevel::STRONGBOX),
3168 KeyParameter::new(
3169 KeyParameterValue::EcCurve(EcCurve::P_384),
3170 SecurityLevel::TRUSTED_ENVIRONMENT,
3171 ),
3172 KeyParameter::new(
3173 KeyParameterValue::EcCurve(EcCurve::P_521),
3174 SecurityLevel::TRUSTED_ENVIRONMENT,
3175 ),
3176 KeyParameter::new(
3177 KeyParameterValue::RSAPublicExponent(3),
3178 SecurityLevel::TRUSTED_ENVIRONMENT,
3179 ),
3180 KeyParameter::new(
3181 KeyParameterValue::IncludeUniqueID,
3182 SecurityLevel::TRUSTED_ENVIRONMENT,
3183 ),
3184 KeyParameter::new(KeyParameterValue::BootLoaderOnly, SecurityLevel::STRONGBOX),
3185 KeyParameter::new(KeyParameterValue::RollbackResistance, SecurityLevel::STRONGBOX),
3186 KeyParameter::new(
3187 KeyParameterValue::ActiveDateTime(1234567890),
3188 SecurityLevel::STRONGBOX,
3189 ),
3190 KeyParameter::new(
3191 KeyParameterValue::OriginationExpireDateTime(1234567890),
3192 SecurityLevel::TRUSTED_ENVIRONMENT,
3193 ),
3194 KeyParameter::new(
3195 KeyParameterValue::UsageExpireDateTime(1234567890),
3196 SecurityLevel::TRUSTED_ENVIRONMENT,
3197 ),
3198 KeyParameter::new(
3199 KeyParameterValue::MinSecondsBetweenOps(1234567890),
3200 SecurityLevel::TRUSTED_ENVIRONMENT,
3201 ),
3202 KeyParameter::new(
3203 KeyParameterValue::MaxUsesPerBoot(1234567890),
3204 SecurityLevel::TRUSTED_ENVIRONMENT,
3205 ),
3206 KeyParameter::new(KeyParameterValue::UserID(1), SecurityLevel::STRONGBOX),
3207 KeyParameter::new(KeyParameterValue::UserSecureID(42), SecurityLevel::STRONGBOX),
3208 KeyParameter::new(
3209 KeyParameterValue::NoAuthRequired,
3210 SecurityLevel::TRUSTED_ENVIRONMENT,
3211 ),
3212 KeyParameter::new(
3213 KeyParameterValue::HardwareAuthenticatorType(HardwareAuthenticatorType::PASSWORD),
3214 SecurityLevel::TRUSTED_ENVIRONMENT,
3215 ),
3216 KeyParameter::new(KeyParameterValue::AuthTimeout(1234567890), SecurityLevel::SOFTWARE),
3217 KeyParameter::new(KeyParameterValue::AllowWhileOnBody, SecurityLevel::SOFTWARE),
3218 KeyParameter::new(
3219 KeyParameterValue::TrustedUserPresenceRequired,
3220 SecurityLevel::TRUSTED_ENVIRONMENT,
3221 ),
3222 KeyParameter::new(
3223 KeyParameterValue::TrustedConfirmationRequired,
3224 SecurityLevel::TRUSTED_ENVIRONMENT,
3225 ),
3226 KeyParameter::new(
3227 KeyParameterValue::UnlockedDeviceRequired,
3228 SecurityLevel::TRUSTED_ENVIRONMENT,
3229 ),
3230 KeyParameter::new(
3231 KeyParameterValue::ApplicationID(vec![1u8, 2u8, 3u8, 4u8]),
3232 SecurityLevel::SOFTWARE,
3233 ),
3234 KeyParameter::new(
3235 KeyParameterValue::ApplicationData(vec![4u8, 3u8, 2u8, 1u8]),
3236 SecurityLevel::SOFTWARE,
3237 ),
3238 KeyParameter::new(
3239 KeyParameterValue::CreationDateTime(12345677890),
3240 SecurityLevel::SOFTWARE,
3241 ),
3242 KeyParameter::new(
3243 KeyParameterValue::KeyOrigin(KeyOrigin::GENERATED),
3244 SecurityLevel::TRUSTED_ENVIRONMENT,
3245 ),
3246 KeyParameter::new(
3247 KeyParameterValue::RootOfTrust(vec![3u8, 2u8, 1u8, 4u8]),
3248 SecurityLevel::TRUSTED_ENVIRONMENT,
3249 ),
3250 KeyParameter::new(KeyParameterValue::OSVersion(1), SecurityLevel::TRUSTED_ENVIRONMENT),
3251 KeyParameter::new(KeyParameterValue::OSPatchLevel(2), SecurityLevel::SOFTWARE),
3252 KeyParameter::new(
3253 KeyParameterValue::UniqueID(vec![4u8, 3u8, 1u8, 2u8]),
3254 SecurityLevel::SOFTWARE,
3255 ),
3256 KeyParameter::new(
3257 KeyParameterValue::AttestationChallenge(vec![4u8, 3u8, 1u8, 2u8]),
3258 SecurityLevel::TRUSTED_ENVIRONMENT,
3259 ),
3260 KeyParameter::new(
3261 KeyParameterValue::AttestationApplicationID(vec![4u8, 3u8, 1u8, 2u8]),
3262 SecurityLevel::TRUSTED_ENVIRONMENT,
3263 ),
3264 KeyParameter::new(
3265 KeyParameterValue::AttestationIdBrand(vec![4u8, 3u8, 1u8, 2u8]),
3266 SecurityLevel::TRUSTED_ENVIRONMENT,
3267 ),
3268 KeyParameter::new(
3269 KeyParameterValue::AttestationIdDevice(vec![4u8, 3u8, 1u8, 2u8]),
3270 SecurityLevel::TRUSTED_ENVIRONMENT,
3271 ),
3272 KeyParameter::new(
3273 KeyParameterValue::AttestationIdProduct(vec![4u8, 3u8, 1u8, 2u8]),
3274 SecurityLevel::TRUSTED_ENVIRONMENT,
3275 ),
3276 KeyParameter::new(
3277 KeyParameterValue::AttestationIdSerial(vec![4u8, 3u8, 1u8, 2u8]),
3278 SecurityLevel::TRUSTED_ENVIRONMENT,
3279 ),
3280 KeyParameter::new(
3281 KeyParameterValue::AttestationIdIMEI(vec![4u8, 3u8, 1u8, 2u8]),
3282 SecurityLevel::TRUSTED_ENVIRONMENT,
3283 ),
3284 KeyParameter::new(
3285 KeyParameterValue::AttestationIdMEID(vec![4u8, 3u8, 1u8, 2u8]),
3286 SecurityLevel::TRUSTED_ENVIRONMENT,
3287 ),
3288 KeyParameter::new(
3289 KeyParameterValue::AttestationIdManufacturer(vec![4u8, 3u8, 1u8, 2u8]),
3290 SecurityLevel::TRUSTED_ENVIRONMENT,
3291 ),
3292 KeyParameter::new(
3293 KeyParameterValue::AttestationIdModel(vec![4u8, 3u8, 1u8, 2u8]),
3294 SecurityLevel::TRUSTED_ENVIRONMENT,
3295 ),
3296 KeyParameter::new(
3297 KeyParameterValue::VendorPatchLevel(3),
3298 SecurityLevel::TRUSTED_ENVIRONMENT,
3299 ),
3300 KeyParameter::new(
3301 KeyParameterValue::BootPatchLevel(4),
3302 SecurityLevel::TRUSTED_ENVIRONMENT,
3303 ),
3304 KeyParameter::new(
3305 KeyParameterValue::AssociatedData(vec![4u8, 3u8, 1u8, 2u8]),
3306 SecurityLevel::TRUSTED_ENVIRONMENT,
3307 ),
3308 KeyParameter::new(
3309 KeyParameterValue::Nonce(vec![4u8, 3u8, 1u8, 2u8]),
3310 SecurityLevel::TRUSTED_ENVIRONMENT,
3311 ),
3312 KeyParameter::new(
3313 KeyParameterValue::MacLength(256),
3314 SecurityLevel::TRUSTED_ENVIRONMENT,
3315 ),
3316 KeyParameter::new(
3317 KeyParameterValue::ResetSinceIdRotation,
3318 SecurityLevel::TRUSTED_ENVIRONMENT,
3319 ),
3320 KeyParameter::new(
3321 KeyParameterValue::ConfirmationToken(vec![5u8, 5u8, 5u8, 5u8]),
3322 SecurityLevel::TRUSTED_ENVIRONMENT,
3323 ),
Qi Wub9433b52020-12-01 14:52:46 +08003324 ];
3325 if let Some(value) = max_usage_count {
3326 params.push(KeyParameter::new(
3327 KeyParameterValue::UsageCountLimit(value),
3328 SecurityLevel::SOFTWARE,
3329 ));
3330 }
3331 params
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07003332 }
3333
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003334 fn make_test_key_entry(
3335 db: &mut KeystoreDB,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003336 domain: Domain,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003337 namespace: i64,
3338 alias: &str,
Qi Wub9433b52020-12-01 14:52:46 +08003339 max_usage_count: Option<i32>,
Janis Danisevskisaec14592020-11-12 09:41:49 -08003340 ) -> Result<KeyIdGuard> {
Max Bires8e93d2b2021-01-14 13:17:59 -08003341 let key_id = db.create_key_entry(domain, namespace, &KEYSTORE_UUID)?;
Janis Danisevskis377d1002021-01-27 19:07:48 -08003342 db.set_blob(&key_id, SubComponentType::KEY_BLOB, Some(TEST_KEY_BLOB))?;
3343 db.set_blob(&key_id, SubComponentType::CERT, Some(TEST_CERT_BLOB))?;
3344 db.set_blob(&key_id, SubComponentType::CERT_CHAIN, Some(TEST_CERT_CHAIN_BLOB))?;
Qi Wub9433b52020-12-01 14:52:46 +08003345
3346 let params = make_test_params(max_usage_count);
3347 db.insert_keyparameter(&key_id, &params)?;
3348
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003349 let mut metadata = KeyMetaData::new();
3350 metadata.add(KeyMetaEntry::EncryptedBy(EncryptedBy::Password));
3351 metadata.add(KeyMetaEntry::Salt(vec![1, 2, 3]));
3352 metadata.add(KeyMetaEntry::Iv(vec![2, 3, 1]));
3353 metadata.add(KeyMetaEntry::AeadTag(vec![3, 1, 2]));
3354 db.insert_key_metadata(&key_id, &metadata)?;
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003355 rebind_alias(db, &key_id, alias, domain, namespace)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003356 Ok(key_id)
3357 }
3358
Qi Wub9433b52020-12-01 14:52:46 +08003359 fn make_test_key_entry_test_vector(key_id: i64, max_usage_count: Option<i32>) -> KeyEntry {
3360 let params = make_test_params(max_usage_count);
3361
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003362 let mut metadata = KeyMetaData::new();
3363 metadata.add(KeyMetaEntry::EncryptedBy(EncryptedBy::Password));
3364 metadata.add(KeyMetaEntry::Salt(vec![1, 2, 3]));
3365 metadata.add(KeyMetaEntry::Iv(vec![2, 3, 1]));
3366 metadata.add(KeyMetaEntry::AeadTag(vec![3, 1, 2]));
3367
3368 KeyEntry {
3369 id: key_id,
3370 km_blob: Some(TEST_KEY_BLOB.to_vec()),
3371 cert: Some(TEST_CERT_BLOB.to_vec()),
3372 cert_chain: Some(TEST_CERT_CHAIN_BLOB.to_vec()),
Max Bires8e93d2b2021-01-14 13:17:59 -08003373 km_uuid: KEYSTORE_UUID,
Qi Wub9433b52020-12-01 14:52:46 +08003374 parameters: params,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003375 metadata,
Janis Danisevskis377d1002021-01-27 19:07:48 -08003376 pure_cert: false,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003377 }
3378 }
3379
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003380 fn debug_dump_keyentry_table(db: &mut KeystoreDB) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003381 let mut stmt = db.conn.prepare(
Max Bires8e93d2b2021-01-14 13:17:59 -08003382 "SELECT id, key_type, domain, namespace, alias, state, km_uuid FROM persistent.keyentry;",
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003383 )?;
Max Bires8e93d2b2021-01-14 13:17:59 -08003384 let rows = stmt.query_map::<(i64, KeyType, i32, i64, String, KeyLifeCycle, Uuid), _, _>(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003385 NO_PARAMS,
3386 |row| {
Max Bires8e93d2b2021-01-14 13:17:59 -08003387 Ok((
3388 row.get(0)?,
3389 row.get(1)?,
3390 row.get(2)?,
3391 row.get(3)?,
3392 row.get(4)?,
3393 row.get(5)?,
3394 row.get(6)?,
3395 ))
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003396 },
3397 )?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003398
3399 println!("Key entry table rows:");
3400 for r in rows {
Max Bires8e93d2b2021-01-14 13:17:59 -08003401 let (id, key_type, domain, namespace, alias, state, km_uuid) = r.unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003402 println!(
Max Bires8e93d2b2021-01-14 13:17:59 -08003403 " id: {} KeyType: {:?} Domain: {} Namespace: {} Alias: {} State: {:?} KmUuid: {:?}",
3404 id, key_type, domain, namespace, alias, state, km_uuid
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003405 );
3406 }
3407 Ok(())
3408 }
3409
3410 fn debug_dump_grant_table(db: &mut KeystoreDB) -> Result<()> {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08003411 let mut stmt = db
3412 .conn
3413 .prepare("SELECT id, grantee, keyentryid, access_vector FROM persistent.grant;")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003414 let rows = stmt.query_map::<(i64, i64, i64, i64), _, _>(NO_PARAMS, |row| {
3415 Ok((row.get(0)?, row.get(1)?, row.get(2)?, row.get(3)?))
3416 })?;
3417
3418 println!("Grant table rows:");
3419 for r in rows {
3420 let (id, gt, ki, av) = r.unwrap();
3421 println!(" id: {} grantee: {} key_id: {} access_vector: {}", id, gt, ki, av);
3422 }
3423 Ok(())
3424 }
3425
Joel Galenson0891bc12020-07-20 10:37:03 -07003426 // Use a custom random number generator that repeats each number once.
3427 // This allows us to test repeated elements.
3428
3429 thread_local! {
3430 static RANDOM_COUNTER: RefCell<i64> = RefCell::new(0);
3431 }
3432
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003433 fn reset_random() {
3434 RANDOM_COUNTER.with(|counter| {
3435 *counter.borrow_mut() = 0;
3436 })
3437 }
3438
Joel Galenson0891bc12020-07-20 10:37:03 -07003439 pub fn random() -> i64 {
3440 RANDOM_COUNTER.with(|counter| {
3441 let result = *counter.borrow() / 2;
3442 *counter.borrow_mut() += 1;
3443 result
3444 })
3445 }
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00003446
3447 #[test]
3448 fn test_last_off_body() -> Result<()> {
3449 let mut db = new_test_db()?;
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08003450 db.insert_last_off_body(MonotonicRawTime::now())?;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00003451 let tx = db.conn.transaction_with_behavior(TransactionBehavior::Immediate)?;
3452 let last_off_body_1 = KeystoreDB::get_last_off_body(&tx)?;
3453 tx.commit()?;
3454 let one_second = Duration::from_secs(1);
3455 thread::sleep(one_second);
3456 db.update_last_off_body(MonotonicRawTime::now())?;
3457 let tx2 = db.conn.transaction_with_behavior(TransactionBehavior::Immediate)?;
3458 let last_off_body_2 = KeystoreDB::get_last_off_body(&tx2)?;
3459 tx2.commit()?;
3460 assert!(last_off_body_1.seconds() < last_off_body_2.seconds());
3461 Ok(())
3462 }
Joel Galenson26f4d012020-07-17 14:57:21 -07003463}