blob: f9710f9133a811d9d4effb5b354a1a19a3170907 [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
Qi Wub9433b52020-12-01 14:52:46 +080044use crate::error::{Error as KsError, ErrorCode, ResponseCode};
Janis Danisevskisb42fc182020-12-15 08:41:27 -080045use crate::impl_metadata; // This is in db_utils.rs
Janis Danisevskis4522c2b2020-11-27 18:04:58 -080046use crate::key_parameter::{KeyParameter, Tag};
Janis Danisevskisc5b210b2020-09-11 13:27:37 -070047use crate::permission::KeyPermSet;
Hasini Gunasingheda895552021-01-27 19:34:37 +000048use crate::utils::{get_current_time_in_seconds, AID_USER_OFFSET};
Janis Danisevskis7e8b4622021-02-13 10:01:59 -080049use crate::{
50 db_utils::{self, SqlField},
51 gc::Gc,
52};
Janis Danisevskisb42fc182020-12-15 08:41:27 -080053use anyhow::{anyhow, Context, Result};
Max Bires8e93d2b2021-01-14 13:17:59 -080054use std::{convert::TryFrom, convert::TryInto, ops::Deref, time::SystemTimeError};
Janis Danisevskis60400fe2020-08-26 15:24:42 -070055
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +000056use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
Janis Danisevskis5ed8c532021-01-11 14:19:42 -080057 HardwareAuthToken::HardwareAuthToken,
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +000058 HardwareAuthenticatorType::HardwareAuthenticatorType, SecurityLevel::SecurityLevel,
Janis Danisevskisc3a496b2021-01-05 10:37:22 -080059};
60use android_hardware_security_secureclock::aidl::android::hardware::security::secureclock::{
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +000061 Timestamp::Timestamp,
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +000062};
Janis Danisevskisc5b210b2020-09-11 13:27:37 -070063use android_system_keystore2::aidl::android::system::keystore2::{
Janis Danisevskis04b02832020-10-26 09:21:40 -070064 Domain::Domain, KeyDescriptor::KeyDescriptor,
Janis Danisevskis60400fe2020-08-26 15:24:42 -070065};
Max Bires2b2e6562020-09-22 11:22:36 -070066use android_security_remoteprovisioning::aidl::android::security::remoteprovisioning::{
67 AttestationPoolStatus::AttestationPoolStatus,
68};
69
70use keystore2_crypto::ZVec;
Janis Danisevskisaec14592020-11-12 09:41:49 -080071use lazy_static::lazy_static;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +000072use log::error;
Joel Galenson0891bc12020-07-20 10:37:03 -070073#[cfg(not(test))]
74use rand::prelude::random;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -070075use rusqlite::{
Janis Danisevskisb42fc182020-12-15 08:41:27 -080076 params,
77 types::FromSql,
78 types::FromSqlResult,
79 types::ToSqlOutput,
80 types::{FromSqlError, Value, ValueRef},
Janis Danisevskis5ed8c532021-01-11 14:19:42 -080081 Connection, OptionalExtension, ToSql, Transaction, TransactionBehavior, NO_PARAMS,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -070082};
Max Bires2b2e6562020-09-22 11:22:36 -070083
Janis Danisevskisaec14592020-11-12 09:41:49 -080084use std::{
Janis Danisevskisb42fc182020-12-15 08:41:27 -080085 collections::{HashMap, HashSet},
Janis Danisevskisbf15d732020-12-08 10:35:26 -080086 path::Path,
87 sync::{Condvar, Mutex},
Janis Danisevskisb42fc182020-12-15 08:41:27 -080088 time::{Duration, SystemTime},
Janis Danisevskisaec14592020-11-12 09:41:49 -080089};
Max Bires2b2e6562020-09-22 11:22:36 -070090
Joel Galenson0891bc12020-07-20 10:37:03 -070091#[cfg(test)]
92use tests::random;
Joel Galenson26f4d012020-07-17 14:57:21 -070093
Janis Danisevskisb42fc182020-12-15 08:41:27 -080094impl_metadata!(
95 /// A set of metadata for key entries.
96 #[derive(Debug, Default, Eq, PartialEq)]
97 pub struct KeyMetaData;
98 /// A metadata entry for key entries.
99 #[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
100 pub enum KeyMetaEntry {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800101 /// Date of the creation of the key entry.
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800102 CreationDate(DateTime) with accessor creation_date,
103 /// Expiration date for attestation keys.
104 AttestationExpirationDate(DateTime) with accessor attestation_expiration_date,
Max Bires2b2e6562020-09-22 11:22:36 -0700105 /// CBOR Blob that represents a COSE_Key and associated metadata needed for remote
106 /// provisioning
107 AttestationMacedPublicKey(Vec<u8>) with accessor attestation_maced_public_key,
108 /// Vector representing the raw public key so results from the server can be matched
109 /// to the right entry
110 AttestationRawPubKey(Vec<u8>) with accessor attestation_raw_pub_key,
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800111 // --- ADD NEW META DATA FIELDS HERE ---
112 // For backwards compatibility add new entries only to
113 // end of this list and above this comment.
114 };
115);
116
117impl KeyMetaData {
118 fn load_from_db(key_id: i64, tx: &Transaction) -> Result<Self> {
119 let mut stmt = tx
120 .prepare(
121 "SELECT tag, data from persistent.keymetadata
122 WHERE keyentryid = ?;",
123 )
124 .context("In KeyMetaData::load_from_db: prepare statement failed.")?;
125
126 let mut metadata: HashMap<i64, KeyMetaEntry> = Default::default();
127
128 let mut rows =
129 stmt.query(params![key_id]).context("In KeyMetaData::load_from_db: query failed.")?;
130 db_utils::with_rows_extract_all(&mut rows, |row| {
131 let db_tag: i64 = row.get(0).context("Failed to read tag.")?;
132 metadata.insert(
133 db_tag,
134 KeyMetaEntry::new_from_sql(db_tag, &SqlField::new(1, &row))
135 .context("Failed to read KeyMetaEntry.")?,
136 );
137 Ok(())
138 })
139 .context("In KeyMetaData::load_from_db.")?;
140
141 Ok(Self { data: metadata })
142 }
143
144 fn store_in_db(&self, key_id: i64, tx: &Transaction) -> Result<()> {
145 let mut stmt = tx
146 .prepare(
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000147 "INSERT or REPLACE INTO persistent.keymetadata (keyentryid, tag, data)
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800148 VALUES (?, ?, ?);",
149 )
150 .context("In KeyMetaData::store_in_db: Failed to prepare statement.")?;
151
152 let iter = self.data.iter();
153 for (tag, entry) in iter {
154 stmt.insert(params![key_id, tag, entry,]).with_context(|| {
155 format!("In KeyMetaData::store_in_db: Failed to insert {:?}", entry)
156 })?;
157 }
158 Ok(())
159 }
160}
161
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800162impl_metadata!(
163 /// A set of metadata for key blobs.
164 #[derive(Debug, Default, Eq, PartialEq)]
165 pub struct BlobMetaData;
166 /// A metadata entry for key blobs.
167 #[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
168 pub enum BlobMetaEntry {
169 /// If present, indicates that the blob is encrypted with another key or a key derived
170 /// from a password.
171 EncryptedBy(EncryptedBy) with accessor encrypted_by,
172 /// If the blob is password encrypted this field is set to the
173 /// salt used for the key derivation.
174 Salt(Vec<u8>) with accessor salt,
175 /// If the blob is encrypted, this field is set to the initialization vector.
176 Iv(Vec<u8>) with accessor iv,
177 /// If the blob is encrypted, this field holds the AEAD TAG.
178 AeadTag(Vec<u8>) with accessor aead_tag,
179 /// The uuid of the owning KeyMint instance.
180 KmUuid(Uuid) with accessor km_uuid,
181 // --- ADD NEW META DATA FIELDS HERE ---
182 // For backwards compatibility add new entries only to
183 // end of this list and above this comment.
184 };
185);
186
187impl BlobMetaData {
188 fn load_from_db(blob_id: i64, tx: &Transaction) -> Result<Self> {
189 let mut stmt = tx
190 .prepare(
191 "SELECT tag, data from persistent.blobmetadata
192 WHERE blobentryid = ?;",
193 )
194 .context("In BlobMetaData::load_from_db: prepare statement failed.")?;
195
196 let mut metadata: HashMap<i64, BlobMetaEntry> = Default::default();
197
198 let mut rows =
199 stmt.query(params![blob_id]).context("In BlobMetaData::load_from_db: query failed.")?;
200 db_utils::with_rows_extract_all(&mut rows, |row| {
201 let db_tag: i64 = row.get(0).context("Failed to read tag.")?;
202 metadata.insert(
203 db_tag,
204 BlobMetaEntry::new_from_sql(db_tag, &SqlField::new(1, &row))
205 .context("Failed to read BlobMetaEntry.")?,
206 );
207 Ok(())
208 })
209 .context("In BlobMetaData::load_from_db.")?;
210
211 Ok(Self { data: metadata })
212 }
213
214 fn store_in_db(&self, blob_id: i64, tx: &Transaction) -> Result<()> {
215 let mut stmt = tx
216 .prepare(
217 "INSERT or REPLACE INTO persistent.blobmetadata (blobentryid, tag, data)
218 VALUES (?, ?, ?);",
219 )
220 .context("In BlobMetaData::store_in_db: Failed to prepare statement.")?;
221
222 let iter = self.data.iter();
223 for (tag, entry) in iter {
224 stmt.insert(params![blob_id, tag, entry,]).with_context(|| {
225 format!("In BlobMetaData::store_in_db: Failed to insert {:?}", entry)
226 })?;
227 }
228 Ok(())
229 }
230}
231
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800232/// Indicates the type of the keyentry.
233#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
234pub enum KeyType {
235 /// This is a client key type. These keys are created or imported through the Keystore 2.0
236 /// AIDL interface android.system.keystore2.
237 Client,
238 /// This is a super key type. These keys are created by keystore itself and used to encrypt
239 /// other key blobs to provide LSKF binding.
240 Super,
241 /// This is an attestation key. These keys are created by the remote provisioning mechanism.
242 Attestation,
243}
244
245impl ToSql for KeyType {
246 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
247 Ok(ToSqlOutput::Owned(Value::Integer(match self {
248 KeyType::Client => 0,
249 KeyType::Super => 1,
250 KeyType::Attestation => 2,
251 })))
252 }
253}
254
255impl FromSql for KeyType {
256 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
257 match i64::column_result(value)? {
258 0 => Ok(KeyType::Client),
259 1 => Ok(KeyType::Super),
260 2 => Ok(KeyType::Attestation),
261 v => Err(FromSqlError::OutOfRange(v)),
262 }
263 }
264}
265
Max Bires8e93d2b2021-01-14 13:17:59 -0800266/// Uuid representation that can be stored in the database.
267/// Right now it can only be initialized from SecurityLevel.
268/// Once KeyMint provides a UUID type a corresponding From impl shall be added.
269#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
270pub struct Uuid([u8; 16]);
271
272impl Deref for Uuid {
273 type Target = [u8; 16];
274
275 fn deref(&self) -> &Self::Target {
276 &self.0
277 }
278}
279
280impl From<SecurityLevel> for Uuid {
281 fn from(sec_level: SecurityLevel) -> Self {
282 Self((sec_level.0 as u128).to_be_bytes())
283 }
284}
285
286impl ToSql for Uuid {
287 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
288 self.0.to_sql()
289 }
290}
291
292impl FromSql for Uuid {
293 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
294 let blob = Vec::<u8>::column_result(value)?;
295 if blob.len() != 16 {
296 return Err(FromSqlError::OutOfRange(blob.len() as i64));
297 }
298 let mut arr = [0u8; 16];
299 arr.copy_from_slice(&blob);
300 Ok(Self(arr))
301 }
302}
303
304/// Key entries that are not associated with any KeyMint instance, such as pure certificate
305/// entries are associated with this UUID.
306pub static KEYSTORE_UUID: Uuid = Uuid([
307 0x41, 0xe3, 0xb9, 0xce, 0x27, 0x58, 0x4e, 0x91, 0xbc, 0xfd, 0xa5, 0x5d, 0x91, 0x85, 0xab, 0x11,
308]);
309
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800310/// Indicates how the sensitive part of this key blob is encrypted.
311#[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
312pub enum EncryptedBy {
313 /// The keyblob is encrypted by a user password.
314 /// In the database this variant is represented as NULL.
315 Password,
316 /// The keyblob is encrypted by another key with wrapped key id.
317 /// In the database this variant is represented as non NULL value
318 /// that is convertible to i64, typically NUMERIC.
319 KeyId(i64),
320}
321
322impl ToSql for EncryptedBy {
323 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
324 match self {
325 Self::Password => Ok(ToSqlOutput::Owned(Value::Null)),
326 Self::KeyId(id) => id.to_sql(),
327 }
328 }
329}
330
331impl FromSql for EncryptedBy {
332 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
333 match value {
334 ValueRef::Null => Ok(Self::Password),
335 _ => Ok(Self::KeyId(i64::column_result(value)?)),
336 }
337 }
338}
339
340/// A database representation of wall clock time. DateTime stores unix epoch time as
341/// i64 in milliseconds.
342#[derive(Debug, Copy, Clone, Default, Eq, PartialEq, Ord, PartialOrd)]
343pub struct DateTime(i64);
344
345/// Error type returned when creating DateTime or converting it from and to
346/// SystemTime.
347#[derive(thiserror::Error, Debug)]
348pub enum DateTimeError {
349 /// This is returned when SystemTime and Duration computations fail.
350 #[error(transparent)]
351 SystemTimeError(#[from] SystemTimeError),
352
353 /// This is returned when type conversions fail.
354 #[error(transparent)]
355 TypeConversion(#[from] std::num::TryFromIntError),
356
357 /// This is returned when checked time arithmetic failed.
358 #[error("Time arithmetic failed.")]
359 TimeArithmetic,
360}
361
362impl DateTime {
363 /// Constructs a new DateTime object denoting the current time. This may fail during
364 /// conversion to unix epoch time and during conversion to the internal i64 representation.
365 pub fn now() -> Result<Self, DateTimeError> {
366 Ok(Self(SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_millis().try_into()?))
367 }
368
369 /// Constructs a new DateTime object from milliseconds.
370 pub fn from_millis_epoch(millis: i64) -> Self {
371 Self(millis)
372 }
373
374 /// Returns unix epoch time in milliseconds.
375 pub fn to_millis_epoch(&self) -> i64 {
376 self.0
377 }
378
379 /// Returns unix epoch time in seconds.
380 pub fn to_secs_epoch(&self) -> i64 {
381 self.0 / 1000
382 }
383}
384
385impl ToSql for DateTime {
386 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
387 Ok(ToSqlOutput::Owned(Value::Integer(self.0)))
388 }
389}
390
391impl FromSql for DateTime {
392 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
393 Ok(Self(i64::column_result(value)?))
394 }
395}
396
397impl TryInto<SystemTime> for DateTime {
398 type Error = DateTimeError;
399
400 fn try_into(self) -> Result<SystemTime, Self::Error> {
401 // We want to construct a SystemTime representation equivalent to self, denoting
402 // a point in time THEN, but we cannot set the time directly. We can only construct
403 // a SystemTime denoting NOW, and we can get the duration between EPOCH and NOW,
404 // and between EPOCH and THEN. With this common reference we can construct the
405 // duration between NOW and THEN which we can add to our SystemTime representation
406 // of NOW to get a SystemTime representation of THEN.
407 // Durations can only be positive, thus the if statement below.
408 let now = SystemTime::now();
409 let now_epoch = now.duration_since(SystemTime::UNIX_EPOCH)?;
410 let then_epoch = Duration::from_millis(self.0.try_into()?);
411 Ok(if now_epoch > then_epoch {
412 // then = now - (now_epoch - then_epoch)
413 now_epoch
414 .checked_sub(then_epoch)
415 .and_then(|d| now.checked_sub(d))
416 .ok_or(DateTimeError::TimeArithmetic)?
417 } else {
418 // then = now + (then_epoch - now_epoch)
419 then_epoch
420 .checked_sub(now_epoch)
421 .and_then(|d| now.checked_add(d))
422 .ok_or(DateTimeError::TimeArithmetic)?
423 })
424 }
425}
426
427impl TryFrom<SystemTime> for DateTime {
428 type Error = DateTimeError;
429
430 fn try_from(t: SystemTime) -> Result<Self, Self::Error> {
431 Ok(Self(t.duration_since(SystemTime::UNIX_EPOCH)?.as_millis().try_into()?))
432 }
433}
434
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800435#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone)]
436enum KeyLifeCycle {
437 /// Existing keys have a key ID but are not fully populated yet.
438 /// This is a transient state. If Keystore finds any such keys when it starts up, it must move
439 /// them to Unreferenced for garbage collection.
440 Existing,
441 /// A live key is fully populated and usable by clients.
442 Live,
443 /// An unreferenced key is scheduled for garbage collection.
444 Unreferenced,
445}
446
447impl ToSql for KeyLifeCycle {
448 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
449 match self {
450 Self::Existing => Ok(ToSqlOutput::Owned(Value::Integer(0))),
451 Self::Live => Ok(ToSqlOutput::Owned(Value::Integer(1))),
452 Self::Unreferenced => Ok(ToSqlOutput::Owned(Value::Integer(2))),
453 }
454 }
455}
456
457impl FromSql for KeyLifeCycle {
458 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
459 match i64::column_result(value)? {
460 0 => Ok(KeyLifeCycle::Existing),
461 1 => Ok(KeyLifeCycle::Live),
462 2 => Ok(KeyLifeCycle::Unreferenced),
463 v => Err(FromSqlError::OutOfRange(v)),
464 }
465 }
466}
467
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700468/// Keys have a KeyMint blob component and optional public certificate and
469/// certificate chain components.
470/// KeyEntryLoadBits is a bitmap that indicates to `KeystoreDB::load_key_entry`
471/// which components shall be loaded from the database if present.
Janis Danisevskis66784c42021-01-27 08:40:25 -0800472#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700473pub struct KeyEntryLoadBits(u32);
474
475impl KeyEntryLoadBits {
476 /// Indicate to `KeystoreDB::load_key_entry` that no component shall be loaded.
477 pub const NONE: KeyEntryLoadBits = Self(0);
478 /// Indicate to `KeystoreDB::load_key_entry` that the KeyMint component shall be loaded.
479 pub const KM: KeyEntryLoadBits = Self(1);
480 /// Indicate to `KeystoreDB::load_key_entry` that the Public components shall be loaded.
481 pub const PUBLIC: KeyEntryLoadBits = Self(2);
482 /// Indicate to `KeystoreDB::load_key_entry` that both components shall be loaded.
483 pub const BOTH: KeyEntryLoadBits = Self(3);
484
485 /// Returns true if this object indicates that the public components shall be loaded.
486 pub const fn load_public(&self) -> bool {
487 self.0 & Self::PUBLIC.0 != 0
488 }
489
490 /// Returns true if the object indicates that the KeyMint component shall be loaded.
491 pub const fn load_km(&self) -> bool {
492 self.0 & Self::KM.0 != 0
493 }
494}
495
Janis Danisevskisaec14592020-11-12 09:41:49 -0800496lazy_static! {
497 static ref KEY_ID_LOCK: KeyIdLockDb = KeyIdLockDb::new();
498}
499
500struct KeyIdLockDb {
501 locked_keys: Mutex<HashSet<i64>>,
502 cond_var: Condvar,
503}
504
505/// A locked key. While a guard exists for a given key id, the same key cannot be loaded
506/// from the database a second time. Most functions manipulating the key blob database
507/// require a KeyIdGuard.
508#[derive(Debug)]
509pub struct KeyIdGuard(i64);
510
511impl KeyIdLockDb {
512 fn new() -> Self {
513 Self { locked_keys: Mutex::new(HashSet::new()), cond_var: Condvar::new() }
514 }
515
516 /// This function blocks until an exclusive lock for the given key entry id can
517 /// be acquired. It returns a guard object, that represents the lifecycle of the
518 /// acquired lock.
519 pub fn get(&self, key_id: i64) -> KeyIdGuard {
520 let mut locked_keys = self.locked_keys.lock().unwrap();
521 while locked_keys.contains(&key_id) {
522 locked_keys = self.cond_var.wait(locked_keys).unwrap();
523 }
524 locked_keys.insert(key_id);
525 KeyIdGuard(key_id)
526 }
527
528 /// This function attempts to acquire an exclusive lock on a given key id. If the
529 /// given key id is already taken the function returns None immediately. If a lock
530 /// can be acquired this function returns a guard object, that represents the
531 /// lifecycle of the acquired lock.
532 pub fn try_get(&self, key_id: i64) -> Option<KeyIdGuard> {
533 let mut locked_keys = self.locked_keys.lock().unwrap();
534 if locked_keys.insert(key_id) {
535 Some(KeyIdGuard(key_id))
536 } else {
537 None
538 }
539 }
540}
541
542impl KeyIdGuard {
543 /// Get the numeric key id of the locked key.
544 pub fn id(&self) -> i64 {
545 self.0
546 }
547}
548
549impl Drop for KeyIdGuard {
550 fn drop(&mut self) {
551 let mut locked_keys = KEY_ID_LOCK.locked_keys.lock().unwrap();
552 locked_keys.remove(&self.0);
Janis Danisevskis7fd53582020-11-23 13:40:34 -0800553 drop(locked_keys);
Janis Danisevskisaec14592020-11-12 09:41:49 -0800554 KEY_ID_LOCK.cond_var.notify_all();
555 }
556}
557
Max Bires8e93d2b2021-01-14 13:17:59 -0800558/// This type represents a certificate and certificate chain entry for a key.
Max Bires2b2e6562020-09-22 11:22:36 -0700559#[derive(Debug, Default)]
Max Bires8e93d2b2021-01-14 13:17:59 -0800560pub struct CertificateInfo {
561 cert: Option<Vec<u8>>,
562 cert_chain: Option<Vec<u8>>,
563}
564
565impl CertificateInfo {
566 /// Constructs a new CertificateInfo object from `cert` and `cert_chain`
567 pub fn new(cert: Option<Vec<u8>>, cert_chain: Option<Vec<u8>>) -> Self {
568 Self { cert, cert_chain }
569 }
570
571 /// Take the cert
572 pub fn take_cert(&mut self) -> Option<Vec<u8>> {
573 self.cert.take()
574 }
575
576 /// Take the cert chain
577 pub fn take_cert_chain(&mut self) -> Option<Vec<u8>> {
578 self.cert_chain.take()
579 }
580}
581
Max Bires2b2e6562020-09-22 11:22:36 -0700582/// This type represents a certificate chain with a private key corresponding to the leaf
583/// certificate. TODO(jbires): This will be used in a follow-on CL, for now it's used in the tests.
584#[allow(dead_code)]
585pub struct CertificateChain {
586 private_key: ZVec,
Max Biresb2e1d032021-02-08 21:35:05 -0800587 batch_cert: ZVec,
Max Bires2b2e6562020-09-22 11:22:36 -0700588 cert_chain: ZVec,
589}
590
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700591/// This type represents a Keystore 2.0 key entry.
592/// An entry has a unique `id` by which it can be found in the database.
593/// It has a security level field, key parameters, and three optional fields
594/// for the KeyMint blob, public certificate and a public certificate chain.
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800595#[derive(Debug, Default, Eq, PartialEq)]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700596pub struct KeyEntry {
597 id: i64,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800598 key_blob_info: Option<(Vec<u8>, BlobMetaData)>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700599 cert: Option<Vec<u8>>,
600 cert_chain: Option<Vec<u8>>,
Max Bires8e93d2b2021-01-14 13:17:59 -0800601 km_uuid: Uuid,
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700602 parameters: Vec<KeyParameter>,
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800603 metadata: KeyMetaData,
Janis Danisevskis377d1002021-01-27 19:07:48 -0800604 pure_cert: bool,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700605}
606
607impl KeyEntry {
608 /// Returns the unique id of the Key entry.
609 pub fn id(&self) -> i64 {
610 self.id
611 }
612 /// Exposes the optional KeyMint blob.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800613 pub fn key_blob_info(&self) -> &Option<(Vec<u8>, BlobMetaData)> {
614 &self.key_blob_info
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700615 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800616 /// Extracts the Optional KeyMint blob including its metadata.
617 pub fn take_key_blob_info(&mut self) -> Option<(Vec<u8>, BlobMetaData)> {
618 self.key_blob_info.take()
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700619 }
620 /// Exposes the optional public certificate.
621 pub fn cert(&self) -> &Option<Vec<u8>> {
622 &self.cert
623 }
624 /// Extracts the optional public certificate.
625 pub fn take_cert(&mut self) -> Option<Vec<u8>> {
626 self.cert.take()
627 }
628 /// Exposes the optional public certificate chain.
629 pub fn cert_chain(&self) -> &Option<Vec<u8>> {
630 &self.cert_chain
631 }
632 /// Extracts the optional public certificate_chain.
633 pub fn take_cert_chain(&mut self) -> Option<Vec<u8>> {
634 self.cert_chain.take()
635 }
Max Bires8e93d2b2021-01-14 13:17:59 -0800636 /// Returns the uuid of the owning KeyMint instance.
637 pub fn km_uuid(&self) -> &Uuid {
638 &self.km_uuid
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700639 }
Janis Danisevskis04b02832020-10-26 09:21:40 -0700640 /// Exposes the key parameters of this key entry.
641 pub fn key_parameters(&self) -> &Vec<KeyParameter> {
642 &self.parameters
643 }
644 /// Consumes this key entry and extracts the keyparameters from it.
645 pub fn into_key_parameters(self) -> Vec<KeyParameter> {
646 self.parameters
647 }
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800648 /// Exposes the key metadata of this key entry.
649 pub fn metadata(&self) -> &KeyMetaData {
650 &self.metadata
651 }
Janis Danisevskis377d1002021-01-27 19:07:48 -0800652 /// This returns true if the entry is a pure certificate entry with no
653 /// private key component.
654 pub fn pure_cert(&self) -> bool {
655 self.pure_cert
656 }
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000657 /// Consumes this key entry and extracts the keyparameters and metadata from it.
658 pub fn into_key_parameters_and_metadata(self) -> (Vec<KeyParameter>, KeyMetaData) {
659 (self.parameters, self.metadata)
660 }
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700661}
662
663/// Indicates the sub component of a key entry for persistent storage.
Janis Danisevskis377d1002021-01-27 19:07:48 -0800664#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700665pub struct SubComponentType(u32);
666impl SubComponentType {
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800667 /// Persistent identifier for a key blob.
668 pub const KEY_BLOB: SubComponentType = Self(0);
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700669 /// Persistent identifier for a certificate blob.
670 pub const CERT: SubComponentType = Self(1);
671 /// Persistent identifier for a certificate chain blob.
672 pub const CERT_CHAIN: SubComponentType = Self(2);
673}
674
675impl ToSql for SubComponentType {
676 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
677 self.0.to_sql()
678 }
679}
680
681impl FromSql for SubComponentType {
682 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
683 Ok(Self(u32::column_result(value)?))
684 }
685}
686
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800687/// This trait is private to the database module. It is used to convey whether or not the garbage
688/// collector shall be invoked after a database access. All closures passed to
689/// `KeystoreDB::with_transaction` return a tuple (bool, T) where the bool indicates if the
690/// gc needs to be triggered. This convenience function allows to turn any anyhow::Result<T>
691/// into anyhow::Result<(bool, T)> by simply appending one of `.do_gc(bool)`, `.no_gc()`, or
692/// `.need_gc()`.
693trait DoGc<T> {
694 fn do_gc(self, need_gc: bool) -> Result<(bool, T)>;
695
696 fn no_gc(self) -> Result<(bool, T)>;
697
698 fn need_gc(self) -> Result<(bool, T)>;
699}
700
701impl<T> DoGc<T> for Result<T> {
702 fn do_gc(self, need_gc: bool) -> Result<(bool, T)> {
703 self.map(|r| (need_gc, r))
704 }
705
706 fn no_gc(self) -> Result<(bool, T)> {
707 self.do_gc(false)
708 }
709
710 fn need_gc(self) -> Result<(bool, T)> {
711 self.do_gc(true)
712 }
713}
714
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700715/// KeystoreDB wraps a connection to an SQLite database and tracks its
716/// ownership. It also implements all of Keystore 2.0's database functionality.
Joel Galenson26f4d012020-07-17 14:57:21 -0700717pub struct KeystoreDB {
Joel Galenson26f4d012020-07-17 14:57:21 -0700718 conn: Connection,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800719 gc: Option<Gc>,
Joel Galenson26f4d012020-07-17 14:57:21 -0700720}
721
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000722/// Database representation of the monotonic time retrieved from the system call clock_gettime with
723/// CLOCK_MONOTONIC_RAW. Stores monotonic time as i64 in seconds.
724#[derive(Debug, Copy, Clone, Default, Eq, PartialEq, Ord, PartialOrd)]
725pub struct MonotonicRawTime(i64);
726
727impl MonotonicRawTime {
728 /// Constructs a new MonotonicRawTime
729 pub fn now() -> Self {
730 Self(get_current_time_in_seconds())
731 }
732
733 /// Returns the integer value of MonotonicRawTime as i64
734 pub fn seconds(&self) -> i64 {
735 self.0
736 }
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800737
738 /// Like i64::checked_sub.
739 pub fn checked_sub(&self, other: &Self) -> Option<Self> {
740 self.0.checked_sub(other.0).map(Self)
741 }
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000742}
743
744impl ToSql for MonotonicRawTime {
745 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
746 Ok(ToSqlOutput::Owned(Value::Integer(self.0)))
747 }
748}
749
750impl FromSql for MonotonicRawTime {
751 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
752 Ok(Self(i64::column_result(value)?))
753 }
754}
755
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000756/// This struct encapsulates the information to be stored in the database about the auth tokens
757/// received by keystore.
758pub struct AuthTokenEntry {
759 auth_token: HardwareAuthToken,
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000760 time_received: MonotonicRawTime,
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000761}
762
763impl AuthTokenEntry {
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000764 fn new(auth_token: HardwareAuthToken, time_received: MonotonicRawTime) -> Self {
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000765 AuthTokenEntry { auth_token, time_received }
766 }
767
768 /// Checks if this auth token satisfies the given authentication information.
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800769 pub fn satisfies(&self, user_secure_ids: &[i64], auth_type: HardwareAuthenticatorType) -> bool {
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000770 user_secure_ids.iter().any(|&sid| {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800771 (sid == self.auth_token.userId || sid == self.auth_token.authenticatorId)
772 && (((auth_type.0 as i32) & (self.auth_token.authenticatorType.0 as i32)) != 0)
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000773 })
774 }
775
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000776 /// Returns the auth token wrapped by the AuthTokenEntry
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800777 pub fn auth_token(&self) -> &HardwareAuthToken {
778 &self.auth_token
779 }
780
781 /// Returns the auth token wrapped by the AuthTokenEntry
782 pub fn take_auth_token(self) -> HardwareAuthToken {
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000783 self.auth_token
784 }
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800785
786 /// Returns the time that this auth token was received.
787 pub fn time_received(&self) -> MonotonicRawTime {
788 self.time_received
789 }
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000790}
791
Janis Danisevskisb00ebd02021-02-02 21:52:24 -0800792/// Shared in-memory databases get destroyed as soon as the last connection to them gets closed.
793/// This object does not allow access to the database connection. But it keeps a database
794/// connection alive in order to keep the in memory per boot database alive.
795pub struct PerBootDbKeepAlive(Connection);
796
Joel Galenson26f4d012020-07-17 14:57:21 -0700797impl KeystoreDB {
Janis Danisevskisb00ebd02021-02-02 21:52:24 -0800798 const PERBOOT_DB_FILE_NAME: &'static str = &"file:perboot.sqlite?mode=memory&cache=shared";
799
Hasini Gunasinghe0e161452021-01-27 19:34:37 +0000800 /// The alias of the user super key.
801 pub const USER_SUPER_KEY_ALIAS: &'static str = &"USER_SUPER_KEY";
802
Janis Danisevskisb00ebd02021-02-02 21:52:24 -0800803 /// This creates a PerBootDbKeepAlive object to keep the per boot database alive.
804 pub fn keep_perboot_db_alive() -> Result<PerBootDbKeepAlive> {
805 let conn = Connection::open_in_memory()
806 .context("In keep_perboot_db_alive: Failed to initialize SQLite connection.")?;
807
808 conn.execute("ATTACH DATABASE ? as perboot;", params![Self::PERBOOT_DB_FILE_NAME])
809 .context("In keep_perboot_db_alive: Failed to attach database perboot.")?;
810 Ok(PerBootDbKeepAlive(conn))
811 }
812
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700813 /// This will create a new database connection connecting the two
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800814 /// files persistent.sqlite and perboot.sqlite in the given directory.
815 /// It also attempts to initialize all of the tables.
816 /// KeystoreDB cannot be used by multiple threads.
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700817 /// Each thread should open their own connection using `thread_local!`.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800818 pub fn new(db_root: &Path, gc: Option<Gc>) -> Result<Self> {
Janis Danisevskisb00ebd02021-02-02 21:52:24 -0800819 // Build the path to the sqlite file.
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800820 let mut persistent_path = db_root.to_path_buf();
821 persistent_path.push("persistent.sqlite");
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700822
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800823 // Now convert them to strings prefixed with "file:"
824 let mut persistent_path_str = "file:".to_owned();
825 persistent_path_str.push_str(&persistent_path.to_string_lossy());
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800826
Janis Danisevskisb00ebd02021-02-02 21:52:24 -0800827 let conn = Self::make_connection(&persistent_path_str, &Self::PERBOOT_DB_FILE_NAME)?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800828
Janis Danisevskis66784c42021-01-27 08:40:25 -0800829 // On busy fail Immediately. It is unlikely to succeed given a bug in sqlite.
830 conn.busy_handler(None).context("In KeystoreDB::new: Failed to set busy handler.")?;
831
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800832 let mut db = Self { conn, gc };
Janis Danisevskis66784c42021-01-27 08:40:25 -0800833 db.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800834 Self::init_tables(tx).context("Trying to initialize tables.").no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -0800835 })?;
836 Ok(db)
Joel Galenson2aab4432020-07-22 15:27:57 -0700837 }
838
Janis Danisevskis66784c42021-01-27 08:40:25 -0800839 fn init_tables(tx: &Transaction) -> Result<()> {
840 tx.execute(
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700841 "CREATE TABLE IF NOT EXISTS persistent.keyentry (
Joel Galenson0891bc12020-07-20 10:37:03 -0700842 id INTEGER UNIQUE,
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800843 key_type INTEGER,
Joel Galenson0891bc12020-07-20 10:37:03 -0700844 domain INTEGER,
845 namespace INTEGER,
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800846 alias BLOB,
Max Bires8e93d2b2021-01-14 13:17:59 -0800847 state INTEGER,
848 km_uuid BLOB);",
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700849 NO_PARAMS,
850 )
851 .context("Failed to initialize \"keyentry\" table.")?;
852
Janis Danisevskis66784c42021-01-27 08:40:25 -0800853 tx.execute(
Janis Danisevskisa5438182021-02-02 14:22:59 -0800854 "CREATE INDEX IF NOT EXISTS persistent.keyentry_id_index
855 ON keyentry(id);",
856 NO_PARAMS,
857 )
858 .context("Failed to create index keyentry_id_index.")?;
859
860 tx.execute(
861 "CREATE INDEX IF NOT EXISTS persistent.keyentry_domain_namespace_index
862 ON keyentry(domain, namespace, alias);",
863 NO_PARAMS,
864 )
865 .context("Failed to create index keyentry_domain_namespace_index.")?;
866
867 tx.execute(
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700868 "CREATE TABLE IF NOT EXISTS persistent.blobentry (
869 id INTEGER PRIMARY KEY,
870 subcomponent_type INTEGER,
871 keyentryid INTEGER,
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800872 blob BLOB);",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700873 NO_PARAMS,
874 )
875 .context("Failed to initialize \"blobentry\" table.")?;
876
Janis Danisevskis66784c42021-01-27 08:40:25 -0800877 tx.execute(
Janis Danisevskisa5438182021-02-02 14:22:59 -0800878 "CREATE INDEX IF NOT EXISTS persistent.blobentry_keyentryid_index
879 ON blobentry(keyentryid);",
880 NO_PARAMS,
881 )
882 .context("Failed to create index blobentry_keyentryid_index.")?;
883
884 tx.execute(
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800885 "CREATE TABLE IF NOT EXISTS persistent.blobmetadata (
886 id INTEGER PRIMARY KEY,
887 blobentryid INTEGER,
888 tag INTEGER,
889 data ANY,
890 UNIQUE (blobentryid, tag));",
891 NO_PARAMS,
892 )
893 .context("Failed to initialize \"blobmetadata\" table.")?;
894
895 tx.execute(
896 "CREATE INDEX IF NOT EXISTS persistent.blobmetadata_blobentryid_index
897 ON blobmetadata(blobentryid);",
898 NO_PARAMS,
899 )
900 .context("Failed to create index blobmetadata_blobentryid_index.")?;
901
902 tx.execute(
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700903 "CREATE TABLE IF NOT EXISTS persistent.keyparameter (
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000904 keyentryid INTEGER,
905 tag INTEGER,
906 data ANY,
907 security_level INTEGER);",
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700908 NO_PARAMS,
909 )
910 .context("Failed to initialize \"keyparameter\" table.")?;
911
Janis Danisevskis66784c42021-01-27 08:40:25 -0800912 tx.execute(
Janis Danisevskisa5438182021-02-02 14:22:59 -0800913 "CREATE INDEX IF NOT EXISTS persistent.keyparameter_keyentryid_index
914 ON keyparameter(keyentryid);",
915 NO_PARAMS,
916 )
917 .context("Failed to create index keyparameter_keyentryid_index.")?;
918
919 tx.execute(
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800920 "CREATE TABLE IF NOT EXISTS persistent.keymetadata (
921 keyentryid INTEGER,
922 tag INTEGER,
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000923 data ANY,
924 UNIQUE (keyentryid, tag));",
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800925 NO_PARAMS,
926 )
927 .context("Failed to initialize \"keymetadata\" table.")?;
928
Janis Danisevskis66784c42021-01-27 08:40:25 -0800929 tx.execute(
Janis Danisevskisa5438182021-02-02 14:22:59 -0800930 "CREATE INDEX IF NOT EXISTS persistent.keymetadata_keyentryid_index
931 ON keymetadata(keyentryid);",
932 NO_PARAMS,
933 )
934 .context("Failed to create index keymetadata_keyentryid_index.")?;
935
936 tx.execute(
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800937 "CREATE TABLE IF NOT EXISTS persistent.grant (
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700938 id INTEGER UNIQUE,
939 grantee INTEGER,
940 keyentryid INTEGER,
941 access_vector INTEGER);",
942 NO_PARAMS,
943 )
944 .context("Failed to initialize \"grant\" table.")?;
945
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000946 //TODO: only drop the following two perboot tables if this is the first start up
947 //during the boot (b/175716626).
Janis Danisevskis66784c42021-01-27 08:40:25 -0800948 // tx.execute("DROP TABLE IF EXISTS perboot.authtoken;", NO_PARAMS)
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000949 // .context("Failed to drop perboot.authtoken table")?;
Janis Danisevskis66784c42021-01-27 08:40:25 -0800950 tx.execute(
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000951 "CREATE TABLE IF NOT EXISTS perboot.authtoken (
952 id INTEGER PRIMARY KEY,
953 challenge INTEGER,
954 user_id INTEGER,
955 auth_id INTEGER,
956 authenticator_type INTEGER,
957 timestamp INTEGER,
958 mac BLOB,
959 time_received INTEGER,
960 UNIQUE(user_id, auth_id, authenticator_type));",
961 NO_PARAMS,
962 )
963 .context("Failed to initialize \"authtoken\" table.")?;
964
Janis Danisevskis66784c42021-01-27 08:40:25 -0800965 // tx.execute("DROP TABLE IF EXISTS perboot.metadata;", NO_PARAMS)
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000966 // .context("Failed to drop perboot.metadata table")?;
967 // metadata table stores certain miscellaneous information required for keystore functioning
968 // during a boot cycle, as key-value pairs.
Janis Danisevskis66784c42021-01-27 08:40:25 -0800969 tx.execute(
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000970 "CREATE TABLE IF NOT EXISTS perboot.metadata (
971 key TEXT,
972 value BLOB,
973 UNIQUE(key));",
974 NO_PARAMS,
975 )
976 .context("Failed to initialize \"metadata\" table.")?;
Joel Galenson0891bc12020-07-20 10:37:03 -0700977 Ok(())
978 }
979
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700980 fn make_connection(persistent_file: &str, perboot_file: &str) -> Result<Connection> {
981 let conn =
982 Connection::open_in_memory().context("Failed to initialize SQLite connection.")?;
983
Janis Danisevskis66784c42021-01-27 08:40:25 -0800984 loop {
985 if let Err(e) = conn
986 .execute("ATTACH DATABASE ? as persistent;", params![persistent_file])
987 .context("Failed to attach database persistent.")
988 {
989 if Self::is_locked_error(&e) {
990 std::thread::sleep(std::time::Duration::from_micros(500));
991 continue;
992 } else {
993 return Err(e);
994 }
995 }
996 break;
997 }
998 loop {
999 if let Err(e) = conn
1000 .execute("ATTACH DATABASE ? as perboot;", params![perboot_file])
1001 .context("Failed to attach database perboot.")
1002 {
1003 if Self::is_locked_error(&e) {
1004 std::thread::sleep(std::time::Duration::from_micros(500));
1005 continue;
1006 } else {
1007 return Err(e);
1008 }
1009 }
1010 break;
1011 }
Janis Danisevskis4df44f42020-08-26 14:40:03 -07001012
1013 Ok(conn)
1014 }
1015
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001016 /// This function is intended to be used by the garbage collector.
1017 /// It deletes the blob given by `blob_id_to_delete`. It then tries to find a superseded
1018 /// key blob that might need special handling by the garbage collector.
1019 /// If no further superseded blobs can be found it deletes all other superseded blobs that don't
1020 /// need special handling and returns None.
1021 pub fn handle_next_superseded_blob(
1022 &mut self,
1023 blob_id_to_delete: Option<i64>,
1024 ) -> Result<Option<(i64, Vec<u8>, BlobMetaData)>> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001025 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001026 // Delete the given blob if one was given.
1027 if let Some(blob_id_to_delete) = blob_id_to_delete {
1028 tx.execute(
1029 "DELETE FROM persistent.blobmetadata WHERE blobentryid = ?;",
1030 params![blob_id_to_delete],
1031 )
1032 .context("Trying to delete blob metadata.")?;
1033 tx.execute(
1034 "DELETE FROM persistent.blobentry WHERE id = ?;",
1035 params![blob_id_to_delete],
1036 )
1037 .context("Trying to blob.")?;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001038 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001039
1040 // Find another superseded keyblob load its metadata and return it.
1041 if let Some((blob_id, blob)) = tx
1042 .query_row(
1043 "SELECT id, blob FROM persistent.blobentry
1044 WHERE subcomponent_type = ?
1045 AND (
1046 id NOT IN (
1047 SELECT MAX(id) FROM persistent.blobentry
1048 WHERE subcomponent_type = ?
1049 GROUP BY keyentryid, subcomponent_type
1050 )
1051 OR keyentryid NOT IN (SELECT id FROM persistent.keyentry)
1052 );",
1053 params![SubComponentType::KEY_BLOB, SubComponentType::KEY_BLOB],
1054 |row| Ok((row.get(0)?, row.get(1)?)),
1055 )
1056 .optional()
1057 .context("Trying to query superseded blob.")?
1058 {
1059 let blob_metadata = BlobMetaData::load_from_db(blob_id, tx)
1060 .context("Trying to load blob metadata.")?;
1061 return Ok(Some((blob_id, blob, blob_metadata))).no_gc();
1062 }
1063
1064 // We did not find any superseded key blob, so let's remove other superseded blob in
1065 // one transaction.
1066 tx.execute(
1067 "DELETE FROM persistent.blobentry
1068 WHERE NOT subcomponent_type = ?
1069 AND (
1070 id NOT IN (
1071 SELECT MAX(id) FROM persistent.blobentry
1072 WHERE NOT subcomponent_type = ?
1073 GROUP BY keyentryid, subcomponent_type
1074 ) OR keyentryid NOT IN (SELECT id FROM persistent.keyentry)
1075 );",
1076 params![SubComponentType::KEY_BLOB, SubComponentType::KEY_BLOB],
1077 )
1078 .context("Trying to purge superseded blobs.")?;
1079
1080 Ok(None).no_gc()
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001081 })
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001082 .context("In handle_next_superseded_blob.")
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001083 }
1084
1085 /// This maintenance function should be called only once before the database is used for the
1086 /// first time. It restores the invariant that `KeyLifeCycle::Existing` is a transient state.
1087 /// The function transitions all key entries from Existing to Unreferenced unconditionally and
1088 /// returns the number of rows affected. If this returns a value greater than 0, it means that
1089 /// Keystore crashed at some point during key generation. Callers may want to log such
1090 /// occurrences.
1091 /// Unlike with `mark_unreferenced`, we don't need to purge grants, because only keys that made
1092 /// it to `KeyLifeCycle::Live` may have grants.
1093 pub fn cleanup_leftovers(&mut self) -> Result<usize> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001094 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1095 tx.execute(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001096 "UPDATE persistent.keyentry SET state = ? WHERE state = ?;",
1097 params![KeyLifeCycle::Unreferenced, KeyLifeCycle::Existing],
1098 )
Janis Danisevskis66784c42021-01-27 08:40:25 -08001099 .context("Failed to execute query.")
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001100 .need_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08001101 })
1102 .context("In cleanup_leftovers.")
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001103 }
1104
Hasini Gunasinghe0e161452021-01-27 19:34:37 +00001105 /// Checks if a key exists with given key type and key descriptor properties.
1106 pub fn key_exists(
1107 &mut self,
1108 domain: Domain,
1109 nspace: i64,
1110 alias: &str,
1111 key_type: KeyType,
1112 ) -> Result<bool> {
1113 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1114 let key_descriptor =
1115 KeyDescriptor { domain, nspace, alias: Some(alias.to_string()), blob: None };
1116 let result = Self::load_key_entry_id(&tx, &key_descriptor, key_type);
1117 match result {
1118 Ok(_) => Ok(true),
1119 Err(error) => match error.root_cause().downcast_ref::<KsError>() {
1120 Some(KsError::Rc(ResponseCode::KEY_NOT_FOUND)) => Ok(false),
1121 _ => Err(error).context("In key_exists: Failed to find if the key exists."),
1122 },
1123 }
1124 .no_gc()
1125 })
1126 .context("In key_exists.")
1127 }
1128
Hasini Gunasingheda895552021-01-27 19:34:37 +00001129 /// Stores a super key in the database.
1130 pub fn store_super_key(
1131 &mut self,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +00001132 user_id: u32,
Hasini Gunasingheda895552021-01-27 19:34:37 +00001133 blob_info: &(&[u8], &BlobMetaData),
1134 ) -> Result<KeyEntry> {
1135 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1136 let key_id = Self::insert_with_retry(|id| {
1137 tx.execute(
1138 "INSERT into persistent.keyentry
1139 (id, key_type, domain, namespace, alias, state, km_uuid)
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00001140 VALUES(?, ?, ?, ?, ?, ?, ?);",
Hasini Gunasingheda895552021-01-27 19:34:37 +00001141 params![
1142 id,
1143 KeyType::Super,
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00001144 Domain::APP.0,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +00001145 user_id as i64,
Hasini Gunasingheda895552021-01-27 19:34:37 +00001146 Self::USER_SUPER_KEY_ALIAS,
1147 KeyLifeCycle::Live,
1148 &KEYSTORE_UUID,
1149 ],
1150 )
1151 })
1152 .context("Failed to insert into keyentry table.")?;
1153
1154 let (blob, blob_metadata) = *blob_info;
1155 Self::set_blob_internal(
1156 &tx,
1157 key_id,
1158 SubComponentType::KEY_BLOB,
1159 Some(blob),
1160 Some(blob_metadata),
1161 )
1162 .context("Failed to store key blob.")?;
1163
1164 Self::load_key_components(tx, KeyEntryLoadBits::KM, key_id)
1165 .context("Trying to load key components.")
1166 .no_gc()
1167 })
1168 .context("In store_super_key.")
1169 }
1170
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +00001171 /// Loads super key of a given user, if exists
1172 pub fn load_super_key(&mut self, user_id: u32) -> Result<Option<(KeyIdGuard, KeyEntry)>> {
1173 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1174 let key_descriptor = KeyDescriptor {
1175 domain: Domain::APP,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +00001176 nspace: user_id as i64,
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +00001177 alias: Some(String::from("USER_SUPER_KEY")),
1178 blob: None,
1179 };
1180 let id = Self::load_key_entry_id(&tx, &key_descriptor, KeyType::Super);
1181 match id {
1182 Ok(id) => {
1183 let key_entry = Self::load_key_components(&tx, KeyEntryLoadBits::KM, id)
1184 .context("In load_super_key. Failed to load key entry.")?;
1185 Ok(Some((KEY_ID_LOCK.get(id), key_entry)))
1186 }
1187 Err(error) => match error.root_cause().downcast_ref::<KsError>() {
1188 Some(KsError::Rc(ResponseCode::KEY_NOT_FOUND)) => Ok(None),
1189 _ => Err(error).context("In load_super_key."),
1190 },
1191 }
1192 .no_gc()
1193 })
1194 .context("In load_super_key.")
1195 }
1196
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001197 /// Atomically loads a key entry and associated metadata or creates it using the
1198 /// callback create_new_key callback. The callback is called during a database
1199 /// transaction. This means that implementers should be mindful about using
1200 /// blocking operations such as IPC or grabbing mutexes.
1201 pub fn get_or_create_key_with<F>(
1202 &mut self,
1203 domain: Domain,
1204 namespace: i64,
1205 alias: &str,
Max Bires8e93d2b2021-01-14 13:17:59 -08001206 km_uuid: Uuid,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001207 create_new_key: F,
1208 ) -> Result<(KeyIdGuard, KeyEntry)>
1209 where
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001210 F: Fn() -> Result<(Vec<u8>, BlobMetaData)>,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001211 {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001212 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1213 let id = {
1214 let mut stmt = tx
1215 .prepare(
1216 "SELECT id FROM persistent.keyentry
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001217 WHERE
1218 key_type = ?
1219 AND domain = ?
1220 AND namespace = ?
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001221 AND alias = ?
1222 AND state = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08001223 )
1224 .context("In get_or_create_key_with: Failed to select from keyentry table.")?;
1225 let mut rows = stmt
1226 .query(params![KeyType::Super, domain.0, namespace, alias, KeyLifeCycle::Live])
1227 .context("In get_or_create_key_with: Failed to query from keyentry table.")?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001228
Janis Danisevskis66784c42021-01-27 08:40:25 -08001229 db_utils::with_rows_extract_one(&mut rows, |row| {
1230 Ok(match row {
1231 Some(r) => r.get(0).context("Failed to unpack id.")?,
1232 None => None,
1233 })
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001234 })
Janis Danisevskis66784c42021-01-27 08:40:25 -08001235 .context("In get_or_create_key_with.")?
1236 };
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001237
Janis Danisevskis66784c42021-01-27 08:40:25 -08001238 let (id, entry) = match id {
1239 Some(id) => (
1240 id,
1241 Self::load_key_components(&tx, KeyEntryLoadBits::KM, id)
1242 .context("In get_or_create_key_with.")?,
1243 ),
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001244
Janis Danisevskis66784c42021-01-27 08:40:25 -08001245 None => {
1246 let id = Self::insert_with_retry(|id| {
1247 tx.execute(
1248 "INSERT into persistent.keyentry
Max Bires8e93d2b2021-01-14 13:17:59 -08001249 (id, key_type, domain, namespace, alias, state, km_uuid)
1250 VALUES(?, ?, ?, ?, ?, ?, ?);",
Janis Danisevskis66784c42021-01-27 08:40:25 -08001251 params![
1252 id,
1253 KeyType::Super,
1254 domain.0,
1255 namespace,
1256 alias,
1257 KeyLifeCycle::Live,
1258 km_uuid,
1259 ],
1260 )
1261 })
1262 .context("In get_or_create_key_with.")?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001263
Janis Danisevskis66784c42021-01-27 08:40:25 -08001264 let (blob, metadata) =
1265 create_new_key().context("In get_or_create_key_with.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001266 Self::set_blob_internal(
1267 &tx,
1268 id,
1269 SubComponentType::KEY_BLOB,
1270 Some(&blob),
1271 Some(&metadata),
1272 )
1273 .context("In get_of_create_key_with.")?;
Janis Danisevskis66784c42021-01-27 08:40:25 -08001274 (
Janis Danisevskis377d1002021-01-27 19:07:48 -08001275 id,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001276 KeyEntry {
1277 id,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001278 key_blob_info: Some((blob, metadata)),
Janis Danisevskis66784c42021-01-27 08:40:25 -08001279 pure_cert: false,
1280 ..Default::default()
1281 },
1282 )
1283 }
1284 };
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001285 Ok((KEY_ID_LOCK.get(id), entry)).no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08001286 })
1287 .context("In get_or_create_key_with.")
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001288 }
1289
Janis Danisevskis66784c42021-01-27 08:40:25 -08001290 /// SQLite3 seems to hold a shared mutex while running the busy handler when
1291 /// waiting for the database file to become available. This makes it
1292 /// impossible to successfully recover from a locked database when the
1293 /// transaction holding the device busy is in the same process on a
1294 /// different connection. As a result the busy handler has to time out and
1295 /// fail in order to make progress.
1296 ///
1297 /// Instead, we set the busy handler to None (return immediately). And catch
1298 /// Busy and Locked errors (the latter occur on in memory databases with
1299 /// shared cache, e.g., the per-boot database.) and restart the transaction
1300 /// after a grace period of half a millisecond.
1301 ///
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001302 /// Creates a transaction with the given behavior and executes f with the new transaction.
Janis Danisevskis66784c42021-01-27 08:40:25 -08001303 /// The transaction is committed only if f returns Ok and retried if DatabaseBusy
1304 /// or DatabaseLocked is encountered.
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001305 fn with_transaction<T, F>(&mut self, behavior: TransactionBehavior, f: F) -> Result<T>
1306 where
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001307 F: Fn(&Transaction) -> Result<(bool, T)>,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001308 {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001309 loop {
1310 match self
1311 .conn
1312 .transaction_with_behavior(behavior)
1313 .context("In with_transaction.")
1314 .and_then(|tx| f(&tx).map(|result| (result, tx)))
1315 .and_then(|(result, tx)| {
1316 tx.commit().context("In with_transaction: Failed to commit transaction.")?;
1317 Ok(result)
1318 }) {
1319 Ok(result) => break Ok(result),
1320 Err(e) => {
1321 if Self::is_locked_error(&e) {
1322 std::thread::sleep(std::time::Duration::from_micros(500));
1323 continue;
1324 } else {
1325 return Err(e).context("In with_transaction.");
1326 }
1327 }
1328 }
1329 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001330 .map(|(need_gc, result)| {
1331 if need_gc {
1332 if let Some(ref gc) = self.gc {
1333 gc.notify_gc();
1334 }
1335 }
1336 result
1337 })
Janis Danisevskis66784c42021-01-27 08:40:25 -08001338 }
1339
1340 fn is_locked_error(e: &anyhow::Error) -> bool {
1341 matches!(e.root_cause().downcast_ref::<rusqlite::ffi::Error>(),
1342 Some(rusqlite::ffi::Error {
1343 code: rusqlite::ErrorCode::DatabaseBusy,
1344 ..
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001345 })
Janis Danisevskis66784c42021-01-27 08:40:25 -08001346 | Some(rusqlite::ffi::Error {
1347 code: rusqlite::ErrorCode::DatabaseLocked,
1348 ..
1349 }))
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001350 }
1351
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001352 /// Creates a new key entry and allocates a new randomized id for the new key.
1353 /// The key id gets associated with a domain and namespace but not with an alias.
1354 /// To complete key generation `rebind_alias` should be called after all of the
1355 /// key artifacts, i.e., blobs and parameters have been associated with the new
1356 /// key id. Finalizing with `rebind_alias` makes the creation of a new key entry
1357 /// atomic even if key generation is not.
Max Bires8e93d2b2021-01-14 13:17:59 -08001358 pub fn create_key_entry(
1359 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001360 domain: &Domain,
1361 namespace: &i64,
Max Bires8e93d2b2021-01-14 13:17:59 -08001362 km_uuid: &Uuid,
1363 ) -> Result<KeyIdGuard> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001364 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001365 Self::create_key_entry_internal(tx, domain, namespace, km_uuid).no_gc()
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001366 })
1367 .context("In create_key_entry.")
1368 }
1369
1370 fn create_key_entry_internal(
1371 tx: &Transaction,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001372 domain: &Domain,
1373 namespace: &i64,
Max Bires8e93d2b2021-01-14 13:17:59 -08001374 km_uuid: &Uuid,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001375 ) -> Result<KeyIdGuard> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001376 match *domain {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001377 Domain::APP | Domain::SELINUX => {}
Joel Galenson0891bc12020-07-20 10:37:03 -07001378 _ => {
1379 return Err(KsError::sys())
1380 .context(format!("Domain {:?} must be either App or SELinux.", domain));
1381 }
1382 }
Janis Danisevskisaec14592020-11-12 09:41:49 -08001383 Ok(KEY_ID_LOCK.get(
1384 Self::insert_with_retry(|id| {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001385 tx.execute(
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001386 "INSERT into persistent.keyentry
Max Bires8e93d2b2021-01-14 13:17:59 -08001387 (id, key_type, domain, namespace, alias, state, km_uuid)
1388 VALUES(?, ?, ?, ?, NULL, ?, ?);",
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001389 params![
1390 id,
1391 KeyType::Client,
1392 domain.0 as u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001393 *namespace,
Max Bires8e93d2b2021-01-14 13:17:59 -08001394 KeyLifeCycle::Existing,
1395 km_uuid,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001396 ],
Janis Danisevskisaec14592020-11-12 09:41:49 -08001397 )
1398 })
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001399 .context("In create_key_entry_internal")?,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001400 ))
Joel Galenson26f4d012020-07-17 14:57:21 -07001401 }
Joel Galenson33c04ad2020-08-03 11:04:38 -07001402
Max Bires2b2e6562020-09-22 11:22:36 -07001403 /// Creates a new attestation key entry and allocates a new randomized id for the new key.
1404 /// The key id gets associated with a domain and namespace later but not with an alias. The
1405 /// alias will be used to denote if a key has been signed as each key can only be bound to one
1406 /// domain and namespace pairing so there is no need to use them as a value for indexing into
1407 /// a key.
1408 pub fn create_attestation_key_entry(
1409 &mut self,
1410 maced_public_key: &[u8],
1411 raw_public_key: &[u8],
1412 private_key: &[u8],
1413 km_uuid: &Uuid,
1414 ) -> Result<()> {
1415 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1416 let key_id = KEY_ID_LOCK.get(
1417 Self::insert_with_retry(|id| {
1418 tx.execute(
1419 "INSERT into persistent.keyentry
1420 (id, key_type, domain, namespace, alias, state, km_uuid)
1421 VALUES(?, ?, NULL, NULL, NULL, ?, ?);",
1422 params![id, KeyType::Attestation, KeyLifeCycle::Live, km_uuid],
1423 )
1424 })
1425 .context("In create_key_entry")?,
1426 );
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001427 Self::set_blob_internal(
1428 &tx,
1429 key_id.0,
1430 SubComponentType::KEY_BLOB,
1431 Some(private_key),
1432 None,
1433 )?;
Max Bires2b2e6562020-09-22 11:22:36 -07001434 let mut metadata = KeyMetaData::new();
1435 metadata.add(KeyMetaEntry::AttestationMacedPublicKey(maced_public_key.to_vec()));
1436 metadata.add(KeyMetaEntry::AttestationRawPubKey(raw_public_key.to_vec()));
1437 metadata.store_in_db(key_id.0, &tx)?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001438 Ok(()).no_gc()
Max Bires2b2e6562020-09-22 11:22:36 -07001439 })
1440 .context("In create_attestation_key_entry")
1441 }
1442
Janis Danisevskis377d1002021-01-27 19:07:48 -08001443 /// Set a new blob and associates it with the given key id. Each blob
1444 /// has a sub component type.
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001445 /// Each key can have one of each sub component type associated. If more
1446 /// are added only the most recent can be retrieved, and superseded blobs
Janis Danisevskis377d1002021-01-27 19:07:48 -08001447 /// will get garbage collected.
1448 /// Components SubComponentType::CERT and SubComponentType::CERT_CHAIN can be
1449 /// removed by setting blob to None.
1450 pub fn set_blob(
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001451 &mut self,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001452 key_id: &KeyIdGuard,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001453 sc_type: SubComponentType,
Janis Danisevskis377d1002021-01-27 19:07:48 -08001454 blob: Option<&[u8]>,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001455 blob_metadata: Option<&BlobMetaData>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001456 ) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001457 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001458 Self::set_blob_internal(&tx, key_id.0, sc_type, blob, blob_metadata).need_gc()
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001459 })
Janis Danisevskis377d1002021-01-27 19:07:48 -08001460 .context("In set_blob.")
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001461 }
1462
Janis Danisevskis377d1002021-01-27 19:07:48 -08001463 fn set_blob_internal(
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001464 tx: &Transaction,
1465 key_id: i64,
1466 sc_type: SubComponentType,
Janis Danisevskis377d1002021-01-27 19:07:48 -08001467 blob: Option<&[u8]>,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001468 blob_metadata: Option<&BlobMetaData>,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001469 ) -> Result<()> {
Janis Danisevskis377d1002021-01-27 19:07:48 -08001470 match (blob, sc_type) {
1471 (Some(blob), _) => {
1472 tx.execute(
1473 "INSERT INTO persistent.blobentry
1474 (subcomponent_type, keyentryid, blob) VALUES (?, ?, ?);",
1475 params![sc_type, key_id, blob],
1476 )
1477 .context("In set_blob_internal: Failed to insert blob.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001478 if let Some(blob_metadata) = blob_metadata {
1479 let blob_id = tx
1480 .query_row("SELECT MAX(id) FROM persistent.blobentry;", NO_PARAMS, |row| {
1481 row.get(0)
1482 })
1483 .context("In set_blob_internal: Failed to get new blob id.")?;
1484 blob_metadata
1485 .store_in_db(blob_id, tx)
1486 .context("In set_blob_internal: Trying to store blob metadata.")?;
1487 }
Janis Danisevskis377d1002021-01-27 19:07:48 -08001488 }
1489 (None, SubComponentType::CERT) | (None, SubComponentType::CERT_CHAIN) => {
1490 tx.execute(
1491 "DELETE FROM persistent.blobentry
1492 WHERE subcomponent_type = ? AND keyentryid = ?;",
1493 params![sc_type, key_id],
1494 )
1495 .context("In set_blob_internal: Failed to delete blob.")?;
1496 }
1497 (None, _) => {
1498 return Err(KsError::sys())
1499 .context("In set_blob_internal: Other blobs cannot be deleted in this way.");
1500 }
1501 }
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001502 Ok(())
1503 }
1504
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001505 /// Inserts a collection of key parameters into the `persistent.keyparameter` table
1506 /// and associates them with the given `key_id`.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001507 #[cfg(test)]
1508 fn insert_keyparameter(&mut self, key_id: &KeyIdGuard, params: &[KeyParameter]) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001509 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001510 Self::insert_keyparameter_internal(tx, key_id, params).no_gc()
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001511 })
1512 .context("In insert_keyparameter.")
1513 }
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001514
Janis Danisevskis66784c42021-01-27 08:40:25 -08001515 fn insert_keyparameter_internal(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001516 tx: &Transaction,
1517 key_id: &KeyIdGuard,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001518 params: &[KeyParameter],
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001519 ) -> Result<()> {
1520 let mut stmt = tx
1521 .prepare(
1522 "INSERT into persistent.keyparameter (keyentryid, tag, data, security_level)
1523 VALUES (?, ?, ?, ?);",
1524 )
1525 .context("In insert_keyparameter_internal: Failed to prepare statement.")?;
1526
Janis Danisevskis66784c42021-01-27 08:40:25 -08001527 for p in params.iter() {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001528 stmt.insert(params![
1529 key_id.0,
1530 p.get_tag().0,
1531 p.key_parameter_value(),
1532 p.security_level().0
1533 ])
1534 .with_context(|| {
1535 format!("In insert_keyparameter_internal: Failed to insert {:?}", p)
1536 })?;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001537 }
1538 Ok(())
1539 }
1540
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001541 /// Insert a set of key entry specific metadata into the database.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001542 #[cfg(test)]
1543 fn insert_key_metadata(&mut self, key_id: &KeyIdGuard, metadata: &KeyMetaData) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001544 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001545 metadata.store_in_db(key_id.0, &tx).no_gc()
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001546 })
1547 .context("In insert_key_metadata.")
1548 }
1549
Max Bires2b2e6562020-09-22 11:22:36 -07001550 /// Stores a signed certificate chain signed by a remote provisioning server, keyed
1551 /// on the public key.
1552 pub fn store_signed_attestation_certificate_chain(
1553 &mut self,
1554 raw_public_key: &[u8],
Max Biresb2e1d032021-02-08 21:35:05 -08001555 batch_cert: &[u8],
Max Bires2b2e6562020-09-22 11:22:36 -07001556 cert_chain: &[u8],
1557 expiration_date: i64,
1558 km_uuid: &Uuid,
1559 ) -> Result<()> {
1560 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1561 let mut stmt = tx
1562 .prepare(
1563 "SELECT keyentryid
1564 FROM persistent.keymetadata
1565 WHERE tag = ? AND data = ? AND keyentryid IN
1566 (SELECT id
1567 FROM persistent.keyentry
1568 WHERE
1569 alias IS NULL AND
1570 domain IS NULL AND
1571 namespace IS NULL AND
1572 key_type = ? AND
1573 km_uuid = ?);",
1574 )
1575 .context("Failed to store attestation certificate chain.")?;
1576 let mut rows = stmt
1577 .query(params![
1578 KeyMetaData::AttestationRawPubKey,
1579 raw_public_key,
1580 KeyType::Attestation,
1581 km_uuid
1582 ])
1583 .context("Failed to fetch keyid")?;
1584 let key_id = db_utils::with_rows_extract_one(&mut rows, |row| {
1585 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?
1586 .get(0)
1587 .context("Failed to unpack id.")
1588 })
1589 .context("Failed to get key_id.")?;
1590 let num_updated = tx
1591 .execute(
1592 "UPDATE persistent.keyentry
1593 SET alias = ?
1594 WHERE id = ?;",
1595 params!["signed", key_id],
1596 )
1597 .context("Failed to update alias.")?;
1598 if num_updated != 1 {
1599 return Err(KsError::sys()).context("Alias not updated for the key.");
1600 }
1601 let mut metadata = KeyMetaData::new();
1602 metadata.add(KeyMetaEntry::AttestationExpirationDate(DateTime::from_millis_epoch(
1603 expiration_date,
1604 )));
1605 metadata.store_in_db(key_id, &tx).context("Failed to insert key metadata.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001606 Self::set_blob_internal(
1607 &tx,
1608 key_id,
1609 SubComponentType::CERT_CHAIN,
1610 Some(cert_chain),
1611 None,
1612 )
1613 .context("Failed to insert cert chain")?;
Max Biresb2e1d032021-02-08 21:35:05 -08001614 Self::set_blob_internal(&tx, key_id, SubComponentType::CERT, Some(batch_cert), None)
1615 .context("Failed to insert cert")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001616 Ok(()).no_gc()
Max Bires2b2e6562020-09-22 11:22:36 -07001617 })
1618 .context("In store_signed_attestation_certificate_chain: ")
1619 }
1620
1621 /// Assigns the next unassigned attestation key to a domain/namespace combo that does not
1622 /// currently have a key assigned to it.
1623 pub fn assign_attestation_key(
1624 &mut self,
1625 domain: Domain,
1626 namespace: i64,
1627 km_uuid: &Uuid,
1628 ) -> Result<()> {
1629 match domain {
1630 Domain::APP | Domain::SELINUX => {}
1631 _ => {
1632 return Err(KsError::sys()).context(format!(
1633 concat!(
1634 "In assign_attestation_key: Domain {:?} ",
1635 "must be either App or SELinux.",
1636 ),
1637 domain
1638 ));
1639 }
1640 }
1641 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1642 let result = tx
1643 .execute(
1644 "UPDATE persistent.keyentry
1645 SET domain=?1, namespace=?2
1646 WHERE
1647 id =
1648 (SELECT MIN(id)
1649 FROM persistent.keyentry
1650 WHERE ALIAS IS NOT NULL
1651 AND domain IS NULL
1652 AND key_type IS ?3
1653 AND state IS ?4
1654 AND km_uuid IS ?5)
1655 AND
1656 (SELECT COUNT(*)
1657 FROM persistent.keyentry
1658 WHERE domain=?1
1659 AND namespace=?2
1660 AND key_type IS ?3
1661 AND state IS ?4
1662 AND km_uuid IS ?5) = 0;",
1663 params![
1664 domain.0 as u32,
1665 namespace,
1666 KeyType::Attestation,
1667 KeyLifeCycle::Live,
1668 km_uuid,
1669 ],
1670 )
1671 .context("Failed to assign attestation key")?;
1672 if result != 1 {
1673 return Err(KsError::sys()).context(format!(
1674 "Expected to update a single entry but instead updated {}.",
1675 result
1676 ));
1677 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001678 Ok(()).no_gc()
Max Bires2b2e6562020-09-22 11:22:36 -07001679 })
1680 .context("In assign_attestation_key: ")
1681 }
1682
1683 /// Retrieves num_keys number of attestation keys that have not yet been signed by a remote
1684 /// provisioning server, or the maximum number available if there are not num_keys number of
1685 /// entries in the table.
1686 pub fn fetch_unsigned_attestation_keys(
1687 &mut self,
1688 num_keys: i32,
1689 km_uuid: &Uuid,
1690 ) -> Result<Vec<Vec<u8>>> {
1691 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1692 let mut stmt = tx
1693 .prepare(
1694 "SELECT data
1695 FROM persistent.keymetadata
1696 WHERE tag = ? AND keyentryid IN
1697 (SELECT id
1698 FROM persistent.keyentry
1699 WHERE
1700 alias IS NULL AND
1701 domain IS NULL AND
1702 namespace IS NULL AND
1703 key_type = ? AND
1704 km_uuid = ?
1705 LIMIT ?);",
1706 )
1707 .context("Failed to prepare statement")?;
1708 let rows = stmt
1709 .query_map(
1710 params![
1711 KeyMetaData::AttestationMacedPublicKey,
1712 KeyType::Attestation,
1713 km_uuid,
1714 num_keys
1715 ],
1716 |row| Ok(row.get(0)?),
1717 )?
1718 .collect::<rusqlite::Result<Vec<Vec<u8>>>>()
1719 .context("Failed to execute statement")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001720 Ok(rows).no_gc()
Max Bires2b2e6562020-09-22 11:22:36 -07001721 })
1722 .context("In fetch_unsigned_attestation_keys")
1723 }
1724
1725 /// Removes any keys that have expired as of the current time. Returns the number of keys
1726 /// marked unreferenced that are bound to be garbage collected.
1727 pub fn delete_expired_attestation_keys(&mut self) -> Result<i32> {
1728 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1729 let mut stmt = tx
1730 .prepare(
1731 "SELECT keyentryid, data
1732 FROM persistent.keymetadata
1733 WHERE tag = ? AND keyentryid IN
1734 (SELECT id
1735 FROM persistent.keyentry
1736 WHERE key_type = ?);",
1737 )
1738 .context("Failed to prepare query")?;
1739 let key_ids_to_check = stmt
1740 .query_map(
1741 params![KeyMetaData::AttestationExpirationDate, KeyType::Attestation],
1742 |row| Ok((row.get(0)?, row.get(1)?)),
1743 )?
1744 .collect::<rusqlite::Result<Vec<(i64, DateTime)>>>()
1745 .context("Failed to get date metadata")?;
1746 let curr_time = DateTime::from_millis_epoch(
1747 SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_millis() as i64,
1748 );
1749 let mut num_deleted = 0;
1750 for id in key_ids_to_check.iter().filter(|kt| kt.1 < curr_time).map(|kt| kt.0) {
1751 if Self::mark_unreferenced(&tx, id)? {
1752 num_deleted += 1;
1753 }
1754 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001755 Ok(num_deleted).do_gc(num_deleted != 0)
Max Bires2b2e6562020-09-22 11:22:36 -07001756 })
1757 .context("In delete_expired_attestation_keys: ")
1758 }
1759
1760 /// Counts the number of keys that will expire by the provided epoch date and the number of
1761 /// keys not currently assigned to a domain.
1762 pub fn get_attestation_pool_status(
1763 &mut self,
1764 date: i64,
1765 km_uuid: &Uuid,
1766 ) -> Result<AttestationPoolStatus> {
1767 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1768 let mut stmt = tx.prepare(
1769 "SELECT data
1770 FROM persistent.keymetadata
1771 WHERE tag = ? AND keyentryid IN
1772 (SELECT id
1773 FROM persistent.keyentry
1774 WHERE alias IS NOT NULL
1775 AND key_type = ?
1776 AND km_uuid = ?
1777 AND state = ?);",
1778 )?;
1779 let times = stmt
1780 .query_map(
1781 params![
1782 KeyMetaData::AttestationExpirationDate,
1783 KeyType::Attestation,
1784 km_uuid,
1785 KeyLifeCycle::Live
1786 ],
1787 |row| Ok(row.get(0)?),
1788 )?
1789 .collect::<rusqlite::Result<Vec<DateTime>>>()
1790 .context("Failed to execute metadata statement")?;
1791 let expiring =
1792 times.iter().filter(|time| time < &&DateTime::from_millis_epoch(date)).count()
1793 as i32;
1794 stmt = tx.prepare(
1795 "SELECT alias, domain
1796 FROM persistent.keyentry
1797 WHERE key_type = ? AND km_uuid = ? AND state = ?;",
1798 )?;
1799 let rows = stmt
1800 .query_map(params![KeyType::Attestation, km_uuid, KeyLifeCycle::Live], |row| {
1801 Ok((row.get(0)?, row.get(1)?))
1802 })?
1803 .collect::<rusqlite::Result<Vec<(Option<String>, Option<u32>)>>>()
1804 .context("Failed to execute keyentry statement")?;
1805 let mut unassigned = 0i32;
1806 let mut attested = 0i32;
1807 let total = rows.len() as i32;
1808 for (alias, domain) in rows {
1809 match (alias, domain) {
1810 (Some(_alias), None) => {
1811 attested += 1;
1812 unassigned += 1;
1813 }
1814 (Some(_alias), Some(_domain)) => {
1815 attested += 1;
1816 }
1817 _ => {}
1818 }
1819 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001820 Ok(AttestationPoolStatus { expiring, unassigned, attested, total }).no_gc()
Max Bires2b2e6562020-09-22 11:22:36 -07001821 })
1822 .context("In get_attestation_pool_status: ")
1823 }
1824
1825 /// Fetches the private key and corresponding certificate chain assigned to a
1826 /// domain/namespace pair. Will either return nothing if the domain/namespace is
1827 /// not assigned, or one CertificateChain.
1828 pub fn retrieve_attestation_key_and_cert_chain(
1829 &mut self,
1830 domain: Domain,
1831 namespace: i64,
1832 km_uuid: &Uuid,
1833 ) -> Result<Option<CertificateChain>> {
1834 match domain {
1835 Domain::APP | Domain::SELINUX => {}
1836 _ => {
1837 return Err(KsError::sys())
1838 .context(format!("Domain {:?} must be either App or SELinux.", domain));
1839 }
1840 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001841 self.with_transaction(TransactionBehavior::Deferred, |tx| {
1842 let mut stmt = tx.prepare(
1843 "SELECT subcomponent_type, blob
Max Bires2b2e6562020-09-22 11:22:36 -07001844 FROM persistent.blobentry
1845 WHERE keyentryid IN
1846 (SELECT id
1847 FROM persistent.keyentry
1848 WHERE key_type = ?
1849 AND domain = ?
1850 AND namespace = ?
1851 AND state = ?
1852 AND km_uuid = ?);",
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001853 )?;
1854 let rows = stmt
1855 .query_map(
1856 params![
1857 KeyType::Attestation,
1858 domain.0 as u32,
1859 namespace,
1860 KeyLifeCycle::Live,
1861 km_uuid
1862 ],
1863 |row| Ok((row.get(0)?, row.get(1)?)),
1864 )?
1865 .collect::<rusqlite::Result<Vec<(SubComponentType, Vec<u8>)>>>()
Max Biresb2e1d032021-02-08 21:35:05 -08001866 .context("query failed.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001867 if rows.is_empty() {
1868 return Ok(None).no_gc();
Max Biresb2e1d032021-02-08 21:35:05 -08001869 } else if rows.len() != 3 {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001870 return Err(KsError::sys()).context(format!(
1871 concat!(
Max Biresb2e1d032021-02-08 21:35:05 -08001872 "Expected to get a single attestation",
1873 "key, cert, and cert chain for a total of 3 entries, but instead got {}."
1874 ),
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001875 rows.len()
1876 ));
Max Bires2b2e6562020-09-22 11:22:36 -07001877 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001878 let mut km_blob: Vec<u8> = Vec::new();
1879 let mut cert_chain_blob: Vec<u8> = Vec::new();
Max Biresb2e1d032021-02-08 21:35:05 -08001880 let mut batch_cert_blob: Vec<u8> = Vec::new();
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001881 for row in rows {
1882 let sub_type: SubComponentType = row.0;
1883 match sub_type {
1884 SubComponentType::KEY_BLOB => {
1885 km_blob = row.1;
1886 }
1887 SubComponentType::CERT_CHAIN => {
1888 cert_chain_blob = row.1;
1889 }
Max Biresb2e1d032021-02-08 21:35:05 -08001890 SubComponentType::CERT => {
1891 batch_cert_blob = row.1;
1892 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001893 _ => Err(KsError::sys()).context("Unknown or incorrect subcomponent type.")?,
1894 }
1895 }
1896 Ok(Some(CertificateChain {
1897 private_key: ZVec::try_from(km_blob)?,
Max Biresb2e1d032021-02-08 21:35:05 -08001898 batch_cert: ZVec::try_from(batch_cert_blob)?,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001899 cert_chain: ZVec::try_from(cert_chain_blob)?,
1900 }))
1901 .no_gc()
1902 })
Max Biresb2e1d032021-02-08 21:35:05 -08001903 .context("In retrieve_attestation_key_and_cert_chain:")
Max Bires2b2e6562020-09-22 11:22:36 -07001904 }
1905
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001906 /// Updates the alias column of the given key id `newid` with the given alias,
1907 /// and atomically, removes the alias, domain, and namespace from another row
1908 /// with the same alias-domain-namespace tuple if such row exits.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001909 /// Returns Ok(true) if an old key was marked unreferenced as a hint to the garbage
1910 /// collector.
1911 fn rebind_alias(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001912 tx: &Transaction,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001913 newid: &KeyIdGuard,
Joel Galenson33c04ad2020-08-03 11:04:38 -07001914 alias: &str,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001915 domain: &Domain,
1916 namespace: &i64,
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001917 ) -> Result<bool> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001918 match *domain {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001919 Domain::APP | Domain::SELINUX => {}
Joel Galenson33c04ad2020-08-03 11:04:38 -07001920 _ => {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001921 return Err(KsError::sys()).context(format!(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001922 "In rebind_alias: Domain {:?} must be either App or SELinux.",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001923 domain
1924 ));
Joel Galenson33c04ad2020-08-03 11:04:38 -07001925 }
1926 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001927 let updated = tx
1928 .execute(
1929 "UPDATE persistent.keyentry
1930 SET alias = NULL, domain = NULL, namespace = NULL, state = ?
Joel Galenson33c04ad2020-08-03 11:04:38 -07001931 WHERE alias = ? AND domain = ? AND namespace = ?;",
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001932 params![KeyLifeCycle::Unreferenced, alias, domain.0 as u32, namespace],
1933 )
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001934 .context("In rebind_alias: Failed to rebind existing entry.")?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07001935 let result = tx
1936 .execute(
1937 "UPDATE persistent.keyentry
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001938 SET alias = ?, state = ?
1939 WHERE id = ? AND domain = ? AND namespace = ? AND state = ?;",
1940 params![
1941 alias,
1942 KeyLifeCycle::Live,
1943 newid.0,
1944 domain.0 as u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001945 *namespace,
Max Bires8e93d2b2021-01-14 13:17:59 -08001946 KeyLifeCycle::Existing,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001947 ],
Joel Galenson33c04ad2020-08-03 11:04:38 -07001948 )
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001949 .context("In rebind_alias: Failed to set alias.")?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07001950 if result != 1 {
Joel Galenson33c04ad2020-08-03 11:04:38 -07001951 return Err(KsError::sys()).context(format!(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001952 "In rebind_alias: Expected to update a single entry but instead updated {}.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07001953 result
1954 ));
1955 }
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001956 Ok(updated != 0)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001957 }
1958
1959 /// Store a new key in a single transaction.
1960 /// The function creates a new key entry, populates the blob, key parameter, and metadata
1961 /// fields, and rebinds the given alias to the new key.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001962 /// The boolean returned is a hint for the garbage collector. If true, a key was replaced,
1963 /// is now unreferenced and needs to be collected.
Janis Danisevskis66784c42021-01-27 08:40:25 -08001964 pub fn store_new_key(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001965 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001966 key: &KeyDescriptor,
1967 params: &[KeyParameter],
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001968 blob_info: &(&[u8], &BlobMetaData),
Max Bires8e93d2b2021-01-14 13:17:59 -08001969 cert_info: &CertificateInfo,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001970 metadata: &KeyMetaData,
Max Bires8e93d2b2021-01-14 13:17:59 -08001971 km_uuid: &Uuid,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001972 ) -> Result<KeyIdGuard> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001973 let (alias, domain, namespace) = match key {
1974 KeyDescriptor { alias: Some(alias), domain: Domain::APP, nspace, blob: None }
1975 | KeyDescriptor { alias: Some(alias), domain: Domain::SELINUX, nspace, blob: None } => {
1976 (alias, key.domain, nspace)
1977 }
1978 _ => {
1979 return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT))
1980 .context("In store_new_key: Need alias and domain must be APP or SELINUX.")
1981 }
1982 };
1983 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001984 let key_id = Self::create_key_entry_internal(tx, &domain, namespace, km_uuid)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001985 .context("Trying to create new key entry.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001986 let (blob, blob_metadata) = *blob_info;
1987 Self::set_blob_internal(
1988 tx,
1989 key_id.id(),
1990 SubComponentType::KEY_BLOB,
1991 Some(blob),
1992 Some(&blob_metadata),
1993 )
1994 .context("Trying to insert the key blob.")?;
Max Bires8e93d2b2021-01-14 13:17:59 -08001995 if let Some(cert) = &cert_info.cert {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001996 Self::set_blob_internal(tx, key_id.id(), SubComponentType::CERT, Some(&cert), None)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001997 .context("Trying to insert the certificate.")?;
1998 }
Max Bires8e93d2b2021-01-14 13:17:59 -08001999 if let Some(cert_chain) = &cert_info.cert_chain {
Janis Danisevskis377d1002021-01-27 19:07:48 -08002000 Self::set_blob_internal(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002001 tx,
2002 key_id.id(),
2003 SubComponentType::CERT_CHAIN,
Janis Danisevskis377d1002021-01-27 19:07:48 -08002004 Some(&cert_chain),
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002005 None,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002006 )
2007 .context("Trying to insert the certificate chain.")?;
2008 }
2009 Self::insert_keyparameter_internal(tx, &key_id, params)
2010 .context("Trying to insert key parameters.")?;
Janis Danisevskis377d1002021-01-27 19:07:48 -08002011 metadata.store_in_db(key_id.id(), tx).context("Trying to insert key metadata.")?;
Janis Danisevskis66784c42021-01-27 08:40:25 -08002012 let need_gc = Self::rebind_alias(tx, &key_id, &alias, &domain, namespace)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002013 .context("Trying to rebind alias.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002014 Ok(key_id).do_gc(need_gc)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002015 })
2016 .context("In store_new_key.")
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002017 }
2018
Janis Danisevskis377d1002021-01-27 19:07:48 -08002019 /// Store a new certificate
2020 /// The function creates a new key entry, populates the blob field and metadata, and rebinds
2021 /// the given alias to the new cert.
Max Bires8e93d2b2021-01-14 13:17:59 -08002022 pub fn store_new_certificate(
2023 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002024 key: &KeyDescriptor,
Max Bires8e93d2b2021-01-14 13:17:59 -08002025 cert: &[u8],
2026 km_uuid: &Uuid,
2027 ) -> Result<KeyIdGuard> {
Janis Danisevskis377d1002021-01-27 19:07:48 -08002028 let (alias, domain, namespace) = match key {
2029 KeyDescriptor { alias: Some(alias), domain: Domain::APP, nspace, blob: None }
2030 | KeyDescriptor { alias: Some(alias), domain: Domain::SELINUX, nspace, blob: None } => {
2031 (alias, key.domain, nspace)
2032 }
2033 _ => {
2034 return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT)).context(
2035 "In store_new_certificate: Need alias and domain must be APP or SELINUX.",
2036 )
2037 }
2038 };
2039 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002040 let key_id = Self::create_key_entry_internal(tx, &domain, namespace, km_uuid)
Janis Danisevskis377d1002021-01-27 19:07:48 -08002041 .context("Trying to create new key entry.")?;
2042
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002043 Self::set_blob_internal(
2044 tx,
2045 key_id.id(),
2046 SubComponentType::CERT_CHAIN,
2047 Some(cert),
2048 None,
2049 )
2050 .context("Trying to insert certificate.")?;
Janis Danisevskis377d1002021-01-27 19:07:48 -08002051
2052 let mut metadata = KeyMetaData::new();
2053 metadata.add(KeyMetaEntry::CreationDate(
2054 DateTime::now().context("Trying to make creation time.")?,
2055 ));
2056
2057 metadata.store_in_db(key_id.id(), tx).context("Trying to insert key metadata.")?;
2058
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002059 let need_gc = Self::rebind_alias(tx, &key_id, &alias, &domain, namespace)
Janis Danisevskis377d1002021-01-27 19:07:48 -08002060 .context("Trying to rebind alias.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002061 Ok(key_id).do_gc(need_gc)
Janis Danisevskis377d1002021-01-27 19:07:48 -08002062 })
2063 .context("In store_new_certificate.")
2064 }
2065
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002066 // Helper function loading the key_id given the key descriptor
2067 // tuple comprising domain, namespace, and alias.
2068 // Requires a valid transaction.
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002069 fn load_key_entry_id(tx: &Transaction, key: &KeyDescriptor, key_type: KeyType) -> Result<i64> {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002070 let alias = key
2071 .alias
2072 .as_ref()
2073 .map_or_else(|| Err(KsError::sys()), Ok)
2074 .context("In load_key_entry_id: Alias must be specified.")?;
2075 let mut stmt = tx
2076 .prepare(
2077 "SELECT id FROM persistent.keyentry
2078 WHERE
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00002079 key_type = ?
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002080 AND domain = ?
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002081 AND namespace = ?
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002082 AND alias = ?
2083 AND state = ?;",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002084 )
2085 .context("In load_key_entry_id: Failed to select from keyentry table.")?;
2086 let mut rows = stmt
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002087 .query(params![key_type, key.domain.0 as u32, key.nspace, alias, KeyLifeCycle::Live])
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002088 .context("In load_key_entry_id: Failed to read from keyentry table.")?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002089 db_utils::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002090 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002091 .get(0)
2092 .context("Failed to unpack id.")
2093 })
2094 .context("In load_key_entry_id.")
2095 }
2096
2097 /// This helper function completes the access tuple of a key, which is required
2098 /// to perform access control. The strategy depends on the `domain` field in the
2099 /// key descriptor.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002100 /// * Domain::SELINUX: The access tuple is complete and this function only loads
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002101 /// the key_id for further processing.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002102 /// * Domain::APP: Like Domain::SELINUX, but the tuple is completed by `caller_uid`
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002103 /// which serves as the namespace.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002104 /// * Domain::GRANT: The grant table is queried for the `key_id` and the
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002105 /// `access_vector`.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002106 /// * Domain::KEY_ID: The keyentry table is queried for the owning `domain` and
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002107 /// `namespace`.
2108 /// In each case the information returned is sufficient to perform the access
2109 /// check and the key id can be used to load further key artifacts.
2110 fn load_access_tuple(
2111 tx: &Transaction,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002112 key: &KeyDescriptor,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002113 key_type: KeyType,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002114 caller_uid: u32,
2115 ) -> Result<(i64, KeyDescriptor, Option<KeyPermSet>)> {
2116 match key.domain {
2117 // Domain App or SELinux. In this case we load the key_id from
2118 // the keyentry database for further loading of key components.
2119 // We already have the full access tuple to perform access control.
2120 // The only distinction is that we use the caller_uid instead
2121 // of the caller supplied namespace if the domain field is
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002122 // Domain::APP.
2123 Domain::APP | Domain::SELINUX => {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002124 let mut access_key = key.clone();
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002125 if access_key.domain == Domain::APP {
2126 access_key.nspace = caller_uid as i64;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002127 }
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002128 let key_id = Self::load_key_entry_id(&tx, &access_key, key_type)
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002129 .with_context(|| format!("With key.domain = {:?}.", access_key.domain))?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002130
2131 Ok((key_id, access_key, None))
2132 }
2133
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002134 // Domain::GRANT. In this case we load the key_id and the access_vector
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002135 // from the grant table.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002136 Domain::GRANT => {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002137 let mut stmt = tx
2138 .prepare(
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002139 "SELECT keyentryid, access_vector FROM persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002140 WHERE grantee = ? AND id = ?;",
2141 )
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002142 .context("Domain::GRANT prepare statement failed")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002143 let mut rows = stmt
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002144 .query(params![caller_uid as i64, key.nspace])
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002145 .context("Domain:Grant: query failed.")?;
2146 let (key_id, access_vector): (i64, i32) =
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002147 db_utils::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002148 let r =
2149 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002150 Ok((
2151 r.get(0).context("Failed to unpack key_id.")?,
2152 r.get(1).context("Failed to unpack access_vector.")?,
2153 ))
2154 })
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002155 .context("Domain::GRANT.")?;
Janis Danisevskis66784c42021-01-27 08:40:25 -08002156 Ok((key_id, key.clone(), Some(access_vector.into())))
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002157 }
2158
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002159 // Domain::KEY_ID. In this case we load the domain and namespace from the
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002160 // keyentry database because we need them for access control.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002161 Domain::KEY_ID => {
Janis Danisevskis45760022021-01-19 16:34:10 -08002162 let (domain, namespace): (Domain, i64) = {
2163 let mut stmt = tx
2164 .prepare(
2165 "SELECT domain, namespace FROM persistent.keyentry
2166 WHERE
2167 id = ?
2168 AND state = ?;",
2169 )
2170 .context("Domain::KEY_ID: prepare statement failed")?;
2171 let mut rows = stmt
2172 .query(params![key.nspace, KeyLifeCycle::Live])
2173 .context("Domain::KEY_ID: query failed.")?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002174 db_utils::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002175 let r =
2176 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002177 Ok((
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002178 Domain(r.get(0).context("Failed to unpack domain.")?),
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002179 r.get(1).context("Failed to unpack namespace.")?,
2180 ))
2181 })
Janis Danisevskis45760022021-01-19 16:34:10 -08002182 .context("Domain::KEY_ID.")?
2183 };
2184
2185 // We may use a key by id after loading it by grant.
2186 // In this case we have to check if the caller has a grant for this particular
2187 // key. We can skip this if we already know that the caller is the owner.
2188 // But we cannot know this if domain is anything but App. E.g. in the case
2189 // of Domain::SELINUX we have to speculatively check for grants because we have to
2190 // consult the SEPolicy before we know if the caller is the owner.
2191 let access_vector: Option<KeyPermSet> =
2192 if domain != Domain::APP || namespace != caller_uid as i64 {
2193 let access_vector: Option<i32> = tx
2194 .query_row(
2195 "SELECT access_vector FROM persistent.grant
2196 WHERE grantee = ? AND keyentryid = ?;",
2197 params![caller_uid as i64, key.nspace],
2198 |row| row.get(0),
2199 )
2200 .optional()
2201 .context("Domain::KEY_ID: query grant failed.")?;
2202 access_vector.map(|p| p.into())
2203 } else {
2204 None
2205 };
2206
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002207 let key_id = key.nspace;
Janis Danisevskis66784c42021-01-27 08:40:25 -08002208 let mut access_key: KeyDescriptor = key.clone();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002209 access_key.domain = domain;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002210 access_key.nspace = namespace;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002211
Janis Danisevskis45760022021-01-19 16:34:10 -08002212 Ok((key_id, access_key, access_vector))
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002213 }
2214 _ => Err(anyhow!(KsError::sys())),
2215 }
2216 }
2217
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002218 fn load_blob_components(
2219 key_id: i64,
2220 load_bits: KeyEntryLoadBits,
2221 tx: &Transaction,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002222 ) -> Result<(bool, Option<(Vec<u8>, BlobMetaData)>, Option<Vec<u8>>, Option<Vec<u8>>)> {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002223 let mut stmt = tx
2224 .prepare(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002225 "SELECT MAX(id), subcomponent_type, blob FROM persistent.blobentry
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002226 WHERE keyentryid = ? GROUP BY subcomponent_type;",
2227 )
2228 .context("In load_blob_components: prepare statement failed.")?;
2229
2230 let mut rows =
2231 stmt.query(params![key_id]).context("In load_blob_components: query failed.")?;
2232
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002233 let mut key_blob: Option<(i64, Vec<u8>)> = None;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002234 let mut cert_blob: Option<Vec<u8>> = None;
2235 let mut cert_chain_blob: Option<Vec<u8>> = None;
Janis Danisevskis377d1002021-01-27 19:07:48 -08002236 let mut has_km_blob: bool = false;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002237 db_utils::with_rows_extract_all(&mut rows, |row| {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002238 let sub_type: SubComponentType =
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002239 row.get(1).context("Failed to extract subcomponent_type.")?;
Janis Danisevskis377d1002021-01-27 19:07:48 -08002240 has_km_blob = has_km_blob || sub_type == SubComponentType::KEY_BLOB;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002241 match (sub_type, load_bits.load_public(), load_bits.load_km()) {
2242 (SubComponentType::KEY_BLOB, _, true) => {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002243 key_blob = Some((
2244 row.get(0).context("Failed to extract key blob id.")?,
2245 row.get(2).context("Failed to extract key blob.")?,
2246 ));
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002247 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002248 (SubComponentType::CERT, true, _) => {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002249 cert_blob =
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002250 Some(row.get(2).context("Failed to extract public certificate blob.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002251 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002252 (SubComponentType::CERT_CHAIN, true, _) => {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002253 cert_chain_blob =
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002254 Some(row.get(2).context("Failed to extract certificate chain blob.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002255 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002256 (SubComponentType::CERT, _, _)
2257 | (SubComponentType::CERT_CHAIN, _, _)
2258 | (SubComponentType::KEY_BLOB, _, _) => {}
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002259 _ => Err(KsError::sys()).context("Unknown subcomponent type.")?,
2260 }
2261 Ok(())
2262 })
2263 .context("In load_blob_components.")?;
2264
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002265 let blob_info = key_blob.map_or::<Result<_>, _>(Ok(None), |(blob_id, blob)| {
2266 Ok(Some((
2267 blob,
2268 BlobMetaData::load_from_db(blob_id, tx)
2269 .context("In load_blob_components: Trying to load blob_metadata.")?,
2270 )))
2271 })?;
2272
2273 Ok((has_km_blob, blob_info, cert_blob, cert_chain_blob))
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002274 }
2275
2276 fn load_key_parameters(key_id: i64, tx: &Transaction) -> Result<Vec<KeyParameter>> {
2277 let mut stmt = tx
2278 .prepare(
2279 "SELECT tag, data, security_level from persistent.keyparameter
2280 WHERE keyentryid = ?;",
2281 )
2282 .context("In load_key_parameters: prepare statement failed.")?;
2283
2284 let mut parameters: Vec<KeyParameter> = Vec::new();
2285
2286 let mut rows =
2287 stmt.query(params![key_id]).context("In load_key_parameters: query failed.")?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002288 db_utils::with_rows_extract_all(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002289 let tag = Tag(row.get(0).context("Failed to read tag.")?);
2290 let sec_level = SecurityLevel(row.get(2).context("Failed to read sec_level.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002291 parameters.push(
2292 KeyParameter::new_from_sql(tag, &SqlField::new(1, &row), sec_level)
2293 .context("Failed to read KeyParameter.")?,
2294 );
2295 Ok(())
2296 })
2297 .context("In load_key_parameters.")?;
2298
2299 Ok(parameters)
2300 }
2301
Qi Wub9433b52020-12-01 14:52:46 +08002302 /// Decrements the usage count of a limited use key. This function first checks whether the
2303 /// usage has been exhausted, if not, decreases the usage count. If the usage count reaches
2304 /// zero, the key also gets marked unreferenced and scheduled for deletion.
2305 /// Returns Ok(true) if the key was marked unreferenced as a hint to the garbage collector.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002306 pub fn check_and_update_key_usage_count(&mut self, key_id: i64) -> Result<()> {
Qi Wub9433b52020-12-01 14:52:46 +08002307 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2308 let limit: Option<i32> = tx
2309 .query_row(
2310 "SELECT data FROM persistent.keyparameter WHERE keyentryid = ? AND tag = ?;",
2311 params![key_id, Tag::USAGE_COUNT_LIMIT.0],
2312 |row| row.get(0),
2313 )
2314 .optional()
2315 .context("Trying to load usage count")?;
2316
2317 let limit = limit
2318 .ok_or(KsError::Km(ErrorCode::INVALID_KEY_BLOB))
2319 .context("The Key no longer exists. Key is exhausted.")?;
2320
2321 tx.execute(
2322 "UPDATE persistent.keyparameter
2323 SET data = data - 1
2324 WHERE keyentryid = ? AND tag = ? AND data > 0;",
2325 params![key_id, Tag::USAGE_COUNT_LIMIT.0],
2326 )
2327 .context("Failed to update key usage count.")?;
2328
2329 match limit {
2330 1 => Self::mark_unreferenced(tx, key_id)
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002331 .map(|need_gc| (need_gc, ()))
Qi Wub9433b52020-12-01 14:52:46 +08002332 .context("Trying to mark limited use key for deletion."),
2333 0 => Err(KsError::Km(ErrorCode::INVALID_KEY_BLOB)).context("Key is exhausted."),
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002334 _ => Ok(()).no_gc(),
Qi Wub9433b52020-12-01 14:52:46 +08002335 }
2336 })
2337 .context("In check_and_update_key_usage_count.")
2338 }
2339
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002340 /// Load a key entry by the given key descriptor.
2341 /// It uses the `check_permission` callback to verify if the access is allowed
2342 /// given the key access tuple read from the database using `load_access_tuple`.
2343 /// With `load_bits` the caller may specify which blobs shall be loaded from
2344 /// the blob database.
2345 pub fn load_key_entry(
2346 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002347 key: &KeyDescriptor,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002348 key_type: KeyType,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002349 load_bits: KeyEntryLoadBits,
2350 caller_uid: u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002351 check_permission: impl Fn(&KeyDescriptor, Option<KeyPermSet>) -> Result<()>,
2352 ) -> Result<(KeyIdGuard, KeyEntry)> {
2353 loop {
2354 match self.load_key_entry_internal(
2355 key,
2356 key_type,
2357 load_bits,
2358 caller_uid,
2359 &check_permission,
2360 ) {
2361 Ok(result) => break Ok(result),
2362 Err(e) => {
2363 if Self::is_locked_error(&e) {
2364 std::thread::sleep(std::time::Duration::from_micros(500));
2365 continue;
2366 } else {
2367 return Err(e).context("In load_key_entry.");
2368 }
2369 }
2370 }
2371 }
2372 }
2373
2374 fn load_key_entry_internal(
2375 &mut self,
2376 key: &KeyDescriptor,
2377 key_type: KeyType,
2378 load_bits: KeyEntryLoadBits,
2379 caller_uid: u32,
2380 check_permission: &impl Fn(&KeyDescriptor, Option<KeyPermSet>) -> Result<()>,
Janis Danisevskisaec14592020-11-12 09:41:49 -08002381 ) -> Result<(KeyIdGuard, KeyEntry)> {
2382 // KEY ID LOCK 1/2
2383 // If we got a key descriptor with a key id we can get the lock right away.
2384 // Otherwise we have to defer it until we know the key id.
2385 let key_id_guard = match key.domain {
2386 Domain::KEY_ID => Some(KEY_ID_LOCK.get(key.nspace)),
2387 _ => None,
2388 };
2389
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002390 let tx = self
2391 .conn
Janis Danisevskisaec14592020-11-12 09:41:49 -08002392 .unchecked_transaction()
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002393 .context("In load_key_entry: Failed to initialize transaction.")?;
2394
2395 // Load the key_id and complete the access control tuple.
2396 let (key_id, access_key_descriptor, access_vector) =
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002397 Self::load_access_tuple(&tx, key, key_type, caller_uid)
2398 .context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002399
2400 // Perform access control. It is vital that we return here if the permission is denied.
2401 // So do not touch that '?' at the end.
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002402 check_permission(&access_key_descriptor, access_vector).context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002403
Janis Danisevskisaec14592020-11-12 09:41:49 -08002404 // KEY ID LOCK 2/2
2405 // If we did not get a key id lock by now, it was because we got a key descriptor
2406 // without a key id. At this point we got the key id, so we can try and get a lock.
2407 // However, we cannot block here, because we are in the middle of the transaction.
2408 // So first we try to get the lock non blocking. If that fails, we roll back the
2409 // transaction and block until we get the lock. After we successfully got the lock,
2410 // we start a new transaction and load the access tuple again.
2411 //
2412 // We don't need to perform access control again, because we already established
2413 // that the caller had access to the given key. But we need to make sure that the
2414 // key id still exists. So we have to load the key entry by key id this time.
2415 let (key_id_guard, tx) = match key_id_guard {
2416 None => match KEY_ID_LOCK.try_get(key_id) {
2417 None => {
2418 // Roll back the transaction.
2419 tx.rollback().context("In load_key_entry: Failed to roll back transaction.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002420
Janis Danisevskisaec14592020-11-12 09:41:49 -08002421 // Block until we have a key id lock.
2422 let key_id_guard = KEY_ID_LOCK.get(key_id);
2423
2424 // Create a new transaction.
Janis Danisevskis66784c42021-01-27 08:40:25 -08002425 let tx = self
2426 .conn
2427 .unchecked_transaction()
2428 .context("In load_key_entry: Failed to initialize transaction.")?;
Janis Danisevskisaec14592020-11-12 09:41:49 -08002429
2430 Self::load_access_tuple(
2431 &tx,
2432 // This time we have to load the key by the retrieved key id, because the
2433 // alias may have been rebound after we rolled back the transaction.
Janis Danisevskis66784c42021-01-27 08:40:25 -08002434 &KeyDescriptor {
Janis Danisevskisaec14592020-11-12 09:41:49 -08002435 domain: Domain::KEY_ID,
2436 nspace: key_id,
2437 ..Default::default()
2438 },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002439 key_type,
Janis Danisevskisaec14592020-11-12 09:41:49 -08002440 caller_uid,
2441 )
2442 .context("In load_key_entry. (deferred key lock)")?;
2443 (key_id_guard, tx)
2444 }
2445 Some(l) => (l, tx),
2446 },
2447 Some(key_id_guard) => (key_id_guard, tx),
2448 };
2449
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002450 let key_entry = Self::load_key_components(&tx, load_bits, key_id_guard.id())
2451 .context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002452
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002453 tx.commit().context("In load_key_entry: Failed to commit transaction.")?;
2454
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002455 Ok((key_id_guard, key_entry))
2456 }
2457
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002458 fn mark_unreferenced(tx: &Transaction, key_id: i64) -> Result<bool> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002459 let updated = tx
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002460 .execute("DELETE FROM persistent.keyentry WHERE id = ?;", params![key_id])
2461 .context("Trying to delete keyentry.")?;
2462 tx.execute("DELETE FROM persistent.keymetadata WHERE keyentryid = ?;", params![key_id])
2463 .context("Trying to delete keymetadata.")?;
2464 tx.execute("DELETE FROM persistent.keyparameter WHERE keyentryid = ?;", params![key_id])
2465 .context("Trying to delete keyparameters.")?;
2466 tx.execute("DELETE FROM persistent.grant WHERE keyentryid = ?;", params![key_id])
2467 .context("Trying to delete grants.")?;
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002468 Ok(updated != 0)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002469 }
2470
2471 /// Marks the given key as unreferenced and removes all of the grants to this key.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002472 /// Returns Ok(true) if a key was marked unreferenced as a hint for the garbage collector.
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002473 pub fn unbind_key(
2474 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002475 key: &KeyDescriptor,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002476 key_type: KeyType,
2477 caller_uid: u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002478 check_permission: impl Fn(&KeyDescriptor, Option<KeyPermSet>) -> Result<()>,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002479 ) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002480 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2481 let (key_id, access_key_descriptor, access_vector) =
2482 Self::load_access_tuple(tx, key, key_type, caller_uid)
2483 .context("Trying to get access tuple.")?;
2484
2485 // Perform access control. It is vital that we return here if the permission is denied.
2486 // So do not touch that '?' at the end.
2487 check_permission(&access_key_descriptor, access_vector)
2488 .context("While checking permission.")?;
2489
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002490 Self::mark_unreferenced(tx, key_id)
2491 .map(|need_gc| (need_gc, ()))
2492 .context("Trying to mark the key unreferenced.")
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002493 })
2494 .context("In unbind_key.")
2495 }
2496
Max Bires8e93d2b2021-01-14 13:17:59 -08002497 fn get_key_km_uuid(tx: &Transaction, key_id: i64) -> Result<Uuid> {
2498 tx.query_row(
2499 "SELECT km_uuid FROM persistent.keyentry WHERE id = ?",
2500 params![key_id],
2501 |row| row.get(0),
2502 )
2503 .context("In get_key_km_uuid.")
2504 }
2505
Hasini Gunasingheda895552021-01-27 19:34:37 +00002506 /// Delete the keys created on behalf of the user, denoted by the user id.
2507 /// Delete all the keys unless 'keep_non_super_encrypted_keys' set to true.
2508 /// Returned boolean is to hint the garbage collector to delete the unbound keys.
2509 /// The caller of this function should notify the gc if the returned value is true.
2510 pub fn unbind_keys_for_user(
2511 &mut self,
2512 user_id: u32,
2513 keep_non_super_encrypted_keys: bool,
2514 ) -> Result<()> {
2515 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2516 let mut stmt = tx
2517 .prepare(&format!(
2518 "SELECT id from persistent.keyentry
2519 WHERE (
2520 key_type = ?
2521 AND domain = ?
2522 AND cast ( (namespace/{aid_user_offset}) as int) = ?
2523 AND state = ?
2524 ) OR (
2525 key_type = ?
2526 AND namespace = ?
2527 AND alias = ?
2528 AND state = ?
2529 );",
2530 aid_user_offset = AID_USER_OFFSET
2531 ))
2532 .context(concat!(
2533 "In unbind_keys_for_user. ",
2534 "Failed to prepare the query to find the keys created by apps."
2535 ))?;
2536
2537 let mut rows = stmt
2538 .query(params![
2539 // WHERE client key:
2540 KeyType::Client,
2541 Domain::APP.0 as u32,
2542 user_id,
2543 KeyLifeCycle::Live,
2544 // OR super key:
2545 KeyType::Super,
2546 user_id,
2547 Self::USER_SUPER_KEY_ALIAS,
2548 KeyLifeCycle::Live
2549 ])
2550 .context("In unbind_keys_for_user. Failed to query the keys created by apps.")?;
2551
2552 let mut key_ids: Vec<i64> = Vec::new();
2553 db_utils::with_rows_extract_all(&mut rows, |row| {
2554 key_ids
2555 .push(row.get(0).context("Failed to read key id of a key created by an app.")?);
2556 Ok(())
2557 })
2558 .context("In unbind_keys_for_user.")?;
2559
2560 let mut notify_gc = false;
2561 for key_id in key_ids {
2562 if keep_non_super_encrypted_keys {
2563 // Load metadata and filter out non-super-encrypted keys.
2564 if let (_, Some((_, blob_metadata)), _, _) =
2565 Self::load_blob_components(key_id, KeyEntryLoadBits::KM, tx)
2566 .context("In unbind_keys_for_user: Trying to load blob info.")?
2567 {
2568 if blob_metadata.encrypted_by().is_none() {
2569 continue;
2570 }
2571 }
2572 }
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +00002573 notify_gc = Self::mark_unreferenced(&tx, key_id)
Hasini Gunasingheda895552021-01-27 19:34:37 +00002574 .context("In unbind_keys_for_user.")?
2575 || notify_gc;
2576 }
2577 Ok(()).do_gc(notify_gc)
2578 })
2579 .context("In unbind_keys_for_user.")
2580 }
2581
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002582 fn load_key_components(
2583 tx: &Transaction,
2584 load_bits: KeyEntryLoadBits,
2585 key_id: i64,
2586 ) -> Result<KeyEntry> {
2587 let metadata = KeyMetaData::load_from_db(key_id, &tx).context("In load_key_components.")?;
2588
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002589 let (has_km_blob, key_blob_info, cert_blob, cert_chain_blob) =
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002590 Self::load_blob_components(key_id, load_bits, &tx)
2591 .context("In load_key_components.")?;
2592
Max Bires8e93d2b2021-01-14 13:17:59 -08002593 let parameters = Self::load_key_parameters(key_id, &tx)
2594 .context("In load_key_components: Trying to load key parameters.")?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002595
Max Bires8e93d2b2021-01-14 13:17:59 -08002596 let km_uuid = Self::get_key_km_uuid(&tx, key_id)
2597 .context("In load_key_components: Trying to get KM uuid.")?;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002598
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002599 Ok(KeyEntry {
2600 id: key_id,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002601 key_blob_info,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002602 cert: cert_blob,
2603 cert_chain: cert_chain_blob,
Max Bires8e93d2b2021-01-14 13:17:59 -08002604 km_uuid,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002605 parameters,
2606 metadata,
Janis Danisevskis377d1002021-01-27 19:07:48 -08002607 pure_cert: !has_km_blob,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002608 })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002609 }
2610
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002611 /// Returns a list of KeyDescriptors in the selected domain/namespace.
2612 /// The key descriptors will have the domain, nspace, and alias field set.
2613 /// Domain must be APP or SELINUX, the caller must make sure of that.
2614 pub fn list(&mut self, domain: Domain, namespace: i64) -> Result<Vec<KeyDescriptor>> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002615 self.with_transaction(TransactionBehavior::Deferred, |tx| {
2616 let mut stmt = tx
2617 .prepare(
2618 "SELECT alias FROM persistent.keyentry
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002619 WHERE domain = ? AND namespace = ? AND alias IS NOT NULL AND state = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08002620 )
2621 .context("In list: Failed to prepare.")?;
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002622
Janis Danisevskis66784c42021-01-27 08:40:25 -08002623 let mut rows = stmt
2624 .query(params![domain.0 as u32, namespace, KeyLifeCycle::Live])
2625 .context("In list: Failed to query.")?;
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002626
Janis Danisevskis66784c42021-01-27 08:40:25 -08002627 let mut descriptors: Vec<KeyDescriptor> = Vec::new();
2628 db_utils::with_rows_extract_all(&mut rows, |row| {
2629 descriptors.push(KeyDescriptor {
2630 domain,
2631 nspace: namespace,
2632 alias: Some(row.get(0).context("Trying to extract alias.")?),
2633 blob: None,
2634 });
2635 Ok(())
2636 })
2637 .context("In list: Failed to extract rows.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002638 Ok(descriptors).no_gc()
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002639 })
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002640 }
2641
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002642 /// Adds a grant to the grant table.
2643 /// Like `load_key_entry` this function loads the access tuple before
2644 /// it uses the callback for a permission check. Upon success,
2645 /// it inserts the `grantee_uid`, `key_id`, and `access_vector` into the
2646 /// grant table. The new row will have a randomized id, which is used as
2647 /// grant id in the namespace field of the resulting KeyDescriptor.
2648 pub fn grant(
2649 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002650 key: &KeyDescriptor,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002651 caller_uid: u32,
2652 grantee_uid: u32,
2653 access_vector: KeyPermSet,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002654 check_permission: impl Fn(&KeyDescriptor, &KeyPermSet) -> Result<()>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002655 ) -> Result<KeyDescriptor> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002656 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2657 // Load the key_id and complete the access control tuple.
2658 // We ignore the access vector here because grants cannot be granted.
2659 // The access vector returned here expresses the permissions the
2660 // grantee has if key.domain == Domain::GRANT. But this vector
2661 // cannot include the grant permission by design, so there is no way the
2662 // subsequent permission check can pass.
2663 // We could check key.domain == Domain::GRANT and fail early.
2664 // But even if we load the access tuple by grant here, the permission
2665 // check denies the attempt to create a grant by grant descriptor.
2666 let (key_id, access_key_descriptor, _) =
2667 Self::load_access_tuple(&tx, key, KeyType::Client, caller_uid)
2668 .context("In grant")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002669
Janis Danisevskis66784c42021-01-27 08:40:25 -08002670 // Perform access control. It is vital that we return here if the permission
2671 // was denied. So do not touch that '?' at the end of the line.
2672 // This permission check checks if the caller has the grant permission
2673 // for the given key and in addition to all of the permissions
2674 // expressed in `access_vector`.
2675 check_permission(&access_key_descriptor, &access_vector)
2676 .context("In grant: check_permission failed.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002677
Janis Danisevskis66784c42021-01-27 08:40:25 -08002678 let grant_id = if let Some(grant_id) = tx
2679 .query_row(
2680 "SELECT id FROM persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002681 WHERE keyentryid = ? AND grantee = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08002682 params![key_id, grantee_uid],
2683 |row| row.get(0),
2684 )
2685 .optional()
2686 .context("In grant: Failed get optional existing grant id.")?
2687 {
2688 tx.execute(
2689 "UPDATE persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002690 SET access_vector = ?
2691 WHERE id = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08002692 params![i32::from(access_vector), grant_id],
Joel Galenson845f74b2020-09-09 14:11:55 -07002693 )
Janis Danisevskis66784c42021-01-27 08:40:25 -08002694 .context("In grant: Failed to update existing grant.")?;
2695 grant_id
2696 } else {
2697 Self::insert_with_retry(|id| {
2698 tx.execute(
2699 "INSERT INTO persistent.grant (id, grantee, keyentryid, access_vector)
2700 VALUES (?, ?, ?, ?);",
2701 params![id, grantee_uid, key_id, i32::from(access_vector)],
2702 )
2703 })
2704 .context("In grant")?
2705 };
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002706
Janis Danisevskis66784c42021-01-27 08:40:25 -08002707 Ok(KeyDescriptor { domain: Domain::GRANT, nspace: grant_id, alias: None, blob: None })
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002708 .no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08002709 })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002710 }
2711
2712 /// This function checks permissions like `grant` and `load_key_entry`
2713 /// before removing a grant from the grant table.
2714 pub fn ungrant(
2715 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002716 key: &KeyDescriptor,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002717 caller_uid: u32,
2718 grantee_uid: u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002719 check_permission: impl Fn(&KeyDescriptor) -> Result<()>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002720 ) -> Result<()> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002721 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2722 // Load the key_id and complete the access control tuple.
2723 // We ignore the access vector here because grants cannot be granted.
2724 let (key_id, access_key_descriptor, _) =
2725 Self::load_access_tuple(&tx, key, KeyType::Client, caller_uid)
2726 .context("In ungrant.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002727
Janis Danisevskis66784c42021-01-27 08:40:25 -08002728 // Perform access control. We must return here if the permission
2729 // was denied. So do not touch the '?' at the end of this line.
2730 check_permission(&access_key_descriptor)
2731 .context("In grant: check_permission failed.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002732
Janis Danisevskis66784c42021-01-27 08:40:25 -08002733 tx.execute(
2734 "DELETE FROM persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002735 WHERE keyentryid = ? AND grantee = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08002736 params![key_id, grantee_uid],
2737 )
2738 .context("Failed to delete grant.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002739
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002740 Ok(()).no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08002741 })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002742 }
2743
Joel Galenson845f74b2020-09-09 14:11:55 -07002744 // Generates a random id and passes it to the given function, which will
2745 // try to insert it into a database. If that insertion fails, retry;
2746 // otherwise return the id.
2747 fn insert_with_retry(inserter: impl Fn(i64) -> rusqlite::Result<usize>) -> Result<i64> {
2748 loop {
2749 let newid: i64 = random();
2750 match inserter(newid) {
2751 // If the id already existed, try again.
2752 Err(rusqlite::Error::SqliteFailure(
2753 libsqlite3_sys::Error {
2754 code: libsqlite3_sys::ErrorCode::ConstraintViolation,
2755 extended_code: libsqlite3_sys::SQLITE_CONSTRAINT_UNIQUE,
2756 },
2757 _,
2758 )) => (),
2759 Err(e) => {
2760 return Err(e).context("In insert_with_retry: failed to insert into database.")
2761 }
2762 _ => return Ok(newid),
2763 }
2764 }
2765 }
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002766
2767 /// Insert or replace the auth token based on the UNIQUE constraint of the auth token table
2768 pub fn insert_auth_token(&mut self, auth_token: &HardwareAuthToken) -> Result<()> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002769 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2770 tx.execute(
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002771 "INSERT OR REPLACE INTO perboot.authtoken (challenge, user_id, auth_id,
2772 authenticator_type, timestamp, mac, time_received) VALUES(?, ?, ?, ?, ?, ?, ?);",
2773 params![
2774 auth_token.challenge,
2775 auth_token.userId,
2776 auth_token.authenticatorId,
2777 auth_token.authenticatorType.0 as i32,
2778 auth_token.timestamp.milliSeconds as i64,
2779 auth_token.mac,
2780 MonotonicRawTime::now(),
2781 ],
2782 )
2783 .context("In insert_auth_token: failed to insert auth token into the database")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002784 Ok(()).no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08002785 })
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002786 }
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002787
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002788 /// Find the newest auth token matching the given predicate.
2789 pub fn find_auth_token_entry<F>(
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002790 &mut self,
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002791 p: F,
2792 ) -> Result<Option<(AuthTokenEntry, MonotonicRawTime)>>
2793 where
2794 F: Fn(&AuthTokenEntry) -> bool,
2795 {
2796 self.with_transaction(TransactionBehavior::Deferred, |tx| {
2797 let mut stmt = tx
2798 .prepare("SELECT * from perboot.authtoken ORDER BY time_received DESC;")
2799 .context("Prepare statement failed.")?;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002800
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002801 let mut rows = stmt.query(NO_PARAMS).context("Failed to query.")?;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002802
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002803 while let Some(row) = rows.next().context("Failed to get next row.")? {
2804 let entry = AuthTokenEntry::new(
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002805 HardwareAuthToken {
2806 challenge: row.get(1)?,
2807 userId: row.get(2)?,
2808 authenticatorId: row.get(3)?,
2809 authenticatorType: HardwareAuthenticatorType(row.get(4)?),
2810 timestamp: Timestamp { milliSeconds: row.get(5)? },
2811 mac: row.get(6)?,
2812 },
2813 row.get(7)?,
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002814 );
2815 if p(&entry) {
2816 return Ok(Some((
2817 entry,
2818 Self::get_last_off_body(tx)
2819 .context("In find_auth_token_entry: Trying to get last off body")?,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002820 )))
2821 .no_gc();
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002822 }
2823 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002824 Ok(None).no_gc()
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002825 })
2826 .context("In find_auth_token_entry.")
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002827 }
2828
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002829 /// Insert last_off_body into the metadata table at the initialization of auth token table
Janis Danisevskis66784c42021-01-27 08:40:25 -08002830 pub fn insert_last_off_body(&mut self, last_off_body: MonotonicRawTime) -> Result<()> {
2831 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2832 tx.execute(
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002833 "INSERT OR REPLACE INTO perboot.metadata (key, value) VALUES (?, ?);",
2834 params!["last_off_body", last_off_body],
2835 )
2836 .context("In insert_last_off_body: failed to insert.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002837 Ok(()).no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08002838 })
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002839 }
2840
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002841 /// Update last_off_body when on_device_off_body is called
Janis Danisevskis66784c42021-01-27 08:40:25 -08002842 pub fn update_last_off_body(&mut self, last_off_body: MonotonicRawTime) -> Result<()> {
2843 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2844 tx.execute(
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002845 "UPDATE perboot.metadata SET value = ? WHERE key = ?;",
2846 params![last_off_body, "last_off_body"],
2847 )
2848 .context("In update_last_off_body: failed to update.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002849 Ok(()).no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08002850 })
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002851 }
2852
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002853 /// Get last_off_body time when finding auth tokens
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002854 fn get_last_off_body(tx: &Transaction) -> Result<MonotonicRawTime> {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002855 tx.query_row(
2856 "SELECT value from perboot.metadata WHERE key = ?;",
2857 params!["last_off_body"],
2858 |row| Ok(row.get(0)?),
2859 )
2860 .context("In get_last_off_body: query_row failed.")
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002861 }
Joel Galenson26f4d012020-07-17 14:57:21 -07002862}
2863
2864#[cfg(test)]
2865mod tests {
2866
2867 use super::*;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002868 use crate::key_parameter::{
2869 Algorithm, BlockMode, Digest, EcCurve, HardwareAuthenticatorType, KeyOrigin, KeyParameter,
2870 KeyParameterValue, KeyPurpose, PaddingMode, SecurityLevel,
2871 };
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002872 use crate::key_perm_set;
2873 use crate::permission::{KeyPerm, KeyPermSet};
Hasini Gunasingheda895552021-01-27 19:34:37 +00002874 use crate::super_key::SuperKeyManager;
Janis Danisevskis2a8330a2021-01-20 15:34:26 -08002875 use keystore2_test_utils::TempDir;
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002876 use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
2877 HardwareAuthToken::HardwareAuthToken,
2878 HardwareAuthenticatorType::HardwareAuthenticatorType as kmhw_authenticator_type,
Janis Danisevskisc3a496b2021-01-05 10:37:22 -08002879 };
2880 use android_hardware_security_secureclock::aidl::android::hardware::security::secureclock::{
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002881 Timestamp::Timestamp,
2882 };
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002883 use rusqlite::NO_PARAMS;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002884 use rusqlite::{Error, TransactionBehavior};
Joel Galenson0891bc12020-07-20 10:37:03 -07002885 use std::cell::RefCell;
Janis Danisevskisaec14592020-11-12 09:41:49 -08002886 use std::sync::atomic::{AtomicU8, Ordering};
2887 use std::sync::Arc;
2888 use std::thread;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002889 use std::time::{Duration, SystemTime};
Janis Danisevskis66784c42021-01-27 08:40:25 -08002890 #[cfg(disabled)]
2891 use std::time::Instant;
Joel Galenson0891bc12020-07-20 10:37:03 -07002892
Janis Danisevskis4df44f42020-08-26 14:40:03 -07002893 fn new_test_db() -> Result<KeystoreDB> {
2894 let conn = KeystoreDB::make_connection("file::memory:", "file::memory:")?;
2895
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002896 let mut db = KeystoreDB { conn, gc: None };
Janis Danisevskis66784c42021-01-27 08:40:25 -08002897 db.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002898 KeystoreDB::init_tables(tx).context("Failed to initialize tables.").no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08002899 })?;
2900 Ok(db)
Janis Danisevskis4df44f42020-08-26 14:40:03 -07002901 }
2902
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002903 fn new_test_db_with_gc<F>(path: &Path, cb: F) -> Result<KeystoreDB>
2904 where
2905 F: Fn(&Uuid, &[u8]) -> Result<()> + Send + 'static,
2906 {
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00002907 let super_key = Arc::new(SuperKeyManager::new());
2908
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002909 let gc_db = KeystoreDB::new(path, None).expect("Failed to open test gc db_connection.");
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00002910 let gc = Gc::new_init_with(Default::default(), move || (Box::new(cb), gc_db, super_key));
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002911
2912 KeystoreDB::new(path, Some(gc))
2913 }
2914
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002915 fn rebind_alias(
2916 db: &mut KeystoreDB,
2917 newid: &KeyIdGuard,
2918 alias: &str,
2919 domain: Domain,
2920 namespace: i64,
2921 ) -> Result<bool> {
2922 db.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002923 KeystoreDB::rebind_alias(tx, newid, alias, &domain, &namespace).no_gc()
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002924 })
2925 .context("In rebind_alias.")
2926 }
2927
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002928 #[test]
2929 fn datetime() -> Result<()> {
2930 let conn = Connection::open_in_memory()?;
2931 conn.execute("CREATE TABLE test (ts DATETIME);", NO_PARAMS)?;
2932 let now = SystemTime::now();
2933 let duration = Duration::from_secs(1000);
2934 let then = now.checked_sub(duration).unwrap();
2935 let soon = now.checked_add(duration).unwrap();
2936 conn.execute(
2937 "INSERT INTO test (ts) VALUES (?), (?), (?);",
2938 params![DateTime::try_from(now)?, DateTime::try_from(then)?, DateTime::try_from(soon)?],
2939 )?;
2940 let mut stmt = conn.prepare("SELECT ts FROM test ORDER BY ts ASC;")?;
2941 let mut rows = stmt.query(NO_PARAMS)?;
2942 assert_eq!(DateTime::try_from(then)?, rows.next()?.unwrap().get(0)?);
2943 assert_eq!(DateTime::try_from(now)?, rows.next()?.unwrap().get(0)?);
2944 assert_eq!(DateTime::try_from(soon)?, rows.next()?.unwrap().get(0)?);
2945 assert!(rows.next()?.is_none());
2946 assert!(DateTime::try_from(then)? < DateTime::try_from(now)?);
2947 assert!(DateTime::try_from(then)? < DateTime::try_from(soon)?);
2948 assert!(DateTime::try_from(now)? < DateTime::try_from(soon)?);
2949 Ok(())
2950 }
2951
Joel Galenson0891bc12020-07-20 10:37:03 -07002952 // Ensure that we're using the "injected" random function, not the real one.
2953 #[test]
2954 fn test_mocked_random() {
2955 let rand1 = random();
2956 let rand2 = random();
2957 let rand3 = random();
2958 if rand1 == rand2 {
2959 assert_eq!(rand2 + 1, rand3);
2960 } else {
2961 assert_eq!(rand1 + 1, rand2);
2962 assert_eq!(rand2, rand3);
2963 }
2964 }
Joel Galenson26f4d012020-07-17 14:57:21 -07002965
Joel Galenson26f4d012020-07-17 14:57:21 -07002966 // Test that we have the correct tables.
2967 #[test]
2968 fn test_tables() -> Result<()> {
Janis Danisevskis4df44f42020-08-26 14:40:03 -07002969 let db = new_test_db()?;
Joel Galenson26f4d012020-07-17 14:57:21 -07002970 let tables = db
2971 .conn
Joel Galenson2aab4432020-07-22 15:27:57 -07002972 .prepare("SELECT name from persistent.sqlite_master WHERE type='table' ORDER BY name;")?
Joel Galenson26f4d012020-07-17 14:57:21 -07002973 .query_map(params![], |row| row.get(0))?
2974 .collect::<rusqlite::Result<Vec<String>>>()?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002975 assert_eq!(tables.len(), 6);
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002976 assert_eq!(tables[0], "blobentry");
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002977 assert_eq!(tables[1], "blobmetadata");
2978 assert_eq!(tables[2], "grant");
2979 assert_eq!(tables[3], "keyentry");
2980 assert_eq!(tables[4], "keymetadata");
2981 assert_eq!(tables[5], "keyparameter");
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002982 let tables = db
2983 .conn
2984 .prepare("SELECT name from perboot.sqlite_master WHERE type='table' ORDER BY name;")?
2985 .query_map(params![], |row| row.get(0))?
2986 .collect::<rusqlite::Result<Vec<String>>>()?;
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002987
2988 assert_eq!(tables.len(), 2);
2989 assert_eq!(tables[0], "authtoken");
2990 assert_eq!(tables[1], "metadata");
Joel Galenson2aab4432020-07-22 15:27:57 -07002991 Ok(())
2992 }
2993
2994 #[test]
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002995 fn test_auth_token_table_invariant() -> Result<()> {
2996 let mut db = new_test_db()?;
2997 let auth_token1 = HardwareAuthToken {
2998 challenge: i64::MAX,
2999 userId: 200,
3000 authenticatorId: 200,
3001 authenticatorType: kmhw_authenticator_type(kmhw_authenticator_type::PASSWORD.0),
3002 timestamp: Timestamp { milliSeconds: 500 },
3003 mac: String::from("mac").into_bytes(),
3004 };
3005 db.insert_auth_token(&auth_token1)?;
3006 let auth_tokens_returned = get_auth_tokens(&mut db)?;
3007 assert_eq!(auth_tokens_returned.len(), 1);
3008
3009 // insert another auth token with the same values for the columns in the UNIQUE constraint
3010 // of the auth token table and different value for timestamp
3011 let auth_token2 = HardwareAuthToken {
3012 challenge: i64::MAX,
3013 userId: 200,
3014 authenticatorId: 200,
3015 authenticatorType: kmhw_authenticator_type(kmhw_authenticator_type::PASSWORD.0),
3016 timestamp: Timestamp { milliSeconds: 600 },
3017 mac: String::from("mac").into_bytes(),
3018 };
3019
3020 db.insert_auth_token(&auth_token2)?;
3021 let mut auth_tokens_returned = get_auth_tokens(&mut db)?;
3022 assert_eq!(auth_tokens_returned.len(), 1);
3023
3024 if let Some(auth_token) = auth_tokens_returned.pop() {
3025 assert_eq!(auth_token.auth_token.timestamp.milliSeconds, 600);
3026 }
3027
3028 // insert another auth token with the different values for the columns in the UNIQUE
3029 // constraint of the auth token table
3030 let auth_token3 = HardwareAuthToken {
3031 challenge: i64::MAX,
3032 userId: 201,
3033 authenticatorId: 200,
3034 authenticatorType: kmhw_authenticator_type(kmhw_authenticator_type::PASSWORD.0),
3035 timestamp: Timestamp { milliSeconds: 600 },
3036 mac: String::from("mac").into_bytes(),
3037 };
3038
3039 db.insert_auth_token(&auth_token3)?;
3040 let auth_tokens_returned = get_auth_tokens(&mut db)?;
3041 assert_eq!(auth_tokens_returned.len(), 2);
3042
3043 Ok(())
3044 }
3045
3046 // utility function for test_auth_token_table_invariant()
3047 fn get_auth_tokens(db: &mut KeystoreDB) -> Result<Vec<AuthTokenEntry>> {
3048 let mut stmt = db.conn.prepare("SELECT * from perboot.authtoken;")?;
3049
3050 let auth_token_entries: Vec<AuthTokenEntry> = stmt
3051 .query_map(NO_PARAMS, |row| {
3052 Ok(AuthTokenEntry::new(
3053 HardwareAuthToken {
3054 challenge: row.get(1)?,
3055 userId: row.get(2)?,
3056 authenticatorId: row.get(3)?,
3057 authenticatorType: HardwareAuthenticatorType(row.get(4)?),
3058 timestamp: Timestamp { milliSeconds: row.get(5)? },
3059 mac: row.get(6)?,
3060 },
3061 row.get(7)?,
3062 ))
3063 })?
3064 .collect::<Result<Vec<AuthTokenEntry>, Error>>()?;
3065 Ok(auth_token_entries)
3066 }
3067
3068 #[test]
Joel Galenson2aab4432020-07-22 15:27:57 -07003069 fn test_persistence_for_files() -> Result<()> {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08003070 let temp_dir = TempDir::new("persistent_db_test")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003071 let mut db = KeystoreDB::new(temp_dir.path(), None)?;
Joel Galenson2aab4432020-07-22 15:27:57 -07003072
Janis Danisevskis66784c42021-01-27 08:40:25 -08003073 db.create_key_entry(&Domain::APP, &100, &KEYSTORE_UUID)?;
Joel Galenson2aab4432020-07-22 15:27:57 -07003074 let entries = get_keyentry(&db)?;
3075 assert_eq!(entries.len(), 1);
Janis Danisevskisbf15d732020-12-08 10:35:26 -08003076
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003077 let db = KeystoreDB::new(temp_dir.path(), None)?;
Joel Galenson2aab4432020-07-22 15:27:57 -07003078
3079 let entries_new = get_keyentry(&db)?;
3080 assert_eq!(entries, entries_new);
3081 Ok(())
3082 }
3083
3084 #[test]
Joel Galenson0891bc12020-07-20 10:37:03 -07003085 fn test_create_key_entry() -> Result<()> {
Max Bires8e93d2b2021-01-14 13:17:59 -08003086 fn extractor(ke: &KeyEntryRow) -> (Domain, i64, Option<&str>, Uuid) {
3087 (ke.domain.unwrap(), ke.namespace.unwrap(), ke.alias.as_deref(), ke.km_uuid.unwrap())
Joel Galenson0891bc12020-07-20 10:37:03 -07003088 }
3089
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003090 let mut db = new_test_db()?;
Joel Galenson0891bc12020-07-20 10:37:03 -07003091
Janis Danisevskis66784c42021-01-27 08:40:25 -08003092 db.create_key_entry(&Domain::APP, &100, &KEYSTORE_UUID)?;
3093 db.create_key_entry(&Domain::SELINUX, &101, &KEYSTORE_UUID)?;
Joel Galenson0891bc12020-07-20 10:37:03 -07003094
3095 let entries = get_keyentry(&db)?;
3096 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08003097 assert_eq!(extractor(&entries[0]), (Domain::APP, 100, None, KEYSTORE_UUID));
3098 assert_eq!(extractor(&entries[1]), (Domain::SELINUX, 101, None, KEYSTORE_UUID));
Joel Galenson0891bc12020-07-20 10:37:03 -07003099
3100 // Test that we must pass in a valid Domain.
3101 check_result_is_error_containing_string(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003102 db.create_key_entry(&Domain::GRANT, &102, &KEYSTORE_UUID),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003103 "Domain Domain(1) must be either App or SELinux.",
Joel Galenson0891bc12020-07-20 10:37:03 -07003104 );
3105 check_result_is_error_containing_string(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003106 db.create_key_entry(&Domain::BLOB, &103, &KEYSTORE_UUID),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003107 "Domain Domain(3) must be either App or SELinux.",
Joel Galenson0891bc12020-07-20 10:37:03 -07003108 );
3109 check_result_is_error_containing_string(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003110 db.create_key_entry(&Domain::KEY_ID, &104, &KEYSTORE_UUID),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003111 "Domain Domain(4) must be either App or SELinux.",
Joel Galenson0891bc12020-07-20 10:37:03 -07003112 );
3113
3114 Ok(())
3115 }
3116
Joel Galenson33c04ad2020-08-03 11:04:38 -07003117 #[test]
Max Bires2b2e6562020-09-22 11:22:36 -07003118 fn test_add_unsigned_key() -> Result<()> {
3119 let mut db = new_test_db()?;
3120 let public_key: Vec<u8> = vec![0x01, 0x02, 0x03];
3121 let private_key: Vec<u8> = vec![0x04, 0x05, 0x06];
3122 let raw_public_key: Vec<u8> = vec![0x07, 0x08, 0x09];
3123 db.create_attestation_key_entry(
3124 &public_key,
3125 &raw_public_key,
3126 &private_key,
3127 &KEYSTORE_UUID,
3128 )?;
3129 let keys = db.fetch_unsigned_attestation_keys(5, &KEYSTORE_UUID)?;
3130 assert_eq!(keys.len(), 1);
3131 assert_eq!(keys[0], public_key);
3132 Ok(())
3133 }
3134
3135 #[test]
3136 fn test_store_signed_attestation_certificate_chain() -> Result<()> {
3137 let mut db = new_test_db()?;
3138 let expiration_date: i64 = 20;
3139 let namespace: i64 = 30;
3140 let base_byte: u8 = 1;
3141 let loaded_values =
3142 load_attestation_key_pool(&mut db, expiration_date, namespace, base_byte)?;
3143 let chain =
3144 db.retrieve_attestation_key_and_cert_chain(Domain::APP, namespace, &KEYSTORE_UUID)?;
3145 assert_eq!(true, chain.is_some());
3146 let cert_chain = chain.unwrap();
Max Biresb2e1d032021-02-08 21:35:05 -08003147 assert_eq!(cert_chain.private_key.to_vec(), loaded_values.priv_key);
3148 assert_eq!(cert_chain.batch_cert.to_vec(), loaded_values.batch_cert);
3149 assert_eq!(cert_chain.cert_chain.to_vec(), loaded_values.cert_chain);
Max Bires2b2e6562020-09-22 11:22:36 -07003150 Ok(())
3151 }
3152
3153 #[test]
3154 fn test_get_attestation_pool_status() -> Result<()> {
3155 let mut db = new_test_db()?;
3156 let namespace: i64 = 30;
3157 load_attestation_key_pool(
3158 &mut db, 10, /* expiration */
3159 namespace, 0x01, /* base_byte */
3160 )?;
3161 load_attestation_key_pool(&mut db, 20 /* expiration */, namespace + 1, 0x02)?;
3162 load_attestation_key_pool(&mut db, 40 /* expiration */, namespace + 2, 0x03)?;
3163 let mut status = db.get_attestation_pool_status(9 /* expiration */, &KEYSTORE_UUID)?;
3164 assert_eq!(status.expiring, 0);
3165 assert_eq!(status.attested, 3);
3166 assert_eq!(status.unassigned, 0);
3167 assert_eq!(status.total, 3);
3168 assert_eq!(
3169 db.get_attestation_pool_status(15 /* expiration */, &KEYSTORE_UUID)?.expiring,
3170 1
3171 );
3172 assert_eq!(
3173 db.get_attestation_pool_status(25 /* expiration */, &KEYSTORE_UUID)?.expiring,
3174 2
3175 );
3176 assert_eq!(
3177 db.get_attestation_pool_status(60 /* expiration */, &KEYSTORE_UUID)?.expiring,
3178 3
3179 );
3180 let public_key: Vec<u8> = vec![0x01, 0x02, 0x03];
3181 let private_key: Vec<u8> = vec![0x04, 0x05, 0x06];
3182 let raw_public_key: Vec<u8> = vec![0x07, 0x08, 0x09];
3183 let cert_chain: Vec<u8> = vec![0x0a, 0x0b, 0x0c];
Max Biresb2e1d032021-02-08 21:35:05 -08003184 let batch_cert: Vec<u8> = vec![0x0d, 0x0e, 0x0f];
Max Bires2b2e6562020-09-22 11:22:36 -07003185 db.create_attestation_key_entry(
3186 &public_key,
3187 &raw_public_key,
3188 &private_key,
3189 &KEYSTORE_UUID,
3190 )?;
3191 status = db.get_attestation_pool_status(0 /* expiration */, &KEYSTORE_UUID)?;
3192 assert_eq!(status.attested, 3);
3193 assert_eq!(status.unassigned, 0);
3194 assert_eq!(status.total, 4);
3195 db.store_signed_attestation_certificate_chain(
3196 &raw_public_key,
Max Biresb2e1d032021-02-08 21:35:05 -08003197 &batch_cert,
Max Bires2b2e6562020-09-22 11:22:36 -07003198 &cert_chain,
3199 20,
3200 &KEYSTORE_UUID,
3201 )?;
3202 status = db.get_attestation_pool_status(0 /* expiration */, &KEYSTORE_UUID)?;
3203 assert_eq!(status.attested, 4);
3204 assert_eq!(status.unassigned, 1);
3205 assert_eq!(status.total, 4);
3206 Ok(())
3207 }
3208
3209 #[test]
3210 fn test_remove_expired_certs() -> Result<()> {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003211 let temp_dir =
3212 TempDir::new("test_remove_expired_certs_").expect("Failed to create temp dir.");
3213 let mut db = new_test_db_with_gc(temp_dir.path(), |_, _| Ok(()))?;
Max Bires2b2e6562020-09-22 11:22:36 -07003214 let expiration_date: i64 =
3215 SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_millis() as i64 + 10000;
3216 let namespace: i64 = 30;
3217 let namespace_del1: i64 = 45;
3218 let namespace_del2: i64 = 60;
3219 let entry_values = load_attestation_key_pool(
3220 &mut db,
3221 expiration_date,
3222 namespace,
3223 0x01, /* base_byte */
3224 )?;
3225 load_attestation_key_pool(&mut db, 45, namespace_del1, 0x02)?;
3226 load_attestation_key_pool(&mut db, 60, namespace_del2, 0x03)?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003227
3228 let blob_entry_row_count: u32 = db
3229 .conn
3230 .query_row("SELECT COUNT(id) FROM persistent.blobentry;", NO_PARAMS, |row| row.get(0))
3231 .expect("Failed to get blob entry row count.");
Max Biresb2e1d032021-02-08 21:35:05 -08003232 // We expect 9 rows here because there are three blobs per attestation key, i.e.,
3233 // one key, one certificate chain, and one certificate.
3234 assert_eq!(blob_entry_row_count, 9);
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003235
Max Bires2b2e6562020-09-22 11:22:36 -07003236 assert_eq!(db.delete_expired_attestation_keys()?, 2);
3237
3238 let mut cert_chain =
3239 db.retrieve_attestation_key_and_cert_chain(Domain::APP, namespace, &KEYSTORE_UUID)?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003240 assert!(cert_chain.is_some());
Max Bires2b2e6562020-09-22 11:22:36 -07003241 let value = cert_chain.unwrap();
Max Biresb2e1d032021-02-08 21:35:05 -08003242 assert_eq!(entry_values.batch_cert, value.batch_cert.to_vec());
3243 assert_eq!(entry_values.cert_chain, value.cert_chain.to_vec());
3244 assert_eq!(entry_values.priv_key, value.private_key.to_vec());
Max Bires2b2e6562020-09-22 11:22:36 -07003245
3246 cert_chain = db.retrieve_attestation_key_and_cert_chain(
3247 Domain::APP,
3248 namespace_del1,
3249 &KEYSTORE_UUID,
3250 )?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003251 assert!(!cert_chain.is_some());
Max Bires2b2e6562020-09-22 11:22:36 -07003252 cert_chain = db.retrieve_attestation_key_and_cert_chain(
3253 Domain::APP,
3254 namespace_del2,
3255 &KEYSTORE_UUID,
3256 )?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003257 assert!(!cert_chain.is_some());
Max Bires2b2e6562020-09-22 11:22:36 -07003258
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003259 // Give the garbage collector half a second to catch up.
3260 std::thread::sleep(Duration::from_millis(500));
Max Bires2b2e6562020-09-22 11:22:36 -07003261
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003262 let blob_entry_row_count: u32 = db
3263 .conn
3264 .query_row("SELECT COUNT(id) FROM persistent.blobentry;", NO_PARAMS, |row| row.get(0))
3265 .expect("Failed to get blob entry row count.");
Max Biresb2e1d032021-02-08 21:35:05 -08003266 // There shound be 3 blob entries left, because we deleted two of the attestation
3267 // key entries with three blobs each.
3268 assert_eq!(blob_entry_row_count, 3);
Max Bires2b2e6562020-09-22 11:22:36 -07003269
Max Bires2b2e6562020-09-22 11:22:36 -07003270 Ok(())
3271 }
3272
3273 #[test]
Joel Galenson33c04ad2020-08-03 11:04:38 -07003274 fn test_rebind_alias() -> Result<()> {
Max Bires8e93d2b2021-01-14 13:17:59 -08003275 fn extractor(
3276 ke: &KeyEntryRow,
3277 ) -> (Option<Domain>, Option<i64>, Option<&str>, Option<Uuid>) {
3278 (ke.domain, ke.namespace, ke.alias.as_deref(), ke.km_uuid)
Joel Galenson33c04ad2020-08-03 11:04:38 -07003279 }
3280
Janis Danisevskis4df44f42020-08-26 14:40:03 -07003281 let mut db = new_test_db()?;
Janis Danisevskis66784c42021-01-27 08:40:25 -08003282 db.create_key_entry(&Domain::APP, &42, &KEYSTORE_UUID)?;
3283 db.create_key_entry(&Domain::APP, &42, &KEYSTORE_UUID)?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07003284 let entries = get_keyentry(&db)?;
3285 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08003286 assert_eq!(
3287 extractor(&entries[0]),
3288 (Some(Domain::APP), Some(42), None, Some(KEYSTORE_UUID))
3289 );
3290 assert_eq!(
3291 extractor(&entries[1]),
3292 (Some(Domain::APP), Some(42), None, Some(KEYSTORE_UUID))
3293 );
Joel Galenson33c04ad2020-08-03 11:04:38 -07003294
3295 // Test that the first call to rebind_alias sets the alias.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003296 rebind_alias(&mut db, &KEY_ID_LOCK.get(entries[0].id), "foo", Domain::APP, 42)?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07003297 let entries = get_keyentry(&db)?;
3298 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08003299 assert_eq!(
3300 extractor(&entries[0]),
3301 (Some(Domain::APP), Some(42), Some("foo"), Some(KEYSTORE_UUID))
3302 );
3303 assert_eq!(
3304 extractor(&entries[1]),
3305 (Some(Domain::APP), Some(42), None, Some(KEYSTORE_UUID))
3306 );
Joel Galenson33c04ad2020-08-03 11:04:38 -07003307
3308 // Test that the second call to rebind_alias also empties the old one.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003309 rebind_alias(&mut db, &KEY_ID_LOCK.get(entries[1].id), "foo", Domain::APP, 42)?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07003310 let entries = get_keyentry(&db)?;
3311 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08003312 assert_eq!(extractor(&entries[0]), (None, None, None, Some(KEYSTORE_UUID)));
3313 assert_eq!(
3314 extractor(&entries[1]),
3315 (Some(Domain::APP), Some(42), Some("foo"), Some(KEYSTORE_UUID))
3316 );
Joel Galenson33c04ad2020-08-03 11:04:38 -07003317
3318 // Test that we must pass in a valid Domain.
3319 check_result_is_error_containing_string(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003320 rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::GRANT, 42),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003321 "Domain Domain(1) must be either App or SELinux.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07003322 );
3323 check_result_is_error_containing_string(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003324 rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::BLOB, 42),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003325 "Domain Domain(3) must be either App or SELinux.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07003326 );
3327 check_result_is_error_containing_string(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003328 rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::KEY_ID, 42),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003329 "Domain Domain(4) must be either App or SELinux.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07003330 );
3331
3332 // Test that we correctly handle setting an alias for something that does not exist.
3333 check_result_is_error_containing_string(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003334 rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::SELINUX, 42),
Joel Galenson33c04ad2020-08-03 11:04:38 -07003335 "Expected to update a single entry but instead updated 0",
3336 );
3337 // Test that we correctly abort the transaction in this case.
3338 let entries = get_keyentry(&db)?;
3339 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08003340 assert_eq!(extractor(&entries[0]), (None, None, None, Some(KEYSTORE_UUID)));
3341 assert_eq!(
3342 extractor(&entries[1]),
3343 (Some(Domain::APP), Some(42), Some("foo"), Some(KEYSTORE_UUID))
3344 );
Joel Galenson33c04ad2020-08-03 11:04:38 -07003345
3346 Ok(())
3347 }
3348
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003349 #[test]
3350 fn test_grant_ungrant() -> Result<()> {
3351 const CALLER_UID: u32 = 15;
3352 const GRANTEE_UID: u32 = 12;
3353 const SELINUX_NAMESPACE: i64 = 7;
3354
3355 let mut db = new_test_db()?;
3356 db.conn.execute(
Max Bires8e93d2b2021-01-14 13:17:59 -08003357 "INSERT INTO persistent.keyentry (id, key_type, domain, namespace, alias, state, km_uuid)
3358 VALUES (1, 0, 0, 15, 'key', 1, ?), (2, 0, 2, 7, 'yek', 1, ?);",
3359 params![KEYSTORE_UUID, KEYSTORE_UUID],
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003360 )?;
3361 let app_key = KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003362 domain: super::Domain::APP,
3363 nspace: 0,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003364 alias: Some("key".to_string()),
3365 blob: None,
3366 };
3367 const PVEC1: KeyPermSet = key_perm_set![KeyPerm::use_(), KeyPerm::get_info()];
3368 const PVEC2: KeyPermSet = key_perm_set![KeyPerm::use_()];
3369
3370 // Reset totally predictable random number generator in case we
3371 // are not the first test running on this thread.
3372 reset_random();
3373 let next_random = 0i64;
3374
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003375 let app_granted_key = db
Janis Danisevskis66784c42021-01-27 08:40:25 -08003376 .grant(&app_key, CALLER_UID, GRANTEE_UID, PVEC1, |k, a| {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003377 assert_eq!(*a, PVEC1);
3378 assert_eq!(
3379 *k,
3380 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003381 domain: super::Domain::APP,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003382 // namespace must be set to the caller_uid.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003383 nspace: CALLER_UID as i64,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003384 alias: Some("key".to_string()),
3385 blob: None,
3386 }
3387 );
3388 Ok(())
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003389 })
3390 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003391
3392 assert_eq!(
3393 app_granted_key,
3394 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003395 domain: super::Domain::GRANT,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003396 // The grantid is next_random due to the mock random number generator.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003397 nspace: next_random,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003398 alias: None,
3399 blob: None,
3400 }
3401 );
3402
3403 let selinux_key = KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003404 domain: super::Domain::SELINUX,
3405 nspace: SELINUX_NAMESPACE,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003406 alias: Some("yek".to_string()),
3407 blob: None,
3408 };
3409
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003410 let selinux_granted_key = db
Janis Danisevskis66784c42021-01-27 08:40:25 -08003411 .grant(&selinux_key, CALLER_UID, 12, PVEC1, |k, a| {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003412 assert_eq!(*a, PVEC1);
3413 assert_eq!(
3414 *k,
3415 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003416 domain: super::Domain::SELINUX,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003417 // namespace must be the supplied SELinux
3418 // namespace.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003419 nspace: SELINUX_NAMESPACE,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003420 alias: Some("yek".to_string()),
3421 blob: None,
3422 }
3423 );
3424 Ok(())
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003425 })
3426 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003427
3428 assert_eq!(
3429 selinux_granted_key,
3430 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003431 domain: super::Domain::GRANT,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003432 // The grantid is next_random + 1 due to the mock random number generator.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003433 nspace: next_random + 1,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003434 alias: None,
3435 blob: None,
3436 }
3437 );
3438
3439 // This should update the existing grant with PVEC2.
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003440 let selinux_granted_key = db
Janis Danisevskis66784c42021-01-27 08:40:25 -08003441 .grant(&selinux_key, CALLER_UID, 12, PVEC2, |k, a| {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003442 assert_eq!(*a, PVEC2);
3443 assert_eq!(
3444 *k,
3445 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003446 domain: super::Domain::SELINUX,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003447 // namespace must be the supplied SELinux
3448 // namespace.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003449 nspace: SELINUX_NAMESPACE,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003450 alias: Some("yek".to_string()),
3451 blob: None,
3452 }
3453 );
3454 Ok(())
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003455 })
3456 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003457
3458 assert_eq!(
3459 selinux_granted_key,
3460 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003461 domain: super::Domain::GRANT,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003462 // Same grant id as before. The entry was only updated.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003463 nspace: next_random + 1,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003464 alias: None,
3465 blob: None,
3466 }
3467 );
3468
3469 {
3470 // Limiting scope of stmt, because it borrows db.
3471 let mut stmt = db
3472 .conn
Janis Danisevskisbf15d732020-12-08 10:35:26 -08003473 .prepare("SELECT id, grantee, keyentryid, access_vector FROM persistent.grant;")?;
Janis Danisevskisee10b5f2020-09-22 16:42:35 -07003474 let mut rows =
3475 stmt.query_map::<(i64, u32, i64, KeyPermSet), _, _>(NO_PARAMS, |row| {
3476 Ok((
3477 row.get(0)?,
3478 row.get(1)?,
3479 row.get(2)?,
3480 KeyPermSet::from(row.get::<_, i32>(3)?),
3481 ))
3482 })?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003483
3484 let r = rows.next().unwrap().unwrap();
Janis Danisevskisee10b5f2020-09-22 16:42:35 -07003485 assert_eq!(r, (next_random, GRANTEE_UID, 1, PVEC1));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003486 let r = rows.next().unwrap().unwrap();
Janis Danisevskisee10b5f2020-09-22 16:42:35 -07003487 assert_eq!(r, (next_random + 1, GRANTEE_UID, 2, PVEC2));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003488 assert!(rows.next().is_none());
3489 }
3490
3491 debug_dump_keyentry_table(&mut db)?;
3492 println!("app_key {:?}", app_key);
3493 println!("selinux_key {:?}", selinux_key);
3494
Janis Danisevskis66784c42021-01-27 08:40:25 -08003495 db.ungrant(&app_key, CALLER_UID, GRANTEE_UID, |_| Ok(()))?;
3496 db.ungrant(&selinux_key, CALLER_UID, GRANTEE_UID, |_| Ok(()))?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003497
3498 Ok(())
3499 }
3500
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003501 static TEST_KEY_BLOB: &[u8] = b"my test blob";
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003502 static TEST_CERT_BLOB: &[u8] = b"my test cert";
3503 static TEST_CERT_CHAIN_BLOB: &[u8] = b"my test cert_chain";
3504
3505 #[test]
Janis Danisevskis377d1002021-01-27 19:07:48 -08003506 fn test_set_blob() -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003507 let key_id = KEY_ID_LOCK.get(3000);
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003508 let mut db = new_test_db()?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003509 let mut blob_metadata = BlobMetaData::new();
3510 blob_metadata.add(BlobMetaEntry::KmUuid(KEYSTORE_UUID));
3511 db.set_blob(
3512 &key_id,
3513 SubComponentType::KEY_BLOB,
3514 Some(TEST_KEY_BLOB),
3515 Some(&blob_metadata),
3516 )?;
3517 db.set_blob(&key_id, SubComponentType::CERT, Some(TEST_CERT_BLOB), None)?;
3518 db.set_blob(&key_id, SubComponentType::CERT_CHAIN, Some(TEST_CERT_CHAIN_BLOB), None)?;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003519 drop(key_id);
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003520
3521 let mut stmt = db.conn.prepare(
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003522 "SELECT subcomponent_type, keyentryid, blob, id FROM persistent.blobentry
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003523 ORDER BY subcomponent_type ASC;",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003524 )?;
3525 let mut rows = stmt
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003526 .query_map::<((SubComponentType, i64, Vec<u8>), i64), _, _>(NO_PARAMS, |row| {
3527 Ok(((row.get(0)?, row.get(1)?, row.get(2)?), row.get(3)?))
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003528 })?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003529 let (r, id) = rows.next().unwrap().unwrap();
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003530 assert_eq!(r, (SubComponentType::KEY_BLOB, 3000, TEST_KEY_BLOB.to_vec()));
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003531 let (r, _) = rows.next().unwrap().unwrap();
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003532 assert_eq!(r, (SubComponentType::CERT, 3000, TEST_CERT_BLOB.to_vec()));
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003533 let (r, _) = rows.next().unwrap().unwrap();
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003534 assert_eq!(r, (SubComponentType::CERT_CHAIN, 3000, TEST_CERT_CHAIN_BLOB.to_vec()));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003535
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003536 drop(rows);
3537 drop(stmt);
3538
3539 assert_eq!(
3540 db.with_transaction(TransactionBehavior::Immediate, |tx| {
3541 BlobMetaData::load_from_db(id, tx).no_gc()
3542 })
3543 .expect("Should find blob metadata."),
3544 blob_metadata
3545 );
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003546 Ok(())
3547 }
3548
3549 static TEST_ALIAS: &str = "my super duper key";
3550
3551 #[test]
3552 fn test_insert_and_load_full_keyentry_domain_app() -> Result<()> {
3553 let mut db = new_test_db()?;
Qi Wub9433b52020-12-01 14:52:46 +08003554 let key_id = make_test_key_entry(&mut db, Domain::APP, 1, TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08003555 .context("test_insert_and_load_full_keyentry_domain_app")?
3556 .0;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003557 let (_key_guard, key_entry) = db
3558 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003559 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003560 domain: Domain::APP,
3561 nspace: 0,
3562 alias: Some(TEST_ALIAS.to_string()),
3563 blob: None,
3564 },
3565 KeyType::Client,
3566 KeyEntryLoadBits::BOTH,
3567 1,
3568 |_k, _av| Ok(()),
3569 )
3570 .unwrap();
Qi Wub9433b52020-12-01 14:52:46 +08003571 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003572
3573 db.unbind_key(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003574 &KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003575 domain: Domain::APP,
3576 nspace: 0,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003577 alias: Some(TEST_ALIAS.to_string()),
3578 blob: None,
3579 },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003580 KeyType::Client,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003581 1,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003582 |_, _| Ok(()),
3583 )
3584 .unwrap();
3585
3586 assert_eq!(
3587 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
3588 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003589 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003590 domain: Domain::APP,
3591 nspace: 0,
3592 alias: Some(TEST_ALIAS.to_string()),
3593 blob: None,
3594 },
3595 KeyType::Client,
3596 KeyEntryLoadBits::NONE,
3597 1,
3598 |_k, _av| Ok(()),
3599 )
3600 .unwrap_err()
3601 .root_cause()
3602 .downcast_ref::<KsError>()
3603 );
3604
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003605 Ok(())
3606 }
3607
3608 #[test]
Janis Danisevskis377d1002021-01-27 19:07:48 -08003609 fn test_insert_and_load_certificate_entry_domain_app() -> Result<()> {
3610 let mut db = new_test_db()?;
3611
3612 db.store_new_certificate(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003613 &KeyDescriptor {
Janis Danisevskis377d1002021-01-27 19:07:48 -08003614 domain: Domain::APP,
3615 nspace: 1,
3616 alias: Some(TEST_ALIAS.to_string()),
3617 blob: None,
3618 },
3619 TEST_CERT_BLOB,
Max Bires8e93d2b2021-01-14 13:17:59 -08003620 &KEYSTORE_UUID,
Janis Danisevskis377d1002021-01-27 19:07:48 -08003621 )
3622 .expect("Trying to insert cert.");
3623
3624 let (_key_guard, mut key_entry) = db
3625 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003626 &KeyDescriptor {
Janis Danisevskis377d1002021-01-27 19:07:48 -08003627 domain: Domain::APP,
3628 nspace: 1,
3629 alias: Some(TEST_ALIAS.to_string()),
3630 blob: None,
3631 },
3632 KeyType::Client,
3633 KeyEntryLoadBits::PUBLIC,
3634 1,
3635 |_k, _av| Ok(()),
3636 )
3637 .expect("Trying to read certificate entry.");
3638
3639 assert!(key_entry.pure_cert());
3640 assert!(key_entry.cert().is_none());
3641 assert_eq!(key_entry.take_cert_chain(), Some(TEST_CERT_BLOB.to_vec()));
3642
3643 db.unbind_key(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003644 &KeyDescriptor {
Janis Danisevskis377d1002021-01-27 19:07:48 -08003645 domain: Domain::APP,
3646 nspace: 1,
3647 alias: Some(TEST_ALIAS.to_string()),
3648 blob: None,
3649 },
3650 KeyType::Client,
3651 1,
3652 |_, _| Ok(()),
3653 )
3654 .unwrap();
3655
3656 assert_eq!(
3657 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
3658 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003659 &KeyDescriptor {
Janis Danisevskis377d1002021-01-27 19:07:48 -08003660 domain: Domain::APP,
3661 nspace: 1,
3662 alias: Some(TEST_ALIAS.to_string()),
3663 blob: None,
3664 },
3665 KeyType::Client,
3666 KeyEntryLoadBits::NONE,
3667 1,
3668 |_k, _av| Ok(()),
3669 )
3670 .unwrap_err()
3671 .root_cause()
3672 .downcast_ref::<KsError>()
3673 );
3674
3675 Ok(())
3676 }
3677
3678 #[test]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003679 fn test_insert_and_load_full_keyentry_domain_selinux() -> Result<()> {
3680 let mut db = new_test_db()?;
Qi Wub9433b52020-12-01 14:52:46 +08003681 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08003682 .context("test_insert_and_load_full_keyentry_domain_selinux")?
3683 .0;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003684 let (_key_guard, key_entry) = db
3685 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003686 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003687 domain: Domain::SELINUX,
3688 nspace: 1,
3689 alias: Some(TEST_ALIAS.to_string()),
3690 blob: None,
3691 },
3692 KeyType::Client,
3693 KeyEntryLoadBits::BOTH,
3694 1,
3695 |_k, _av| Ok(()),
3696 )
3697 .unwrap();
Qi Wub9433b52020-12-01 14:52:46 +08003698 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003699
3700 db.unbind_key(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003701 &KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003702 domain: Domain::SELINUX,
3703 nspace: 1,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003704 alias: Some(TEST_ALIAS.to_string()),
3705 blob: None,
3706 },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003707 KeyType::Client,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003708 1,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003709 |_, _| Ok(()),
3710 )
3711 .unwrap();
3712
3713 assert_eq!(
3714 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
3715 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003716 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003717 domain: Domain::SELINUX,
3718 nspace: 1,
3719 alias: Some(TEST_ALIAS.to_string()),
3720 blob: None,
3721 },
3722 KeyType::Client,
3723 KeyEntryLoadBits::NONE,
3724 1,
3725 |_k, _av| Ok(()),
3726 )
3727 .unwrap_err()
3728 .root_cause()
3729 .downcast_ref::<KsError>()
3730 );
3731
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003732 Ok(())
3733 }
3734
3735 #[test]
3736 fn test_insert_and_load_full_keyentry_domain_key_id() -> Result<()> {
3737 let mut db = new_test_db()?;
Qi Wub9433b52020-12-01 14:52:46 +08003738 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08003739 .context("test_insert_and_load_full_keyentry_domain_key_id")?
3740 .0;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003741 let (_, key_entry) = db
3742 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003743 &KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003744 KeyType::Client,
3745 KeyEntryLoadBits::BOTH,
3746 1,
3747 |_k, _av| Ok(()),
3748 )
3749 .unwrap();
3750
Qi Wub9433b52020-12-01 14:52:46 +08003751 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003752
3753 db.unbind_key(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003754 &KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003755 KeyType::Client,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003756 1,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003757 |_, _| Ok(()),
3758 )
3759 .unwrap();
3760
3761 assert_eq!(
3762 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
3763 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003764 &KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003765 KeyType::Client,
3766 KeyEntryLoadBits::NONE,
3767 1,
3768 |_k, _av| Ok(()),
3769 )
3770 .unwrap_err()
3771 .root_cause()
3772 .downcast_ref::<KsError>()
3773 );
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003774
3775 Ok(())
3776 }
3777
3778 #[test]
Qi Wub9433b52020-12-01 14:52:46 +08003779 fn test_check_and_update_key_usage_count_with_limited_use_key() -> Result<()> {
3780 let mut db = new_test_db()?;
3781 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, Some(123))
3782 .context("test_check_and_update_key_usage_count_with_limited_use_key")?
3783 .0;
3784 // Update the usage count of the limited use key.
3785 db.check_and_update_key_usage_count(key_id)?;
3786
3787 let (_key_guard, key_entry) = db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003788 &KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
Qi Wub9433b52020-12-01 14:52:46 +08003789 KeyType::Client,
3790 KeyEntryLoadBits::BOTH,
3791 1,
3792 |_k, _av| Ok(()),
3793 )?;
3794
3795 // The usage count is decremented now.
3796 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, Some(122)));
3797
3798 Ok(())
3799 }
3800
3801 #[test]
3802 fn test_check_and_update_key_usage_count_with_exhausted_limited_use_key() -> Result<()> {
3803 let mut db = new_test_db()?;
3804 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, Some(1))
3805 .context("test_check_and_update_key_usage_count_with_exhausted_limited_use_key")?
3806 .0;
3807 // Update the usage count of the limited use key.
3808 db.check_and_update_key_usage_count(key_id).expect(concat!(
3809 "In test_check_and_update_key_usage_count_with_exhausted_limited_use_key: ",
3810 "This should succeed."
3811 ));
3812
3813 // Try to update the exhausted limited use key.
3814 let e = db.check_and_update_key_usage_count(key_id).expect_err(concat!(
3815 "In test_check_and_update_key_usage_count_with_exhausted_limited_use_key: ",
3816 "This should fail."
3817 ));
3818 assert_eq!(
3819 &KsError::Km(ErrorCode::INVALID_KEY_BLOB),
3820 e.root_cause().downcast_ref::<KsError>().unwrap()
3821 );
3822
3823 Ok(())
3824 }
3825
3826 #[test]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003827 fn test_insert_and_load_full_keyentry_from_grant() -> Result<()> {
3828 let mut db = new_test_db()?;
Qi Wub9433b52020-12-01 14:52:46 +08003829 let key_id = make_test_key_entry(&mut db, Domain::APP, 1, TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08003830 .context("test_insert_and_load_full_keyentry_from_grant")?
3831 .0;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003832
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003833 let granted_key = db
3834 .grant(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003835 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003836 domain: Domain::APP,
3837 nspace: 0,
3838 alias: Some(TEST_ALIAS.to_string()),
3839 blob: None,
3840 },
3841 1,
3842 2,
3843 key_perm_set![KeyPerm::use_()],
3844 |_k, _av| Ok(()),
3845 )
3846 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003847
3848 debug_dump_grant_table(&mut db)?;
3849
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003850 let (_key_guard, key_entry) = db
Janis Danisevskis66784c42021-01-27 08:40:25 -08003851 .load_key_entry(&granted_key, KeyType::Client, KeyEntryLoadBits::BOTH, 2, |k, av| {
3852 assert_eq!(Domain::GRANT, k.domain);
3853 assert!(av.unwrap().includes(KeyPerm::use_()));
3854 Ok(())
3855 })
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003856 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003857
Qi Wub9433b52020-12-01 14:52:46 +08003858 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003859
Janis Danisevskis66784c42021-01-27 08:40:25 -08003860 db.unbind_key(&granted_key, KeyType::Client, 2, |_, _| Ok(())).unwrap();
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003861
3862 assert_eq!(
3863 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
3864 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003865 &granted_key,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003866 KeyType::Client,
3867 KeyEntryLoadBits::NONE,
3868 2,
3869 |_k, _av| Ok(()),
3870 )
3871 .unwrap_err()
3872 .root_cause()
3873 .downcast_ref::<KsError>()
3874 );
3875
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003876 Ok(())
3877 }
3878
Janis Danisevskis45760022021-01-19 16:34:10 -08003879 // This test attempts to load a key by key id while the caller is not the owner
3880 // but a grant exists for the given key and the caller.
3881 #[test]
3882 fn test_insert_and_load_full_keyentry_from_grant_by_key_id() -> Result<()> {
3883 let mut db = new_test_db()?;
3884 const OWNER_UID: u32 = 1u32;
3885 const GRANTEE_UID: u32 = 2u32;
3886 const SOMEONE_ELSE_UID: u32 = 3u32;
3887 let key_id = make_test_key_entry(&mut db, Domain::APP, OWNER_UID as i64, TEST_ALIAS, None)
3888 .context("test_insert_and_load_full_keyentry_from_grant_by_key_id")?
3889 .0;
3890
3891 db.grant(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003892 &KeyDescriptor {
Janis Danisevskis45760022021-01-19 16:34:10 -08003893 domain: Domain::APP,
3894 nspace: 0,
3895 alias: Some(TEST_ALIAS.to_string()),
3896 blob: None,
3897 },
3898 OWNER_UID,
3899 GRANTEE_UID,
3900 key_perm_set![KeyPerm::use_()],
3901 |_k, _av| Ok(()),
3902 )
3903 .unwrap();
3904
3905 debug_dump_grant_table(&mut db)?;
3906
3907 let id_descriptor =
3908 KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, ..Default::default() };
3909
3910 let (_, key_entry) = db
3911 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003912 &id_descriptor,
Janis Danisevskis45760022021-01-19 16:34:10 -08003913 KeyType::Client,
3914 KeyEntryLoadBits::BOTH,
3915 GRANTEE_UID,
3916 |k, av| {
3917 assert_eq!(Domain::APP, k.domain);
3918 assert_eq!(OWNER_UID as i64, k.nspace);
3919 assert!(av.unwrap().includes(KeyPerm::use_()));
3920 Ok(())
3921 },
3922 )
3923 .unwrap();
3924
3925 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
3926
3927 let (_, key_entry) = db
3928 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003929 &id_descriptor,
Janis Danisevskis45760022021-01-19 16:34:10 -08003930 KeyType::Client,
3931 KeyEntryLoadBits::BOTH,
3932 SOMEONE_ELSE_UID,
3933 |k, av| {
3934 assert_eq!(Domain::APP, k.domain);
3935 assert_eq!(OWNER_UID as i64, k.nspace);
3936 assert!(av.is_none());
3937 Ok(())
3938 },
3939 )
3940 .unwrap();
3941
3942 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
3943
Janis Danisevskis66784c42021-01-27 08:40:25 -08003944 db.unbind_key(&id_descriptor, KeyType::Client, OWNER_UID, |_, _| Ok(())).unwrap();
Janis Danisevskis45760022021-01-19 16:34:10 -08003945
3946 assert_eq!(
3947 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
3948 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003949 &id_descriptor,
Janis Danisevskis45760022021-01-19 16:34:10 -08003950 KeyType::Client,
3951 KeyEntryLoadBits::NONE,
3952 GRANTEE_UID,
3953 |_k, _av| Ok(()),
3954 )
3955 .unwrap_err()
3956 .root_cause()
3957 .downcast_ref::<KsError>()
3958 );
3959
3960 Ok(())
3961 }
3962
Janis Danisevskisaec14592020-11-12 09:41:49 -08003963 static KEY_LOCK_TEST_ALIAS: &str = "my super duper locked key";
3964
Janis Danisevskisaec14592020-11-12 09:41:49 -08003965 #[test]
3966 fn test_insert_and_load_full_keyentry_domain_app_concurrently() -> Result<()> {
3967 let handle = {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08003968 let temp_dir = Arc::new(TempDir::new("id_lock_test")?);
3969 let temp_dir_clone = temp_dir.clone();
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003970 let mut db = KeystoreDB::new(temp_dir.path(), None)?;
Qi Wub9433b52020-12-01 14:52:46 +08003971 let key_id = make_test_key_entry(&mut db, Domain::APP, 33, KEY_LOCK_TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08003972 .context("test_insert_and_load_full_keyentry_domain_app")?
3973 .0;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003974 let (_key_guard, key_entry) = db
3975 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003976 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003977 domain: Domain::APP,
3978 nspace: 0,
3979 alias: Some(KEY_LOCK_TEST_ALIAS.to_string()),
3980 blob: None,
3981 },
3982 KeyType::Client,
3983 KeyEntryLoadBits::BOTH,
3984 33,
3985 |_k, _av| Ok(()),
3986 )
3987 .unwrap();
Qi Wub9433b52020-12-01 14:52:46 +08003988 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskisaec14592020-11-12 09:41:49 -08003989 let state = Arc::new(AtomicU8::new(1));
3990 let state2 = state.clone();
3991
3992 // Spawning a second thread that attempts to acquire the key id lock
3993 // for the same key as the primary thread. The primary thread then
3994 // waits, thereby forcing the secondary thread into the second stage
3995 // of acquiring the lock (see KEY ID LOCK 2/2 above).
3996 // The test succeeds if the secondary thread observes the transition
3997 // of `state` from 1 to 2, despite having a whole second to overtake
3998 // the primary thread.
3999 let handle = thread::spawn(move || {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08004000 let temp_dir = temp_dir_clone;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004001 let mut db = KeystoreDB::new(temp_dir.path(), None).unwrap();
Janis Danisevskisaec14592020-11-12 09:41:49 -08004002 assert!(db
4003 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004004 &KeyDescriptor {
Janis Danisevskisaec14592020-11-12 09:41:49 -08004005 domain: Domain::APP,
4006 nspace: 0,
4007 alias: Some(KEY_LOCK_TEST_ALIAS.to_string()),
4008 blob: None,
4009 },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004010 KeyType::Client,
Janis Danisevskisaec14592020-11-12 09:41:49 -08004011 KeyEntryLoadBits::BOTH,
4012 33,
4013 |_k, _av| Ok(()),
4014 )
4015 .is_ok());
4016 // We should only see a 2 here because we can only return
4017 // from load_key_entry when the `_key_guard` expires,
4018 // which happens at the end of the scope.
4019 assert_eq!(2, state2.load(Ordering::Relaxed));
4020 });
4021
4022 thread::sleep(std::time::Duration::from_millis(1000));
4023
4024 assert_eq!(Ok(1), state.compare_exchange(1, 2, Ordering::Relaxed, Ordering::Relaxed));
4025
4026 // Return the handle from this scope so we can join with the
4027 // secondary thread after the key id lock has expired.
4028 handle
4029 // This is where the `_key_guard` goes out of scope,
4030 // which is the reason for concurrent load_key_entry on the same key
4031 // to unblock.
4032 };
4033 // Join with the secondary thread and unwrap, to propagate failing asserts to the
4034 // main test thread. We will not see failing asserts in secondary threads otherwise.
4035 handle.join().unwrap();
4036 Ok(())
4037 }
4038
Janis Danisevskise92a5e62020-12-02 12:57:41 -08004039 #[test]
Janis Danisevskis66784c42021-01-27 08:40:25 -08004040 fn teset_database_busy_error_code() {
4041 let temp_dir =
4042 TempDir::new("test_database_busy_error_code_").expect("Failed to create temp dir.");
4043
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004044 let mut db1 = KeystoreDB::new(temp_dir.path(), None).expect("Failed to open database1.");
4045 let mut db2 = KeystoreDB::new(temp_dir.path(), None).expect("Failed to open database2.");
Janis Danisevskis66784c42021-01-27 08:40:25 -08004046
4047 let _tx1 = db1
4048 .conn
4049 .transaction_with_behavior(TransactionBehavior::Immediate)
4050 .expect("Failed to create first transaction.");
4051
4052 let error = db2
4053 .conn
4054 .transaction_with_behavior(TransactionBehavior::Immediate)
4055 .context("Transaction begin failed.")
4056 .expect_err("This should fail.");
4057 let root_cause = error.root_cause();
4058 if let Some(rusqlite::ffi::Error { code: rusqlite::ErrorCode::DatabaseBusy, .. }) =
4059 root_cause.downcast_ref::<rusqlite::ffi::Error>()
4060 {
4061 return;
4062 }
4063 panic!(
4064 "Unexpected error {:?} \n{:?} \n{:?}",
4065 error,
4066 root_cause,
4067 root_cause.downcast_ref::<rusqlite::ffi::Error>()
4068 )
4069 }
4070
4071 #[cfg(disabled)]
4072 #[test]
4073 fn test_large_number_of_concurrent_db_manipulations() -> Result<()> {
4074 let temp_dir = Arc::new(
4075 TempDir::new("test_large_number_of_concurrent_db_manipulations_")
4076 .expect("Failed to create temp dir."),
4077 );
4078
4079 let test_begin = Instant::now();
4080
4081 let mut db = KeystoreDB::new(temp_dir.path()).expect("Failed to open database.");
4082 const KEY_COUNT: u32 = 500u32;
4083 const OPEN_DB_COUNT: u32 = 50u32;
4084
4085 let mut actual_key_count = KEY_COUNT;
4086 // First insert KEY_COUNT keys.
4087 for count in 0..KEY_COUNT {
4088 if Instant::now().duration_since(test_begin) >= Duration::from_secs(15) {
4089 actual_key_count = count;
4090 break;
4091 }
4092 let alias = format!("test_alias_{}", count);
4093 make_test_key_entry(&mut db, Domain::APP, 1, &alias, None)
4094 .expect("Failed to make key entry.");
4095 }
4096
4097 // Insert more keys from a different thread and into a different namespace.
4098 let temp_dir1 = temp_dir.clone();
4099 let handle1 = thread::spawn(move || {
4100 let mut db = KeystoreDB::new(temp_dir1.path()).expect("Failed to open database.");
4101
4102 for count in 0..actual_key_count {
4103 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
4104 return;
4105 }
4106 let alias = format!("test_alias_{}", count);
4107 make_test_key_entry(&mut db, Domain::APP, 2, &alias, None)
4108 .expect("Failed to make key entry.");
4109 }
4110
4111 // then unbind them again.
4112 for count in 0..actual_key_count {
4113 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
4114 return;
4115 }
4116 let key = KeyDescriptor {
4117 domain: Domain::APP,
4118 nspace: -1,
4119 alias: Some(format!("test_alias_{}", count)),
4120 blob: None,
4121 };
4122 db.unbind_key(&key, KeyType::Client, 2, |_, _| Ok(())).expect("Unbind Failed.");
4123 }
4124 });
4125
4126 // And start unbinding the first set of keys.
4127 let temp_dir2 = temp_dir.clone();
4128 let handle2 = thread::spawn(move || {
4129 let mut db = KeystoreDB::new(temp_dir2.path()).expect("Failed to open database.");
4130
4131 for count in 0..actual_key_count {
4132 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
4133 return;
4134 }
4135 let key = KeyDescriptor {
4136 domain: Domain::APP,
4137 nspace: -1,
4138 alias: Some(format!("test_alias_{}", count)),
4139 blob: None,
4140 };
4141 db.unbind_key(&key, KeyType::Client, 1, |_, _| Ok(())).expect("Unbind Failed.");
4142 }
4143 });
4144
4145 let stop_deleting = Arc::new(AtomicU8::new(0));
4146 let stop_deleting2 = stop_deleting.clone();
4147
4148 // And delete anything that is unreferenced keys.
4149 let temp_dir3 = temp_dir.clone();
4150 let handle3 = thread::spawn(move || {
4151 let mut db = KeystoreDB::new(temp_dir3.path()).expect("Failed to open database.");
4152
4153 while stop_deleting2.load(Ordering::Relaxed) != 1 {
4154 while let Some((key_guard, _key)) =
4155 db.get_unreferenced_key().expect("Failed to get unreferenced Key.")
4156 {
4157 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
4158 return;
4159 }
4160 db.purge_key_entry(key_guard).expect("Failed to purge key.");
4161 }
4162 std::thread::sleep(std::time::Duration::from_millis(100));
4163 }
4164 });
4165
4166 // While a lot of inserting and deleting is going on we have to open database connections
4167 // successfully and use them.
4168 // This clone is not redundant, because temp_dir needs to be kept alive until db goes
4169 // out of scope.
4170 #[allow(clippy::redundant_clone)]
4171 let temp_dir4 = temp_dir.clone();
4172 let handle4 = thread::spawn(move || {
4173 for count in 0..OPEN_DB_COUNT {
4174 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
4175 return;
4176 }
4177 let mut db = KeystoreDB::new(temp_dir4.path()).expect("Failed to open database.");
4178
4179 let alias = format!("test_alias_{}", count);
4180 make_test_key_entry(&mut db, Domain::APP, 3, &alias, None)
4181 .expect("Failed to make key entry.");
4182 let key = KeyDescriptor {
4183 domain: Domain::APP,
4184 nspace: -1,
4185 alias: Some(alias),
4186 blob: None,
4187 };
4188 db.unbind_key(&key, KeyType::Client, 3, |_, _| Ok(())).expect("Unbind Failed.");
4189 }
4190 });
4191
4192 handle1.join().expect("Thread 1 panicked.");
4193 handle2.join().expect("Thread 2 panicked.");
4194 handle4.join().expect("Thread 4 panicked.");
4195
4196 stop_deleting.store(1, Ordering::Relaxed);
4197 handle3.join().expect("Thread 3 panicked.");
4198
4199 Ok(())
4200 }
4201
4202 #[test]
Janis Danisevskise92a5e62020-12-02 12:57:41 -08004203 fn list() -> Result<()> {
4204 let temp_dir = TempDir::new("list_test")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004205 let mut db = KeystoreDB::new(temp_dir.path(), None)?;
Janis Danisevskise92a5e62020-12-02 12:57:41 -08004206 static LIST_O_ENTRIES: &[(Domain, i64, &str)] = &[
4207 (Domain::APP, 1, "test1"),
4208 (Domain::APP, 1, "test2"),
4209 (Domain::APP, 1, "test3"),
4210 (Domain::APP, 1, "test4"),
4211 (Domain::APP, 1, "test5"),
4212 (Domain::APP, 1, "test6"),
4213 (Domain::APP, 1, "test7"),
4214 (Domain::APP, 2, "test1"),
4215 (Domain::APP, 2, "test2"),
4216 (Domain::APP, 2, "test3"),
4217 (Domain::APP, 2, "test4"),
4218 (Domain::APP, 2, "test5"),
4219 (Domain::APP, 2, "test6"),
4220 (Domain::APP, 2, "test8"),
4221 (Domain::SELINUX, 100, "test1"),
4222 (Domain::SELINUX, 100, "test2"),
4223 (Domain::SELINUX, 100, "test3"),
4224 (Domain::SELINUX, 100, "test4"),
4225 (Domain::SELINUX, 100, "test5"),
4226 (Domain::SELINUX, 100, "test6"),
4227 (Domain::SELINUX, 100, "test9"),
4228 ];
4229
4230 let list_o_keys: Vec<(i64, i64)> = LIST_O_ENTRIES
4231 .iter()
4232 .map(|(domain, ns, alias)| {
Qi Wub9433b52020-12-01 14:52:46 +08004233 let entry = make_test_key_entry(&mut db, *domain, *ns, *alias, None)
4234 .unwrap_or_else(|e| {
Janis Danisevskise92a5e62020-12-02 12:57:41 -08004235 panic!("Failed to insert {:?} {} {}. Error {:?}", domain, ns, alias, e)
4236 });
4237 (entry.id(), *ns)
4238 })
4239 .collect();
4240
4241 for (domain, namespace) in
4242 &[(Domain::APP, 1i64), (Domain::APP, 2i64), (Domain::SELINUX, 100i64)]
4243 {
4244 let mut list_o_descriptors: Vec<KeyDescriptor> = LIST_O_ENTRIES
4245 .iter()
4246 .filter_map(|(domain, ns, alias)| match ns {
4247 ns if *ns == *namespace => Some(KeyDescriptor {
4248 domain: *domain,
4249 nspace: *ns,
4250 alias: Some(alias.to_string()),
4251 blob: None,
4252 }),
4253 _ => None,
4254 })
4255 .collect();
4256 list_o_descriptors.sort();
4257 let mut list_result = db.list(*domain, *namespace)?;
4258 list_result.sort();
4259 assert_eq!(list_o_descriptors, list_result);
4260
4261 let mut list_o_ids: Vec<i64> = list_o_descriptors
4262 .into_iter()
4263 .map(|d| {
4264 let (_, entry) = db
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004265 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004266 &d,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004267 KeyType::Client,
4268 KeyEntryLoadBits::NONE,
4269 *namespace as u32,
4270 |_, _| Ok(()),
4271 )
Janis Danisevskise92a5e62020-12-02 12:57:41 -08004272 .unwrap();
4273 entry.id()
4274 })
4275 .collect();
4276 list_o_ids.sort_unstable();
4277 let mut loaded_entries: Vec<i64> = list_o_keys
4278 .iter()
4279 .filter_map(|(id, ns)| match ns {
4280 ns if *ns == *namespace => Some(*id),
4281 _ => None,
4282 })
4283 .collect();
4284 loaded_entries.sort_unstable();
4285 assert_eq!(list_o_ids, loaded_entries);
4286 }
4287 assert_eq!(Vec::<KeyDescriptor>::new(), db.list(Domain::SELINUX, 101)?);
4288
4289 Ok(())
4290 }
4291
Joel Galenson0891bc12020-07-20 10:37:03 -07004292 // Helpers
4293
4294 // Checks that the given result is an error containing the given string.
4295 fn check_result_is_error_containing_string<T>(result: Result<T>, target: &str) {
4296 let error_str = format!(
4297 "{:#?}",
4298 result.err().unwrap_or_else(|| panic!("Expected the error: {}", target))
4299 );
4300 assert!(
4301 error_str.contains(target),
4302 "The string \"{}\" should contain \"{}\"",
4303 error_str,
4304 target
4305 );
4306 }
4307
Joel Galenson2aab4432020-07-22 15:27:57 -07004308 #[derive(Debug, PartialEq)]
Joel Galenson0891bc12020-07-20 10:37:03 -07004309 #[allow(dead_code)]
4310 struct KeyEntryRow {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004311 id: i64,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004312 key_type: KeyType,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07004313 domain: Option<Domain>,
Joel Galenson0891bc12020-07-20 10:37:03 -07004314 namespace: Option<i64>,
4315 alias: Option<String>,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004316 state: KeyLifeCycle,
Max Bires8e93d2b2021-01-14 13:17:59 -08004317 km_uuid: Option<Uuid>,
Joel Galenson0891bc12020-07-20 10:37:03 -07004318 }
4319
4320 fn get_keyentry(db: &KeystoreDB) -> Result<Vec<KeyEntryRow>> {
4321 db.conn
Joel Galenson2aab4432020-07-22 15:27:57 -07004322 .prepare("SELECT * FROM persistent.keyentry;")?
Joel Galenson0891bc12020-07-20 10:37:03 -07004323 .query_map(NO_PARAMS, |row| {
Joel Galenson0891bc12020-07-20 10:37:03 -07004324 Ok(KeyEntryRow {
4325 id: row.get(0)?,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004326 key_type: row.get(1)?,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07004327 domain: match row.get(2)? {
4328 Some(i) => Some(Domain(i)),
4329 None => None,
4330 },
Joel Galenson0891bc12020-07-20 10:37:03 -07004331 namespace: row.get(3)?,
4332 alias: row.get(4)?,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004333 state: row.get(5)?,
Max Bires8e93d2b2021-01-14 13:17:59 -08004334 km_uuid: row.get(6)?,
Joel Galenson0891bc12020-07-20 10:37:03 -07004335 })
4336 })?
4337 .map(|r| r.context("Could not read keyentry row."))
4338 .collect::<Result<Vec<_>>>()
4339 }
4340
Max Biresb2e1d032021-02-08 21:35:05 -08004341 struct RemoteProvValues {
4342 cert_chain: Vec<u8>,
4343 priv_key: Vec<u8>,
4344 batch_cert: Vec<u8>,
4345 }
4346
Max Bires2b2e6562020-09-22 11:22:36 -07004347 fn load_attestation_key_pool(
4348 db: &mut KeystoreDB,
4349 expiration_date: i64,
4350 namespace: i64,
4351 base_byte: u8,
Max Biresb2e1d032021-02-08 21:35:05 -08004352 ) -> Result<RemoteProvValues> {
Max Bires2b2e6562020-09-22 11:22:36 -07004353 let public_key: Vec<u8> = vec![base_byte, 0x02 * base_byte];
4354 let cert_chain: Vec<u8> = vec![0x03 * base_byte, 0x04 * base_byte];
4355 let priv_key: Vec<u8> = vec![0x05 * base_byte, 0x06 * base_byte];
4356 let raw_public_key: Vec<u8> = vec![0x0b * base_byte, 0x0c * base_byte];
Max Biresb2e1d032021-02-08 21:35:05 -08004357 let batch_cert: Vec<u8> = vec![base_byte * 0x0d, base_byte * 0x0e];
Max Bires2b2e6562020-09-22 11:22:36 -07004358 db.create_attestation_key_entry(&public_key, &raw_public_key, &priv_key, &KEYSTORE_UUID)?;
4359 db.store_signed_attestation_certificate_chain(
4360 &raw_public_key,
Max Biresb2e1d032021-02-08 21:35:05 -08004361 &batch_cert,
Max Bires2b2e6562020-09-22 11:22:36 -07004362 &cert_chain,
4363 expiration_date,
4364 &KEYSTORE_UUID,
4365 )?;
4366 db.assign_attestation_key(Domain::APP, namespace, &KEYSTORE_UUID)?;
Max Biresb2e1d032021-02-08 21:35:05 -08004367 Ok(RemoteProvValues { cert_chain, priv_key, batch_cert })
Max Bires2b2e6562020-09-22 11:22:36 -07004368 }
4369
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07004370 // Note: The parameters and SecurityLevel associations are nonsensical. This
4371 // collection is only used to check if the parameters are preserved as expected by the
4372 // database.
Qi Wub9433b52020-12-01 14:52:46 +08004373 fn make_test_params(max_usage_count: Option<i32>) -> Vec<KeyParameter> {
4374 let mut params = vec![
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07004375 KeyParameter::new(KeyParameterValue::Invalid, SecurityLevel::TRUSTED_ENVIRONMENT),
4376 KeyParameter::new(
4377 KeyParameterValue::KeyPurpose(KeyPurpose::SIGN),
4378 SecurityLevel::TRUSTED_ENVIRONMENT,
4379 ),
4380 KeyParameter::new(
4381 KeyParameterValue::KeyPurpose(KeyPurpose::DECRYPT),
4382 SecurityLevel::TRUSTED_ENVIRONMENT,
4383 ),
4384 KeyParameter::new(
4385 KeyParameterValue::Algorithm(Algorithm::RSA),
4386 SecurityLevel::TRUSTED_ENVIRONMENT,
4387 ),
4388 KeyParameter::new(KeyParameterValue::KeySize(1024), SecurityLevel::TRUSTED_ENVIRONMENT),
4389 KeyParameter::new(
4390 KeyParameterValue::BlockMode(BlockMode::ECB),
4391 SecurityLevel::TRUSTED_ENVIRONMENT,
4392 ),
4393 KeyParameter::new(
4394 KeyParameterValue::BlockMode(BlockMode::GCM),
4395 SecurityLevel::TRUSTED_ENVIRONMENT,
4396 ),
4397 KeyParameter::new(KeyParameterValue::Digest(Digest::NONE), SecurityLevel::STRONGBOX),
4398 KeyParameter::new(
4399 KeyParameterValue::Digest(Digest::MD5),
4400 SecurityLevel::TRUSTED_ENVIRONMENT,
4401 ),
4402 KeyParameter::new(
4403 KeyParameterValue::Digest(Digest::SHA_2_224),
4404 SecurityLevel::TRUSTED_ENVIRONMENT,
4405 ),
4406 KeyParameter::new(
4407 KeyParameterValue::Digest(Digest::SHA_2_256),
4408 SecurityLevel::STRONGBOX,
4409 ),
4410 KeyParameter::new(
4411 KeyParameterValue::PaddingMode(PaddingMode::NONE),
4412 SecurityLevel::TRUSTED_ENVIRONMENT,
4413 ),
4414 KeyParameter::new(
4415 KeyParameterValue::PaddingMode(PaddingMode::RSA_OAEP),
4416 SecurityLevel::TRUSTED_ENVIRONMENT,
4417 ),
4418 KeyParameter::new(
4419 KeyParameterValue::PaddingMode(PaddingMode::RSA_PSS),
4420 SecurityLevel::STRONGBOX,
4421 ),
4422 KeyParameter::new(
4423 KeyParameterValue::PaddingMode(PaddingMode::RSA_PKCS1_1_5_SIGN),
4424 SecurityLevel::TRUSTED_ENVIRONMENT,
4425 ),
4426 KeyParameter::new(KeyParameterValue::CallerNonce, SecurityLevel::TRUSTED_ENVIRONMENT),
4427 KeyParameter::new(KeyParameterValue::MinMacLength(256), SecurityLevel::STRONGBOX),
4428 KeyParameter::new(
4429 KeyParameterValue::EcCurve(EcCurve::P_224),
4430 SecurityLevel::TRUSTED_ENVIRONMENT,
4431 ),
4432 KeyParameter::new(KeyParameterValue::EcCurve(EcCurve::P_256), SecurityLevel::STRONGBOX),
4433 KeyParameter::new(
4434 KeyParameterValue::EcCurve(EcCurve::P_384),
4435 SecurityLevel::TRUSTED_ENVIRONMENT,
4436 ),
4437 KeyParameter::new(
4438 KeyParameterValue::EcCurve(EcCurve::P_521),
4439 SecurityLevel::TRUSTED_ENVIRONMENT,
4440 ),
4441 KeyParameter::new(
4442 KeyParameterValue::RSAPublicExponent(3),
4443 SecurityLevel::TRUSTED_ENVIRONMENT,
4444 ),
4445 KeyParameter::new(
4446 KeyParameterValue::IncludeUniqueID,
4447 SecurityLevel::TRUSTED_ENVIRONMENT,
4448 ),
4449 KeyParameter::new(KeyParameterValue::BootLoaderOnly, SecurityLevel::STRONGBOX),
4450 KeyParameter::new(KeyParameterValue::RollbackResistance, SecurityLevel::STRONGBOX),
4451 KeyParameter::new(
4452 KeyParameterValue::ActiveDateTime(1234567890),
4453 SecurityLevel::STRONGBOX,
4454 ),
4455 KeyParameter::new(
4456 KeyParameterValue::OriginationExpireDateTime(1234567890),
4457 SecurityLevel::TRUSTED_ENVIRONMENT,
4458 ),
4459 KeyParameter::new(
4460 KeyParameterValue::UsageExpireDateTime(1234567890),
4461 SecurityLevel::TRUSTED_ENVIRONMENT,
4462 ),
4463 KeyParameter::new(
4464 KeyParameterValue::MinSecondsBetweenOps(1234567890),
4465 SecurityLevel::TRUSTED_ENVIRONMENT,
4466 ),
4467 KeyParameter::new(
4468 KeyParameterValue::MaxUsesPerBoot(1234567890),
4469 SecurityLevel::TRUSTED_ENVIRONMENT,
4470 ),
4471 KeyParameter::new(KeyParameterValue::UserID(1), SecurityLevel::STRONGBOX),
4472 KeyParameter::new(KeyParameterValue::UserSecureID(42), SecurityLevel::STRONGBOX),
4473 KeyParameter::new(
4474 KeyParameterValue::NoAuthRequired,
4475 SecurityLevel::TRUSTED_ENVIRONMENT,
4476 ),
4477 KeyParameter::new(
4478 KeyParameterValue::HardwareAuthenticatorType(HardwareAuthenticatorType::PASSWORD),
4479 SecurityLevel::TRUSTED_ENVIRONMENT,
4480 ),
4481 KeyParameter::new(KeyParameterValue::AuthTimeout(1234567890), SecurityLevel::SOFTWARE),
4482 KeyParameter::new(KeyParameterValue::AllowWhileOnBody, SecurityLevel::SOFTWARE),
4483 KeyParameter::new(
4484 KeyParameterValue::TrustedUserPresenceRequired,
4485 SecurityLevel::TRUSTED_ENVIRONMENT,
4486 ),
4487 KeyParameter::new(
4488 KeyParameterValue::TrustedConfirmationRequired,
4489 SecurityLevel::TRUSTED_ENVIRONMENT,
4490 ),
4491 KeyParameter::new(
4492 KeyParameterValue::UnlockedDeviceRequired,
4493 SecurityLevel::TRUSTED_ENVIRONMENT,
4494 ),
4495 KeyParameter::new(
4496 KeyParameterValue::ApplicationID(vec![1u8, 2u8, 3u8, 4u8]),
4497 SecurityLevel::SOFTWARE,
4498 ),
4499 KeyParameter::new(
4500 KeyParameterValue::ApplicationData(vec![4u8, 3u8, 2u8, 1u8]),
4501 SecurityLevel::SOFTWARE,
4502 ),
4503 KeyParameter::new(
4504 KeyParameterValue::CreationDateTime(12345677890),
4505 SecurityLevel::SOFTWARE,
4506 ),
4507 KeyParameter::new(
4508 KeyParameterValue::KeyOrigin(KeyOrigin::GENERATED),
4509 SecurityLevel::TRUSTED_ENVIRONMENT,
4510 ),
4511 KeyParameter::new(
4512 KeyParameterValue::RootOfTrust(vec![3u8, 2u8, 1u8, 4u8]),
4513 SecurityLevel::TRUSTED_ENVIRONMENT,
4514 ),
4515 KeyParameter::new(KeyParameterValue::OSVersion(1), SecurityLevel::TRUSTED_ENVIRONMENT),
4516 KeyParameter::new(KeyParameterValue::OSPatchLevel(2), SecurityLevel::SOFTWARE),
4517 KeyParameter::new(
4518 KeyParameterValue::UniqueID(vec![4u8, 3u8, 1u8, 2u8]),
4519 SecurityLevel::SOFTWARE,
4520 ),
4521 KeyParameter::new(
4522 KeyParameterValue::AttestationChallenge(vec![4u8, 3u8, 1u8, 2u8]),
4523 SecurityLevel::TRUSTED_ENVIRONMENT,
4524 ),
4525 KeyParameter::new(
4526 KeyParameterValue::AttestationApplicationID(vec![4u8, 3u8, 1u8, 2u8]),
4527 SecurityLevel::TRUSTED_ENVIRONMENT,
4528 ),
4529 KeyParameter::new(
4530 KeyParameterValue::AttestationIdBrand(vec![4u8, 3u8, 1u8, 2u8]),
4531 SecurityLevel::TRUSTED_ENVIRONMENT,
4532 ),
4533 KeyParameter::new(
4534 KeyParameterValue::AttestationIdDevice(vec![4u8, 3u8, 1u8, 2u8]),
4535 SecurityLevel::TRUSTED_ENVIRONMENT,
4536 ),
4537 KeyParameter::new(
4538 KeyParameterValue::AttestationIdProduct(vec![4u8, 3u8, 1u8, 2u8]),
4539 SecurityLevel::TRUSTED_ENVIRONMENT,
4540 ),
4541 KeyParameter::new(
4542 KeyParameterValue::AttestationIdSerial(vec![4u8, 3u8, 1u8, 2u8]),
4543 SecurityLevel::TRUSTED_ENVIRONMENT,
4544 ),
4545 KeyParameter::new(
4546 KeyParameterValue::AttestationIdIMEI(vec![4u8, 3u8, 1u8, 2u8]),
4547 SecurityLevel::TRUSTED_ENVIRONMENT,
4548 ),
4549 KeyParameter::new(
4550 KeyParameterValue::AttestationIdMEID(vec![4u8, 3u8, 1u8, 2u8]),
4551 SecurityLevel::TRUSTED_ENVIRONMENT,
4552 ),
4553 KeyParameter::new(
4554 KeyParameterValue::AttestationIdManufacturer(vec![4u8, 3u8, 1u8, 2u8]),
4555 SecurityLevel::TRUSTED_ENVIRONMENT,
4556 ),
4557 KeyParameter::new(
4558 KeyParameterValue::AttestationIdModel(vec![4u8, 3u8, 1u8, 2u8]),
4559 SecurityLevel::TRUSTED_ENVIRONMENT,
4560 ),
4561 KeyParameter::new(
4562 KeyParameterValue::VendorPatchLevel(3),
4563 SecurityLevel::TRUSTED_ENVIRONMENT,
4564 ),
4565 KeyParameter::new(
4566 KeyParameterValue::BootPatchLevel(4),
4567 SecurityLevel::TRUSTED_ENVIRONMENT,
4568 ),
4569 KeyParameter::new(
4570 KeyParameterValue::AssociatedData(vec![4u8, 3u8, 1u8, 2u8]),
4571 SecurityLevel::TRUSTED_ENVIRONMENT,
4572 ),
4573 KeyParameter::new(
4574 KeyParameterValue::Nonce(vec![4u8, 3u8, 1u8, 2u8]),
4575 SecurityLevel::TRUSTED_ENVIRONMENT,
4576 ),
4577 KeyParameter::new(
4578 KeyParameterValue::MacLength(256),
4579 SecurityLevel::TRUSTED_ENVIRONMENT,
4580 ),
4581 KeyParameter::new(
4582 KeyParameterValue::ResetSinceIdRotation,
4583 SecurityLevel::TRUSTED_ENVIRONMENT,
4584 ),
4585 KeyParameter::new(
4586 KeyParameterValue::ConfirmationToken(vec![5u8, 5u8, 5u8, 5u8]),
4587 SecurityLevel::TRUSTED_ENVIRONMENT,
4588 ),
Qi Wub9433b52020-12-01 14:52:46 +08004589 ];
4590 if let Some(value) = max_usage_count {
4591 params.push(KeyParameter::new(
4592 KeyParameterValue::UsageCountLimit(value),
4593 SecurityLevel::SOFTWARE,
4594 ));
4595 }
4596 params
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07004597 }
4598
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004599 fn make_test_key_entry(
4600 db: &mut KeystoreDB,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07004601 domain: Domain,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004602 namespace: i64,
4603 alias: &str,
Qi Wub9433b52020-12-01 14:52:46 +08004604 max_usage_count: Option<i32>,
Janis Danisevskisaec14592020-11-12 09:41:49 -08004605 ) -> Result<KeyIdGuard> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08004606 let key_id = db.create_key_entry(&domain, &namespace, &KEYSTORE_UUID)?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004607 let mut blob_metadata = BlobMetaData::new();
4608 blob_metadata.add(BlobMetaEntry::EncryptedBy(EncryptedBy::Password));
4609 blob_metadata.add(BlobMetaEntry::Salt(vec![1, 2, 3]));
4610 blob_metadata.add(BlobMetaEntry::Iv(vec![2, 3, 1]));
4611 blob_metadata.add(BlobMetaEntry::AeadTag(vec![3, 1, 2]));
4612 blob_metadata.add(BlobMetaEntry::KmUuid(KEYSTORE_UUID));
4613
4614 db.set_blob(
4615 &key_id,
4616 SubComponentType::KEY_BLOB,
4617 Some(TEST_KEY_BLOB),
4618 Some(&blob_metadata),
4619 )?;
4620 db.set_blob(&key_id, SubComponentType::CERT, Some(TEST_CERT_BLOB), None)?;
4621 db.set_blob(&key_id, SubComponentType::CERT_CHAIN, Some(TEST_CERT_CHAIN_BLOB), None)?;
Qi Wub9433b52020-12-01 14:52:46 +08004622
4623 let params = make_test_params(max_usage_count);
4624 db.insert_keyparameter(&key_id, &params)?;
4625
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004626 let mut metadata = KeyMetaData::new();
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004627 metadata.add(KeyMetaEntry::CreationDate(DateTime::from_millis_epoch(123456789)));
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004628 db.insert_key_metadata(&key_id, &metadata)?;
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08004629 rebind_alias(db, &key_id, alias, domain, namespace)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004630 Ok(key_id)
4631 }
4632
Qi Wub9433b52020-12-01 14:52:46 +08004633 fn make_test_key_entry_test_vector(key_id: i64, max_usage_count: Option<i32>) -> KeyEntry {
4634 let params = make_test_params(max_usage_count);
4635
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004636 let mut blob_metadata = BlobMetaData::new();
4637 blob_metadata.add(BlobMetaEntry::EncryptedBy(EncryptedBy::Password));
4638 blob_metadata.add(BlobMetaEntry::Salt(vec![1, 2, 3]));
4639 blob_metadata.add(BlobMetaEntry::Iv(vec![2, 3, 1]));
4640 blob_metadata.add(BlobMetaEntry::AeadTag(vec![3, 1, 2]));
4641 blob_metadata.add(BlobMetaEntry::KmUuid(KEYSTORE_UUID));
4642
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004643 let mut metadata = KeyMetaData::new();
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004644 metadata.add(KeyMetaEntry::CreationDate(DateTime::from_millis_epoch(123456789)));
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004645
4646 KeyEntry {
4647 id: key_id,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004648 key_blob_info: Some((TEST_KEY_BLOB.to_vec(), blob_metadata)),
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004649 cert: Some(TEST_CERT_BLOB.to_vec()),
4650 cert_chain: Some(TEST_CERT_CHAIN_BLOB.to_vec()),
Max Bires8e93d2b2021-01-14 13:17:59 -08004651 km_uuid: KEYSTORE_UUID,
Qi Wub9433b52020-12-01 14:52:46 +08004652 parameters: params,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004653 metadata,
Janis Danisevskis377d1002021-01-27 19:07:48 -08004654 pure_cert: false,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004655 }
4656 }
4657
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004658 fn debug_dump_keyentry_table(db: &mut KeystoreDB) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004659 let mut stmt = db.conn.prepare(
Max Bires8e93d2b2021-01-14 13:17:59 -08004660 "SELECT id, key_type, domain, namespace, alias, state, km_uuid FROM persistent.keyentry;",
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004661 )?;
Max Bires8e93d2b2021-01-14 13:17:59 -08004662 let rows = stmt.query_map::<(i64, KeyType, i32, i64, String, KeyLifeCycle, Uuid), _, _>(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004663 NO_PARAMS,
4664 |row| {
Max Bires8e93d2b2021-01-14 13:17:59 -08004665 Ok((
4666 row.get(0)?,
4667 row.get(1)?,
4668 row.get(2)?,
4669 row.get(3)?,
4670 row.get(4)?,
4671 row.get(5)?,
4672 row.get(6)?,
4673 ))
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004674 },
4675 )?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004676
4677 println!("Key entry table rows:");
4678 for r in rows {
Max Bires8e93d2b2021-01-14 13:17:59 -08004679 let (id, key_type, domain, namespace, alias, state, km_uuid) = r.unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004680 println!(
Max Bires8e93d2b2021-01-14 13:17:59 -08004681 " id: {} KeyType: {:?} Domain: {} Namespace: {} Alias: {} State: {:?} KmUuid: {:?}",
4682 id, key_type, domain, namespace, alias, state, km_uuid
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004683 );
4684 }
4685 Ok(())
4686 }
4687
4688 fn debug_dump_grant_table(db: &mut KeystoreDB) -> Result<()> {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08004689 let mut stmt = db
4690 .conn
4691 .prepare("SELECT id, grantee, keyentryid, access_vector FROM persistent.grant;")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004692 let rows = stmt.query_map::<(i64, i64, i64, i64), _, _>(NO_PARAMS, |row| {
4693 Ok((row.get(0)?, row.get(1)?, row.get(2)?, row.get(3)?))
4694 })?;
4695
4696 println!("Grant table rows:");
4697 for r in rows {
4698 let (id, gt, ki, av) = r.unwrap();
4699 println!(" id: {} grantee: {} key_id: {} access_vector: {}", id, gt, ki, av);
4700 }
4701 Ok(())
4702 }
4703
Joel Galenson0891bc12020-07-20 10:37:03 -07004704 // Use a custom random number generator that repeats each number once.
4705 // This allows us to test repeated elements.
4706
4707 thread_local! {
4708 static RANDOM_COUNTER: RefCell<i64> = RefCell::new(0);
4709 }
4710
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004711 fn reset_random() {
4712 RANDOM_COUNTER.with(|counter| {
4713 *counter.borrow_mut() = 0;
4714 })
4715 }
4716
Joel Galenson0891bc12020-07-20 10:37:03 -07004717 pub fn random() -> i64 {
4718 RANDOM_COUNTER.with(|counter| {
4719 let result = *counter.borrow() / 2;
4720 *counter.borrow_mut() += 1;
4721 result
4722 })
4723 }
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00004724
4725 #[test]
4726 fn test_last_off_body() -> Result<()> {
4727 let mut db = new_test_db()?;
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08004728 db.insert_last_off_body(MonotonicRawTime::now())?;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00004729 let tx = db.conn.transaction_with_behavior(TransactionBehavior::Immediate)?;
4730 let last_off_body_1 = KeystoreDB::get_last_off_body(&tx)?;
4731 tx.commit()?;
4732 let one_second = Duration::from_secs(1);
4733 thread::sleep(one_second);
4734 db.update_last_off_body(MonotonicRawTime::now())?;
4735 let tx2 = db.conn.transaction_with_behavior(TransactionBehavior::Immediate)?;
4736 let last_off_body_2 = KeystoreDB::get_last_off_body(&tx2)?;
4737 tx2.commit()?;
4738 assert!(last_off_body_1.seconds() < last_off_body_2.seconds());
4739 Ok(())
4740 }
Hasini Gunasingheda895552021-01-27 19:34:37 +00004741
4742 #[test]
4743 fn test_unbind_keys_for_user() -> Result<()> {
4744 let mut db = new_test_db()?;
4745 db.unbind_keys_for_user(1, false)?;
4746
4747 make_test_key_entry(&mut db, Domain::APP, 210000, TEST_ALIAS, None)?;
4748 make_test_key_entry(&mut db, Domain::APP, 110000, TEST_ALIAS, None)?;
4749 db.unbind_keys_for_user(2, false)?;
4750
4751 assert_eq!(1, db.list(Domain::APP, 110000)?.len());
4752 assert_eq!(0, db.list(Domain::APP, 210000)?.len());
4753
4754 db.unbind_keys_for_user(1, true)?;
4755 assert_eq!(0, db.list(Domain::APP, 110000)?.len());
4756
4757 Ok(())
4758 }
4759
4760 #[test]
4761 fn test_store_super_key() -> Result<()> {
4762 let mut db = new_test_db()?;
4763 let pw = "xyzabc".as_bytes();
4764 let super_key = keystore2_crypto::generate_aes256_key()?;
4765 let secret = String::from("keystore2 is great.");
4766 let secret_bytes = secret.into_bytes();
4767 let (encrypted_secret, iv, tag) =
4768 keystore2_crypto::aes_gcm_encrypt(&secret_bytes, &super_key)?;
4769
4770 let (encrypted_super_key, metadata) =
4771 SuperKeyManager::encrypt_with_password(&super_key, &pw)?;
4772 db.store_super_key(1, &(&encrypted_super_key, &metadata))?;
4773
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00004774 //check if super key exists
4775 assert!(db.key_exists(Domain::APP, 1, "USER_SUPER_KEY", KeyType::Super)?);
4776
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +00004777 let (_, key_entry) = db.load_super_key(1)?.unwrap();
Hasini Gunasingheda895552021-01-27 19:34:37 +00004778 let loaded_super_key = SuperKeyManager::extract_super_key_from_key_entry(key_entry, &pw)?;
4779
4780 let decrypted_secret_bytes = keystore2_crypto::aes_gcm_decrypt(
4781 &encrypted_secret,
4782 &iv,
4783 &tag,
4784 &loaded_super_key.get_key(),
4785 )?;
4786 let decrypted_secret = String::from_utf8((&decrypted_secret_bytes).to_vec())?;
4787 assert_eq!(String::from("keystore2 is great."), decrypted_secret);
4788 Ok(())
4789 }
Joel Galenson26f4d012020-07-17 14:57:21 -07004790}