blob: 5f19cf06c459a0ba68ae3160f8027e816644939f [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
Hasini Gunasingheb3715fb2021-02-26 20:34:45 +0000741 /// Returns the value of MonotonicRawTime in milli seconds as i64
742 pub fn milli_seconds(&self) -> i64 {
743 self.0 * 1000
744 }
745
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800746 /// Like i64::checked_sub.
747 pub fn checked_sub(&self, other: &Self) -> Option<Self> {
748 self.0.checked_sub(other.0).map(Self)
749 }
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000750}
751
752impl ToSql for MonotonicRawTime {
753 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
754 Ok(ToSqlOutput::Owned(Value::Integer(self.0)))
755 }
756}
757
758impl FromSql for MonotonicRawTime {
759 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
760 Ok(Self(i64::column_result(value)?))
761 }
762}
763
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000764/// This struct encapsulates the information to be stored in the database about the auth tokens
765/// received by keystore.
766pub struct AuthTokenEntry {
767 auth_token: HardwareAuthToken,
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000768 time_received: MonotonicRawTime,
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000769}
770
771impl AuthTokenEntry {
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000772 fn new(auth_token: HardwareAuthToken, time_received: MonotonicRawTime) -> Self {
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000773 AuthTokenEntry { auth_token, time_received }
774 }
775
776 /// Checks if this auth token satisfies the given authentication information.
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800777 pub fn satisfies(&self, user_secure_ids: &[i64], auth_type: HardwareAuthenticatorType) -> bool {
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000778 user_secure_ids.iter().any(|&sid| {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800779 (sid == self.auth_token.userId || sid == self.auth_token.authenticatorId)
780 && (((auth_type.0 as i32) & (self.auth_token.authenticatorType.0 as i32)) != 0)
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000781 })
782 }
783
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000784 /// Returns the auth token wrapped by the AuthTokenEntry
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800785 pub fn auth_token(&self) -> &HardwareAuthToken {
786 &self.auth_token
787 }
788
789 /// Returns the auth token wrapped by the AuthTokenEntry
790 pub fn take_auth_token(self) -> HardwareAuthToken {
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000791 self.auth_token
792 }
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800793
794 /// Returns the time that this auth token was received.
795 pub fn time_received(&self) -> MonotonicRawTime {
796 self.time_received
797 }
Hasini Gunasingheb3715fb2021-02-26 20:34:45 +0000798
799 /// Returns the challenge value of the auth token.
800 pub fn challenge(&self) -> i64 {
801 self.auth_token.challenge
802 }
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000803}
804
Janis Danisevskisb00ebd02021-02-02 21:52:24 -0800805/// Shared in-memory databases get destroyed as soon as the last connection to them gets closed.
806/// This object does not allow access to the database connection. But it keeps a database
807/// connection alive in order to keep the in memory per boot database alive.
808pub struct PerBootDbKeepAlive(Connection);
809
Joel Galenson26f4d012020-07-17 14:57:21 -0700810impl KeystoreDB {
Janis Danisevskiseed69842021-02-18 20:04:10 -0800811 const UNASSIGNED_KEY_ID: i64 = -1i64;
Janis Danisevskisb00ebd02021-02-02 21:52:24 -0800812 const PERBOOT_DB_FILE_NAME: &'static str = &"file:perboot.sqlite?mode=memory&cache=shared";
813
Hasini Gunasinghe0e161452021-01-27 19:34:37 +0000814 /// The alias of the user super key.
815 pub const USER_SUPER_KEY_ALIAS: &'static str = &"USER_SUPER_KEY";
816
Janis Danisevskisb00ebd02021-02-02 21:52:24 -0800817 /// This creates a PerBootDbKeepAlive object to keep the per boot database alive.
818 pub fn keep_perboot_db_alive() -> Result<PerBootDbKeepAlive> {
819 let conn = Connection::open_in_memory()
820 .context("In keep_perboot_db_alive: Failed to initialize SQLite connection.")?;
821
822 conn.execute("ATTACH DATABASE ? as perboot;", params![Self::PERBOOT_DB_FILE_NAME])
823 .context("In keep_perboot_db_alive: Failed to attach database perboot.")?;
824 Ok(PerBootDbKeepAlive(conn))
825 }
826
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700827 /// This will create a new database connection connecting the two
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800828 /// files persistent.sqlite and perboot.sqlite in the given directory.
829 /// It also attempts to initialize all of the tables.
830 /// KeystoreDB cannot be used by multiple threads.
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700831 /// Each thread should open their own connection using `thread_local!`.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800832 pub fn new(db_root: &Path, gc: Option<Gc>) -> Result<Self> {
Janis Danisevskisb00ebd02021-02-02 21:52:24 -0800833 // Build the path to the sqlite file.
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800834 let mut persistent_path = db_root.to_path_buf();
835 persistent_path.push("persistent.sqlite");
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700836
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800837 // Now convert them to strings prefixed with "file:"
838 let mut persistent_path_str = "file:".to_owned();
839 persistent_path_str.push_str(&persistent_path.to_string_lossy());
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800840
Janis Danisevskisb00ebd02021-02-02 21:52:24 -0800841 let conn = Self::make_connection(&persistent_path_str, &Self::PERBOOT_DB_FILE_NAME)?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800842
Janis Danisevskis66784c42021-01-27 08:40:25 -0800843 // On busy fail Immediately. It is unlikely to succeed given a bug in sqlite.
844 conn.busy_handler(None).context("In KeystoreDB::new: Failed to set busy handler.")?;
845
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800846 let mut db = Self { conn, gc };
Janis Danisevskis66784c42021-01-27 08:40:25 -0800847 db.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800848 Self::init_tables(tx).context("Trying to initialize tables.").no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -0800849 })?;
850 Ok(db)
Joel Galenson2aab4432020-07-22 15:27:57 -0700851 }
852
Janis Danisevskis66784c42021-01-27 08:40:25 -0800853 fn init_tables(tx: &Transaction) -> Result<()> {
854 tx.execute(
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700855 "CREATE TABLE IF NOT EXISTS persistent.keyentry (
Joel Galenson0891bc12020-07-20 10:37:03 -0700856 id INTEGER UNIQUE,
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800857 key_type INTEGER,
Joel Galenson0891bc12020-07-20 10:37:03 -0700858 domain INTEGER,
859 namespace INTEGER,
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800860 alias BLOB,
Max Bires8e93d2b2021-01-14 13:17:59 -0800861 state INTEGER,
862 km_uuid BLOB);",
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700863 NO_PARAMS,
864 )
865 .context("Failed to initialize \"keyentry\" table.")?;
866
Janis Danisevskis66784c42021-01-27 08:40:25 -0800867 tx.execute(
Janis Danisevskisa5438182021-02-02 14:22:59 -0800868 "CREATE INDEX IF NOT EXISTS persistent.keyentry_id_index
869 ON keyentry(id);",
870 NO_PARAMS,
871 )
872 .context("Failed to create index keyentry_id_index.")?;
873
874 tx.execute(
875 "CREATE INDEX IF NOT EXISTS persistent.keyentry_domain_namespace_index
876 ON keyentry(domain, namespace, alias);",
877 NO_PARAMS,
878 )
879 .context("Failed to create index keyentry_domain_namespace_index.")?;
880
881 tx.execute(
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700882 "CREATE TABLE IF NOT EXISTS persistent.blobentry (
883 id INTEGER PRIMARY KEY,
884 subcomponent_type INTEGER,
885 keyentryid INTEGER,
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800886 blob BLOB);",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700887 NO_PARAMS,
888 )
889 .context("Failed to initialize \"blobentry\" table.")?;
890
Janis Danisevskis66784c42021-01-27 08:40:25 -0800891 tx.execute(
Janis Danisevskisa5438182021-02-02 14:22:59 -0800892 "CREATE INDEX IF NOT EXISTS persistent.blobentry_keyentryid_index
893 ON blobentry(keyentryid);",
894 NO_PARAMS,
895 )
896 .context("Failed to create index blobentry_keyentryid_index.")?;
897
898 tx.execute(
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800899 "CREATE TABLE IF NOT EXISTS persistent.blobmetadata (
900 id INTEGER PRIMARY KEY,
901 blobentryid INTEGER,
902 tag INTEGER,
903 data ANY,
904 UNIQUE (blobentryid, tag));",
905 NO_PARAMS,
906 )
907 .context("Failed to initialize \"blobmetadata\" table.")?;
908
909 tx.execute(
910 "CREATE INDEX IF NOT EXISTS persistent.blobmetadata_blobentryid_index
911 ON blobmetadata(blobentryid);",
912 NO_PARAMS,
913 )
914 .context("Failed to create index blobmetadata_blobentryid_index.")?;
915
916 tx.execute(
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700917 "CREATE TABLE IF NOT EXISTS persistent.keyparameter (
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000918 keyentryid INTEGER,
919 tag INTEGER,
920 data ANY,
921 security_level INTEGER);",
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700922 NO_PARAMS,
923 )
924 .context("Failed to initialize \"keyparameter\" table.")?;
925
Janis Danisevskis66784c42021-01-27 08:40:25 -0800926 tx.execute(
Janis Danisevskisa5438182021-02-02 14:22:59 -0800927 "CREATE INDEX IF NOT EXISTS persistent.keyparameter_keyentryid_index
928 ON keyparameter(keyentryid);",
929 NO_PARAMS,
930 )
931 .context("Failed to create index keyparameter_keyentryid_index.")?;
932
933 tx.execute(
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800934 "CREATE TABLE IF NOT EXISTS persistent.keymetadata (
935 keyentryid INTEGER,
936 tag INTEGER,
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000937 data ANY,
938 UNIQUE (keyentryid, tag));",
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800939 NO_PARAMS,
940 )
941 .context("Failed to initialize \"keymetadata\" table.")?;
942
Janis Danisevskis66784c42021-01-27 08:40:25 -0800943 tx.execute(
Janis Danisevskisa5438182021-02-02 14:22:59 -0800944 "CREATE INDEX IF NOT EXISTS persistent.keymetadata_keyentryid_index
945 ON keymetadata(keyentryid);",
946 NO_PARAMS,
947 )
948 .context("Failed to create index keymetadata_keyentryid_index.")?;
949
950 tx.execute(
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800951 "CREATE TABLE IF NOT EXISTS persistent.grant (
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700952 id INTEGER UNIQUE,
953 grantee INTEGER,
954 keyentryid INTEGER,
955 access_vector INTEGER);",
956 NO_PARAMS,
957 )
958 .context("Failed to initialize \"grant\" table.")?;
959
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000960 //TODO: only drop the following two perboot tables if this is the first start up
961 //during the boot (b/175716626).
Janis Danisevskis66784c42021-01-27 08:40:25 -0800962 // tx.execute("DROP TABLE IF EXISTS perboot.authtoken;", NO_PARAMS)
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000963 // .context("Failed to drop perboot.authtoken table")?;
Janis Danisevskis66784c42021-01-27 08:40:25 -0800964 tx.execute(
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000965 "CREATE TABLE IF NOT EXISTS perboot.authtoken (
966 id INTEGER PRIMARY KEY,
967 challenge INTEGER,
968 user_id INTEGER,
969 auth_id INTEGER,
970 authenticator_type INTEGER,
971 timestamp INTEGER,
972 mac BLOB,
973 time_received INTEGER,
974 UNIQUE(user_id, auth_id, authenticator_type));",
975 NO_PARAMS,
976 )
977 .context("Failed to initialize \"authtoken\" table.")?;
978
Janis Danisevskis66784c42021-01-27 08:40:25 -0800979 // tx.execute("DROP TABLE IF EXISTS perboot.metadata;", NO_PARAMS)
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000980 // .context("Failed to drop perboot.metadata table")?;
981 // metadata table stores certain miscellaneous information required for keystore functioning
982 // during a boot cycle, as key-value pairs.
Janis Danisevskis66784c42021-01-27 08:40:25 -0800983 tx.execute(
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000984 "CREATE TABLE IF NOT EXISTS perboot.metadata (
985 key TEXT,
986 value BLOB,
987 UNIQUE(key));",
988 NO_PARAMS,
989 )
990 .context("Failed to initialize \"metadata\" table.")?;
Joel Galenson0891bc12020-07-20 10:37:03 -0700991 Ok(())
992 }
993
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700994 fn make_connection(persistent_file: &str, perboot_file: &str) -> Result<Connection> {
995 let conn =
996 Connection::open_in_memory().context("Failed to initialize SQLite connection.")?;
997
Janis Danisevskis66784c42021-01-27 08:40:25 -0800998 loop {
999 if let Err(e) = conn
1000 .execute("ATTACH DATABASE ? as persistent;", params![persistent_file])
1001 .context("Failed to attach database persistent.")
1002 {
1003 if Self::is_locked_error(&e) {
1004 std::thread::sleep(std::time::Duration::from_micros(500));
1005 continue;
1006 } else {
1007 return Err(e);
1008 }
1009 }
1010 break;
1011 }
1012 loop {
1013 if let Err(e) = conn
1014 .execute("ATTACH DATABASE ? as perboot;", params![perboot_file])
1015 .context("Failed to attach database perboot.")
1016 {
1017 if Self::is_locked_error(&e) {
1018 std::thread::sleep(std::time::Duration::from_micros(500));
1019 continue;
1020 } else {
1021 return Err(e);
1022 }
1023 }
1024 break;
1025 }
Janis Danisevskis4df44f42020-08-26 14:40:03 -07001026
1027 Ok(conn)
1028 }
1029
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001030 /// This function is intended to be used by the garbage collector.
1031 /// It deletes the blob given by `blob_id_to_delete`. It then tries to find a superseded
1032 /// key blob that might need special handling by the garbage collector.
1033 /// If no further superseded blobs can be found it deletes all other superseded blobs that don't
1034 /// need special handling and returns None.
1035 pub fn handle_next_superseded_blob(
1036 &mut self,
1037 blob_id_to_delete: Option<i64>,
1038 ) -> Result<Option<(i64, Vec<u8>, BlobMetaData)>> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001039 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001040 // Delete the given blob if one was given.
1041 if let Some(blob_id_to_delete) = blob_id_to_delete {
1042 tx.execute(
1043 "DELETE FROM persistent.blobmetadata WHERE blobentryid = ?;",
1044 params![blob_id_to_delete],
1045 )
1046 .context("Trying to delete blob metadata.")?;
1047 tx.execute(
1048 "DELETE FROM persistent.blobentry WHERE id = ?;",
1049 params![blob_id_to_delete],
1050 )
1051 .context("Trying to blob.")?;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001052 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001053
1054 // Find another superseded keyblob load its metadata and return it.
1055 if let Some((blob_id, blob)) = tx
1056 .query_row(
1057 "SELECT id, blob FROM persistent.blobentry
1058 WHERE subcomponent_type = ?
1059 AND (
1060 id NOT IN (
1061 SELECT MAX(id) FROM persistent.blobentry
1062 WHERE subcomponent_type = ?
1063 GROUP BY keyentryid, subcomponent_type
1064 )
1065 OR keyentryid NOT IN (SELECT id FROM persistent.keyentry)
1066 );",
1067 params![SubComponentType::KEY_BLOB, SubComponentType::KEY_BLOB],
1068 |row| Ok((row.get(0)?, row.get(1)?)),
1069 )
1070 .optional()
1071 .context("Trying to query superseded blob.")?
1072 {
1073 let blob_metadata = BlobMetaData::load_from_db(blob_id, tx)
1074 .context("Trying to load blob metadata.")?;
1075 return Ok(Some((blob_id, blob, blob_metadata))).no_gc();
1076 }
1077
1078 // We did not find any superseded key blob, so let's remove other superseded blob in
1079 // one transaction.
1080 tx.execute(
1081 "DELETE FROM persistent.blobentry
1082 WHERE NOT subcomponent_type = ?
1083 AND (
1084 id NOT IN (
1085 SELECT MAX(id) FROM persistent.blobentry
1086 WHERE NOT subcomponent_type = ?
1087 GROUP BY keyentryid, subcomponent_type
1088 ) OR keyentryid NOT IN (SELECT id FROM persistent.keyentry)
1089 );",
1090 params![SubComponentType::KEY_BLOB, SubComponentType::KEY_BLOB],
1091 )
1092 .context("Trying to purge superseded blobs.")?;
1093
1094 Ok(None).no_gc()
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001095 })
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001096 .context("In handle_next_superseded_blob.")
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001097 }
1098
1099 /// This maintenance function should be called only once before the database is used for the
1100 /// first time. It restores the invariant that `KeyLifeCycle::Existing` is a transient state.
1101 /// The function transitions all key entries from Existing to Unreferenced unconditionally and
1102 /// returns the number of rows affected. If this returns a value greater than 0, it means that
1103 /// Keystore crashed at some point during key generation. Callers may want to log such
1104 /// occurrences.
1105 /// Unlike with `mark_unreferenced`, we don't need to purge grants, because only keys that made
1106 /// it to `KeyLifeCycle::Live` may have grants.
1107 pub fn cleanup_leftovers(&mut self) -> Result<usize> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001108 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1109 tx.execute(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001110 "UPDATE persistent.keyentry SET state = ? WHERE state = ?;",
1111 params![KeyLifeCycle::Unreferenced, KeyLifeCycle::Existing],
1112 )
Janis Danisevskis66784c42021-01-27 08:40:25 -08001113 .context("Failed to execute query.")
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001114 .need_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08001115 })
1116 .context("In cleanup_leftovers.")
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001117 }
1118
Hasini Gunasinghe0e161452021-01-27 19:34:37 +00001119 /// Checks if a key exists with given key type and key descriptor properties.
1120 pub fn key_exists(
1121 &mut self,
1122 domain: Domain,
1123 nspace: i64,
1124 alias: &str,
1125 key_type: KeyType,
1126 ) -> Result<bool> {
1127 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1128 let key_descriptor =
1129 KeyDescriptor { domain, nspace, alias: Some(alias.to_string()), blob: None };
1130 let result = Self::load_key_entry_id(&tx, &key_descriptor, key_type);
1131 match result {
1132 Ok(_) => Ok(true),
1133 Err(error) => match error.root_cause().downcast_ref::<KsError>() {
1134 Some(KsError::Rc(ResponseCode::KEY_NOT_FOUND)) => Ok(false),
1135 _ => Err(error).context("In key_exists: Failed to find if the key exists."),
1136 },
1137 }
1138 .no_gc()
1139 })
1140 .context("In key_exists.")
1141 }
1142
Hasini Gunasingheda895552021-01-27 19:34:37 +00001143 /// Stores a super key in the database.
1144 pub fn store_super_key(
1145 &mut self,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +00001146 user_id: u32,
Hasini Gunasingheda895552021-01-27 19:34:37 +00001147 blob_info: &(&[u8], &BlobMetaData),
1148 ) -> Result<KeyEntry> {
1149 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1150 let key_id = Self::insert_with_retry(|id| {
1151 tx.execute(
1152 "INSERT into persistent.keyentry
1153 (id, key_type, domain, namespace, alias, state, km_uuid)
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00001154 VALUES(?, ?, ?, ?, ?, ?, ?);",
Hasini Gunasingheda895552021-01-27 19:34:37 +00001155 params![
1156 id,
1157 KeyType::Super,
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00001158 Domain::APP.0,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +00001159 user_id as i64,
Hasini Gunasingheda895552021-01-27 19:34:37 +00001160 Self::USER_SUPER_KEY_ALIAS,
1161 KeyLifeCycle::Live,
1162 &KEYSTORE_UUID,
1163 ],
1164 )
1165 })
1166 .context("Failed to insert into keyentry table.")?;
1167
1168 let (blob, blob_metadata) = *blob_info;
1169 Self::set_blob_internal(
1170 &tx,
1171 key_id,
1172 SubComponentType::KEY_BLOB,
1173 Some(blob),
1174 Some(blob_metadata),
1175 )
1176 .context("Failed to store key blob.")?;
1177
1178 Self::load_key_components(tx, KeyEntryLoadBits::KM, key_id)
1179 .context("Trying to load key components.")
1180 .no_gc()
1181 })
1182 .context("In store_super_key.")
1183 }
1184
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +00001185 /// Loads super key of a given user, if exists
1186 pub fn load_super_key(&mut self, user_id: u32) -> Result<Option<(KeyIdGuard, KeyEntry)>> {
1187 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1188 let key_descriptor = KeyDescriptor {
1189 domain: Domain::APP,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +00001190 nspace: user_id as i64,
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +00001191 alias: Some(String::from("USER_SUPER_KEY")),
1192 blob: None,
1193 };
1194 let id = Self::load_key_entry_id(&tx, &key_descriptor, KeyType::Super);
1195 match id {
1196 Ok(id) => {
1197 let key_entry = Self::load_key_components(&tx, KeyEntryLoadBits::KM, id)
1198 .context("In load_super_key. Failed to load key entry.")?;
1199 Ok(Some((KEY_ID_LOCK.get(id), key_entry)))
1200 }
1201 Err(error) => match error.root_cause().downcast_ref::<KsError>() {
1202 Some(KsError::Rc(ResponseCode::KEY_NOT_FOUND)) => Ok(None),
1203 _ => Err(error).context("In load_super_key."),
1204 },
1205 }
1206 .no_gc()
1207 })
1208 .context("In load_super_key.")
1209 }
1210
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001211 /// Atomically loads a key entry and associated metadata or creates it using the
1212 /// callback create_new_key callback. The callback is called during a database
1213 /// transaction. This means that implementers should be mindful about using
1214 /// blocking operations such as IPC or grabbing mutexes.
1215 pub fn get_or_create_key_with<F>(
1216 &mut self,
1217 domain: Domain,
1218 namespace: i64,
1219 alias: &str,
Max Bires8e93d2b2021-01-14 13:17:59 -08001220 km_uuid: Uuid,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001221 create_new_key: F,
1222 ) -> Result<(KeyIdGuard, KeyEntry)>
1223 where
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001224 F: Fn() -> Result<(Vec<u8>, BlobMetaData)>,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001225 {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001226 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1227 let id = {
1228 let mut stmt = tx
1229 .prepare(
1230 "SELECT id FROM persistent.keyentry
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001231 WHERE
1232 key_type = ?
1233 AND domain = ?
1234 AND namespace = ?
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001235 AND alias = ?
1236 AND state = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08001237 )
1238 .context("In get_or_create_key_with: Failed to select from keyentry table.")?;
1239 let mut rows = stmt
1240 .query(params![KeyType::Super, domain.0, namespace, alias, KeyLifeCycle::Live])
1241 .context("In get_or_create_key_with: Failed to query from keyentry table.")?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001242
Janis Danisevskis66784c42021-01-27 08:40:25 -08001243 db_utils::with_rows_extract_one(&mut rows, |row| {
1244 Ok(match row {
1245 Some(r) => r.get(0).context("Failed to unpack id.")?,
1246 None => None,
1247 })
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001248 })
Janis Danisevskis66784c42021-01-27 08:40:25 -08001249 .context("In get_or_create_key_with.")?
1250 };
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001251
Janis Danisevskis66784c42021-01-27 08:40:25 -08001252 let (id, entry) = match id {
1253 Some(id) => (
1254 id,
1255 Self::load_key_components(&tx, KeyEntryLoadBits::KM, id)
1256 .context("In get_or_create_key_with.")?,
1257 ),
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001258
Janis Danisevskis66784c42021-01-27 08:40:25 -08001259 None => {
1260 let id = Self::insert_with_retry(|id| {
1261 tx.execute(
1262 "INSERT into persistent.keyentry
Max Bires8e93d2b2021-01-14 13:17:59 -08001263 (id, key_type, domain, namespace, alias, state, km_uuid)
1264 VALUES(?, ?, ?, ?, ?, ?, ?);",
Janis Danisevskis66784c42021-01-27 08:40:25 -08001265 params![
1266 id,
1267 KeyType::Super,
1268 domain.0,
1269 namespace,
1270 alias,
1271 KeyLifeCycle::Live,
1272 km_uuid,
1273 ],
1274 )
1275 })
1276 .context("In get_or_create_key_with.")?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001277
Janis Danisevskis66784c42021-01-27 08:40:25 -08001278 let (blob, metadata) =
1279 create_new_key().context("In get_or_create_key_with.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001280 Self::set_blob_internal(
1281 &tx,
1282 id,
1283 SubComponentType::KEY_BLOB,
1284 Some(&blob),
1285 Some(&metadata),
1286 )
1287 .context("In get_of_create_key_with.")?;
Janis Danisevskis66784c42021-01-27 08:40:25 -08001288 (
Janis Danisevskis377d1002021-01-27 19:07:48 -08001289 id,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001290 KeyEntry {
1291 id,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001292 key_blob_info: Some((blob, metadata)),
Janis Danisevskis66784c42021-01-27 08:40:25 -08001293 pure_cert: false,
1294 ..Default::default()
1295 },
1296 )
1297 }
1298 };
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001299 Ok((KEY_ID_LOCK.get(id), entry)).no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08001300 })
1301 .context("In get_or_create_key_with.")
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001302 }
1303
Janis Danisevskis66784c42021-01-27 08:40:25 -08001304 /// SQLite3 seems to hold a shared mutex while running the busy handler when
1305 /// waiting for the database file to become available. This makes it
1306 /// impossible to successfully recover from a locked database when the
1307 /// transaction holding the device busy is in the same process on a
1308 /// different connection. As a result the busy handler has to time out and
1309 /// fail in order to make progress.
1310 ///
1311 /// Instead, we set the busy handler to None (return immediately). And catch
1312 /// Busy and Locked errors (the latter occur on in memory databases with
1313 /// shared cache, e.g., the per-boot database.) and restart the transaction
1314 /// after a grace period of half a millisecond.
1315 ///
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001316 /// Creates a transaction with the given behavior and executes f with the new transaction.
Janis Danisevskis66784c42021-01-27 08:40:25 -08001317 /// The transaction is committed only if f returns Ok and retried if DatabaseBusy
1318 /// or DatabaseLocked is encountered.
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001319 fn with_transaction<T, F>(&mut self, behavior: TransactionBehavior, f: F) -> Result<T>
1320 where
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001321 F: Fn(&Transaction) -> Result<(bool, T)>,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001322 {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001323 loop {
1324 match self
1325 .conn
1326 .transaction_with_behavior(behavior)
1327 .context("In with_transaction.")
1328 .and_then(|tx| f(&tx).map(|result| (result, tx)))
1329 .and_then(|(result, tx)| {
1330 tx.commit().context("In with_transaction: Failed to commit transaction.")?;
1331 Ok(result)
1332 }) {
1333 Ok(result) => break Ok(result),
1334 Err(e) => {
1335 if Self::is_locked_error(&e) {
1336 std::thread::sleep(std::time::Duration::from_micros(500));
1337 continue;
1338 } else {
1339 return Err(e).context("In with_transaction.");
1340 }
1341 }
1342 }
1343 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001344 .map(|(need_gc, result)| {
1345 if need_gc {
1346 if let Some(ref gc) = self.gc {
1347 gc.notify_gc();
1348 }
1349 }
1350 result
1351 })
Janis Danisevskis66784c42021-01-27 08:40:25 -08001352 }
1353
1354 fn is_locked_error(e: &anyhow::Error) -> bool {
1355 matches!(e.root_cause().downcast_ref::<rusqlite::ffi::Error>(),
1356 Some(rusqlite::ffi::Error {
1357 code: rusqlite::ErrorCode::DatabaseBusy,
1358 ..
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001359 })
Janis Danisevskis66784c42021-01-27 08:40:25 -08001360 | Some(rusqlite::ffi::Error {
1361 code: rusqlite::ErrorCode::DatabaseLocked,
1362 ..
1363 }))
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001364 }
1365
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001366 /// Creates a new key entry and allocates a new randomized id for the new key.
1367 /// The key id gets associated with a domain and namespace but not with an alias.
1368 /// To complete key generation `rebind_alias` should be called after all of the
1369 /// key artifacts, i.e., blobs and parameters have been associated with the new
1370 /// key id. Finalizing with `rebind_alias` makes the creation of a new key entry
1371 /// atomic even if key generation is not.
Max Bires8e93d2b2021-01-14 13:17:59 -08001372 pub fn create_key_entry(
1373 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001374 domain: &Domain,
1375 namespace: &i64,
Max Bires8e93d2b2021-01-14 13:17:59 -08001376 km_uuid: &Uuid,
1377 ) -> Result<KeyIdGuard> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001378 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001379 Self::create_key_entry_internal(tx, domain, namespace, km_uuid).no_gc()
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001380 })
1381 .context("In create_key_entry.")
1382 }
1383
1384 fn create_key_entry_internal(
1385 tx: &Transaction,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001386 domain: &Domain,
1387 namespace: &i64,
Max Bires8e93d2b2021-01-14 13:17:59 -08001388 km_uuid: &Uuid,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001389 ) -> Result<KeyIdGuard> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001390 match *domain {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001391 Domain::APP | Domain::SELINUX => {}
Joel Galenson0891bc12020-07-20 10:37:03 -07001392 _ => {
1393 return Err(KsError::sys())
1394 .context(format!("Domain {:?} must be either App or SELinux.", domain));
1395 }
1396 }
Janis Danisevskisaec14592020-11-12 09:41:49 -08001397 Ok(KEY_ID_LOCK.get(
1398 Self::insert_with_retry(|id| {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001399 tx.execute(
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001400 "INSERT into persistent.keyentry
Max Bires8e93d2b2021-01-14 13:17:59 -08001401 (id, key_type, domain, namespace, alias, state, km_uuid)
1402 VALUES(?, ?, ?, ?, NULL, ?, ?);",
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001403 params![
1404 id,
1405 KeyType::Client,
1406 domain.0 as u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001407 *namespace,
Max Bires8e93d2b2021-01-14 13:17:59 -08001408 KeyLifeCycle::Existing,
1409 km_uuid,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001410 ],
Janis Danisevskisaec14592020-11-12 09:41:49 -08001411 )
1412 })
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001413 .context("In create_key_entry_internal")?,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001414 ))
Joel Galenson26f4d012020-07-17 14:57:21 -07001415 }
Joel Galenson33c04ad2020-08-03 11:04:38 -07001416
Max Bires2b2e6562020-09-22 11:22:36 -07001417 /// Creates a new attestation key entry and allocates a new randomized id for the new key.
1418 /// The key id gets associated with a domain and namespace later but not with an alias. The
1419 /// alias will be used to denote if a key has been signed as each key can only be bound to one
1420 /// domain and namespace pairing so there is no need to use them as a value for indexing into
1421 /// a key.
1422 pub fn create_attestation_key_entry(
1423 &mut self,
1424 maced_public_key: &[u8],
1425 raw_public_key: &[u8],
1426 private_key: &[u8],
1427 km_uuid: &Uuid,
1428 ) -> Result<()> {
1429 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1430 let key_id = KEY_ID_LOCK.get(
1431 Self::insert_with_retry(|id| {
1432 tx.execute(
1433 "INSERT into persistent.keyentry
1434 (id, key_type, domain, namespace, alias, state, km_uuid)
1435 VALUES(?, ?, NULL, NULL, NULL, ?, ?);",
1436 params![id, KeyType::Attestation, KeyLifeCycle::Live, km_uuid],
1437 )
1438 })
1439 .context("In create_key_entry")?,
1440 );
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001441 Self::set_blob_internal(
1442 &tx,
1443 key_id.0,
1444 SubComponentType::KEY_BLOB,
1445 Some(private_key),
1446 None,
1447 )?;
Max Bires2b2e6562020-09-22 11:22:36 -07001448 let mut metadata = KeyMetaData::new();
1449 metadata.add(KeyMetaEntry::AttestationMacedPublicKey(maced_public_key.to_vec()));
1450 metadata.add(KeyMetaEntry::AttestationRawPubKey(raw_public_key.to_vec()));
1451 metadata.store_in_db(key_id.0, &tx)?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001452 Ok(()).no_gc()
Max Bires2b2e6562020-09-22 11:22:36 -07001453 })
1454 .context("In create_attestation_key_entry")
1455 }
1456
Janis Danisevskis377d1002021-01-27 19:07:48 -08001457 /// Set a new blob and associates it with the given key id. Each blob
1458 /// has a sub component type.
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001459 /// Each key can have one of each sub component type associated. If more
1460 /// are added only the most recent can be retrieved, and superseded blobs
Janis Danisevskis377d1002021-01-27 19:07:48 -08001461 /// will get garbage collected.
1462 /// Components SubComponentType::CERT and SubComponentType::CERT_CHAIN can be
1463 /// removed by setting blob to None.
1464 pub fn set_blob(
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001465 &mut self,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001466 key_id: &KeyIdGuard,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001467 sc_type: SubComponentType,
Janis Danisevskis377d1002021-01-27 19:07:48 -08001468 blob: Option<&[u8]>,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001469 blob_metadata: Option<&BlobMetaData>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001470 ) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001471 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001472 Self::set_blob_internal(&tx, key_id.0, sc_type, blob, blob_metadata).need_gc()
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001473 })
Janis Danisevskis377d1002021-01-27 19:07:48 -08001474 .context("In set_blob.")
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001475 }
1476
Janis Danisevskiseed69842021-02-18 20:04:10 -08001477 /// Why would we insert a deleted blob? This weird function is for the purpose of legacy
1478 /// key migration in the case where we bulk delete all the keys of an app or even a user.
1479 /// We use this to insert key blobs into the database which can then be garbage collected
1480 /// lazily by the key garbage collector.
1481 pub fn set_deleted_blob(&mut self, blob: &[u8], blob_metadata: &BlobMetaData) -> Result<()> {
1482 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1483 Self::set_blob_internal(
1484 &tx,
1485 Self::UNASSIGNED_KEY_ID,
1486 SubComponentType::KEY_BLOB,
1487 Some(blob),
1488 Some(blob_metadata),
1489 )
1490 .need_gc()
1491 })
1492 .context("In set_deleted_blob.")
1493 }
1494
Janis Danisevskis377d1002021-01-27 19:07:48 -08001495 fn set_blob_internal(
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001496 tx: &Transaction,
1497 key_id: i64,
1498 sc_type: SubComponentType,
Janis Danisevskis377d1002021-01-27 19:07:48 -08001499 blob: Option<&[u8]>,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001500 blob_metadata: Option<&BlobMetaData>,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001501 ) -> Result<()> {
Janis Danisevskis377d1002021-01-27 19:07:48 -08001502 match (blob, sc_type) {
1503 (Some(blob), _) => {
1504 tx.execute(
1505 "INSERT INTO persistent.blobentry
1506 (subcomponent_type, keyentryid, blob) VALUES (?, ?, ?);",
1507 params![sc_type, key_id, blob],
1508 )
1509 .context("In set_blob_internal: Failed to insert blob.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001510 if let Some(blob_metadata) = blob_metadata {
1511 let blob_id = tx
1512 .query_row("SELECT MAX(id) FROM persistent.blobentry;", NO_PARAMS, |row| {
1513 row.get(0)
1514 })
1515 .context("In set_blob_internal: Failed to get new blob id.")?;
1516 blob_metadata
1517 .store_in_db(blob_id, tx)
1518 .context("In set_blob_internal: Trying to store blob metadata.")?;
1519 }
Janis Danisevskis377d1002021-01-27 19:07:48 -08001520 }
1521 (None, SubComponentType::CERT) | (None, SubComponentType::CERT_CHAIN) => {
1522 tx.execute(
1523 "DELETE FROM persistent.blobentry
1524 WHERE subcomponent_type = ? AND keyentryid = ?;",
1525 params![sc_type, key_id],
1526 )
1527 .context("In set_blob_internal: Failed to delete blob.")?;
1528 }
1529 (None, _) => {
1530 return Err(KsError::sys())
1531 .context("In set_blob_internal: Other blobs cannot be deleted in this way.");
1532 }
1533 }
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001534 Ok(())
1535 }
1536
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001537 /// Inserts a collection of key parameters into the `persistent.keyparameter` table
1538 /// and associates them with the given `key_id`.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001539 #[cfg(test)]
1540 fn insert_keyparameter(&mut self, key_id: &KeyIdGuard, params: &[KeyParameter]) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001541 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001542 Self::insert_keyparameter_internal(tx, key_id, params).no_gc()
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001543 })
1544 .context("In insert_keyparameter.")
1545 }
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001546
Janis Danisevskis66784c42021-01-27 08:40:25 -08001547 fn insert_keyparameter_internal(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001548 tx: &Transaction,
1549 key_id: &KeyIdGuard,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001550 params: &[KeyParameter],
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001551 ) -> Result<()> {
1552 let mut stmt = tx
1553 .prepare(
1554 "INSERT into persistent.keyparameter (keyentryid, tag, data, security_level)
1555 VALUES (?, ?, ?, ?);",
1556 )
1557 .context("In insert_keyparameter_internal: Failed to prepare statement.")?;
1558
Janis Danisevskis66784c42021-01-27 08:40:25 -08001559 for p in params.iter() {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001560 stmt.insert(params![
1561 key_id.0,
1562 p.get_tag().0,
1563 p.key_parameter_value(),
1564 p.security_level().0
1565 ])
1566 .with_context(|| {
1567 format!("In insert_keyparameter_internal: Failed to insert {:?}", p)
1568 })?;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001569 }
1570 Ok(())
1571 }
1572
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001573 /// Insert a set of key entry specific metadata into the database.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001574 #[cfg(test)]
1575 fn insert_key_metadata(&mut self, key_id: &KeyIdGuard, metadata: &KeyMetaData) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001576 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001577 metadata.store_in_db(key_id.0, &tx).no_gc()
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001578 })
1579 .context("In insert_key_metadata.")
1580 }
1581
Max Bires2b2e6562020-09-22 11:22:36 -07001582 /// Stores a signed certificate chain signed by a remote provisioning server, keyed
1583 /// on the public key.
1584 pub fn store_signed_attestation_certificate_chain(
1585 &mut self,
1586 raw_public_key: &[u8],
Max Biresb2e1d032021-02-08 21:35:05 -08001587 batch_cert: &[u8],
Max Bires2b2e6562020-09-22 11:22:36 -07001588 cert_chain: &[u8],
1589 expiration_date: i64,
1590 km_uuid: &Uuid,
1591 ) -> Result<()> {
1592 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1593 let mut stmt = tx
1594 .prepare(
1595 "SELECT keyentryid
1596 FROM persistent.keymetadata
1597 WHERE tag = ? AND data = ? AND keyentryid IN
1598 (SELECT id
1599 FROM persistent.keyentry
1600 WHERE
1601 alias IS NULL AND
1602 domain IS NULL AND
1603 namespace IS NULL AND
1604 key_type = ? AND
1605 km_uuid = ?);",
1606 )
1607 .context("Failed to store attestation certificate chain.")?;
1608 let mut rows = stmt
1609 .query(params![
1610 KeyMetaData::AttestationRawPubKey,
1611 raw_public_key,
1612 KeyType::Attestation,
1613 km_uuid
1614 ])
1615 .context("Failed to fetch keyid")?;
1616 let key_id = db_utils::with_rows_extract_one(&mut rows, |row| {
1617 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?
1618 .get(0)
1619 .context("Failed to unpack id.")
1620 })
1621 .context("Failed to get key_id.")?;
1622 let num_updated = tx
1623 .execute(
1624 "UPDATE persistent.keyentry
1625 SET alias = ?
1626 WHERE id = ?;",
1627 params!["signed", key_id],
1628 )
1629 .context("Failed to update alias.")?;
1630 if num_updated != 1 {
1631 return Err(KsError::sys()).context("Alias not updated for the key.");
1632 }
1633 let mut metadata = KeyMetaData::new();
1634 metadata.add(KeyMetaEntry::AttestationExpirationDate(DateTime::from_millis_epoch(
1635 expiration_date,
1636 )));
1637 metadata.store_in_db(key_id, &tx).context("Failed to insert key metadata.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001638 Self::set_blob_internal(
1639 &tx,
1640 key_id,
1641 SubComponentType::CERT_CHAIN,
1642 Some(cert_chain),
1643 None,
1644 )
1645 .context("Failed to insert cert chain")?;
Max Biresb2e1d032021-02-08 21:35:05 -08001646 Self::set_blob_internal(&tx, key_id, SubComponentType::CERT, Some(batch_cert), None)
1647 .context("Failed to insert cert")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001648 Ok(()).no_gc()
Max Bires2b2e6562020-09-22 11:22:36 -07001649 })
1650 .context("In store_signed_attestation_certificate_chain: ")
1651 }
1652
1653 /// Assigns the next unassigned attestation key to a domain/namespace combo that does not
1654 /// currently have a key assigned to it.
1655 pub fn assign_attestation_key(
1656 &mut self,
1657 domain: Domain,
1658 namespace: i64,
1659 km_uuid: &Uuid,
1660 ) -> Result<()> {
1661 match domain {
1662 Domain::APP | Domain::SELINUX => {}
1663 _ => {
1664 return Err(KsError::sys()).context(format!(
1665 concat!(
1666 "In assign_attestation_key: Domain {:?} ",
1667 "must be either App or SELinux.",
1668 ),
1669 domain
1670 ));
1671 }
1672 }
1673 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1674 let result = tx
1675 .execute(
1676 "UPDATE persistent.keyentry
1677 SET domain=?1, namespace=?2
1678 WHERE
1679 id =
1680 (SELECT MIN(id)
1681 FROM persistent.keyentry
1682 WHERE ALIAS IS NOT NULL
1683 AND domain IS NULL
1684 AND key_type IS ?3
1685 AND state IS ?4
1686 AND km_uuid IS ?5)
1687 AND
1688 (SELECT COUNT(*)
1689 FROM persistent.keyentry
1690 WHERE domain=?1
1691 AND namespace=?2
1692 AND key_type IS ?3
1693 AND state IS ?4
1694 AND km_uuid IS ?5) = 0;",
1695 params![
1696 domain.0 as u32,
1697 namespace,
1698 KeyType::Attestation,
1699 KeyLifeCycle::Live,
1700 km_uuid,
1701 ],
1702 )
1703 .context("Failed to assign attestation key")?;
1704 if result != 1 {
1705 return Err(KsError::sys()).context(format!(
1706 "Expected to update a single entry but instead updated {}.",
1707 result
1708 ));
1709 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001710 Ok(()).no_gc()
Max Bires2b2e6562020-09-22 11:22:36 -07001711 })
1712 .context("In assign_attestation_key: ")
1713 }
1714
1715 /// Retrieves num_keys number of attestation keys that have not yet been signed by a remote
1716 /// provisioning server, or the maximum number available if there are not num_keys number of
1717 /// entries in the table.
1718 pub fn fetch_unsigned_attestation_keys(
1719 &mut self,
1720 num_keys: i32,
1721 km_uuid: &Uuid,
1722 ) -> Result<Vec<Vec<u8>>> {
1723 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1724 let mut stmt = tx
1725 .prepare(
1726 "SELECT data
1727 FROM persistent.keymetadata
1728 WHERE tag = ? AND keyentryid IN
1729 (SELECT id
1730 FROM persistent.keyentry
1731 WHERE
1732 alias IS NULL AND
1733 domain IS NULL AND
1734 namespace IS NULL AND
1735 key_type = ? AND
1736 km_uuid = ?
1737 LIMIT ?);",
1738 )
1739 .context("Failed to prepare statement")?;
1740 let rows = stmt
1741 .query_map(
1742 params![
1743 KeyMetaData::AttestationMacedPublicKey,
1744 KeyType::Attestation,
1745 km_uuid,
1746 num_keys
1747 ],
1748 |row| Ok(row.get(0)?),
1749 )?
1750 .collect::<rusqlite::Result<Vec<Vec<u8>>>>()
1751 .context("Failed to execute statement")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001752 Ok(rows).no_gc()
Max Bires2b2e6562020-09-22 11:22:36 -07001753 })
1754 .context("In fetch_unsigned_attestation_keys")
1755 }
1756
1757 /// Removes any keys that have expired as of the current time. Returns the number of keys
1758 /// marked unreferenced that are bound to be garbage collected.
1759 pub fn delete_expired_attestation_keys(&mut self) -> Result<i32> {
1760 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1761 let mut stmt = tx
1762 .prepare(
1763 "SELECT keyentryid, data
1764 FROM persistent.keymetadata
1765 WHERE tag = ? AND keyentryid IN
1766 (SELECT id
1767 FROM persistent.keyentry
1768 WHERE key_type = ?);",
1769 )
1770 .context("Failed to prepare query")?;
1771 let key_ids_to_check = stmt
1772 .query_map(
1773 params![KeyMetaData::AttestationExpirationDate, KeyType::Attestation],
1774 |row| Ok((row.get(0)?, row.get(1)?)),
1775 )?
1776 .collect::<rusqlite::Result<Vec<(i64, DateTime)>>>()
1777 .context("Failed to get date metadata")?;
1778 let curr_time = DateTime::from_millis_epoch(
1779 SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_millis() as i64,
1780 );
1781 let mut num_deleted = 0;
1782 for id in key_ids_to_check.iter().filter(|kt| kt.1 < curr_time).map(|kt| kt.0) {
1783 if Self::mark_unreferenced(&tx, id)? {
1784 num_deleted += 1;
1785 }
1786 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001787 Ok(num_deleted).do_gc(num_deleted != 0)
Max Bires2b2e6562020-09-22 11:22:36 -07001788 })
1789 .context("In delete_expired_attestation_keys: ")
1790 }
1791
1792 /// Counts the number of keys that will expire by the provided epoch date and the number of
1793 /// keys not currently assigned to a domain.
1794 pub fn get_attestation_pool_status(
1795 &mut self,
1796 date: i64,
1797 km_uuid: &Uuid,
1798 ) -> Result<AttestationPoolStatus> {
1799 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1800 let mut stmt = tx.prepare(
1801 "SELECT data
1802 FROM persistent.keymetadata
1803 WHERE tag = ? AND keyentryid IN
1804 (SELECT id
1805 FROM persistent.keyentry
1806 WHERE alias IS NOT NULL
1807 AND key_type = ?
1808 AND km_uuid = ?
1809 AND state = ?);",
1810 )?;
1811 let times = stmt
1812 .query_map(
1813 params![
1814 KeyMetaData::AttestationExpirationDate,
1815 KeyType::Attestation,
1816 km_uuid,
1817 KeyLifeCycle::Live
1818 ],
1819 |row| Ok(row.get(0)?),
1820 )?
1821 .collect::<rusqlite::Result<Vec<DateTime>>>()
1822 .context("Failed to execute metadata statement")?;
1823 let expiring =
1824 times.iter().filter(|time| time < &&DateTime::from_millis_epoch(date)).count()
1825 as i32;
1826 stmt = tx.prepare(
1827 "SELECT alias, domain
1828 FROM persistent.keyentry
1829 WHERE key_type = ? AND km_uuid = ? AND state = ?;",
1830 )?;
1831 let rows = stmt
1832 .query_map(params![KeyType::Attestation, km_uuid, KeyLifeCycle::Live], |row| {
1833 Ok((row.get(0)?, row.get(1)?))
1834 })?
1835 .collect::<rusqlite::Result<Vec<(Option<String>, Option<u32>)>>>()
1836 .context("Failed to execute keyentry statement")?;
1837 let mut unassigned = 0i32;
1838 let mut attested = 0i32;
1839 let total = rows.len() as i32;
1840 for (alias, domain) in rows {
1841 match (alias, domain) {
1842 (Some(_alias), None) => {
1843 attested += 1;
1844 unassigned += 1;
1845 }
1846 (Some(_alias), Some(_domain)) => {
1847 attested += 1;
1848 }
1849 _ => {}
1850 }
1851 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001852 Ok(AttestationPoolStatus { expiring, unassigned, attested, total }).no_gc()
Max Bires2b2e6562020-09-22 11:22:36 -07001853 })
1854 .context("In get_attestation_pool_status: ")
1855 }
1856
1857 /// Fetches the private key and corresponding certificate chain assigned to a
1858 /// domain/namespace pair. Will either return nothing if the domain/namespace is
1859 /// not assigned, or one CertificateChain.
1860 pub fn retrieve_attestation_key_and_cert_chain(
1861 &mut self,
1862 domain: Domain,
1863 namespace: i64,
1864 km_uuid: &Uuid,
1865 ) -> Result<Option<CertificateChain>> {
1866 match domain {
1867 Domain::APP | Domain::SELINUX => {}
1868 _ => {
1869 return Err(KsError::sys())
1870 .context(format!("Domain {:?} must be either App or SELinux.", domain));
1871 }
1872 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001873 self.with_transaction(TransactionBehavior::Deferred, |tx| {
1874 let mut stmt = tx.prepare(
1875 "SELECT subcomponent_type, blob
Max Bires2b2e6562020-09-22 11:22:36 -07001876 FROM persistent.blobentry
1877 WHERE keyentryid IN
1878 (SELECT id
1879 FROM persistent.keyentry
1880 WHERE key_type = ?
1881 AND domain = ?
1882 AND namespace = ?
1883 AND state = ?
1884 AND km_uuid = ?);",
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001885 )?;
1886 let rows = stmt
1887 .query_map(
1888 params![
1889 KeyType::Attestation,
1890 domain.0 as u32,
1891 namespace,
1892 KeyLifeCycle::Live,
1893 km_uuid
1894 ],
1895 |row| Ok((row.get(0)?, row.get(1)?)),
1896 )?
1897 .collect::<rusqlite::Result<Vec<(SubComponentType, Vec<u8>)>>>()
Max Biresb2e1d032021-02-08 21:35:05 -08001898 .context("query failed.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001899 if rows.is_empty() {
1900 return Ok(None).no_gc();
Max Biresb2e1d032021-02-08 21:35:05 -08001901 } else if rows.len() != 3 {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001902 return Err(KsError::sys()).context(format!(
1903 concat!(
Max Biresb2e1d032021-02-08 21:35:05 -08001904 "Expected to get a single attestation",
1905 "key, cert, and cert chain for a total of 3 entries, but instead got {}."
1906 ),
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001907 rows.len()
1908 ));
Max Bires2b2e6562020-09-22 11:22:36 -07001909 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001910 let mut km_blob: Vec<u8> = Vec::new();
1911 let mut cert_chain_blob: Vec<u8> = Vec::new();
Max Biresb2e1d032021-02-08 21:35:05 -08001912 let mut batch_cert_blob: Vec<u8> = Vec::new();
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001913 for row in rows {
1914 let sub_type: SubComponentType = row.0;
1915 match sub_type {
1916 SubComponentType::KEY_BLOB => {
1917 km_blob = row.1;
1918 }
1919 SubComponentType::CERT_CHAIN => {
1920 cert_chain_blob = row.1;
1921 }
Max Biresb2e1d032021-02-08 21:35:05 -08001922 SubComponentType::CERT => {
1923 batch_cert_blob = row.1;
1924 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001925 _ => Err(KsError::sys()).context("Unknown or incorrect subcomponent type.")?,
1926 }
1927 }
1928 Ok(Some(CertificateChain {
1929 private_key: ZVec::try_from(km_blob)?,
Max Bires97f96812021-02-23 23:44:57 -08001930 batch_cert: batch_cert_blob,
1931 cert_chain: cert_chain_blob,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001932 }))
1933 .no_gc()
1934 })
Max Biresb2e1d032021-02-08 21:35:05 -08001935 .context("In retrieve_attestation_key_and_cert_chain:")
Max Bires2b2e6562020-09-22 11:22:36 -07001936 }
1937
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001938 /// Updates the alias column of the given key id `newid` with the given alias,
1939 /// and atomically, removes the alias, domain, and namespace from another row
1940 /// with the same alias-domain-namespace tuple if such row exits.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001941 /// Returns Ok(true) if an old key was marked unreferenced as a hint to the garbage
1942 /// collector.
1943 fn rebind_alias(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001944 tx: &Transaction,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001945 newid: &KeyIdGuard,
Joel Galenson33c04ad2020-08-03 11:04:38 -07001946 alias: &str,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001947 domain: &Domain,
1948 namespace: &i64,
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001949 ) -> Result<bool> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001950 match *domain {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001951 Domain::APP | Domain::SELINUX => {}
Joel Galenson33c04ad2020-08-03 11:04:38 -07001952 _ => {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001953 return Err(KsError::sys()).context(format!(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001954 "In rebind_alias: Domain {:?} must be either App or SELinux.",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001955 domain
1956 ));
Joel Galenson33c04ad2020-08-03 11:04:38 -07001957 }
1958 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001959 let updated = tx
1960 .execute(
1961 "UPDATE persistent.keyentry
1962 SET alias = NULL, domain = NULL, namespace = NULL, state = ?
Joel Galenson33c04ad2020-08-03 11:04:38 -07001963 WHERE alias = ? AND domain = ? AND namespace = ?;",
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001964 params![KeyLifeCycle::Unreferenced, alias, domain.0 as u32, namespace],
1965 )
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001966 .context("In rebind_alias: Failed to rebind existing entry.")?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07001967 let result = tx
1968 .execute(
1969 "UPDATE persistent.keyentry
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001970 SET alias = ?, state = ?
1971 WHERE id = ? AND domain = ? AND namespace = ? AND state = ?;",
1972 params![
1973 alias,
1974 KeyLifeCycle::Live,
1975 newid.0,
1976 domain.0 as u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001977 *namespace,
Max Bires8e93d2b2021-01-14 13:17:59 -08001978 KeyLifeCycle::Existing,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001979 ],
Joel Galenson33c04ad2020-08-03 11:04:38 -07001980 )
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001981 .context("In rebind_alias: Failed to set alias.")?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07001982 if result != 1 {
Joel Galenson33c04ad2020-08-03 11:04:38 -07001983 return Err(KsError::sys()).context(format!(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001984 "In rebind_alias: Expected to update a single entry but instead updated {}.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07001985 result
1986 ));
1987 }
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001988 Ok(updated != 0)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001989 }
1990
1991 /// Store a new key in a single transaction.
1992 /// The function creates a new key entry, populates the blob, key parameter, and metadata
1993 /// fields, and rebinds the given alias to the new key.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001994 /// The boolean returned is a hint for the garbage collector. If true, a key was replaced,
1995 /// is now unreferenced and needs to be collected.
Janis Danisevskis66784c42021-01-27 08:40:25 -08001996 pub fn store_new_key(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001997 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001998 key: &KeyDescriptor,
1999 params: &[KeyParameter],
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002000 blob_info: &(&[u8], &BlobMetaData),
Max Bires8e93d2b2021-01-14 13:17:59 -08002001 cert_info: &CertificateInfo,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002002 metadata: &KeyMetaData,
Max Bires8e93d2b2021-01-14 13:17:59 -08002003 km_uuid: &Uuid,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002004 ) -> Result<KeyIdGuard> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002005 let (alias, domain, namespace) = match key {
2006 KeyDescriptor { alias: Some(alias), domain: Domain::APP, nspace, blob: None }
2007 | KeyDescriptor { alias: Some(alias), domain: Domain::SELINUX, nspace, blob: None } => {
2008 (alias, key.domain, nspace)
2009 }
2010 _ => {
2011 return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT))
2012 .context("In store_new_key: Need alias and domain must be APP or SELINUX.")
2013 }
2014 };
2015 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002016 let key_id = Self::create_key_entry_internal(tx, &domain, namespace, km_uuid)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002017 .context("Trying to create new key entry.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002018 let (blob, blob_metadata) = *blob_info;
2019 Self::set_blob_internal(
2020 tx,
2021 key_id.id(),
2022 SubComponentType::KEY_BLOB,
2023 Some(blob),
2024 Some(&blob_metadata),
2025 )
2026 .context("Trying to insert the key blob.")?;
Max Bires8e93d2b2021-01-14 13:17:59 -08002027 if let Some(cert) = &cert_info.cert {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002028 Self::set_blob_internal(tx, key_id.id(), SubComponentType::CERT, Some(&cert), None)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002029 .context("Trying to insert the certificate.")?;
2030 }
Max Bires8e93d2b2021-01-14 13:17:59 -08002031 if let Some(cert_chain) = &cert_info.cert_chain {
Janis Danisevskis377d1002021-01-27 19:07:48 -08002032 Self::set_blob_internal(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002033 tx,
2034 key_id.id(),
2035 SubComponentType::CERT_CHAIN,
Janis Danisevskis377d1002021-01-27 19:07:48 -08002036 Some(&cert_chain),
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002037 None,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002038 )
2039 .context("Trying to insert the certificate chain.")?;
2040 }
2041 Self::insert_keyparameter_internal(tx, &key_id, params)
2042 .context("Trying to insert key parameters.")?;
Janis Danisevskis377d1002021-01-27 19:07:48 -08002043 metadata.store_in_db(key_id.id(), tx).context("Trying to insert key metadata.")?;
Janis Danisevskis66784c42021-01-27 08:40:25 -08002044 let need_gc = Self::rebind_alias(tx, &key_id, &alias, &domain, namespace)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002045 .context("Trying to rebind alias.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002046 Ok(key_id).do_gc(need_gc)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002047 })
2048 .context("In store_new_key.")
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002049 }
2050
Janis Danisevskis377d1002021-01-27 19:07:48 -08002051 /// Store a new certificate
2052 /// The function creates a new key entry, populates the blob field and metadata, and rebinds
2053 /// the given alias to the new cert.
Max Bires8e93d2b2021-01-14 13:17:59 -08002054 pub fn store_new_certificate(
2055 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002056 key: &KeyDescriptor,
Max Bires8e93d2b2021-01-14 13:17:59 -08002057 cert: &[u8],
2058 km_uuid: &Uuid,
2059 ) -> Result<KeyIdGuard> {
Janis Danisevskis377d1002021-01-27 19:07:48 -08002060 let (alias, domain, namespace) = match key {
2061 KeyDescriptor { alias: Some(alias), domain: Domain::APP, nspace, blob: None }
2062 | KeyDescriptor { alias: Some(alias), domain: Domain::SELINUX, nspace, blob: None } => {
2063 (alias, key.domain, nspace)
2064 }
2065 _ => {
2066 return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT)).context(
2067 "In store_new_certificate: Need alias and domain must be APP or SELINUX.",
2068 )
2069 }
2070 };
2071 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002072 let key_id = Self::create_key_entry_internal(tx, &domain, namespace, km_uuid)
Janis Danisevskis377d1002021-01-27 19:07:48 -08002073 .context("Trying to create new key entry.")?;
2074
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002075 Self::set_blob_internal(
2076 tx,
2077 key_id.id(),
2078 SubComponentType::CERT_CHAIN,
2079 Some(cert),
2080 None,
2081 )
2082 .context("Trying to insert certificate.")?;
Janis Danisevskis377d1002021-01-27 19:07:48 -08002083
2084 let mut metadata = KeyMetaData::new();
2085 metadata.add(KeyMetaEntry::CreationDate(
2086 DateTime::now().context("Trying to make creation time.")?,
2087 ));
2088
2089 metadata.store_in_db(key_id.id(), tx).context("Trying to insert key metadata.")?;
2090
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002091 let need_gc = Self::rebind_alias(tx, &key_id, &alias, &domain, namespace)
Janis Danisevskis377d1002021-01-27 19:07:48 -08002092 .context("Trying to rebind alias.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002093 Ok(key_id).do_gc(need_gc)
Janis Danisevskis377d1002021-01-27 19:07:48 -08002094 })
2095 .context("In store_new_certificate.")
2096 }
2097
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002098 // Helper function loading the key_id given the key descriptor
2099 // tuple comprising domain, namespace, and alias.
2100 // Requires a valid transaction.
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002101 fn load_key_entry_id(tx: &Transaction, key: &KeyDescriptor, key_type: KeyType) -> Result<i64> {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002102 let alias = key
2103 .alias
2104 .as_ref()
2105 .map_or_else(|| Err(KsError::sys()), Ok)
2106 .context("In load_key_entry_id: Alias must be specified.")?;
2107 let mut stmt = tx
2108 .prepare(
2109 "SELECT id FROM persistent.keyentry
2110 WHERE
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00002111 key_type = ?
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002112 AND domain = ?
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002113 AND namespace = ?
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002114 AND alias = ?
2115 AND state = ?;",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002116 )
2117 .context("In load_key_entry_id: Failed to select from keyentry table.")?;
2118 let mut rows = stmt
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002119 .query(params![key_type, key.domain.0 as u32, key.nspace, alias, KeyLifeCycle::Live])
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002120 .context("In load_key_entry_id: Failed to read from keyentry table.")?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002121 db_utils::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002122 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002123 .get(0)
2124 .context("Failed to unpack id.")
2125 })
2126 .context("In load_key_entry_id.")
2127 }
2128
2129 /// This helper function completes the access tuple of a key, which is required
2130 /// to perform access control. The strategy depends on the `domain` field in the
2131 /// key descriptor.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002132 /// * Domain::SELINUX: The access tuple is complete and this function only loads
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002133 /// the key_id for further processing.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002134 /// * Domain::APP: Like Domain::SELINUX, but the tuple is completed by `caller_uid`
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002135 /// which serves as the namespace.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002136 /// * Domain::GRANT: The grant table is queried for the `key_id` and the
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002137 /// `access_vector`.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002138 /// * Domain::KEY_ID: The keyentry table is queried for the owning `domain` and
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002139 /// `namespace`.
2140 /// In each case the information returned is sufficient to perform the access
2141 /// check and the key id can be used to load further key artifacts.
2142 fn load_access_tuple(
2143 tx: &Transaction,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002144 key: &KeyDescriptor,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002145 key_type: KeyType,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002146 caller_uid: u32,
2147 ) -> Result<(i64, KeyDescriptor, Option<KeyPermSet>)> {
2148 match key.domain {
2149 // Domain App or SELinux. In this case we load the key_id from
2150 // the keyentry database for further loading of key components.
2151 // We already have the full access tuple to perform access control.
2152 // The only distinction is that we use the caller_uid instead
2153 // of the caller supplied namespace if the domain field is
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002154 // Domain::APP.
2155 Domain::APP | Domain::SELINUX => {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002156 let mut access_key = key.clone();
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002157 if access_key.domain == Domain::APP {
2158 access_key.nspace = caller_uid as i64;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002159 }
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002160 let key_id = Self::load_key_entry_id(&tx, &access_key, key_type)
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002161 .with_context(|| format!("With key.domain = {:?}.", access_key.domain))?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002162
2163 Ok((key_id, access_key, None))
2164 }
2165
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002166 // Domain::GRANT. In this case we load the key_id and the access_vector
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002167 // from the grant table.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002168 Domain::GRANT => {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002169 let mut stmt = tx
2170 .prepare(
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002171 "SELECT keyentryid, access_vector FROM persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002172 WHERE grantee = ? AND id = ?;",
2173 )
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002174 .context("Domain::GRANT prepare statement failed")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002175 let mut rows = stmt
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002176 .query(params![caller_uid as i64, key.nspace])
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002177 .context("Domain:Grant: query failed.")?;
2178 let (key_id, access_vector): (i64, i32) =
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002179 db_utils::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002180 let r =
2181 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002182 Ok((
2183 r.get(0).context("Failed to unpack key_id.")?,
2184 r.get(1).context("Failed to unpack access_vector.")?,
2185 ))
2186 })
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002187 .context("Domain::GRANT.")?;
Janis Danisevskis66784c42021-01-27 08:40:25 -08002188 Ok((key_id, key.clone(), Some(access_vector.into())))
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002189 }
2190
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002191 // Domain::KEY_ID. In this case we load the domain and namespace from the
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002192 // keyentry database because we need them for access control.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002193 Domain::KEY_ID => {
Janis Danisevskis45760022021-01-19 16:34:10 -08002194 let (domain, namespace): (Domain, i64) = {
2195 let mut stmt = tx
2196 .prepare(
2197 "SELECT domain, namespace FROM persistent.keyentry
2198 WHERE
2199 id = ?
2200 AND state = ?;",
2201 )
2202 .context("Domain::KEY_ID: prepare statement failed")?;
2203 let mut rows = stmt
2204 .query(params![key.nspace, KeyLifeCycle::Live])
2205 .context("Domain::KEY_ID: query failed.")?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002206 db_utils::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002207 let r =
2208 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002209 Ok((
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002210 Domain(r.get(0).context("Failed to unpack domain.")?),
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002211 r.get(1).context("Failed to unpack namespace.")?,
2212 ))
2213 })
Janis Danisevskis45760022021-01-19 16:34:10 -08002214 .context("Domain::KEY_ID.")?
2215 };
2216
2217 // We may use a key by id after loading it by grant.
2218 // In this case we have to check if the caller has a grant for this particular
2219 // key. We can skip this if we already know that the caller is the owner.
2220 // But we cannot know this if domain is anything but App. E.g. in the case
2221 // of Domain::SELINUX we have to speculatively check for grants because we have to
2222 // consult the SEPolicy before we know if the caller is the owner.
2223 let access_vector: Option<KeyPermSet> =
2224 if domain != Domain::APP || namespace != caller_uid as i64 {
2225 let access_vector: Option<i32> = tx
2226 .query_row(
2227 "SELECT access_vector FROM persistent.grant
2228 WHERE grantee = ? AND keyentryid = ?;",
2229 params![caller_uid as i64, key.nspace],
2230 |row| row.get(0),
2231 )
2232 .optional()
2233 .context("Domain::KEY_ID: query grant failed.")?;
2234 access_vector.map(|p| p.into())
2235 } else {
2236 None
2237 };
2238
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002239 let key_id = key.nspace;
Janis Danisevskis66784c42021-01-27 08:40:25 -08002240 let mut access_key: KeyDescriptor = key.clone();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002241 access_key.domain = domain;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002242 access_key.nspace = namespace;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002243
Janis Danisevskis45760022021-01-19 16:34:10 -08002244 Ok((key_id, access_key, access_vector))
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002245 }
2246 _ => Err(anyhow!(KsError::sys())),
2247 }
2248 }
2249
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002250 fn load_blob_components(
2251 key_id: i64,
2252 load_bits: KeyEntryLoadBits,
2253 tx: &Transaction,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002254 ) -> Result<(bool, Option<(Vec<u8>, BlobMetaData)>, Option<Vec<u8>>, Option<Vec<u8>>)> {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002255 let mut stmt = tx
2256 .prepare(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002257 "SELECT MAX(id), subcomponent_type, blob FROM persistent.blobentry
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002258 WHERE keyentryid = ? GROUP BY subcomponent_type;",
2259 )
2260 .context("In load_blob_components: prepare statement failed.")?;
2261
2262 let mut rows =
2263 stmt.query(params![key_id]).context("In load_blob_components: query failed.")?;
2264
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002265 let mut key_blob: Option<(i64, Vec<u8>)> = None;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002266 let mut cert_blob: Option<Vec<u8>> = None;
2267 let mut cert_chain_blob: Option<Vec<u8>> = None;
Janis Danisevskis377d1002021-01-27 19:07:48 -08002268 let mut has_km_blob: bool = false;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002269 db_utils::with_rows_extract_all(&mut rows, |row| {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002270 let sub_type: SubComponentType =
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002271 row.get(1).context("Failed to extract subcomponent_type.")?;
Janis Danisevskis377d1002021-01-27 19:07:48 -08002272 has_km_blob = has_km_blob || sub_type == SubComponentType::KEY_BLOB;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002273 match (sub_type, load_bits.load_public(), load_bits.load_km()) {
2274 (SubComponentType::KEY_BLOB, _, true) => {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002275 key_blob = Some((
2276 row.get(0).context("Failed to extract key blob id.")?,
2277 row.get(2).context("Failed to extract key blob.")?,
2278 ));
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002279 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002280 (SubComponentType::CERT, true, _) => {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002281 cert_blob =
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002282 Some(row.get(2).context("Failed to extract public certificate blob.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002283 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002284 (SubComponentType::CERT_CHAIN, true, _) => {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002285 cert_chain_blob =
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002286 Some(row.get(2).context("Failed to extract certificate chain blob.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002287 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002288 (SubComponentType::CERT, _, _)
2289 | (SubComponentType::CERT_CHAIN, _, _)
2290 | (SubComponentType::KEY_BLOB, _, _) => {}
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002291 _ => Err(KsError::sys()).context("Unknown subcomponent type.")?,
2292 }
2293 Ok(())
2294 })
2295 .context("In load_blob_components.")?;
2296
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002297 let blob_info = key_blob.map_or::<Result<_>, _>(Ok(None), |(blob_id, blob)| {
2298 Ok(Some((
2299 blob,
2300 BlobMetaData::load_from_db(blob_id, tx)
2301 .context("In load_blob_components: Trying to load blob_metadata.")?,
2302 )))
2303 })?;
2304
2305 Ok((has_km_blob, blob_info, cert_blob, cert_chain_blob))
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002306 }
2307
2308 fn load_key_parameters(key_id: i64, tx: &Transaction) -> Result<Vec<KeyParameter>> {
2309 let mut stmt = tx
2310 .prepare(
2311 "SELECT tag, data, security_level from persistent.keyparameter
2312 WHERE keyentryid = ?;",
2313 )
2314 .context("In load_key_parameters: prepare statement failed.")?;
2315
2316 let mut parameters: Vec<KeyParameter> = Vec::new();
2317
2318 let mut rows =
2319 stmt.query(params![key_id]).context("In load_key_parameters: query failed.")?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002320 db_utils::with_rows_extract_all(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002321 let tag = Tag(row.get(0).context("Failed to read tag.")?);
2322 let sec_level = SecurityLevel(row.get(2).context("Failed to read sec_level.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002323 parameters.push(
2324 KeyParameter::new_from_sql(tag, &SqlField::new(1, &row), sec_level)
2325 .context("Failed to read KeyParameter.")?,
2326 );
2327 Ok(())
2328 })
2329 .context("In load_key_parameters.")?;
2330
2331 Ok(parameters)
2332 }
2333
Qi Wub9433b52020-12-01 14:52:46 +08002334 /// Decrements the usage count of a limited use key. This function first checks whether the
2335 /// usage has been exhausted, if not, decreases the usage count. If the usage count reaches
2336 /// zero, the key also gets marked unreferenced and scheduled for deletion.
2337 /// Returns Ok(true) if the key was marked unreferenced as a hint to the garbage collector.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002338 pub fn check_and_update_key_usage_count(&mut self, key_id: i64) -> Result<()> {
Qi Wub9433b52020-12-01 14:52:46 +08002339 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2340 let limit: Option<i32> = tx
2341 .query_row(
2342 "SELECT data FROM persistent.keyparameter WHERE keyentryid = ? AND tag = ?;",
2343 params![key_id, Tag::USAGE_COUNT_LIMIT.0],
2344 |row| row.get(0),
2345 )
2346 .optional()
2347 .context("Trying to load usage count")?;
2348
2349 let limit = limit
2350 .ok_or(KsError::Km(ErrorCode::INVALID_KEY_BLOB))
2351 .context("The Key no longer exists. Key is exhausted.")?;
2352
2353 tx.execute(
2354 "UPDATE persistent.keyparameter
2355 SET data = data - 1
2356 WHERE keyentryid = ? AND tag = ? AND data > 0;",
2357 params![key_id, Tag::USAGE_COUNT_LIMIT.0],
2358 )
2359 .context("Failed to update key usage count.")?;
2360
2361 match limit {
2362 1 => Self::mark_unreferenced(tx, key_id)
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002363 .map(|need_gc| (need_gc, ()))
Qi Wub9433b52020-12-01 14:52:46 +08002364 .context("Trying to mark limited use key for deletion."),
2365 0 => Err(KsError::Km(ErrorCode::INVALID_KEY_BLOB)).context("Key is exhausted."),
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002366 _ => Ok(()).no_gc(),
Qi Wub9433b52020-12-01 14:52:46 +08002367 }
2368 })
2369 .context("In check_and_update_key_usage_count.")
2370 }
2371
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002372 /// Load a key entry by the given key descriptor.
2373 /// It uses the `check_permission` callback to verify if the access is allowed
2374 /// given the key access tuple read from the database using `load_access_tuple`.
2375 /// With `load_bits` the caller may specify which blobs shall be loaded from
2376 /// the blob database.
2377 pub fn load_key_entry(
2378 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002379 key: &KeyDescriptor,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002380 key_type: KeyType,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002381 load_bits: KeyEntryLoadBits,
2382 caller_uid: u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002383 check_permission: impl Fn(&KeyDescriptor, Option<KeyPermSet>) -> Result<()>,
2384 ) -> Result<(KeyIdGuard, KeyEntry)> {
2385 loop {
2386 match self.load_key_entry_internal(
2387 key,
2388 key_type,
2389 load_bits,
2390 caller_uid,
2391 &check_permission,
2392 ) {
2393 Ok(result) => break Ok(result),
2394 Err(e) => {
2395 if Self::is_locked_error(&e) {
2396 std::thread::sleep(std::time::Duration::from_micros(500));
2397 continue;
2398 } else {
2399 return Err(e).context("In load_key_entry.");
2400 }
2401 }
2402 }
2403 }
2404 }
2405
2406 fn load_key_entry_internal(
2407 &mut self,
2408 key: &KeyDescriptor,
2409 key_type: KeyType,
2410 load_bits: KeyEntryLoadBits,
2411 caller_uid: u32,
2412 check_permission: &impl Fn(&KeyDescriptor, Option<KeyPermSet>) -> Result<()>,
Janis Danisevskisaec14592020-11-12 09:41:49 -08002413 ) -> Result<(KeyIdGuard, KeyEntry)> {
2414 // KEY ID LOCK 1/2
2415 // If we got a key descriptor with a key id we can get the lock right away.
2416 // Otherwise we have to defer it until we know the key id.
2417 let key_id_guard = match key.domain {
2418 Domain::KEY_ID => Some(KEY_ID_LOCK.get(key.nspace)),
2419 _ => None,
2420 };
2421
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002422 let tx = self
2423 .conn
Janis Danisevskisaec14592020-11-12 09:41:49 -08002424 .unchecked_transaction()
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002425 .context("In load_key_entry: Failed to initialize transaction.")?;
2426
2427 // Load the key_id and complete the access control tuple.
2428 let (key_id, access_key_descriptor, access_vector) =
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002429 Self::load_access_tuple(&tx, key, key_type, caller_uid)
2430 .context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002431
2432 // Perform access control. It is vital that we return here if the permission is denied.
2433 // So do not touch that '?' at the end.
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002434 check_permission(&access_key_descriptor, access_vector).context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002435
Janis Danisevskisaec14592020-11-12 09:41:49 -08002436 // KEY ID LOCK 2/2
2437 // If we did not get a key id lock by now, it was because we got a key descriptor
2438 // without a key id. At this point we got the key id, so we can try and get a lock.
2439 // However, we cannot block here, because we are in the middle of the transaction.
2440 // So first we try to get the lock non blocking. If that fails, we roll back the
2441 // transaction and block until we get the lock. After we successfully got the lock,
2442 // we start a new transaction and load the access tuple again.
2443 //
2444 // We don't need to perform access control again, because we already established
2445 // that the caller had access to the given key. But we need to make sure that the
2446 // key id still exists. So we have to load the key entry by key id this time.
2447 let (key_id_guard, tx) = match key_id_guard {
2448 None => match KEY_ID_LOCK.try_get(key_id) {
2449 None => {
2450 // Roll back the transaction.
2451 tx.rollback().context("In load_key_entry: Failed to roll back transaction.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002452
Janis Danisevskisaec14592020-11-12 09:41:49 -08002453 // Block until we have a key id lock.
2454 let key_id_guard = KEY_ID_LOCK.get(key_id);
2455
2456 // Create a new transaction.
Janis Danisevskis66784c42021-01-27 08:40:25 -08002457 let tx = self
2458 .conn
2459 .unchecked_transaction()
2460 .context("In load_key_entry: Failed to initialize transaction.")?;
Janis Danisevskisaec14592020-11-12 09:41:49 -08002461
2462 Self::load_access_tuple(
2463 &tx,
2464 // This time we have to load the key by the retrieved key id, because the
2465 // alias may have been rebound after we rolled back the transaction.
Janis Danisevskis66784c42021-01-27 08:40:25 -08002466 &KeyDescriptor {
Janis Danisevskisaec14592020-11-12 09:41:49 -08002467 domain: Domain::KEY_ID,
2468 nspace: key_id,
2469 ..Default::default()
2470 },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002471 key_type,
Janis Danisevskisaec14592020-11-12 09:41:49 -08002472 caller_uid,
2473 )
2474 .context("In load_key_entry. (deferred key lock)")?;
2475 (key_id_guard, tx)
2476 }
2477 Some(l) => (l, tx),
2478 },
2479 Some(key_id_guard) => (key_id_guard, tx),
2480 };
2481
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002482 let key_entry = Self::load_key_components(&tx, load_bits, key_id_guard.id())
2483 .context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002484
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002485 tx.commit().context("In load_key_entry: Failed to commit transaction.")?;
2486
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002487 Ok((key_id_guard, key_entry))
2488 }
2489
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002490 fn mark_unreferenced(tx: &Transaction, key_id: i64) -> Result<bool> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002491 let updated = tx
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002492 .execute("DELETE FROM persistent.keyentry WHERE id = ?;", params![key_id])
2493 .context("Trying to delete keyentry.")?;
2494 tx.execute("DELETE FROM persistent.keymetadata WHERE keyentryid = ?;", params![key_id])
2495 .context("Trying to delete keymetadata.")?;
2496 tx.execute("DELETE FROM persistent.keyparameter WHERE keyentryid = ?;", params![key_id])
2497 .context("Trying to delete keyparameters.")?;
2498 tx.execute("DELETE FROM persistent.grant WHERE keyentryid = ?;", params![key_id])
2499 .context("Trying to delete grants.")?;
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002500 Ok(updated != 0)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002501 }
2502
2503 /// Marks the given key as unreferenced and removes all of the grants to this key.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002504 /// Returns Ok(true) if a key was marked unreferenced as a hint for the garbage collector.
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002505 pub fn unbind_key(
2506 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002507 key: &KeyDescriptor,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002508 key_type: KeyType,
2509 caller_uid: u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002510 check_permission: impl Fn(&KeyDescriptor, Option<KeyPermSet>) -> Result<()>,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002511 ) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002512 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2513 let (key_id, access_key_descriptor, access_vector) =
2514 Self::load_access_tuple(tx, key, key_type, caller_uid)
2515 .context("Trying to get access tuple.")?;
2516
2517 // Perform access control. It is vital that we return here if the permission is denied.
2518 // So do not touch that '?' at the end.
2519 check_permission(&access_key_descriptor, access_vector)
2520 .context("While checking permission.")?;
2521
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002522 Self::mark_unreferenced(tx, key_id)
2523 .map(|need_gc| (need_gc, ()))
2524 .context("Trying to mark the key unreferenced.")
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002525 })
2526 .context("In unbind_key.")
2527 }
2528
Max Bires8e93d2b2021-01-14 13:17:59 -08002529 fn get_key_km_uuid(tx: &Transaction, key_id: i64) -> Result<Uuid> {
2530 tx.query_row(
2531 "SELECT km_uuid FROM persistent.keyentry WHERE id = ?",
2532 params![key_id],
2533 |row| row.get(0),
2534 )
2535 .context("In get_key_km_uuid.")
2536 }
2537
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002538 /// Delete all artifacts belonging to the namespace given by the domain-namespace tuple.
2539 /// This leaves all of the blob entries orphaned for subsequent garbage collection.
2540 pub fn unbind_keys_for_namespace(&mut self, domain: Domain, namespace: i64) -> Result<()> {
2541 if !(domain == Domain::APP || domain == Domain::SELINUX) {
2542 return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT))
2543 .context("In unbind_keys_for_namespace.");
2544 }
2545 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2546 tx.execute(
2547 "DELETE FROM persistent.keymetadata
2548 WHERE keyentryid IN (
2549 SELECT id FROM persistent.keyentry
2550 WHERE domain = ? AND namespace = ?
2551 );",
2552 params![domain.0, namespace],
2553 )
2554 .context("Trying to delete keymetadata.")?;
2555 tx.execute(
2556 "DELETE FROM persistent.keyparameter
2557 WHERE keyentryid IN (
2558 SELECT id FROM persistent.keyentry
2559 WHERE domain = ? AND namespace = ?
2560 );",
2561 params![domain.0, namespace],
2562 )
2563 .context("Trying to delete keyparameters.")?;
2564 tx.execute(
2565 "DELETE FROM persistent.grant
2566 WHERE keyentryid IN (
2567 SELECT id FROM persistent.keyentry
2568 WHERE domain = ? AND namespace = ?
2569 );",
2570 params![domain.0, namespace],
2571 )
2572 .context("Trying to delete grants.")?;
2573 tx.execute(
2574 "DELETE FROM persistent.keyentry WHERE domain = ? AND namespace = ?;",
2575 params![domain.0, namespace],
2576 )
2577 .context("Trying to delete keyentry.")?;
2578 Ok(()).need_gc()
2579 })
2580 .context("In unbind_keys_for_namespace")
2581 }
2582
Hasini Gunasingheda895552021-01-27 19:34:37 +00002583 /// Delete the keys created on behalf of the user, denoted by the user id.
2584 /// Delete all the keys unless 'keep_non_super_encrypted_keys' set to true.
2585 /// Returned boolean is to hint the garbage collector to delete the unbound keys.
2586 /// The caller of this function should notify the gc if the returned value is true.
2587 pub fn unbind_keys_for_user(
2588 &mut self,
2589 user_id: u32,
2590 keep_non_super_encrypted_keys: bool,
2591 ) -> Result<()> {
2592 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2593 let mut stmt = tx
2594 .prepare(&format!(
2595 "SELECT id from persistent.keyentry
2596 WHERE (
2597 key_type = ?
2598 AND domain = ?
2599 AND cast ( (namespace/{aid_user_offset}) as int) = ?
2600 AND state = ?
2601 ) OR (
2602 key_type = ?
2603 AND namespace = ?
2604 AND alias = ?
2605 AND state = ?
2606 );",
2607 aid_user_offset = AID_USER_OFFSET
2608 ))
2609 .context(concat!(
2610 "In unbind_keys_for_user. ",
2611 "Failed to prepare the query to find the keys created by apps."
2612 ))?;
2613
2614 let mut rows = stmt
2615 .query(params![
2616 // WHERE client key:
2617 KeyType::Client,
2618 Domain::APP.0 as u32,
2619 user_id,
2620 KeyLifeCycle::Live,
2621 // OR super key:
2622 KeyType::Super,
2623 user_id,
2624 Self::USER_SUPER_KEY_ALIAS,
2625 KeyLifeCycle::Live
2626 ])
2627 .context("In unbind_keys_for_user. Failed to query the keys created by apps.")?;
2628
2629 let mut key_ids: Vec<i64> = Vec::new();
2630 db_utils::with_rows_extract_all(&mut rows, |row| {
2631 key_ids
2632 .push(row.get(0).context("Failed to read key id of a key created by an app.")?);
2633 Ok(())
2634 })
2635 .context("In unbind_keys_for_user.")?;
2636
2637 let mut notify_gc = false;
2638 for key_id in key_ids {
2639 if keep_non_super_encrypted_keys {
2640 // Load metadata and filter out non-super-encrypted keys.
2641 if let (_, Some((_, blob_metadata)), _, _) =
2642 Self::load_blob_components(key_id, KeyEntryLoadBits::KM, tx)
2643 .context("In unbind_keys_for_user: Trying to load blob info.")?
2644 {
2645 if blob_metadata.encrypted_by().is_none() {
2646 continue;
2647 }
2648 }
2649 }
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +00002650 notify_gc = Self::mark_unreferenced(&tx, key_id)
Hasini Gunasingheda895552021-01-27 19:34:37 +00002651 .context("In unbind_keys_for_user.")?
2652 || notify_gc;
2653 }
2654 Ok(()).do_gc(notify_gc)
2655 })
2656 .context("In unbind_keys_for_user.")
2657 }
2658
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002659 fn load_key_components(
2660 tx: &Transaction,
2661 load_bits: KeyEntryLoadBits,
2662 key_id: i64,
2663 ) -> Result<KeyEntry> {
2664 let metadata = KeyMetaData::load_from_db(key_id, &tx).context("In load_key_components.")?;
2665
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002666 let (has_km_blob, key_blob_info, cert_blob, cert_chain_blob) =
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002667 Self::load_blob_components(key_id, load_bits, &tx)
2668 .context("In load_key_components.")?;
2669
Max Bires8e93d2b2021-01-14 13:17:59 -08002670 let parameters = Self::load_key_parameters(key_id, &tx)
2671 .context("In load_key_components: Trying to load key parameters.")?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002672
Max Bires8e93d2b2021-01-14 13:17:59 -08002673 let km_uuid = Self::get_key_km_uuid(&tx, key_id)
2674 .context("In load_key_components: Trying to get KM uuid.")?;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002675
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002676 Ok(KeyEntry {
2677 id: key_id,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002678 key_blob_info,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002679 cert: cert_blob,
2680 cert_chain: cert_chain_blob,
Max Bires8e93d2b2021-01-14 13:17:59 -08002681 km_uuid,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002682 parameters,
2683 metadata,
Janis Danisevskis377d1002021-01-27 19:07:48 -08002684 pure_cert: !has_km_blob,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002685 })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002686 }
2687
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002688 /// Returns a list of KeyDescriptors in the selected domain/namespace.
2689 /// The key descriptors will have the domain, nspace, and alias field set.
2690 /// Domain must be APP or SELINUX, the caller must make sure of that.
2691 pub fn list(&mut self, domain: Domain, namespace: i64) -> Result<Vec<KeyDescriptor>> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002692 self.with_transaction(TransactionBehavior::Deferred, |tx| {
2693 let mut stmt = tx
2694 .prepare(
2695 "SELECT alias FROM persistent.keyentry
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002696 WHERE domain = ? AND namespace = ? AND alias IS NOT NULL AND state = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08002697 )
2698 .context("In list: Failed to prepare.")?;
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002699
Janis Danisevskis66784c42021-01-27 08:40:25 -08002700 let mut rows = stmt
2701 .query(params![domain.0 as u32, namespace, KeyLifeCycle::Live])
2702 .context("In list: Failed to query.")?;
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002703
Janis Danisevskis66784c42021-01-27 08:40:25 -08002704 let mut descriptors: Vec<KeyDescriptor> = Vec::new();
2705 db_utils::with_rows_extract_all(&mut rows, |row| {
2706 descriptors.push(KeyDescriptor {
2707 domain,
2708 nspace: namespace,
2709 alias: Some(row.get(0).context("Trying to extract alias.")?),
2710 blob: None,
2711 });
2712 Ok(())
2713 })
2714 .context("In list: Failed to extract rows.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002715 Ok(descriptors).no_gc()
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002716 })
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002717 }
2718
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002719 /// Adds a grant to the grant table.
2720 /// Like `load_key_entry` this function loads the access tuple before
2721 /// it uses the callback for a permission check. Upon success,
2722 /// it inserts the `grantee_uid`, `key_id`, and `access_vector` into the
2723 /// grant table. The new row will have a randomized id, which is used as
2724 /// grant id in the namespace field of the resulting KeyDescriptor.
2725 pub fn grant(
2726 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002727 key: &KeyDescriptor,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002728 caller_uid: u32,
2729 grantee_uid: u32,
2730 access_vector: KeyPermSet,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002731 check_permission: impl Fn(&KeyDescriptor, &KeyPermSet) -> Result<()>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002732 ) -> Result<KeyDescriptor> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002733 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2734 // Load the key_id and complete the access control tuple.
2735 // We ignore the access vector here because grants cannot be granted.
2736 // The access vector returned here expresses the permissions the
2737 // grantee has if key.domain == Domain::GRANT. But this vector
2738 // cannot include the grant permission by design, so there is no way the
2739 // subsequent permission check can pass.
2740 // We could check key.domain == Domain::GRANT and fail early.
2741 // But even if we load the access tuple by grant here, the permission
2742 // check denies the attempt to create a grant by grant descriptor.
2743 let (key_id, access_key_descriptor, _) =
2744 Self::load_access_tuple(&tx, key, KeyType::Client, caller_uid)
2745 .context("In grant")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002746
Janis Danisevskis66784c42021-01-27 08:40:25 -08002747 // Perform access control. It is vital that we return here if the permission
2748 // was denied. So do not touch that '?' at the end of the line.
2749 // This permission check checks if the caller has the grant permission
2750 // for the given key and in addition to all of the permissions
2751 // expressed in `access_vector`.
2752 check_permission(&access_key_descriptor, &access_vector)
2753 .context("In grant: check_permission failed.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002754
Janis Danisevskis66784c42021-01-27 08:40:25 -08002755 let grant_id = if let Some(grant_id) = tx
2756 .query_row(
2757 "SELECT id FROM persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002758 WHERE keyentryid = ? AND grantee = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08002759 params![key_id, grantee_uid],
2760 |row| row.get(0),
2761 )
2762 .optional()
2763 .context("In grant: Failed get optional existing grant id.")?
2764 {
2765 tx.execute(
2766 "UPDATE persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002767 SET access_vector = ?
2768 WHERE id = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08002769 params![i32::from(access_vector), grant_id],
Joel Galenson845f74b2020-09-09 14:11:55 -07002770 )
Janis Danisevskis66784c42021-01-27 08:40:25 -08002771 .context("In grant: Failed to update existing grant.")?;
2772 grant_id
2773 } else {
2774 Self::insert_with_retry(|id| {
2775 tx.execute(
2776 "INSERT INTO persistent.grant (id, grantee, keyentryid, access_vector)
2777 VALUES (?, ?, ?, ?);",
2778 params![id, grantee_uid, key_id, i32::from(access_vector)],
2779 )
2780 })
2781 .context("In grant")?
2782 };
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002783
Janis Danisevskis66784c42021-01-27 08:40:25 -08002784 Ok(KeyDescriptor { domain: Domain::GRANT, nspace: grant_id, alias: None, blob: None })
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002785 .no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08002786 })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002787 }
2788
2789 /// This function checks permissions like `grant` and `load_key_entry`
2790 /// before removing a grant from the grant table.
2791 pub fn ungrant(
2792 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002793 key: &KeyDescriptor,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002794 caller_uid: u32,
2795 grantee_uid: u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002796 check_permission: impl Fn(&KeyDescriptor) -> Result<()>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002797 ) -> Result<()> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002798 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2799 // Load the key_id and complete the access control tuple.
2800 // We ignore the access vector here because grants cannot be granted.
2801 let (key_id, access_key_descriptor, _) =
2802 Self::load_access_tuple(&tx, key, KeyType::Client, caller_uid)
2803 .context("In ungrant.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002804
Janis Danisevskis66784c42021-01-27 08:40:25 -08002805 // Perform access control. We must return here if the permission
2806 // was denied. So do not touch the '?' at the end of this line.
2807 check_permission(&access_key_descriptor)
2808 .context("In grant: check_permission failed.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002809
Janis Danisevskis66784c42021-01-27 08:40:25 -08002810 tx.execute(
2811 "DELETE FROM persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002812 WHERE keyentryid = ? AND grantee = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08002813 params![key_id, grantee_uid],
2814 )
2815 .context("Failed to delete grant.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002816
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002817 Ok(()).no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08002818 })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002819 }
2820
Joel Galenson845f74b2020-09-09 14:11:55 -07002821 // Generates a random id and passes it to the given function, which will
2822 // try to insert it into a database. If that insertion fails, retry;
2823 // otherwise return the id.
2824 fn insert_with_retry(inserter: impl Fn(i64) -> rusqlite::Result<usize>) -> Result<i64> {
2825 loop {
Janis Danisevskiseed69842021-02-18 20:04:10 -08002826 let newid: i64 = match random() {
2827 Self::UNASSIGNED_KEY_ID => continue, // UNASSIGNED_KEY_ID cannot be assigned.
2828 i => i,
2829 };
Joel Galenson845f74b2020-09-09 14:11:55 -07002830 match inserter(newid) {
2831 // If the id already existed, try again.
2832 Err(rusqlite::Error::SqliteFailure(
2833 libsqlite3_sys::Error {
2834 code: libsqlite3_sys::ErrorCode::ConstraintViolation,
2835 extended_code: libsqlite3_sys::SQLITE_CONSTRAINT_UNIQUE,
2836 },
2837 _,
2838 )) => (),
2839 Err(e) => {
2840 return Err(e).context("In insert_with_retry: failed to insert into database.")
2841 }
2842 _ => return Ok(newid),
2843 }
2844 }
2845 }
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002846
2847 /// Insert or replace the auth token based on the UNIQUE constraint of the auth token table
2848 pub fn insert_auth_token(&mut self, auth_token: &HardwareAuthToken) -> Result<()> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002849 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2850 tx.execute(
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002851 "INSERT OR REPLACE INTO perboot.authtoken (challenge, user_id, auth_id,
2852 authenticator_type, timestamp, mac, time_received) VALUES(?, ?, ?, ?, ?, ?, ?);",
2853 params![
2854 auth_token.challenge,
2855 auth_token.userId,
2856 auth_token.authenticatorId,
2857 auth_token.authenticatorType.0 as i32,
2858 auth_token.timestamp.milliSeconds as i64,
2859 auth_token.mac,
2860 MonotonicRawTime::now(),
2861 ],
2862 )
2863 .context("In insert_auth_token: failed to insert auth token into the database")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002864 Ok(()).no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08002865 })
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002866 }
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002867
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002868 /// Find the newest auth token matching the given predicate.
2869 pub fn find_auth_token_entry<F>(
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002870 &mut self,
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002871 p: F,
2872 ) -> Result<Option<(AuthTokenEntry, MonotonicRawTime)>>
2873 where
2874 F: Fn(&AuthTokenEntry) -> bool,
2875 {
2876 self.with_transaction(TransactionBehavior::Deferred, |tx| {
2877 let mut stmt = tx
2878 .prepare("SELECT * from perboot.authtoken ORDER BY time_received DESC;")
2879 .context("Prepare statement failed.")?;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002880
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002881 let mut rows = stmt.query(NO_PARAMS).context("Failed to query.")?;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002882
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002883 while let Some(row) = rows.next().context("Failed to get next row.")? {
2884 let entry = AuthTokenEntry::new(
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002885 HardwareAuthToken {
2886 challenge: row.get(1)?,
2887 userId: row.get(2)?,
2888 authenticatorId: row.get(3)?,
2889 authenticatorType: HardwareAuthenticatorType(row.get(4)?),
2890 timestamp: Timestamp { milliSeconds: row.get(5)? },
2891 mac: row.get(6)?,
2892 },
2893 row.get(7)?,
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002894 );
2895 if p(&entry) {
2896 return Ok(Some((
2897 entry,
2898 Self::get_last_off_body(tx)
2899 .context("In find_auth_token_entry: Trying to get last off body")?,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002900 )))
2901 .no_gc();
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002902 }
2903 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002904 Ok(None).no_gc()
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002905 })
2906 .context("In find_auth_token_entry.")
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002907 }
2908
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002909 /// Insert last_off_body into the metadata table at the initialization of auth token table
Janis Danisevskis66784c42021-01-27 08:40:25 -08002910 pub fn insert_last_off_body(&mut self, last_off_body: MonotonicRawTime) -> Result<()> {
2911 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2912 tx.execute(
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002913 "INSERT OR REPLACE INTO perboot.metadata (key, value) VALUES (?, ?);",
2914 params!["last_off_body", last_off_body],
2915 )
2916 .context("In insert_last_off_body: failed to insert.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002917 Ok(()).no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08002918 })
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002919 }
2920
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002921 /// Update last_off_body when on_device_off_body is called
Janis Danisevskis66784c42021-01-27 08:40:25 -08002922 pub fn update_last_off_body(&mut self, last_off_body: MonotonicRawTime) -> Result<()> {
2923 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2924 tx.execute(
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002925 "UPDATE perboot.metadata SET value = ? WHERE key = ?;",
2926 params![last_off_body, "last_off_body"],
2927 )
2928 .context("In update_last_off_body: failed to update.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002929 Ok(()).no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08002930 })
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002931 }
2932
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002933 /// Get last_off_body time when finding auth tokens
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002934 fn get_last_off_body(tx: &Transaction) -> Result<MonotonicRawTime> {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002935 tx.query_row(
2936 "SELECT value from perboot.metadata WHERE key = ?;",
2937 params!["last_off_body"],
2938 |row| Ok(row.get(0)?),
2939 )
2940 .context("In get_last_off_body: query_row failed.")
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002941 }
Joel Galenson26f4d012020-07-17 14:57:21 -07002942}
2943
2944#[cfg(test)]
2945mod tests {
2946
2947 use super::*;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002948 use crate::key_parameter::{
2949 Algorithm, BlockMode, Digest, EcCurve, HardwareAuthenticatorType, KeyOrigin, KeyParameter,
2950 KeyParameterValue, KeyPurpose, PaddingMode, SecurityLevel,
2951 };
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002952 use crate::key_perm_set;
2953 use crate::permission::{KeyPerm, KeyPermSet};
Hasini Gunasingheda895552021-01-27 19:34:37 +00002954 use crate::super_key::SuperKeyManager;
Janis Danisevskis2a8330a2021-01-20 15:34:26 -08002955 use keystore2_test_utils::TempDir;
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002956 use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
2957 HardwareAuthToken::HardwareAuthToken,
2958 HardwareAuthenticatorType::HardwareAuthenticatorType as kmhw_authenticator_type,
Janis Danisevskisc3a496b2021-01-05 10:37:22 -08002959 };
2960 use android_hardware_security_secureclock::aidl::android::hardware::security::secureclock::{
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002961 Timestamp::Timestamp,
2962 };
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002963 use rusqlite::NO_PARAMS;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002964 use rusqlite::{Error, TransactionBehavior};
Joel Galenson0891bc12020-07-20 10:37:03 -07002965 use std::cell::RefCell;
Janis Danisevskisaec14592020-11-12 09:41:49 -08002966 use std::sync::atomic::{AtomicU8, Ordering};
2967 use std::sync::Arc;
2968 use std::thread;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002969 use std::time::{Duration, SystemTime};
Janis Danisevskis66784c42021-01-27 08:40:25 -08002970 #[cfg(disabled)]
2971 use std::time::Instant;
Joel Galenson0891bc12020-07-20 10:37:03 -07002972
Janis Danisevskis4df44f42020-08-26 14:40:03 -07002973 fn new_test_db() -> Result<KeystoreDB> {
2974 let conn = KeystoreDB::make_connection("file::memory:", "file::memory:")?;
2975
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002976 let mut db = KeystoreDB { conn, gc: None };
Janis Danisevskis66784c42021-01-27 08:40:25 -08002977 db.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002978 KeystoreDB::init_tables(tx).context("Failed to initialize tables.").no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08002979 })?;
2980 Ok(db)
Janis Danisevskis4df44f42020-08-26 14:40:03 -07002981 }
2982
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002983 fn new_test_db_with_gc<F>(path: &Path, cb: F) -> Result<KeystoreDB>
2984 where
2985 F: Fn(&Uuid, &[u8]) -> Result<()> + Send + 'static,
2986 {
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00002987 let super_key = Arc::new(SuperKeyManager::new());
2988
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002989 let gc_db = KeystoreDB::new(path, None).expect("Failed to open test gc db_connection.");
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00002990 let gc = Gc::new_init_with(Default::default(), move || (Box::new(cb), gc_db, super_key));
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002991
2992 KeystoreDB::new(path, Some(gc))
2993 }
2994
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002995 fn rebind_alias(
2996 db: &mut KeystoreDB,
2997 newid: &KeyIdGuard,
2998 alias: &str,
2999 domain: Domain,
3000 namespace: i64,
3001 ) -> Result<bool> {
3002 db.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003003 KeystoreDB::rebind_alias(tx, newid, alias, &domain, &namespace).no_gc()
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003004 })
3005 .context("In rebind_alias.")
3006 }
3007
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003008 #[test]
3009 fn datetime() -> Result<()> {
3010 let conn = Connection::open_in_memory()?;
3011 conn.execute("CREATE TABLE test (ts DATETIME);", NO_PARAMS)?;
3012 let now = SystemTime::now();
3013 let duration = Duration::from_secs(1000);
3014 let then = now.checked_sub(duration).unwrap();
3015 let soon = now.checked_add(duration).unwrap();
3016 conn.execute(
3017 "INSERT INTO test (ts) VALUES (?), (?), (?);",
3018 params![DateTime::try_from(now)?, DateTime::try_from(then)?, DateTime::try_from(soon)?],
3019 )?;
3020 let mut stmt = conn.prepare("SELECT ts FROM test ORDER BY ts ASC;")?;
3021 let mut rows = stmt.query(NO_PARAMS)?;
3022 assert_eq!(DateTime::try_from(then)?, rows.next()?.unwrap().get(0)?);
3023 assert_eq!(DateTime::try_from(now)?, rows.next()?.unwrap().get(0)?);
3024 assert_eq!(DateTime::try_from(soon)?, rows.next()?.unwrap().get(0)?);
3025 assert!(rows.next()?.is_none());
3026 assert!(DateTime::try_from(then)? < DateTime::try_from(now)?);
3027 assert!(DateTime::try_from(then)? < DateTime::try_from(soon)?);
3028 assert!(DateTime::try_from(now)? < DateTime::try_from(soon)?);
3029 Ok(())
3030 }
3031
Joel Galenson0891bc12020-07-20 10:37:03 -07003032 // Ensure that we're using the "injected" random function, not the real one.
3033 #[test]
3034 fn test_mocked_random() {
3035 let rand1 = random();
3036 let rand2 = random();
3037 let rand3 = random();
3038 if rand1 == rand2 {
3039 assert_eq!(rand2 + 1, rand3);
3040 } else {
3041 assert_eq!(rand1 + 1, rand2);
3042 assert_eq!(rand2, rand3);
3043 }
3044 }
Joel Galenson26f4d012020-07-17 14:57:21 -07003045
Joel Galenson26f4d012020-07-17 14:57:21 -07003046 // Test that we have the correct tables.
3047 #[test]
3048 fn test_tables() -> Result<()> {
Janis Danisevskis4df44f42020-08-26 14:40:03 -07003049 let db = new_test_db()?;
Joel Galenson26f4d012020-07-17 14:57:21 -07003050 let tables = db
3051 .conn
Joel Galenson2aab4432020-07-22 15:27:57 -07003052 .prepare("SELECT name from persistent.sqlite_master WHERE type='table' ORDER BY name;")?
Joel Galenson26f4d012020-07-17 14:57:21 -07003053 .query_map(params![], |row| row.get(0))?
3054 .collect::<rusqlite::Result<Vec<String>>>()?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003055 assert_eq!(tables.len(), 6);
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003056 assert_eq!(tables[0], "blobentry");
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003057 assert_eq!(tables[1], "blobmetadata");
3058 assert_eq!(tables[2], "grant");
3059 assert_eq!(tables[3], "keyentry");
3060 assert_eq!(tables[4], "keymetadata");
3061 assert_eq!(tables[5], "keyparameter");
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003062 let tables = db
3063 .conn
3064 .prepare("SELECT name from perboot.sqlite_master WHERE type='table' ORDER BY name;")?
3065 .query_map(params![], |row| row.get(0))?
3066 .collect::<rusqlite::Result<Vec<String>>>()?;
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00003067
3068 assert_eq!(tables.len(), 2);
3069 assert_eq!(tables[0], "authtoken");
3070 assert_eq!(tables[1], "metadata");
Joel Galenson2aab4432020-07-22 15:27:57 -07003071 Ok(())
3072 }
3073
3074 #[test]
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00003075 fn test_auth_token_table_invariant() -> Result<()> {
3076 let mut db = new_test_db()?;
3077 let auth_token1 = HardwareAuthToken {
3078 challenge: i64::MAX,
3079 userId: 200,
3080 authenticatorId: 200,
3081 authenticatorType: kmhw_authenticator_type(kmhw_authenticator_type::PASSWORD.0),
3082 timestamp: Timestamp { milliSeconds: 500 },
3083 mac: String::from("mac").into_bytes(),
3084 };
3085 db.insert_auth_token(&auth_token1)?;
3086 let auth_tokens_returned = get_auth_tokens(&mut db)?;
3087 assert_eq!(auth_tokens_returned.len(), 1);
3088
3089 // insert another auth token with the same values for the columns in the UNIQUE constraint
3090 // of the auth token table and different value for timestamp
3091 let auth_token2 = HardwareAuthToken {
3092 challenge: i64::MAX,
3093 userId: 200,
3094 authenticatorId: 200,
3095 authenticatorType: kmhw_authenticator_type(kmhw_authenticator_type::PASSWORD.0),
3096 timestamp: Timestamp { milliSeconds: 600 },
3097 mac: String::from("mac").into_bytes(),
3098 };
3099
3100 db.insert_auth_token(&auth_token2)?;
3101 let mut auth_tokens_returned = get_auth_tokens(&mut db)?;
3102 assert_eq!(auth_tokens_returned.len(), 1);
3103
3104 if let Some(auth_token) = auth_tokens_returned.pop() {
3105 assert_eq!(auth_token.auth_token.timestamp.milliSeconds, 600);
3106 }
3107
3108 // insert another auth token with the different values for the columns in the UNIQUE
3109 // constraint of the auth token table
3110 let auth_token3 = HardwareAuthToken {
3111 challenge: i64::MAX,
3112 userId: 201,
3113 authenticatorId: 200,
3114 authenticatorType: kmhw_authenticator_type(kmhw_authenticator_type::PASSWORD.0),
3115 timestamp: Timestamp { milliSeconds: 600 },
3116 mac: String::from("mac").into_bytes(),
3117 };
3118
3119 db.insert_auth_token(&auth_token3)?;
3120 let auth_tokens_returned = get_auth_tokens(&mut db)?;
3121 assert_eq!(auth_tokens_returned.len(), 2);
3122
3123 Ok(())
3124 }
3125
3126 // utility function for test_auth_token_table_invariant()
3127 fn get_auth_tokens(db: &mut KeystoreDB) -> Result<Vec<AuthTokenEntry>> {
3128 let mut stmt = db.conn.prepare("SELECT * from perboot.authtoken;")?;
3129
3130 let auth_token_entries: Vec<AuthTokenEntry> = stmt
3131 .query_map(NO_PARAMS, |row| {
3132 Ok(AuthTokenEntry::new(
3133 HardwareAuthToken {
3134 challenge: row.get(1)?,
3135 userId: row.get(2)?,
3136 authenticatorId: row.get(3)?,
3137 authenticatorType: HardwareAuthenticatorType(row.get(4)?),
3138 timestamp: Timestamp { milliSeconds: row.get(5)? },
3139 mac: row.get(6)?,
3140 },
3141 row.get(7)?,
3142 ))
3143 })?
3144 .collect::<Result<Vec<AuthTokenEntry>, Error>>()?;
3145 Ok(auth_token_entries)
3146 }
3147
3148 #[test]
Joel Galenson2aab4432020-07-22 15:27:57 -07003149 fn test_persistence_for_files() -> Result<()> {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08003150 let temp_dir = TempDir::new("persistent_db_test")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003151 let mut db = KeystoreDB::new(temp_dir.path(), None)?;
Joel Galenson2aab4432020-07-22 15:27:57 -07003152
Janis Danisevskis66784c42021-01-27 08:40:25 -08003153 db.create_key_entry(&Domain::APP, &100, &KEYSTORE_UUID)?;
Joel Galenson2aab4432020-07-22 15:27:57 -07003154 let entries = get_keyentry(&db)?;
3155 assert_eq!(entries.len(), 1);
Janis Danisevskisbf15d732020-12-08 10:35:26 -08003156
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003157 let db = KeystoreDB::new(temp_dir.path(), None)?;
Joel Galenson2aab4432020-07-22 15:27:57 -07003158
3159 let entries_new = get_keyentry(&db)?;
3160 assert_eq!(entries, entries_new);
3161 Ok(())
3162 }
3163
3164 #[test]
Joel Galenson0891bc12020-07-20 10:37:03 -07003165 fn test_create_key_entry() -> Result<()> {
Max Bires8e93d2b2021-01-14 13:17:59 -08003166 fn extractor(ke: &KeyEntryRow) -> (Domain, i64, Option<&str>, Uuid) {
3167 (ke.domain.unwrap(), ke.namespace.unwrap(), ke.alias.as_deref(), ke.km_uuid.unwrap())
Joel Galenson0891bc12020-07-20 10:37:03 -07003168 }
3169
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003170 let mut db = new_test_db()?;
Joel Galenson0891bc12020-07-20 10:37:03 -07003171
Janis Danisevskis66784c42021-01-27 08:40:25 -08003172 db.create_key_entry(&Domain::APP, &100, &KEYSTORE_UUID)?;
3173 db.create_key_entry(&Domain::SELINUX, &101, &KEYSTORE_UUID)?;
Joel Galenson0891bc12020-07-20 10:37:03 -07003174
3175 let entries = get_keyentry(&db)?;
3176 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08003177 assert_eq!(extractor(&entries[0]), (Domain::APP, 100, None, KEYSTORE_UUID));
3178 assert_eq!(extractor(&entries[1]), (Domain::SELINUX, 101, None, KEYSTORE_UUID));
Joel Galenson0891bc12020-07-20 10:37:03 -07003179
3180 // Test that we must pass in a valid Domain.
3181 check_result_is_error_containing_string(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003182 db.create_key_entry(&Domain::GRANT, &102, &KEYSTORE_UUID),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003183 "Domain Domain(1) must be either App or SELinux.",
Joel Galenson0891bc12020-07-20 10:37:03 -07003184 );
3185 check_result_is_error_containing_string(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003186 db.create_key_entry(&Domain::BLOB, &103, &KEYSTORE_UUID),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003187 "Domain Domain(3) must be either App or SELinux.",
Joel Galenson0891bc12020-07-20 10:37:03 -07003188 );
3189 check_result_is_error_containing_string(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003190 db.create_key_entry(&Domain::KEY_ID, &104, &KEYSTORE_UUID),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003191 "Domain Domain(4) must be either App or SELinux.",
Joel Galenson0891bc12020-07-20 10:37:03 -07003192 );
3193
3194 Ok(())
3195 }
3196
Joel Galenson33c04ad2020-08-03 11:04:38 -07003197 #[test]
Max Bires2b2e6562020-09-22 11:22:36 -07003198 fn test_add_unsigned_key() -> Result<()> {
3199 let mut db = new_test_db()?;
3200 let public_key: Vec<u8> = vec![0x01, 0x02, 0x03];
3201 let private_key: Vec<u8> = vec![0x04, 0x05, 0x06];
3202 let raw_public_key: Vec<u8> = vec![0x07, 0x08, 0x09];
3203 db.create_attestation_key_entry(
3204 &public_key,
3205 &raw_public_key,
3206 &private_key,
3207 &KEYSTORE_UUID,
3208 )?;
3209 let keys = db.fetch_unsigned_attestation_keys(5, &KEYSTORE_UUID)?;
3210 assert_eq!(keys.len(), 1);
3211 assert_eq!(keys[0], public_key);
3212 Ok(())
3213 }
3214
3215 #[test]
3216 fn test_store_signed_attestation_certificate_chain() -> Result<()> {
3217 let mut db = new_test_db()?;
3218 let expiration_date: i64 = 20;
3219 let namespace: i64 = 30;
3220 let base_byte: u8 = 1;
3221 let loaded_values =
3222 load_attestation_key_pool(&mut db, expiration_date, namespace, base_byte)?;
3223 let chain =
3224 db.retrieve_attestation_key_and_cert_chain(Domain::APP, namespace, &KEYSTORE_UUID)?;
3225 assert_eq!(true, chain.is_some());
3226 let cert_chain = chain.unwrap();
Max Biresb2e1d032021-02-08 21:35:05 -08003227 assert_eq!(cert_chain.private_key.to_vec(), loaded_values.priv_key);
Max Bires97f96812021-02-23 23:44:57 -08003228 assert_eq!(cert_chain.batch_cert, loaded_values.batch_cert);
3229 assert_eq!(cert_chain.cert_chain, loaded_values.cert_chain);
Max Bires2b2e6562020-09-22 11:22:36 -07003230 Ok(())
3231 }
3232
3233 #[test]
3234 fn test_get_attestation_pool_status() -> Result<()> {
3235 let mut db = new_test_db()?;
3236 let namespace: i64 = 30;
3237 load_attestation_key_pool(
3238 &mut db, 10, /* expiration */
3239 namespace, 0x01, /* base_byte */
3240 )?;
3241 load_attestation_key_pool(&mut db, 20 /* expiration */, namespace + 1, 0x02)?;
3242 load_attestation_key_pool(&mut db, 40 /* expiration */, namespace + 2, 0x03)?;
3243 let mut status = db.get_attestation_pool_status(9 /* expiration */, &KEYSTORE_UUID)?;
3244 assert_eq!(status.expiring, 0);
3245 assert_eq!(status.attested, 3);
3246 assert_eq!(status.unassigned, 0);
3247 assert_eq!(status.total, 3);
3248 assert_eq!(
3249 db.get_attestation_pool_status(15 /* expiration */, &KEYSTORE_UUID)?.expiring,
3250 1
3251 );
3252 assert_eq!(
3253 db.get_attestation_pool_status(25 /* expiration */, &KEYSTORE_UUID)?.expiring,
3254 2
3255 );
3256 assert_eq!(
3257 db.get_attestation_pool_status(60 /* expiration */, &KEYSTORE_UUID)?.expiring,
3258 3
3259 );
3260 let public_key: Vec<u8> = vec![0x01, 0x02, 0x03];
3261 let private_key: Vec<u8> = vec![0x04, 0x05, 0x06];
3262 let raw_public_key: Vec<u8> = vec![0x07, 0x08, 0x09];
3263 let cert_chain: Vec<u8> = vec![0x0a, 0x0b, 0x0c];
Max Biresb2e1d032021-02-08 21:35:05 -08003264 let batch_cert: Vec<u8> = vec![0x0d, 0x0e, 0x0f];
Max Bires2b2e6562020-09-22 11:22:36 -07003265 db.create_attestation_key_entry(
3266 &public_key,
3267 &raw_public_key,
3268 &private_key,
3269 &KEYSTORE_UUID,
3270 )?;
3271 status = db.get_attestation_pool_status(0 /* expiration */, &KEYSTORE_UUID)?;
3272 assert_eq!(status.attested, 3);
3273 assert_eq!(status.unassigned, 0);
3274 assert_eq!(status.total, 4);
3275 db.store_signed_attestation_certificate_chain(
3276 &raw_public_key,
Max Biresb2e1d032021-02-08 21:35:05 -08003277 &batch_cert,
Max Bires2b2e6562020-09-22 11:22:36 -07003278 &cert_chain,
3279 20,
3280 &KEYSTORE_UUID,
3281 )?;
3282 status = db.get_attestation_pool_status(0 /* expiration */, &KEYSTORE_UUID)?;
3283 assert_eq!(status.attested, 4);
3284 assert_eq!(status.unassigned, 1);
3285 assert_eq!(status.total, 4);
3286 Ok(())
3287 }
3288
3289 #[test]
3290 fn test_remove_expired_certs() -> Result<()> {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003291 let temp_dir =
3292 TempDir::new("test_remove_expired_certs_").expect("Failed to create temp dir.");
3293 let mut db = new_test_db_with_gc(temp_dir.path(), |_, _| Ok(()))?;
Max Bires2b2e6562020-09-22 11:22:36 -07003294 let expiration_date: i64 =
3295 SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_millis() as i64 + 10000;
3296 let namespace: i64 = 30;
3297 let namespace_del1: i64 = 45;
3298 let namespace_del2: i64 = 60;
3299 let entry_values = load_attestation_key_pool(
3300 &mut db,
3301 expiration_date,
3302 namespace,
3303 0x01, /* base_byte */
3304 )?;
3305 load_attestation_key_pool(&mut db, 45, namespace_del1, 0x02)?;
3306 load_attestation_key_pool(&mut db, 60, namespace_del2, 0x03)?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003307
3308 let blob_entry_row_count: u32 = db
3309 .conn
3310 .query_row("SELECT COUNT(id) FROM persistent.blobentry;", NO_PARAMS, |row| row.get(0))
3311 .expect("Failed to get blob entry row count.");
Max Biresb2e1d032021-02-08 21:35:05 -08003312 // We expect 9 rows here because there are three blobs per attestation key, i.e.,
3313 // one key, one certificate chain, and one certificate.
3314 assert_eq!(blob_entry_row_count, 9);
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003315
Max Bires2b2e6562020-09-22 11:22:36 -07003316 assert_eq!(db.delete_expired_attestation_keys()?, 2);
3317
3318 let mut cert_chain =
3319 db.retrieve_attestation_key_and_cert_chain(Domain::APP, namespace, &KEYSTORE_UUID)?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003320 assert!(cert_chain.is_some());
Max Bires2b2e6562020-09-22 11:22:36 -07003321 let value = cert_chain.unwrap();
Max Bires97f96812021-02-23 23:44:57 -08003322 assert_eq!(entry_values.batch_cert, value.batch_cert);
3323 assert_eq!(entry_values.cert_chain, value.cert_chain);
Max Biresb2e1d032021-02-08 21:35:05 -08003324 assert_eq!(entry_values.priv_key, value.private_key.to_vec());
Max Bires2b2e6562020-09-22 11:22:36 -07003325
3326 cert_chain = db.retrieve_attestation_key_and_cert_chain(
3327 Domain::APP,
3328 namespace_del1,
3329 &KEYSTORE_UUID,
3330 )?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003331 assert!(!cert_chain.is_some());
Max Bires2b2e6562020-09-22 11:22:36 -07003332 cert_chain = db.retrieve_attestation_key_and_cert_chain(
3333 Domain::APP,
3334 namespace_del2,
3335 &KEYSTORE_UUID,
3336 )?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003337 assert!(!cert_chain.is_some());
Max Bires2b2e6562020-09-22 11:22:36 -07003338
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003339 // Give the garbage collector half a second to catch up.
3340 std::thread::sleep(Duration::from_millis(500));
Max Bires2b2e6562020-09-22 11:22:36 -07003341
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003342 let blob_entry_row_count: u32 = db
3343 .conn
3344 .query_row("SELECT COUNT(id) FROM persistent.blobentry;", NO_PARAMS, |row| row.get(0))
3345 .expect("Failed to get blob entry row count.");
Max Biresb2e1d032021-02-08 21:35:05 -08003346 // There shound be 3 blob entries left, because we deleted two of the attestation
3347 // key entries with three blobs each.
3348 assert_eq!(blob_entry_row_count, 3);
Max Bires2b2e6562020-09-22 11:22:36 -07003349
Max Bires2b2e6562020-09-22 11:22:36 -07003350 Ok(())
3351 }
3352
3353 #[test]
Joel Galenson33c04ad2020-08-03 11:04:38 -07003354 fn test_rebind_alias() -> Result<()> {
Max Bires8e93d2b2021-01-14 13:17:59 -08003355 fn extractor(
3356 ke: &KeyEntryRow,
3357 ) -> (Option<Domain>, Option<i64>, Option<&str>, Option<Uuid>) {
3358 (ke.domain, ke.namespace, ke.alias.as_deref(), ke.km_uuid)
Joel Galenson33c04ad2020-08-03 11:04:38 -07003359 }
3360
Janis Danisevskis4df44f42020-08-26 14:40:03 -07003361 let mut db = new_test_db()?;
Janis Danisevskis66784c42021-01-27 08:40:25 -08003362 db.create_key_entry(&Domain::APP, &42, &KEYSTORE_UUID)?;
3363 db.create_key_entry(&Domain::APP, &42, &KEYSTORE_UUID)?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07003364 let entries = get_keyentry(&db)?;
3365 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08003366 assert_eq!(
3367 extractor(&entries[0]),
3368 (Some(Domain::APP), Some(42), None, Some(KEYSTORE_UUID))
3369 );
3370 assert_eq!(
3371 extractor(&entries[1]),
3372 (Some(Domain::APP), Some(42), None, Some(KEYSTORE_UUID))
3373 );
Joel Galenson33c04ad2020-08-03 11:04:38 -07003374
3375 // Test that the first call to rebind_alias sets the alias.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003376 rebind_alias(&mut db, &KEY_ID_LOCK.get(entries[0].id), "foo", Domain::APP, 42)?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07003377 let entries = get_keyentry(&db)?;
3378 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08003379 assert_eq!(
3380 extractor(&entries[0]),
3381 (Some(Domain::APP), Some(42), Some("foo"), Some(KEYSTORE_UUID))
3382 );
3383 assert_eq!(
3384 extractor(&entries[1]),
3385 (Some(Domain::APP), Some(42), None, Some(KEYSTORE_UUID))
3386 );
Joel Galenson33c04ad2020-08-03 11:04:38 -07003387
3388 // Test that the second call to rebind_alias also empties the old one.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003389 rebind_alias(&mut db, &KEY_ID_LOCK.get(entries[1].id), "foo", Domain::APP, 42)?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07003390 let entries = get_keyentry(&db)?;
3391 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08003392 assert_eq!(extractor(&entries[0]), (None, None, None, Some(KEYSTORE_UUID)));
3393 assert_eq!(
3394 extractor(&entries[1]),
3395 (Some(Domain::APP), Some(42), Some("foo"), Some(KEYSTORE_UUID))
3396 );
Joel Galenson33c04ad2020-08-03 11:04:38 -07003397
3398 // Test that we must pass in a valid Domain.
3399 check_result_is_error_containing_string(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003400 rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::GRANT, 42),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003401 "Domain Domain(1) must be either App or SELinux.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07003402 );
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::BLOB, 42),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003405 "Domain Domain(3) must be either App or SELinux.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07003406 );
3407 check_result_is_error_containing_string(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003408 rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::KEY_ID, 42),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003409 "Domain Domain(4) must be either App or SELinux.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07003410 );
3411
3412 // Test that we correctly handle setting an alias for something that does not exist.
3413 check_result_is_error_containing_string(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003414 rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::SELINUX, 42),
Joel Galenson33c04ad2020-08-03 11:04:38 -07003415 "Expected to update a single entry but instead updated 0",
3416 );
3417 // Test that we correctly abort the transaction in this case.
3418 let entries = get_keyentry(&db)?;
3419 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08003420 assert_eq!(extractor(&entries[0]), (None, None, None, Some(KEYSTORE_UUID)));
3421 assert_eq!(
3422 extractor(&entries[1]),
3423 (Some(Domain::APP), Some(42), Some("foo"), Some(KEYSTORE_UUID))
3424 );
Joel Galenson33c04ad2020-08-03 11:04:38 -07003425
3426 Ok(())
3427 }
3428
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003429 #[test]
3430 fn test_grant_ungrant() -> Result<()> {
3431 const CALLER_UID: u32 = 15;
3432 const GRANTEE_UID: u32 = 12;
3433 const SELINUX_NAMESPACE: i64 = 7;
3434
3435 let mut db = new_test_db()?;
3436 db.conn.execute(
Max Bires8e93d2b2021-01-14 13:17:59 -08003437 "INSERT INTO persistent.keyentry (id, key_type, domain, namespace, alias, state, km_uuid)
3438 VALUES (1, 0, 0, 15, 'key', 1, ?), (2, 0, 2, 7, 'yek', 1, ?);",
3439 params![KEYSTORE_UUID, KEYSTORE_UUID],
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003440 )?;
3441 let app_key = KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003442 domain: super::Domain::APP,
3443 nspace: 0,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003444 alias: Some("key".to_string()),
3445 blob: None,
3446 };
3447 const PVEC1: KeyPermSet = key_perm_set![KeyPerm::use_(), KeyPerm::get_info()];
3448 const PVEC2: KeyPermSet = key_perm_set![KeyPerm::use_()];
3449
3450 // Reset totally predictable random number generator in case we
3451 // are not the first test running on this thread.
3452 reset_random();
3453 let next_random = 0i64;
3454
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003455 let app_granted_key = db
Janis Danisevskis66784c42021-01-27 08:40:25 -08003456 .grant(&app_key, CALLER_UID, GRANTEE_UID, PVEC1, |k, a| {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003457 assert_eq!(*a, PVEC1);
3458 assert_eq!(
3459 *k,
3460 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003461 domain: super::Domain::APP,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003462 // namespace must be set to the caller_uid.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003463 nspace: CALLER_UID as i64,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003464 alias: Some("key".to_string()),
3465 blob: None,
3466 }
3467 );
3468 Ok(())
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003469 })
3470 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003471
3472 assert_eq!(
3473 app_granted_key,
3474 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003475 domain: super::Domain::GRANT,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003476 // The grantid is next_random due to the mock random number generator.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003477 nspace: next_random,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003478 alias: None,
3479 blob: None,
3480 }
3481 );
3482
3483 let selinux_key = KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003484 domain: super::Domain::SELINUX,
3485 nspace: SELINUX_NAMESPACE,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003486 alias: Some("yek".to_string()),
3487 blob: None,
3488 };
3489
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003490 let selinux_granted_key = db
Janis Danisevskis66784c42021-01-27 08:40:25 -08003491 .grant(&selinux_key, CALLER_UID, 12, PVEC1, |k, a| {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003492 assert_eq!(*a, PVEC1);
3493 assert_eq!(
3494 *k,
3495 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003496 domain: super::Domain::SELINUX,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003497 // namespace must be the supplied SELinux
3498 // namespace.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003499 nspace: SELINUX_NAMESPACE,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003500 alias: Some("yek".to_string()),
3501 blob: None,
3502 }
3503 );
3504 Ok(())
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003505 })
3506 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003507
3508 assert_eq!(
3509 selinux_granted_key,
3510 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003511 domain: super::Domain::GRANT,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003512 // The grantid is next_random + 1 due to the mock random number generator.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003513 nspace: next_random + 1,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003514 alias: None,
3515 blob: None,
3516 }
3517 );
3518
3519 // This should update the existing grant with PVEC2.
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003520 let selinux_granted_key = db
Janis Danisevskis66784c42021-01-27 08:40:25 -08003521 .grant(&selinux_key, CALLER_UID, 12, PVEC2, |k, a| {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003522 assert_eq!(*a, PVEC2);
3523 assert_eq!(
3524 *k,
3525 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003526 domain: super::Domain::SELINUX,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003527 // namespace must be the supplied SELinux
3528 // namespace.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003529 nspace: SELINUX_NAMESPACE,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003530 alias: Some("yek".to_string()),
3531 blob: None,
3532 }
3533 );
3534 Ok(())
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003535 })
3536 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003537
3538 assert_eq!(
3539 selinux_granted_key,
3540 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003541 domain: super::Domain::GRANT,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003542 // Same grant id as before. The entry was only updated.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003543 nspace: next_random + 1,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003544 alias: None,
3545 blob: None,
3546 }
3547 );
3548
3549 {
3550 // Limiting scope of stmt, because it borrows db.
3551 let mut stmt = db
3552 .conn
Janis Danisevskisbf15d732020-12-08 10:35:26 -08003553 .prepare("SELECT id, grantee, keyentryid, access_vector FROM persistent.grant;")?;
Janis Danisevskisee10b5f2020-09-22 16:42:35 -07003554 let mut rows =
3555 stmt.query_map::<(i64, u32, i64, KeyPermSet), _, _>(NO_PARAMS, |row| {
3556 Ok((
3557 row.get(0)?,
3558 row.get(1)?,
3559 row.get(2)?,
3560 KeyPermSet::from(row.get::<_, i32>(3)?),
3561 ))
3562 })?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003563
3564 let r = rows.next().unwrap().unwrap();
Janis Danisevskisee10b5f2020-09-22 16:42:35 -07003565 assert_eq!(r, (next_random, GRANTEE_UID, 1, PVEC1));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003566 let r = rows.next().unwrap().unwrap();
Janis Danisevskisee10b5f2020-09-22 16:42:35 -07003567 assert_eq!(r, (next_random + 1, GRANTEE_UID, 2, PVEC2));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003568 assert!(rows.next().is_none());
3569 }
3570
3571 debug_dump_keyentry_table(&mut db)?;
3572 println!("app_key {:?}", app_key);
3573 println!("selinux_key {:?}", selinux_key);
3574
Janis Danisevskis66784c42021-01-27 08:40:25 -08003575 db.ungrant(&app_key, CALLER_UID, GRANTEE_UID, |_| Ok(()))?;
3576 db.ungrant(&selinux_key, CALLER_UID, GRANTEE_UID, |_| Ok(()))?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003577
3578 Ok(())
3579 }
3580
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003581 static TEST_KEY_BLOB: &[u8] = b"my test blob";
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003582 static TEST_CERT_BLOB: &[u8] = b"my test cert";
3583 static TEST_CERT_CHAIN_BLOB: &[u8] = b"my test cert_chain";
3584
3585 #[test]
Janis Danisevskis377d1002021-01-27 19:07:48 -08003586 fn test_set_blob() -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003587 let key_id = KEY_ID_LOCK.get(3000);
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003588 let mut db = new_test_db()?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003589 let mut blob_metadata = BlobMetaData::new();
3590 blob_metadata.add(BlobMetaEntry::KmUuid(KEYSTORE_UUID));
3591 db.set_blob(
3592 &key_id,
3593 SubComponentType::KEY_BLOB,
3594 Some(TEST_KEY_BLOB),
3595 Some(&blob_metadata),
3596 )?;
3597 db.set_blob(&key_id, SubComponentType::CERT, Some(TEST_CERT_BLOB), None)?;
3598 db.set_blob(&key_id, SubComponentType::CERT_CHAIN, Some(TEST_CERT_CHAIN_BLOB), None)?;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003599 drop(key_id);
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003600
3601 let mut stmt = db.conn.prepare(
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003602 "SELECT subcomponent_type, keyentryid, blob, id FROM persistent.blobentry
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003603 ORDER BY subcomponent_type ASC;",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003604 )?;
3605 let mut rows = stmt
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003606 .query_map::<((SubComponentType, i64, Vec<u8>), i64), _, _>(NO_PARAMS, |row| {
3607 Ok(((row.get(0)?, row.get(1)?, row.get(2)?), row.get(3)?))
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003608 })?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003609 let (r, id) = rows.next().unwrap().unwrap();
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003610 assert_eq!(r, (SubComponentType::KEY_BLOB, 3000, TEST_KEY_BLOB.to_vec()));
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003611 let (r, _) = rows.next().unwrap().unwrap();
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003612 assert_eq!(r, (SubComponentType::CERT, 3000, TEST_CERT_BLOB.to_vec()));
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003613 let (r, _) = rows.next().unwrap().unwrap();
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003614 assert_eq!(r, (SubComponentType::CERT_CHAIN, 3000, TEST_CERT_CHAIN_BLOB.to_vec()));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003615
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003616 drop(rows);
3617 drop(stmt);
3618
3619 assert_eq!(
3620 db.with_transaction(TransactionBehavior::Immediate, |tx| {
3621 BlobMetaData::load_from_db(id, tx).no_gc()
3622 })
3623 .expect("Should find blob metadata."),
3624 blob_metadata
3625 );
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003626 Ok(())
3627 }
3628
3629 static TEST_ALIAS: &str = "my super duper key";
3630
3631 #[test]
3632 fn test_insert_and_load_full_keyentry_domain_app() -> Result<()> {
3633 let mut db = new_test_db()?;
Qi Wub9433b52020-12-01 14:52:46 +08003634 let key_id = make_test_key_entry(&mut db, Domain::APP, 1, TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08003635 .context("test_insert_and_load_full_keyentry_domain_app")?
3636 .0;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003637 let (_key_guard, key_entry) = db
3638 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003639 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003640 domain: Domain::APP,
3641 nspace: 0,
3642 alias: Some(TEST_ALIAS.to_string()),
3643 blob: None,
3644 },
3645 KeyType::Client,
3646 KeyEntryLoadBits::BOTH,
3647 1,
3648 |_k, _av| Ok(()),
3649 )
3650 .unwrap();
Qi Wub9433b52020-12-01 14:52:46 +08003651 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003652
3653 db.unbind_key(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003654 &KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003655 domain: Domain::APP,
3656 nspace: 0,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003657 alias: Some(TEST_ALIAS.to_string()),
3658 blob: None,
3659 },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003660 KeyType::Client,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003661 1,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003662 |_, _| Ok(()),
3663 )
3664 .unwrap();
3665
3666 assert_eq!(
3667 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
3668 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003669 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003670 domain: Domain::APP,
3671 nspace: 0,
3672 alias: Some(TEST_ALIAS.to_string()),
3673 blob: None,
3674 },
3675 KeyType::Client,
3676 KeyEntryLoadBits::NONE,
3677 1,
3678 |_k, _av| Ok(()),
3679 )
3680 .unwrap_err()
3681 .root_cause()
3682 .downcast_ref::<KsError>()
3683 );
3684
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003685 Ok(())
3686 }
3687
3688 #[test]
Janis Danisevskis377d1002021-01-27 19:07:48 -08003689 fn test_insert_and_load_certificate_entry_domain_app() -> Result<()> {
3690 let mut db = new_test_db()?;
3691
3692 db.store_new_certificate(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003693 &KeyDescriptor {
Janis Danisevskis377d1002021-01-27 19:07:48 -08003694 domain: Domain::APP,
3695 nspace: 1,
3696 alias: Some(TEST_ALIAS.to_string()),
3697 blob: None,
3698 },
3699 TEST_CERT_BLOB,
Max Bires8e93d2b2021-01-14 13:17:59 -08003700 &KEYSTORE_UUID,
Janis Danisevskis377d1002021-01-27 19:07:48 -08003701 )
3702 .expect("Trying to insert cert.");
3703
3704 let (_key_guard, mut key_entry) = db
3705 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003706 &KeyDescriptor {
Janis Danisevskis377d1002021-01-27 19:07:48 -08003707 domain: Domain::APP,
3708 nspace: 1,
3709 alias: Some(TEST_ALIAS.to_string()),
3710 blob: None,
3711 },
3712 KeyType::Client,
3713 KeyEntryLoadBits::PUBLIC,
3714 1,
3715 |_k, _av| Ok(()),
3716 )
3717 .expect("Trying to read certificate entry.");
3718
3719 assert!(key_entry.pure_cert());
3720 assert!(key_entry.cert().is_none());
3721 assert_eq!(key_entry.take_cert_chain(), Some(TEST_CERT_BLOB.to_vec()));
3722
3723 db.unbind_key(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003724 &KeyDescriptor {
Janis Danisevskis377d1002021-01-27 19:07:48 -08003725 domain: Domain::APP,
3726 nspace: 1,
3727 alias: Some(TEST_ALIAS.to_string()),
3728 blob: None,
3729 },
3730 KeyType::Client,
3731 1,
3732 |_, _| Ok(()),
3733 )
3734 .unwrap();
3735
3736 assert_eq!(
3737 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
3738 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003739 &KeyDescriptor {
Janis Danisevskis377d1002021-01-27 19:07:48 -08003740 domain: Domain::APP,
3741 nspace: 1,
3742 alias: Some(TEST_ALIAS.to_string()),
3743 blob: None,
3744 },
3745 KeyType::Client,
3746 KeyEntryLoadBits::NONE,
3747 1,
3748 |_k, _av| Ok(()),
3749 )
3750 .unwrap_err()
3751 .root_cause()
3752 .downcast_ref::<KsError>()
3753 );
3754
3755 Ok(())
3756 }
3757
3758 #[test]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003759 fn test_insert_and_load_full_keyentry_domain_selinux() -> Result<()> {
3760 let mut db = new_test_db()?;
Qi Wub9433b52020-12-01 14:52:46 +08003761 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08003762 .context("test_insert_and_load_full_keyentry_domain_selinux")?
3763 .0;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003764 let (_key_guard, key_entry) = db
3765 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003766 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003767 domain: Domain::SELINUX,
3768 nspace: 1,
3769 alias: Some(TEST_ALIAS.to_string()),
3770 blob: None,
3771 },
3772 KeyType::Client,
3773 KeyEntryLoadBits::BOTH,
3774 1,
3775 |_k, _av| Ok(()),
3776 )
3777 .unwrap();
Qi Wub9433b52020-12-01 14:52:46 +08003778 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003779
3780 db.unbind_key(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003781 &KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003782 domain: Domain::SELINUX,
3783 nspace: 1,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003784 alias: Some(TEST_ALIAS.to_string()),
3785 blob: None,
3786 },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003787 KeyType::Client,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003788 1,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003789 |_, _| Ok(()),
3790 )
3791 .unwrap();
3792
3793 assert_eq!(
3794 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
3795 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003796 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003797 domain: Domain::SELINUX,
3798 nspace: 1,
3799 alias: Some(TEST_ALIAS.to_string()),
3800 blob: None,
3801 },
3802 KeyType::Client,
3803 KeyEntryLoadBits::NONE,
3804 1,
3805 |_k, _av| Ok(()),
3806 )
3807 .unwrap_err()
3808 .root_cause()
3809 .downcast_ref::<KsError>()
3810 );
3811
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003812 Ok(())
3813 }
3814
3815 #[test]
3816 fn test_insert_and_load_full_keyentry_domain_key_id() -> Result<()> {
3817 let mut db = new_test_db()?;
Qi Wub9433b52020-12-01 14:52:46 +08003818 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08003819 .context("test_insert_and_load_full_keyentry_domain_key_id")?
3820 .0;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003821 let (_, key_entry) = db
3822 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003823 &KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003824 KeyType::Client,
3825 KeyEntryLoadBits::BOTH,
3826 1,
3827 |_k, _av| Ok(()),
3828 )
3829 .unwrap();
3830
Qi Wub9433b52020-12-01 14:52:46 +08003831 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003832
3833 db.unbind_key(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003834 &KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003835 KeyType::Client,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003836 1,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003837 |_, _| Ok(()),
3838 )
3839 .unwrap();
3840
3841 assert_eq!(
3842 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
3843 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003844 &KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003845 KeyType::Client,
3846 KeyEntryLoadBits::NONE,
3847 1,
3848 |_k, _av| Ok(()),
3849 )
3850 .unwrap_err()
3851 .root_cause()
3852 .downcast_ref::<KsError>()
3853 );
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003854
3855 Ok(())
3856 }
3857
3858 #[test]
Qi Wub9433b52020-12-01 14:52:46 +08003859 fn test_check_and_update_key_usage_count_with_limited_use_key() -> Result<()> {
3860 let mut db = new_test_db()?;
3861 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, Some(123))
3862 .context("test_check_and_update_key_usage_count_with_limited_use_key")?
3863 .0;
3864 // Update the usage count of the limited use key.
3865 db.check_and_update_key_usage_count(key_id)?;
3866
3867 let (_key_guard, key_entry) = db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003868 &KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
Qi Wub9433b52020-12-01 14:52:46 +08003869 KeyType::Client,
3870 KeyEntryLoadBits::BOTH,
3871 1,
3872 |_k, _av| Ok(()),
3873 )?;
3874
3875 // The usage count is decremented now.
3876 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, Some(122)));
3877
3878 Ok(())
3879 }
3880
3881 #[test]
3882 fn test_check_and_update_key_usage_count_with_exhausted_limited_use_key() -> Result<()> {
3883 let mut db = new_test_db()?;
3884 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, Some(1))
3885 .context("test_check_and_update_key_usage_count_with_exhausted_limited_use_key")?
3886 .0;
3887 // Update the usage count of the limited use key.
3888 db.check_and_update_key_usage_count(key_id).expect(concat!(
3889 "In test_check_and_update_key_usage_count_with_exhausted_limited_use_key: ",
3890 "This should succeed."
3891 ));
3892
3893 // Try to update the exhausted limited use key.
3894 let e = db.check_and_update_key_usage_count(key_id).expect_err(concat!(
3895 "In test_check_and_update_key_usage_count_with_exhausted_limited_use_key: ",
3896 "This should fail."
3897 ));
3898 assert_eq!(
3899 &KsError::Km(ErrorCode::INVALID_KEY_BLOB),
3900 e.root_cause().downcast_ref::<KsError>().unwrap()
3901 );
3902
3903 Ok(())
3904 }
3905
3906 #[test]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003907 fn test_insert_and_load_full_keyentry_from_grant() -> Result<()> {
3908 let mut db = new_test_db()?;
Qi Wub9433b52020-12-01 14:52:46 +08003909 let key_id = make_test_key_entry(&mut db, Domain::APP, 1, TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08003910 .context("test_insert_and_load_full_keyentry_from_grant")?
3911 .0;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003912
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003913 let granted_key = db
3914 .grant(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003915 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003916 domain: Domain::APP,
3917 nspace: 0,
3918 alias: Some(TEST_ALIAS.to_string()),
3919 blob: None,
3920 },
3921 1,
3922 2,
3923 key_perm_set![KeyPerm::use_()],
3924 |_k, _av| Ok(()),
3925 )
3926 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003927
3928 debug_dump_grant_table(&mut db)?;
3929
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003930 let (_key_guard, key_entry) = db
Janis Danisevskis66784c42021-01-27 08:40:25 -08003931 .load_key_entry(&granted_key, KeyType::Client, KeyEntryLoadBits::BOTH, 2, |k, av| {
3932 assert_eq!(Domain::GRANT, k.domain);
3933 assert!(av.unwrap().includes(KeyPerm::use_()));
3934 Ok(())
3935 })
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003936 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003937
Qi Wub9433b52020-12-01 14:52:46 +08003938 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003939
Janis Danisevskis66784c42021-01-27 08:40:25 -08003940 db.unbind_key(&granted_key, KeyType::Client, 2, |_, _| Ok(())).unwrap();
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003941
3942 assert_eq!(
3943 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
3944 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003945 &granted_key,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003946 KeyType::Client,
3947 KeyEntryLoadBits::NONE,
3948 2,
3949 |_k, _av| Ok(()),
3950 )
3951 .unwrap_err()
3952 .root_cause()
3953 .downcast_ref::<KsError>()
3954 );
3955
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003956 Ok(())
3957 }
3958
Janis Danisevskis45760022021-01-19 16:34:10 -08003959 // This test attempts to load a key by key id while the caller is not the owner
3960 // but a grant exists for the given key and the caller.
3961 #[test]
3962 fn test_insert_and_load_full_keyentry_from_grant_by_key_id() -> Result<()> {
3963 let mut db = new_test_db()?;
3964 const OWNER_UID: u32 = 1u32;
3965 const GRANTEE_UID: u32 = 2u32;
3966 const SOMEONE_ELSE_UID: u32 = 3u32;
3967 let key_id = make_test_key_entry(&mut db, Domain::APP, OWNER_UID as i64, TEST_ALIAS, None)
3968 .context("test_insert_and_load_full_keyentry_from_grant_by_key_id")?
3969 .0;
3970
3971 db.grant(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003972 &KeyDescriptor {
Janis Danisevskis45760022021-01-19 16:34:10 -08003973 domain: Domain::APP,
3974 nspace: 0,
3975 alias: Some(TEST_ALIAS.to_string()),
3976 blob: None,
3977 },
3978 OWNER_UID,
3979 GRANTEE_UID,
3980 key_perm_set![KeyPerm::use_()],
3981 |_k, _av| Ok(()),
3982 )
3983 .unwrap();
3984
3985 debug_dump_grant_table(&mut db)?;
3986
3987 let id_descriptor =
3988 KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, ..Default::default() };
3989
3990 let (_, key_entry) = db
3991 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003992 &id_descriptor,
Janis Danisevskis45760022021-01-19 16:34:10 -08003993 KeyType::Client,
3994 KeyEntryLoadBits::BOTH,
3995 GRANTEE_UID,
3996 |k, av| {
3997 assert_eq!(Domain::APP, k.domain);
3998 assert_eq!(OWNER_UID as i64, k.nspace);
3999 assert!(av.unwrap().includes(KeyPerm::use_()));
4000 Ok(())
4001 },
4002 )
4003 .unwrap();
4004
4005 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
4006
4007 let (_, key_entry) = db
4008 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004009 &id_descriptor,
Janis Danisevskis45760022021-01-19 16:34:10 -08004010 KeyType::Client,
4011 KeyEntryLoadBits::BOTH,
4012 SOMEONE_ELSE_UID,
4013 |k, av| {
4014 assert_eq!(Domain::APP, k.domain);
4015 assert_eq!(OWNER_UID as i64, k.nspace);
4016 assert!(av.is_none());
4017 Ok(())
4018 },
4019 )
4020 .unwrap();
4021
4022 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
4023
Janis Danisevskis66784c42021-01-27 08:40:25 -08004024 db.unbind_key(&id_descriptor, KeyType::Client, OWNER_UID, |_, _| Ok(())).unwrap();
Janis Danisevskis45760022021-01-19 16:34:10 -08004025
4026 assert_eq!(
4027 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
4028 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004029 &id_descriptor,
Janis Danisevskis45760022021-01-19 16:34:10 -08004030 KeyType::Client,
4031 KeyEntryLoadBits::NONE,
4032 GRANTEE_UID,
4033 |_k, _av| Ok(()),
4034 )
4035 .unwrap_err()
4036 .root_cause()
4037 .downcast_ref::<KsError>()
4038 );
4039
4040 Ok(())
4041 }
4042
Janis Danisevskisaec14592020-11-12 09:41:49 -08004043 static KEY_LOCK_TEST_ALIAS: &str = "my super duper locked key";
4044
Janis Danisevskisaec14592020-11-12 09:41:49 -08004045 #[test]
4046 fn test_insert_and_load_full_keyentry_domain_app_concurrently() -> Result<()> {
4047 let handle = {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08004048 let temp_dir = Arc::new(TempDir::new("id_lock_test")?);
4049 let temp_dir_clone = temp_dir.clone();
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004050 let mut db = KeystoreDB::new(temp_dir.path(), None)?;
Qi Wub9433b52020-12-01 14:52:46 +08004051 let key_id = make_test_key_entry(&mut db, Domain::APP, 33, KEY_LOCK_TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08004052 .context("test_insert_and_load_full_keyentry_domain_app")?
4053 .0;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004054 let (_key_guard, key_entry) = db
4055 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004056 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004057 domain: Domain::APP,
4058 nspace: 0,
4059 alias: Some(KEY_LOCK_TEST_ALIAS.to_string()),
4060 blob: None,
4061 },
4062 KeyType::Client,
4063 KeyEntryLoadBits::BOTH,
4064 33,
4065 |_k, _av| Ok(()),
4066 )
4067 .unwrap();
Qi Wub9433b52020-12-01 14:52:46 +08004068 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskisaec14592020-11-12 09:41:49 -08004069 let state = Arc::new(AtomicU8::new(1));
4070 let state2 = state.clone();
4071
4072 // Spawning a second thread that attempts to acquire the key id lock
4073 // for the same key as the primary thread. The primary thread then
4074 // waits, thereby forcing the secondary thread into the second stage
4075 // of acquiring the lock (see KEY ID LOCK 2/2 above).
4076 // The test succeeds if the secondary thread observes the transition
4077 // of `state` from 1 to 2, despite having a whole second to overtake
4078 // the primary thread.
4079 let handle = thread::spawn(move || {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08004080 let temp_dir = temp_dir_clone;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004081 let mut db = KeystoreDB::new(temp_dir.path(), None).unwrap();
Janis Danisevskisaec14592020-11-12 09:41:49 -08004082 assert!(db
4083 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004084 &KeyDescriptor {
Janis Danisevskisaec14592020-11-12 09:41:49 -08004085 domain: Domain::APP,
4086 nspace: 0,
4087 alias: Some(KEY_LOCK_TEST_ALIAS.to_string()),
4088 blob: None,
4089 },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004090 KeyType::Client,
Janis Danisevskisaec14592020-11-12 09:41:49 -08004091 KeyEntryLoadBits::BOTH,
4092 33,
4093 |_k, _av| Ok(()),
4094 )
4095 .is_ok());
4096 // We should only see a 2 here because we can only return
4097 // from load_key_entry when the `_key_guard` expires,
4098 // which happens at the end of the scope.
4099 assert_eq!(2, state2.load(Ordering::Relaxed));
4100 });
4101
4102 thread::sleep(std::time::Duration::from_millis(1000));
4103
4104 assert_eq!(Ok(1), state.compare_exchange(1, 2, Ordering::Relaxed, Ordering::Relaxed));
4105
4106 // Return the handle from this scope so we can join with the
4107 // secondary thread after the key id lock has expired.
4108 handle
4109 // This is where the `_key_guard` goes out of scope,
4110 // which is the reason for concurrent load_key_entry on the same key
4111 // to unblock.
4112 };
4113 // Join with the secondary thread and unwrap, to propagate failing asserts to the
4114 // main test thread. We will not see failing asserts in secondary threads otherwise.
4115 handle.join().unwrap();
4116 Ok(())
4117 }
4118
Janis Danisevskise92a5e62020-12-02 12:57:41 -08004119 #[test]
Janis Danisevskis66784c42021-01-27 08:40:25 -08004120 fn teset_database_busy_error_code() {
4121 let temp_dir =
4122 TempDir::new("test_database_busy_error_code_").expect("Failed to create temp dir.");
4123
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004124 let mut db1 = KeystoreDB::new(temp_dir.path(), None).expect("Failed to open database1.");
4125 let mut db2 = KeystoreDB::new(temp_dir.path(), None).expect("Failed to open database2.");
Janis Danisevskis66784c42021-01-27 08:40:25 -08004126
4127 let _tx1 = db1
4128 .conn
4129 .transaction_with_behavior(TransactionBehavior::Immediate)
4130 .expect("Failed to create first transaction.");
4131
4132 let error = db2
4133 .conn
4134 .transaction_with_behavior(TransactionBehavior::Immediate)
4135 .context("Transaction begin failed.")
4136 .expect_err("This should fail.");
4137 let root_cause = error.root_cause();
4138 if let Some(rusqlite::ffi::Error { code: rusqlite::ErrorCode::DatabaseBusy, .. }) =
4139 root_cause.downcast_ref::<rusqlite::ffi::Error>()
4140 {
4141 return;
4142 }
4143 panic!(
4144 "Unexpected error {:?} \n{:?} \n{:?}",
4145 error,
4146 root_cause,
4147 root_cause.downcast_ref::<rusqlite::ffi::Error>()
4148 )
4149 }
4150
4151 #[cfg(disabled)]
4152 #[test]
4153 fn test_large_number_of_concurrent_db_manipulations() -> Result<()> {
4154 let temp_dir = Arc::new(
4155 TempDir::new("test_large_number_of_concurrent_db_manipulations_")
4156 .expect("Failed to create temp dir."),
4157 );
4158
4159 let test_begin = Instant::now();
4160
4161 let mut db = KeystoreDB::new(temp_dir.path()).expect("Failed to open database.");
4162 const KEY_COUNT: u32 = 500u32;
4163 const OPEN_DB_COUNT: u32 = 50u32;
4164
4165 let mut actual_key_count = KEY_COUNT;
4166 // First insert KEY_COUNT keys.
4167 for count in 0..KEY_COUNT {
4168 if Instant::now().duration_since(test_begin) >= Duration::from_secs(15) {
4169 actual_key_count = count;
4170 break;
4171 }
4172 let alias = format!("test_alias_{}", count);
4173 make_test_key_entry(&mut db, Domain::APP, 1, &alias, None)
4174 .expect("Failed to make key entry.");
4175 }
4176
4177 // Insert more keys from a different thread and into a different namespace.
4178 let temp_dir1 = temp_dir.clone();
4179 let handle1 = thread::spawn(move || {
4180 let mut db = KeystoreDB::new(temp_dir1.path()).expect("Failed to open database.");
4181
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 alias = format!("test_alias_{}", count);
4187 make_test_key_entry(&mut db, Domain::APP, 2, &alias, None)
4188 .expect("Failed to make key entry.");
4189 }
4190
4191 // then unbind them again.
4192 for count in 0..actual_key_count {
4193 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
4194 return;
4195 }
4196 let key = KeyDescriptor {
4197 domain: Domain::APP,
4198 nspace: -1,
4199 alias: Some(format!("test_alias_{}", count)),
4200 blob: None,
4201 };
4202 db.unbind_key(&key, KeyType::Client, 2, |_, _| Ok(())).expect("Unbind Failed.");
4203 }
4204 });
4205
4206 // And start unbinding the first set of keys.
4207 let temp_dir2 = temp_dir.clone();
4208 let handle2 = thread::spawn(move || {
4209 let mut db = KeystoreDB::new(temp_dir2.path()).expect("Failed to open database.");
4210
4211 for count in 0..actual_key_count {
4212 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
4213 return;
4214 }
4215 let key = KeyDescriptor {
4216 domain: Domain::APP,
4217 nspace: -1,
4218 alias: Some(format!("test_alias_{}", count)),
4219 blob: None,
4220 };
4221 db.unbind_key(&key, KeyType::Client, 1, |_, _| Ok(())).expect("Unbind Failed.");
4222 }
4223 });
4224
4225 let stop_deleting = Arc::new(AtomicU8::new(0));
4226 let stop_deleting2 = stop_deleting.clone();
4227
4228 // And delete anything that is unreferenced keys.
4229 let temp_dir3 = temp_dir.clone();
4230 let handle3 = thread::spawn(move || {
4231 let mut db = KeystoreDB::new(temp_dir3.path()).expect("Failed to open database.");
4232
4233 while stop_deleting2.load(Ordering::Relaxed) != 1 {
4234 while let Some((key_guard, _key)) =
4235 db.get_unreferenced_key().expect("Failed to get unreferenced Key.")
4236 {
4237 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
4238 return;
4239 }
4240 db.purge_key_entry(key_guard).expect("Failed to purge key.");
4241 }
4242 std::thread::sleep(std::time::Duration::from_millis(100));
4243 }
4244 });
4245
4246 // While a lot of inserting and deleting is going on we have to open database connections
4247 // successfully and use them.
4248 // This clone is not redundant, because temp_dir needs to be kept alive until db goes
4249 // out of scope.
4250 #[allow(clippy::redundant_clone)]
4251 let temp_dir4 = temp_dir.clone();
4252 let handle4 = thread::spawn(move || {
4253 for count in 0..OPEN_DB_COUNT {
4254 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
4255 return;
4256 }
4257 let mut db = KeystoreDB::new(temp_dir4.path()).expect("Failed to open database.");
4258
4259 let alias = format!("test_alias_{}", count);
4260 make_test_key_entry(&mut db, Domain::APP, 3, &alias, None)
4261 .expect("Failed to make key entry.");
4262 let key = KeyDescriptor {
4263 domain: Domain::APP,
4264 nspace: -1,
4265 alias: Some(alias),
4266 blob: None,
4267 };
4268 db.unbind_key(&key, KeyType::Client, 3, |_, _| Ok(())).expect("Unbind Failed.");
4269 }
4270 });
4271
4272 handle1.join().expect("Thread 1 panicked.");
4273 handle2.join().expect("Thread 2 panicked.");
4274 handle4.join().expect("Thread 4 panicked.");
4275
4276 stop_deleting.store(1, Ordering::Relaxed);
4277 handle3.join().expect("Thread 3 panicked.");
4278
4279 Ok(())
4280 }
4281
4282 #[test]
Janis Danisevskise92a5e62020-12-02 12:57:41 -08004283 fn list() -> Result<()> {
4284 let temp_dir = TempDir::new("list_test")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004285 let mut db = KeystoreDB::new(temp_dir.path(), None)?;
Janis Danisevskise92a5e62020-12-02 12:57:41 -08004286 static LIST_O_ENTRIES: &[(Domain, i64, &str)] = &[
4287 (Domain::APP, 1, "test1"),
4288 (Domain::APP, 1, "test2"),
4289 (Domain::APP, 1, "test3"),
4290 (Domain::APP, 1, "test4"),
4291 (Domain::APP, 1, "test5"),
4292 (Domain::APP, 1, "test6"),
4293 (Domain::APP, 1, "test7"),
4294 (Domain::APP, 2, "test1"),
4295 (Domain::APP, 2, "test2"),
4296 (Domain::APP, 2, "test3"),
4297 (Domain::APP, 2, "test4"),
4298 (Domain::APP, 2, "test5"),
4299 (Domain::APP, 2, "test6"),
4300 (Domain::APP, 2, "test8"),
4301 (Domain::SELINUX, 100, "test1"),
4302 (Domain::SELINUX, 100, "test2"),
4303 (Domain::SELINUX, 100, "test3"),
4304 (Domain::SELINUX, 100, "test4"),
4305 (Domain::SELINUX, 100, "test5"),
4306 (Domain::SELINUX, 100, "test6"),
4307 (Domain::SELINUX, 100, "test9"),
4308 ];
4309
4310 let list_o_keys: Vec<(i64, i64)> = LIST_O_ENTRIES
4311 .iter()
4312 .map(|(domain, ns, alias)| {
Qi Wub9433b52020-12-01 14:52:46 +08004313 let entry = make_test_key_entry(&mut db, *domain, *ns, *alias, None)
4314 .unwrap_or_else(|e| {
Janis Danisevskise92a5e62020-12-02 12:57:41 -08004315 panic!("Failed to insert {:?} {} {}. Error {:?}", domain, ns, alias, e)
4316 });
4317 (entry.id(), *ns)
4318 })
4319 .collect();
4320
4321 for (domain, namespace) in
4322 &[(Domain::APP, 1i64), (Domain::APP, 2i64), (Domain::SELINUX, 100i64)]
4323 {
4324 let mut list_o_descriptors: Vec<KeyDescriptor> = LIST_O_ENTRIES
4325 .iter()
4326 .filter_map(|(domain, ns, alias)| match ns {
4327 ns if *ns == *namespace => Some(KeyDescriptor {
4328 domain: *domain,
4329 nspace: *ns,
4330 alias: Some(alias.to_string()),
4331 blob: None,
4332 }),
4333 _ => None,
4334 })
4335 .collect();
4336 list_o_descriptors.sort();
4337 let mut list_result = db.list(*domain, *namespace)?;
4338 list_result.sort();
4339 assert_eq!(list_o_descriptors, list_result);
4340
4341 let mut list_o_ids: Vec<i64> = list_o_descriptors
4342 .into_iter()
4343 .map(|d| {
4344 let (_, entry) = db
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004345 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004346 &d,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004347 KeyType::Client,
4348 KeyEntryLoadBits::NONE,
4349 *namespace as u32,
4350 |_, _| Ok(()),
4351 )
Janis Danisevskise92a5e62020-12-02 12:57:41 -08004352 .unwrap();
4353 entry.id()
4354 })
4355 .collect();
4356 list_o_ids.sort_unstable();
4357 let mut loaded_entries: Vec<i64> = list_o_keys
4358 .iter()
4359 .filter_map(|(id, ns)| match ns {
4360 ns if *ns == *namespace => Some(*id),
4361 _ => None,
4362 })
4363 .collect();
4364 loaded_entries.sort_unstable();
4365 assert_eq!(list_o_ids, loaded_entries);
4366 }
4367 assert_eq!(Vec::<KeyDescriptor>::new(), db.list(Domain::SELINUX, 101)?);
4368
4369 Ok(())
4370 }
4371
Joel Galenson0891bc12020-07-20 10:37:03 -07004372 // Helpers
4373
4374 // Checks that the given result is an error containing the given string.
4375 fn check_result_is_error_containing_string<T>(result: Result<T>, target: &str) {
4376 let error_str = format!(
4377 "{:#?}",
4378 result.err().unwrap_or_else(|| panic!("Expected the error: {}", target))
4379 );
4380 assert!(
4381 error_str.contains(target),
4382 "The string \"{}\" should contain \"{}\"",
4383 error_str,
4384 target
4385 );
4386 }
4387
Joel Galenson2aab4432020-07-22 15:27:57 -07004388 #[derive(Debug, PartialEq)]
Joel Galenson0891bc12020-07-20 10:37:03 -07004389 #[allow(dead_code)]
4390 struct KeyEntryRow {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004391 id: i64,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004392 key_type: KeyType,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07004393 domain: Option<Domain>,
Joel Galenson0891bc12020-07-20 10:37:03 -07004394 namespace: Option<i64>,
4395 alias: Option<String>,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004396 state: KeyLifeCycle,
Max Bires8e93d2b2021-01-14 13:17:59 -08004397 km_uuid: Option<Uuid>,
Joel Galenson0891bc12020-07-20 10:37:03 -07004398 }
4399
4400 fn get_keyentry(db: &KeystoreDB) -> Result<Vec<KeyEntryRow>> {
4401 db.conn
Joel Galenson2aab4432020-07-22 15:27:57 -07004402 .prepare("SELECT * FROM persistent.keyentry;")?
Joel Galenson0891bc12020-07-20 10:37:03 -07004403 .query_map(NO_PARAMS, |row| {
Joel Galenson0891bc12020-07-20 10:37:03 -07004404 Ok(KeyEntryRow {
4405 id: row.get(0)?,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004406 key_type: row.get(1)?,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07004407 domain: match row.get(2)? {
4408 Some(i) => Some(Domain(i)),
4409 None => None,
4410 },
Joel Galenson0891bc12020-07-20 10:37:03 -07004411 namespace: row.get(3)?,
4412 alias: row.get(4)?,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004413 state: row.get(5)?,
Max Bires8e93d2b2021-01-14 13:17:59 -08004414 km_uuid: row.get(6)?,
Joel Galenson0891bc12020-07-20 10:37:03 -07004415 })
4416 })?
4417 .map(|r| r.context("Could not read keyentry row."))
4418 .collect::<Result<Vec<_>>>()
4419 }
4420
Max Biresb2e1d032021-02-08 21:35:05 -08004421 struct RemoteProvValues {
4422 cert_chain: Vec<u8>,
4423 priv_key: Vec<u8>,
4424 batch_cert: Vec<u8>,
4425 }
4426
Max Bires2b2e6562020-09-22 11:22:36 -07004427 fn load_attestation_key_pool(
4428 db: &mut KeystoreDB,
4429 expiration_date: i64,
4430 namespace: i64,
4431 base_byte: u8,
Max Biresb2e1d032021-02-08 21:35:05 -08004432 ) -> Result<RemoteProvValues> {
Max Bires2b2e6562020-09-22 11:22:36 -07004433 let public_key: Vec<u8> = vec![base_byte, 0x02 * base_byte];
4434 let cert_chain: Vec<u8> = vec![0x03 * base_byte, 0x04 * base_byte];
4435 let priv_key: Vec<u8> = vec![0x05 * base_byte, 0x06 * base_byte];
4436 let raw_public_key: Vec<u8> = vec![0x0b * base_byte, 0x0c * base_byte];
Max Biresb2e1d032021-02-08 21:35:05 -08004437 let batch_cert: Vec<u8> = vec![base_byte * 0x0d, base_byte * 0x0e];
Max Bires2b2e6562020-09-22 11:22:36 -07004438 db.create_attestation_key_entry(&public_key, &raw_public_key, &priv_key, &KEYSTORE_UUID)?;
4439 db.store_signed_attestation_certificate_chain(
4440 &raw_public_key,
Max Biresb2e1d032021-02-08 21:35:05 -08004441 &batch_cert,
Max Bires2b2e6562020-09-22 11:22:36 -07004442 &cert_chain,
4443 expiration_date,
4444 &KEYSTORE_UUID,
4445 )?;
4446 db.assign_attestation_key(Domain::APP, namespace, &KEYSTORE_UUID)?;
Max Biresb2e1d032021-02-08 21:35:05 -08004447 Ok(RemoteProvValues { cert_chain, priv_key, batch_cert })
Max Bires2b2e6562020-09-22 11:22:36 -07004448 }
4449
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07004450 // Note: The parameters and SecurityLevel associations are nonsensical. This
4451 // collection is only used to check if the parameters are preserved as expected by the
4452 // database.
Qi Wub9433b52020-12-01 14:52:46 +08004453 fn make_test_params(max_usage_count: Option<i32>) -> Vec<KeyParameter> {
4454 let mut params = vec![
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07004455 KeyParameter::new(KeyParameterValue::Invalid, SecurityLevel::TRUSTED_ENVIRONMENT),
4456 KeyParameter::new(
4457 KeyParameterValue::KeyPurpose(KeyPurpose::SIGN),
4458 SecurityLevel::TRUSTED_ENVIRONMENT,
4459 ),
4460 KeyParameter::new(
4461 KeyParameterValue::KeyPurpose(KeyPurpose::DECRYPT),
4462 SecurityLevel::TRUSTED_ENVIRONMENT,
4463 ),
4464 KeyParameter::new(
4465 KeyParameterValue::Algorithm(Algorithm::RSA),
4466 SecurityLevel::TRUSTED_ENVIRONMENT,
4467 ),
4468 KeyParameter::new(KeyParameterValue::KeySize(1024), SecurityLevel::TRUSTED_ENVIRONMENT),
4469 KeyParameter::new(
4470 KeyParameterValue::BlockMode(BlockMode::ECB),
4471 SecurityLevel::TRUSTED_ENVIRONMENT,
4472 ),
4473 KeyParameter::new(
4474 KeyParameterValue::BlockMode(BlockMode::GCM),
4475 SecurityLevel::TRUSTED_ENVIRONMENT,
4476 ),
4477 KeyParameter::new(KeyParameterValue::Digest(Digest::NONE), SecurityLevel::STRONGBOX),
4478 KeyParameter::new(
4479 KeyParameterValue::Digest(Digest::MD5),
4480 SecurityLevel::TRUSTED_ENVIRONMENT,
4481 ),
4482 KeyParameter::new(
4483 KeyParameterValue::Digest(Digest::SHA_2_224),
4484 SecurityLevel::TRUSTED_ENVIRONMENT,
4485 ),
4486 KeyParameter::new(
4487 KeyParameterValue::Digest(Digest::SHA_2_256),
4488 SecurityLevel::STRONGBOX,
4489 ),
4490 KeyParameter::new(
4491 KeyParameterValue::PaddingMode(PaddingMode::NONE),
4492 SecurityLevel::TRUSTED_ENVIRONMENT,
4493 ),
4494 KeyParameter::new(
4495 KeyParameterValue::PaddingMode(PaddingMode::RSA_OAEP),
4496 SecurityLevel::TRUSTED_ENVIRONMENT,
4497 ),
4498 KeyParameter::new(
4499 KeyParameterValue::PaddingMode(PaddingMode::RSA_PSS),
4500 SecurityLevel::STRONGBOX,
4501 ),
4502 KeyParameter::new(
4503 KeyParameterValue::PaddingMode(PaddingMode::RSA_PKCS1_1_5_SIGN),
4504 SecurityLevel::TRUSTED_ENVIRONMENT,
4505 ),
4506 KeyParameter::new(KeyParameterValue::CallerNonce, SecurityLevel::TRUSTED_ENVIRONMENT),
4507 KeyParameter::new(KeyParameterValue::MinMacLength(256), SecurityLevel::STRONGBOX),
4508 KeyParameter::new(
4509 KeyParameterValue::EcCurve(EcCurve::P_224),
4510 SecurityLevel::TRUSTED_ENVIRONMENT,
4511 ),
4512 KeyParameter::new(KeyParameterValue::EcCurve(EcCurve::P_256), SecurityLevel::STRONGBOX),
4513 KeyParameter::new(
4514 KeyParameterValue::EcCurve(EcCurve::P_384),
4515 SecurityLevel::TRUSTED_ENVIRONMENT,
4516 ),
4517 KeyParameter::new(
4518 KeyParameterValue::EcCurve(EcCurve::P_521),
4519 SecurityLevel::TRUSTED_ENVIRONMENT,
4520 ),
4521 KeyParameter::new(
4522 KeyParameterValue::RSAPublicExponent(3),
4523 SecurityLevel::TRUSTED_ENVIRONMENT,
4524 ),
4525 KeyParameter::new(
4526 KeyParameterValue::IncludeUniqueID,
4527 SecurityLevel::TRUSTED_ENVIRONMENT,
4528 ),
4529 KeyParameter::new(KeyParameterValue::BootLoaderOnly, SecurityLevel::STRONGBOX),
4530 KeyParameter::new(KeyParameterValue::RollbackResistance, SecurityLevel::STRONGBOX),
4531 KeyParameter::new(
4532 KeyParameterValue::ActiveDateTime(1234567890),
4533 SecurityLevel::STRONGBOX,
4534 ),
4535 KeyParameter::new(
4536 KeyParameterValue::OriginationExpireDateTime(1234567890),
4537 SecurityLevel::TRUSTED_ENVIRONMENT,
4538 ),
4539 KeyParameter::new(
4540 KeyParameterValue::UsageExpireDateTime(1234567890),
4541 SecurityLevel::TRUSTED_ENVIRONMENT,
4542 ),
4543 KeyParameter::new(
4544 KeyParameterValue::MinSecondsBetweenOps(1234567890),
4545 SecurityLevel::TRUSTED_ENVIRONMENT,
4546 ),
4547 KeyParameter::new(
4548 KeyParameterValue::MaxUsesPerBoot(1234567890),
4549 SecurityLevel::TRUSTED_ENVIRONMENT,
4550 ),
4551 KeyParameter::new(KeyParameterValue::UserID(1), SecurityLevel::STRONGBOX),
4552 KeyParameter::new(KeyParameterValue::UserSecureID(42), SecurityLevel::STRONGBOX),
4553 KeyParameter::new(
4554 KeyParameterValue::NoAuthRequired,
4555 SecurityLevel::TRUSTED_ENVIRONMENT,
4556 ),
4557 KeyParameter::new(
4558 KeyParameterValue::HardwareAuthenticatorType(HardwareAuthenticatorType::PASSWORD),
4559 SecurityLevel::TRUSTED_ENVIRONMENT,
4560 ),
4561 KeyParameter::new(KeyParameterValue::AuthTimeout(1234567890), SecurityLevel::SOFTWARE),
4562 KeyParameter::new(KeyParameterValue::AllowWhileOnBody, SecurityLevel::SOFTWARE),
4563 KeyParameter::new(
4564 KeyParameterValue::TrustedUserPresenceRequired,
4565 SecurityLevel::TRUSTED_ENVIRONMENT,
4566 ),
4567 KeyParameter::new(
4568 KeyParameterValue::TrustedConfirmationRequired,
4569 SecurityLevel::TRUSTED_ENVIRONMENT,
4570 ),
4571 KeyParameter::new(
4572 KeyParameterValue::UnlockedDeviceRequired,
4573 SecurityLevel::TRUSTED_ENVIRONMENT,
4574 ),
4575 KeyParameter::new(
4576 KeyParameterValue::ApplicationID(vec![1u8, 2u8, 3u8, 4u8]),
4577 SecurityLevel::SOFTWARE,
4578 ),
4579 KeyParameter::new(
4580 KeyParameterValue::ApplicationData(vec![4u8, 3u8, 2u8, 1u8]),
4581 SecurityLevel::SOFTWARE,
4582 ),
4583 KeyParameter::new(
4584 KeyParameterValue::CreationDateTime(12345677890),
4585 SecurityLevel::SOFTWARE,
4586 ),
4587 KeyParameter::new(
4588 KeyParameterValue::KeyOrigin(KeyOrigin::GENERATED),
4589 SecurityLevel::TRUSTED_ENVIRONMENT,
4590 ),
4591 KeyParameter::new(
4592 KeyParameterValue::RootOfTrust(vec![3u8, 2u8, 1u8, 4u8]),
4593 SecurityLevel::TRUSTED_ENVIRONMENT,
4594 ),
4595 KeyParameter::new(KeyParameterValue::OSVersion(1), SecurityLevel::TRUSTED_ENVIRONMENT),
4596 KeyParameter::new(KeyParameterValue::OSPatchLevel(2), SecurityLevel::SOFTWARE),
4597 KeyParameter::new(
4598 KeyParameterValue::UniqueID(vec![4u8, 3u8, 1u8, 2u8]),
4599 SecurityLevel::SOFTWARE,
4600 ),
4601 KeyParameter::new(
4602 KeyParameterValue::AttestationChallenge(vec![4u8, 3u8, 1u8, 2u8]),
4603 SecurityLevel::TRUSTED_ENVIRONMENT,
4604 ),
4605 KeyParameter::new(
4606 KeyParameterValue::AttestationApplicationID(vec![4u8, 3u8, 1u8, 2u8]),
4607 SecurityLevel::TRUSTED_ENVIRONMENT,
4608 ),
4609 KeyParameter::new(
4610 KeyParameterValue::AttestationIdBrand(vec![4u8, 3u8, 1u8, 2u8]),
4611 SecurityLevel::TRUSTED_ENVIRONMENT,
4612 ),
4613 KeyParameter::new(
4614 KeyParameterValue::AttestationIdDevice(vec![4u8, 3u8, 1u8, 2u8]),
4615 SecurityLevel::TRUSTED_ENVIRONMENT,
4616 ),
4617 KeyParameter::new(
4618 KeyParameterValue::AttestationIdProduct(vec![4u8, 3u8, 1u8, 2u8]),
4619 SecurityLevel::TRUSTED_ENVIRONMENT,
4620 ),
4621 KeyParameter::new(
4622 KeyParameterValue::AttestationIdSerial(vec![4u8, 3u8, 1u8, 2u8]),
4623 SecurityLevel::TRUSTED_ENVIRONMENT,
4624 ),
4625 KeyParameter::new(
4626 KeyParameterValue::AttestationIdIMEI(vec![4u8, 3u8, 1u8, 2u8]),
4627 SecurityLevel::TRUSTED_ENVIRONMENT,
4628 ),
4629 KeyParameter::new(
4630 KeyParameterValue::AttestationIdMEID(vec![4u8, 3u8, 1u8, 2u8]),
4631 SecurityLevel::TRUSTED_ENVIRONMENT,
4632 ),
4633 KeyParameter::new(
4634 KeyParameterValue::AttestationIdManufacturer(vec![4u8, 3u8, 1u8, 2u8]),
4635 SecurityLevel::TRUSTED_ENVIRONMENT,
4636 ),
4637 KeyParameter::new(
4638 KeyParameterValue::AttestationIdModel(vec![4u8, 3u8, 1u8, 2u8]),
4639 SecurityLevel::TRUSTED_ENVIRONMENT,
4640 ),
4641 KeyParameter::new(
4642 KeyParameterValue::VendorPatchLevel(3),
4643 SecurityLevel::TRUSTED_ENVIRONMENT,
4644 ),
4645 KeyParameter::new(
4646 KeyParameterValue::BootPatchLevel(4),
4647 SecurityLevel::TRUSTED_ENVIRONMENT,
4648 ),
4649 KeyParameter::new(
4650 KeyParameterValue::AssociatedData(vec![4u8, 3u8, 1u8, 2u8]),
4651 SecurityLevel::TRUSTED_ENVIRONMENT,
4652 ),
4653 KeyParameter::new(
4654 KeyParameterValue::Nonce(vec![4u8, 3u8, 1u8, 2u8]),
4655 SecurityLevel::TRUSTED_ENVIRONMENT,
4656 ),
4657 KeyParameter::new(
4658 KeyParameterValue::MacLength(256),
4659 SecurityLevel::TRUSTED_ENVIRONMENT,
4660 ),
4661 KeyParameter::new(
4662 KeyParameterValue::ResetSinceIdRotation,
4663 SecurityLevel::TRUSTED_ENVIRONMENT,
4664 ),
4665 KeyParameter::new(
4666 KeyParameterValue::ConfirmationToken(vec![5u8, 5u8, 5u8, 5u8]),
4667 SecurityLevel::TRUSTED_ENVIRONMENT,
4668 ),
Qi Wub9433b52020-12-01 14:52:46 +08004669 ];
4670 if let Some(value) = max_usage_count {
4671 params.push(KeyParameter::new(
4672 KeyParameterValue::UsageCountLimit(value),
4673 SecurityLevel::SOFTWARE,
4674 ));
4675 }
4676 params
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07004677 }
4678
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004679 fn make_test_key_entry(
4680 db: &mut KeystoreDB,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07004681 domain: Domain,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004682 namespace: i64,
4683 alias: &str,
Qi Wub9433b52020-12-01 14:52:46 +08004684 max_usage_count: Option<i32>,
Janis Danisevskisaec14592020-11-12 09:41:49 -08004685 ) -> Result<KeyIdGuard> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08004686 let key_id = db.create_key_entry(&domain, &namespace, &KEYSTORE_UUID)?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004687 let mut blob_metadata = BlobMetaData::new();
4688 blob_metadata.add(BlobMetaEntry::EncryptedBy(EncryptedBy::Password));
4689 blob_metadata.add(BlobMetaEntry::Salt(vec![1, 2, 3]));
4690 blob_metadata.add(BlobMetaEntry::Iv(vec![2, 3, 1]));
4691 blob_metadata.add(BlobMetaEntry::AeadTag(vec![3, 1, 2]));
4692 blob_metadata.add(BlobMetaEntry::KmUuid(KEYSTORE_UUID));
4693
4694 db.set_blob(
4695 &key_id,
4696 SubComponentType::KEY_BLOB,
4697 Some(TEST_KEY_BLOB),
4698 Some(&blob_metadata),
4699 )?;
4700 db.set_blob(&key_id, SubComponentType::CERT, Some(TEST_CERT_BLOB), None)?;
4701 db.set_blob(&key_id, SubComponentType::CERT_CHAIN, Some(TEST_CERT_CHAIN_BLOB), None)?;
Qi Wub9433b52020-12-01 14:52:46 +08004702
4703 let params = make_test_params(max_usage_count);
4704 db.insert_keyparameter(&key_id, &params)?;
4705
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004706 let mut metadata = KeyMetaData::new();
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004707 metadata.add(KeyMetaEntry::CreationDate(DateTime::from_millis_epoch(123456789)));
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004708 db.insert_key_metadata(&key_id, &metadata)?;
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08004709 rebind_alias(db, &key_id, alias, domain, namespace)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004710 Ok(key_id)
4711 }
4712
Qi Wub9433b52020-12-01 14:52:46 +08004713 fn make_test_key_entry_test_vector(key_id: i64, max_usage_count: Option<i32>) -> KeyEntry {
4714 let params = make_test_params(max_usage_count);
4715
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004716 let mut blob_metadata = BlobMetaData::new();
4717 blob_metadata.add(BlobMetaEntry::EncryptedBy(EncryptedBy::Password));
4718 blob_metadata.add(BlobMetaEntry::Salt(vec![1, 2, 3]));
4719 blob_metadata.add(BlobMetaEntry::Iv(vec![2, 3, 1]));
4720 blob_metadata.add(BlobMetaEntry::AeadTag(vec![3, 1, 2]));
4721 blob_metadata.add(BlobMetaEntry::KmUuid(KEYSTORE_UUID));
4722
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004723 let mut metadata = KeyMetaData::new();
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004724 metadata.add(KeyMetaEntry::CreationDate(DateTime::from_millis_epoch(123456789)));
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004725
4726 KeyEntry {
4727 id: key_id,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004728 key_blob_info: Some((TEST_KEY_BLOB.to_vec(), blob_metadata)),
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004729 cert: Some(TEST_CERT_BLOB.to_vec()),
4730 cert_chain: Some(TEST_CERT_CHAIN_BLOB.to_vec()),
Max Bires8e93d2b2021-01-14 13:17:59 -08004731 km_uuid: KEYSTORE_UUID,
Qi Wub9433b52020-12-01 14:52:46 +08004732 parameters: params,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004733 metadata,
Janis Danisevskis377d1002021-01-27 19:07:48 -08004734 pure_cert: false,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004735 }
4736 }
4737
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004738 fn debug_dump_keyentry_table(db: &mut KeystoreDB) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004739 let mut stmt = db.conn.prepare(
Max Bires8e93d2b2021-01-14 13:17:59 -08004740 "SELECT id, key_type, domain, namespace, alias, state, km_uuid FROM persistent.keyentry;",
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004741 )?;
Max Bires8e93d2b2021-01-14 13:17:59 -08004742 let rows = stmt.query_map::<(i64, KeyType, i32, i64, String, KeyLifeCycle, Uuid), _, _>(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004743 NO_PARAMS,
4744 |row| {
Max Bires8e93d2b2021-01-14 13:17:59 -08004745 Ok((
4746 row.get(0)?,
4747 row.get(1)?,
4748 row.get(2)?,
4749 row.get(3)?,
4750 row.get(4)?,
4751 row.get(5)?,
4752 row.get(6)?,
4753 ))
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004754 },
4755 )?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004756
4757 println!("Key entry table rows:");
4758 for r in rows {
Max Bires8e93d2b2021-01-14 13:17:59 -08004759 let (id, key_type, domain, namespace, alias, state, km_uuid) = r.unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004760 println!(
Max Bires8e93d2b2021-01-14 13:17:59 -08004761 " id: {} KeyType: {:?} Domain: {} Namespace: {} Alias: {} State: {:?} KmUuid: {:?}",
4762 id, key_type, domain, namespace, alias, state, km_uuid
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004763 );
4764 }
4765 Ok(())
4766 }
4767
4768 fn debug_dump_grant_table(db: &mut KeystoreDB) -> Result<()> {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08004769 let mut stmt = db
4770 .conn
4771 .prepare("SELECT id, grantee, keyentryid, access_vector FROM persistent.grant;")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004772 let rows = stmt.query_map::<(i64, i64, i64, i64), _, _>(NO_PARAMS, |row| {
4773 Ok((row.get(0)?, row.get(1)?, row.get(2)?, row.get(3)?))
4774 })?;
4775
4776 println!("Grant table rows:");
4777 for r in rows {
4778 let (id, gt, ki, av) = r.unwrap();
4779 println!(" id: {} grantee: {} key_id: {} access_vector: {}", id, gt, ki, av);
4780 }
4781 Ok(())
4782 }
4783
Joel Galenson0891bc12020-07-20 10:37:03 -07004784 // Use a custom random number generator that repeats each number once.
4785 // This allows us to test repeated elements.
4786
4787 thread_local! {
4788 static RANDOM_COUNTER: RefCell<i64> = RefCell::new(0);
4789 }
4790
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004791 fn reset_random() {
4792 RANDOM_COUNTER.with(|counter| {
4793 *counter.borrow_mut() = 0;
4794 })
4795 }
4796
Joel Galenson0891bc12020-07-20 10:37:03 -07004797 pub fn random() -> i64 {
4798 RANDOM_COUNTER.with(|counter| {
4799 let result = *counter.borrow() / 2;
4800 *counter.borrow_mut() += 1;
4801 result
4802 })
4803 }
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00004804
4805 #[test]
4806 fn test_last_off_body() -> Result<()> {
4807 let mut db = new_test_db()?;
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08004808 db.insert_last_off_body(MonotonicRawTime::now())?;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00004809 let tx = db.conn.transaction_with_behavior(TransactionBehavior::Immediate)?;
4810 let last_off_body_1 = KeystoreDB::get_last_off_body(&tx)?;
4811 tx.commit()?;
4812 let one_second = Duration::from_secs(1);
4813 thread::sleep(one_second);
4814 db.update_last_off_body(MonotonicRawTime::now())?;
4815 let tx2 = db.conn.transaction_with_behavior(TransactionBehavior::Immediate)?;
4816 let last_off_body_2 = KeystoreDB::get_last_off_body(&tx2)?;
4817 tx2.commit()?;
4818 assert!(last_off_body_1.seconds() < last_off_body_2.seconds());
4819 Ok(())
4820 }
Hasini Gunasingheda895552021-01-27 19:34:37 +00004821
4822 #[test]
4823 fn test_unbind_keys_for_user() -> Result<()> {
4824 let mut db = new_test_db()?;
4825 db.unbind_keys_for_user(1, false)?;
4826
4827 make_test_key_entry(&mut db, Domain::APP, 210000, TEST_ALIAS, None)?;
4828 make_test_key_entry(&mut db, Domain::APP, 110000, TEST_ALIAS, None)?;
4829 db.unbind_keys_for_user(2, false)?;
4830
4831 assert_eq!(1, db.list(Domain::APP, 110000)?.len());
4832 assert_eq!(0, db.list(Domain::APP, 210000)?.len());
4833
4834 db.unbind_keys_for_user(1, true)?;
4835 assert_eq!(0, db.list(Domain::APP, 110000)?.len());
4836
4837 Ok(())
4838 }
4839
4840 #[test]
4841 fn test_store_super_key() -> Result<()> {
4842 let mut db = new_test_db()?;
4843 let pw = "xyzabc".as_bytes();
4844 let super_key = keystore2_crypto::generate_aes256_key()?;
4845 let secret = String::from("keystore2 is great.");
4846 let secret_bytes = secret.into_bytes();
4847 let (encrypted_secret, iv, tag) =
4848 keystore2_crypto::aes_gcm_encrypt(&secret_bytes, &super_key)?;
4849
4850 let (encrypted_super_key, metadata) =
4851 SuperKeyManager::encrypt_with_password(&super_key, &pw)?;
4852 db.store_super_key(1, &(&encrypted_super_key, &metadata))?;
4853
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00004854 //check if super key exists
4855 assert!(db.key_exists(Domain::APP, 1, "USER_SUPER_KEY", KeyType::Super)?);
4856
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +00004857 let (_, key_entry) = db.load_super_key(1)?.unwrap();
Hasini Gunasingheda895552021-01-27 19:34:37 +00004858 let loaded_super_key = SuperKeyManager::extract_super_key_from_key_entry(key_entry, &pw)?;
4859
4860 let decrypted_secret_bytes = keystore2_crypto::aes_gcm_decrypt(
4861 &encrypted_secret,
4862 &iv,
4863 &tag,
4864 &loaded_super_key.get_key(),
4865 )?;
4866 let decrypted_secret = String::from_utf8((&decrypted_secret_bytes).to_vec())?;
4867 assert_eq!(String::from("keystore2 is great."), decrypted_secret);
4868 Ok(())
4869 }
Joel Galenson26f4d012020-07-17 14:57:21 -07004870}