blob: 57ca7aad79280d19e676258dd8c56899903f1302 [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.
Max Bires2b2e6562020-09-22 11:22:36 -0700584pub struct CertificateChain {
Max Bires97f96812021-02-23 23:44:57 -0800585 /// A KM key blob
586 pub private_key: ZVec,
587 /// A batch cert for private_key
588 pub batch_cert: Vec<u8>,
589 /// A full certificate chain from root signing authority to private_key, including batch_cert
590 /// for convenience.
591 pub cert_chain: Vec<u8>,
Max Bires2b2e6562020-09-22 11:22:36 -0700592}
593
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700594/// This type represents a Keystore 2.0 key entry.
595/// An entry has a unique `id` by which it can be found in the database.
596/// It has a security level field, key parameters, and three optional fields
597/// for the KeyMint blob, public certificate and a public certificate chain.
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800598#[derive(Debug, Default, Eq, PartialEq)]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700599pub struct KeyEntry {
600 id: i64,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800601 key_blob_info: Option<(Vec<u8>, BlobMetaData)>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700602 cert: Option<Vec<u8>>,
603 cert_chain: Option<Vec<u8>>,
Max Bires8e93d2b2021-01-14 13:17:59 -0800604 km_uuid: Uuid,
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700605 parameters: Vec<KeyParameter>,
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800606 metadata: KeyMetaData,
Janis Danisevskis377d1002021-01-27 19:07:48 -0800607 pure_cert: bool,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700608}
609
610impl KeyEntry {
611 /// Returns the unique id of the Key entry.
612 pub fn id(&self) -> i64 {
613 self.id
614 }
615 /// Exposes the optional KeyMint blob.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800616 pub fn key_blob_info(&self) -> &Option<(Vec<u8>, BlobMetaData)> {
617 &self.key_blob_info
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700618 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800619 /// Extracts the Optional KeyMint blob including its metadata.
620 pub fn take_key_blob_info(&mut self) -> Option<(Vec<u8>, BlobMetaData)> {
621 self.key_blob_info.take()
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700622 }
623 /// Exposes the optional public certificate.
624 pub fn cert(&self) -> &Option<Vec<u8>> {
625 &self.cert
626 }
627 /// Extracts the optional public certificate.
628 pub fn take_cert(&mut self) -> Option<Vec<u8>> {
629 self.cert.take()
630 }
631 /// Exposes the optional public certificate chain.
632 pub fn cert_chain(&self) -> &Option<Vec<u8>> {
633 &self.cert_chain
634 }
635 /// Extracts the optional public certificate_chain.
636 pub fn take_cert_chain(&mut self) -> Option<Vec<u8>> {
637 self.cert_chain.take()
638 }
Max Bires8e93d2b2021-01-14 13:17:59 -0800639 /// Returns the uuid of the owning KeyMint instance.
640 pub fn km_uuid(&self) -> &Uuid {
641 &self.km_uuid
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700642 }
Janis Danisevskis04b02832020-10-26 09:21:40 -0700643 /// Exposes the key parameters of this key entry.
644 pub fn key_parameters(&self) -> &Vec<KeyParameter> {
645 &self.parameters
646 }
647 /// Consumes this key entry and extracts the keyparameters from it.
648 pub fn into_key_parameters(self) -> Vec<KeyParameter> {
649 self.parameters
650 }
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800651 /// Exposes the key metadata of this key entry.
652 pub fn metadata(&self) -> &KeyMetaData {
653 &self.metadata
654 }
Janis Danisevskis377d1002021-01-27 19:07:48 -0800655 /// This returns true if the entry is a pure certificate entry with no
656 /// private key component.
657 pub fn pure_cert(&self) -> bool {
658 self.pure_cert
659 }
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000660 /// Consumes this key entry and extracts the keyparameters and metadata from it.
661 pub fn into_key_parameters_and_metadata(self) -> (Vec<KeyParameter>, KeyMetaData) {
662 (self.parameters, self.metadata)
663 }
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700664}
665
666/// Indicates the sub component of a key entry for persistent storage.
Janis Danisevskis377d1002021-01-27 19:07:48 -0800667#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700668pub struct SubComponentType(u32);
669impl SubComponentType {
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800670 /// Persistent identifier for a key blob.
671 pub const KEY_BLOB: SubComponentType = Self(0);
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700672 /// Persistent identifier for a certificate blob.
673 pub const CERT: SubComponentType = Self(1);
674 /// Persistent identifier for a certificate chain blob.
675 pub const CERT_CHAIN: SubComponentType = Self(2);
676}
677
678impl ToSql for SubComponentType {
679 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
680 self.0.to_sql()
681 }
682}
683
684impl FromSql for SubComponentType {
685 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
686 Ok(Self(u32::column_result(value)?))
687 }
688}
689
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800690/// This trait is private to the database module. It is used to convey whether or not the garbage
691/// collector shall be invoked after a database access. All closures passed to
692/// `KeystoreDB::with_transaction` return a tuple (bool, T) where the bool indicates if the
693/// gc needs to be triggered. This convenience function allows to turn any anyhow::Result<T>
694/// into anyhow::Result<(bool, T)> by simply appending one of `.do_gc(bool)`, `.no_gc()`, or
695/// `.need_gc()`.
696trait DoGc<T> {
697 fn do_gc(self, need_gc: bool) -> Result<(bool, T)>;
698
699 fn no_gc(self) -> Result<(bool, T)>;
700
701 fn need_gc(self) -> Result<(bool, T)>;
702}
703
704impl<T> DoGc<T> for Result<T> {
705 fn do_gc(self, need_gc: bool) -> Result<(bool, T)> {
706 self.map(|r| (need_gc, r))
707 }
708
709 fn no_gc(self) -> Result<(bool, T)> {
710 self.do_gc(false)
711 }
712
713 fn need_gc(self) -> Result<(bool, T)> {
714 self.do_gc(true)
715 }
716}
717
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700718/// KeystoreDB wraps a connection to an SQLite database and tracks its
719/// ownership. It also implements all of Keystore 2.0's database functionality.
Joel Galenson26f4d012020-07-17 14:57:21 -0700720pub struct KeystoreDB {
Joel Galenson26f4d012020-07-17 14:57:21 -0700721 conn: Connection,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800722 gc: Option<Gc>,
Joel Galenson26f4d012020-07-17 14:57:21 -0700723}
724
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000725/// Database representation of the monotonic time retrieved from the system call clock_gettime with
726/// CLOCK_MONOTONIC_RAW. Stores monotonic time as i64 in seconds.
727#[derive(Debug, Copy, Clone, Default, Eq, PartialEq, Ord, PartialOrd)]
728pub struct MonotonicRawTime(i64);
729
730impl MonotonicRawTime {
731 /// Constructs a new MonotonicRawTime
732 pub fn now() -> Self {
733 Self(get_current_time_in_seconds())
734 }
735
736 /// Returns the integer value of MonotonicRawTime as i64
737 pub fn seconds(&self) -> i64 {
738 self.0
739 }
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800740
741 /// Like i64::checked_sub.
742 pub fn checked_sub(&self, other: &Self) -> Option<Self> {
743 self.0.checked_sub(other.0).map(Self)
744 }
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000745}
746
747impl ToSql for MonotonicRawTime {
748 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
749 Ok(ToSqlOutput::Owned(Value::Integer(self.0)))
750 }
751}
752
753impl FromSql for MonotonicRawTime {
754 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
755 Ok(Self(i64::column_result(value)?))
756 }
757}
758
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000759/// This struct encapsulates the information to be stored in the database about the auth tokens
760/// received by keystore.
761pub struct AuthTokenEntry {
762 auth_token: HardwareAuthToken,
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000763 time_received: MonotonicRawTime,
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000764}
765
766impl AuthTokenEntry {
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000767 fn new(auth_token: HardwareAuthToken, time_received: MonotonicRawTime) -> Self {
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000768 AuthTokenEntry { auth_token, time_received }
769 }
770
771 /// Checks if this auth token satisfies the given authentication information.
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800772 pub fn satisfies(&self, user_secure_ids: &[i64], auth_type: HardwareAuthenticatorType) -> bool {
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000773 user_secure_ids.iter().any(|&sid| {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800774 (sid == self.auth_token.userId || sid == self.auth_token.authenticatorId)
775 && (((auth_type.0 as i32) & (self.auth_token.authenticatorType.0 as i32)) != 0)
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000776 })
777 }
778
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000779 /// Returns the auth token wrapped by the AuthTokenEntry
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800780 pub fn auth_token(&self) -> &HardwareAuthToken {
781 &self.auth_token
782 }
783
784 /// Returns the auth token wrapped by the AuthTokenEntry
785 pub fn take_auth_token(self) -> HardwareAuthToken {
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000786 self.auth_token
787 }
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800788
789 /// Returns the time that this auth token was received.
790 pub fn time_received(&self) -> MonotonicRawTime {
791 self.time_received
792 }
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000793}
794
Janis Danisevskisb00ebd02021-02-02 21:52:24 -0800795/// Shared in-memory databases get destroyed as soon as the last connection to them gets closed.
796/// This object does not allow access to the database connection. But it keeps a database
797/// connection alive in order to keep the in memory per boot database alive.
798pub struct PerBootDbKeepAlive(Connection);
799
Joel Galenson26f4d012020-07-17 14:57:21 -0700800impl KeystoreDB {
Janis Danisevskiseed69842021-02-18 20:04:10 -0800801 const UNASSIGNED_KEY_ID: i64 = -1i64;
Janis Danisevskisb00ebd02021-02-02 21:52:24 -0800802 const PERBOOT_DB_FILE_NAME: &'static str = &"file:perboot.sqlite?mode=memory&cache=shared";
803
Hasini Gunasinghe0e161452021-01-27 19:34:37 +0000804 /// The alias of the user super key.
805 pub const USER_SUPER_KEY_ALIAS: &'static str = &"USER_SUPER_KEY";
806
Janis Danisevskisb00ebd02021-02-02 21:52:24 -0800807 /// This creates a PerBootDbKeepAlive object to keep the per boot database alive.
808 pub fn keep_perboot_db_alive() -> Result<PerBootDbKeepAlive> {
809 let conn = Connection::open_in_memory()
810 .context("In keep_perboot_db_alive: Failed to initialize SQLite connection.")?;
811
812 conn.execute("ATTACH DATABASE ? as perboot;", params![Self::PERBOOT_DB_FILE_NAME])
813 .context("In keep_perboot_db_alive: Failed to attach database perboot.")?;
814 Ok(PerBootDbKeepAlive(conn))
815 }
816
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700817 /// This will create a new database connection connecting the two
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800818 /// files persistent.sqlite and perboot.sqlite in the given directory.
819 /// It also attempts to initialize all of the tables.
820 /// KeystoreDB cannot be used by multiple threads.
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700821 /// Each thread should open their own connection using `thread_local!`.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800822 pub fn new(db_root: &Path, gc: Option<Gc>) -> Result<Self> {
Janis Danisevskisb00ebd02021-02-02 21:52:24 -0800823 // Build the path to the sqlite file.
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800824 let mut persistent_path = db_root.to_path_buf();
825 persistent_path.push("persistent.sqlite");
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700826
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800827 // Now convert them to strings prefixed with "file:"
828 let mut persistent_path_str = "file:".to_owned();
829 persistent_path_str.push_str(&persistent_path.to_string_lossy());
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800830
Janis Danisevskisb00ebd02021-02-02 21:52:24 -0800831 let conn = Self::make_connection(&persistent_path_str, &Self::PERBOOT_DB_FILE_NAME)?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800832
Janis Danisevskis66784c42021-01-27 08:40:25 -0800833 // On busy fail Immediately. It is unlikely to succeed given a bug in sqlite.
834 conn.busy_handler(None).context("In KeystoreDB::new: Failed to set busy handler.")?;
835
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800836 let mut db = Self { conn, gc };
Janis Danisevskis66784c42021-01-27 08:40:25 -0800837 db.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800838 Self::init_tables(tx).context("Trying to initialize tables.").no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -0800839 })?;
840 Ok(db)
Joel Galenson2aab4432020-07-22 15:27:57 -0700841 }
842
Janis Danisevskis66784c42021-01-27 08:40:25 -0800843 fn init_tables(tx: &Transaction) -> Result<()> {
844 tx.execute(
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700845 "CREATE TABLE IF NOT EXISTS persistent.keyentry (
Joel Galenson0891bc12020-07-20 10:37:03 -0700846 id INTEGER UNIQUE,
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800847 key_type INTEGER,
Joel Galenson0891bc12020-07-20 10:37:03 -0700848 domain INTEGER,
849 namespace INTEGER,
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800850 alias BLOB,
Max Bires8e93d2b2021-01-14 13:17:59 -0800851 state INTEGER,
852 km_uuid BLOB);",
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700853 NO_PARAMS,
854 )
855 .context("Failed to initialize \"keyentry\" table.")?;
856
Janis Danisevskis66784c42021-01-27 08:40:25 -0800857 tx.execute(
Janis Danisevskisa5438182021-02-02 14:22:59 -0800858 "CREATE INDEX IF NOT EXISTS persistent.keyentry_id_index
859 ON keyentry(id);",
860 NO_PARAMS,
861 )
862 .context("Failed to create index keyentry_id_index.")?;
863
864 tx.execute(
865 "CREATE INDEX IF NOT EXISTS persistent.keyentry_domain_namespace_index
866 ON keyentry(domain, namespace, alias);",
867 NO_PARAMS,
868 )
869 .context("Failed to create index keyentry_domain_namespace_index.")?;
870
871 tx.execute(
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700872 "CREATE TABLE IF NOT EXISTS persistent.blobentry (
873 id INTEGER PRIMARY KEY,
874 subcomponent_type INTEGER,
875 keyentryid INTEGER,
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800876 blob BLOB);",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700877 NO_PARAMS,
878 )
879 .context("Failed to initialize \"blobentry\" table.")?;
880
Janis Danisevskis66784c42021-01-27 08:40:25 -0800881 tx.execute(
Janis Danisevskisa5438182021-02-02 14:22:59 -0800882 "CREATE INDEX IF NOT EXISTS persistent.blobentry_keyentryid_index
883 ON blobentry(keyentryid);",
884 NO_PARAMS,
885 )
886 .context("Failed to create index blobentry_keyentryid_index.")?;
887
888 tx.execute(
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800889 "CREATE TABLE IF NOT EXISTS persistent.blobmetadata (
890 id INTEGER PRIMARY KEY,
891 blobentryid INTEGER,
892 tag INTEGER,
893 data ANY,
894 UNIQUE (blobentryid, tag));",
895 NO_PARAMS,
896 )
897 .context("Failed to initialize \"blobmetadata\" table.")?;
898
899 tx.execute(
900 "CREATE INDEX IF NOT EXISTS persistent.blobmetadata_blobentryid_index
901 ON blobmetadata(blobentryid);",
902 NO_PARAMS,
903 )
904 .context("Failed to create index blobmetadata_blobentryid_index.")?;
905
906 tx.execute(
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700907 "CREATE TABLE IF NOT EXISTS persistent.keyparameter (
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000908 keyentryid INTEGER,
909 tag INTEGER,
910 data ANY,
911 security_level INTEGER);",
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700912 NO_PARAMS,
913 )
914 .context("Failed to initialize \"keyparameter\" table.")?;
915
Janis Danisevskis66784c42021-01-27 08:40:25 -0800916 tx.execute(
Janis Danisevskisa5438182021-02-02 14:22:59 -0800917 "CREATE INDEX IF NOT EXISTS persistent.keyparameter_keyentryid_index
918 ON keyparameter(keyentryid);",
919 NO_PARAMS,
920 )
921 .context("Failed to create index keyparameter_keyentryid_index.")?;
922
923 tx.execute(
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800924 "CREATE TABLE IF NOT EXISTS persistent.keymetadata (
925 keyentryid INTEGER,
926 tag INTEGER,
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000927 data ANY,
928 UNIQUE (keyentryid, tag));",
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800929 NO_PARAMS,
930 )
931 .context("Failed to initialize \"keymetadata\" table.")?;
932
Janis Danisevskis66784c42021-01-27 08:40:25 -0800933 tx.execute(
Janis Danisevskisa5438182021-02-02 14:22:59 -0800934 "CREATE INDEX IF NOT EXISTS persistent.keymetadata_keyentryid_index
935 ON keymetadata(keyentryid);",
936 NO_PARAMS,
937 )
938 .context("Failed to create index keymetadata_keyentryid_index.")?;
939
940 tx.execute(
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800941 "CREATE TABLE IF NOT EXISTS persistent.grant (
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700942 id INTEGER UNIQUE,
943 grantee INTEGER,
944 keyentryid INTEGER,
945 access_vector INTEGER);",
946 NO_PARAMS,
947 )
948 .context("Failed to initialize \"grant\" table.")?;
949
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000950 //TODO: only drop the following two perboot tables if this is the first start up
951 //during the boot (b/175716626).
Janis Danisevskis66784c42021-01-27 08:40:25 -0800952 // tx.execute("DROP TABLE IF EXISTS perboot.authtoken;", NO_PARAMS)
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000953 // .context("Failed to drop perboot.authtoken table")?;
Janis Danisevskis66784c42021-01-27 08:40:25 -0800954 tx.execute(
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000955 "CREATE TABLE IF NOT EXISTS perboot.authtoken (
956 id INTEGER PRIMARY KEY,
957 challenge INTEGER,
958 user_id INTEGER,
959 auth_id INTEGER,
960 authenticator_type INTEGER,
961 timestamp INTEGER,
962 mac BLOB,
963 time_received INTEGER,
964 UNIQUE(user_id, auth_id, authenticator_type));",
965 NO_PARAMS,
966 )
967 .context("Failed to initialize \"authtoken\" table.")?;
968
Janis Danisevskis66784c42021-01-27 08:40:25 -0800969 // tx.execute("DROP TABLE IF EXISTS perboot.metadata;", NO_PARAMS)
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000970 // .context("Failed to drop perboot.metadata table")?;
971 // metadata table stores certain miscellaneous information required for keystore functioning
972 // during a boot cycle, as key-value pairs.
Janis Danisevskis66784c42021-01-27 08:40:25 -0800973 tx.execute(
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000974 "CREATE TABLE IF NOT EXISTS perboot.metadata (
975 key TEXT,
976 value BLOB,
977 UNIQUE(key));",
978 NO_PARAMS,
979 )
980 .context("Failed to initialize \"metadata\" table.")?;
Joel Galenson0891bc12020-07-20 10:37:03 -0700981 Ok(())
982 }
983
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700984 fn make_connection(persistent_file: &str, perboot_file: &str) -> Result<Connection> {
985 let conn =
986 Connection::open_in_memory().context("Failed to initialize SQLite connection.")?;
987
Janis Danisevskis66784c42021-01-27 08:40:25 -0800988 loop {
989 if let Err(e) = conn
990 .execute("ATTACH DATABASE ? as persistent;", params![persistent_file])
991 .context("Failed to attach database persistent.")
992 {
993 if Self::is_locked_error(&e) {
994 std::thread::sleep(std::time::Duration::from_micros(500));
995 continue;
996 } else {
997 return Err(e);
998 }
999 }
1000 break;
1001 }
1002 loop {
1003 if let Err(e) = conn
1004 .execute("ATTACH DATABASE ? as perboot;", params![perboot_file])
1005 .context("Failed to attach database perboot.")
1006 {
1007 if Self::is_locked_error(&e) {
1008 std::thread::sleep(std::time::Duration::from_micros(500));
1009 continue;
1010 } else {
1011 return Err(e);
1012 }
1013 }
1014 break;
1015 }
Janis Danisevskis4df44f42020-08-26 14:40:03 -07001016
1017 Ok(conn)
1018 }
1019
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001020 /// This function is intended to be used by the garbage collector.
1021 /// It deletes the blob given by `blob_id_to_delete`. It then tries to find a superseded
1022 /// key blob that might need special handling by the garbage collector.
1023 /// If no further superseded blobs can be found it deletes all other superseded blobs that don't
1024 /// need special handling and returns None.
1025 pub fn handle_next_superseded_blob(
1026 &mut self,
1027 blob_id_to_delete: Option<i64>,
1028 ) -> Result<Option<(i64, Vec<u8>, BlobMetaData)>> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001029 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001030 // Delete the given blob if one was given.
1031 if let Some(blob_id_to_delete) = blob_id_to_delete {
1032 tx.execute(
1033 "DELETE FROM persistent.blobmetadata WHERE blobentryid = ?;",
1034 params![blob_id_to_delete],
1035 )
1036 .context("Trying to delete blob metadata.")?;
1037 tx.execute(
1038 "DELETE FROM persistent.blobentry WHERE id = ?;",
1039 params![blob_id_to_delete],
1040 )
1041 .context("Trying to blob.")?;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001042 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001043
1044 // Find another superseded keyblob load its metadata and return it.
1045 if let Some((blob_id, blob)) = tx
1046 .query_row(
1047 "SELECT id, blob FROM persistent.blobentry
1048 WHERE subcomponent_type = ?
1049 AND (
1050 id NOT IN (
1051 SELECT MAX(id) FROM persistent.blobentry
1052 WHERE subcomponent_type = ?
1053 GROUP BY keyentryid, subcomponent_type
1054 )
1055 OR keyentryid NOT IN (SELECT id FROM persistent.keyentry)
1056 );",
1057 params![SubComponentType::KEY_BLOB, SubComponentType::KEY_BLOB],
1058 |row| Ok((row.get(0)?, row.get(1)?)),
1059 )
1060 .optional()
1061 .context("Trying to query superseded blob.")?
1062 {
1063 let blob_metadata = BlobMetaData::load_from_db(blob_id, tx)
1064 .context("Trying to load blob metadata.")?;
1065 return Ok(Some((blob_id, blob, blob_metadata))).no_gc();
1066 }
1067
1068 // We did not find any superseded key blob, so let's remove other superseded blob in
1069 // one transaction.
1070 tx.execute(
1071 "DELETE FROM persistent.blobentry
1072 WHERE NOT subcomponent_type = ?
1073 AND (
1074 id NOT IN (
1075 SELECT MAX(id) FROM persistent.blobentry
1076 WHERE NOT subcomponent_type = ?
1077 GROUP BY keyentryid, subcomponent_type
1078 ) OR keyentryid NOT IN (SELECT id FROM persistent.keyentry)
1079 );",
1080 params![SubComponentType::KEY_BLOB, SubComponentType::KEY_BLOB],
1081 )
1082 .context("Trying to purge superseded blobs.")?;
1083
1084 Ok(None).no_gc()
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001085 })
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001086 .context("In handle_next_superseded_blob.")
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001087 }
1088
1089 /// This maintenance function should be called only once before the database is used for the
1090 /// first time. It restores the invariant that `KeyLifeCycle::Existing` is a transient state.
1091 /// The function transitions all key entries from Existing to Unreferenced unconditionally and
1092 /// returns the number of rows affected. If this returns a value greater than 0, it means that
1093 /// Keystore crashed at some point during key generation. Callers may want to log such
1094 /// occurrences.
1095 /// Unlike with `mark_unreferenced`, we don't need to purge grants, because only keys that made
1096 /// it to `KeyLifeCycle::Live` may have grants.
1097 pub fn cleanup_leftovers(&mut self) -> Result<usize> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001098 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1099 tx.execute(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001100 "UPDATE persistent.keyentry SET state = ? WHERE state = ?;",
1101 params![KeyLifeCycle::Unreferenced, KeyLifeCycle::Existing],
1102 )
Janis Danisevskis66784c42021-01-27 08:40:25 -08001103 .context("Failed to execute query.")
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001104 .need_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08001105 })
1106 .context("In cleanup_leftovers.")
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001107 }
1108
Hasini Gunasinghe0e161452021-01-27 19:34:37 +00001109 /// Checks if a key exists with given key type and key descriptor properties.
1110 pub fn key_exists(
1111 &mut self,
1112 domain: Domain,
1113 nspace: i64,
1114 alias: &str,
1115 key_type: KeyType,
1116 ) -> Result<bool> {
1117 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1118 let key_descriptor =
1119 KeyDescriptor { domain, nspace, alias: Some(alias.to_string()), blob: None };
1120 let result = Self::load_key_entry_id(&tx, &key_descriptor, key_type);
1121 match result {
1122 Ok(_) => Ok(true),
1123 Err(error) => match error.root_cause().downcast_ref::<KsError>() {
1124 Some(KsError::Rc(ResponseCode::KEY_NOT_FOUND)) => Ok(false),
1125 _ => Err(error).context("In key_exists: Failed to find if the key exists."),
1126 },
1127 }
1128 .no_gc()
1129 })
1130 .context("In key_exists.")
1131 }
1132
Hasini Gunasingheda895552021-01-27 19:34:37 +00001133 /// Stores a super key in the database.
1134 pub fn store_super_key(
1135 &mut self,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +00001136 user_id: u32,
Hasini Gunasingheda895552021-01-27 19:34:37 +00001137 blob_info: &(&[u8], &BlobMetaData),
1138 ) -> Result<KeyEntry> {
1139 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1140 let key_id = Self::insert_with_retry(|id| {
1141 tx.execute(
1142 "INSERT into persistent.keyentry
1143 (id, key_type, domain, namespace, alias, state, km_uuid)
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00001144 VALUES(?, ?, ?, ?, ?, ?, ?);",
Hasini Gunasingheda895552021-01-27 19:34:37 +00001145 params![
1146 id,
1147 KeyType::Super,
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00001148 Domain::APP.0,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +00001149 user_id as i64,
Hasini Gunasingheda895552021-01-27 19:34:37 +00001150 Self::USER_SUPER_KEY_ALIAS,
1151 KeyLifeCycle::Live,
1152 &KEYSTORE_UUID,
1153 ],
1154 )
1155 })
1156 .context("Failed to insert into keyentry table.")?;
1157
1158 let (blob, blob_metadata) = *blob_info;
1159 Self::set_blob_internal(
1160 &tx,
1161 key_id,
1162 SubComponentType::KEY_BLOB,
1163 Some(blob),
1164 Some(blob_metadata),
1165 )
1166 .context("Failed to store key blob.")?;
1167
1168 Self::load_key_components(tx, KeyEntryLoadBits::KM, key_id)
1169 .context("Trying to load key components.")
1170 .no_gc()
1171 })
1172 .context("In store_super_key.")
1173 }
1174
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +00001175 /// Loads super key of a given user, if exists
1176 pub fn load_super_key(&mut self, user_id: u32) -> Result<Option<(KeyIdGuard, KeyEntry)>> {
1177 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1178 let key_descriptor = KeyDescriptor {
1179 domain: Domain::APP,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +00001180 nspace: user_id as i64,
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +00001181 alias: Some(String::from("USER_SUPER_KEY")),
1182 blob: None,
1183 };
1184 let id = Self::load_key_entry_id(&tx, &key_descriptor, KeyType::Super);
1185 match id {
1186 Ok(id) => {
1187 let key_entry = Self::load_key_components(&tx, KeyEntryLoadBits::KM, id)
1188 .context("In load_super_key. Failed to load key entry.")?;
1189 Ok(Some((KEY_ID_LOCK.get(id), key_entry)))
1190 }
1191 Err(error) => match error.root_cause().downcast_ref::<KsError>() {
1192 Some(KsError::Rc(ResponseCode::KEY_NOT_FOUND)) => Ok(None),
1193 _ => Err(error).context("In load_super_key."),
1194 },
1195 }
1196 .no_gc()
1197 })
1198 .context("In load_super_key.")
1199 }
1200
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001201 /// Atomically loads a key entry and associated metadata or creates it using the
1202 /// callback create_new_key callback. The callback is called during a database
1203 /// transaction. This means that implementers should be mindful about using
1204 /// blocking operations such as IPC or grabbing mutexes.
1205 pub fn get_or_create_key_with<F>(
1206 &mut self,
1207 domain: Domain,
1208 namespace: i64,
1209 alias: &str,
Max Bires8e93d2b2021-01-14 13:17:59 -08001210 km_uuid: Uuid,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001211 create_new_key: F,
1212 ) -> Result<(KeyIdGuard, KeyEntry)>
1213 where
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001214 F: Fn() -> Result<(Vec<u8>, BlobMetaData)>,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001215 {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001216 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1217 let id = {
1218 let mut stmt = tx
1219 .prepare(
1220 "SELECT id FROM persistent.keyentry
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001221 WHERE
1222 key_type = ?
1223 AND domain = ?
1224 AND namespace = ?
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001225 AND alias = ?
1226 AND state = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08001227 )
1228 .context("In get_or_create_key_with: Failed to select from keyentry table.")?;
1229 let mut rows = stmt
1230 .query(params![KeyType::Super, domain.0, namespace, alias, KeyLifeCycle::Live])
1231 .context("In get_or_create_key_with: Failed to query from keyentry table.")?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001232
Janis Danisevskis66784c42021-01-27 08:40:25 -08001233 db_utils::with_rows_extract_one(&mut rows, |row| {
1234 Ok(match row {
1235 Some(r) => r.get(0).context("Failed to unpack id.")?,
1236 None => None,
1237 })
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001238 })
Janis Danisevskis66784c42021-01-27 08:40:25 -08001239 .context("In get_or_create_key_with.")?
1240 };
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001241
Janis Danisevskis66784c42021-01-27 08:40:25 -08001242 let (id, entry) = match id {
1243 Some(id) => (
1244 id,
1245 Self::load_key_components(&tx, KeyEntryLoadBits::KM, id)
1246 .context("In get_or_create_key_with.")?,
1247 ),
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001248
Janis Danisevskis66784c42021-01-27 08:40:25 -08001249 None => {
1250 let id = Self::insert_with_retry(|id| {
1251 tx.execute(
1252 "INSERT into persistent.keyentry
Max Bires8e93d2b2021-01-14 13:17:59 -08001253 (id, key_type, domain, namespace, alias, state, km_uuid)
1254 VALUES(?, ?, ?, ?, ?, ?, ?);",
Janis Danisevskis66784c42021-01-27 08:40:25 -08001255 params![
1256 id,
1257 KeyType::Super,
1258 domain.0,
1259 namespace,
1260 alias,
1261 KeyLifeCycle::Live,
1262 km_uuid,
1263 ],
1264 )
1265 })
1266 .context("In get_or_create_key_with.")?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001267
Janis Danisevskis66784c42021-01-27 08:40:25 -08001268 let (blob, metadata) =
1269 create_new_key().context("In get_or_create_key_with.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001270 Self::set_blob_internal(
1271 &tx,
1272 id,
1273 SubComponentType::KEY_BLOB,
1274 Some(&blob),
1275 Some(&metadata),
1276 )
1277 .context("In get_of_create_key_with.")?;
Janis Danisevskis66784c42021-01-27 08:40:25 -08001278 (
Janis Danisevskis377d1002021-01-27 19:07:48 -08001279 id,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001280 KeyEntry {
1281 id,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001282 key_blob_info: Some((blob, metadata)),
Janis Danisevskis66784c42021-01-27 08:40:25 -08001283 pure_cert: false,
1284 ..Default::default()
1285 },
1286 )
1287 }
1288 };
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001289 Ok((KEY_ID_LOCK.get(id), entry)).no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08001290 })
1291 .context("In get_or_create_key_with.")
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001292 }
1293
Janis Danisevskis66784c42021-01-27 08:40:25 -08001294 /// SQLite3 seems to hold a shared mutex while running the busy handler when
1295 /// waiting for the database file to become available. This makes it
1296 /// impossible to successfully recover from a locked database when the
1297 /// transaction holding the device busy is in the same process on a
1298 /// different connection. As a result the busy handler has to time out and
1299 /// fail in order to make progress.
1300 ///
1301 /// Instead, we set the busy handler to None (return immediately). And catch
1302 /// Busy and Locked errors (the latter occur on in memory databases with
1303 /// shared cache, e.g., the per-boot database.) and restart the transaction
1304 /// after a grace period of half a millisecond.
1305 ///
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001306 /// Creates a transaction with the given behavior and executes f with the new transaction.
Janis Danisevskis66784c42021-01-27 08:40:25 -08001307 /// The transaction is committed only if f returns Ok and retried if DatabaseBusy
1308 /// or DatabaseLocked is encountered.
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001309 fn with_transaction<T, F>(&mut self, behavior: TransactionBehavior, f: F) -> Result<T>
1310 where
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001311 F: Fn(&Transaction) -> Result<(bool, T)>,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001312 {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001313 loop {
1314 match self
1315 .conn
1316 .transaction_with_behavior(behavior)
1317 .context("In with_transaction.")
1318 .and_then(|tx| f(&tx).map(|result| (result, tx)))
1319 .and_then(|(result, tx)| {
1320 tx.commit().context("In with_transaction: Failed to commit transaction.")?;
1321 Ok(result)
1322 }) {
1323 Ok(result) => break Ok(result),
1324 Err(e) => {
1325 if Self::is_locked_error(&e) {
1326 std::thread::sleep(std::time::Duration::from_micros(500));
1327 continue;
1328 } else {
1329 return Err(e).context("In with_transaction.");
1330 }
1331 }
1332 }
1333 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001334 .map(|(need_gc, result)| {
1335 if need_gc {
1336 if let Some(ref gc) = self.gc {
1337 gc.notify_gc();
1338 }
1339 }
1340 result
1341 })
Janis Danisevskis66784c42021-01-27 08:40:25 -08001342 }
1343
1344 fn is_locked_error(e: &anyhow::Error) -> bool {
1345 matches!(e.root_cause().downcast_ref::<rusqlite::ffi::Error>(),
1346 Some(rusqlite::ffi::Error {
1347 code: rusqlite::ErrorCode::DatabaseBusy,
1348 ..
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001349 })
Janis Danisevskis66784c42021-01-27 08:40:25 -08001350 | Some(rusqlite::ffi::Error {
1351 code: rusqlite::ErrorCode::DatabaseLocked,
1352 ..
1353 }))
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001354 }
1355
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001356 /// Creates a new key entry and allocates a new randomized id for the new key.
1357 /// The key id gets associated with a domain and namespace but not with an alias.
1358 /// To complete key generation `rebind_alias` should be called after all of the
1359 /// key artifacts, i.e., blobs and parameters have been associated with the new
1360 /// key id. Finalizing with `rebind_alias` makes the creation of a new key entry
1361 /// atomic even if key generation is not.
Max Bires8e93d2b2021-01-14 13:17:59 -08001362 pub fn create_key_entry(
1363 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001364 domain: &Domain,
1365 namespace: &i64,
Max Bires8e93d2b2021-01-14 13:17:59 -08001366 km_uuid: &Uuid,
1367 ) -> Result<KeyIdGuard> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001368 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001369 Self::create_key_entry_internal(tx, domain, namespace, km_uuid).no_gc()
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001370 })
1371 .context("In create_key_entry.")
1372 }
1373
1374 fn create_key_entry_internal(
1375 tx: &Transaction,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001376 domain: &Domain,
1377 namespace: &i64,
Max Bires8e93d2b2021-01-14 13:17:59 -08001378 km_uuid: &Uuid,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001379 ) -> Result<KeyIdGuard> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001380 match *domain {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001381 Domain::APP | Domain::SELINUX => {}
Joel Galenson0891bc12020-07-20 10:37:03 -07001382 _ => {
1383 return Err(KsError::sys())
1384 .context(format!("Domain {:?} must be either App or SELinux.", domain));
1385 }
1386 }
Janis Danisevskisaec14592020-11-12 09:41:49 -08001387 Ok(KEY_ID_LOCK.get(
1388 Self::insert_with_retry(|id| {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001389 tx.execute(
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001390 "INSERT into persistent.keyentry
Max Bires8e93d2b2021-01-14 13:17:59 -08001391 (id, key_type, domain, namespace, alias, state, km_uuid)
1392 VALUES(?, ?, ?, ?, NULL, ?, ?);",
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001393 params![
1394 id,
1395 KeyType::Client,
1396 domain.0 as u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001397 *namespace,
Max Bires8e93d2b2021-01-14 13:17:59 -08001398 KeyLifeCycle::Existing,
1399 km_uuid,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001400 ],
Janis Danisevskisaec14592020-11-12 09:41:49 -08001401 )
1402 })
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001403 .context("In create_key_entry_internal")?,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001404 ))
Joel Galenson26f4d012020-07-17 14:57:21 -07001405 }
Joel Galenson33c04ad2020-08-03 11:04:38 -07001406
Max Bires2b2e6562020-09-22 11:22:36 -07001407 /// Creates a new attestation key entry and allocates a new randomized id for the new key.
1408 /// The key id gets associated with a domain and namespace later but not with an alias. The
1409 /// alias will be used to denote if a key has been signed as each key can only be bound to one
1410 /// domain and namespace pairing so there is no need to use them as a value for indexing into
1411 /// a key.
1412 pub fn create_attestation_key_entry(
1413 &mut self,
1414 maced_public_key: &[u8],
1415 raw_public_key: &[u8],
1416 private_key: &[u8],
1417 km_uuid: &Uuid,
1418 ) -> Result<()> {
1419 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1420 let key_id = KEY_ID_LOCK.get(
1421 Self::insert_with_retry(|id| {
1422 tx.execute(
1423 "INSERT into persistent.keyentry
1424 (id, key_type, domain, namespace, alias, state, km_uuid)
1425 VALUES(?, ?, NULL, NULL, NULL, ?, ?);",
1426 params![id, KeyType::Attestation, KeyLifeCycle::Live, km_uuid],
1427 )
1428 })
1429 .context("In create_key_entry")?,
1430 );
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001431 Self::set_blob_internal(
1432 &tx,
1433 key_id.0,
1434 SubComponentType::KEY_BLOB,
1435 Some(private_key),
1436 None,
1437 )?;
Max Bires2b2e6562020-09-22 11:22:36 -07001438 let mut metadata = KeyMetaData::new();
1439 metadata.add(KeyMetaEntry::AttestationMacedPublicKey(maced_public_key.to_vec()));
1440 metadata.add(KeyMetaEntry::AttestationRawPubKey(raw_public_key.to_vec()));
1441 metadata.store_in_db(key_id.0, &tx)?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001442 Ok(()).no_gc()
Max Bires2b2e6562020-09-22 11:22:36 -07001443 })
1444 .context("In create_attestation_key_entry")
1445 }
1446
Janis Danisevskis377d1002021-01-27 19:07:48 -08001447 /// Set a new blob and associates it with the given key id. Each blob
1448 /// has a sub component type.
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001449 /// Each key can have one of each sub component type associated. If more
1450 /// are added only the most recent can be retrieved, and superseded blobs
Janis Danisevskis377d1002021-01-27 19:07:48 -08001451 /// will get garbage collected.
1452 /// Components SubComponentType::CERT and SubComponentType::CERT_CHAIN can be
1453 /// removed by setting blob to None.
1454 pub fn set_blob(
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001455 &mut self,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001456 key_id: &KeyIdGuard,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001457 sc_type: SubComponentType,
Janis Danisevskis377d1002021-01-27 19:07:48 -08001458 blob: Option<&[u8]>,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001459 blob_metadata: Option<&BlobMetaData>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001460 ) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001461 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001462 Self::set_blob_internal(&tx, key_id.0, sc_type, blob, blob_metadata).need_gc()
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001463 })
Janis Danisevskis377d1002021-01-27 19:07:48 -08001464 .context("In set_blob.")
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001465 }
1466
Janis Danisevskiseed69842021-02-18 20:04:10 -08001467 /// Why would we insert a deleted blob? This weird function is for the purpose of legacy
1468 /// key migration in the case where we bulk delete all the keys of an app or even a user.
1469 /// We use this to insert key blobs into the database which can then be garbage collected
1470 /// lazily by the key garbage collector.
1471 pub fn set_deleted_blob(&mut self, blob: &[u8], blob_metadata: &BlobMetaData) -> Result<()> {
1472 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1473 Self::set_blob_internal(
1474 &tx,
1475 Self::UNASSIGNED_KEY_ID,
1476 SubComponentType::KEY_BLOB,
1477 Some(blob),
1478 Some(blob_metadata),
1479 )
1480 .need_gc()
1481 })
1482 .context("In set_deleted_blob.")
1483 }
1484
Janis Danisevskis377d1002021-01-27 19:07:48 -08001485 fn set_blob_internal(
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001486 tx: &Transaction,
1487 key_id: i64,
1488 sc_type: SubComponentType,
Janis Danisevskis377d1002021-01-27 19:07:48 -08001489 blob: Option<&[u8]>,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001490 blob_metadata: Option<&BlobMetaData>,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001491 ) -> Result<()> {
Janis Danisevskis377d1002021-01-27 19:07:48 -08001492 match (blob, sc_type) {
1493 (Some(blob), _) => {
1494 tx.execute(
1495 "INSERT INTO persistent.blobentry
1496 (subcomponent_type, keyentryid, blob) VALUES (?, ?, ?);",
1497 params![sc_type, key_id, blob],
1498 )
1499 .context("In set_blob_internal: Failed to insert blob.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001500 if let Some(blob_metadata) = blob_metadata {
1501 let blob_id = tx
1502 .query_row("SELECT MAX(id) FROM persistent.blobentry;", NO_PARAMS, |row| {
1503 row.get(0)
1504 })
1505 .context("In set_blob_internal: Failed to get new blob id.")?;
1506 blob_metadata
1507 .store_in_db(blob_id, tx)
1508 .context("In set_blob_internal: Trying to store blob metadata.")?;
1509 }
Janis Danisevskis377d1002021-01-27 19:07:48 -08001510 }
1511 (None, SubComponentType::CERT) | (None, SubComponentType::CERT_CHAIN) => {
1512 tx.execute(
1513 "DELETE FROM persistent.blobentry
1514 WHERE subcomponent_type = ? AND keyentryid = ?;",
1515 params![sc_type, key_id],
1516 )
1517 .context("In set_blob_internal: Failed to delete blob.")?;
1518 }
1519 (None, _) => {
1520 return Err(KsError::sys())
1521 .context("In set_blob_internal: Other blobs cannot be deleted in this way.");
1522 }
1523 }
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001524 Ok(())
1525 }
1526
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001527 /// Inserts a collection of key parameters into the `persistent.keyparameter` table
1528 /// and associates them with the given `key_id`.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001529 #[cfg(test)]
1530 fn insert_keyparameter(&mut self, key_id: &KeyIdGuard, params: &[KeyParameter]) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001531 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001532 Self::insert_keyparameter_internal(tx, key_id, params).no_gc()
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001533 })
1534 .context("In insert_keyparameter.")
1535 }
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001536
Janis Danisevskis66784c42021-01-27 08:40:25 -08001537 fn insert_keyparameter_internal(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001538 tx: &Transaction,
1539 key_id: &KeyIdGuard,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001540 params: &[KeyParameter],
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001541 ) -> Result<()> {
1542 let mut stmt = tx
1543 .prepare(
1544 "INSERT into persistent.keyparameter (keyentryid, tag, data, security_level)
1545 VALUES (?, ?, ?, ?);",
1546 )
1547 .context("In insert_keyparameter_internal: Failed to prepare statement.")?;
1548
Janis Danisevskis66784c42021-01-27 08:40:25 -08001549 for p in params.iter() {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001550 stmt.insert(params![
1551 key_id.0,
1552 p.get_tag().0,
1553 p.key_parameter_value(),
1554 p.security_level().0
1555 ])
1556 .with_context(|| {
1557 format!("In insert_keyparameter_internal: Failed to insert {:?}", p)
1558 })?;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001559 }
1560 Ok(())
1561 }
1562
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001563 /// Insert a set of key entry specific metadata into the database.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001564 #[cfg(test)]
1565 fn insert_key_metadata(&mut self, key_id: &KeyIdGuard, metadata: &KeyMetaData) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001566 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001567 metadata.store_in_db(key_id.0, &tx).no_gc()
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001568 })
1569 .context("In insert_key_metadata.")
1570 }
1571
Max Bires2b2e6562020-09-22 11:22:36 -07001572 /// Stores a signed certificate chain signed by a remote provisioning server, keyed
1573 /// on the public key.
1574 pub fn store_signed_attestation_certificate_chain(
1575 &mut self,
1576 raw_public_key: &[u8],
Max Biresb2e1d032021-02-08 21:35:05 -08001577 batch_cert: &[u8],
Max Bires2b2e6562020-09-22 11:22:36 -07001578 cert_chain: &[u8],
1579 expiration_date: i64,
1580 km_uuid: &Uuid,
1581 ) -> Result<()> {
1582 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1583 let mut stmt = tx
1584 .prepare(
1585 "SELECT keyentryid
1586 FROM persistent.keymetadata
1587 WHERE tag = ? AND data = ? AND keyentryid IN
1588 (SELECT id
1589 FROM persistent.keyentry
1590 WHERE
1591 alias IS NULL AND
1592 domain IS NULL AND
1593 namespace IS NULL AND
1594 key_type = ? AND
1595 km_uuid = ?);",
1596 )
1597 .context("Failed to store attestation certificate chain.")?;
1598 let mut rows = stmt
1599 .query(params![
1600 KeyMetaData::AttestationRawPubKey,
1601 raw_public_key,
1602 KeyType::Attestation,
1603 km_uuid
1604 ])
1605 .context("Failed to fetch keyid")?;
1606 let key_id = db_utils::with_rows_extract_one(&mut rows, |row| {
1607 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?
1608 .get(0)
1609 .context("Failed to unpack id.")
1610 })
1611 .context("Failed to get key_id.")?;
1612 let num_updated = tx
1613 .execute(
1614 "UPDATE persistent.keyentry
1615 SET alias = ?
1616 WHERE id = ?;",
1617 params!["signed", key_id],
1618 )
1619 .context("Failed to update alias.")?;
1620 if num_updated != 1 {
1621 return Err(KsError::sys()).context("Alias not updated for the key.");
1622 }
1623 let mut metadata = KeyMetaData::new();
1624 metadata.add(KeyMetaEntry::AttestationExpirationDate(DateTime::from_millis_epoch(
1625 expiration_date,
1626 )));
1627 metadata.store_in_db(key_id, &tx).context("Failed to insert key metadata.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001628 Self::set_blob_internal(
1629 &tx,
1630 key_id,
1631 SubComponentType::CERT_CHAIN,
1632 Some(cert_chain),
1633 None,
1634 )
1635 .context("Failed to insert cert chain")?;
Max Biresb2e1d032021-02-08 21:35:05 -08001636 Self::set_blob_internal(&tx, key_id, SubComponentType::CERT, Some(batch_cert), None)
1637 .context("Failed to insert cert")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001638 Ok(()).no_gc()
Max Bires2b2e6562020-09-22 11:22:36 -07001639 })
1640 .context("In store_signed_attestation_certificate_chain: ")
1641 }
1642
1643 /// Assigns the next unassigned attestation key to a domain/namespace combo that does not
1644 /// currently have a key assigned to it.
1645 pub fn assign_attestation_key(
1646 &mut self,
1647 domain: Domain,
1648 namespace: i64,
1649 km_uuid: &Uuid,
1650 ) -> Result<()> {
1651 match domain {
1652 Domain::APP | Domain::SELINUX => {}
1653 _ => {
1654 return Err(KsError::sys()).context(format!(
1655 concat!(
1656 "In assign_attestation_key: Domain {:?} ",
1657 "must be either App or SELinux.",
1658 ),
1659 domain
1660 ));
1661 }
1662 }
1663 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1664 let result = tx
1665 .execute(
1666 "UPDATE persistent.keyentry
1667 SET domain=?1, namespace=?2
1668 WHERE
1669 id =
1670 (SELECT MIN(id)
1671 FROM persistent.keyentry
1672 WHERE ALIAS IS NOT NULL
1673 AND domain IS NULL
1674 AND key_type IS ?3
1675 AND state IS ?4
1676 AND km_uuid IS ?5)
1677 AND
1678 (SELECT COUNT(*)
1679 FROM persistent.keyentry
1680 WHERE domain=?1
1681 AND namespace=?2
1682 AND key_type IS ?3
1683 AND state IS ?4
1684 AND km_uuid IS ?5) = 0;",
1685 params![
1686 domain.0 as u32,
1687 namespace,
1688 KeyType::Attestation,
1689 KeyLifeCycle::Live,
1690 km_uuid,
1691 ],
1692 )
1693 .context("Failed to assign attestation key")?;
1694 if result != 1 {
1695 return Err(KsError::sys()).context(format!(
1696 "Expected to update a single entry but instead updated {}.",
1697 result
1698 ));
1699 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001700 Ok(()).no_gc()
Max Bires2b2e6562020-09-22 11:22:36 -07001701 })
1702 .context("In assign_attestation_key: ")
1703 }
1704
1705 /// Retrieves num_keys number of attestation keys that have not yet been signed by a remote
1706 /// provisioning server, or the maximum number available if there are not num_keys number of
1707 /// entries in the table.
1708 pub fn fetch_unsigned_attestation_keys(
1709 &mut self,
1710 num_keys: i32,
1711 km_uuid: &Uuid,
1712 ) -> Result<Vec<Vec<u8>>> {
1713 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1714 let mut stmt = tx
1715 .prepare(
1716 "SELECT data
1717 FROM persistent.keymetadata
1718 WHERE tag = ? AND keyentryid IN
1719 (SELECT id
1720 FROM persistent.keyentry
1721 WHERE
1722 alias IS NULL AND
1723 domain IS NULL AND
1724 namespace IS NULL AND
1725 key_type = ? AND
1726 km_uuid = ?
1727 LIMIT ?);",
1728 )
1729 .context("Failed to prepare statement")?;
1730 let rows = stmt
1731 .query_map(
1732 params![
1733 KeyMetaData::AttestationMacedPublicKey,
1734 KeyType::Attestation,
1735 km_uuid,
1736 num_keys
1737 ],
1738 |row| Ok(row.get(0)?),
1739 )?
1740 .collect::<rusqlite::Result<Vec<Vec<u8>>>>()
1741 .context("Failed to execute statement")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001742 Ok(rows).no_gc()
Max Bires2b2e6562020-09-22 11:22:36 -07001743 })
1744 .context("In fetch_unsigned_attestation_keys")
1745 }
1746
1747 /// Removes any keys that have expired as of the current time. Returns the number of keys
1748 /// marked unreferenced that are bound to be garbage collected.
1749 pub fn delete_expired_attestation_keys(&mut self) -> Result<i32> {
1750 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1751 let mut stmt = tx
1752 .prepare(
1753 "SELECT keyentryid, data
1754 FROM persistent.keymetadata
1755 WHERE tag = ? AND keyentryid IN
1756 (SELECT id
1757 FROM persistent.keyentry
1758 WHERE key_type = ?);",
1759 )
1760 .context("Failed to prepare query")?;
1761 let key_ids_to_check = stmt
1762 .query_map(
1763 params![KeyMetaData::AttestationExpirationDate, KeyType::Attestation],
1764 |row| Ok((row.get(0)?, row.get(1)?)),
1765 )?
1766 .collect::<rusqlite::Result<Vec<(i64, DateTime)>>>()
1767 .context("Failed to get date metadata")?;
1768 let curr_time = DateTime::from_millis_epoch(
1769 SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_millis() as i64,
1770 );
1771 let mut num_deleted = 0;
1772 for id in key_ids_to_check.iter().filter(|kt| kt.1 < curr_time).map(|kt| kt.0) {
1773 if Self::mark_unreferenced(&tx, id)? {
1774 num_deleted += 1;
1775 }
1776 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001777 Ok(num_deleted).do_gc(num_deleted != 0)
Max Bires2b2e6562020-09-22 11:22:36 -07001778 })
1779 .context("In delete_expired_attestation_keys: ")
1780 }
1781
1782 /// Counts the number of keys that will expire by the provided epoch date and the number of
1783 /// keys not currently assigned to a domain.
1784 pub fn get_attestation_pool_status(
1785 &mut self,
1786 date: i64,
1787 km_uuid: &Uuid,
1788 ) -> Result<AttestationPoolStatus> {
1789 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1790 let mut stmt = tx.prepare(
1791 "SELECT data
1792 FROM persistent.keymetadata
1793 WHERE tag = ? AND keyentryid IN
1794 (SELECT id
1795 FROM persistent.keyentry
1796 WHERE alias IS NOT NULL
1797 AND key_type = ?
1798 AND km_uuid = ?
1799 AND state = ?);",
1800 )?;
1801 let times = stmt
1802 .query_map(
1803 params![
1804 KeyMetaData::AttestationExpirationDate,
1805 KeyType::Attestation,
1806 km_uuid,
1807 KeyLifeCycle::Live
1808 ],
1809 |row| Ok(row.get(0)?),
1810 )?
1811 .collect::<rusqlite::Result<Vec<DateTime>>>()
1812 .context("Failed to execute metadata statement")?;
1813 let expiring =
1814 times.iter().filter(|time| time < &&DateTime::from_millis_epoch(date)).count()
1815 as i32;
1816 stmt = tx.prepare(
1817 "SELECT alias, domain
1818 FROM persistent.keyentry
1819 WHERE key_type = ? AND km_uuid = ? AND state = ?;",
1820 )?;
1821 let rows = stmt
1822 .query_map(params![KeyType::Attestation, km_uuid, KeyLifeCycle::Live], |row| {
1823 Ok((row.get(0)?, row.get(1)?))
1824 })?
1825 .collect::<rusqlite::Result<Vec<(Option<String>, Option<u32>)>>>()
1826 .context("Failed to execute keyentry statement")?;
1827 let mut unassigned = 0i32;
1828 let mut attested = 0i32;
1829 let total = rows.len() as i32;
1830 for (alias, domain) in rows {
1831 match (alias, domain) {
1832 (Some(_alias), None) => {
1833 attested += 1;
1834 unassigned += 1;
1835 }
1836 (Some(_alias), Some(_domain)) => {
1837 attested += 1;
1838 }
1839 _ => {}
1840 }
1841 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001842 Ok(AttestationPoolStatus { expiring, unassigned, attested, total }).no_gc()
Max Bires2b2e6562020-09-22 11:22:36 -07001843 })
1844 .context("In get_attestation_pool_status: ")
1845 }
1846
1847 /// Fetches the private key and corresponding certificate chain assigned to a
1848 /// domain/namespace pair. Will either return nothing if the domain/namespace is
1849 /// not assigned, or one CertificateChain.
1850 pub fn retrieve_attestation_key_and_cert_chain(
1851 &mut self,
1852 domain: Domain,
1853 namespace: i64,
1854 km_uuid: &Uuid,
1855 ) -> Result<Option<CertificateChain>> {
1856 match domain {
1857 Domain::APP | Domain::SELINUX => {}
1858 _ => {
1859 return Err(KsError::sys())
1860 .context(format!("Domain {:?} must be either App or SELinux.", domain));
1861 }
1862 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001863 self.with_transaction(TransactionBehavior::Deferred, |tx| {
1864 let mut stmt = tx.prepare(
1865 "SELECT subcomponent_type, blob
Max Bires2b2e6562020-09-22 11:22:36 -07001866 FROM persistent.blobentry
1867 WHERE keyentryid IN
1868 (SELECT id
1869 FROM persistent.keyentry
1870 WHERE key_type = ?
1871 AND domain = ?
1872 AND namespace = ?
1873 AND state = ?
1874 AND km_uuid = ?);",
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001875 )?;
1876 let rows = stmt
1877 .query_map(
1878 params![
1879 KeyType::Attestation,
1880 domain.0 as u32,
1881 namespace,
1882 KeyLifeCycle::Live,
1883 km_uuid
1884 ],
1885 |row| Ok((row.get(0)?, row.get(1)?)),
1886 )?
1887 .collect::<rusqlite::Result<Vec<(SubComponentType, Vec<u8>)>>>()
Max Biresb2e1d032021-02-08 21:35:05 -08001888 .context("query failed.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001889 if rows.is_empty() {
1890 return Ok(None).no_gc();
Max Biresb2e1d032021-02-08 21:35:05 -08001891 } else if rows.len() != 3 {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001892 return Err(KsError::sys()).context(format!(
1893 concat!(
Max Biresb2e1d032021-02-08 21:35:05 -08001894 "Expected to get a single attestation",
1895 "key, cert, and cert chain for a total of 3 entries, but instead got {}."
1896 ),
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001897 rows.len()
1898 ));
Max Bires2b2e6562020-09-22 11:22:36 -07001899 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001900 let mut km_blob: Vec<u8> = Vec::new();
1901 let mut cert_chain_blob: Vec<u8> = Vec::new();
Max Biresb2e1d032021-02-08 21:35:05 -08001902 let mut batch_cert_blob: Vec<u8> = Vec::new();
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001903 for row in rows {
1904 let sub_type: SubComponentType = row.0;
1905 match sub_type {
1906 SubComponentType::KEY_BLOB => {
1907 km_blob = row.1;
1908 }
1909 SubComponentType::CERT_CHAIN => {
1910 cert_chain_blob = row.1;
1911 }
Max Biresb2e1d032021-02-08 21:35:05 -08001912 SubComponentType::CERT => {
1913 batch_cert_blob = row.1;
1914 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001915 _ => Err(KsError::sys()).context("Unknown or incorrect subcomponent type.")?,
1916 }
1917 }
1918 Ok(Some(CertificateChain {
1919 private_key: ZVec::try_from(km_blob)?,
Max Bires97f96812021-02-23 23:44:57 -08001920 batch_cert: batch_cert_blob,
1921 cert_chain: cert_chain_blob,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001922 }))
1923 .no_gc()
1924 })
Max Biresb2e1d032021-02-08 21:35:05 -08001925 .context("In retrieve_attestation_key_and_cert_chain:")
Max Bires2b2e6562020-09-22 11:22:36 -07001926 }
1927
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001928 /// Updates the alias column of the given key id `newid` with the given alias,
1929 /// and atomically, removes the alias, domain, and namespace from another row
1930 /// with the same alias-domain-namespace tuple if such row exits.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001931 /// Returns Ok(true) if an old key was marked unreferenced as a hint to the garbage
1932 /// collector.
1933 fn rebind_alias(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001934 tx: &Transaction,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001935 newid: &KeyIdGuard,
Joel Galenson33c04ad2020-08-03 11:04:38 -07001936 alias: &str,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001937 domain: &Domain,
1938 namespace: &i64,
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001939 ) -> Result<bool> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001940 match *domain {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001941 Domain::APP | Domain::SELINUX => {}
Joel Galenson33c04ad2020-08-03 11:04:38 -07001942 _ => {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001943 return Err(KsError::sys()).context(format!(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001944 "In rebind_alias: Domain {:?} must be either App or SELinux.",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001945 domain
1946 ));
Joel Galenson33c04ad2020-08-03 11:04:38 -07001947 }
1948 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001949 let updated = tx
1950 .execute(
1951 "UPDATE persistent.keyentry
1952 SET alias = NULL, domain = NULL, namespace = NULL, state = ?
Joel Galenson33c04ad2020-08-03 11:04:38 -07001953 WHERE alias = ? AND domain = ? AND namespace = ?;",
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001954 params![KeyLifeCycle::Unreferenced, alias, domain.0 as u32, namespace],
1955 )
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001956 .context("In rebind_alias: Failed to rebind existing entry.")?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07001957 let result = tx
1958 .execute(
1959 "UPDATE persistent.keyentry
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001960 SET alias = ?, state = ?
1961 WHERE id = ? AND domain = ? AND namespace = ? AND state = ?;",
1962 params![
1963 alias,
1964 KeyLifeCycle::Live,
1965 newid.0,
1966 domain.0 as u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001967 *namespace,
Max Bires8e93d2b2021-01-14 13:17:59 -08001968 KeyLifeCycle::Existing,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001969 ],
Joel Galenson33c04ad2020-08-03 11:04:38 -07001970 )
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001971 .context("In rebind_alias: Failed to set alias.")?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07001972 if result != 1 {
Joel Galenson33c04ad2020-08-03 11:04:38 -07001973 return Err(KsError::sys()).context(format!(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001974 "In rebind_alias: Expected to update a single entry but instead updated {}.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07001975 result
1976 ));
1977 }
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001978 Ok(updated != 0)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001979 }
1980
1981 /// Store a new key in a single transaction.
1982 /// The function creates a new key entry, populates the blob, key parameter, and metadata
1983 /// fields, and rebinds the given alias to the new key.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001984 /// The boolean returned is a hint for the garbage collector. If true, a key was replaced,
1985 /// is now unreferenced and needs to be collected.
Janis Danisevskis66784c42021-01-27 08:40:25 -08001986 pub fn store_new_key(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001987 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001988 key: &KeyDescriptor,
1989 params: &[KeyParameter],
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001990 blob_info: &(&[u8], &BlobMetaData),
Max Bires8e93d2b2021-01-14 13:17:59 -08001991 cert_info: &CertificateInfo,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001992 metadata: &KeyMetaData,
Max Bires8e93d2b2021-01-14 13:17:59 -08001993 km_uuid: &Uuid,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001994 ) -> Result<KeyIdGuard> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001995 let (alias, domain, namespace) = match key {
1996 KeyDescriptor { alias: Some(alias), domain: Domain::APP, nspace, blob: None }
1997 | KeyDescriptor { alias: Some(alias), domain: Domain::SELINUX, nspace, blob: None } => {
1998 (alias, key.domain, nspace)
1999 }
2000 _ => {
2001 return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT))
2002 .context("In store_new_key: Need alias and domain must be APP or SELINUX.")
2003 }
2004 };
2005 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002006 let key_id = Self::create_key_entry_internal(tx, &domain, namespace, km_uuid)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002007 .context("Trying to create new key entry.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002008 let (blob, blob_metadata) = *blob_info;
2009 Self::set_blob_internal(
2010 tx,
2011 key_id.id(),
2012 SubComponentType::KEY_BLOB,
2013 Some(blob),
2014 Some(&blob_metadata),
2015 )
2016 .context("Trying to insert the key blob.")?;
Max Bires8e93d2b2021-01-14 13:17:59 -08002017 if let Some(cert) = &cert_info.cert {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002018 Self::set_blob_internal(tx, key_id.id(), SubComponentType::CERT, Some(&cert), None)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002019 .context("Trying to insert the certificate.")?;
2020 }
Max Bires8e93d2b2021-01-14 13:17:59 -08002021 if let Some(cert_chain) = &cert_info.cert_chain {
Janis Danisevskis377d1002021-01-27 19:07:48 -08002022 Self::set_blob_internal(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002023 tx,
2024 key_id.id(),
2025 SubComponentType::CERT_CHAIN,
Janis Danisevskis377d1002021-01-27 19:07:48 -08002026 Some(&cert_chain),
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002027 None,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002028 )
2029 .context("Trying to insert the certificate chain.")?;
2030 }
2031 Self::insert_keyparameter_internal(tx, &key_id, params)
2032 .context("Trying to insert key parameters.")?;
Janis Danisevskis377d1002021-01-27 19:07:48 -08002033 metadata.store_in_db(key_id.id(), tx).context("Trying to insert key metadata.")?;
Janis Danisevskis66784c42021-01-27 08:40:25 -08002034 let need_gc = Self::rebind_alias(tx, &key_id, &alias, &domain, namespace)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002035 .context("Trying to rebind alias.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002036 Ok(key_id).do_gc(need_gc)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002037 })
2038 .context("In store_new_key.")
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002039 }
2040
Janis Danisevskis377d1002021-01-27 19:07:48 -08002041 /// Store a new certificate
2042 /// The function creates a new key entry, populates the blob field and metadata, and rebinds
2043 /// the given alias to the new cert.
Max Bires8e93d2b2021-01-14 13:17:59 -08002044 pub fn store_new_certificate(
2045 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002046 key: &KeyDescriptor,
Max Bires8e93d2b2021-01-14 13:17:59 -08002047 cert: &[u8],
2048 km_uuid: &Uuid,
2049 ) -> Result<KeyIdGuard> {
Janis Danisevskis377d1002021-01-27 19:07:48 -08002050 let (alias, domain, namespace) = match key {
2051 KeyDescriptor { alias: Some(alias), domain: Domain::APP, nspace, blob: None }
2052 | KeyDescriptor { alias: Some(alias), domain: Domain::SELINUX, nspace, blob: None } => {
2053 (alias, key.domain, nspace)
2054 }
2055 _ => {
2056 return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT)).context(
2057 "In store_new_certificate: Need alias and domain must be APP or SELINUX.",
2058 )
2059 }
2060 };
2061 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002062 let key_id = Self::create_key_entry_internal(tx, &domain, namespace, km_uuid)
Janis Danisevskis377d1002021-01-27 19:07:48 -08002063 .context("Trying to create new key entry.")?;
2064
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002065 Self::set_blob_internal(
2066 tx,
2067 key_id.id(),
2068 SubComponentType::CERT_CHAIN,
2069 Some(cert),
2070 None,
2071 )
2072 .context("Trying to insert certificate.")?;
Janis Danisevskis377d1002021-01-27 19:07:48 -08002073
2074 let mut metadata = KeyMetaData::new();
2075 metadata.add(KeyMetaEntry::CreationDate(
2076 DateTime::now().context("Trying to make creation time.")?,
2077 ));
2078
2079 metadata.store_in_db(key_id.id(), tx).context("Trying to insert key metadata.")?;
2080
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002081 let need_gc = Self::rebind_alias(tx, &key_id, &alias, &domain, namespace)
Janis Danisevskis377d1002021-01-27 19:07:48 -08002082 .context("Trying to rebind alias.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002083 Ok(key_id).do_gc(need_gc)
Janis Danisevskis377d1002021-01-27 19:07:48 -08002084 })
2085 .context("In store_new_certificate.")
2086 }
2087
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002088 // Helper function loading the key_id given the key descriptor
2089 // tuple comprising domain, namespace, and alias.
2090 // Requires a valid transaction.
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002091 fn load_key_entry_id(tx: &Transaction, key: &KeyDescriptor, key_type: KeyType) -> Result<i64> {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002092 let alias = key
2093 .alias
2094 .as_ref()
2095 .map_or_else(|| Err(KsError::sys()), Ok)
2096 .context("In load_key_entry_id: Alias must be specified.")?;
2097 let mut stmt = tx
2098 .prepare(
2099 "SELECT id FROM persistent.keyentry
2100 WHERE
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00002101 key_type = ?
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002102 AND domain = ?
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002103 AND namespace = ?
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002104 AND alias = ?
2105 AND state = ?;",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002106 )
2107 .context("In load_key_entry_id: Failed to select from keyentry table.")?;
2108 let mut rows = stmt
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002109 .query(params![key_type, key.domain.0 as u32, key.nspace, alias, KeyLifeCycle::Live])
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002110 .context("In load_key_entry_id: Failed to read from keyentry table.")?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002111 db_utils::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002112 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002113 .get(0)
2114 .context("Failed to unpack id.")
2115 })
2116 .context("In load_key_entry_id.")
2117 }
2118
2119 /// This helper function completes the access tuple of a key, which is required
2120 /// to perform access control. The strategy depends on the `domain` field in the
2121 /// key descriptor.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002122 /// * Domain::SELINUX: The access tuple is complete and this function only loads
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002123 /// the key_id for further processing.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002124 /// * Domain::APP: Like Domain::SELINUX, but the tuple is completed by `caller_uid`
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002125 /// which serves as the namespace.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002126 /// * Domain::GRANT: The grant table is queried for the `key_id` and the
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002127 /// `access_vector`.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002128 /// * Domain::KEY_ID: The keyentry table is queried for the owning `domain` and
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002129 /// `namespace`.
2130 /// In each case the information returned is sufficient to perform the access
2131 /// check and the key id can be used to load further key artifacts.
2132 fn load_access_tuple(
2133 tx: &Transaction,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002134 key: &KeyDescriptor,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002135 key_type: KeyType,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002136 caller_uid: u32,
2137 ) -> Result<(i64, KeyDescriptor, Option<KeyPermSet>)> {
2138 match key.domain {
2139 // Domain App or SELinux. In this case we load the key_id from
2140 // the keyentry database for further loading of key components.
2141 // We already have the full access tuple to perform access control.
2142 // The only distinction is that we use the caller_uid instead
2143 // of the caller supplied namespace if the domain field is
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002144 // Domain::APP.
2145 Domain::APP | Domain::SELINUX => {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002146 let mut access_key = key.clone();
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002147 if access_key.domain == Domain::APP {
2148 access_key.nspace = caller_uid as i64;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002149 }
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002150 let key_id = Self::load_key_entry_id(&tx, &access_key, key_type)
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002151 .with_context(|| format!("With key.domain = {:?}.", access_key.domain))?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002152
2153 Ok((key_id, access_key, None))
2154 }
2155
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002156 // Domain::GRANT. In this case we load the key_id and the access_vector
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002157 // from the grant table.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002158 Domain::GRANT => {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002159 let mut stmt = tx
2160 .prepare(
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002161 "SELECT keyentryid, access_vector FROM persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002162 WHERE grantee = ? AND id = ?;",
2163 )
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002164 .context("Domain::GRANT prepare statement failed")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002165 let mut rows = stmt
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002166 .query(params![caller_uid as i64, key.nspace])
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002167 .context("Domain:Grant: query failed.")?;
2168 let (key_id, access_vector): (i64, i32) =
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002169 db_utils::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002170 let r =
2171 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002172 Ok((
2173 r.get(0).context("Failed to unpack key_id.")?,
2174 r.get(1).context("Failed to unpack access_vector.")?,
2175 ))
2176 })
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002177 .context("Domain::GRANT.")?;
Janis Danisevskis66784c42021-01-27 08:40:25 -08002178 Ok((key_id, key.clone(), Some(access_vector.into())))
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002179 }
2180
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002181 // Domain::KEY_ID. In this case we load the domain and namespace from the
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002182 // keyentry database because we need them for access control.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002183 Domain::KEY_ID => {
Janis Danisevskis45760022021-01-19 16:34:10 -08002184 let (domain, namespace): (Domain, i64) = {
2185 let mut stmt = tx
2186 .prepare(
2187 "SELECT domain, namespace FROM persistent.keyentry
2188 WHERE
2189 id = ?
2190 AND state = ?;",
2191 )
2192 .context("Domain::KEY_ID: prepare statement failed")?;
2193 let mut rows = stmt
2194 .query(params![key.nspace, KeyLifeCycle::Live])
2195 .context("Domain::KEY_ID: query failed.")?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002196 db_utils::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002197 let r =
2198 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002199 Ok((
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002200 Domain(r.get(0).context("Failed to unpack domain.")?),
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002201 r.get(1).context("Failed to unpack namespace.")?,
2202 ))
2203 })
Janis Danisevskis45760022021-01-19 16:34:10 -08002204 .context("Domain::KEY_ID.")?
2205 };
2206
2207 // We may use a key by id after loading it by grant.
2208 // In this case we have to check if the caller has a grant for this particular
2209 // key. We can skip this if we already know that the caller is the owner.
2210 // But we cannot know this if domain is anything but App. E.g. in the case
2211 // of Domain::SELINUX we have to speculatively check for grants because we have to
2212 // consult the SEPolicy before we know if the caller is the owner.
2213 let access_vector: Option<KeyPermSet> =
2214 if domain != Domain::APP || namespace != caller_uid as i64 {
2215 let access_vector: Option<i32> = tx
2216 .query_row(
2217 "SELECT access_vector FROM persistent.grant
2218 WHERE grantee = ? AND keyentryid = ?;",
2219 params![caller_uid as i64, key.nspace],
2220 |row| row.get(0),
2221 )
2222 .optional()
2223 .context("Domain::KEY_ID: query grant failed.")?;
2224 access_vector.map(|p| p.into())
2225 } else {
2226 None
2227 };
2228
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002229 let key_id = key.nspace;
Janis Danisevskis66784c42021-01-27 08:40:25 -08002230 let mut access_key: KeyDescriptor = key.clone();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002231 access_key.domain = domain;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002232 access_key.nspace = namespace;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002233
Janis Danisevskis45760022021-01-19 16:34:10 -08002234 Ok((key_id, access_key, access_vector))
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002235 }
2236 _ => Err(anyhow!(KsError::sys())),
2237 }
2238 }
2239
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002240 fn load_blob_components(
2241 key_id: i64,
2242 load_bits: KeyEntryLoadBits,
2243 tx: &Transaction,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002244 ) -> Result<(bool, Option<(Vec<u8>, BlobMetaData)>, Option<Vec<u8>>, Option<Vec<u8>>)> {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002245 let mut stmt = tx
2246 .prepare(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002247 "SELECT MAX(id), subcomponent_type, blob FROM persistent.blobentry
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002248 WHERE keyentryid = ? GROUP BY subcomponent_type;",
2249 )
2250 .context("In load_blob_components: prepare statement failed.")?;
2251
2252 let mut rows =
2253 stmt.query(params![key_id]).context("In load_blob_components: query failed.")?;
2254
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002255 let mut key_blob: Option<(i64, Vec<u8>)> = None;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002256 let mut cert_blob: Option<Vec<u8>> = None;
2257 let mut cert_chain_blob: Option<Vec<u8>> = None;
Janis Danisevskis377d1002021-01-27 19:07:48 -08002258 let mut has_km_blob: bool = false;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002259 db_utils::with_rows_extract_all(&mut rows, |row| {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002260 let sub_type: SubComponentType =
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002261 row.get(1).context("Failed to extract subcomponent_type.")?;
Janis Danisevskis377d1002021-01-27 19:07:48 -08002262 has_km_blob = has_km_blob || sub_type == SubComponentType::KEY_BLOB;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002263 match (sub_type, load_bits.load_public(), load_bits.load_km()) {
2264 (SubComponentType::KEY_BLOB, _, true) => {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002265 key_blob = Some((
2266 row.get(0).context("Failed to extract key blob id.")?,
2267 row.get(2).context("Failed to extract key blob.")?,
2268 ));
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002269 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002270 (SubComponentType::CERT, true, _) => {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002271 cert_blob =
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002272 Some(row.get(2).context("Failed to extract public certificate blob.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002273 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002274 (SubComponentType::CERT_CHAIN, true, _) => {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002275 cert_chain_blob =
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002276 Some(row.get(2).context("Failed to extract certificate chain blob.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002277 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002278 (SubComponentType::CERT, _, _)
2279 | (SubComponentType::CERT_CHAIN, _, _)
2280 | (SubComponentType::KEY_BLOB, _, _) => {}
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002281 _ => Err(KsError::sys()).context("Unknown subcomponent type.")?,
2282 }
2283 Ok(())
2284 })
2285 .context("In load_blob_components.")?;
2286
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002287 let blob_info = key_blob.map_or::<Result<_>, _>(Ok(None), |(blob_id, blob)| {
2288 Ok(Some((
2289 blob,
2290 BlobMetaData::load_from_db(blob_id, tx)
2291 .context("In load_blob_components: Trying to load blob_metadata.")?,
2292 )))
2293 })?;
2294
2295 Ok((has_km_blob, blob_info, cert_blob, cert_chain_blob))
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002296 }
2297
2298 fn load_key_parameters(key_id: i64, tx: &Transaction) -> Result<Vec<KeyParameter>> {
2299 let mut stmt = tx
2300 .prepare(
2301 "SELECT tag, data, security_level from persistent.keyparameter
2302 WHERE keyentryid = ?;",
2303 )
2304 .context("In load_key_parameters: prepare statement failed.")?;
2305
2306 let mut parameters: Vec<KeyParameter> = Vec::new();
2307
2308 let mut rows =
2309 stmt.query(params![key_id]).context("In load_key_parameters: query failed.")?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002310 db_utils::with_rows_extract_all(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002311 let tag = Tag(row.get(0).context("Failed to read tag.")?);
2312 let sec_level = SecurityLevel(row.get(2).context("Failed to read sec_level.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002313 parameters.push(
2314 KeyParameter::new_from_sql(tag, &SqlField::new(1, &row), sec_level)
2315 .context("Failed to read KeyParameter.")?,
2316 );
2317 Ok(())
2318 })
2319 .context("In load_key_parameters.")?;
2320
2321 Ok(parameters)
2322 }
2323
Qi Wub9433b52020-12-01 14:52:46 +08002324 /// Decrements the usage count of a limited use key. This function first checks whether the
2325 /// usage has been exhausted, if not, decreases the usage count. If the usage count reaches
2326 /// zero, the key also gets marked unreferenced and scheduled for deletion.
2327 /// Returns Ok(true) if the key was marked unreferenced as a hint to the garbage collector.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002328 pub fn check_and_update_key_usage_count(&mut self, key_id: i64) -> Result<()> {
Qi Wub9433b52020-12-01 14:52:46 +08002329 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2330 let limit: Option<i32> = tx
2331 .query_row(
2332 "SELECT data FROM persistent.keyparameter WHERE keyentryid = ? AND tag = ?;",
2333 params![key_id, Tag::USAGE_COUNT_LIMIT.0],
2334 |row| row.get(0),
2335 )
2336 .optional()
2337 .context("Trying to load usage count")?;
2338
2339 let limit = limit
2340 .ok_or(KsError::Km(ErrorCode::INVALID_KEY_BLOB))
2341 .context("The Key no longer exists. Key is exhausted.")?;
2342
2343 tx.execute(
2344 "UPDATE persistent.keyparameter
2345 SET data = data - 1
2346 WHERE keyentryid = ? AND tag = ? AND data > 0;",
2347 params![key_id, Tag::USAGE_COUNT_LIMIT.0],
2348 )
2349 .context("Failed to update key usage count.")?;
2350
2351 match limit {
2352 1 => Self::mark_unreferenced(tx, key_id)
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002353 .map(|need_gc| (need_gc, ()))
Qi Wub9433b52020-12-01 14:52:46 +08002354 .context("Trying to mark limited use key for deletion."),
2355 0 => Err(KsError::Km(ErrorCode::INVALID_KEY_BLOB)).context("Key is exhausted."),
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002356 _ => Ok(()).no_gc(),
Qi Wub9433b52020-12-01 14:52:46 +08002357 }
2358 })
2359 .context("In check_and_update_key_usage_count.")
2360 }
2361
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002362 /// Load a key entry by the given key descriptor.
2363 /// It uses the `check_permission` callback to verify if the access is allowed
2364 /// given the key access tuple read from the database using `load_access_tuple`.
2365 /// With `load_bits` the caller may specify which blobs shall be loaded from
2366 /// the blob database.
2367 pub fn load_key_entry(
2368 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002369 key: &KeyDescriptor,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002370 key_type: KeyType,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002371 load_bits: KeyEntryLoadBits,
2372 caller_uid: u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002373 check_permission: impl Fn(&KeyDescriptor, Option<KeyPermSet>) -> Result<()>,
2374 ) -> Result<(KeyIdGuard, KeyEntry)> {
2375 loop {
2376 match self.load_key_entry_internal(
2377 key,
2378 key_type,
2379 load_bits,
2380 caller_uid,
2381 &check_permission,
2382 ) {
2383 Ok(result) => break Ok(result),
2384 Err(e) => {
2385 if Self::is_locked_error(&e) {
2386 std::thread::sleep(std::time::Duration::from_micros(500));
2387 continue;
2388 } else {
2389 return Err(e).context("In load_key_entry.");
2390 }
2391 }
2392 }
2393 }
2394 }
2395
2396 fn load_key_entry_internal(
2397 &mut self,
2398 key: &KeyDescriptor,
2399 key_type: KeyType,
2400 load_bits: KeyEntryLoadBits,
2401 caller_uid: u32,
2402 check_permission: &impl Fn(&KeyDescriptor, Option<KeyPermSet>) -> Result<()>,
Janis Danisevskisaec14592020-11-12 09:41:49 -08002403 ) -> Result<(KeyIdGuard, KeyEntry)> {
2404 // KEY ID LOCK 1/2
2405 // If we got a key descriptor with a key id we can get the lock right away.
2406 // Otherwise we have to defer it until we know the key id.
2407 let key_id_guard = match key.domain {
2408 Domain::KEY_ID => Some(KEY_ID_LOCK.get(key.nspace)),
2409 _ => None,
2410 };
2411
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002412 let tx = self
2413 .conn
Janis Danisevskisaec14592020-11-12 09:41:49 -08002414 .unchecked_transaction()
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002415 .context("In load_key_entry: Failed to initialize transaction.")?;
2416
2417 // Load the key_id and complete the access control tuple.
2418 let (key_id, access_key_descriptor, access_vector) =
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002419 Self::load_access_tuple(&tx, key, key_type, caller_uid)
2420 .context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002421
2422 // Perform access control. It is vital that we return here if the permission is denied.
2423 // So do not touch that '?' at the end.
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002424 check_permission(&access_key_descriptor, access_vector).context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002425
Janis Danisevskisaec14592020-11-12 09:41:49 -08002426 // KEY ID LOCK 2/2
2427 // If we did not get a key id lock by now, it was because we got a key descriptor
2428 // without a key id. At this point we got the key id, so we can try and get a lock.
2429 // However, we cannot block here, because we are in the middle of the transaction.
2430 // So first we try to get the lock non blocking. If that fails, we roll back the
2431 // transaction and block until we get the lock. After we successfully got the lock,
2432 // we start a new transaction and load the access tuple again.
2433 //
2434 // We don't need to perform access control again, because we already established
2435 // that the caller had access to the given key. But we need to make sure that the
2436 // key id still exists. So we have to load the key entry by key id this time.
2437 let (key_id_guard, tx) = match key_id_guard {
2438 None => match KEY_ID_LOCK.try_get(key_id) {
2439 None => {
2440 // Roll back the transaction.
2441 tx.rollback().context("In load_key_entry: Failed to roll back transaction.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002442
Janis Danisevskisaec14592020-11-12 09:41:49 -08002443 // Block until we have a key id lock.
2444 let key_id_guard = KEY_ID_LOCK.get(key_id);
2445
2446 // Create a new transaction.
Janis Danisevskis66784c42021-01-27 08:40:25 -08002447 let tx = self
2448 .conn
2449 .unchecked_transaction()
2450 .context("In load_key_entry: Failed to initialize transaction.")?;
Janis Danisevskisaec14592020-11-12 09:41:49 -08002451
2452 Self::load_access_tuple(
2453 &tx,
2454 // This time we have to load the key by the retrieved key id, because the
2455 // alias may have been rebound after we rolled back the transaction.
Janis Danisevskis66784c42021-01-27 08:40:25 -08002456 &KeyDescriptor {
Janis Danisevskisaec14592020-11-12 09:41:49 -08002457 domain: Domain::KEY_ID,
2458 nspace: key_id,
2459 ..Default::default()
2460 },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002461 key_type,
Janis Danisevskisaec14592020-11-12 09:41:49 -08002462 caller_uid,
2463 )
2464 .context("In load_key_entry. (deferred key lock)")?;
2465 (key_id_guard, tx)
2466 }
2467 Some(l) => (l, tx),
2468 },
2469 Some(key_id_guard) => (key_id_guard, tx),
2470 };
2471
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002472 let key_entry = Self::load_key_components(&tx, load_bits, key_id_guard.id())
2473 .context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002474
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002475 tx.commit().context("In load_key_entry: Failed to commit transaction.")?;
2476
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002477 Ok((key_id_guard, key_entry))
2478 }
2479
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002480 fn mark_unreferenced(tx: &Transaction, key_id: i64) -> Result<bool> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002481 let updated = tx
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002482 .execute("DELETE FROM persistent.keyentry WHERE id = ?;", params![key_id])
2483 .context("Trying to delete keyentry.")?;
2484 tx.execute("DELETE FROM persistent.keymetadata WHERE keyentryid = ?;", params![key_id])
2485 .context("Trying to delete keymetadata.")?;
2486 tx.execute("DELETE FROM persistent.keyparameter WHERE keyentryid = ?;", params![key_id])
2487 .context("Trying to delete keyparameters.")?;
2488 tx.execute("DELETE FROM persistent.grant WHERE keyentryid = ?;", params![key_id])
2489 .context("Trying to delete grants.")?;
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002490 Ok(updated != 0)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002491 }
2492
2493 /// Marks the given key as unreferenced and removes all of the grants to this key.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002494 /// Returns Ok(true) if a key was marked unreferenced as a hint for the garbage collector.
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002495 pub fn unbind_key(
2496 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002497 key: &KeyDescriptor,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002498 key_type: KeyType,
2499 caller_uid: u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002500 check_permission: impl Fn(&KeyDescriptor, Option<KeyPermSet>) -> Result<()>,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002501 ) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002502 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2503 let (key_id, access_key_descriptor, access_vector) =
2504 Self::load_access_tuple(tx, key, key_type, caller_uid)
2505 .context("Trying to get access tuple.")?;
2506
2507 // Perform access control. It is vital that we return here if the permission is denied.
2508 // So do not touch that '?' at the end.
2509 check_permission(&access_key_descriptor, access_vector)
2510 .context("While checking permission.")?;
2511
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002512 Self::mark_unreferenced(tx, key_id)
2513 .map(|need_gc| (need_gc, ()))
2514 .context("Trying to mark the key unreferenced.")
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002515 })
2516 .context("In unbind_key.")
2517 }
2518
Max Bires8e93d2b2021-01-14 13:17:59 -08002519 fn get_key_km_uuid(tx: &Transaction, key_id: i64) -> Result<Uuid> {
2520 tx.query_row(
2521 "SELECT km_uuid FROM persistent.keyentry WHERE id = ?",
2522 params![key_id],
2523 |row| row.get(0),
2524 )
2525 .context("In get_key_km_uuid.")
2526 }
2527
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002528 /// Delete all artifacts belonging to the namespace given by the domain-namespace tuple.
2529 /// This leaves all of the blob entries orphaned for subsequent garbage collection.
2530 pub fn unbind_keys_for_namespace(&mut self, domain: Domain, namespace: i64) -> Result<()> {
2531 if !(domain == Domain::APP || domain == Domain::SELINUX) {
2532 return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT))
2533 .context("In unbind_keys_for_namespace.");
2534 }
2535 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2536 tx.execute(
2537 "DELETE FROM persistent.keymetadata
2538 WHERE keyentryid IN (
2539 SELECT id FROM persistent.keyentry
2540 WHERE domain = ? AND namespace = ?
2541 );",
2542 params![domain.0, namespace],
2543 )
2544 .context("Trying to delete keymetadata.")?;
2545 tx.execute(
2546 "DELETE FROM persistent.keyparameter
2547 WHERE keyentryid IN (
2548 SELECT id FROM persistent.keyentry
2549 WHERE domain = ? AND namespace = ?
2550 );",
2551 params![domain.0, namespace],
2552 )
2553 .context("Trying to delete keyparameters.")?;
2554 tx.execute(
2555 "DELETE FROM persistent.grant
2556 WHERE keyentryid IN (
2557 SELECT id FROM persistent.keyentry
2558 WHERE domain = ? AND namespace = ?
2559 );",
2560 params![domain.0, namespace],
2561 )
2562 .context("Trying to delete grants.")?;
2563 tx.execute(
2564 "DELETE FROM persistent.keyentry WHERE domain = ? AND namespace = ?;",
2565 params![domain.0, namespace],
2566 )
2567 .context("Trying to delete keyentry.")?;
2568 Ok(()).need_gc()
2569 })
2570 .context("In unbind_keys_for_namespace")
2571 }
2572
Hasini Gunasingheda895552021-01-27 19:34:37 +00002573 /// Delete the keys created on behalf of the user, denoted by the user id.
2574 /// Delete all the keys unless 'keep_non_super_encrypted_keys' set to true.
2575 /// Returned boolean is to hint the garbage collector to delete the unbound keys.
2576 /// The caller of this function should notify the gc if the returned value is true.
2577 pub fn unbind_keys_for_user(
2578 &mut self,
2579 user_id: u32,
2580 keep_non_super_encrypted_keys: bool,
2581 ) -> Result<()> {
2582 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2583 let mut stmt = tx
2584 .prepare(&format!(
2585 "SELECT id from persistent.keyentry
2586 WHERE (
2587 key_type = ?
2588 AND domain = ?
2589 AND cast ( (namespace/{aid_user_offset}) as int) = ?
2590 AND state = ?
2591 ) OR (
2592 key_type = ?
2593 AND namespace = ?
2594 AND alias = ?
2595 AND state = ?
2596 );",
2597 aid_user_offset = AID_USER_OFFSET
2598 ))
2599 .context(concat!(
2600 "In unbind_keys_for_user. ",
2601 "Failed to prepare the query to find the keys created by apps."
2602 ))?;
2603
2604 let mut rows = stmt
2605 .query(params![
2606 // WHERE client key:
2607 KeyType::Client,
2608 Domain::APP.0 as u32,
2609 user_id,
2610 KeyLifeCycle::Live,
2611 // OR super key:
2612 KeyType::Super,
2613 user_id,
2614 Self::USER_SUPER_KEY_ALIAS,
2615 KeyLifeCycle::Live
2616 ])
2617 .context("In unbind_keys_for_user. Failed to query the keys created by apps.")?;
2618
2619 let mut key_ids: Vec<i64> = Vec::new();
2620 db_utils::with_rows_extract_all(&mut rows, |row| {
2621 key_ids
2622 .push(row.get(0).context("Failed to read key id of a key created by an app.")?);
2623 Ok(())
2624 })
2625 .context("In unbind_keys_for_user.")?;
2626
2627 let mut notify_gc = false;
2628 for key_id in key_ids {
2629 if keep_non_super_encrypted_keys {
2630 // Load metadata and filter out non-super-encrypted keys.
2631 if let (_, Some((_, blob_metadata)), _, _) =
2632 Self::load_blob_components(key_id, KeyEntryLoadBits::KM, tx)
2633 .context("In unbind_keys_for_user: Trying to load blob info.")?
2634 {
2635 if blob_metadata.encrypted_by().is_none() {
2636 continue;
2637 }
2638 }
2639 }
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +00002640 notify_gc = Self::mark_unreferenced(&tx, key_id)
Hasini Gunasingheda895552021-01-27 19:34:37 +00002641 .context("In unbind_keys_for_user.")?
2642 || notify_gc;
2643 }
2644 Ok(()).do_gc(notify_gc)
2645 })
2646 .context("In unbind_keys_for_user.")
2647 }
2648
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002649 fn load_key_components(
2650 tx: &Transaction,
2651 load_bits: KeyEntryLoadBits,
2652 key_id: i64,
2653 ) -> Result<KeyEntry> {
2654 let metadata = KeyMetaData::load_from_db(key_id, &tx).context("In load_key_components.")?;
2655
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002656 let (has_km_blob, key_blob_info, cert_blob, cert_chain_blob) =
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002657 Self::load_blob_components(key_id, load_bits, &tx)
2658 .context("In load_key_components.")?;
2659
Max Bires8e93d2b2021-01-14 13:17:59 -08002660 let parameters = Self::load_key_parameters(key_id, &tx)
2661 .context("In load_key_components: Trying to load key parameters.")?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002662
Max Bires8e93d2b2021-01-14 13:17:59 -08002663 let km_uuid = Self::get_key_km_uuid(&tx, key_id)
2664 .context("In load_key_components: Trying to get KM uuid.")?;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002665
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002666 Ok(KeyEntry {
2667 id: key_id,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002668 key_blob_info,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002669 cert: cert_blob,
2670 cert_chain: cert_chain_blob,
Max Bires8e93d2b2021-01-14 13:17:59 -08002671 km_uuid,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002672 parameters,
2673 metadata,
Janis Danisevskis377d1002021-01-27 19:07:48 -08002674 pure_cert: !has_km_blob,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002675 })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002676 }
2677
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002678 /// Returns a list of KeyDescriptors in the selected domain/namespace.
2679 /// The key descriptors will have the domain, nspace, and alias field set.
2680 /// Domain must be APP or SELINUX, the caller must make sure of that.
2681 pub fn list(&mut self, domain: Domain, namespace: i64) -> Result<Vec<KeyDescriptor>> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002682 self.with_transaction(TransactionBehavior::Deferred, |tx| {
2683 let mut stmt = tx
2684 .prepare(
2685 "SELECT alias FROM persistent.keyentry
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002686 WHERE domain = ? AND namespace = ? AND alias IS NOT NULL AND state = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08002687 )
2688 .context("In list: Failed to prepare.")?;
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002689
Janis Danisevskis66784c42021-01-27 08:40:25 -08002690 let mut rows = stmt
2691 .query(params![domain.0 as u32, namespace, KeyLifeCycle::Live])
2692 .context("In list: Failed to query.")?;
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002693
Janis Danisevskis66784c42021-01-27 08:40:25 -08002694 let mut descriptors: Vec<KeyDescriptor> = Vec::new();
2695 db_utils::with_rows_extract_all(&mut rows, |row| {
2696 descriptors.push(KeyDescriptor {
2697 domain,
2698 nspace: namespace,
2699 alias: Some(row.get(0).context("Trying to extract alias.")?),
2700 blob: None,
2701 });
2702 Ok(())
2703 })
2704 .context("In list: Failed to extract rows.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002705 Ok(descriptors).no_gc()
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002706 })
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002707 }
2708
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002709 /// Adds a grant to the grant table.
2710 /// Like `load_key_entry` this function loads the access tuple before
2711 /// it uses the callback for a permission check. Upon success,
2712 /// it inserts the `grantee_uid`, `key_id`, and `access_vector` into the
2713 /// grant table. The new row will have a randomized id, which is used as
2714 /// grant id in the namespace field of the resulting KeyDescriptor.
2715 pub fn grant(
2716 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002717 key: &KeyDescriptor,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002718 caller_uid: u32,
2719 grantee_uid: u32,
2720 access_vector: KeyPermSet,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002721 check_permission: impl Fn(&KeyDescriptor, &KeyPermSet) -> Result<()>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002722 ) -> Result<KeyDescriptor> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002723 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2724 // Load the key_id and complete the access control tuple.
2725 // We ignore the access vector here because grants cannot be granted.
2726 // The access vector returned here expresses the permissions the
2727 // grantee has if key.domain == Domain::GRANT. But this vector
2728 // cannot include the grant permission by design, so there is no way the
2729 // subsequent permission check can pass.
2730 // We could check key.domain == Domain::GRANT and fail early.
2731 // But even if we load the access tuple by grant here, the permission
2732 // check denies the attempt to create a grant by grant descriptor.
2733 let (key_id, access_key_descriptor, _) =
2734 Self::load_access_tuple(&tx, key, KeyType::Client, caller_uid)
2735 .context("In grant")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002736
Janis Danisevskis66784c42021-01-27 08:40:25 -08002737 // Perform access control. It is vital that we return here if the permission
2738 // was denied. So do not touch that '?' at the end of the line.
2739 // This permission check checks if the caller has the grant permission
2740 // for the given key and in addition to all of the permissions
2741 // expressed in `access_vector`.
2742 check_permission(&access_key_descriptor, &access_vector)
2743 .context("In grant: check_permission failed.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002744
Janis Danisevskis66784c42021-01-27 08:40:25 -08002745 let grant_id = if let Some(grant_id) = tx
2746 .query_row(
2747 "SELECT id FROM persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002748 WHERE keyentryid = ? AND grantee = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08002749 params![key_id, grantee_uid],
2750 |row| row.get(0),
2751 )
2752 .optional()
2753 .context("In grant: Failed get optional existing grant id.")?
2754 {
2755 tx.execute(
2756 "UPDATE persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002757 SET access_vector = ?
2758 WHERE id = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08002759 params![i32::from(access_vector), grant_id],
Joel Galenson845f74b2020-09-09 14:11:55 -07002760 )
Janis Danisevskis66784c42021-01-27 08:40:25 -08002761 .context("In grant: Failed to update existing grant.")?;
2762 grant_id
2763 } else {
2764 Self::insert_with_retry(|id| {
2765 tx.execute(
2766 "INSERT INTO persistent.grant (id, grantee, keyentryid, access_vector)
2767 VALUES (?, ?, ?, ?);",
2768 params![id, grantee_uid, key_id, i32::from(access_vector)],
2769 )
2770 })
2771 .context("In grant")?
2772 };
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002773
Janis Danisevskis66784c42021-01-27 08:40:25 -08002774 Ok(KeyDescriptor { domain: Domain::GRANT, nspace: grant_id, alias: None, blob: None })
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002775 .no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08002776 })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002777 }
2778
2779 /// This function checks permissions like `grant` and `load_key_entry`
2780 /// before removing a grant from the grant table.
2781 pub fn ungrant(
2782 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002783 key: &KeyDescriptor,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002784 caller_uid: u32,
2785 grantee_uid: u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002786 check_permission: impl Fn(&KeyDescriptor) -> Result<()>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002787 ) -> Result<()> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002788 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2789 // Load the key_id and complete the access control tuple.
2790 // We ignore the access vector here because grants cannot be granted.
2791 let (key_id, access_key_descriptor, _) =
2792 Self::load_access_tuple(&tx, key, KeyType::Client, caller_uid)
2793 .context("In ungrant.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002794
Janis Danisevskis66784c42021-01-27 08:40:25 -08002795 // Perform access control. We must return here if the permission
2796 // was denied. So do not touch the '?' at the end of this line.
2797 check_permission(&access_key_descriptor)
2798 .context("In grant: check_permission failed.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002799
Janis Danisevskis66784c42021-01-27 08:40:25 -08002800 tx.execute(
2801 "DELETE FROM persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002802 WHERE keyentryid = ? AND grantee = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08002803 params![key_id, grantee_uid],
2804 )
2805 .context("Failed to delete grant.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002806
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002807 Ok(()).no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08002808 })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002809 }
2810
Joel Galenson845f74b2020-09-09 14:11:55 -07002811 // Generates a random id and passes it to the given function, which will
2812 // try to insert it into a database. If that insertion fails, retry;
2813 // otherwise return the id.
2814 fn insert_with_retry(inserter: impl Fn(i64) -> rusqlite::Result<usize>) -> Result<i64> {
2815 loop {
Janis Danisevskiseed69842021-02-18 20:04:10 -08002816 let newid: i64 = match random() {
2817 Self::UNASSIGNED_KEY_ID => continue, // UNASSIGNED_KEY_ID cannot be assigned.
2818 i => i,
2819 };
Joel Galenson845f74b2020-09-09 14:11:55 -07002820 match inserter(newid) {
2821 // If the id already existed, try again.
2822 Err(rusqlite::Error::SqliteFailure(
2823 libsqlite3_sys::Error {
2824 code: libsqlite3_sys::ErrorCode::ConstraintViolation,
2825 extended_code: libsqlite3_sys::SQLITE_CONSTRAINT_UNIQUE,
2826 },
2827 _,
2828 )) => (),
2829 Err(e) => {
2830 return Err(e).context("In insert_with_retry: failed to insert into database.")
2831 }
2832 _ => return Ok(newid),
2833 }
2834 }
2835 }
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002836
2837 /// Insert or replace the auth token based on the UNIQUE constraint of the auth token table
2838 pub fn insert_auth_token(&mut self, auth_token: &HardwareAuthToken) -> Result<()> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002839 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2840 tx.execute(
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002841 "INSERT OR REPLACE INTO perboot.authtoken (challenge, user_id, auth_id,
2842 authenticator_type, timestamp, mac, time_received) VALUES(?, ?, ?, ?, ?, ?, ?);",
2843 params![
2844 auth_token.challenge,
2845 auth_token.userId,
2846 auth_token.authenticatorId,
2847 auth_token.authenticatorType.0 as i32,
2848 auth_token.timestamp.milliSeconds as i64,
2849 auth_token.mac,
2850 MonotonicRawTime::now(),
2851 ],
2852 )
2853 .context("In insert_auth_token: failed to insert auth token into the database")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002854 Ok(()).no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08002855 })
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002856 }
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002857
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002858 /// Find the newest auth token matching the given predicate.
2859 pub fn find_auth_token_entry<F>(
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002860 &mut self,
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002861 p: F,
2862 ) -> Result<Option<(AuthTokenEntry, MonotonicRawTime)>>
2863 where
2864 F: Fn(&AuthTokenEntry) -> bool,
2865 {
2866 self.with_transaction(TransactionBehavior::Deferred, |tx| {
2867 let mut stmt = tx
2868 .prepare("SELECT * from perboot.authtoken ORDER BY time_received DESC;")
2869 .context("Prepare statement failed.")?;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002870
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002871 let mut rows = stmt.query(NO_PARAMS).context("Failed to query.")?;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002872
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002873 while let Some(row) = rows.next().context("Failed to get next row.")? {
2874 let entry = AuthTokenEntry::new(
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002875 HardwareAuthToken {
2876 challenge: row.get(1)?,
2877 userId: row.get(2)?,
2878 authenticatorId: row.get(3)?,
2879 authenticatorType: HardwareAuthenticatorType(row.get(4)?),
2880 timestamp: Timestamp { milliSeconds: row.get(5)? },
2881 mac: row.get(6)?,
2882 },
2883 row.get(7)?,
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002884 );
2885 if p(&entry) {
2886 return Ok(Some((
2887 entry,
2888 Self::get_last_off_body(tx)
2889 .context("In find_auth_token_entry: Trying to get last off body")?,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002890 )))
2891 .no_gc();
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002892 }
2893 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002894 Ok(None).no_gc()
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002895 })
2896 .context("In find_auth_token_entry.")
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002897 }
2898
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002899 /// Insert last_off_body into the metadata table at the initialization of auth token table
Janis Danisevskis66784c42021-01-27 08:40:25 -08002900 pub fn insert_last_off_body(&mut self, last_off_body: MonotonicRawTime) -> Result<()> {
2901 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2902 tx.execute(
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002903 "INSERT OR REPLACE INTO perboot.metadata (key, value) VALUES (?, ?);",
2904 params!["last_off_body", last_off_body],
2905 )
2906 .context("In insert_last_off_body: failed to insert.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002907 Ok(()).no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08002908 })
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002909 }
2910
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002911 /// Update last_off_body when on_device_off_body is called
Janis Danisevskis66784c42021-01-27 08:40:25 -08002912 pub fn update_last_off_body(&mut self, last_off_body: MonotonicRawTime) -> Result<()> {
2913 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2914 tx.execute(
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002915 "UPDATE perboot.metadata SET value = ? WHERE key = ?;",
2916 params![last_off_body, "last_off_body"],
2917 )
2918 .context("In update_last_off_body: failed to update.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002919 Ok(()).no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08002920 })
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002921 }
2922
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002923 /// Get last_off_body time when finding auth tokens
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002924 fn get_last_off_body(tx: &Transaction) -> Result<MonotonicRawTime> {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002925 tx.query_row(
2926 "SELECT value from perboot.metadata WHERE key = ?;",
2927 params!["last_off_body"],
2928 |row| Ok(row.get(0)?),
2929 )
2930 .context("In get_last_off_body: query_row failed.")
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002931 }
Joel Galenson26f4d012020-07-17 14:57:21 -07002932}
2933
2934#[cfg(test)]
2935mod tests {
2936
2937 use super::*;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002938 use crate::key_parameter::{
2939 Algorithm, BlockMode, Digest, EcCurve, HardwareAuthenticatorType, KeyOrigin, KeyParameter,
2940 KeyParameterValue, KeyPurpose, PaddingMode, SecurityLevel,
2941 };
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002942 use crate::key_perm_set;
2943 use crate::permission::{KeyPerm, KeyPermSet};
Hasini Gunasingheda895552021-01-27 19:34:37 +00002944 use crate::super_key::SuperKeyManager;
Janis Danisevskis2a8330a2021-01-20 15:34:26 -08002945 use keystore2_test_utils::TempDir;
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002946 use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
2947 HardwareAuthToken::HardwareAuthToken,
2948 HardwareAuthenticatorType::HardwareAuthenticatorType as kmhw_authenticator_type,
Janis Danisevskisc3a496b2021-01-05 10:37:22 -08002949 };
2950 use android_hardware_security_secureclock::aidl::android::hardware::security::secureclock::{
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002951 Timestamp::Timestamp,
2952 };
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002953 use rusqlite::NO_PARAMS;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002954 use rusqlite::{Error, TransactionBehavior};
Joel Galenson0891bc12020-07-20 10:37:03 -07002955 use std::cell::RefCell;
Janis Danisevskisaec14592020-11-12 09:41:49 -08002956 use std::sync::atomic::{AtomicU8, Ordering};
2957 use std::sync::Arc;
2958 use std::thread;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002959 use std::time::{Duration, SystemTime};
Janis Danisevskis66784c42021-01-27 08:40:25 -08002960 #[cfg(disabled)]
2961 use std::time::Instant;
Joel Galenson0891bc12020-07-20 10:37:03 -07002962
Janis Danisevskis4df44f42020-08-26 14:40:03 -07002963 fn new_test_db() -> Result<KeystoreDB> {
2964 let conn = KeystoreDB::make_connection("file::memory:", "file::memory:")?;
2965
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002966 let mut db = KeystoreDB { conn, gc: None };
Janis Danisevskis66784c42021-01-27 08:40:25 -08002967 db.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002968 KeystoreDB::init_tables(tx).context("Failed to initialize tables.").no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08002969 })?;
2970 Ok(db)
Janis Danisevskis4df44f42020-08-26 14:40:03 -07002971 }
2972
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002973 fn new_test_db_with_gc<F>(path: &Path, cb: F) -> Result<KeystoreDB>
2974 where
2975 F: Fn(&Uuid, &[u8]) -> Result<()> + Send + 'static,
2976 {
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00002977 let super_key = Arc::new(SuperKeyManager::new());
2978
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002979 let gc_db = KeystoreDB::new(path, None).expect("Failed to open test gc db_connection.");
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00002980 let gc = Gc::new_init_with(Default::default(), move || (Box::new(cb), gc_db, super_key));
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002981
2982 KeystoreDB::new(path, Some(gc))
2983 }
2984
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002985 fn rebind_alias(
2986 db: &mut KeystoreDB,
2987 newid: &KeyIdGuard,
2988 alias: &str,
2989 domain: Domain,
2990 namespace: i64,
2991 ) -> Result<bool> {
2992 db.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002993 KeystoreDB::rebind_alias(tx, newid, alias, &domain, &namespace).no_gc()
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002994 })
2995 .context("In rebind_alias.")
2996 }
2997
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002998 #[test]
2999 fn datetime() -> Result<()> {
3000 let conn = Connection::open_in_memory()?;
3001 conn.execute("CREATE TABLE test (ts DATETIME);", NO_PARAMS)?;
3002 let now = SystemTime::now();
3003 let duration = Duration::from_secs(1000);
3004 let then = now.checked_sub(duration).unwrap();
3005 let soon = now.checked_add(duration).unwrap();
3006 conn.execute(
3007 "INSERT INTO test (ts) VALUES (?), (?), (?);",
3008 params![DateTime::try_from(now)?, DateTime::try_from(then)?, DateTime::try_from(soon)?],
3009 )?;
3010 let mut stmt = conn.prepare("SELECT ts FROM test ORDER BY ts ASC;")?;
3011 let mut rows = stmt.query(NO_PARAMS)?;
3012 assert_eq!(DateTime::try_from(then)?, rows.next()?.unwrap().get(0)?);
3013 assert_eq!(DateTime::try_from(now)?, rows.next()?.unwrap().get(0)?);
3014 assert_eq!(DateTime::try_from(soon)?, rows.next()?.unwrap().get(0)?);
3015 assert!(rows.next()?.is_none());
3016 assert!(DateTime::try_from(then)? < DateTime::try_from(now)?);
3017 assert!(DateTime::try_from(then)? < DateTime::try_from(soon)?);
3018 assert!(DateTime::try_from(now)? < DateTime::try_from(soon)?);
3019 Ok(())
3020 }
3021
Joel Galenson0891bc12020-07-20 10:37:03 -07003022 // Ensure that we're using the "injected" random function, not the real one.
3023 #[test]
3024 fn test_mocked_random() {
3025 let rand1 = random();
3026 let rand2 = random();
3027 let rand3 = random();
3028 if rand1 == rand2 {
3029 assert_eq!(rand2 + 1, rand3);
3030 } else {
3031 assert_eq!(rand1 + 1, rand2);
3032 assert_eq!(rand2, rand3);
3033 }
3034 }
Joel Galenson26f4d012020-07-17 14:57:21 -07003035
Joel Galenson26f4d012020-07-17 14:57:21 -07003036 // Test that we have the correct tables.
3037 #[test]
3038 fn test_tables() -> Result<()> {
Janis Danisevskis4df44f42020-08-26 14:40:03 -07003039 let db = new_test_db()?;
Joel Galenson26f4d012020-07-17 14:57:21 -07003040 let tables = db
3041 .conn
Joel Galenson2aab4432020-07-22 15:27:57 -07003042 .prepare("SELECT name from persistent.sqlite_master WHERE type='table' ORDER BY name;")?
Joel Galenson26f4d012020-07-17 14:57:21 -07003043 .query_map(params![], |row| row.get(0))?
3044 .collect::<rusqlite::Result<Vec<String>>>()?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003045 assert_eq!(tables.len(), 6);
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003046 assert_eq!(tables[0], "blobentry");
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003047 assert_eq!(tables[1], "blobmetadata");
3048 assert_eq!(tables[2], "grant");
3049 assert_eq!(tables[3], "keyentry");
3050 assert_eq!(tables[4], "keymetadata");
3051 assert_eq!(tables[5], "keyparameter");
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003052 let tables = db
3053 .conn
3054 .prepare("SELECT name from perboot.sqlite_master WHERE type='table' ORDER BY name;")?
3055 .query_map(params![], |row| row.get(0))?
3056 .collect::<rusqlite::Result<Vec<String>>>()?;
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00003057
3058 assert_eq!(tables.len(), 2);
3059 assert_eq!(tables[0], "authtoken");
3060 assert_eq!(tables[1], "metadata");
Joel Galenson2aab4432020-07-22 15:27:57 -07003061 Ok(())
3062 }
3063
3064 #[test]
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00003065 fn test_auth_token_table_invariant() -> Result<()> {
3066 let mut db = new_test_db()?;
3067 let auth_token1 = HardwareAuthToken {
3068 challenge: i64::MAX,
3069 userId: 200,
3070 authenticatorId: 200,
3071 authenticatorType: kmhw_authenticator_type(kmhw_authenticator_type::PASSWORD.0),
3072 timestamp: Timestamp { milliSeconds: 500 },
3073 mac: String::from("mac").into_bytes(),
3074 };
3075 db.insert_auth_token(&auth_token1)?;
3076 let auth_tokens_returned = get_auth_tokens(&mut db)?;
3077 assert_eq!(auth_tokens_returned.len(), 1);
3078
3079 // insert another auth token with the same values for the columns in the UNIQUE constraint
3080 // of the auth token table and different value for timestamp
3081 let auth_token2 = HardwareAuthToken {
3082 challenge: i64::MAX,
3083 userId: 200,
3084 authenticatorId: 200,
3085 authenticatorType: kmhw_authenticator_type(kmhw_authenticator_type::PASSWORD.0),
3086 timestamp: Timestamp { milliSeconds: 600 },
3087 mac: String::from("mac").into_bytes(),
3088 };
3089
3090 db.insert_auth_token(&auth_token2)?;
3091 let mut auth_tokens_returned = get_auth_tokens(&mut db)?;
3092 assert_eq!(auth_tokens_returned.len(), 1);
3093
3094 if let Some(auth_token) = auth_tokens_returned.pop() {
3095 assert_eq!(auth_token.auth_token.timestamp.milliSeconds, 600);
3096 }
3097
3098 // insert another auth token with the different values for the columns in the UNIQUE
3099 // constraint of the auth token table
3100 let auth_token3 = HardwareAuthToken {
3101 challenge: i64::MAX,
3102 userId: 201,
3103 authenticatorId: 200,
3104 authenticatorType: kmhw_authenticator_type(kmhw_authenticator_type::PASSWORD.0),
3105 timestamp: Timestamp { milliSeconds: 600 },
3106 mac: String::from("mac").into_bytes(),
3107 };
3108
3109 db.insert_auth_token(&auth_token3)?;
3110 let auth_tokens_returned = get_auth_tokens(&mut db)?;
3111 assert_eq!(auth_tokens_returned.len(), 2);
3112
3113 Ok(())
3114 }
3115
3116 // utility function for test_auth_token_table_invariant()
3117 fn get_auth_tokens(db: &mut KeystoreDB) -> Result<Vec<AuthTokenEntry>> {
3118 let mut stmt = db.conn.prepare("SELECT * from perboot.authtoken;")?;
3119
3120 let auth_token_entries: Vec<AuthTokenEntry> = stmt
3121 .query_map(NO_PARAMS, |row| {
3122 Ok(AuthTokenEntry::new(
3123 HardwareAuthToken {
3124 challenge: row.get(1)?,
3125 userId: row.get(2)?,
3126 authenticatorId: row.get(3)?,
3127 authenticatorType: HardwareAuthenticatorType(row.get(4)?),
3128 timestamp: Timestamp { milliSeconds: row.get(5)? },
3129 mac: row.get(6)?,
3130 },
3131 row.get(7)?,
3132 ))
3133 })?
3134 .collect::<Result<Vec<AuthTokenEntry>, Error>>()?;
3135 Ok(auth_token_entries)
3136 }
3137
3138 #[test]
Joel Galenson2aab4432020-07-22 15:27:57 -07003139 fn test_persistence_for_files() -> Result<()> {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08003140 let temp_dir = TempDir::new("persistent_db_test")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003141 let mut db = KeystoreDB::new(temp_dir.path(), None)?;
Joel Galenson2aab4432020-07-22 15:27:57 -07003142
Janis Danisevskis66784c42021-01-27 08:40:25 -08003143 db.create_key_entry(&Domain::APP, &100, &KEYSTORE_UUID)?;
Joel Galenson2aab4432020-07-22 15:27:57 -07003144 let entries = get_keyentry(&db)?;
3145 assert_eq!(entries.len(), 1);
Janis Danisevskisbf15d732020-12-08 10:35:26 -08003146
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003147 let db = KeystoreDB::new(temp_dir.path(), None)?;
Joel Galenson2aab4432020-07-22 15:27:57 -07003148
3149 let entries_new = get_keyentry(&db)?;
3150 assert_eq!(entries, entries_new);
3151 Ok(())
3152 }
3153
3154 #[test]
Joel Galenson0891bc12020-07-20 10:37:03 -07003155 fn test_create_key_entry() -> Result<()> {
Max Bires8e93d2b2021-01-14 13:17:59 -08003156 fn extractor(ke: &KeyEntryRow) -> (Domain, i64, Option<&str>, Uuid) {
3157 (ke.domain.unwrap(), ke.namespace.unwrap(), ke.alias.as_deref(), ke.km_uuid.unwrap())
Joel Galenson0891bc12020-07-20 10:37:03 -07003158 }
3159
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003160 let mut db = new_test_db()?;
Joel Galenson0891bc12020-07-20 10:37:03 -07003161
Janis Danisevskis66784c42021-01-27 08:40:25 -08003162 db.create_key_entry(&Domain::APP, &100, &KEYSTORE_UUID)?;
3163 db.create_key_entry(&Domain::SELINUX, &101, &KEYSTORE_UUID)?;
Joel Galenson0891bc12020-07-20 10:37:03 -07003164
3165 let entries = get_keyentry(&db)?;
3166 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08003167 assert_eq!(extractor(&entries[0]), (Domain::APP, 100, None, KEYSTORE_UUID));
3168 assert_eq!(extractor(&entries[1]), (Domain::SELINUX, 101, None, KEYSTORE_UUID));
Joel Galenson0891bc12020-07-20 10:37:03 -07003169
3170 // Test that we must pass in a valid Domain.
3171 check_result_is_error_containing_string(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003172 db.create_key_entry(&Domain::GRANT, &102, &KEYSTORE_UUID),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003173 "Domain Domain(1) must be either App or SELinux.",
Joel Galenson0891bc12020-07-20 10:37:03 -07003174 );
3175 check_result_is_error_containing_string(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003176 db.create_key_entry(&Domain::BLOB, &103, &KEYSTORE_UUID),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003177 "Domain Domain(3) must be either App or SELinux.",
Joel Galenson0891bc12020-07-20 10:37:03 -07003178 );
3179 check_result_is_error_containing_string(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003180 db.create_key_entry(&Domain::KEY_ID, &104, &KEYSTORE_UUID),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003181 "Domain Domain(4) must be either App or SELinux.",
Joel Galenson0891bc12020-07-20 10:37:03 -07003182 );
3183
3184 Ok(())
3185 }
3186
Joel Galenson33c04ad2020-08-03 11:04:38 -07003187 #[test]
Max Bires2b2e6562020-09-22 11:22:36 -07003188 fn test_add_unsigned_key() -> Result<()> {
3189 let mut db = new_test_db()?;
3190 let public_key: Vec<u8> = vec![0x01, 0x02, 0x03];
3191 let private_key: Vec<u8> = vec![0x04, 0x05, 0x06];
3192 let raw_public_key: Vec<u8> = vec![0x07, 0x08, 0x09];
3193 db.create_attestation_key_entry(
3194 &public_key,
3195 &raw_public_key,
3196 &private_key,
3197 &KEYSTORE_UUID,
3198 )?;
3199 let keys = db.fetch_unsigned_attestation_keys(5, &KEYSTORE_UUID)?;
3200 assert_eq!(keys.len(), 1);
3201 assert_eq!(keys[0], public_key);
3202 Ok(())
3203 }
3204
3205 #[test]
3206 fn test_store_signed_attestation_certificate_chain() -> Result<()> {
3207 let mut db = new_test_db()?;
3208 let expiration_date: i64 = 20;
3209 let namespace: i64 = 30;
3210 let base_byte: u8 = 1;
3211 let loaded_values =
3212 load_attestation_key_pool(&mut db, expiration_date, namespace, base_byte)?;
3213 let chain =
3214 db.retrieve_attestation_key_and_cert_chain(Domain::APP, namespace, &KEYSTORE_UUID)?;
3215 assert_eq!(true, chain.is_some());
3216 let cert_chain = chain.unwrap();
Max Biresb2e1d032021-02-08 21:35:05 -08003217 assert_eq!(cert_chain.private_key.to_vec(), loaded_values.priv_key);
Max Bires97f96812021-02-23 23:44:57 -08003218 assert_eq!(cert_chain.batch_cert, loaded_values.batch_cert);
3219 assert_eq!(cert_chain.cert_chain, loaded_values.cert_chain);
Max Bires2b2e6562020-09-22 11:22:36 -07003220 Ok(())
3221 }
3222
3223 #[test]
3224 fn test_get_attestation_pool_status() -> Result<()> {
3225 let mut db = new_test_db()?;
3226 let namespace: i64 = 30;
3227 load_attestation_key_pool(
3228 &mut db, 10, /* expiration */
3229 namespace, 0x01, /* base_byte */
3230 )?;
3231 load_attestation_key_pool(&mut db, 20 /* expiration */, namespace + 1, 0x02)?;
3232 load_attestation_key_pool(&mut db, 40 /* expiration */, namespace + 2, 0x03)?;
3233 let mut status = db.get_attestation_pool_status(9 /* expiration */, &KEYSTORE_UUID)?;
3234 assert_eq!(status.expiring, 0);
3235 assert_eq!(status.attested, 3);
3236 assert_eq!(status.unassigned, 0);
3237 assert_eq!(status.total, 3);
3238 assert_eq!(
3239 db.get_attestation_pool_status(15 /* expiration */, &KEYSTORE_UUID)?.expiring,
3240 1
3241 );
3242 assert_eq!(
3243 db.get_attestation_pool_status(25 /* expiration */, &KEYSTORE_UUID)?.expiring,
3244 2
3245 );
3246 assert_eq!(
3247 db.get_attestation_pool_status(60 /* expiration */, &KEYSTORE_UUID)?.expiring,
3248 3
3249 );
3250 let public_key: Vec<u8> = vec![0x01, 0x02, 0x03];
3251 let private_key: Vec<u8> = vec![0x04, 0x05, 0x06];
3252 let raw_public_key: Vec<u8> = vec![0x07, 0x08, 0x09];
3253 let cert_chain: Vec<u8> = vec![0x0a, 0x0b, 0x0c];
Max Biresb2e1d032021-02-08 21:35:05 -08003254 let batch_cert: Vec<u8> = vec![0x0d, 0x0e, 0x0f];
Max Bires2b2e6562020-09-22 11:22:36 -07003255 db.create_attestation_key_entry(
3256 &public_key,
3257 &raw_public_key,
3258 &private_key,
3259 &KEYSTORE_UUID,
3260 )?;
3261 status = db.get_attestation_pool_status(0 /* expiration */, &KEYSTORE_UUID)?;
3262 assert_eq!(status.attested, 3);
3263 assert_eq!(status.unassigned, 0);
3264 assert_eq!(status.total, 4);
3265 db.store_signed_attestation_certificate_chain(
3266 &raw_public_key,
Max Biresb2e1d032021-02-08 21:35:05 -08003267 &batch_cert,
Max Bires2b2e6562020-09-22 11:22:36 -07003268 &cert_chain,
3269 20,
3270 &KEYSTORE_UUID,
3271 )?;
3272 status = db.get_attestation_pool_status(0 /* expiration */, &KEYSTORE_UUID)?;
3273 assert_eq!(status.attested, 4);
3274 assert_eq!(status.unassigned, 1);
3275 assert_eq!(status.total, 4);
3276 Ok(())
3277 }
3278
3279 #[test]
3280 fn test_remove_expired_certs() -> Result<()> {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003281 let temp_dir =
3282 TempDir::new("test_remove_expired_certs_").expect("Failed to create temp dir.");
3283 let mut db = new_test_db_with_gc(temp_dir.path(), |_, _| Ok(()))?;
Max Bires2b2e6562020-09-22 11:22:36 -07003284 let expiration_date: i64 =
3285 SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_millis() as i64 + 10000;
3286 let namespace: i64 = 30;
3287 let namespace_del1: i64 = 45;
3288 let namespace_del2: i64 = 60;
3289 let entry_values = load_attestation_key_pool(
3290 &mut db,
3291 expiration_date,
3292 namespace,
3293 0x01, /* base_byte */
3294 )?;
3295 load_attestation_key_pool(&mut db, 45, namespace_del1, 0x02)?;
3296 load_attestation_key_pool(&mut db, 60, namespace_del2, 0x03)?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003297
3298 let blob_entry_row_count: u32 = db
3299 .conn
3300 .query_row("SELECT COUNT(id) FROM persistent.blobentry;", NO_PARAMS, |row| row.get(0))
3301 .expect("Failed to get blob entry row count.");
Max Biresb2e1d032021-02-08 21:35:05 -08003302 // We expect 9 rows here because there are three blobs per attestation key, i.e.,
3303 // one key, one certificate chain, and one certificate.
3304 assert_eq!(blob_entry_row_count, 9);
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003305
Max Bires2b2e6562020-09-22 11:22:36 -07003306 assert_eq!(db.delete_expired_attestation_keys()?, 2);
3307
3308 let mut cert_chain =
3309 db.retrieve_attestation_key_and_cert_chain(Domain::APP, namespace, &KEYSTORE_UUID)?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003310 assert!(cert_chain.is_some());
Max Bires2b2e6562020-09-22 11:22:36 -07003311 let value = cert_chain.unwrap();
Max Bires97f96812021-02-23 23:44:57 -08003312 assert_eq!(entry_values.batch_cert, value.batch_cert);
3313 assert_eq!(entry_values.cert_chain, value.cert_chain);
Max Biresb2e1d032021-02-08 21:35:05 -08003314 assert_eq!(entry_values.priv_key, value.private_key.to_vec());
Max Bires2b2e6562020-09-22 11:22:36 -07003315
3316 cert_chain = db.retrieve_attestation_key_and_cert_chain(
3317 Domain::APP,
3318 namespace_del1,
3319 &KEYSTORE_UUID,
3320 )?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003321 assert!(!cert_chain.is_some());
Max Bires2b2e6562020-09-22 11:22:36 -07003322 cert_chain = db.retrieve_attestation_key_and_cert_chain(
3323 Domain::APP,
3324 namespace_del2,
3325 &KEYSTORE_UUID,
3326 )?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003327 assert!(!cert_chain.is_some());
Max Bires2b2e6562020-09-22 11:22:36 -07003328
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003329 // Give the garbage collector half a second to catch up.
3330 std::thread::sleep(Duration::from_millis(500));
Max Bires2b2e6562020-09-22 11:22:36 -07003331
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003332 let blob_entry_row_count: u32 = db
3333 .conn
3334 .query_row("SELECT COUNT(id) FROM persistent.blobentry;", NO_PARAMS, |row| row.get(0))
3335 .expect("Failed to get blob entry row count.");
Max Biresb2e1d032021-02-08 21:35:05 -08003336 // There shound be 3 blob entries left, because we deleted two of the attestation
3337 // key entries with three blobs each.
3338 assert_eq!(blob_entry_row_count, 3);
Max Bires2b2e6562020-09-22 11:22:36 -07003339
Max Bires2b2e6562020-09-22 11:22:36 -07003340 Ok(())
3341 }
3342
3343 #[test]
Joel Galenson33c04ad2020-08-03 11:04:38 -07003344 fn test_rebind_alias() -> Result<()> {
Max Bires8e93d2b2021-01-14 13:17:59 -08003345 fn extractor(
3346 ke: &KeyEntryRow,
3347 ) -> (Option<Domain>, Option<i64>, Option<&str>, Option<Uuid>) {
3348 (ke.domain, ke.namespace, ke.alias.as_deref(), ke.km_uuid)
Joel Galenson33c04ad2020-08-03 11:04:38 -07003349 }
3350
Janis Danisevskis4df44f42020-08-26 14:40:03 -07003351 let mut db = new_test_db()?;
Janis Danisevskis66784c42021-01-27 08:40:25 -08003352 db.create_key_entry(&Domain::APP, &42, &KEYSTORE_UUID)?;
3353 db.create_key_entry(&Domain::APP, &42, &KEYSTORE_UUID)?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07003354 let entries = get_keyentry(&db)?;
3355 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08003356 assert_eq!(
3357 extractor(&entries[0]),
3358 (Some(Domain::APP), Some(42), None, Some(KEYSTORE_UUID))
3359 );
3360 assert_eq!(
3361 extractor(&entries[1]),
3362 (Some(Domain::APP), Some(42), None, Some(KEYSTORE_UUID))
3363 );
Joel Galenson33c04ad2020-08-03 11:04:38 -07003364
3365 // Test that the first call to rebind_alias sets the alias.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003366 rebind_alias(&mut db, &KEY_ID_LOCK.get(entries[0].id), "foo", Domain::APP, 42)?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07003367 let entries = get_keyentry(&db)?;
3368 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08003369 assert_eq!(
3370 extractor(&entries[0]),
3371 (Some(Domain::APP), Some(42), Some("foo"), Some(KEYSTORE_UUID))
3372 );
3373 assert_eq!(
3374 extractor(&entries[1]),
3375 (Some(Domain::APP), Some(42), None, Some(KEYSTORE_UUID))
3376 );
Joel Galenson33c04ad2020-08-03 11:04:38 -07003377
3378 // Test that the second call to rebind_alias also empties the old one.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003379 rebind_alias(&mut db, &KEY_ID_LOCK.get(entries[1].id), "foo", Domain::APP, 42)?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07003380 let entries = get_keyentry(&db)?;
3381 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08003382 assert_eq!(extractor(&entries[0]), (None, None, None, Some(KEYSTORE_UUID)));
3383 assert_eq!(
3384 extractor(&entries[1]),
3385 (Some(Domain::APP), Some(42), Some("foo"), Some(KEYSTORE_UUID))
3386 );
Joel Galenson33c04ad2020-08-03 11:04:38 -07003387
3388 // Test that we must pass in a valid Domain.
3389 check_result_is_error_containing_string(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003390 rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::GRANT, 42),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003391 "Domain Domain(1) must be either App or SELinux.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07003392 );
3393 check_result_is_error_containing_string(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003394 rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::BLOB, 42),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003395 "Domain Domain(3) must be either App or SELinux.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07003396 );
3397 check_result_is_error_containing_string(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003398 rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::KEY_ID, 42),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003399 "Domain Domain(4) must be either App or SELinux.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07003400 );
3401
3402 // Test that we correctly handle setting an alias for something that does not exist.
3403 check_result_is_error_containing_string(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003404 rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::SELINUX, 42),
Joel Galenson33c04ad2020-08-03 11:04:38 -07003405 "Expected to update a single entry but instead updated 0",
3406 );
3407 // Test that we correctly abort the transaction in this case.
3408 let entries = get_keyentry(&db)?;
3409 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08003410 assert_eq!(extractor(&entries[0]), (None, None, None, Some(KEYSTORE_UUID)));
3411 assert_eq!(
3412 extractor(&entries[1]),
3413 (Some(Domain::APP), Some(42), Some("foo"), Some(KEYSTORE_UUID))
3414 );
Joel Galenson33c04ad2020-08-03 11:04:38 -07003415
3416 Ok(())
3417 }
3418
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003419 #[test]
3420 fn test_grant_ungrant() -> Result<()> {
3421 const CALLER_UID: u32 = 15;
3422 const GRANTEE_UID: u32 = 12;
3423 const SELINUX_NAMESPACE: i64 = 7;
3424
3425 let mut db = new_test_db()?;
3426 db.conn.execute(
Max Bires8e93d2b2021-01-14 13:17:59 -08003427 "INSERT INTO persistent.keyentry (id, key_type, domain, namespace, alias, state, km_uuid)
3428 VALUES (1, 0, 0, 15, 'key', 1, ?), (2, 0, 2, 7, 'yek', 1, ?);",
3429 params![KEYSTORE_UUID, KEYSTORE_UUID],
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003430 )?;
3431 let app_key = KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003432 domain: super::Domain::APP,
3433 nspace: 0,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003434 alias: Some("key".to_string()),
3435 blob: None,
3436 };
3437 const PVEC1: KeyPermSet = key_perm_set![KeyPerm::use_(), KeyPerm::get_info()];
3438 const PVEC2: KeyPermSet = key_perm_set![KeyPerm::use_()];
3439
3440 // Reset totally predictable random number generator in case we
3441 // are not the first test running on this thread.
3442 reset_random();
3443 let next_random = 0i64;
3444
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003445 let app_granted_key = db
Janis Danisevskis66784c42021-01-27 08:40:25 -08003446 .grant(&app_key, CALLER_UID, GRANTEE_UID, PVEC1, |k, a| {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003447 assert_eq!(*a, PVEC1);
3448 assert_eq!(
3449 *k,
3450 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003451 domain: super::Domain::APP,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003452 // namespace must be set to the caller_uid.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003453 nspace: CALLER_UID as i64,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003454 alias: Some("key".to_string()),
3455 blob: None,
3456 }
3457 );
3458 Ok(())
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003459 })
3460 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003461
3462 assert_eq!(
3463 app_granted_key,
3464 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003465 domain: super::Domain::GRANT,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003466 // The grantid is next_random due to the mock random number generator.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003467 nspace: next_random,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003468 alias: None,
3469 blob: None,
3470 }
3471 );
3472
3473 let selinux_key = KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003474 domain: super::Domain::SELINUX,
3475 nspace: SELINUX_NAMESPACE,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003476 alias: Some("yek".to_string()),
3477 blob: None,
3478 };
3479
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003480 let selinux_granted_key = db
Janis Danisevskis66784c42021-01-27 08:40:25 -08003481 .grant(&selinux_key, CALLER_UID, 12, PVEC1, |k, a| {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003482 assert_eq!(*a, PVEC1);
3483 assert_eq!(
3484 *k,
3485 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003486 domain: super::Domain::SELINUX,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003487 // namespace must be the supplied SELinux
3488 // namespace.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003489 nspace: SELINUX_NAMESPACE,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003490 alias: Some("yek".to_string()),
3491 blob: None,
3492 }
3493 );
3494 Ok(())
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003495 })
3496 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003497
3498 assert_eq!(
3499 selinux_granted_key,
3500 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003501 domain: super::Domain::GRANT,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003502 // The grantid is next_random + 1 due to the mock random number generator.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003503 nspace: next_random + 1,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003504 alias: None,
3505 blob: None,
3506 }
3507 );
3508
3509 // This should update the existing grant with PVEC2.
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003510 let selinux_granted_key = db
Janis Danisevskis66784c42021-01-27 08:40:25 -08003511 .grant(&selinux_key, CALLER_UID, 12, PVEC2, |k, a| {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003512 assert_eq!(*a, PVEC2);
3513 assert_eq!(
3514 *k,
3515 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003516 domain: super::Domain::SELINUX,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003517 // namespace must be the supplied SELinux
3518 // namespace.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003519 nspace: SELINUX_NAMESPACE,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003520 alias: Some("yek".to_string()),
3521 blob: None,
3522 }
3523 );
3524 Ok(())
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003525 })
3526 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003527
3528 assert_eq!(
3529 selinux_granted_key,
3530 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003531 domain: super::Domain::GRANT,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003532 // Same grant id as before. The entry was only updated.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003533 nspace: next_random + 1,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003534 alias: None,
3535 blob: None,
3536 }
3537 );
3538
3539 {
3540 // Limiting scope of stmt, because it borrows db.
3541 let mut stmt = db
3542 .conn
Janis Danisevskisbf15d732020-12-08 10:35:26 -08003543 .prepare("SELECT id, grantee, keyentryid, access_vector FROM persistent.grant;")?;
Janis Danisevskisee10b5f2020-09-22 16:42:35 -07003544 let mut rows =
3545 stmt.query_map::<(i64, u32, i64, KeyPermSet), _, _>(NO_PARAMS, |row| {
3546 Ok((
3547 row.get(0)?,
3548 row.get(1)?,
3549 row.get(2)?,
3550 KeyPermSet::from(row.get::<_, i32>(3)?),
3551 ))
3552 })?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003553
3554 let r = rows.next().unwrap().unwrap();
Janis Danisevskisee10b5f2020-09-22 16:42:35 -07003555 assert_eq!(r, (next_random, GRANTEE_UID, 1, PVEC1));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003556 let r = rows.next().unwrap().unwrap();
Janis Danisevskisee10b5f2020-09-22 16:42:35 -07003557 assert_eq!(r, (next_random + 1, GRANTEE_UID, 2, PVEC2));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003558 assert!(rows.next().is_none());
3559 }
3560
3561 debug_dump_keyentry_table(&mut db)?;
3562 println!("app_key {:?}", app_key);
3563 println!("selinux_key {:?}", selinux_key);
3564
Janis Danisevskis66784c42021-01-27 08:40:25 -08003565 db.ungrant(&app_key, CALLER_UID, GRANTEE_UID, |_| Ok(()))?;
3566 db.ungrant(&selinux_key, CALLER_UID, GRANTEE_UID, |_| Ok(()))?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003567
3568 Ok(())
3569 }
3570
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003571 static TEST_KEY_BLOB: &[u8] = b"my test blob";
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003572 static TEST_CERT_BLOB: &[u8] = b"my test cert";
3573 static TEST_CERT_CHAIN_BLOB: &[u8] = b"my test cert_chain";
3574
3575 #[test]
Janis Danisevskis377d1002021-01-27 19:07:48 -08003576 fn test_set_blob() -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003577 let key_id = KEY_ID_LOCK.get(3000);
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003578 let mut db = new_test_db()?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003579 let mut blob_metadata = BlobMetaData::new();
3580 blob_metadata.add(BlobMetaEntry::KmUuid(KEYSTORE_UUID));
3581 db.set_blob(
3582 &key_id,
3583 SubComponentType::KEY_BLOB,
3584 Some(TEST_KEY_BLOB),
3585 Some(&blob_metadata),
3586 )?;
3587 db.set_blob(&key_id, SubComponentType::CERT, Some(TEST_CERT_BLOB), None)?;
3588 db.set_blob(&key_id, SubComponentType::CERT_CHAIN, Some(TEST_CERT_CHAIN_BLOB), None)?;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003589 drop(key_id);
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003590
3591 let mut stmt = db.conn.prepare(
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003592 "SELECT subcomponent_type, keyentryid, blob, id FROM persistent.blobentry
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003593 ORDER BY subcomponent_type ASC;",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003594 )?;
3595 let mut rows = stmt
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003596 .query_map::<((SubComponentType, i64, Vec<u8>), i64), _, _>(NO_PARAMS, |row| {
3597 Ok(((row.get(0)?, row.get(1)?, row.get(2)?), row.get(3)?))
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003598 })?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003599 let (r, id) = rows.next().unwrap().unwrap();
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003600 assert_eq!(r, (SubComponentType::KEY_BLOB, 3000, TEST_KEY_BLOB.to_vec()));
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003601 let (r, _) = rows.next().unwrap().unwrap();
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003602 assert_eq!(r, (SubComponentType::CERT, 3000, TEST_CERT_BLOB.to_vec()));
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003603 let (r, _) = rows.next().unwrap().unwrap();
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003604 assert_eq!(r, (SubComponentType::CERT_CHAIN, 3000, TEST_CERT_CHAIN_BLOB.to_vec()));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003605
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003606 drop(rows);
3607 drop(stmt);
3608
3609 assert_eq!(
3610 db.with_transaction(TransactionBehavior::Immediate, |tx| {
3611 BlobMetaData::load_from_db(id, tx).no_gc()
3612 })
3613 .expect("Should find blob metadata."),
3614 blob_metadata
3615 );
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003616 Ok(())
3617 }
3618
3619 static TEST_ALIAS: &str = "my super duper key";
3620
3621 #[test]
3622 fn test_insert_and_load_full_keyentry_domain_app() -> Result<()> {
3623 let mut db = new_test_db()?;
Qi Wub9433b52020-12-01 14:52:46 +08003624 let key_id = make_test_key_entry(&mut db, Domain::APP, 1, TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08003625 .context("test_insert_and_load_full_keyentry_domain_app")?
3626 .0;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003627 let (_key_guard, key_entry) = db
3628 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003629 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003630 domain: Domain::APP,
3631 nspace: 0,
3632 alias: Some(TEST_ALIAS.to_string()),
3633 blob: None,
3634 },
3635 KeyType::Client,
3636 KeyEntryLoadBits::BOTH,
3637 1,
3638 |_k, _av| Ok(()),
3639 )
3640 .unwrap();
Qi Wub9433b52020-12-01 14:52:46 +08003641 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003642
3643 db.unbind_key(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003644 &KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003645 domain: Domain::APP,
3646 nspace: 0,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003647 alias: Some(TEST_ALIAS.to_string()),
3648 blob: None,
3649 },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003650 KeyType::Client,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003651 1,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003652 |_, _| 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 Danisevskis93927dd2020-12-23 12:23:08 -08003660 domain: Domain::APP,
3661 nspace: 0,
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
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003675 Ok(())
3676 }
3677
3678 #[test]
Janis Danisevskis377d1002021-01-27 19:07:48 -08003679 fn test_insert_and_load_certificate_entry_domain_app() -> Result<()> {
3680 let mut db = new_test_db()?;
3681
3682 db.store_new_certificate(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003683 &KeyDescriptor {
Janis Danisevskis377d1002021-01-27 19:07:48 -08003684 domain: Domain::APP,
3685 nspace: 1,
3686 alias: Some(TEST_ALIAS.to_string()),
3687 blob: None,
3688 },
3689 TEST_CERT_BLOB,
Max Bires8e93d2b2021-01-14 13:17:59 -08003690 &KEYSTORE_UUID,
Janis Danisevskis377d1002021-01-27 19:07:48 -08003691 )
3692 .expect("Trying to insert cert.");
3693
3694 let (_key_guard, mut key_entry) = db
3695 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003696 &KeyDescriptor {
Janis Danisevskis377d1002021-01-27 19:07:48 -08003697 domain: Domain::APP,
3698 nspace: 1,
3699 alias: Some(TEST_ALIAS.to_string()),
3700 blob: None,
3701 },
3702 KeyType::Client,
3703 KeyEntryLoadBits::PUBLIC,
3704 1,
3705 |_k, _av| Ok(()),
3706 )
3707 .expect("Trying to read certificate entry.");
3708
3709 assert!(key_entry.pure_cert());
3710 assert!(key_entry.cert().is_none());
3711 assert_eq!(key_entry.take_cert_chain(), Some(TEST_CERT_BLOB.to_vec()));
3712
3713 db.unbind_key(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003714 &KeyDescriptor {
Janis Danisevskis377d1002021-01-27 19:07:48 -08003715 domain: Domain::APP,
3716 nspace: 1,
3717 alias: Some(TEST_ALIAS.to_string()),
3718 blob: None,
3719 },
3720 KeyType::Client,
3721 1,
3722 |_, _| Ok(()),
3723 )
3724 .unwrap();
3725
3726 assert_eq!(
3727 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
3728 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003729 &KeyDescriptor {
Janis Danisevskis377d1002021-01-27 19:07:48 -08003730 domain: Domain::APP,
3731 nspace: 1,
3732 alias: Some(TEST_ALIAS.to_string()),
3733 blob: None,
3734 },
3735 KeyType::Client,
3736 KeyEntryLoadBits::NONE,
3737 1,
3738 |_k, _av| Ok(()),
3739 )
3740 .unwrap_err()
3741 .root_cause()
3742 .downcast_ref::<KsError>()
3743 );
3744
3745 Ok(())
3746 }
3747
3748 #[test]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003749 fn test_insert_and_load_full_keyentry_domain_selinux() -> Result<()> {
3750 let mut db = new_test_db()?;
Qi Wub9433b52020-12-01 14:52:46 +08003751 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08003752 .context("test_insert_and_load_full_keyentry_domain_selinux")?
3753 .0;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003754 let (_key_guard, key_entry) = db
3755 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003756 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003757 domain: Domain::SELINUX,
3758 nspace: 1,
3759 alias: Some(TEST_ALIAS.to_string()),
3760 blob: None,
3761 },
3762 KeyType::Client,
3763 KeyEntryLoadBits::BOTH,
3764 1,
3765 |_k, _av| Ok(()),
3766 )
3767 .unwrap();
Qi Wub9433b52020-12-01 14:52:46 +08003768 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003769
3770 db.unbind_key(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003771 &KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003772 domain: Domain::SELINUX,
3773 nspace: 1,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003774 alias: Some(TEST_ALIAS.to_string()),
3775 blob: None,
3776 },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003777 KeyType::Client,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003778 1,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003779 |_, _| Ok(()),
3780 )
3781 .unwrap();
3782
3783 assert_eq!(
3784 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
3785 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003786 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003787 domain: Domain::SELINUX,
3788 nspace: 1,
3789 alias: Some(TEST_ALIAS.to_string()),
3790 blob: None,
3791 },
3792 KeyType::Client,
3793 KeyEntryLoadBits::NONE,
3794 1,
3795 |_k, _av| Ok(()),
3796 )
3797 .unwrap_err()
3798 .root_cause()
3799 .downcast_ref::<KsError>()
3800 );
3801
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003802 Ok(())
3803 }
3804
3805 #[test]
3806 fn test_insert_and_load_full_keyentry_domain_key_id() -> Result<()> {
3807 let mut db = new_test_db()?;
Qi Wub9433b52020-12-01 14:52:46 +08003808 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08003809 .context("test_insert_and_load_full_keyentry_domain_key_id")?
3810 .0;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003811 let (_, key_entry) = db
3812 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003813 &KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003814 KeyType::Client,
3815 KeyEntryLoadBits::BOTH,
3816 1,
3817 |_k, _av| Ok(()),
3818 )
3819 .unwrap();
3820
Qi Wub9433b52020-12-01 14:52:46 +08003821 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003822
3823 db.unbind_key(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003824 &KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003825 KeyType::Client,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003826 1,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003827 |_, _| Ok(()),
3828 )
3829 .unwrap();
3830
3831 assert_eq!(
3832 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
3833 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003834 &KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003835 KeyType::Client,
3836 KeyEntryLoadBits::NONE,
3837 1,
3838 |_k, _av| Ok(()),
3839 )
3840 .unwrap_err()
3841 .root_cause()
3842 .downcast_ref::<KsError>()
3843 );
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003844
3845 Ok(())
3846 }
3847
3848 #[test]
Qi Wub9433b52020-12-01 14:52:46 +08003849 fn test_check_and_update_key_usage_count_with_limited_use_key() -> Result<()> {
3850 let mut db = new_test_db()?;
3851 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, Some(123))
3852 .context("test_check_and_update_key_usage_count_with_limited_use_key")?
3853 .0;
3854 // Update the usage count of the limited use key.
3855 db.check_and_update_key_usage_count(key_id)?;
3856
3857 let (_key_guard, key_entry) = db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003858 &KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
Qi Wub9433b52020-12-01 14:52:46 +08003859 KeyType::Client,
3860 KeyEntryLoadBits::BOTH,
3861 1,
3862 |_k, _av| Ok(()),
3863 )?;
3864
3865 // The usage count is decremented now.
3866 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, Some(122)));
3867
3868 Ok(())
3869 }
3870
3871 #[test]
3872 fn test_check_and_update_key_usage_count_with_exhausted_limited_use_key() -> Result<()> {
3873 let mut db = new_test_db()?;
3874 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, Some(1))
3875 .context("test_check_and_update_key_usage_count_with_exhausted_limited_use_key")?
3876 .0;
3877 // Update the usage count of the limited use key.
3878 db.check_and_update_key_usage_count(key_id).expect(concat!(
3879 "In test_check_and_update_key_usage_count_with_exhausted_limited_use_key: ",
3880 "This should succeed."
3881 ));
3882
3883 // Try to update the exhausted limited use key.
3884 let e = db.check_and_update_key_usage_count(key_id).expect_err(concat!(
3885 "In test_check_and_update_key_usage_count_with_exhausted_limited_use_key: ",
3886 "This should fail."
3887 ));
3888 assert_eq!(
3889 &KsError::Km(ErrorCode::INVALID_KEY_BLOB),
3890 e.root_cause().downcast_ref::<KsError>().unwrap()
3891 );
3892
3893 Ok(())
3894 }
3895
3896 #[test]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003897 fn test_insert_and_load_full_keyentry_from_grant() -> Result<()> {
3898 let mut db = new_test_db()?;
Qi Wub9433b52020-12-01 14:52:46 +08003899 let key_id = make_test_key_entry(&mut db, Domain::APP, 1, TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08003900 .context("test_insert_and_load_full_keyentry_from_grant")?
3901 .0;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003902
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003903 let granted_key = db
3904 .grant(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003905 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003906 domain: Domain::APP,
3907 nspace: 0,
3908 alias: Some(TEST_ALIAS.to_string()),
3909 blob: None,
3910 },
3911 1,
3912 2,
3913 key_perm_set![KeyPerm::use_()],
3914 |_k, _av| Ok(()),
3915 )
3916 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003917
3918 debug_dump_grant_table(&mut db)?;
3919
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003920 let (_key_guard, key_entry) = db
Janis Danisevskis66784c42021-01-27 08:40:25 -08003921 .load_key_entry(&granted_key, KeyType::Client, KeyEntryLoadBits::BOTH, 2, |k, av| {
3922 assert_eq!(Domain::GRANT, k.domain);
3923 assert!(av.unwrap().includes(KeyPerm::use_()));
3924 Ok(())
3925 })
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003926 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003927
Qi Wub9433b52020-12-01 14:52:46 +08003928 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003929
Janis Danisevskis66784c42021-01-27 08:40:25 -08003930 db.unbind_key(&granted_key, KeyType::Client, 2, |_, _| Ok(())).unwrap();
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003931
3932 assert_eq!(
3933 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
3934 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003935 &granted_key,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003936 KeyType::Client,
3937 KeyEntryLoadBits::NONE,
3938 2,
3939 |_k, _av| Ok(()),
3940 )
3941 .unwrap_err()
3942 .root_cause()
3943 .downcast_ref::<KsError>()
3944 );
3945
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003946 Ok(())
3947 }
3948
Janis Danisevskis45760022021-01-19 16:34:10 -08003949 // This test attempts to load a key by key id while the caller is not the owner
3950 // but a grant exists for the given key and the caller.
3951 #[test]
3952 fn test_insert_and_load_full_keyentry_from_grant_by_key_id() -> Result<()> {
3953 let mut db = new_test_db()?;
3954 const OWNER_UID: u32 = 1u32;
3955 const GRANTEE_UID: u32 = 2u32;
3956 const SOMEONE_ELSE_UID: u32 = 3u32;
3957 let key_id = make_test_key_entry(&mut db, Domain::APP, OWNER_UID as i64, TEST_ALIAS, None)
3958 .context("test_insert_and_load_full_keyentry_from_grant_by_key_id")?
3959 .0;
3960
3961 db.grant(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003962 &KeyDescriptor {
Janis Danisevskis45760022021-01-19 16:34:10 -08003963 domain: Domain::APP,
3964 nspace: 0,
3965 alias: Some(TEST_ALIAS.to_string()),
3966 blob: None,
3967 },
3968 OWNER_UID,
3969 GRANTEE_UID,
3970 key_perm_set![KeyPerm::use_()],
3971 |_k, _av| Ok(()),
3972 )
3973 .unwrap();
3974
3975 debug_dump_grant_table(&mut db)?;
3976
3977 let id_descriptor =
3978 KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, ..Default::default() };
3979
3980 let (_, key_entry) = db
3981 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003982 &id_descriptor,
Janis Danisevskis45760022021-01-19 16:34:10 -08003983 KeyType::Client,
3984 KeyEntryLoadBits::BOTH,
3985 GRANTEE_UID,
3986 |k, av| {
3987 assert_eq!(Domain::APP, k.domain);
3988 assert_eq!(OWNER_UID as i64, k.nspace);
3989 assert!(av.unwrap().includes(KeyPerm::use_()));
3990 Ok(())
3991 },
3992 )
3993 .unwrap();
3994
3995 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
3996
3997 let (_, key_entry) = db
3998 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003999 &id_descriptor,
Janis Danisevskis45760022021-01-19 16:34:10 -08004000 KeyType::Client,
4001 KeyEntryLoadBits::BOTH,
4002 SOMEONE_ELSE_UID,
4003 |k, av| {
4004 assert_eq!(Domain::APP, k.domain);
4005 assert_eq!(OWNER_UID as i64, k.nspace);
4006 assert!(av.is_none());
4007 Ok(())
4008 },
4009 )
4010 .unwrap();
4011
4012 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
4013
Janis Danisevskis66784c42021-01-27 08:40:25 -08004014 db.unbind_key(&id_descriptor, KeyType::Client, OWNER_UID, |_, _| Ok(())).unwrap();
Janis Danisevskis45760022021-01-19 16:34:10 -08004015
4016 assert_eq!(
4017 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
4018 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004019 &id_descriptor,
Janis Danisevskis45760022021-01-19 16:34:10 -08004020 KeyType::Client,
4021 KeyEntryLoadBits::NONE,
4022 GRANTEE_UID,
4023 |_k, _av| Ok(()),
4024 )
4025 .unwrap_err()
4026 .root_cause()
4027 .downcast_ref::<KsError>()
4028 );
4029
4030 Ok(())
4031 }
4032
Janis Danisevskisaec14592020-11-12 09:41:49 -08004033 static KEY_LOCK_TEST_ALIAS: &str = "my super duper locked key";
4034
Janis Danisevskisaec14592020-11-12 09:41:49 -08004035 #[test]
4036 fn test_insert_and_load_full_keyentry_domain_app_concurrently() -> Result<()> {
4037 let handle = {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08004038 let temp_dir = Arc::new(TempDir::new("id_lock_test")?);
4039 let temp_dir_clone = temp_dir.clone();
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004040 let mut db = KeystoreDB::new(temp_dir.path(), None)?;
Qi Wub9433b52020-12-01 14:52:46 +08004041 let key_id = make_test_key_entry(&mut db, Domain::APP, 33, KEY_LOCK_TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08004042 .context("test_insert_and_load_full_keyentry_domain_app")?
4043 .0;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004044 let (_key_guard, key_entry) = db
4045 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004046 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004047 domain: Domain::APP,
4048 nspace: 0,
4049 alias: Some(KEY_LOCK_TEST_ALIAS.to_string()),
4050 blob: None,
4051 },
4052 KeyType::Client,
4053 KeyEntryLoadBits::BOTH,
4054 33,
4055 |_k, _av| Ok(()),
4056 )
4057 .unwrap();
Qi Wub9433b52020-12-01 14:52:46 +08004058 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskisaec14592020-11-12 09:41:49 -08004059 let state = Arc::new(AtomicU8::new(1));
4060 let state2 = state.clone();
4061
4062 // Spawning a second thread that attempts to acquire the key id lock
4063 // for the same key as the primary thread. The primary thread then
4064 // waits, thereby forcing the secondary thread into the second stage
4065 // of acquiring the lock (see KEY ID LOCK 2/2 above).
4066 // The test succeeds if the secondary thread observes the transition
4067 // of `state` from 1 to 2, despite having a whole second to overtake
4068 // the primary thread.
4069 let handle = thread::spawn(move || {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08004070 let temp_dir = temp_dir_clone;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004071 let mut db = KeystoreDB::new(temp_dir.path(), None).unwrap();
Janis Danisevskisaec14592020-11-12 09:41:49 -08004072 assert!(db
4073 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004074 &KeyDescriptor {
Janis Danisevskisaec14592020-11-12 09:41:49 -08004075 domain: Domain::APP,
4076 nspace: 0,
4077 alias: Some(KEY_LOCK_TEST_ALIAS.to_string()),
4078 blob: None,
4079 },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004080 KeyType::Client,
Janis Danisevskisaec14592020-11-12 09:41:49 -08004081 KeyEntryLoadBits::BOTH,
4082 33,
4083 |_k, _av| Ok(()),
4084 )
4085 .is_ok());
4086 // We should only see a 2 here because we can only return
4087 // from load_key_entry when the `_key_guard` expires,
4088 // which happens at the end of the scope.
4089 assert_eq!(2, state2.load(Ordering::Relaxed));
4090 });
4091
4092 thread::sleep(std::time::Duration::from_millis(1000));
4093
4094 assert_eq!(Ok(1), state.compare_exchange(1, 2, Ordering::Relaxed, Ordering::Relaxed));
4095
4096 // Return the handle from this scope so we can join with the
4097 // secondary thread after the key id lock has expired.
4098 handle
4099 // This is where the `_key_guard` goes out of scope,
4100 // which is the reason for concurrent load_key_entry on the same key
4101 // to unblock.
4102 };
4103 // Join with the secondary thread and unwrap, to propagate failing asserts to the
4104 // main test thread. We will not see failing asserts in secondary threads otherwise.
4105 handle.join().unwrap();
4106 Ok(())
4107 }
4108
Janis Danisevskise92a5e62020-12-02 12:57:41 -08004109 #[test]
Janis Danisevskis66784c42021-01-27 08:40:25 -08004110 fn teset_database_busy_error_code() {
4111 let temp_dir =
4112 TempDir::new("test_database_busy_error_code_").expect("Failed to create temp dir.");
4113
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004114 let mut db1 = KeystoreDB::new(temp_dir.path(), None).expect("Failed to open database1.");
4115 let mut db2 = KeystoreDB::new(temp_dir.path(), None).expect("Failed to open database2.");
Janis Danisevskis66784c42021-01-27 08:40:25 -08004116
4117 let _tx1 = db1
4118 .conn
4119 .transaction_with_behavior(TransactionBehavior::Immediate)
4120 .expect("Failed to create first transaction.");
4121
4122 let error = db2
4123 .conn
4124 .transaction_with_behavior(TransactionBehavior::Immediate)
4125 .context("Transaction begin failed.")
4126 .expect_err("This should fail.");
4127 let root_cause = error.root_cause();
4128 if let Some(rusqlite::ffi::Error { code: rusqlite::ErrorCode::DatabaseBusy, .. }) =
4129 root_cause.downcast_ref::<rusqlite::ffi::Error>()
4130 {
4131 return;
4132 }
4133 panic!(
4134 "Unexpected error {:?} \n{:?} \n{:?}",
4135 error,
4136 root_cause,
4137 root_cause.downcast_ref::<rusqlite::ffi::Error>()
4138 )
4139 }
4140
4141 #[cfg(disabled)]
4142 #[test]
4143 fn test_large_number_of_concurrent_db_manipulations() -> Result<()> {
4144 let temp_dir = Arc::new(
4145 TempDir::new("test_large_number_of_concurrent_db_manipulations_")
4146 .expect("Failed to create temp dir."),
4147 );
4148
4149 let test_begin = Instant::now();
4150
4151 let mut db = KeystoreDB::new(temp_dir.path()).expect("Failed to open database.");
4152 const KEY_COUNT: u32 = 500u32;
4153 const OPEN_DB_COUNT: u32 = 50u32;
4154
4155 let mut actual_key_count = KEY_COUNT;
4156 // First insert KEY_COUNT keys.
4157 for count in 0..KEY_COUNT {
4158 if Instant::now().duration_since(test_begin) >= Duration::from_secs(15) {
4159 actual_key_count = count;
4160 break;
4161 }
4162 let alias = format!("test_alias_{}", count);
4163 make_test_key_entry(&mut db, Domain::APP, 1, &alias, None)
4164 .expect("Failed to make key entry.");
4165 }
4166
4167 // Insert more keys from a different thread and into a different namespace.
4168 let temp_dir1 = temp_dir.clone();
4169 let handle1 = thread::spawn(move || {
4170 let mut db = KeystoreDB::new(temp_dir1.path()).expect("Failed to open database.");
4171
4172 for count in 0..actual_key_count {
4173 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
4174 return;
4175 }
4176 let alias = format!("test_alias_{}", count);
4177 make_test_key_entry(&mut db, Domain::APP, 2, &alias, None)
4178 .expect("Failed to make key entry.");
4179 }
4180
4181 // then unbind them again.
4182 for count in 0..actual_key_count {
4183 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
4184 return;
4185 }
4186 let key = KeyDescriptor {
4187 domain: Domain::APP,
4188 nspace: -1,
4189 alias: Some(format!("test_alias_{}", count)),
4190 blob: None,
4191 };
4192 db.unbind_key(&key, KeyType::Client, 2, |_, _| Ok(())).expect("Unbind Failed.");
4193 }
4194 });
4195
4196 // And start unbinding the first set of keys.
4197 let temp_dir2 = temp_dir.clone();
4198 let handle2 = thread::spawn(move || {
4199 let mut db = KeystoreDB::new(temp_dir2.path()).expect("Failed to open database.");
4200
4201 for count in 0..actual_key_count {
4202 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
4203 return;
4204 }
4205 let key = KeyDescriptor {
4206 domain: Domain::APP,
4207 nspace: -1,
4208 alias: Some(format!("test_alias_{}", count)),
4209 blob: None,
4210 };
4211 db.unbind_key(&key, KeyType::Client, 1, |_, _| Ok(())).expect("Unbind Failed.");
4212 }
4213 });
4214
4215 let stop_deleting = Arc::new(AtomicU8::new(0));
4216 let stop_deleting2 = stop_deleting.clone();
4217
4218 // And delete anything that is unreferenced keys.
4219 let temp_dir3 = temp_dir.clone();
4220 let handle3 = thread::spawn(move || {
4221 let mut db = KeystoreDB::new(temp_dir3.path()).expect("Failed to open database.");
4222
4223 while stop_deleting2.load(Ordering::Relaxed) != 1 {
4224 while let Some((key_guard, _key)) =
4225 db.get_unreferenced_key().expect("Failed to get unreferenced Key.")
4226 {
4227 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
4228 return;
4229 }
4230 db.purge_key_entry(key_guard).expect("Failed to purge key.");
4231 }
4232 std::thread::sleep(std::time::Duration::from_millis(100));
4233 }
4234 });
4235
4236 // While a lot of inserting and deleting is going on we have to open database connections
4237 // successfully and use them.
4238 // This clone is not redundant, because temp_dir needs to be kept alive until db goes
4239 // out of scope.
4240 #[allow(clippy::redundant_clone)]
4241 let temp_dir4 = temp_dir.clone();
4242 let handle4 = thread::spawn(move || {
4243 for count in 0..OPEN_DB_COUNT {
4244 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
4245 return;
4246 }
4247 let mut db = KeystoreDB::new(temp_dir4.path()).expect("Failed to open database.");
4248
4249 let alias = format!("test_alias_{}", count);
4250 make_test_key_entry(&mut db, Domain::APP, 3, &alias, None)
4251 .expect("Failed to make key entry.");
4252 let key = KeyDescriptor {
4253 domain: Domain::APP,
4254 nspace: -1,
4255 alias: Some(alias),
4256 blob: None,
4257 };
4258 db.unbind_key(&key, KeyType::Client, 3, |_, _| Ok(())).expect("Unbind Failed.");
4259 }
4260 });
4261
4262 handle1.join().expect("Thread 1 panicked.");
4263 handle2.join().expect("Thread 2 panicked.");
4264 handle4.join().expect("Thread 4 panicked.");
4265
4266 stop_deleting.store(1, Ordering::Relaxed);
4267 handle3.join().expect("Thread 3 panicked.");
4268
4269 Ok(())
4270 }
4271
4272 #[test]
Janis Danisevskise92a5e62020-12-02 12:57:41 -08004273 fn list() -> Result<()> {
4274 let temp_dir = TempDir::new("list_test")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004275 let mut db = KeystoreDB::new(temp_dir.path(), None)?;
Janis Danisevskise92a5e62020-12-02 12:57:41 -08004276 static LIST_O_ENTRIES: &[(Domain, i64, &str)] = &[
4277 (Domain::APP, 1, "test1"),
4278 (Domain::APP, 1, "test2"),
4279 (Domain::APP, 1, "test3"),
4280 (Domain::APP, 1, "test4"),
4281 (Domain::APP, 1, "test5"),
4282 (Domain::APP, 1, "test6"),
4283 (Domain::APP, 1, "test7"),
4284 (Domain::APP, 2, "test1"),
4285 (Domain::APP, 2, "test2"),
4286 (Domain::APP, 2, "test3"),
4287 (Domain::APP, 2, "test4"),
4288 (Domain::APP, 2, "test5"),
4289 (Domain::APP, 2, "test6"),
4290 (Domain::APP, 2, "test8"),
4291 (Domain::SELINUX, 100, "test1"),
4292 (Domain::SELINUX, 100, "test2"),
4293 (Domain::SELINUX, 100, "test3"),
4294 (Domain::SELINUX, 100, "test4"),
4295 (Domain::SELINUX, 100, "test5"),
4296 (Domain::SELINUX, 100, "test6"),
4297 (Domain::SELINUX, 100, "test9"),
4298 ];
4299
4300 let list_o_keys: Vec<(i64, i64)> = LIST_O_ENTRIES
4301 .iter()
4302 .map(|(domain, ns, alias)| {
Qi Wub9433b52020-12-01 14:52:46 +08004303 let entry = make_test_key_entry(&mut db, *domain, *ns, *alias, None)
4304 .unwrap_or_else(|e| {
Janis Danisevskise92a5e62020-12-02 12:57:41 -08004305 panic!("Failed to insert {:?} {} {}. Error {:?}", domain, ns, alias, e)
4306 });
4307 (entry.id(), *ns)
4308 })
4309 .collect();
4310
4311 for (domain, namespace) in
4312 &[(Domain::APP, 1i64), (Domain::APP, 2i64), (Domain::SELINUX, 100i64)]
4313 {
4314 let mut list_o_descriptors: Vec<KeyDescriptor> = LIST_O_ENTRIES
4315 .iter()
4316 .filter_map(|(domain, ns, alias)| match ns {
4317 ns if *ns == *namespace => Some(KeyDescriptor {
4318 domain: *domain,
4319 nspace: *ns,
4320 alias: Some(alias.to_string()),
4321 blob: None,
4322 }),
4323 _ => None,
4324 })
4325 .collect();
4326 list_o_descriptors.sort();
4327 let mut list_result = db.list(*domain, *namespace)?;
4328 list_result.sort();
4329 assert_eq!(list_o_descriptors, list_result);
4330
4331 let mut list_o_ids: Vec<i64> = list_o_descriptors
4332 .into_iter()
4333 .map(|d| {
4334 let (_, entry) = db
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004335 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004336 &d,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004337 KeyType::Client,
4338 KeyEntryLoadBits::NONE,
4339 *namespace as u32,
4340 |_, _| Ok(()),
4341 )
Janis Danisevskise92a5e62020-12-02 12:57:41 -08004342 .unwrap();
4343 entry.id()
4344 })
4345 .collect();
4346 list_o_ids.sort_unstable();
4347 let mut loaded_entries: Vec<i64> = list_o_keys
4348 .iter()
4349 .filter_map(|(id, ns)| match ns {
4350 ns if *ns == *namespace => Some(*id),
4351 _ => None,
4352 })
4353 .collect();
4354 loaded_entries.sort_unstable();
4355 assert_eq!(list_o_ids, loaded_entries);
4356 }
4357 assert_eq!(Vec::<KeyDescriptor>::new(), db.list(Domain::SELINUX, 101)?);
4358
4359 Ok(())
4360 }
4361
Joel Galenson0891bc12020-07-20 10:37:03 -07004362 // Helpers
4363
4364 // Checks that the given result is an error containing the given string.
4365 fn check_result_is_error_containing_string<T>(result: Result<T>, target: &str) {
4366 let error_str = format!(
4367 "{:#?}",
4368 result.err().unwrap_or_else(|| panic!("Expected the error: {}", target))
4369 );
4370 assert!(
4371 error_str.contains(target),
4372 "The string \"{}\" should contain \"{}\"",
4373 error_str,
4374 target
4375 );
4376 }
4377
Joel Galenson2aab4432020-07-22 15:27:57 -07004378 #[derive(Debug, PartialEq)]
Joel Galenson0891bc12020-07-20 10:37:03 -07004379 #[allow(dead_code)]
4380 struct KeyEntryRow {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004381 id: i64,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004382 key_type: KeyType,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07004383 domain: Option<Domain>,
Joel Galenson0891bc12020-07-20 10:37:03 -07004384 namespace: Option<i64>,
4385 alias: Option<String>,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004386 state: KeyLifeCycle,
Max Bires8e93d2b2021-01-14 13:17:59 -08004387 km_uuid: Option<Uuid>,
Joel Galenson0891bc12020-07-20 10:37:03 -07004388 }
4389
4390 fn get_keyentry(db: &KeystoreDB) -> Result<Vec<KeyEntryRow>> {
4391 db.conn
Joel Galenson2aab4432020-07-22 15:27:57 -07004392 .prepare("SELECT * FROM persistent.keyentry;")?
Joel Galenson0891bc12020-07-20 10:37:03 -07004393 .query_map(NO_PARAMS, |row| {
Joel Galenson0891bc12020-07-20 10:37:03 -07004394 Ok(KeyEntryRow {
4395 id: row.get(0)?,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004396 key_type: row.get(1)?,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07004397 domain: match row.get(2)? {
4398 Some(i) => Some(Domain(i)),
4399 None => None,
4400 },
Joel Galenson0891bc12020-07-20 10:37:03 -07004401 namespace: row.get(3)?,
4402 alias: row.get(4)?,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004403 state: row.get(5)?,
Max Bires8e93d2b2021-01-14 13:17:59 -08004404 km_uuid: row.get(6)?,
Joel Galenson0891bc12020-07-20 10:37:03 -07004405 })
4406 })?
4407 .map(|r| r.context("Could not read keyentry row."))
4408 .collect::<Result<Vec<_>>>()
4409 }
4410
Max Biresb2e1d032021-02-08 21:35:05 -08004411 struct RemoteProvValues {
4412 cert_chain: Vec<u8>,
4413 priv_key: Vec<u8>,
4414 batch_cert: Vec<u8>,
4415 }
4416
Max Bires2b2e6562020-09-22 11:22:36 -07004417 fn load_attestation_key_pool(
4418 db: &mut KeystoreDB,
4419 expiration_date: i64,
4420 namespace: i64,
4421 base_byte: u8,
Max Biresb2e1d032021-02-08 21:35:05 -08004422 ) -> Result<RemoteProvValues> {
Max Bires2b2e6562020-09-22 11:22:36 -07004423 let public_key: Vec<u8> = vec![base_byte, 0x02 * base_byte];
4424 let cert_chain: Vec<u8> = vec![0x03 * base_byte, 0x04 * base_byte];
4425 let priv_key: Vec<u8> = vec![0x05 * base_byte, 0x06 * base_byte];
4426 let raw_public_key: Vec<u8> = vec![0x0b * base_byte, 0x0c * base_byte];
Max Biresb2e1d032021-02-08 21:35:05 -08004427 let batch_cert: Vec<u8> = vec![base_byte * 0x0d, base_byte * 0x0e];
Max Bires2b2e6562020-09-22 11:22:36 -07004428 db.create_attestation_key_entry(&public_key, &raw_public_key, &priv_key, &KEYSTORE_UUID)?;
4429 db.store_signed_attestation_certificate_chain(
4430 &raw_public_key,
Max Biresb2e1d032021-02-08 21:35:05 -08004431 &batch_cert,
Max Bires2b2e6562020-09-22 11:22:36 -07004432 &cert_chain,
4433 expiration_date,
4434 &KEYSTORE_UUID,
4435 )?;
4436 db.assign_attestation_key(Domain::APP, namespace, &KEYSTORE_UUID)?;
Max Biresb2e1d032021-02-08 21:35:05 -08004437 Ok(RemoteProvValues { cert_chain, priv_key, batch_cert })
Max Bires2b2e6562020-09-22 11:22:36 -07004438 }
4439
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07004440 // Note: The parameters and SecurityLevel associations are nonsensical. This
4441 // collection is only used to check if the parameters are preserved as expected by the
4442 // database.
Qi Wub9433b52020-12-01 14:52:46 +08004443 fn make_test_params(max_usage_count: Option<i32>) -> Vec<KeyParameter> {
4444 let mut params = vec![
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07004445 KeyParameter::new(KeyParameterValue::Invalid, SecurityLevel::TRUSTED_ENVIRONMENT),
4446 KeyParameter::new(
4447 KeyParameterValue::KeyPurpose(KeyPurpose::SIGN),
4448 SecurityLevel::TRUSTED_ENVIRONMENT,
4449 ),
4450 KeyParameter::new(
4451 KeyParameterValue::KeyPurpose(KeyPurpose::DECRYPT),
4452 SecurityLevel::TRUSTED_ENVIRONMENT,
4453 ),
4454 KeyParameter::new(
4455 KeyParameterValue::Algorithm(Algorithm::RSA),
4456 SecurityLevel::TRUSTED_ENVIRONMENT,
4457 ),
4458 KeyParameter::new(KeyParameterValue::KeySize(1024), SecurityLevel::TRUSTED_ENVIRONMENT),
4459 KeyParameter::new(
4460 KeyParameterValue::BlockMode(BlockMode::ECB),
4461 SecurityLevel::TRUSTED_ENVIRONMENT,
4462 ),
4463 KeyParameter::new(
4464 KeyParameterValue::BlockMode(BlockMode::GCM),
4465 SecurityLevel::TRUSTED_ENVIRONMENT,
4466 ),
4467 KeyParameter::new(KeyParameterValue::Digest(Digest::NONE), SecurityLevel::STRONGBOX),
4468 KeyParameter::new(
4469 KeyParameterValue::Digest(Digest::MD5),
4470 SecurityLevel::TRUSTED_ENVIRONMENT,
4471 ),
4472 KeyParameter::new(
4473 KeyParameterValue::Digest(Digest::SHA_2_224),
4474 SecurityLevel::TRUSTED_ENVIRONMENT,
4475 ),
4476 KeyParameter::new(
4477 KeyParameterValue::Digest(Digest::SHA_2_256),
4478 SecurityLevel::STRONGBOX,
4479 ),
4480 KeyParameter::new(
4481 KeyParameterValue::PaddingMode(PaddingMode::NONE),
4482 SecurityLevel::TRUSTED_ENVIRONMENT,
4483 ),
4484 KeyParameter::new(
4485 KeyParameterValue::PaddingMode(PaddingMode::RSA_OAEP),
4486 SecurityLevel::TRUSTED_ENVIRONMENT,
4487 ),
4488 KeyParameter::new(
4489 KeyParameterValue::PaddingMode(PaddingMode::RSA_PSS),
4490 SecurityLevel::STRONGBOX,
4491 ),
4492 KeyParameter::new(
4493 KeyParameterValue::PaddingMode(PaddingMode::RSA_PKCS1_1_5_SIGN),
4494 SecurityLevel::TRUSTED_ENVIRONMENT,
4495 ),
4496 KeyParameter::new(KeyParameterValue::CallerNonce, SecurityLevel::TRUSTED_ENVIRONMENT),
4497 KeyParameter::new(KeyParameterValue::MinMacLength(256), SecurityLevel::STRONGBOX),
4498 KeyParameter::new(
4499 KeyParameterValue::EcCurve(EcCurve::P_224),
4500 SecurityLevel::TRUSTED_ENVIRONMENT,
4501 ),
4502 KeyParameter::new(KeyParameterValue::EcCurve(EcCurve::P_256), SecurityLevel::STRONGBOX),
4503 KeyParameter::new(
4504 KeyParameterValue::EcCurve(EcCurve::P_384),
4505 SecurityLevel::TRUSTED_ENVIRONMENT,
4506 ),
4507 KeyParameter::new(
4508 KeyParameterValue::EcCurve(EcCurve::P_521),
4509 SecurityLevel::TRUSTED_ENVIRONMENT,
4510 ),
4511 KeyParameter::new(
4512 KeyParameterValue::RSAPublicExponent(3),
4513 SecurityLevel::TRUSTED_ENVIRONMENT,
4514 ),
4515 KeyParameter::new(
4516 KeyParameterValue::IncludeUniqueID,
4517 SecurityLevel::TRUSTED_ENVIRONMENT,
4518 ),
4519 KeyParameter::new(KeyParameterValue::BootLoaderOnly, SecurityLevel::STRONGBOX),
4520 KeyParameter::new(KeyParameterValue::RollbackResistance, SecurityLevel::STRONGBOX),
4521 KeyParameter::new(
4522 KeyParameterValue::ActiveDateTime(1234567890),
4523 SecurityLevel::STRONGBOX,
4524 ),
4525 KeyParameter::new(
4526 KeyParameterValue::OriginationExpireDateTime(1234567890),
4527 SecurityLevel::TRUSTED_ENVIRONMENT,
4528 ),
4529 KeyParameter::new(
4530 KeyParameterValue::UsageExpireDateTime(1234567890),
4531 SecurityLevel::TRUSTED_ENVIRONMENT,
4532 ),
4533 KeyParameter::new(
4534 KeyParameterValue::MinSecondsBetweenOps(1234567890),
4535 SecurityLevel::TRUSTED_ENVIRONMENT,
4536 ),
4537 KeyParameter::new(
4538 KeyParameterValue::MaxUsesPerBoot(1234567890),
4539 SecurityLevel::TRUSTED_ENVIRONMENT,
4540 ),
4541 KeyParameter::new(KeyParameterValue::UserID(1), SecurityLevel::STRONGBOX),
4542 KeyParameter::new(KeyParameterValue::UserSecureID(42), SecurityLevel::STRONGBOX),
4543 KeyParameter::new(
4544 KeyParameterValue::NoAuthRequired,
4545 SecurityLevel::TRUSTED_ENVIRONMENT,
4546 ),
4547 KeyParameter::new(
4548 KeyParameterValue::HardwareAuthenticatorType(HardwareAuthenticatorType::PASSWORD),
4549 SecurityLevel::TRUSTED_ENVIRONMENT,
4550 ),
4551 KeyParameter::new(KeyParameterValue::AuthTimeout(1234567890), SecurityLevel::SOFTWARE),
4552 KeyParameter::new(KeyParameterValue::AllowWhileOnBody, SecurityLevel::SOFTWARE),
4553 KeyParameter::new(
4554 KeyParameterValue::TrustedUserPresenceRequired,
4555 SecurityLevel::TRUSTED_ENVIRONMENT,
4556 ),
4557 KeyParameter::new(
4558 KeyParameterValue::TrustedConfirmationRequired,
4559 SecurityLevel::TRUSTED_ENVIRONMENT,
4560 ),
4561 KeyParameter::new(
4562 KeyParameterValue::UnlockedDeviceRequired,
4563 SecurityLevel::TRUSTED_ENVIRONMENT,
4564 ),
4565 KeyParameter::new(
4566 KeyParameterValue::ApplicationID(vec![1u8, 2u8, 3u8, 4u8]),
4567 SecurityLevel::SOFTWARE,
4568 ),
4569 KeyParameter::new(
4570 KeyParameterValue::ApplicationData(vec![4u8, 3u8, 2u8, 1u8]),
4571 SecurityLevel::SOFTWARE,
4572 ),
4573 KeyParameter::new(
4574 KeyParameterValue::CreationDateTime(12345677890),
4575 SecurityLevel::SOFTWARE,
4576 ),
4577 KeyParameter::new(
4578 KeyParameterValue::KeyOrigin(KeyOrigin::GENERATED),
4579 SecurityLevel::TRUSTED_ENVIRONMENT,
4580 ),
4581 KeyParameter::new(
4582 KeyParameterValue::RootOfTrust(vec![3u8, 2u8, 1u8, 4u8]),
4583 SecurityLevel::TRUSTED_ENVIRONMENT,
4584 ),
4585 KeyParameter::new(KeyParameterValue::OSVersion(1), SecurityLevel::TRUSTED_ENVIRONMENT),
4586 KeyParameter::new(KeyParameterValue::OSPatchLevel(2), SecurityLevel::SOFTWARE),
4587 KeyParameter::new(
4588 KeyParameterValue::UniqueID(vec![4u8, 3u8, 1u8, 2u8]),
4589 SecurityLevel::SOFTWARE,
4590 ),
4591 KeyParameter::new(
4592 KeyParameterValue::AttestationChallenge(vec![4u8, 3u8, 1u8, 2u8]),
4593 SecurityLevel::TRUSTED_ENVIRONMENT,
4594 ),
4595 KeyParameter::new(
4596 KeyParameterValue::AttestationApplicationID(vec![4u8, 3u8, 1u8, 2u8]),
4597 SecurityLevel::TRUSTED_ENVIRONMENT,
4598 ),
4599 KeyParameter::new(
4600 KeyParameterValue::AttestationIdBrand(vec![4u8, 3u8, 1u8, 2u8]),
4601 SecurityLevel::TRUSTED_ENVIRONMENT,
4602 ),
4603 KeyParameter::new(
4604 KeyParameterValue::AttestationIdDevice(vec![4u8, 3u8, 1u8, 2u8]),
4605 SecurityLevel::TRUSTED_ENVIRONMENT,
4606 ),
4607 KeyParameter::new(
4608 KeyParameterValue::AttestationIdProduct(vec![4u8, 3u8, 1u8, 2u8]),
4609 SecurityLevel::TRUSTED_ENVIRONMENT,
4610 ),
4611 KeyParameter::new(
4612 KeyParameterValue::AttestationIdSerial(vec![4u8, 3u8, 1u8, 2u8]),
4613 SecurityLevel::TRUSTED_ENVIRONMENT,
4614 ),
4615 KeyParameter::new(
4616 KeyParameterValue::AttestationIdIMEI(vec![4u8, 3u8, 1u8, 2u8]),
4617 SecurityLevel::TRUSTED_ENVIRONMENT,
4618 ),
4619 KeyParameter::new(
4620 KeyParameterValue::AttestationIdMEID(vec![4u8, 3u8, 1u8, 2u8]),
4621 SecurityLevel::TRUSTED_ENVIRONMENT,
4622 ),
4623 KeyParameter::new(
4624 KeyParameterValue::AttestationIdManufacturer(vec![4u8, 3u8, 1u8, 2u8]),
4625 SecurityLevel::TRUSTED_ENVIRONMENT,
4626 ),
4627 KeyParameter::new(
4628 KeyParameterValue::AttestationIdModel(vec![4u8, 3u8, 1u8, 2u8]),
4629 SecurityLevel::TRUSTED_ENVIRONMENT,
4630 ),
4631 KeyParameter::new(
4632 KeyParameterValue::VendorPatchLevel(3),
4633 SecurityLevel::TRUSTED_ENVIRONMENT,
4634 ),
4635 KeyParameter::new(
4636 KeyParameterValue::BootPatchLevel(4),
4637 SecurityLevel::TRUSTED_ENVIRONMENT,
4638 ),
4639 KeyParameter::new(
4640 KeyParameterValue::AssociatedData(vec![4u8, 3u8, 1u8, 2u8]),
4641 SecurityLevel::TRUSTED_ENVIRONMENT,
4642 ),
4643 KeyParameter::new(
4644 KeyParameterValue::Nonce(vec![4u8, 3u8, 1u8, 2u8]),
4645 SecurityLevel::TRUSTED_ENVIRONMENT,
4646 ),
4647 KeyParameter::new(
4648 KeyParameterValue::MacLength(256),
4649 SecurityLevel::TRUSTED_ENVIRONMENT,
4650 ),
4651 KeyParameter::new(
4652 KeyParameterValue::ResetSinceIdRotation,
4653 SecurityLevel::TRUSTED_ENVIRONMENT,
4654 ),
4655 KeyParameter::new(
4656 KeyParameterValue::ConfirmationToken(vec![5u8, 5u8, 5u8, 5u8]),
4657 SecurityLevel::TRUSTED_ENVIRONMENT,
4658 ),
Qi Wub9433b52020-12-01 14:52:46 +08004659 ];
4660 if let Some(value) = max_usage_count {
4661 params.push(KeyParameter::new(
4662 KeyParameterValue::UsageCountLimit(value),
4663 SecurityLevel::SOFTWARE,
4664 ));
4665 }
4666 params
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07004667 }
4668
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004669 fn make_test_key_entry(
4670 db: &mut KeystoreDB,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07004671 domain: Domain,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004672 namespace: i64,
4673 alias: &str,
Qi Wub9433b52020-12-01 14:52:46 +08004674 max_usage_count: Option<i32>,
Janis Danisevskisaec14592020-11-12 09:41:49 -08004675 ) -> Result<KeyIdGuard> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08004676 let key_id = db.create_key_entry(&domain, &namespace, &KEYSTORE_UUID)?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004677 let mut blob_metadata = BlobMetaData::new();
4678 blob_metadata.add(BlobMetaEntry::EncryptedBy(EncryptedBy::Password));
4679 blob_metadata.add(BlobMetaEntry::Salt(vec![1, 2, 3]));
4680 blob_metadata.add(BlobMetaEntry::Iv(vec![2, 3, 1]));
4681 blob_metadata.add(BlobMetaEntry::AeadTag(vec![3, 1, 2]));
4682 blob_metadata.add(BlobMetaEntry::KmUuid(KEYSTORE_UUID));
4683
4684 db.set_blob(
4685 &key_id,
4686 SubComponentType::KEY_BLOB,
4687 Some(TEST_KEY_BLOB),
4688 Some(&blob_metadata),
4689 )?;
4690 db.set_blob(&key_id, SubComponentType::CERT, Some(TEST_CERT_BLOB), None)?;
4691 db.set_blob(&key_id, SubComponentType::CERT_CHAIN, Some(TEST_CERT_CHAIN_BLOB), None)?;
Qi Wub9433b52020-12-01 14:52:46 +08004692
4693 let params = make_test_params(max_usage_count);
4694 db.insert_keyparameter(&key_id, &params)?;
4695
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004696 let mut metadata = KeyMetaData::new();
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004697 metadata.add(KeyMetaEntry::CreationDate(DateTime::from_millis_epoch(123456789)));
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004698 db.insert_key_metadata(&key_id, &metadata)?;
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08004699 rebind_alias(db, &key_id, alias, domain, namespace)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004700 Ok(key_id)
4701 }
4702
Qi Wub9433b52020-12-01 14:52:46 +08004703 fn make_test_key_entry_test_vector(key_id: i64, max_usage_count: Option<i32>) -> KeyEntry {
4704 let params = make_test_params(max_usage_count);
4705
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004706 let mut blob_metadata = BlobMetaData::new();
4707 blob_metadata.add(BlobMetaEntry::EncryptedBy(EncryptedBy::Password));
4708 blob_metadata.add(BlobMetaEntry::Salt(vec![1, 2, 3]));
4709 blob_metadata.add(BlobMetaEntry::Iv(vec![2, 3, 1]));
4710 blob_metadata.add(BlobMetaEntry::AeadTag(vec![3, 1, 2]));
4711 blob_metadata.add(BlobMetaEntry::KmUuid(KEYSTORE_UUID));
4712
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004713 let mut metadata = KeyMetaData::new();
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004714 metadata.add(KeyMetaEntry::CreationDate(DateTime::from_millis_epoch(123456789)));
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004715
4716 KeyEntry {
4717 id: key_id,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004718 key_blob_info: Some((TEST_KEY_BLOB.to_vec(), blob_metadata)),
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004719 cert: Some(TEST_CERT_BLOB.to_vec()),
4720 cert_chain: Some(TEST_CERT_CHAIN_BLOB.to_vec()),
Max Bires8e93d2b2021-01-14 13:17:59 -08004721 km_uuid: KEYSTORE_UUID,
Qi Wub9433b52020-12-01 14:52:46 +08004722 parameters: params,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004723 metadata,
Janis Danisevskis377d1002021-01-27 19:07:48 -08004724 pure_cert: false,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004725 }
4726 }
4727
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004728 fn debug_dump_keyentry_table(db: &mut KeystoreDB) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004729 let mut stmt = db.conn.prepare(
Max Bires8e93d2b2021-01-14 13:17:59 -08004730 "SELECT id, key_type, domain, namespace, alias, state, km_uuid FROM persistent.keyentry;",
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004731 )?;
Max Bires8e93d2b2021-01-14 13:17:59 -08004732 let rows = stmt.query_map::<(i64, KeyType, i32, i64, String, KeyLifeCycle, Uuid), _, _>(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004733 NO_PARAMS,
4734 |row| {
Max Bires8e93d2b2021-01-14 13:17:59 -08004735 Ok((
4736 row.get(0)?,
4737 row.get(1)?,
4738 row.get(2)?,
4739 row.get(3)?,
4740 row.get(4)?,
4741 row.get(5)?,
4742 row.get(6)?,
4743 ))
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004744 },
4745 )?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004746
4747 println!("Key entry table rows:");
4748 for r in rows {
Max Bires8e93d2b2021-01-14 13:17:59 -08004749 let (id, key_type, domain, namespace, alias, state, km_uuid) = r.unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004750 println!(
Max Bires8e93d2b2021-01-14 13:17:59 -08004751 " id: {} KeyType: {:?} Domain: {} Namespace: {} Alias: {} State: {:?} KmUuid: {:?}",
4752 id, key_type, domain, namespace, alias, state, km_uuid
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004753 );
4754 }
4755 Ok(())
4756 }
4757
4758 fn debug_dump_grant_table(db: &mut KeystoreDB) -> Result<()> {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08004759 let mut stmt = db
4760 .conn
4761 .prepare("SELECT id, grantee, keyentryid, access_vector FROM persistent.grant;")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004762 let rows = stmt.query_map::<(i64, i64, i64, i64), _, _>(NO_PARAMS, |row| {
4763 Ok((row.get(0)?, row.get(1)?, row.get(2)?, row.get(3)?))
4764 })?;
4765
4766 println!("Grant table rows:");
4767 for r in rows {
4768 let (id, gt, ki, av) = r.unwrap();
4769 println!(" id: {} grantee: {} key_id: {} access_vector: {}", id, gt, ki, av);
4770 }
4771 Ok(())
4772 }
4773
Joel Galenson0891bc12020-07-20 10:37:03 -07004774 // Use a custom random number generator that repeats each number once.
4775 // This allows us to test repeated elements.
4776
4777 thread_local! {
4778 static RANDOM_COUNTER: RefCell<i64> = RefCell::new(0);
4779 }
4780
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004781 fn reset_random() {
4782 RANDOM_COUNTER.with(|counter| {
4783 *counter.borrow_mut() = 0;
4784 })
4785 }
4786
Joel Galenson0891bc12020-07-20 10:37:03 -07004787 pub fn random() -> i64 {
4788 RANDOM_COUNTER.with(|counter| {
4789 let result = *counter.borrow() / 2;
4790 *counter.borrow_mut() += 1;
4791 result
4792 })
4793 }
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00004794
4795 #[test]
4796 fn test_last_off_body() -> Result<()> {
4797 let mut db = new_test_db()?;
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08004798 db.insert_last_off_body(MonotonicRawTime::now())?;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00004799 let tx = db.conn.transaction_with_behavior(TransactionBehavior::Immediate)?;
4800 let last_off_body_1 = KeystoreDB::get_last_off_body(&tx)?;
4801 tx.commit()?;
4802 let one_second = Duration::from_secs(1);
4803 thread::sleep(one_second);
4804 db.update_last_off_body(MonotonicRawTime::now())?;
4805 let tx2 = db.conn.transaction_with_behavior(TransactionBehavior::Immediate)?;
4806 let last_off_body_2 = KeystoreDB::get_last_off_body(&tx2)?;
4807 tx2.commit()?;
4808 assert!(last_off_body_1.seconds() < last_off_body_2.seconds());
4809 Ok(())
4810 }
Hasini Gunasingheda895552021-01-27 19:34:37 +00004811
4812 #[test]
4813 fn test_unbind_keys_for_user() -> Result<()> {
4814 let mut db = new_test_db()?;
4815 db.unbind_keys_for_user(1, false)?;
4816
4817 make_test_key_entry(&mut db, Domain::APP, 210000, TEST_ALIAS, None)?;
4818 make_test_key_entry(&mut db, Domain::APP, 110000, TEST_ALIAS, None)?;
4819 db.unbind_keys_for_user(2, false)?;
4820
4821 assert_eq!(1, db.list(Domain::APP, 110000)?.len());
4822 assert_eq!(0, db.list(Domain::APP, 210000)?.len());
4823
4824 db.unbind_keys_for_user(1, true)?;
4825 assert_eq!(0, db.list(Domain::APP, 110000)?.len());
4826
4827 Ok(())
4828 }
4829
4830 #[test]
4831 fn test_store_super_key() -> Result<()> {
4832 let mut db = new_test_db()?;
4833 let pw = "xyzabc".as_bytes();
4834 let super_key = keystore2_crypto::generate_aes256_key()?;
4835 let secret = String::from("keystore2 is great.");
4836 let secret_bytes = secret.into_bytes();
4837 let (encrypted_secret, iv, tag) =
4838 keystore2_crypto::aes_gcm_encrypt(&secret_bytes, &super_key)?;
4839
4840 let (encrypted_super_key, metadata) =
4841 SuperKeyManager::encrypt_with_password(&super_key, &pw)?;
4842 db.store_super_key(1, &(&encrypted_super_key, &metadata))?;
4843
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00004844 //check if super key exists
4845 assert!(db.key_exists(Domain::APP, 1, "USER_SUPER_KEY", KeyType::Super)?);
4846
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +00004847 let (_, key_entry) = db.load_super_key(1)?.unwrap();
Hasini Gunasingheda895552021-01-27 19:34:37 +00004848 let loaded_super_key = SuperKeyManager::extract_super_key_from_key_entry(key_entry, &pw)?;
4849
4850 let decrypted_secret_bytes = keystore2_crypto::aes_gcm_decrypt(
4851 &encrypted_secret,
4852 &iv,
4853 &tag,
4854 &loaded_super_key.get_key(),
4855 )?;
4856 let decrypted_secret = String::from_utf8((&decrypted_secret_bytes).to_vec())?;
4857 assert_eq!(String::from("keystore2 is great."), decrypted_secret);
4858 Ok(())
4859 }
Joel Galenson26f4d012020-07-17 14:57:21 -07004860}