blob: 6b74e3c8eb7df4b1777141d65308f06312850f53 [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
Matthew Maurerd7815ca2021-05-06 21:58:45 -070044mod perboot;
Janis Danisevskis030ba022021-05-26 11:15:30 -070045pub(crate) mod utils;
Janis Danisevskiscfaf9192021-05-26 16:31:02 -070046mod versioning;
Matthew Maurerd7815ca2021-05-06 21:58:45 -070047
Janis Danisevskis11bd2592022-01-04 19:59:26 -080048use crate::gc::Gc;
Hasini Gunasinghe1a8524b2022-05-10 08:49:53 +000049use crate::globals::get_keymint_dev_by_uuid;
Janis Danisevskisb42fc182020-12-15 08:41:27 -080050use crate::impl_metadata; // This is in db_utils.rs
Janis Danisevskis4522c2b2020-11-27 18:04:58 -080051use crate::key_parameter::{KeyParameter, Tag};
Hasini Gunasinghe8af67ea2021-06-30 17:09:01 +000052use crate::metrics_store::log_rkp_error_stats;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -070053use crate::permission::KeyPermSet;
Hasini Gunasinghe66a24602021-05-12 19:03:12 +000054use crate::utils::{get_current_time_in_milliseconds, watchdog as wd, AID_USER_OFFSET};
Janis Danisevskis7e8b4622021-02-13 10:01:59 -080055use crate::{
Paul Crowley7a658392021-03-18 17:08:20 -070056 error::{Error as KsError, ErrorCode, ResponseCode},
57 super_key::SuperKeyType,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -080058};
Janis Danisevskisb42fc182020-12-15 08:41:27 -080059use anyhow::{anyhow, Context, Result};
Max Bires8e93d2b2021-01-14 13:17:59 -080060use std::{convert::TryFrom, convert::TryInto, ops::Deref, time::SystemTimeError};
Janis Danisevskis030ba022021-05-26 11:15:30 -070061use utils as db_utils;
62use utils::SqlField;
Janis Danisevskis60400fe2020-08-26 15:24:42 -070063
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +000064use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
Janis Danisevskis5ed8c532021-01-11 14:19:42 -080065 HardwareAuthToken::HardwareAuthToken,
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +000066 HardwareAuthenticatorType::HardwareAuthenticatorType, SecurityLevel::SecurityLevel,
Janis Danisevskisc3a496b2021-01-05 10:37:22 -080067};
Janis Danisevskisc5b210b2020-09-11 13:27:37 -070068use android_system_keystore2::aidl::android::system::keystore2::{
Janis Danisevskis04b02832020-10-26 09:21:40 -070069 Domain::Domain, KeyDescriptor::KeyDescriptor,
Janis Danisevskis60400fe2020-08-26 15:24:42 -070070};
Max Bires2b2e6562020-09-22 11:22:36 -070071use android_security_remoteprovisioning::aidl::android::security::remoteprovisioning::{
72 AttestationPoolStatus::AttestationPoolStatus,
73};
Hasini Gunasinghe15891e62021-06-10 16:23:27 +000074use android_security_metrics::aidl::android::security::metrics::{
75 StorageStats::StorageStats,
76 Storage::Storage as MetricsStorage,
Hasini Gunasinghe8af67ea2021-06-30 17:09:01 +000077 RkpError::RkpError as MetricsRkpError,
Seth Moore78c091f2021-04-09 21:38:30 +000078};
Max Bires2b2e6562020-09-22 11:22:36 -070079
80use keystore2_crypto::ZVec;
Janis Danisevskisaec14592020-11-12 09:41:49 -080081use lazy_static::lazy_static;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +000082use log::error;
Joel Galenson0891bc12020-07-20 10:37:03 -070083#[cfg(not(test))]
84use rand::prelude::random;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -070085use rusqlite::{
Joel Galensonff79e362021-05-25 16:30:17 -070086 params, params_from_iter,
Janis Danisevskisb42fc182020-12-15 08:41:27 -080087 types::FromSql,
88 types::FromSqlResult,
89 types::ToSqlOutput,
90 types::{FromSqlError, Value, ValueRef},
Janis Danisevskis5ed8c532021-01-11 14:19:42 -080091 Connection, OptionalExtension, ToSql, Transaction, TransactionBehavior, NO_PARAMS,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -070092};
Max Bires2b2e6562020-09-22 11:22:36 -070093
Janis Danisevskisaec14592020-11-12 09:41:49 -080094use std::{
Janis Danisevskisb42fc182020-12-15 08:41:27 -080095 collections::{HashMap, HashSet},
Janis Danisevskisbf15d732020-12-08 10:35:26 -080096 path::Path,
Janis Danisevskis3395f862021-05-06 10:54:17 -070097 sync::{Arc, Condvar, Mutex},
Janis Danisevskisb42fc182020-12-15 08:41:27 -080098 time::{Duration, SystemTime},
Janis Danisevskisaec14592020-11-12 09:41:49 -080099};
Max Bires2b2e6562020-09-22 11:22:36 -0700100
Joel Galenson0891bc12020-07-20 10:37:03 -0700101#[cfg(test)]
102use tests::random;
Joel Galenson26f4d012020-07-17 14:57:21 -0700103
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800104impl_metadata!(
105 /// A set of metadata for key entries.
106 #[derive(Debug, Default, Eq, PartialEq)]
107 pub struct KeyMetaData;
108 /// A metadata entry for key entries.
109 #[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
110 pub enum KeyMetaEntry {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800111 /// Date of the creation of the key entry.
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800112 CreationDate(DateTime) with accessor creation_date,
113 /// Expiration date for attestation keys.
114 AttestationExpirationDate(DateTime) with accessor attestation_expiration_date,
Max Bires2b2e6562020-09-22 11:22:36 -0700115 /// CBOR Blob that represents a COSE_Key and associated metadata needed for remote
116 /// provisioning
117 AttestationMacedPublicKey(Vec<u8>) with accessor attestation_maced_public_key,
118 /// Vector representing the raw public key so results from the server can be matched
119 /// to the right entry
120 AttestationRawPubKey(Vec<u8>) with accessor attestation_raw_pub_key,
Paul Crowley8d5b2532021-03-19 10:53:07 -0700121 /// SEC1 public key for ECDH encryption
122 Sec1PublicKey(Vec<u8>) with accessor sec1_public_key,
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800123 // --- ADD NEW META DATA FIELDS HERE ---
124 // For backwards compatibility add new entries only to
125 // end of this list and above this comment.
126 };
127);
128
129impl KeyMetaData {
130 fn load_from_db(key_id: i64, tx: &Transaction) -> Result<Self> {
131 let mut stmt = tx
132 .prepare(
133 "SELECT tag, data from persistent.keymetadata
134 WHERE keyentryid = ?;",
135 )
136 .context("In KeyMetaData::load_from_db: prepare statement failed.")?;
137
138 let mut metadata: HashMap<i64, KeyMetaEntry> = Default::default();
139
140 let mut rows =
141 stmt.query(params![key_id]).context("In KeyMetaData::load_from_db: query failed.")?;
142 db_utils::with_rows_extract_all(&mut rows, |row| {
143 let db_tag: i64 = row.get(0).context("Failed to read tag.")?;
144 metadata.insert(
145 db_tag,
Chris Wailesd5aaaef2021-07-27 16:04:33 -0700146 KeyMetaEntry::new_from_sql(db_tag, &SqlField::new(1, row))
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800147 .context("Failed to read KeyMetaEntry.")?,
148 );
149 Ok(())
150 })
151 .context("In KeyMetaData::load_from_db.")?;
152
153 Ok(Self { data: metadata })
154 }
155
156 fn store_in_db(&self, key_id: i64, tx: &Transaction) -> Result<()> {
157 let mut stmt = tx
158 .prepare(
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000159 "INSERT or REPLACE INTO persistent.keymetadata (keyentryid, tag, data)
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800160 VALUES (?, ?, ?);",
161 )
162 .context("In KeyMetaData::store_in_db: Failed to prepare statement.")?;
163
164 let iter = self.data.iter();
165 for (tag, entry) in iter {
166 stmt.insert(params![key_id, tag, entry,]).with_context(|| {
167 format!("In KeyMetaData::store_in_db: Failed to insert {:?}", entry)
168 })?;
169 }
170 Ok(())
171 }
172}
173
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800174impl_metadata!(
175 /// A set of metadata for key blobs.
176 #[derive(Debug, Default, Eq, PartialEq)]
177 pub struct BlobMetaData;
178 /// A metadata entry for key blobs.
179 #[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
180 pub enum BlobMetaEntry {
181 /// If present, indicates that the blob is encrypted with another key or a key derived
182 /// from a password.
183 EncryptedBy(EncryptedBy) with accessor encrypted_by,
184 /// If the blob is password encrypted this field is set to the
185 /// salt used for the key derivation.
186 Salt(Vec<u8>) with accessor salt,
187 /// If the blob is encrypted, this field is set to the initialization vector.
188 Iv(Vec<u8>) with accessor iv,
189 /// If the blob is encrypted, this field holds the AEAD TAG.
190 AeadTag(Vec<u8>) with accessor aead_tag,
191 /// The uuid of the owning KeyMint instance.
192 KmUuid(Uuid) with accessor km_uuid,
Paul Crowley8d5b2532021-03-19 10:53:07 -0700193 /// If the key is ECDH encrypted, this is the ephemeral public key
194 PublicKey(Vec<u8>) with accessor public_key,
Paul Crowley44c02da2021-04-08 17:04:43 +0000195 /// If the key is encrypted with a MaxBootLevel key, this is the boot level
196 /// of that key
197 MaxBootLevel(i32) with accessor max_boot_level,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800198 // --- ADD NEW META DATA FIELDS HERE ---
199 // For backwards compatibility add new entries only to
200 // end of this list and above this comment.
201 };
202);
203
204impl BlobMetaData {
205 fn load_from_db(blob_id: i64, tx: &Transaction) -> Result<Self> {
206 let mut stmt = tx
207 .prepare(
208 "SELECT tag, data from persistent.blobmetadata
209 WHERE blobentryid = ?;",
210 )
211 .context("In BlobMetaData::load_from_db: prepare statement failed.")?;
212
213 let mut metadata: HashMap<i64, BlobMetaEntry> = Default::default();
214
215 let mut rows =
216 stmt.query(params![blob_id]).context("In BlobMetaData::load_from_db: query failed.")?;
217 db_utils::with_rows_extract_all(&mut rows, |row| {
218 let db_tag: i64 = row.get(0).context("Failed to read tag.")?;
219 metadata.insert(
220 db_tag,
Chris Wailesd5aaaef2021-07-27 16:04:33 -0700221 BlobMetaEntry::new_from_sql(db_tag, &SqlField::new(1, row))
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800222 .context("Failed to read BlobMetaEntry.")?,
223 );
224 Ok(())
225 })
226 .context("In BlobMetaData::load_from_db.")?;
227
228 Ok(Self { data: metadata })
229 }
230
231 fn store_in_db(&self, blob_id: i64, tx: &Transaction) -> Result<()> {
232 let mut stmt = tx
233 .prepare(
234 "INSERT or REPLACE INTO persistent.blobmetadata (blobentryid, tag, data)
235 VALUES (?, ?, ?);",
236 )
237 .context("In BlobMetaData::store_in_db: Failed to prepare statement.")?;
238
239 let iter = self.data.iter();
240 for (tag, entry) in iter {
241 stmt.insert(params![blob_id, tag, entry,]).with_context(|| {
242 format!("In BlobMetaData::store_in_db: Failed to insert {:?}", entry)
243 })?;
244 }
245 Ok(())
246 }
247}
248
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800249/// Indicates the type of the keyentry.
250#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
251pub enum KeyType {
252 /// This is a client key type. These keys are created or imported through the Keystore 2.0
253 /// AIDL interface android.system.keystore2.
254 Client,
255 /// This is a super key type. These keys are created by keystore itself and used to encrypt
256 /// other key blobs to provide LSKF binding.
257 Super,
258 /// This is an attestation key. These keys are created by the remote provisioning mechanism.
259 Attestation,
260}
261
262impl ToSql for KeyType {
263 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
264 Ok(ToSqlOutput::Owned(Value::Integer(match self {
265 KeyType::Client => 0,
266 KeyType::Super => 1,
267 KeyType::Attestation => 2,
268 })))
269 }
270}
271
272impl FromSql for KeyType {
273 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
274 match i64::column_result(value)? {
275 0 => Ok(KeyType::Client),
276 1 => Ok(KeyType::Super),
277 2 => Ok(KeyType::Attestation),
278 v => Err(FromSqlError::OutOfRange(v)),
279 }
280 }
281}
282
Max Bires8e93d2b2021-01-14 13:17:59 -0800283/// Uuid representation that can be stored in the database.
284/// Right now it can only be initialized from SecurityLevel.
285/// Once KeyMint provides a UUID type a corresponding From impl shall be added.
286#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
287pub struct Uuid([u8; 16]);
288
289impl Deref for Uuid {
290 type Target = [u8; 16];
291
292 fn deref(&self) -> &Self::Target {
293 &self.0
294 }
295}
296
297impl From<SecurityLevel> for Uuid {
298 fn from(sec_level: SecurityLevel) -> Self {
299 Self((sec_level.0 as u128).to_be_bytes())
300 }
301}
302
303impl ToSql for Uuid {
304 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
305 self.0.to_sql()
306 }
307}
308
309impl FromSql for Uuid {
310 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
311 let blob = Vec::<u8>::column_result(value)?;
312 if blob.len() != 16 {
313 return Err(FromSqlError::OutOfRange(blob.len() as i64));
314 }
315 let mut arr = [0u8; 16];
316 arr.copy_from_slice(&blob);
317 Ok(Self(arr))
318 }
319}
320
321/// Key entries that are not associated with any KeyMint instance, such as pure certificate
322/// entries are associated with this UUID.
323pub static KEYSTORE_UUID: Uuid = Uuid([
324 0x41, 0xe3, 0xb9, 0xce, 0x27, 0x58, 0x4e, 0x91, 0xbc, 0xfd, 0xa5, 0x5d, 0x91, 0x85, 0xab, 0x11,
325]);
326
Max Birescd7f7412022-02-11 13:47:36 -0800327static EXPIRATION_BUFFER_MS: i64 = 20000;
328
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800329/// Indicates how the sensitive part of this key blob is encrypted.
330#[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
331pub enum EncryptedBy {
332 /// The keyblob is encrypted by a user password.
333 /// In the database this variant is represented as NULL.
334 Password,
335 /// The keyblob is encrypted by another key with wrapped key id.
336 /// In the database this variant is represented as non NULL value
337 /// that is convertible to i64, typically NUMERIC.
338 KeyId(i64),
339}
340
341impl ToSql for EncryptedBy {
342 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
343 match self {
344 Self::Password => Ok(ToSqlOutput::Owned(Value::Null)),
345 Self::KeyId(id) => id.to_sql(),
346 }
347 }
348}
349
350impl FromSql for EncryptedBy {
351 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
352 match value {
353 ValueRef::Null => Ok(Self::Password),
354 _ => Ok(Self::KeyId(i64::column_result(value)?)),
355 }
356 }
357}
358
359/// A database representation of wall clock time. DateTime stores unix epoch time as
360/// i64 in milliseconds.
361#[derive(Debug, Copy, Clone, Default, Eq, PartialEq, Ord, PartialOrd)]
362pub struct DateTime(i64);
363
364/// Error type returned when creating DateTime or converting it from and to
365/// SystemTime.
366#[derive(thiserror::Error, Debug)]
367pub enum DateTimeError {
368 /// This is returned when SystemTime and Duration computations fail.
369 #[error(transparent)]
370 SystemTimeError(#[from] SystemTimeError),
371
372 /// This is returned when type conversions fail.
373 #[error(transparent)]
374 TypeConversion(#[from] std::num::TryFromIntError),
375
376 /// This is returned when checked time arithmetic failed.
377 #[error("Time arithmetic failed.")]
378 TimeArithmetic,
379}
380
381impl DateTime {
382 /// Constructs a new DateTime object denoting the current time. This may fail during
383 /// conversion to unix epoch time and during conversion to the internal i64 representation.
384 pub fn now() -> Result<Self, DateTimeError> {
385 Ok(Self(SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_millis().try_into()?))
386 }
387
388 /// Constructs a new DateTime object from milliseconds.
389 pub fn from_millis_epoch(millis: i64) -> Self {
390 Self(millis)
391 }
392
393 /// Returns unix epoch time in milliseconds.
Chris Wailes3877f292021-07-26 19:24:18 -0700394 pub fn to_millis_epoch(self) -> i64 {
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800395 self.0
396 }
397
398 /// Returns unix epoch time in seconds.
Chris Wailes3877f292021-07-26 19:24:18 -0700399 pub fn to_secs_epoch(self) -> i64 {
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800400 self.0 / 1000
401 }
402}
403
404impl ToSql for DateTime {
405 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
406 Ok(ToSqlOutput::Owned(Value::Integer(self.0)))
407 }
408}
409
410impl FromSql for DateTime {
411 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
412 Ok(Self(i64::column_result(value)?))
413 }
414}
415
416impl TryInto<SystemTime> for DateTime {
417 type Error = DateTimeError;
418
419 fn try_into(self) -> Result<SystemTime, Self::Error> {
420 // We want to construct a SystemTime representation equivalent to self, denoting
421 // a point in time THEN, but we cannot set the time directly. We can only construct
422 // a SystemTime denoting NOW, and we can get the duration between EPOCH and NOW,
423 // and between EPOCH and THEN. With this common reference we can construct the
424 // duration between NOW and THEN which we can add to our SystemTime representation
425 // of NOW to get a SystemTime representation of THEN.
426 // Durations can only be positive, thus the if statement below.
427 let now = SystemTime::now();
428 let now_epoch = now.duration_since(SystemTime::UNIX_EPOCH)?;
429 let then_epoch = Duration::from_millis(self.0.try_into()?);
430 Ok(if now_epoch > then_epoch {
431 // then = now - (now_epoch - then_epoch)
432 now_epoch
433 .checked_sub(then_epoch)
434 .and_then(|d| now.checked_sub(d))
435 .ok_or(DateTimeError::TimeArithmetic)?
436 } else {
437 // then = now + (then_epoch - now_epoch)
438 then_epoch
439 .checked_sub(now_epoch)
440 .and_then(|d| now.checked_add(d))
441 .ok_or(DateTimeError::TimeArithmetic)?
442 })
443 }
444}
445
446impl TryFrom<SystemTime> for DateTime {
447 type Error = DateTimeError;
448
449 fn try_from(t: SystemTime) -> Result<Self, Self::Error> {
450 Ok(Self(t.duration_since(SystemTime::UNIX_EPOCH)?.as_millis().try_into()?))
451 }
452}
453
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800454#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone)]
455enum KeyLifeCycle {
456 /// Existing keys have a key ID but are not fully populated yet.
457 /// This is a transient state. If Keystore finds any such keys when it starts up, it must move
458 /// them to Unreferenced for garbage collection.
459 Existing,
460 /// A live key is fully populated and usable by clients.
461 Live,
462 /// An unreferenced key is scheduled for garbage collection.
463 Unreferenced,
464}
465
466impl ToSql for KeyLifeCycle {
467 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
468 match self {
469 Self::Existing => Ok(ToSqlOutput::Owned(Value::Integer(0))),
470 Self::Live => Ok(ToSqlOutput::Owned(Value::Integer(1))),
471 Self::Unreferenced => Ok(ToSqlOutput::Owned(Value::Integer(2))),
472 }
473 }
474}
475
476impl FromSql for KeyLifeCycle {
477 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
478 match i64::column_result(value)? {
479 0 => Ok(KeyLifeCycle::Existing),
480 1 => Ok(KeyLifeCycle::Live),
481 2 => Ok(KeyLifeCycle::Unreferenced),
482 v => Err(FromSqlError::OutOfRange(v)),
483 }
484 }
485}
486
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700487/// Keys have a KeyMint blob component and optional public certificate and
488/// certificate chain components.
489/// KeyEntryLoadBits is a bitmap that indicates to `KeystoreDB::load_key_entry`
490/// which components shall be loaded from the database if present.
Janis Danisevskis66784c42021-01-27 08:40:25 -0800491#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700492pub struct KeyEntryLoadBits(u32);
493
494impl KeyEntryLoadBits {
495 /// Indicate to `KeystoreDB::load_key_entry` that no component shall be loaded.
496 pub const NONE: KeyEntryLoadBits = Self(0);
497 /// Indicate to `KeystoreDB::load_key_entry` that the KeyMint component shall be loaded.
498 pub const KM: KeyEntryLoadBits = Self(1);
499 /// Indicate to `KeystoreDB::load_key_entry` that the Public components shall be loaded.
500 pub const PUBLIC: KeyEntryLoadBits = Self(2);
501 /// Indicate to `KeystoreDB::load_key_entry` that both components shall be loaded.
502 pub const BOTH: KeyEntryLoadBits = Self(3);
503
504 /// Returns true if this object indicates that the public components shall be loaded.
505 pub const fn load_public(&self) -> bool {
506 self.0 & Self::PUBLIC.0 != 0
507 }
508
509 /// Returns true if the object indicates that the KeyMint component shall be loaded.
510 pub const fn load_km(&self) -> bool {
511 self.0 & Self::KM.0 != 0
512 }
513}
514
Janis Danisevskisaec14592020-11-12 09:41:49 -0800515lazy_static! {
516 static ref KEY_ID_LOCK: KeyIdLockDb = KeyIdLockDb::new();
517}
518
519struct KeyIdLockDb {
520 locked_keys: Mutex<HashSet<i64>>,
521 cond_var: Condvar,
522}
523
524/// A locked key. While a guard exists for a given key id, the same key cannot be loaded
525/// from the database a second time. Most functions manipulating the key blob database
526/// require a KeyIdGuard.
527#[derive(Debug)]
528pub struct KeyIdGuard(i64);
529
530impl KeyIdLockDb {
531 fn new() -> Self {
532 Self { locked_keys: Mutex::new(HashSet::new()), cond_var: Condvar::new() }
533 }
534
535 /// This function blocks until an exclusive lock for the given key entry id can
536 /// be acquired. It returns a guard object, that represents the lifecycle of the
537 /// acquired lock.
538 pub fn get(&self, key_id: i64) -> KeyIdGuard {
539 let mut locked_keys = self.locked_keys.lock().unwrap();
540 while locked_keys.contains(&key_id) {
541 locked_keys = self.cond_var.wait(locked_keys).unwrap();
542 }
543 locked_keys.insert(key_id);
544 KeyIdGuard(key_id)
545 }
546
547 /// This function attempts to acquire an exclusive lock on a given key id. If the
548 /// given key id is already taken the function returns None immediately. If a lock
549 /// can be acquired this function returns a guard object, that represents the
550 /// lifecycle of the acquired lock.
551 pub fn try_get(&self, key_id: i64) -> Option<KeyIdGuard> {
552 let mut locked_keys = self.locked_keys.lock().unwrap();
553 if locked_keys.insert(key_id) {
554 Some(KeyIdGuard(key_id))
555 } else {
556 None
557 }
558 }
559}
560
561impl KeyIdGuard {
562 /// Get the numeric key id of the locked key.
563 pub fn id(&self) -> i64 {
564 self.0
565 }
566}
567
568impl Drop for KeyIdGuard {
569 fn drop(&mut self) {
570 let mut locked_keys = KEY_ID_LOCK.locked_keys.lock().unwrap();
571 locked_keys.remove(&self.0);
Janis Danisevskis7fd53582020-11-23 13:40:34 -0800572 drop(locked_keys);
Janis Danisevskisaec14592020-11-12 09:41:49 -0800573 KEY_ID_LOCK.cond_var.notify_all();
574 }
575}
576
Max Bires8e93d2b2021-01-14 13:17:59 -0800577/// This type represents a certificate and certificate chain entry for a key.
Max Bires2b2e6562020-09-22 11:22:36 -0700578#[derive(Debug, Default)]
Max Bires8e93d2b2021-01-14 13:17:59 -0800579pub struct CertificateInfo {
580 cert: Option<Vec<u8>>,
581 cert_chain: Option<Vec<u8>>,
582}
583
Janis Danisevskisf84d0b02022-01-26 14:11:14 -0800584/// This type represents a Blob with its metadata and an optional superseded blob.
585#[derive(Debug)]
586pub struct BlobInfo<'a> {
587 blob: &'a [u8],
588 metadata: &'a BlobMetaData,
589 /// Superseded blobs are an artifact of legacy import. In some rare occasions
590 /// the key blob needs to be upgraded during import. In that case two
591 /// blob are imported, the superseded one will have to be imported first,
592 /// so that the garbage collector can reap it.
593 superseded_blob: Option<(&'a [u8], &'a BlobMetaData)>,
594}
595
596impl<'a> BlobInfo<'a> {
597 /// Create a new instance of blob info with blob and corresponding metadata
598 /// and no superseded blob info.
599 pub fn new(blob: &'a [u8], metadata: &'a BlobMetaData) -> Self {
600 Self { blob, metadata, superseded_blob: None }
601 }
602
603 /// Create a new instance of blob info with blob and corresponding metadata
604 /// as well as superseded blob info.
605 pub fn new_with_superseded(
606 blob: &'a [u8],
607 metadata: &'a BlobMetaData,
608 superseded_blob: Option<(&'a [u8], &'a BlobMetaData)>,
609 ) -> Self {
610 Self { blob, metadata, superseded_blob }
611 }
612}
613
Max Bires8e93d2b2021-01-14 13:17:59 -0800614impl CertificateInfo {
615 /// Constructs a new CertificateInfo object from `cert` and `cert_chain`
616 pub fn new(cert: Option<Vec<u8>>, cert_chain: Option<Vec<u8>>) -> Self {
617 Self { cert, cert_chain }
618 }
619
620 /// Take the cert
621 pub fn take_cert(&mut self) -> Option<Vec<u8>> {
622 self.cert.take()
623 }
624
625 /// Take the cert chain
626 pub fn take_cert_chain(&mut self) -> Option<Vec<u8>> {
627 self.cert_chain.take()
628 }
629}
630
Max Bires2b2e6562020-09-22 11:22:36 -0700631/// This type represents a certificate chain with a private key corresponding to the leaf
632/// 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 -0700633pub struct CertificateChain {
Max Bires97f96812021-02-23 23:44:57 -0800634 /// A KM key blob
635 pub private_key: ZVec,
636 /// A batch cert for private_key
637 pub batch_cert: Vec<u8>,
638 /// A full certificate chain from root signing authority to private_key, including batch_cert
639 /// for convenience.
640 pub cert_chain: Vec<u8>,
Max Bires2b2e6562020-09-22 11:22:36 -0700641}
642
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700643/// This type represents a Keystore 2.0 key entry.
644/// An entry has a unique `id` by which it can be found in the database.
645/// It has a security level field, key parameters, and three optional fields
646/// for the KeyMint blob, public certificate and a public certificate chain.
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800647#[derive(Debug, Default, Eq, PartialEq)]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700648pub struct KeyEntry {
649 id: i64,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800650 key_blob_info: Option<(Vec<u8>, BlobMetaData)>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700651 cert: Option<Vec<u8>>,
652 cert_chain: Option<Vec<u8>>,
Max Bires8e93d2b2021-01-14 13:17:59 -0800653 km_uuid: Uuid,
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700654 parameters: Vec<KeyParameter>,
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800655 metadata: KeyMetaData,
Janis Danisevskis377d1002021-01-27 19:07:48 -0800656 pure_cert: bool,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700657}
658
659impl KeyEntry {
660 /// Returns the unique id of the Key entry.
661 pub fn id(&self) -> i64 {
662 self.id
663 }
664 /// Exposes the optional KeyMint blob.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800665 pub fn key_blob_info(&self) -> &Option<(Vec<u8>, BlobMetaData)> {
666 &self.key_blob_info
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700667 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800668 /// Extracts the Optional KeyMint blob including its metadata.
669 pub fn take_key_blob_info(&mut self) -> Option<(Vec<u8>, BlobMetaData)> {
670 self.key_blob_info.take()
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700671 }
672 /// Exposes the optional public certificate.
673 pub fn cert(&self) -> &Option<Vec<u8>> {
674 &self.cert
675 }
676 /// Extracts the optional public certificate.
677 pub fn take_cert(&mut self) -> Option<Vec<u8>> {
678 self.cert.take()
679 }
680 /// Exposes the optional public certificate chain.
681 pub fn cert_chain(&self) -> &Option<Vec<u8>> {
682 &self.cert_chain
683 }
684 /// Extracts the optional public certificate_chain.
685 pub fn take_cert_chain(&mut self) -> Option<Vec<u8>> {
686 self.cert_chain.take()
687 }
Max Bires8e93d2b2021-01-14 13:17:59 -0800688 /// Returns the uuid of the owning KeyMint instance.
689 pub fn km_uuid(&self) -> &Uuid {
690 &self.km_uuid
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700691 }
Janis Danisevskis04b02832020-10-26 09:21:40 -0700692 /// Exposes the key parameters of this key entry.
693 pub fn key_parameters(&self) -> &Vec<KeyParameter> {
694 &self.parameters
695 }
696 /// Consumes this key entry and extracts the keyparameters from it.
697 pub fn into_key_parameters(self) -> Vec<KeyParameter> {
698 self.parameters
699 }
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800700 /// Exposes the key metadata of this key entry.
701 pub fn metadata(&self) -> &KeyMetaData {
702 &self.metadata
703 }
Janis Danisevskis377d1002021-01-27 19:07:48 -0800704 /// This returns true if the entry is a pure certificate entry with no
705 /// private key component.
706 pub fn pure_cert(&self) -> bool {
707 self.pure_cert
708 }
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000709 /// Consumes this key entry and extracts the keyparameters and metadata from it.
710 pub fn into_key_parameters_and_metadata(self) -> (Vec<KeyParameter>, KeyMetaData) {
711 (self.parameters, self.metadata)
712 }
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700713}
714
715/// Indicates the sub component of a key entry for persistent storage.
Janis Danisevskis377d1002021-01-27 19:07:48 -0800716#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700717pub struct SubComponentType(u32);
718impl SubComponentType {
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800719 /// Persistent identifier for a key blob.
720 pub const KEY_BLOB: SubComponentType = Self(0);
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700721 /// Persistent identifier for a certificate blob.
722 pub const CERT: SubComponentType = Self(1);
723 /// Persistent identifier for a certificate chain blob.
724 pub const CERT_CHAIN: SubComponentType = Self(2);
725}
726
727impl ToSql for SubComponentType {
728 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
729 self.0.to_sql()
730 }
731}
732
733impl FromSql for SubComponentType {
734 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
735 Ok(Self(u32::column_result(value)?))
736 }
737}
738
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800739/// This trait is private to the database module. It is used to convey whether or not the garbage
740/// collector shall be invoked after a database access. All closures passed to
741/// `KeystoreDB::with_transaction` return a tuple (bool, T) where the bool indicates if the
742/// gc needs to be triggered. This convenience function allows to turn any anyhow::Result<T>
743/// into anyhow::Result<(bool, T)> by simply appending one of `.do_gc(bool)`, `.no_gc()`, or
744/// `.need_gc()`.
745trait DoGc<T> {
746 fn do_gc(self, need_gc: bool) -> Result<(bool, T)>;
747
748 fn no_gc(self) -> Result<(bool, T)>;
749
750 fn need_gc(self) -> Result<(bool, T)>;
751}
752
753impl<T> DoGc<T> for Result<T> {
754 fn do_gc(self, need_gc: bool) -> Result<(bool, T)> {
755 self.map(|r| (need_gc, r))
756 }
757
758 fn no_gc(self) -> Result<(bool, T)> {
759 self.do_gc(false)
760 }
761
762 fn need_gc(self) -> Result<(bool, T)> {
763 self.do_gc(true)
764 }
765}
766
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700767/// KeystoreDB wraps a connection to an SQLite database and tracks its
768/// ownership. It also implements all of Keystore 2.0's database functionality.
Joel Galenson26f4d012020-07-17 14:57:21 -0700769pub struct KeystoreDB {
Joel Galenson26f4d012020-07-17 14:57:21 -0700770 conn: Connection,
Janis Danisevskis3395f862021-05-06 10:54:17 -0700771 gc: Option<Arc<Gc>>,
Matthew Maurerd7815ca2021-05-06 21:58:45 -0700772 perboot: Arc<perboot::PerbootDB>,
Joel Galenson26f4d012020-07-17 14:57:21 -0700773}
774
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000775/// Database representation of the monotonic time retrieved from the system call clock_gettime with
Hasini Gunasinghe66a24602021-05-12 19:03:12 +0000776/// CLOCK_MONOTONIC_RAW. Stores monotonic time as i64 in milliseconds.
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000777#[derive(Debug, Copy, Clone, Default, Eq, PartialEq, Ord, PartialOrd)]
778pub struct MonotonicRawTime(i64);
779
780impl MonotonicRawTime {
781 /// Constructs a new MonotonicRawTime
782 pub fn now() -> Self {
Hasini Gunasinghe66a24602021-05-12 19:03:12 +0000783 Self(get_current_time_in_milliseconds())
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000784 }
785
Hasini Gunasinghe66a24602021-05-12 19:03:12 +0000786 /// Returns the value of MonotonicRawTime in milliseconds as i64
787 pub fn milliseconds(&self) -> i64 {
788 self.0
David Drysdale0e45a612021-02-25 17:24:36 +0000789 }
790
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000791 /// Returns the integer value of MonotonicRawTime as i64
792 pub fn seconds(&self) -> i64 {
Hasini Gunasinghe66a24602021-05-12 19:03:12 +0000793 self.0 / 1000
Hasini Gunasingheb3715fb2021-02-26 20:34:45 +0000794 }
795
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800796 /// Like i64::checked_sub.
797 pub fn checked_sub(&self, other: &Self) -> Option<Self> {
798 self.0.checked_sub(other.0).map(Self)
799 }
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000800}
801
802impl ToSql for MonotonicRawTime {
803 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
804 Ok(ToSqlOutput::Owned(Value::Integer(self.0)))
805 }
806}
807
808impl FromSql for MonotonicRawTime {
809 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
810 Ok(Self(i64::column_result(value)?))
811 }
812}
813
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000814/// This struct encapsulates the information to be stored in the database about the auth tokens
815/// received by keystore.
Matthew Maurerd7815ca2021-05-06 21:58:45 -0700816#[derive(Clone)]
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000817pub struct AuthTokenEntry {
818 auth_token: HardwareAuthToken,
Hasini Gunasinghe66a24602021-05-12 19:03:12 +0000819 // Time received in milliseconds
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000820 time_received: MonotonicRawTime,
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000821}
822
823impl AuthTokenEntry {
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000824 fn new(auth_token: HardwareAuthToken, time_received: MonotonicRawTime) -> Self {
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000825 AuthTokenEntry { auth_token, time_received }
826 }
827
828 /// Checks if this auth token satisfies the given authentication information.
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800829 pub fn satisfies(&self, user_secure_ids: &[i64], auth_type: HardwareAuthenticatorType) -> bool {
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000830 user_secure_ids.iter().any(|&sid| {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800831 (sid == self.auth_token.userId || sid == self.auth_token.authenticatorId)
832 && (((auth_type.0 as i32) & (self.auth_token.authenticatorType.0 as i32)) != 0)
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000833 })
834 }
835
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000836 /// Returns the auth token wrapped by the AuthTokenEntry
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800837 pub fn auth_token(&self) -> &HardwareAuthToken {
838 &self.auth_token
839 }
840
841 /// Returns the auth token wrapped by the AuthTokenEntry
842 pub fn take_auth_token(self) -> HardwareAuthToken {
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000843 self.auth_token
844 }
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800845
846 /// Returns the time that this auth token was received.
847 pub fn time_received(&self) -> MonotonicRawTime {
848 self.time_received
849 }
Hasini Gunasingheb3715fb2021-02-26 20:34:45 +0000850
851 /// Returns the challenge value of the auth token.
852 pub fn challenge(&self) -> i64 {
853 self.auth_token.challenge
854 }
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000855}
856
Janis Danisevskisb00ebd02021-02-02 21:52:24 -0800857/// Shared in-memory databases get destroyed as soon as the last connection to them gets closed.
858/// This object does not allow access to the database connection. But it keeps a database
859/// connection alive in order to keep the in memory per boot database alive.
860pub struct PerBootDbKeepAlive(Connection);
861
Joel Galenson26f4d012020-07-17 14:57:21 -0700862impl KeystoreDB {
Janis Danisevskiseed69842021-02-18 20:04:10 -0800863 const UNASSIGNED_KEY_ID: i64 = -1i64;
Janis Danisevskiscfaf9192021-05-26 16:31:02 -0700864 const CURRENT_DB_VERSION: u32 = 1;
865 const UPGRADERS: &'static [fn(&Transaction) -> Result<u32>] = &[Self::from_0_to_1];
Janis Danisevskisb00ebd02021-02-02 21:52:24 -0800866
Seth Moore78c091f2021-04-09 21:38:30 +0000867 /// Name of the file that holds the cross-boot persistent database.
Chris Wailesd5aaaef2021-07-27 16:04:33 -0700868 pub const PERSISTENT_DB_FILENAME: &'static str = "persistent.sqlite";
Seth Moore78c091f2021-04-09 21:38:30 +0000869
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700870 /// This will create a new database connection connecting the two
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800871 /// files persistent.sqlite and perboot.sqlite in the given directory.
872 /// It also attempts to initialize all of the tables.
873 /// KeystoreDB cannot be used by multiple threads.
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700874 /// Each thread should open their own connection using `thread_local!`.
Janis Danisevskis3395f862021-05-06 10:54:17 -0700875 pub fn new(db_root: &Path, gc: Option<Arc<Gc>>) -> Result<Self> {
Janis Danisevskis850d4862021-05-05 08:41:14 -0700876 let _wp = wd::watch_millis("KeystoreDB::new", 500);
877
Chris Wailesd5aaaef2021-07-27 16:04:33 -0700878 let persistent_path = Self::make_persistent_path(db_root)?;
Seth Moore472fcbb2021-05-12 10:07:51 -0700879 let conn = Self::make_connection(&persistent_path)?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800880
Matthew Maurerd7815ca2021-05-06 21:58:45 -0700881 let mut db = Self { conn, gc, perboot: perboot::PERBOOT_DB.clone() };
Janis Danisevskis66784c42021-01-27 08:40:25 -0800882 db.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskiscfaf9192021-05-26 16:31:02 -0700883 versioning::upgrade_database(tx, Self::CURRENT_DB_VERSION, Self::UPGRADERS)
884 .context("In KeystoreDB::new: trying to upgrade database.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800885 Self::init_tables(tx).context("Trying to initialize tables.").no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -0800886 })?;
887 Ok(db)
Joel Galenson2aab4432020-07-22 15:27:57 -0700888 }
889
Janis Danisevskiscfaf9192021-05-26 16:31:02 -0700890 // This upgrade function deletes all MAX_BOOT_LEVEL keys, that were generated before
891 // cryptographic binding to the boot level keys was implemented.
892 fn from_0_to_1(tx: &Transaction) -> Result<u32> {
893 tx.execute(
894 "UPDATE persistent.keyentry SET state = ?
895 WHERE
896 id IN (SELECT keyentryid FROM persistent.keyparameter WHERE tag = ?)
897 AND
898 id NOT IN (
899 SELECT keyentryid FROM persistent.blobentry
900 WHERE id IN (
901 SELECT blobentryid FROM persistent.blobmetadata WHERE tag = ?
902 )
903 );",
904 params![KeyLifeCycle::Unreferenced, Tag::MAX_BOOT_LEVEL.0, BlobMetaData::MaxBootLevel],
905 )
906 .context("In from_0_to_1: Failed to delete logical boot level keys.")?;
907 Ok(1)
908 }
909
Janis Danisevskis66784c42021-01-27 08:40:25 -0800910 fn init_tables(tx: &Transaction) -> Result<()> {
911 tx.execute(
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700912 "CREATE TABLE IF NOT EXISTS persistent.keyentry (
Joel Galenson0891bc12020-07-20 10:37:03 -0700913 id INTEGER UNIQUE,
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800914 key_type INTEGER,
Joel Galenson0891bc12020-07-20 10:37:03 -0700915 domain INTEGER,
916 namespace INTEGER,
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800917 alias BLOB,
Max Bires8e93d2b2021-01-14 13:17:59 -0800918 state INTEGER,
919 km_uuid BLOB);",
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700920 NO_PARAMS,
921 )
922 .context("Failed to initialize \"keyentry\" table.")?;
923
Janis Danisevskis66784c42021-01-27 08:40:25 -0800924 tx.execute(
Janis Danisevskisa5438182021-02-02 14:22:59 -0800925 "CREATE INDEX IF NOT EXISTS persistent.keyentry_id_index
926 ON keyentry(id);",
927 NO_PARAMS,
928 )
929 .context("Failed to create index keyentry_id_index.")?;
930
931 tx.execute(
932 "CREATE INDEX IF NOT EXISTS persistent.keyentry_domain_namespace_index
933 ON keyentry(domain, namespace, alias);",
934 NO_PARAMS,
935 )
936 .context("Failed to create index keyentry_domain_namespace_index.")?;
937
938 tx.execute(
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700939 "CREATE TABLE IF NOT EXISTS persistent.blobentry (
940 id INTEGER PRIMARY KEY,
941 subcomponent_type INTEGER,
942 keyentryid INTEGER,
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800943 blob BLOB);",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700944 NO_PARAMS,
945 )
946 .context("Failed to initialize \"blobentry\" table.")?;
947
Janis Danisevskis66784c42021-01-27 08:40:25 -0800948 tx.execute(
Janis Danisevskisa5438182021-02-02 14:22:59 -0800949 "CREATE INDEX IF NOT EXISTS persistent.blobentry_keyentryid_index
950 ON blobentry(keyentryid);",
951 NO_PARAMS,
952 )
953 .context("Failed to create index blobentry_keyentryid_index.")?;
954
955 tx.execute(
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800956 "CREATE TABLE IF NOT EXISTS persistent.blobmetadata (
957 id INTEGER PRIMARY KEY,
958 blobentryid INTEGER,
959 tag INTEGER,
960 data ANY,
961 UNIQUE (blobentryid, tag));",
962 NO_PARAMS,
963 )
964 .context("Failed to initialize \"blobmetadata\" table.")?;
965
966 tx.execute(
967 "CREATE INDEX IF NOT EXISTS persistent.blobmetadata_blobentryid_index
968 ON blobmetadata(blobentryid);",
969 NO_PARAMS,
970 )
971 .context("Failed to create index blobmetadata_blobentryid_index.")?;
972
973 tx.execute(
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700974 "CREATE TABLE IF NOT EXISTS persistent.keyparameter (
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000975 keyentryid INTEGER,
976 tag INTEGER,
977 data ANY,
978 security_level INTEGER);",
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700979 NO_PARAMS,
980 )
981 .context("Failed to initialize \"keyparameter\" table.")?;
982
Janis Danisevskis66784c42021-01-27 08:40:25 -0800983 tx.execute(
Janis Danisevskisa5438182021-02-02 14:22:59 -0800984 "CREATE INDEX IF NOT EXISTS persistent.keyparameter_keyentryid_index
985 ON keyparameter(keyentryid);",
986 NO_PARAMS,
987 )
988 .context("Failed to create index keyparameter_keyentryid_index.")?;
989
990 tx.execute(
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800991 "CREATE TABLE IF NOT EXISTS persistent.keymetadata (
992 keyentryid INTEGER,
993 tag INTEGER,
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000994 data ANY,
995 UNIQUE (keyentryid, tag));",
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800996 NO_PARAMS,
997 )
998 .context("Failed to initialize \"keymetadata\" table.")?;
999
Janis Danisevskis66784c42021-01-27 08:40:25 -08001000 tx.execute(
Janis Danisevskisa5438182021-02-02 14:22:59 -08001001 "CREATE INDEX IF NOT EXISTS persistent.keymetadata_keyentryid_index
1002 ON keymetadata(keyentryid);",
1003 NO_PARAMS,
1004 )
1005 .context("Failed to create index keymetadata_keyentryid_index.")?;
1006
1007 tx.execute(
Janis Danisevskisbf15d732020-12-08 10:35:26 -08001008 "CREATE TABLE IF NOT EXISTS persistent.grant (
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001009 id INTEGER UNIQUE,
1010 grantee INTEGER,
1011 keyentryid INTEGER,
1012 access_vector INTEGER);",
1013 NO_PARAMS,
1014 )
1015 .context("Failed to initialize \"grant\" table.")?;
1016
Joel Galenson0891bc12020-07-20 10:37:03 -07001017 Ok(())
1018 }
1019
Seth Moore472fcbb2021-05-12 10:07:51 -07001020 fn make_persistent_path(db_root: &Path) -> Result<String> {
1021 // Build the path to the sqlite file.
1022 let mut persistent_path = db_root.to_path_buf();
1023 persistent_path.push(Self::PERSISTENT_DB_FILENAME);
1024
1025 // Now convert them to strings prefixed with "file:"
1026 let mut persistent_path_str = "file:".to_owned();
1027 persistent_path_str.push_str(&persistent_path.to_string_lossy());
1028
1029 Ok(persistent_path_str)
1030 }
1031
Matthew Maurerd7815ca2021-05-06 21:58:45 -07001032 fn make_connection(persistent_file: &str) -> Result<Connection> {
Janis Danisevskis4df44f42020-08-26 14:40:03 -07001033 let conn =
1034 Connection::open_in_memory().context("Failed to initialize SQLite connection.")?;
1035
Janis Danisevskis66784c42021-01-27 08:40:25 -08001036 loop {
1037 if let Err(e) = conn
1038 .execute("ATTACH DATABASE ? as persistent;", params![persistent_file])
1039 .context("Failed to attach database persistent.")
1040 {
1041 if Self::is_locked_error(&e) {
1042 std::thread::sleep(std::time::Duration::from_micros(500));
1043 continue;
1044 } else {
1045 return Err(e);
1046 }
1047 }
1048 break;
1049 }
Janis Danisevskis4df44f42020-08-26 14:40:03 -07001050
Matthew Maurer4fb19112021-05-06 15:40:44 -07001051 // Drop the cache size from default (2M) to 0.5M
1052 conn.execute("PRAGMA persistent.cache_size = -500;", params![])
1053 .context("Failed to decrease cache size for persistent db")?;
Matthew Maurer4fb19112021-05-06 15:40:44 -07001054
Janis Danisevskis4df44f42020-08-26 14:40:03 -07001055 Ok(conn)
1056 }
1057
Seth Moore78c091f2021-04-09 21:38:30 +00001058 fn do_table_size_query(
1059 &mut self,
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001060 storage_type: MetricsStorage,
Seth Moore78c091f2021-04-09 21:38:30 +00001061 query: &str,
1062 params: &[&str],
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001063 ) -> Result<StorageStats> {
Seth Moore78c091f2021-04-09 21:38:30 +00001064 let (total, unused) = self.with_transaction(TransactionBehavior::Deferred, |tx| {
Joel Galensonff79e362021-05-25 16:30:17 -07001065 tx.query_row(query, params_from_iter(params), |row| Ok((row.get(0)?, row.get(1)?)))
Seth Moore78c091f2021-04-09 21:38:30 +00001066 .with_context(|| {
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001067 format!("get_storage_stat: Error size of storage type {}", storage_type.0)
Seth Moore78c091f2021-04-09 21:38:30 +00001068 })
1069 .no_gc()
1070 })?;
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001071 Ok(StorageStats { storage_type, size: total, unused_size: unused })
Seth Moore78c091f2021-04-09 21:38:30 +00001072 }
1073
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001074 fn get_total_size(&mut self) -> Result<StorageStats> {
Seth Moore78c091f2021-04-09 21:38:30 +00001075 self.do_table_size_query(
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001076 MetricsStorage::DATABASE,
Seth Moore78c091f2021-04-09 21:38:30 +00001077 "SELECT page_count * page_size, freelist_count * page_size
1078 FROM pragma_page_count('persistent'),
1079 pragma_page_size('persistent'),
1080 persistent.pragma_freelist_count();",
1081 &[],
1082 )
1083 }
1084
1085 fn get_table_size(
1086 &mut self,
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001087 storage_type: MetricsStorage,
Seth Moore78c091f2021-04-09 21:38:30 +00001088 schema: &str,
1089 table: &str,
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001090 ) -> Result<StorageStats> {
Seth Moore78c091f2021-04-09 21:38:30 +00001091 self.do_table_size_query(
1092 storage_type,
1093 "SELECT pgsize,unused FROM dbstat(?1)
1094 WHERE name=?2 AND aggregate=TRUE;",
1095 &[schema, table],
1096 )
1097 }
1098
1099 /// Fetches a storage statisitics atom for a given storage type. For storage
1100 /// types that map to a table, information about the table's storage is
1101 /// returned. Requests for storage types that are not DB tables return None.
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001102 pub fn get_storage_stat(&mut self, storage_type: MetricsStorage) -> Result<StorageStats> {
Janis Danisevskis850d4862021-05-05 08:41:14 -07001103 let _wp = wd::watch_millis("KeystoreDB::get_storage_stat", 500);
1104
Seth Moore78c091f2021-04-09 21:38:30 +00001105 match storage_type {
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001106 MetricsStorage::DATABASE => self.get_total_size(),
1107 MetricsStorage::KEY_ENTRY => {
Seth Moore78c091f2021-04-09 21:38:30 +00001108 self.get_table_size(storage_type, "persistent", "keyentry")
1109 }
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001110 MetricsStorage::KEY_ENTRY_ID_INDEX => {
Seth Moore78c091f2021-04-09 21:38:30 +00001111 self.get_table_size(storage_type, "persistent", "keyentry_id_index")
1112 }
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001113 MetricsStorage::KEY_ENTRY_DOMAIN_NAMESPACE_INDEX => {
Seth Moore78c091f2021-04-09 21:38:30 +00001114 self.get_table_size(storage_type, "persistent", "keyentry_domain_namespace_index")
1115 }
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001116 MetricsStorage::BLOB_ENTRY => {
Seth Moore78c091f2021-04-09 21:38:30 +00001117 self.get_table_size(storage_type, "persistent", "blobentry")
1118 }
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001119 MetricsStorage::BLOB_ENTRY_KEY_ENTRY_ID_INDEX => {
Seth Moore78c091f2021-04-09 21:38:30 +00001120 self.get_table_size(storage_type, "persistent", "blobentry_keyentryid_index")
1121 }
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001122 MetricsStorage::KEY_PARAMETER => {
Seth Moore78c091f2021-04-09 21:38:30 +00001123 self.get_table_size(storage_type, "persistent", "keyparameter")
1124 }
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001125 MetricsStorage::KEY_PARAMETER_KEY_ENTRY_ID_INDEX => {
Seth Moore78c091f2021-04-09 21:38:30 +00001126 self.get_table_size(storage_type, "persistent", "keyparameter_keyentryid_index")
1127 }
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001128 MetricsStorage::KEY_METADATA => {
Seth Moore78c091f2021-04-09 21:38:30 +00001129 self.get_table_size(storage_type, "persistent", "keymetadata")
1130 }
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001131 MetricsStorage::KEY_METADATA_KEY_ENTRY_ID_INDEX => {
Seth Moore78c091f2021-04-09 21:38:30 +00001132 self.get_table_size(storage_type, "persistent", "keymetadata_keyentryid_index")
1133 }
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001134 MetricsStorage::GRANT => self.get_table_size(storage_type, "persistent", "grant"),
1135 MetricsStorage::AUTH_TOKEN => {
Matthew Maurerd7815ca2021-05-06 21:58:45 -07001136 // Since the table is actually a BTreeMap now, unused_size is not meaningfully
1137 // reportable
1138 // Size provided is only an approximation
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001139 Ok(StorageStats {
Matthew Maurerd7815ca2021-05-06 21:58:45 -07001140 storage_type,
1141 size: (self.perboot.auth_tokens_len() * std::mem::size_of::<AuthTokenEntry>())
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001142 as i32,
Matthew Maurerd7815ca2021-05-06 21:58:45 -07001143 unused_size: 0,
1144 })
Seth Moore78c091f2021-04-09 21:38:30 +00001145 }
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001146 MetricsStorage::BLOB_METADATA => {
Seth Moore78c091f2021-04-09 21:38:30 +00001147 self.get_table_size(storage_type, "persistent", "blobmetadata")
1148 }
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001149 MetricsStorage::BLOB_METADATA_BLOB_ENTRY_ID_INDEX => {
Seth Moore78c091f2021-04-09 21:38:30 +00001150 self.get_table_size(storage_type, "persistent", "blobmetadata_blobentryid_index")
1151 }
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001152 _ => Err(anyhow::Error::msg(format!("Unsupported storage type: {}", storage_type.0))),
Seth Moore78c091f2021-04-09 21:38:30 +00001153 }
1154 }
1155
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001156 /// This function is intended to be used by the garbage collector.
Janis Danisevskis3395f862021-05-06 10:54:17 -07001157 /// It deletes the blobs given by `blob_ids_to_delete`. It then tries to find up to `max_blobs`
1158 /// superseded key blobs that might need special handling by the garbage collector.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001159 /// If no further superseded blobs can be found it deletes all other superseded blobs that don't
1160 /// need special handling and returns None.
Janis Danisevskis3395f862021-05-06 10:54:17 -07001161 pub fn handle_next_superseded_blobs(
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001162 &mut self,
Janis Danisevskis3395f862021-05-06 10:54:17 -07001163 blob_ids_to_delete: &[i64],
1164 max_blobs: usize,
1165 ) -> Result<Vec<(i64, Vec<u8>, BlobMetaData)>> {
Janis Danisevskis850d4862021-05-05 08:41:14 -07001166 let _wp = wd::watch_millis("KeystoreDB::handle_next_superseded_blob", 500);
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001167 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis3395f862021-05-06 10:54:17 -07001168 // Delete the given blobs.
1169 for blob_id in blob_ids_to_delete {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001170 tx.execute(
1171 "DELETE FROM persistent.blobmetadata WHERE blobentryid = ?;",
Janis Danisevskis3395f862021-05-06 10:54:17 -07001172 params![blob_id],
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001173 )
1174 .context("Trying to delete blob metadata.")?;
Janis Danisevskis3395f862021-05-06 10:54:17 -07001175 tx.execute("DELETE FROM persistent.blobentry WHERE id = ?;", params![blob_id])
1176 .context("Trying to blob.")?;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001177 }
Janis Danisevskis3cba10d2021-05-06 17:02:19 -07001178
1179 Self::cleanup_unreferenced(tx).context("Trying to cleanup unreferenced.")?;
1180
Janis Danisevskis3395f862021-05-06 10:54:17 -07001181 // Find up to max_blobx more superseded key blobs, load their metadata and return it.
1182 let result: Vec<(i64, Vec<u8>)> = {
1183 let mut stmt = tx
1184 .prepare(
1185 "SELECT id, blob FROM persistent.blobentry
1186 WHERE subcomponent_type = ?
1187 AND (
1188 id NOT IN (
1189 SELECT MAX(id) FROM persistent.blobentry
1190 WHERE subcomponent_type = ?
1191 GROUP BY keyentryid, subcomponent_type
1192 )
1193 OR keyentryid NOT IN (SELECT id FROM persistent.keyentry)
1194 ) LIMIT ?;",
1195 )
1196 .context("Trying to prepare query for superseded blobs.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001197
Janis Danisevskis3395f862021-05-06 10:54:17 -07001198 let rows = stmt
1199 .query_map(
1200 params![
1201 SubComponentType::KEY_BLOB,
1202 SubComponentType::KEY_BLOB,
1203 max_blobs as i64,
1204 ],
1205 |row| Ok((row.get(0)?, row.get(1)?)),
1206 )
1207 .context("Trying to query superseded blob.")?;
1208
1209 rows.collect::<Result<Vec<(i64, Vec<u8>)>, rusqlite::Error>>()
1210 .context("Trying to extract superseded blobs.")?
1211 };
1212
1213 let result = result
1214 .into_iter()
1215 .map(|(blob_id, blob)| {
1216 Ok((blob_id, blob, BlobMetaData::load_from_db(blob_id, tx)?))
1217 })
1218 .collect::<Result<Vec<(i64, Vec<u8>, BlobMetaData)>>>()
1219 .context("Trying to load blob metadata.")?;
1220 if !result.is_empty() {
1221 return Ok(result).no_gc();
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001222 }
1223
1224 // We did not find any superseded key blob, so let's remove other superseded blob in
1225 // one transaction.
1226 tx.execute(
1227 "DELETE FROM persistent.blobentry
1228 WHERE NOT subcomponent_type = ?
1229 AND (
1230 id NOT IN (
1231 SELECT MAX(id) FROM persistent.blobentry
1232 WHERE NOT subcomponent_type = ?
1233 GROUP BY keyentryid, subcomponent_type
1234 ) OR keyentryid NOT IN (SELECT id FROM persistent.keyentry)
1235 );",
1236 params![SubComponentType::KEY_BLOB, SubComponentType::KEY_BLOB],
1237 )
1238 .context("Trying to purge superseded blobs.")?;
1239
Janis Danisevskis3395f862021-05-06 10:54:17 -07001240 Ok(vec![]).no_gc()
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001241 })
Janis Danisevskis3395f862021-05-06 10:54:17 -07001242 .context("In handle_next_superseded_blobs.")
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001243 }
1244
1245 /// This maintenance function should be called only once before the database is used for the
1246 /// first time. It restores the invariant that `KeyLifeCycle::Existing` is a transient state.
1247 /// The function transitions all key entries from Existing to Unreferenced unconditionally and
1248 /// returns the number of rows affected. If this returns a value greater than 0, it means that
1249 /// Keystore crashed at some point during key generation. Callers may want to log such
1250 /// occurrences.
1251 /// Unlike with `mark_unreferenced`, we don't need to purge grants, because only keys that made
1252 /// it to `KeyLifeCycle::Live` may have grants.
1253 pub fn cleanup_leftovers(&mut self) -> Result<usize> {
Janis Danisevskis850d4862021-05-05 08:41:14 -07001254 let _wp = wd::watch_millis("KeystoreDB::cleanup_leftovers", 500);
1255
Janis Danisevskis66784c42021-01-27 08:40:25 -08001256 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1257 tx.execute(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001258 "UPDATE persistent.keyentry SET state = ? WHERE state = ?;",
1259 params![KeyLifeCycle::Unreferenced, KeyLifeCycle::Existing],
1260 )
Janis Danisevskis66784c42021-01-27 08:40:25 -08001261 .context("Failed to execute query.")
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001262 .need_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08001263 })
1264 .context("In cleanup_leftovers.")
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001265 }
1266
Hasini Gunasinghe0e161452021-01-27 19:34:37 +00001267 /// Checks if a key exists with given key type and key descriptor properties.
1268 pub fn key_exists(
1269 &mut self,
1270 domain: Domain,
1271 nspace: i64,
1272 alias: &str,
1273 key_type: KeyType,
1274 ) -> Result<bool> {
Janis Danisevskis850d4862021-05-05 08:41:14 -07001275 let _wp = wd::watch_millis("KeystoreDB::key_exists", 500);
1276
Hasini Gunasinghe0e161452021-01-27 19:34:37 +00001277 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1278 let key_descriptor =
1279 KeyDescriptor { domain, nspace, alias: Some(alias.to_string()), blob: None };
Chris Wailesd5aaaef2021-07-27 16:04:33 -07001280 let result = Self::load_key_entry_id(tx, &key_descriptor, key_type);
Hasini Gunasinghe0e161452021-01-27 19:34:37 +00001281 match result {
1282 Ok(_) => Ok(true),
1283 Err(error) => match error.root_cause().downcast_ref::<KsError>() {
1284 Some(KsError::Rc(ResponseCode::KEY_NOT_FOUND)) => Ok(false),
1285 _ => Err(error).context("In key_exists: Failed to find if the key exists."),
1286 },
1287 }
1288 .no_gc()
1289 })
1290 .context("In key_exists.")
1291 }
1292
Hasini Gunasingheda895552021-01-27 19:34:37 +00001293 /// Stores a super key in the database.
1294 pub fn store_super_key(
1295 &mut self,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +00001296 user_id: u32,
Paul Crowley7a658392021-03-18 17:08:20 -07001297 key_type: &SuperKeyType,
1298 blob: &[u8],
1299 blob_metadata: &BlobMetaData,
Paul Crowley8d5b2532021-03-19 10:53:07 -07001300 key_metadata: &KeyMetaData,
Hasini Gunasingheda895552021-01-27 19:34:37 +00001301 ) -> Result<KeyEntry> {
Janis Danisevskis850d4862021-05-05 08:41:14 -07001302 let _wp = wd::watch_millis("KeystoreDB::store_super_key", 500);
1303
Hasini Gunasingheda895552021-01-27 19:34:37 +00001304 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1305 let key_id = Self::insert_with_retry(|id| {
1306 tx.execute(
1307 "INSERT into persistent.keyentry
1308 (id, key_type, domain, namespace, alias, state, km_uuid)
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00001309 VALUES(?, ?, ?, ?, ?, ?, ?);",
Hasini Gunasingheda895552021-01-27 19:34:37 +00001310 params![
1311 id,
1312 KeyType::Super,
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00001313 Domain::APP.0,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +00001314 user_id as i64,
Paul Crowley7a658392021-03-18 17:08:20 -07001315 key_type.alias,
Hasini Gunasingheda895552021-01-27 19:34:37 +00001316 KeyLifeCycle::Live,
1317 &KEYSTORE_UUID,
1318 ],
1319 )
1320 })
1321 .context("Failed to insert into keyentry table.")?;
1322
Paul Crowley8d5b2532021-03-19 10:53:07 -07001323 key_metadata.store_in_db(key_id, tx).context("KeyMetaData::store_in_db failed")?;
1324
Hasini Gunasingheda895552021-01-27 19:34:37 +00001325 Self::set_blob_internal(
Chris Wailesd5aaaef2021-07-27 16:04:33 -07001326 tx,
Hasini Gunasingheda895552021-01-27 19:34:37 +00001327 key_id,
1328 SubComponentType::KEY_BLOB,
1329 Some(blob),
1330 Some(blob_metadata),
1331 )
1332 .context("Failed to store key blob.")?;
1333
1334 Self::load_key_components(tx, KeyEntryLoadBits::KM, key_id)
1335 .context("Trying to load key components.")
1336 .no_gc()
1337 })
1338 .context("In store_super_key.")
1339 }
1340
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +00001341 /// Loads super key of a given user, if exists
Paul Crowley7a658392021-03-18 17:08:20 -07001342 pub fn load_super_key(
1343 &mut self,
1344 key_type: &SuperKeyType,
1345 user_id: u32,
1346 ) -> Result<Option<(KeyIdGuard, KeyEntry)>> {
Janis Danisevskis850d4862021-05-05 08:41:14 -07001347 let _wp = wd::watch_millis("KeystoreDB::load_super_key", 500);
1348
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +00001349 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1350 let key_descriptor = KeyDescriptor {
1351 domain: Domain::APP,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +00001352 nspace: user_id as i64,
Paul Crowley7a658392021-03-18 17:08:20 -07001353 alias: Some(key_type.alias.into()),
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +00001354 blob: None,
1355 };
Chris Wailesd5aaaef2021-07-27 16:04:33 -07001356 let id = Self::load_key_entry_id(tx, &key_descriptor, KeyType::Super);
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +00001357 match id {
1358 Ok(id) => {
Chris Wailesd5aaaef2021-07-27 16:04:33 -07001359 let key_entry = Self::load_key_components(tx, KeyEntryLoadBits::KM, id)
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +00001360 .context("In load_super_key. Failed to load key entry.")?;
1361 Ok(Some((KEY_ID_LOCK.get(id), key_entry)))
1362 }
1363 Err(error) => match error.root_cause().downcast_ref::<KsError>() {
1364 Some(KsError::Rc(ResponseCode::KEY_NOT_FOUND)) => Ok(None),
1365 _ => Err(error).context("In load_super_key."),
1366 },
1367 }
1368 .no_gc()
1369 })
1370 .context("In load_super_key.")
1371 }
1372
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001373 /// Atomically loads a key entry and associated metadata or creates it using the
1374 /// callback create_new_key callback. The callback is called during a database
1375 /// transaction. This means that implementers should be mindful about using
1376 /// blocking operations such as IPC or grabbing mutexes.
1377 pub fn get_or_create_key_with<F>(
1378 &mut self,
1379 domain: Domain,
1380 namespace: i64,
1381 alias: &str,
Max Bires8e93d2b2021-01-14 13:17:59 -08001382 km_uuid: Uuid,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001383 create_new_key: F,
1384 ) -> Result<(KeyIdGuard, KeyEntry)>
1385 where
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001386 F: Fn() -> Result<(Vec<u8>, BlobMetaData)>,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001387 {
Janis Danisevskis850d4862021-05-05 08:41:14 -07001388 let _wp = wd::watch_millis("KeystoreDB::get_or_create_key_with", 500);
1389
Janis Danisevskis66784c42021-01-27 08:40:25 -08001390 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1391 let id = {
1392 let mut stmt = tx
1393 .prepare(
1394 "SELECT id FROM persistent.keyentry
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001395 WHERE
1396 key_type = ?
1397 AND domain = ?
1398 AND namespace = ?
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001399 AND alias = ?
1400 AND state = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08001401 )
1402 .context("In get_or_create_key_with: Failed to select from keyentry table.")?;
1403 let mut rows = stmt
1404 .query(params![KeyType::Super, domain.0, namespace, alias, KeyLifeCycle::Live])
1405 .context("In get_or_create_key_with: Failed to query from keyentry table.")?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001406
Janis Danisevskis66784c42021-01-27 08:40:25 -08001407 db_utils::with_rows_extract_one(&mut rows, |row| {
1408 Ok(match row {
1409 Some(r) => r.get(0).context("Failed to unpack id.")?,
1410 None => None,
1411 })
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001412 })
Janis Danisevskis66784c42021-01-27 08:40:25 -08001413 .context("In get_or_create_key_with.")?
1414 };
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001415
Janis Danisevskis66784c42021-01-27 08:40:25 -08001416 let (id, entry) = match id {
1417 Some(id) => (
1418 id,
Chris Wailesd5aaaef2021-07-27 16:04:33 -07001419 Self::load_key_components(tx, KeyEntryLoadBits::KM, id)
Janis Danisevskis66784c42021-01-27 08:40:25 -08001420 .context("In get_or_create_key_with.")?,
1421 ),
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001422
Janis Danisevskis66784c42021-01-27 08:40:25 -08001423 None => {
1424 let id = Self::insert_with_retry(|id| {
1425 tx.execute(
1426 "INSERT into persistent.keyentry
Max Bires8e93d2b2021-01-14 13:17:59 -08001427 (id, key_type, domain, namespace, alias, state, km_uuid)
1428 VALUES(?, ?, ?, ?, ?, ?, ?);",
Janis Danisevskis66784c42021-01-27 08:40:25 -08001429 params![
1430 id,
1431 KeyType::Super,
1432 domain.0,
1433 namespace,
1434 alias,
1435 KeyLifeCycle::Live,
1436 km_uuid,
1437 ],
1438 )
1439 })
1440 .context("In get_or_create_key_with.")?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001441
Janis Danisevskis66784c42021-01-27 08:40:25 -08001442 let (blob, metadata) =
1443 create_new_key().context("In get_or_create_key_with.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001444 Self::set_blob_internal(
Chris Wailesd5aaaef2021-07-27 16:04:33 -07001445 tx,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001446 id,
1447 SubComponentType::KEY_BLOB,
1448 Some(&blob),
1449 Some(&metadata),
1450 )
Paul Crowley7a658392021-03-18 17:08:20 -07001451 .context("In get_or_create_key_with.")?;
Janis Danisevskis66784c42021-01-27 08:40:25 -08001452 (
Janis Danisevskis377d1002021-01-27 19:07:48 -08001453 id,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001454 KeyEntry {
1455 id,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001456 key_blob_info: Some((blob, metadata)),
Janis Danisevskis66784c42021-01-27 08:40:25 -08001457 pure_cert: false,
1458 ..Default::default()
1459 },
1460 )
1461 }
1462 };
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001463 Ok((KEY_ID_LOCK.get(id), entry)).no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08001464 })
1465 .context("In get_or_create_key_with.")
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001466 }
1467
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001468 /// Creates a transaction with the given behavior and executes f with the new transaction.
Janis Danisevskis66784c42021-01-27 08:40:25 -08001469 /// The transaction is committed only if f returns Ok and retried if DatabaseBusy
1470 /// or DatabaseLocked is encountered.
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001471 fn with_transaction<T, F>(&mut self, behavior: TransactionBehavior, f: F) -> Result<T>
1472 where
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001473 F: Fn(&Transaction) -> Result<(bool, T)>,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001474 {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001475 loop {
1476 match self
1477 .conn
1478 .transaction_with_behavior(behavior)
1479 .context("In with_transaction.")
1480 .and_then(|tx| f(&tx).map(|result| (result, tx)))
1481 .and_then(|(result, tx)| {
1482 tx.commit().context("In with_transaction: Failed to commit transaction.")?;
1483 Ok(result)
1484 }) {
1485 Ok(result) => break Ok(result),
1486 Err(e) => {
1487 if Self::is_locked_error(&e) {
1488 std::thread::sleep(std::time::Duration::from_micros(500));
1489 continue;
1490 } else {
1491 return Err(e).context("In with_transaction.");
1492 }
1493 }
1494 }
1495 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001496 .map(|(need_gc, result)| {
1497 if need_gc {
1498 if let Some(ref gc) = self.gc {
1499 gc.notify_gc();
1500 }
1501 }
1502 result
1503 })
Janis Danisevskis66784c42021-01-27 08:40:25 -08001504 }
1505
1506 fn is_locked_error(e: &anyhow::Error) -> bool {
Paul Crowleyf61fee72021-03-17 14:38:44 -07001507 matches!(
1508 e.root_cause().downcast_ref::<rusqlite::ffi::Error>(),
1509 Some(rusqlite::ffi::Error { code: rusqlite::ErrorCode::DatabaseBusy, .. })
1510 | Some(rusqlite::ffi::Error { code: rusqlite::ErrorCode::DatabaseLocked, .. })
1511 )
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001512 }
1513
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001514 /// Creates a new key entry and allocates a new randomized id for the new key.
1515 /// The key id gets associated with a domain and namespace but not with an alias.
1516 /// To complete key generation `rebind_alias` should be called after all of the
1517 /// key artifacts, i.e., blobs and parameters have been associated with the new
1518 /// key id. Finalizing with `rebind_alias` makes the creation of a new key entry
1519 /// atomic even if key generation is not.
Max Bires8e93d2b2021-01-14 13:17:59 -08001520 pub fn create_key_entry(
1521 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001522 domain: &Domain,
1523 namespace: &i64,
Janis Danisevskis0cabd712021-05-25 11:07:10 -07001524 key_type: KeyType,
Max Bires8e93d2b2021-01-14 13:17:59 -08001525 km_uuid: &Uuid,
1526 ) -> Result<KeyIdGuard> {
Janis Danisevskis850d4862021-05-05 08:41:14 -07001527 let _wp = wd::watch_millis("KeystoreDB::create_key_entry", 500);
1528
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001529 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis0cabd712021-05-25 11:07:10 -07001530 Self::create_key_entry_internal(tx, domain, namespace, key_type, km_uuid).no_gc()
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001531 })
1532 .context("In create_key_entry.")
1533 }
1534
1535 fn create_key_entry_internal(
1536 tx: &Transaction,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001537 domain: &Domain,
1538 namespace: &i64,
Janis Danisevskis0cabd712021-05-25 11:07:10 -07001539 key_type: KeyType,
Max Bires8e93d2b2021-01-14 13:17:59 -08001540 km_uuid: &Uuid,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001541 ) -> Result<KeyIdGuard> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001542 match *domain {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001543 Domain::APP | Domain::SELINUX => {}
Joel Galenson0891bc12020-07-20 10:37:03 -07001544 _ => {
1545 return Err(KsError::sys())
1546 .context(format!("Domain {:?} must be either App or SELinux.", domain));
1547 }
1548 }
Janis Danisevskisaec14592020-11-12 09:41:49 -08001549 Ok(KEY_ID_LOCK.get(
1550 Self::insert_with_retry(|id| {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001551 tx.execute(
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001552 "INSERT into persistent.keyentry
Max Bires8e93d2b2021-01-14 13:17:59 -08001553 (id, key_type, domain, namespace, alias, state, km_uuid)
1554 VALUES(?, ?, ?, ?, NULL, ?, ?);",
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001555 params![
1556 id,
Janis Danisevskis0cabd712021-05-25 11:07:10 -07001557 key_type,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001558 domain.0 as u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001559 *namespace,
Max Bires8e93d2b2021-01-14 13:17:59 -08001560 KeyLifeCycle::Existing,
1561 km_uuid,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001562 ],
Janis Danisevskisaec14592020-11-12 09:41:49 -08001563 )
1564 })
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001565 .context("In create_key_entry_internal")?,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001566 ))
Joel Galenson26f4d012020-07-17 14:57:21 -07001567 }
Joel Galenson33c04ad2020-08-03 11:04:38 -07001568
Max Bires2b2e6562020-09-22 11:22:36 -07001569 /// Creates a new attestation key entry and allocates a new randomized id for the new key.
1570 /// The key id gets associated with a domain and namespace later but not with an alias. The
1571 /// alias will be used to denote if a key has been signed as each key can only be bound to one
1572 /// domain and namespace pairing so there is no need to use them as a value for indexing into
1573 /// a key.
1574 pub fn create_attestation_key_entry(
1575 &mut self,
1576 maced_public_key: &[u8],
1577 raw_public_key: &[u8],
1578 private_key: &[u8],
1579 km_uuid: &Uuid,
1580 ) -> Result<()> {
Janis Danisevskis850d4862021-05-05 08:41:14 -07001581 let _wp = wd::watch_millis("KeystoreDB::create_attestation_key_entry", 500);
1582
Max Bires2b2e6562020-09-22 11:22:36 -07001583 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1584 let key_id = KEY_ID_LOCK.get(
1585 Self::insert_with_retry(|id| {
1586 tx.execute(
1587 "INSERT into persistent.keyentry
1588 (id, key_type, domain, namespace, alias, state, km_uuid)
1589 VALUES(?, ?, NULL, NULL, NULL, ?, ?);",
1590 params![id, KeyType::Attestation, KeyLifeCycle::Live, km_uuid],
1591 )
1592 })
1593 .context("In create_key_entry")?,
1594 );
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001595 Self::set_blob_internal(
Chris Wailesd5aaaef2021-07-27 16:04:33 -07001596 tx,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001597 key_id.0,
1598 SubComponentType::KEY_BLOB,
1599 Some(private_key),
1600 None,
1601 )?;
Max Bires2b2e6562020-09-22 11:22:36 -07001602 let mut metadata = KeyMetaData::new();
1603 metadata.add(KeyMetaEntry::AttestationMacedPublicKey(maced_public_key.to_vec()));
1604 metadata.add(KeyMetaEntry::AttestationRawPubKey(raw_public_key.to_vec()));
Chris Wailesd5aaaef2021-07-27 16:04:33 -07001605 metadata.store_in_db(key_id.0, tx)?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001606 Ok(()).no_gc()
Max Bires2b2e6562020-09-22 11:22:36 -07001607 })
1608 .context("In create_attestation_key_entry")
1609 }
1610
Janis Danisevskis377d1002021-01-27 19:07:48 -08001611 /// Set a new blob and associates it with the given key id. Each blob
1612 /// has a sub component type.
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001613 /// Each key can have one of each sub component type associated. If more
1614 /// are added only the most recent can be retrieved, and superseded blobs
Janis Danisevskis377d1002021-01-27 19:07:48 -08001615 /// will get garbage collected.
1616 /// Components SubComponentType::CERT and SubComponentType::CERT_CHAIN can be
1617 /// removed by setting blob to None.
1618 pub fn set_blob(
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001619 &mut self,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001620 key_id: &KeyIdGuard,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001621 sc_type: SubComponentType,
Janis Danisevskis377d1002021-01-27 19:07:48 -08001622 blob: Option<&[u8]>,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001623 blob_metadata: Option<&BlobMetaData>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001624 ) -> Result<()> {
Janis Danisevskis850d4862021-05-05 08:41:14 -07001625 let _wp = wd::watch_millis("KeystoreDB::set_blob", 500);
1626
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001627 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Chris Wailesd5aaaef2021-07-27 16:04:33 -07001628 Self::set_blob_internal(tx, key_id.0, sc_type, blob, blob_metadata).need_gc()
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001629 })
Janis Danisevskis377d1002021-01-27 19:07:48 -08001630 .context("In set_blob.")
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001631 }
1632
Janis Danisevskiseed69842021-02-18 20:04:10 -08001633 /// Why would we insert a deleted blob? This weird function is for the purpose of legacy
1634 /// key migration in the case where we bulk delete all the keys of an app or even a user.
1635 /// We use this to insert key blobs into the database which can then be garbage collected
1636 /// lazily by the key garbage collector.
1637 pub fn set_deleted_blob(&mut self, blob: &[u8], blob_metadata: &BlobMetaData) -> Result<()> {
Janis Danisevskis850d4862021-05-05 08:41:14 -07001638 let _wp = wd::watch_millis("KeystoreDB::set_deleted_blob", 500);
1639
Janis Danisevskiseed69842021-02-18 20:04:10 -08001640 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1641 Self::set_blob_internal(
Chris Wailesd5aaaef2021-07-27 16:04:33 -07001642 tx,
Janis Danisevskiseed69842021-02-18 20:04:10 -08001643 Self::UNASSIGNED_KEY_ID,
1644 SubComponentType::KEY_BLOB,
1645 Some(blob),
1646 Some(blob_metadata),
1647 )
1648 .need_gc()
1649 })
1650 .context("In set_deleted_blob.")
1651 }
1652
Janis Danisevskis377d1002021-01-27 19:07:48 -08001653 fn set_blob_internal(
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001654 tx: &Transaction,
1655 key_id: i64,
1656 sc_type: SubComponentType,
Janis Danisevskis377d1002021-01-27 19:07:48 -08001657 blob: Option<&[u8]>,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001658 blob_metadata: Option<&BlobMetaData>,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001659 ) -> Result<()> {
Janis Danisevskis377d1002021-01-27 19:07:48 -08001660 match (blob, sc_type) {
1661 (Some(blob), _) => {
1662 tx.execute(
1663 "INSERT INTO persistent.blobentry
1664 (subcomponent_type, keyentryid, blob) VALUES (?, ?, ?);",
1665 params![sc_type, key_id, blob],
1666 )
1667 .context("In set_blob_internal: Failed to insert blob.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001668 if let Some(blob_metadata) = blob_metadata {
1669 let blob_id = tx
1670 .query_row("SELECT MAX(id) FROM persistent.blobentry;", NO_PARAMS, |row| {
1671 row.get(0)
1672 })
1673 .context("In set_blob_internal: Failed to get new blob id.")?;
1674 blob_metadata
1675 .store_in_db(blob_id, tx)
1676 .context("In set_blob_internal: Trying to store blob metadata.")?;
1677 }
Janis Danisevskis377d1002021-01-27 19:07:48 -08001678 }
1679 (None, SubComponentType::CERT) | (None, SubComponentType::CERT_CHAIN) => {
1680 tx.execute(
1681 "DELETE FROM persistent.blobentry
1682 WHERE subcomponent_type = ? AND keyentryid = ?;",
1683 params![sc_type, key_id],
1684 )
1685 .context("In set_blob_internal: Failed to delete blob.")?;
1686 }
1687 (None, _) => {
1688 return Err(KsError::sys())
1689 .context("In set_blob_internal: Other blobs cannot be deleted in this way.");
1690 }
1691 }
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001692 Ok(())
1693 }
1694
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001695 /// Inserts a collection of key parameters into the `persistent.keyparameter` table
1696 /// and associates them with the given `key_id`.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001697 #[cfg(test)]
1698 fn insert_keyparameter(&mut self, key_id: &KeyIdGuard, params: &[KeyParameter]) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001699 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001700 Self::insert_keyparameter_internal(tx, key_id, params).no_gc()
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001701 })
1702 .context("In insert_keyparameter.")
1703 }
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001704
Janis Danisevskis66784c42021-01-27 08:40:25 -08001705 fn insert_keyparameter_internal(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001706 tx: &Transaction,
1707 key_id: &KeyIdGuard,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001708 params: &[KeyParameter],
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001709 ) -> Result<()> {
1710 let mut stmt = tx
1711 .prepare(
1712 "INSERT into persistent.keyparameter (keyentryid, tag, data, security_level)
1713 VALUES (?, ?, ?, ?);",
1714 )
1715 .context("In insert_keyparameter_internal: Failed to prepare statement.")?;
1716
Janis Danisevskis66784c42021-01-27 08:40:25 -08001717 for p in params.iter() {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001718 stmt.insert(params![
1719 key_id.0,
1720 p.get_tag().0,
1721 p.key_parameter_value(),
1722 p.security_level().0
1723 ])
1724 .with_context(|| {
1725 format!("In insert_keyparameter_internal: Failed to insert {:?}", p)
1726 })?;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001727 }
1728 Ok(())
1729 }
1730
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001731 /// Insert a set of key entry specific metadata into the database.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001732 #[cfg(test)]
1733 fn insert_key_metadata(&mut self, key_id: &KeyIdGuard, metadata: &KeyMetaData) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001734 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Chris Wailesd5aaaef2021-07-27 16:04:33 -07001735 metadata.store_in_db(key_id.0, tx).no_gc()
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001736 })
1737 .context("In insert_key_metadata.")
1738 }
1739
Max Bires2b2e6562020-09-22 11:22:36 -07001740 /// Stores a signed certificate chain signed by a remote provisioning server, keyed
1741 /// on the public key.
1742 pub fn store_signed_attestation_certificate_chain(
1743 &mut self,
1744 raw_public_key: &[u8],
Max Biresb2e1d032021-02-08 21:35:05 -08001745 batch_cert: &[u8],
Max Bires2b2e6562020-09-22 11:22:36 -07001746 cert_chain: &[u8],
1747 expiration_date: i64,
1748 km_uuid: &Uuid,
1749 ) -> Result<()> {
Janis Danisevskis850d4862021-05-05 08:41:14 -07001750 let _wp = wd::watch_millis("KeystoreDB::store_signed_attestation_certificate_chain", 500);
1751
Max Bires2b2e6562020-09-22 11:22:36 -07001752 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1753 let mut stmt = tx
1754 .prepare(
1755 "SELECT keyentryid
1756 FROM persistent.keymetadata
1757 WHERE tag = ? AND data = ? AND keyentryid IN
1758 (SELECT id
1759 FROM persistent.keyentry
1760 WHERE
1761 alias IS NULL AND
1762 domain IS NULL AND
1763 namespace IS NULL AND
1764 key_type = ? AND
1765 km_uuid = ?);",
1766 )
1767 .context("Failed to store attestation certificate chain.")?;
1768 let mut rows = stmt
1769 .query(params![
1770 KeyMetaData::AttestationRawPubKey,
1771 raw_public_key,
1772 KeyType::Attestation,
1773 km_uuid
1774 ])
1775 .context("Failed to fetch keyid")?;
1776 let key_id = db_utils::with_rows_extract_one(&mut rows, |row| {
1777 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?
1778 .get(0)
1779 .context("Failed to unpack id.")
1780 })
1781 .context("Failed to get key_id.")?;
1782 let num_updated = tx
1783 .execute(
1784 "UPDATE persistent.keyentry
1785 SET alias = ?
1786 WHERE id = ?;",
1787 params!["signed", key_id],
1788 )
1789 .context("Failed to update alias.")?;
1790 if num_updated != 1 {
1791 return Err(KsError::sys()).context("Alias not updated for the key.");
1792 }
1793 let mut metadata = KeyMetaData::new();
1794 metadata.add(KeyMetaEntry::AttestationExpirationDate(DateTime::from_millis_epoch(
1795 expiration_date,
1796 )));
Chris Wailesd5aaaef2021-07-27 16:04:33 -07001797 metadata.store_in_db(key_id, tx).context("Failed to insert key metadata.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001798 Self::set_blob_internal(
Chris Wailesd5aaaef2021-07-27 16:04:33 -07001799 tx,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001800 key_id,
1801 SubComponentType::CERT_CHAIN,
1802 Some(cert_chain),
1803 None,
1804 )
1805 .context("Failed to insert cert chain")?;
Chris Wailesd5aaaef2021-07-27 16:04:33 -07001806 Self::set_blob_internal(tx, key_id, SubComponentType::CERT, Some(batch_cert), None)
Max Biresb2e1d032021-02-08 21:35:05 -08001807 .context("Failed to insert cert")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001808 Ok(()).no_gc()
Max Bires2b2e6562020-09-22 11:22:36 -07001809 })
1810 .context("In store_signed_attestation_certificate_chain: ")
1811 }
1812
1813 /// Assigns the next unassigned attestation key to a domain/namespace combo that does not
1814 /// currently have a key assigned to it.
1815 pub fn assign_attestation_key(
1816 &mut self,
1817 domain: Domain,
1818 namespace: i64,
1819 km_uuid: &Uuid,
1820 ) -> Result<()> {
Janis Danisevskis850d4862021-05-05 08:41:14 -07001821 let _wp = wd::watch_millis("KeystoreDB::assign_attestation_key", 500);
1822
Max Bires2b2e6562020-09-22 11:22:36 -07001823 match domain {
1824 Domain::APP | Domain::SELINUX => {}
1825 _ => {
1826 return Err(KsError::sys()).context(format!(
1827 concat!(
1828 "In assign_attestation_key: Domain {:?} ",
1829 "must be either App or SELinux.",
1830 ),
1831 domain
1832 ));
1833 }
1834 }
1835 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1836 let result = tx
1837 .execute(
1838 "UPDATE persistent.keyentry
1839 SET domain=?1, namespace=?2
1840 WHERE
1841 id =
1842 (SELECT MIN(id)
1843 FROM persistent.keyentry
1844 WHERE ALIAS IS NOT NULL
1845 AND domain IS NULL
1846 AND key_type IS ?3
1847 AND state IS ?4
1848 AND km_uuid IS ?5)
1849 AND
1850 (SELECT COUNT(*)
1851 FROM persistent.keyentry
1852 WHERE domain=?1
1853 AND namespace=?2
1854 AND key_type IS ?3
1855 AND state IS ?4
1856 AND km_uuid IS ?5) = 0;",
1857 params![
1858 domain.0 as u32,
1859 namespace,
1860 KeyType::Attestation,
1861 KeyLifeCycle::Live,
1862 km_uuid,
1863 ],
1864 )
1865 .context("Failed to assign attestation key")?;
Max Bires01f8af22021-03-02 23:24:50 -08001866 if result == 0 {
Hasini Gunasinghe1a8524b2022-05-10 08:49:53 +00001867 let (_, hw_info) = get_keymint_dev_by_uuid(km_uuid)
1868 .context("Error in retrieving keymint device by UUID.")?;
1869 log_rkp_error_stats(MetricsRkpError::OUT_OF_KEYS, &hw_info.securityLevel);
Max Bires01f8af22021-03-02 23:24:50 -08001870 return Err(KsError::Rc(ResponseCode::OUT_OF_KEYS)).context("Out of keys.");
1871 } else if result > 1 {
1872 return Err(KsError::sys())
1873 .context(format!("Expected to update 1 entry, instead updated {}", result));
Max Bires2b2e6562020-09-22 11:22:36 -07001874 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001875 Ok(()).no_gc()
Max Bires2b2e6562020-09-22 11:22:36 -07001876 })
1877 .context("In assign_attestation_key: ")
1878 }
1879
1880 /// Retrieves num_keys number of attestation keys that have not yet been signed by a remote
1881 /// provisioning server, or the maximum number available if there are not num_keys number of
1882 /// entries in the table.
1883 pub fn fetch_unsigned_attestation_keys(
1884 &mut self,
1885 num_keys: i32,
1886 km_uuid: &Uuid,
1887 ) -> Result<Vec<Vec<u8>>> {
Janis Danisevskis850d4862021-05-05 08:41:14 -07001888 let _wp = wd::watch_millis("KeystoreDB::fetch_unsigned_attestation_keys", 500);
1889
Max Bires2b2e6562020-09-22 11:22:36 -07001890 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1891 let mut stmt = tx
1892 .prepare(
1893 "SELECT data
1894 FROM persistent.keymetadata
1895 WHERE tag = ? AND keyentryid IN
1896 (SELECT id
1897 FROM persistent.keyentry
1898 WHERE
1899 alias IS NULL AND
1900 domain IS NULL AND
1901 namespace IS NULL AND
1902 key_type = ? AND
1903 km_uuid = ?
1904 LIMIT ?);",
1905 )
1906 .context("Failed to prepare statement")?;
1907 let rows = stmt
1908 .query_map(
1909 params![
1910 KeyMetaData::AttestationMacedPublicKey,
1911 KeyType::Attestation,
1912 km_uuid,
1913 num_keys
1914 ],
Janis Danisevskis82e55f92021-05-06 14:55:48 -07001915 |row| row.get(0),
Max Bires2b2e6562020-09-22 11:22:36 -07001916 )?
1917 .collect::<rusqlite::Result<Vec<Vec<u8>>>>()
1918 .context("Failed to execute statement")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001919 Ok(rows).no_gc()
Max Bires2b2e6562020-09-22 11:22:36 -07001920 })
1921 .context("In fetch_unsigned_attestation_keys")
1922 }
1923
1924 /// Removes any keys that have expired as of the current time. Returns the number of keys
1925 /// marked unreferenced that are bound to be garbage collected.
1926 pub fn delete_expired_attestation_keys(&mut self) -> Result<i32> {
Janis Danisevskis850d4862021-05-05 08:41:14 -07001927 let _wp = wd::watch_millis("KeystoreDB::delete_expired_attestation_keys", 500);
1928
Max Bires2b2e6562020-09-22 11:22:36 -07001929 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1930 let mut stmt = tx
1931 .prepare(
1932 "SELECT keyentryid, data
1933 FROM persistent.keymetadata
1934 WHERE tag = ? AND keyentryid IN
1935 (SELECT id
1936 FROM persistent.keyentry
1937 WHERE key_type = ?);",
1938 )
1939 .context("Failed to prepare query")?;
1940 let key_ids_to_check = stmt
1941 .query_map(
1942 params![KeyMetaData::AttestationExpirationDate, KeyType::Attestation],
1943 |row| Ok((row.get(0)?, row.get(1)?)),
1944 )?
1945 .collect::<rusqlite::Result<Vec<(i64, DateTime)>>>()
1946 .context("Failed to get date metadata")?;
Max Birescd7f7412022-02-11 13:47:36 -08001947 // Calculate curr_time with a discount factor to avoid a key that's milliseconds away
1948 // from expiration dodging this delete call.
Max Bires2b2e6562020-09-22 11:22:36 -07001949 let curr_time = DateTime::from_millis_epoch(
Max Birescd7f7412022-02-11 13:47:36 -08001950 SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_millis() as i64
1951 + EXPIRATION_BUFFER_MS,
Max Bires2b2e6562020-09-22 11:22:36 -07001952 );
1953 let mut num_deleted = 0;
1954 for id in key_ids_to_check.iter().filter(|kt| kt.1 < curr_time).map(|kt| kt.0) {
Chris Wailesd5aaaef2021-07-27 16:04:33 -07001955 if Self::mark_unreferenced(tx, id)? {
Max Bires2b2e6562020-09-22 11:22:36 -07001956 num_deleted += 1;
1957 }
1958 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001959 Ok(num_deleted).do_gc(num_deleted != 0)
Max Bires2b2e6562020-09-22 11:22:36 -07001960 })
1961 .context("In delete_expired_attestation_keys: ")
1962 }
1963
Max Bires60d7ed12021-03-05 15:59:22 -08001964 /// Deletes all remotely provisioned attestation keys in the system, regardless of the state
1965 /// they are in. This is useful primarily as a testing mechanism.
1966 pub fn delete_all_attestation_keys(&mut self) -> Result<i64> {
Janis Danisevskis850d4862021-05-05 08:41:14 -07001967 let _wp = wd::watch_millis("KeystoreDB::delete_all_attestation_keys", 500);
1968
Max Bires60d7ed12021-03-05 15:59:22 -08001969 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1970 let mut stmt = tx
1971 .prepare(
1972 "SELECT id FROM persistent.keyentry
1973 WHERE key_type IS ?;",
1974 )
1975 .context("Failed to prepare statement")?;
1976 let keys_to_delete = stmt
Janis Danisevskis82e55f92021-05-06 14:55:48 -07001977 .query_map(params![KeyType::Attestation], |row| row.get(0))?
Max Bires60d7ed12021-03-05 15:59:22 -08001978 .collect::<rusqlite::Result<Vec<i64>>>()
1979 .context("Failed to execute statement")?;
1980 let num_deleted = keys_to_delete
1981 .iter()
Chris Wailesd5aaaef2021-07-27 16:04:33 -07001982 .map(|id| Self::mark_unreferenced(tx, *id))
Max Bires60d7ed12021-03-05 15:59:22 -08001983 .collect::<Result<Vec<bool>>>()
1984 .context("Failed to execute mark_unreferenced on a keyid")?
1985 .into_iter()
1986 .filter(|result| *result)
1987 .count() as i64;
1988 Ok(num_deleted).do_gc(num_deleted != 0)
1989 })
1990 .context("In delete_all_attestation_keys: ")
1991 }
1992
Max Bires2b2e6562020-09-22 11:22:36 -07001993 /// Counts the number of keys that will expire by the provided epoch date and the number of
1994 /// keys not currently assigned to a domain.
1995 pub fn get_attestation_pool_status(
1996 &mut self,
1997 date: i64,
1998 km_uuid: &Uuid,
1999 ) -> Result<AttestationPoolStatus> {
Janis Danisevskis850d4862021-05-05 08:41:14 -07002000 let _wp = wd::watch_millis("KeystoreDB::get_attestation_pool_status", 500);
2001
Max Bires2b2e6562020-09-22 11:22:36 -07002002 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2003 let mut stmt = tx.prepare(
2004 "SELECT data
2005 FROM persistent.keymetadata
2006 WHERE tag = ? AND keyentryid IN
2007 (SELECT id
2008 FROM persistent.keyentry
2009 WHERE alias IS NOT NULL
2010 AND key_type = ?
2011 AND km_uuid = ?
2012 AND state = ?);",
2013 )?;
2014 let times = stmt
2015 .query_map(
2016 params![
2017 KeyMetaData::AttestationExpirationDate,
2018 KeyType::Attestation,
2019 km_uuid,
2020 KeyLifeCycle::Live
2021 ],
Janis Danisevskis82e55f92021-05-06 14:55:48 -07002022 |row| row.get(0),
Max Bires2b2e6562020-09-22 11:22:36 -07002023 )?
2024 .collect::<rusqlite::Result<Vec<DateTime>>>()
2025 .context("Failed to execute metadata statement")?;
2026 let expiring =
2027 times.iter().filter(|time| time < &&DateTime::from_millis_epoch(date)).count()
2028 as i32;
2029 stmt = tx.prepare(
2030 "SELECT alias, domain
2031 FROM persistent.keyentry
2032 WHERE key_type = ? AND km_uuid = ? AND state = ?;",
2033 )?;
2034 let rows = stmt
2035 .query_map(params![KeyType::Attestation, km_uuid, KeyLifeCycle::Live], |row| {
2036 Ok((row.get(0)?, row.get(1)?))
2037 })?
2038 .collect::<rusqlite::Result<Vec<(Option<String>, Option<u32>)>>>()
2039 .context("Failed to execute keyentry statement")?;
2040 let mut unassigned = 0i32;
2041 let mut attested = 0i32;
2042 let total = rows.len() as i32;
2043 for (alias, domain) in rows {
2044 match (alias, domain) {
2045 (Some(_alias), None) => {
2046 attested += 1;
2047 unassigned += 1;
2048 }
2049 (Some(_alias), Some(_domain)) => {
2050 attested += 1;
2051 }
2052 _ => {}
2053 }
2054 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002055 Ok(AttestationPoolStatus { expiring, unassigned, attested, total }).no_gc()
Max Bires2b2e6562020-09-22 11:22:36 -07002056 })
2057 .context("In get_attestation_pool_status: ")
2058 }
2059
Max Bires55620ff2022-02-11 13:34:15 -08002060 fn query_kid_for_attestation_key_and_cert_chain(
2061 &self,
2062 tx: &Transaction,
2063 domain: Domain,
2064 namespace: i64,
2065 km_uuid: &Uuid,
2066 ) -> Result<Option<i64>> {
2067 let mut stmt = tx.prepare(
2068 "SELECT id
2069 FROM persistent.keyentry
2070 WHERE key_type = ?
2071 AND domain = ?
2072 AND namespace = ?
2073 AND state = ?
2074 AND km_uuid = ?;",
2075 )?;
2076 let rows = stmt
2077 .query_map(
2078 params![
2079 KeyType::Attestation,
2080 domain.0 as u32,
2081 namespace,
2082 KeyLifeCycle::Live,
2083 km_uuid
2084 ],
2085 |row| row.get(0),
2086 )?
2087 .collect::<rusqlite::Result<Vec<i64>>>()
2088 .context("query failed.")?;
2089 if rows.is_empty() {
2090 return Ok(None);
2091 }
2092 Ok(Some(rows[0]))
2093 }
2094
Max Bires2b2e6562020-09-22 11:22:36 -07002095 /// Fetches the private key and corresponding certificate chain assigned to a
2096 /// domain/namespace pair. Will either return nothing if the domain/namespace is
2097 /// not assigned, or one CertificateChain.
2098 pub fn retrieve_attestation_key_and_cert_chain(
2099 &mut self,
2100 domain: Domain,
2101 namespace: i64,
2102 km_uuid: &Uuid,
Max Bires55620ff2022-02-11 13:34:15 -08002103 ) -> Result<Option<(KeyIdGuard, CertificateChain)>> {
Janis Danisevskis850d4862021-05-05 08:41:14 -07002104 let _wp = wd::watch_millis("KeystoreDB::retrieve_attestation_key_and_cert_chain", 500);
2105
Max Bires2b2e6562020-09-22 11:22:36 -07002106 match domain {
2107 Domain::APP | Domain::SELINUX => {}
2108 _ => {
2109 return Err(KsError::sys())
2110 .context(format!("Domain {:?} must be either App or SELinux.", domain));
2111 }
2112 }
Max Bires55620ff2022-02-11 13:34:15 -08002113
Max Birescd7f7412022-02-11 13:47:36 -08002114 self.delete_expired_attestation_keys().context(
2115 "In retrieve_attestation_key_and_cert_chain: failed to prune expired attestation keys",
2116 )?;
Max Bires55620ff2022-02-11 13:34:15 -08002117 let tx = self.conn.unchecked_transaction().context(
2118 "In retrieve_attestation_key_and_cert_chain: Failed to initialize transaction.",
2119 )?;
Chariseea1e1c482022-02-26 01:26:35 +00002120 let key_id: i64 = match self
2121 .query_kid_for_attestation_key_and_cert_chain(&tx, domain, namespace, km_uuid)?
2122 {
Max Bires55620ff2022-02-11 13:34:15 -08002123 None => return Ok(None),
Chariseea1e1c482022-02-26 01:26:35 +00002124 Some(kid) => kid,
2125 };
Max Bires55620ff2022-02-11 13:34:15 -08002126 tx.commit()
2127 .context("In retrieve_attestation_key_and_cert_chain: Failed to commit keyid query")?;
2128 let key_id_guard = KEY_ID_LOCK.get(key_id);
2129 let tx = self.conn.unchecked_transaction().context(
2130 "In retrieve_attestation_key_and_cert_chain: Failed to initialize transaction.",
2131 )?;
2132 let mut stmt = tx.prepare(
2133 "SELECT subcomponent_type, blob
2134 FROM persistent.blobentry
2135 WHERE keyentryid = ?;",
2136 )?;
2137 let rows = stmt
2138 .query_map(params![key_id_guard.id()], |row| Ok((row.get(0)?, row.get(1)?)))?
2139 .collect::<rusqlite::Result<Vec<(SubComponentType, Vec<u8>)>>>()
2140 .context("query failed.")?;
2141 if rows.is_empty() {
2142 return Ok(None);
2143 } else if rows.len() != 3 {
2144 return Err(KsError::sys()).context(format!(
2145 concat!(
2146 "Expected to get a single attestation",
2147 "key, cert, and cert chain for a total of 3 entries, but instead got {}."
2148 ),
2149 rows.len()
2150 ));
2151 }
2152 let mut km_blob: Vec<u8> = Vec::new();
2153 let mut cert_chain_blob: Vec<u8> = Vec::new();
2154 let mut batch_cert_blob: Vec<u8> = Vec::new();
2155 for row in rows {
2156 let sub_type: SubComponentType = row.0;
2157 match sub_type {
2158 SubComponentType::KEY_BLOB => {
2159 km_blob = row.1;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002160 }
Max Bires55620ff2022-02-11 13:34:15 -08002161 SubComponentType::CERT_CHAIN => {
2162 cert_chain_blob = row.1;
2163 }
2164 SubComponentType::CERT => {
2165 batch_cert_blob = row.1;
2166 }
2167 _ => Err(KsError::sys()).context("Unknown or incorrect subcomponent type.")?,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002168 }
Max Bires55620ff2022-02-11 13:34:15 -08002169 }
2170 Ok(Some((
2171 key_id_guard,
2172 CertificateChain {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002173 private_key: ZVec::try_from(km_blob)?,
Max Bires97f96812021-02-23 23:44:57 -08002174 batch_cert: batch_cert_blob,
2175 cert_chain: cert_chain_blob,
Max Bires55620ff2022-02-11 13:34:15 -08002176 },
2177 )))
Max Bires2b2e6562020-09-22 11:22:36 -07002178 }
2179
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002180 /// Updates the alias column of the given key id `newid` with the given alias,
2181 /// and atomically, removes the alias, domain, and namespace from another row
2182 /// with the same alias-domain-namespace tuple if such row exits.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002183 /// Returns Ok(true) if an old key was marked unreferenced as a hint to the garbage
2184 /// collector.
2185 fn rebind_alias(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002186 tx: &Transaction,
Janis Danisevskisaec14592020-11-12 09:41:49 -08002187 newid: &KeyIdGuard,
Joel Galenson33c04ad2020-08-03 11:04:38 -07002188 alias: &str,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002189 domain: &Domain,
2190 namespace: &i64,
Janis Danisevskis0cabd712021-05-25 11:07:10 -07002191 key_type: KeyType,
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002192 ) -> Result<bool> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002193 match *domain {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002194 Domain::APP | Domain::SELINUX => {}
Joel Galenson33c04ad2020-08-03 11:04:38 -07002195 _ => {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002196 return Err(KsError::sys()).context(format!(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002197 "In rebind_alias: Domain {:?} must be either App or SELinux.",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002198 domain
2199 ));
Joel Galenson33c04ad2020-08-03 11:04:38 -07002200 }
2201 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002202 let updated = tx
2203 .execute(
2204 "UPDATE persistent.keyentry
2205 SET alias = NULL, domain = NULL, namespace = NULL, state = ?
Janis Danisevskis0cabd712021-05-25 11:07:10 -07002206 WHERE alias = ? AND domain = ? AND namespace = ? AND key_type = ?;",
2207 params![KeyLifeCycle::Unreferenced, alias, domain.0 as u32, namespace, key_type],
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002208 )
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002209 .context("In rebind_alias: Failed to rebind existing entry.")?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07002210 let result = tx
2211 .execute(
2212 "UPDATE persistent.keyentry
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002213 SET alias = ?, state = ?
Janis Danisevskis0cabd712021-05-25 11:07:10 -07002214 WHERE id = ? AND domain = ? AND namespace = ? AND state = ? AND key_type = ?;",
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002215 params![
2216 alias,
2217 KeyLifeCycle::Live,
2218 newid.0,
2219 domain.0 as u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002220 *namespace,
Max Bires8e93d2b2021-01-14 13:17:59 -08002221 KeyLifeCycle::Existing,
Janis Danisevskis0cabd712021-05-25 11:07:10 -07002222 key_type,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002223 ],
Joel Galenson33c04ad2020-08-03 11:04:38 -07002224 )
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002225 .context("In rebind_alias: Failed to set alias.")?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07002226 if result != 1 {
Joel Galenson33c04ad2020-08-03 11:04:38 -07002227 return Err(KsError::sys()).context(format!(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002228 "In rebind_alias: Expected to update a single entry but instead updated {}.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07002229 result
2230 ));
2231 }
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002232 Ok(updated != 0)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002233 }
2234
Janis Danisevskiscdcf4e52021-04-14 15:44:36 -07002235 /// Moves the key given by KeyIdGuard to the new location at `destination`. If the destination
2236 /// is already occupied by a key, this function fails with `ResponseCode::INVALID_ARGUMENT`.
2237 pub fn migrate_key_namespace(
2238 &mut self,
2239 key_id_guard: KeyIdGuard,
2240 destination: &KeyDescriptor,
2241 caller_uid: u32,
2242 check_permission: impl Fn(&KeyDescriptor) -> Result<()>,
2243 ) -> Result<()> {
Janis Danisevskis850d4862021-05-05 08:41:14 -07002244 let _wp = wd::watch_millis("KeystoreDB::migrate_key_namespace", 500);
2245
Janis Danisevskiscdcf4e52021-04-14 15:44:36 -07002246 let destination = match destination.domain {
2247 Domain::APP => KeyDescriptor { nspace: caller_uid as i64, ..(*destination).clone() },
2248 Domain::SELINUX => (*destination).clone(),
2249 domain => {
2250 return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT))
2251 .context(format!("Domain {:?} must be either APP or SELINUX.", domain));
2252 }
2253 };
2254
2255 // Security critical: Must return immediately on failure. Do not remove the '?';
2256 check_permission(&destination)
2257 .context("In migrate_key_namespace: Trying to check permission.")?;
2258
2259 let alias = destination
2260 .alias
2261 .as_ref()
2262 .ok_or(KsError::Rc(ResponseCode::INVALID_ARGUMENT))
2263 .context("In migrate_key_namespace: Alias must be specified.")?;
2264
2265 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2266 // Query the destination location. If there is a key, the migration request fails.
2267 if tx
2268 .query_row(
2269 "SELECT id FROM persistent.keyentry
2270 WHERE alias = ? AND domain = ? AND namespace = ?;",
2271 params![alias, destination.domain.0, destination.nspace],
2272 |_| Ok(()),
2273 )
2274 .optional()
2275 .context("Failed to query destination.")?
2276 .is_some()
2277 {
2278 return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT))
2279 .context("Target already exists.");
2280 }
2281
2282 let updated = tx
2283 .execute(
2284 "UPDATE persistent.keyentry
2285 SET alias = ?, domain = ?, namespace = ?
2286 WHERE id = ?;",
2287 params![alias, destination.domain.0, destination.nspace, key_id_guard.id()],
2288 )
2289 .context("Failed to update key entry.")?;
2290
2291 if updated != 1 {
2292 return Err(KsError::sys())
2293 .context(format!("Update succeeded, but {} rows were updated.", updated));
2294 }
2295 Ok(()).no_gc()
2296 })
2297 .context("In migrate_key_namespace:")
2298 }
2299
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002300 /// Store a new key in a single transaction.
2301 /// The function creates a new key entry, populates the blob, key parameter, and metadata
2302 /// fields, and rebinds the given alias to the new key.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002303 /// The boolean returned is a hint for the garbage collector. If true, a key was replaced,
2304 /// is now unreferenced and needs to be collected.
Chris Wailes3877f292021-07-26 19:24:18 -07002305 #[allow(clippy::too_many_arguments)]
Janis Danisevskis66784c42021-01-27 08:40:25 -08002306 pub fn store_new_key(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002307 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002308 key: &KeyDescriptor,
Janis Danisevskis0cabd712021-05-25 11:07:10 -07002309 key_type: KeyType,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002310 params: &[KeyParameter],
Janis Danisevskisf84d0b02022-01-26 14:11:14 -08002311 blob_info: &BlobInfo,
Max Bires8e93d2b2021-01-14 13:17:59 -08002312 cert_info: &CertificateInfo,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002313 metadata: &KeyMetaData,
Max Bires8e93d2b2021-01-14 13:17:59 -08002314 km_uuid: &Uuid,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002315 ) -> Result<KeyIdGuard> {
Janis Danisevskis850d4862021-05-05 08:41:14 -07002316 let _wp = wd::watch_millis("KeystoreDB::store_new_key", 500);
2317
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002318 let (alias, domain, namespace) = match key {
2319 KeyDescriptor { alias: Some(alias), domain: Domain::APP, nspace, blob: None }
2320 | KeyDescriptor { alias: Some(alias), domain: Domain::SELINUX, nspace, blob: None } => {
2321 (alias, key.domain, nspace)
2322 }
2323 _ => {
2324 return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT))
2325 .context("In store_new_key: Need alias and domain must be APP or SELINUX.")
2326 }
2327 };
2328 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis0cabd712021-05-25 11:07:10 -07002329 let key_id = Self::create_key_entry_internal(tx, &domain, namespace, key_type, km_uuid)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002330 .context("Trying to create new key entry.")?;
Janis Danisevskisf84d0b02022-01-26 14:11:14 -08002331 let BlobInfo { blob, metadata: blob_metadata, superseded_blob } = *blob_info;
2332
2333 // In some occasions the key blob is already upgraded during the import.
2334 // In order to make sure it gets properly deleted it is inserted into the
2335 // database here and then immediately replaced by the superseding blob.
2336 // The garbage collector will then subject the blob to deleteKey of the
2337 // KM back end to permanently invalidate the key.
2338 let need_gc = if let Some((blob, blob_metadata)) = superseded_blob {
2339 Self::set_blob_internal(
2340 tx,
2341 key_id.id(),
2342 SubComponentType::KEY_BLOB,
2343 Some(blob),
2344 Some(blob_metadata),
2345 )
2346 .context("Trying to insert superseded key blob.")?;
2347 true
2348 } else {
2349 false
2350 };
2351
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002352 Self::set_blob_internal(
2353 tx,
2354 key_id.id(),
2355 SubComponentType::KEY_BLOB,
2356 Some(blob),
Chris Wailesd5aaaef2021-07-27 16:04:33 -07002357 Some(blob_metadata),
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002358 )
2359 .context("Trying to insert the key blob.")?;
Max Bires8e93d2b2021-01-14 13:17:59 -08002360 if let Some(cert) = &cert_info.cert {
Chris Wailesd5aaaef2021-07-27 16:04:33 -07002361 Self::set_blob_internal(tx, key_id.id(), SubComponentType::CERT, Some(cert), None)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002362 .context("Trying to insert the certificate.")?;
2363 }
Max Bires8e93d2b2021-01-14 13:17:59 -08002364 if let Some(cert_chain) = &cert_info.cert_chain {
Janis Danisevskis377d1002021-01-27 19:07:48 -08002365 Self::set_blob_internal(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002366 tx,
2367 key_id.id(),
2368 SubComponentType::CERT_CHAIN,
Chris Wailesd5aaaef2021-07-27 16:04:33 -07002369 Some(cert_chain),
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002370 None,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002371 )
2372 .context("Trying to insert the certificate chain.")?;
2373 }
2374 Self::insert_keyparameter_internal(tx, &key_id, params)
2375 .context("Trying to insert key parameters.")?;
Janis Danisevskis377d1002021-01-27 19:07:48 -08002376 metadata.store_in_db(key_id.id(), tx).context("Trying to insert key metadata.")?;
Chris Wailesd5aaaef2021-07-27 16:04:33 -07002377 let need_gc = Self::rebind_alias(tx, &key_id, alias, &domain, namespace, key_type)
Janis Danisevskisf84d0b02022-01-26 14:11:14 -08002378 .context("Trying to rebind alias.")?
2379 || need_gc;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002380 Ok(key_id).do_gc(need_gc)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002381 })
2382 .context("In store_new_key.")
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002383 }
2384
Janis Danisevskis377d1002021-01-27 19:07:48 -08002385 /// Store a new certificate
2386 /// The function creates a new key entry, populates the blob field and metadata, and rebinds
2387 /// the given alias to the new cert.
Max Bires8e93d2b2021-01-14 13:17:59 -08002388 pub fn store_new_certificate(
2389 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002390 key: &KeyDescriptor,
Janis Danisevskis0cabd712021-05-25 11:07:10 -07002391 key_type: KeyType,
Max Bires8e93d2b2021-01-14 13:17:59 -08002392 cert: &[u8],
2393 km_uuid: &Uuid,
2394 ) -> Result<KeyIdGuard> {
Janis Danisevskis850d4862021-05-05 08:41:14 -07002395 let _wp = wd::watch_millis("KeystoreDB::store_new_certificate", 500);
2396
Janis Danisevskis377d1002021-01-27 19:07:48 -08002397 let (alias, domain, namespace) = match key {
2398 KeyDescriptor { alias: Some(alias), domain: Domain::APP, nspace, blob: None }
2399 | KeyDescriptor { alias: Some(alias), domain: Domain::SELINUX, nspace, blob: None } => {
2400 (alias, key.domain, nspace)
2401 }
2402 _ => {
2403 return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT)).context(
2404 "In store_new_certificate: Need alias and domain must be APP or SELINUX.",
2405 )
2406 }
2407 };
2408 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis0cabd712021-05-25 11:07:10 -07002409 let key_id = Self::create_key_entry_internal(tx, &domain, namespace, key_type, km_uuid)
Janis Danisevskis377d1002021-01-27 19:07:48 -08002410 .context("Trying to create new key entry.")?;
2411
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002412 Self::set_blob_internal(
2413 tx,
2414 key_id.id(),
2415 SubComponentType::CERT_CHAIN,
2416 Some(cert),
2417 None,
2418 )
2419 .context("Trying to insert certificate.")?;
Janis Danisevskis377d1002021-01-27 19:07:48 -08002420
2421 let mut metadata = KeyMetaData::new();
2422 metadata.add(KeyMetaEntry::CreationDate(
2423 DateTime::now().context("Trying to make creation time.")?,
2424 ));
2425
2426 metadata.store_in_db(key_id.id(), tx).context("Trying to insert key metadata.")?;
2427
Chris Wailesd5aaaef2021-07-27 16:04:33 -07002428 let need_gc = Self::rebind_alias(tx, &key_id, alias, &domain, namespace, key_type)
Janis Danisevskis377d1002021-01-27 19:07:48 -08002429 .context("Trying to rebind alias.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002430 Ok(key_id).do_gc(need_gc)
Janis Danisevskis377d1002021-01-27 19:07:48 -08002431 })
2432 .context("In store_new_certificate.")
2433 }
2434
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002435 // Helper function loading the key_id given the key descriptor
2436 // tuple comprising domain, namespace, and alias.
2437 // Requires a valid transaction.
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002438 fn load_key_entry_id(tx: &Transaction, key: &KeyDescriptor, key_type: KeyType) -> Result<i64> {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002439 let alias = key
2440 .alias
2441 .as_ref()
2442 .map_or_else(|| Err(KsError::sys()), Ok)
2443 .context("In load_key_entry_id: Alias must be specified.")?;
2444 let mut stmt = tx
2445 .prepare(
2446 "SELECT id FROM persistent.keyentry
2447 WHERE
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00002448 key_type = ?
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002449 AND domain = ?
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002450 AND namespace = ?
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002451 AND alias = ?
2452 AND state = ?;",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002453 )
2454 .context("In load_key_entry_id: Failed to select from keyentry table.")?;
2455 let mut rows = stmt
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002456 .query(params![key_type, key.domain.0 as u32, key.nspace, alias, KeyLifeCycle::Live])
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002457 .context("In load_key_entry_id: Failed to read from keyentry table.")?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002458 db_utils::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002459 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002460 .get(0)
2461 .context("Failed to unpack id.")
2462 })
2463 .context("In load_key_entry_id.")
2464 }
2465
2466 /// This helper function completes the access tuple of a key, which is required
2467 /// to perform access control. The strategy depends on the `domain` field in the
2468 /// key descriptor.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002469 /// * Domain::SELINUX: The access tuple is complete and this function only loads
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002470 /// the key_id for further processing.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002471 /// * Domain::APP: Like Domain::SELINUX, but the tuple is completed by `caller_uid`
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002472 /// which serves as the namespace.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002473 /// * Domain::GRANT: The grant table is queried for the `key_id` and the
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002474 /// `access_vector`.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002475 /// * Domain::KEY_ID: The keyentry table is queried for the owning `domain` and
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002476 /// `namespace`.
2477 /// In each case the information returned is sufficient to perform the access
2478 /// check and the key id can be used to load further key artifacts.
2479 fn load_access_tuple(
2480 tx: &Transaction,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002481 key: &KeyDescriptor,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002482 key_type: KeyType,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002483 caller_uid: u32,
2484 ) -> Result<(i64, KeyDescriptor, Option<KeyPermSet>)> {
2485 match key.domain {
2486 // Domain App or SELinux. In this case we load the key_id from
2487 // the keyentry database for further loading of key components.
2488 // We already have the full access tuple to perform access control.
2489 // The only distinction is that we use the caller_uid instead
2490 // of the caller supplied namespace if the domain field is
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002491 // Domain::APP.
2492 Domain::APP | Domain::SELINUX => {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002493 let mut access_key = key.clone();
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002494 if access_key.domain == Domain::APP {
2495 access_key.nspace = caller_uid as i64;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002496 }
Chris Wailesd5aaaef2021-07-27 16:04:33 -07002497 let key_id = Self::load_key_entry_id(tx, &access_key, key_type)
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002498 .with_context(|| format!("With key.domain = {:?}.", access_key.domain))?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002499
2500 Ok((key_id, access_key, None))
2501 }
2502
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002503 // Domain::GRANT. In this case we load the key_id and the access_vector
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002504 // from the grant table.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002505 Domain::GRANT => {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002506 let mut stmt = tx
2507 .prepare(
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002508 "SELECT keyentryid, access_vector FROM persistent.grant
Hasini Gunasinghee70a0ec2021-05-10 21:12:34 +00002509 WHERE grantee = ? AND id = ? AND
2510 (SELECT state FROM persistent.keyentry WHERE id = keyentryid) = ?;",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002511 )
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002512 .context("Domain::GRANT prepare statement failed")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002513 let mut rows = stmt
Hasini Gunasinghee70a0ec2021-05-10 21:12:34 +00002514 .query(params![caller_uid as i64, key.nspace, KeyLifeCycle::Live])
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002515 .context("Domain:Grant: query failed.")?;
2516 let (key_id, access_vector): (i64, i32) =
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002517 db_utils::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002518 let r =
2519 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002520 Ok((
2521 r.get(0).context("Failed to unpack key_id.")?,
2522 r.get(1).context("Failed to unpack access_vector.")?,
2523 ))
2524 })
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002525 .context("Domain::GRANT.")?;
Janis Danisevskis66784c42021-01-27 08:40:25 -08002526 Ok((key_id, key.clone(), Some(access_vector.into())))
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002527 }
2528
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002529 // Domain::KEY_ID. In this case we load the domain and namespace from the
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002530 // keyentry database because we need them for access control.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002531 Domain::KEY_ID => {
Janis Danisevskis45760022021-01-19 16:34:10 -08002532 let (domain, namespace): (Domain, i64) = {
2533 let mut stmt = tx
2534 .prepare(
2535 "SELECT domain, namespace FROM persistent.keyentry
2536 WHERE
2537 id = ?
2538 AND state = ?;",
2539 )
2540 .context("Domain::KEY_ID: prepare statement failed")?;
2541 let mut rows = stmt
2542 .query(params![key.nspace, KeyLifeCycle::Live])
2543 .context("Domain::KEY_ID: query failed.")?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002544 db_utils::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002545 let r =
2546 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002547 Ok((
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002548 Domain(r.get(0).context("Failed to unpack domain.")?),
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002549 r.get(1).context("Failed to unpack namespace.")?,
2550 ))
2551 })
Janis Danisevskis45760022021-01-19 16:34:10 -08002552 .context("Domain::KEY_ID.")?
2553 };
2554
2555 // We may use a key by id after loading it by grant.
2556 // In this case we have to check if the caller has a grant for this particular
2557 // key. We can skip this if we already know that the caller is the owner.
2558 // But we cannot know this if domain is anything but App. E.g. in the case
2559 // of Domain::SELINUX we have to speculatively check for grants because we have to
2560 // consult the SEPolicy before we know if the caller is the owner.
2561 let access_vector: Option<KeyPermSet> =
2562 if domain != Domain::APP || namespace != caller_uid as i64 {
2563 let access_vector: Option<i32> = tx
2564 .query_row(
2565 "SELECT access_vector FROM persistent.grant
2566 WHERE grantee = ? AND keyentryid = ?;",
2567 params![caller_uid as i64, key.nspace],
2568 |row| row.get(0),
2569 )
2570 .optional()
2571 .context("Domain::KEY_ID: query grant failed.")?;
2572 access_vector.map(|p| p.into())
2573 } else {
2574 None
2575 };
2576
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002577 let key_id = key.nspace;
Janis Danisevskis66784c42021-01-27 08:40:25 -08002578 let mut access_key: KeyDescriptor = key.clone();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002579 access_key.domain = domain;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002580 access_key.nspace = namespace;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002581
Janis Danisevskis45760022021-01-19 16:34:10 -08002582 Ok((key_id, access_key, access_vector))
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002583 }
2584 _ => Err(anyhow!(KsError::sys())),
2585 }
2586 }
2587
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002588 fn load_blob_components(
2589 key_id: i64,
2590 load_bits: KeyEntryLoadBits,
2591 tx: &Transaction,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002592 ) -> Result<(bool, Option<(Vec<u8>, BlobMetaData)>, Option<Vec<u8>>, Option<Vec<u8>>)> {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002593 let mut stmt = tx
2594 .prepare(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002595 "SELECT MAX(id), subcomponent_type, blob FROM persistent.blobentry
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002596 WHERE keyentryid = ? GROUP BY subcomponent_type;",
2597 )
2598 .context("In load_blob_components: prepare statement failed.")?;
2599
2600 let mut rows =
2601 stmt.query(params![key_id]).context("In load_blob_components: query failed.")?;
2602
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002603 let mut key_blob: Option<(i64, Vec<u8>)> = None;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002604 let mut cert_blob: Option<Vec<u8>> = None;
2605 let mut cert_chain_blob: Option<Vec<u8>> = None;
Janis Danisevskis377d1002021-01-27 19:07:48 -08002606 let mut has_km_blob: bool = false;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002607 db_utils::with_rows_extract_all(&mut rows, |row| {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002608 let sub_type: SubComponentType =
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002609 row.get(1).context("Failed to extract subcomponent_type.")?;
Janis Danisevskis377d1002021-01-27 19:07:48 -08002610 has_km_blob = has_km_blob || sub_type == SubComponentType::KEY_BLOB;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002611 match (sub_type, load_bits.load_public(), load_bits.load_km()) {
2612 (SubComponentType::KEY_BLOB, _, true) => {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002613 key_blob = Some((
2614 row.get(0).context("Failed to extract key blob id.")?,
2615 row.get(2).context("Failed to extract key blob.")?,
2616 ));
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002617 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002618 (SubComponentType::CERT, true, _) => {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002619 cert_blob =
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002620 Some(row.get(2).context("Failed to extract public certificate blob.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002621 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002622 (SubComponentType::CERT_CHAIN, true, _) => {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002623 cert_chain_blob =
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002624 Some(row.get(2).context("Failed to extract certificate chain blob.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002625 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002626 (SubComponentType::CERT, _, _)
2627 | (SubComponentType::CERT_CHAIN, _, _)
2628 | (SubComponentType::KEY_BLOB, _, _) => {}
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002629 _ => Err(KsError::sys()).context("Unknown subcomponent type.")?,
2630 }
2631 Ok(())
2632 })
2633 .context("In load_blob_components.")?;
2634
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002635 let blob_info = key_blob.map_or::<Result<_>, _>(Ok(None), |(blob_id, blob)| {
2636 Ok(Some((
2637 blob,
2638 BlobMetaData::load_from_db(blob_id, tx)
2639 .context("In load_blob_components: Trying to load blob_metadata.")?,
2640 )))
2641 })?;
2642
2643 Ok((has_km_blob, blob_info, cert_blob, cert_chain_blob))
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002644 }
2645
2646 fn load_key_parameters(key_id: i64, tx: &Transaction) -> Result<Vec<KeyParameter>> {
2647 let mut stmt = tx
2648 .prepare(
2649 "SELECT tag, data, security_level from persistent.keyparameter
2650 WHERE keyentryid = ?;",
2651 )
2652 .context("In load_key_parameters: prepare statement failed.")?;
2653
2654 let mut parameters: Vec<KeyParameter> = Vec::new();
2655
2656 let mut rows =
2657 stmt.query(params![key_id]).context("In load_key_parameters: query failed.")?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002658 db_utils::with_rows_extract_all(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002659 let tag = Tag(row.get(0).context("Failed to read tag.")?);
2660 let sec_level = SecurityLevel(row.get(2).context("Failed to read sec_level.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002661 parameters.push(
Chris Wailesd5aaaef2021-07-27 16:04:33 -07002662 KeyParameter::new_from_sql(tag, &SqlField::new(1, row), sec_level)
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002663 .context("Failed to read KeyParameter.")?,
2664 );
2665 Ok(())
2666 })
2667 .context("In load_key_parameters.")?;
2668
2669 Ok(parameters)
2670 }
2671
Qi Wub9433b52020-12-01 14:52:46 +08002672 /// Decrements the usage count of a limited use key. This function first checks whether the
2673 /// usage has been exhausted, if not, decreases the usage count. If the usage count reaches
2674 /// zero, the key also gets marked unreferenced and scheduled for deletion.
2675 /// Returns Ok(true) if the key was marked unreferenced as a hint to the garbage collector.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002676 pub fn check_and_update_key_usage_count(&mut self, key_id: i64) -> Result<()> {
Janis Danisevskis850d4862021-05-05 08:41:14 -07002677 let _wp = wd::watch_millis("KeystoreDB::check_and_update_key_usage_count", 500);
2678
Qi Wub9433b52020-12-01 14:52:46 +08002679 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2680 let limit: Option<i32> = tx
2681 .query_row(
2682 "SELECT data FROM persistent.keyparameter WHERE keyentryid = ? AND tag = ?;",
2683 params![key_id, Tag::USAGE_COUNT_LIMIT.0],
2684 |row| row.get(0),
2685 )
2686 .optional()
2687 .context("Trying to load usage count")?;
2688
2689 let limit = limit
2690 .ok_or(KsError::Km(ErrorCode::INVALID_KEY_BLOB))
2691 .context("The Key no longer exists. Key is exhausted.")?;
2692
2693 tx.execute(
2694 "UPDATE persistent.keyparameter
2695 SET data = data - 1
2696 WHERE keyentryid = ? AND tag = ? AND data > 0;",
2697 params![key_id, Tag::USAGE_COUNT_LIMIT.0],
2698 )
2699 .context("Failed to update key usage count.")?;
2700
2701 match limit {
2702 1 => Self::mark_unreferenced(tx, key_id)
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002703 .map(|need_gc| (need_gc, ()))
Qi Wub9433b52020-12-01 14:52:46 +08002704 .context("Trying to mark limited use key for deletion."),
2705 0 => Err(KsError::Km(ErrorCode::INVALID_KEY_BLOB)).context("Key is exhausted."),
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002706 _ => Ok(()).no_gc(),
Qi Wub9433b52020-12-01 14:52:46 +08002707 }
2708 })
2709 .context("In check_and_update_key_usage_count.")
2710 }
2711
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002712 /// Load a key entry by the given key descriptor.
2713 /// It uses the `check_permission` callback to verify if the access is allowed
2714 /// given the key access tuple read from the database using `load_access_tuple`.
2715 /// With `load_bits` the caller may specify which blobs shall be loaded from
2716 /// the blob database.
2717 pub fn load_key_entry(
2718 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002719 key: &KeyDescriptor,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002720 key_type: KeyType,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002721 load_bits: KeyEntryLoadBits,
2722 caller_uid: u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002723 check_permission: impl Fn(&KeyDescriptor, Option<KeyPermSet>) -> Result<()>,
2724 ) -> Result<(KeyIdGuard, KeyEntry)> {
Janis Danisevskis850d4862021-05-05 08:41:14 -07002725 let _wp = wd::watch_millis("KeystoreDB::load_key_entry", 500);
2726
Janis Danisevskis66784c42021-01-27 08:40:25 -08002727 loop {
2728 match self.load_key_entry_internal(
2729 key,
2730 key_type,
2731 load_bits,
2732 caller_uid,
2733 &check_permission,
2734 ) {
2735 Ok(result) => break Ok(result),
2736 Err(e) => {
2737 if Self::is_locked_error(&e) {
2738 std::thread::sleep(std::time::Duration::from_micros(500));
2739 continue;
2740 } else {
2741 return Err(e).context("In load_key_entry.");
2742 }
2743 }
2744 }
2745 }
2746 }
2747
2748 fn load_key_entry_internal(
2749 &mut self,
2750 key: &KeyDescriptor,
2751 key_type: KeyType,
2752 load_bits: KeyEntryLoadBits,
2753 caller_uid: u32,
2754 check_permission: &impl Fn(&KeyDescriptor, Option<KeyPermSet>) -> Result<()>,
Janis Danisevskisaec14592020-11-12 09:41:49 -08002755 ) -> Result<(KeyIdGuard, KeyEntry)> {
2756 // KEY ID LOCK 1/2
2757 // If we got a key descriptor with a key id we can get the lock right away.
2758 // Otherwise we have to defer it until we know the key id.
2759 let key_id_guard = match key.domain {
2760 Domain::KEY_ID => Some(KEY_ID_LOCK.get(key.nspace)),
2761 _ => None,
2762 };
2763
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002764 let tx = self
2765 .conn
Janis Danisevskisaec14592020-11-12 09:41:49 -08002766 .unchecked_transaction()
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002767 .context("In load_key_entry: Failed to initialize transaction.")?;
2768
2769 // Load the key_id and complete the access control tuple.
2770 let (key_id, access_key_descriptor, access_vector) =
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002771 Self::load_access_tuple(&tx, key, key_type, caller_uid)
2772 .context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002773
2774 // Perform access control. It is vital that we return here if the permission is denied.
2775 // So do not touch that '?' at the end.
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002776 check_permission(&access_key_descriptor, access_vector).context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002777
Janis Danisevskisaec14592020-11-12 09:41:49 -08002778 // KEY ID LOCK 2/2
2779 // If we did not get a key id lock by now, it was because we got a key descriptor
2780 // without a key id. At this point we got the key id, so we can try and get a lock.
2781 // However, we cannot block here, because we are in the middle of the transaction.
2782 // So first we try to get the lock non blocking. If that fails, we roll back the
2783 // transaction and block until we get the lock. After we successfully got the lock,
2784 // we start a new transaction and load the access tuple again.
2785 //
2786 // We don't need to perform access control again, because we already established
2787 // that the caller had access to the given key. But we need to make sure that the
2788 // key id still exists. So we have to load the key entry by key id this time.
2789 let (key_id_guard, tx) = match key_id_guard {
2790 None => match KEY_ID_LOCK.try_get(key_id) {
2791 None => {
2792 // Roll back the transaction.
2793 tx.rollback().context("In load_key_entry: Failed to roll back transaction.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002794
Janis Danisevskisaec14592020-11-12 09:41:49 -08002795 // Block until we have a key id lock.
2796 let key_id_guard = KEY_ID_LOCK.get(key_id);
2797
2798 // Create a new transaction.
Janis Danisevskis66784c42021-01-27 08:40:25 -08002799 let tx = self
2800 .conn
2801 .unchecked_transaction()
2802 .context("In load_key_entry: Failed to initialize transaction.")?;
Janis Danisevskisaec14592020-11-12 09:41:49 -08002803
2804 Self::load_access_tuple(
2805 &tx,
2806 // This time we have to load the key by the retrieved key id, because the
2807 // alias may have been rebound after we rolled back the transaction.
Janis Danisevskis66784c42021-01-27 08:40:25 -08002808 &KeyDescriptor {
Janis Danisevskisaec14592020-11-12 09:41:49 -08002809 domain: Domain::KEY_ID,
2810 nspace: key_id,
2811 ..Default::default()
2812 },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002813 key_type,
Janis Danisevskisaec14592020-11-12 09:41:49 -08002814 caller_uid,
2815 )
2816 .context("In load_key_entry. (deferred key lock)")?;
2817 (key_id_guard, tx)
2818 }
2819 Some(l) => (l, tx),
2820 },
2821 Some(key_id_guard) => (key_id_guard, tx),
2822 };
2823
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002824 let key_entry = Self::load_key_components(&tx, load_bits, key_id_guard.id())
2825 .context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002826
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002827 tx.commit().context("In load_key_entry: Failed to commit transaction.")?;
2828
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002829 Ok((key_id_guard, key_entry))
2830 }
2831
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002832 fn mark_unreferenced(tx: &Transaction, key_id: i64) -> Result<bool> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002833 let updated = tx
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002834 .execute("DELETE FROM persistent.keyentry WHERE id = ?;", params![key_id])
2835 .context("Trying to delete keyentry.")?;
2836 tx.execute("DELETE FROM persistent.keymetadata WHERE keyentryid = ?;", params![key_id])
2837 .context("Trying to delete keymetadata.")?;
2838 tx.execute("DELETE FROM persistent.keyparameter WHERE keyentryid = ?;", params![key_id])
2839 .context("Trying to delete keyparameters.")?;
2840 tx.execute("DELETE FROM persistent.grant WHERE keyentryid = ?;", params![key_id])
2841 .context("Trying to delete grants.")?;
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002842 Ok(updated != 0)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002843 }
2844
2845 /// Marks the given key as unreferenced and removes all of the grants to this key.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002846 /// Returns Ok(true) if a key was marked unreferenced as a hint for the garbage collector.
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002847 pub fn unbind_key(
2848 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002849 key: &KeyDescriptor,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002850 key_type: KeyType,
2851 caller_uid: u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002852 check_permission: impl Fn(&KeyDescriptor, Option<KeyPermSet>) -> Result<()>,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002853 ) -> Result<()> {
Janis Danisevskis850d4862021-05-05 08:41:14 -07002854 let _wp = wd::watch_millis("KeystoreDB::unbind_key", 500);
2855
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002856 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2857 let (key_id, access_key_descriptor, access_vector) =
2858 Self::load_access_tuple(tx, key, key_type, caller_uid)
2859 .context("Trying to get access tuple.")?;
2860
2861 // Perform access control. It is vital that we return here if the permission is denied.
2862 // So do not touch that '?' at the end.
2863 check_permission(&access_key_descriptor, access_vector)
2864 .context("While checking permission.")?;
2865
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002866 Self::mark_unreferenced(tx, key_id)
2867 .map(|need_gc| (need_gc, ()))
2868 .context("Trying to mark the key unreferenced.")
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002869 })
2870 .context("In unbind_key.")
2871 }
2872
Max Bires8e93d2b2021-01-14 13:17:59 -08002873 fn get_key_km_uuid(tx: &Transaction, key_id: i64) -> Result<Uuid> {
2874 tx.query_row(
2875 "SELECT km_uuid FROM persistent.keyentry WHERE id = ?",
2876 params![key_id],
2877 |row| row.get(0),
2878 )
2879 .context("In get_key_km_uuid.")
2880 }
2881
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002882 /// Delete all artifacts belonging to the namespace given by the domain-namespace tuple.
2883 /// This leaves all of the blob entries orphaned for subsequent garbage collection.
2884 pub fn unbind_keys_for_namespace(&mut self, domain: Domain, namespace: i64) -> Result<()> {
Janis Danisevskis850d4862021-05-05 08:41:14 -07002885 let _wp = wd::watch_millis("KeystoreDB::unbind_keys_for_namespace", 500);
2886
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002887 if !(domain == Domain::APP || domain == Domain::SELINUX) {
2888 return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT))
2889 .context("In unbind_keys_for_namespace.");
2890 }
2891 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2892 tx.execute(
2893 "DELETE FROM persistent.keymetadata
2894 WHERE keyentryid IN (
2895 SELECT id FROM persistent.keyentry
Janis Danisevskisb146f312021-05-06 15:05:45 -07002896 WHERE domain = ? AND namespace = ? AND key_type = ?
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002897 );",
Janis Danisevskisb146f312021-05-06 15:05:45 -07002898 params![domain.0, namespace, KeyType::Client],
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002899 )
2900 .context("Trying to delete keymetadata.")?;
2901 tx.execute(
2902 "DELETE FROM persistent.keyparameter
2903 WHERE keyentryid IN (
2904 SELECT id FROM persistent.keyentry
Janis Danisevskisb146f312021-05-06 15:05:45 -07002905 WHERE domain = ? AND namespace = ? AND key_type = ?
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002906 );",
Janis Danisevskisb146f312021-05-06 15:05:45 -07002907 params![domain.0, namespace, KeyType::Client],
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002908 )
2909 .context("Trying to delete keyparameters.")?;
2910 tx.execute(
2911 "DELETE FROM persistent.grant
2912 WHERE keyentryid IN (
2913 SELECT id FROM persistent.keyentry
Janis Danisevskisb146f312021-05-06 15:05:45 -07002914 WHERE domain = ? AND namespace = ? AND key_type = ?
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002915 );",
Janis Danisevskisb146f312021-05-06 15:05:45 -07002916 params![domain.0, namespace, KeyType::Client],
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002917 )
2918 .context("Trying to delete grants.")?;
2919 tx.execute(
Janis Danisevskisb146f312021-05-06 15:05:45 -07002920 "DELETE FROM persistent.keyentry
2921 WHERE domain = ? AND namespace = ? AND key_type = ?;",
2922 params![domain.0, namespace, KeyType::Client],
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002923 )
2924 .context("Trying to delete keyentry.")?;
2925 Ok(()).need_gc()
2926 })
2927 .context("In unbind_keys_for_namespace")
2928 }
2929
Janis Danisevskis3cba10d2021-05-06 17:02:19 -07002930 fn cleanup_unreferenced(tx: &Transaction) -> Result<()> {
2931 let _wp = wd::watch_millis("KeystoreDB::cleanup_unreferenced", 500);
2932 {
2933 tx.execute(
2934 "DELETE FROM persistent.keymetadata
2935 WHERE keyentryid IN (
2936 SELECT id FROM persistent.keyentry
2937 WHERE state = ?
2938 );",
2939 params![KeyLifeCycle::Unreferenced],
2940 )
2941 .context("Trying to delete keymetadata.")?;
2942 tx.execute(
2943 "DELETE FROM persistent.keyparameter
2944 WHERE keyentryid IN (
2945 SELECT id FROM persistent.keyentry
2946 WHERE state = ?
2947 );",
2948 params![KeyLifeCycle::Unreferenced],
2949 )
2950 .context("Trying to delete keyparameters.")?;
2951 tx.execute(
2952 "DELETE FROM persistent.grant
2953 WHERE keyentryid IN (
2954 SELECT id FROM persistent.keyentry
2955 WHERE state = ?
2956 );",
2957 params![KeyLifeCycle::Unreferenced],
2958 )
2959 .context("Trying to delete grants.")?;
2960 tx.execute(
2961 "DELETE FROM persistent.keyentry
2962 WHERE state = ?;",
2963 params![KeyLifeCycle::Unreferenced],
2964 )
2965 .context("Trying to delete keyentry.")?;
2966 Result::<()>::Ok(())
2967 }
2968 .context("In cleanup_unreferenced")
2969 }
2970
Hasini Gunasingheda895552021-01-27 19:34:37 +00002971 /// Delete the keys created on behalf of the user, denoted by the user id.
2972 /// Delete all the keys unless 'keep_non_super_encrypted_keys' set to true.
2973 /// Returned boolean is to hint the garbage collector to delete the unbound keys.
2974 /// The caller of this function should notify the gc if the returned value is true.
2975 pub fn unbind_keys_for_user(
2976 &mut self,
2977 user_id: u32,
2978 keep_non_super_encrypted_keys: bool,
2979 ) -> Result<()> {
Janis Danisevskis850d4862021-05-05 08:41:14 -07002980 let _wp = wd::watch_millis("KeystoreDB::unbind_keys_for_user", 500);
2981
Hasini Gunasingheda895552021-01-27 19:34:37 +00002982 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2983 let mut stmt = tx
2984 .prepare(&format!(
2985 "SELECT id from persistent.keyentry
2986 WHERE (
2987 key_type = ?
2988 AND domain = ?
2989 AND cast ( (namespace/{aid_user_offset}) as int) = ?
2990 AND state = ?
2991 ) OR (
2992 key_type = ?
2993 AND namespace = ?
Hasini Gunasingheda895552021-01-27 19:34:37 +00002994 AND state = ?
2995 );",
2996 aid_user_offset = AID_USER_OFFSET
2997 ))
2998 .context(concat!(
2999 "In unbind_keys_for_user. ",
3000 "Failed to prepare the query to find the keys created by apps."
3001 ))?;
3002
3003 let mut rows = stmt
3004 .query(params![
3005 // WHERE client key:
3006 KeyType::Client,
3007 Domain::APP.0 as u32,
3008 user_id,
3009 KeyLifeCycle::Live,
3010 // OR super key:
3011 KeyType::Super,
3012 user_id,
Hasini Gunasingheda895552021-01-27 19:34:37 +00003013 KeyLifeCycle::Live
3014 ])
3015 .context("In unbind_keys_for_user. Failed to query the keys created by apps.")?;
3016
3017 let mut key_ids: Vec<i64> = Vec::new();
3018 db_utils::with_rows_extract_all(&mut rows, |row| {
3019 key_ids
3020 .push(row.get(0).context("Failed to read key id of a key created by an app.")?);
3021 Ok(())
3022 })
3023 .context("In unbind_keys_for_user.")?;
3024
3025 let mut notify_gc = false;
3026 for key_id in key_ids {
3027 if keep_non_super_encrypted_keys {
3028 // Load metadata and filter out non-super-encrypted keys.
3029 if let (_, Some((_, blob_metadata)), _, _) =
3030 Self::load_blob_components(key_id, KeyEntryLoadBits::KM, tx)
3031 .context("In unbind_keys_for_user: Trying to load blob info.")?
3032 {
3033 if blob_metadata.encrypted_by().is_none() {
3034 continue;
3035 }
3036 }
3037 }
Chris Wailesd5aaaef2021-07-27 16:04:33 -07003038 notify_gc = Self::mark_unreferenced(tx, key_id)
Hasini Gunasingheda895552021-01-27 19:34:37 +00003039 .context("In unbind_keys_for_user.")?
3040 || notify_gc;
3041 }
3042 Ok(()).do_gc(notify_gc)
3043 })
3044 .context("In unbind_keys_for_user.")
3045 }
3046
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003047 fn load_key_components(
3048 tx: &Transaction,
3049 load_bits: KeyEntryLoadBits,
3050 key_id: i64,
3051 ) -> Result<KeyEntry> {
Chris Wailesd5aaaef2021-07-27 16:04:33 -07003052 let metadata = KeyMetaData::load_from_db(key_id, tx).context("In load_key_components.")?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003053
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003054 let (has_km_blob, key_blob_info, cert_blob, cert_chain_blob) =
Chris Wailesd5aaaef2021-07-27 16:04:33 -07003055 Self::load_blob_components(key_id, load_bits, tx).context("In load_key_components.")?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003056
Chris Wailesd5aaaef2021-07-27 16:04:33 -07003057 let parameters = Self::load_key_parameters(key_id, tx)
Max Bires8e93d2b2021-01-14 13:17:59 -08003058 .context("In load_key_components: Trying to load key parameters.")?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003059
Chris Wailesd5aaaef2021-07-27 16:04:33 -07003060 let km_uuid = Self::get_key_km_uuid(tx, key_id)
Max Bires8e93d2b2021-01-14 13:17:59 -08003061 .context("In load_key_components: Trying to get KM uuid.")?;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003062
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003063 Ok(KeyEntry {
3064 id: key_id,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003065 key_blob_info,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003066 cert: cert_blob,
3067 cert_chain: cert_chain_blob,
Max Bires8e93d2b2021-01-14 13:17:59 -08003068 km_uuid,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003069 parameters,
3070 metadata,
Janis Danisevskis377d1002021-01-27 19:07:48 -08003071 pure_cert: !has_km_blob,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003072 })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003073 }
3074
Janis Danisevskise92a5e62020-12-02 12:57:41 -08003075 /// Returns a list of KeyDescriptors in the selected domain/namespace.
3076 /// The key descriptors will have the domain, nspace, and alias field set.
3077 /// Domain must be APP or SELINUX, the caller must make sure of that.
Janis Danisevskis18313832021-05-17 13:30:32 -07003078 pub fn list(
3079 &mut self,
3080 domain: Domain,
3081 namespace: i64,
3082 key_type: KeyType,
3083 ) -> Result<Vec<KeyDescriptor>> {
Janis Danisevskis850d4862021-05-05 08:41:14 -07003084 let _wp = wd::watch_millis("KeystoreDB::list", 500);
3085
Janis Danisevskis66784c42021-01-27 08:40:25 -08003086 self.with_transaction(TransactionBehavior::Deferred, |tx| {
3087 let mut stmt = tx
3088 .prepare(
3089 "SELECT alias FROM persistent.keyentry
Janis Danisevskis18313832021-05-17 13:30:32 -07003090 WHERE domain = ?
3091 AND namespace = ?
3092 AND alias IS NOT NULL
3093 AND state = ?
3094 AND key_type = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08003095 )
3096 .context("In list: Failed to prepare.")?;
Janis Danisevskise92a5e62020-12-02 12:57:41 -08003097
Janis Danisevskis66784c42021-01-27 08:40:25 -08003098 let mut rows = stmt
Janis Danisevskis18313832021-05-17 13:30:32 -07003099 .query(params![domain.0 as u32, namespace, KeyLifeCycle::Live, key_type])
Janis Danisevskis66784c42021-01-27 08:40:25 -08003100 .context("In list: Failed to query.")?;
Janis Danisevskise92a5e62020-12-02 12:57:41 -08003101
Janis Danisevskis66784c42021-01-27 08:40:25 -08003102 let mut descriptors: Vec<KeyDescriptor> = Vec::new();
3103 db_utils::with_rows_extract_all(&mut rows, |row| {
3104 descriptors.push(KeyDescriptor {
3105 domain,
3106 nspace: namespace,
3107 alias: Some(row.get(0).context("Trying to extract alias.")?),
3108 blob: None,
3109 });
3110 Ok(())
3111 })
3112 .context("In list: Failed to extract rows.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003113 Ok(descriptors).no_gc()
Janis Danisevskise92a5e62020-12-02 12:57:41 -08003114 })
Janis Danisevskise92a5e62020-12-02 12:57:41 -08003115 }
3116
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003117 /// Adds a grant to the grant table.
3118 /// Like `load_key_entry` this function loads the access tuple before
3119 /// it uses the callback for a permission check. Upon success,
3120 /// it inserts the `grantee_uid`, `key_id`, and `access_vector` into the
3121 /// grant table. The new row will have a randomized id, which is used as
3122 /// grant id in the namespace field of the resulting KeyDescriptor.
3123 pub fn grant(
3124 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08003125 key: &KeyDescriptor,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003126 caller_uid: u32,
3127 grantee_uid: u32,
3128 access_vector: KeyPermSet,
Janis Danisevskis66784c42021-01-27 08:40:25 -08003129 check_permission: impl Fn(&KeyDescriptor, &KeyPermSet) -> Result<()>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003130 ) -> Result<KeyDescriptor> {
Janis Danisevskis850d4862021-05-05 08:41:14 -07003131 let _wp = wd::watch_millis("KeystoreDB::grant", 500);
3132
Janis Danisevskis66784c42021-01-27 08:40:25 -08003133 self.with_transaction(TransactionBehavior::Immediate, |tx| {
3134 // Load the key_id and complete the access control tuple.
3135 // We ignore the access vector here because grants cannot be granted.
3136 // The access vector returned here expresses the permissions the
3137 // grantee has if key.domain == Domain::GRANT. But this vector
3138 // cannot include the grant permission by design, so there is no way the
3139 // subsequent permission check can pass.
3140 // We could check key.domain == Domain::GRANT and fail early.
3141 // But even if we load the access tuple by grant here, the permission
3142 // check denies the attempt to create a grant by grant descriptor.
3143 let (key_id, access_key_descriptor, _) =
Chris Wailesd5aaaef2021-07-27 16:04:33 -07003144 Self::load_access_tuple(tx, key, KeyType::Client, caller_uid)
Janis Danisevskis66784c42021-01-27 08:40:25 -08003145 .context("In grant")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003146
Janis Danisevskis66784c42021-01-27 08:40:25 -08003147 // Perform access control. It is vital that we return here if the permission
3148 // was denied. So do not touch that '?' at the end of the line.
3149 // This permission check checks if the caller has the grant permission
3150 // for the given key and in addition to all of the permissions
3151 // expressed in `access_vector`.
3152 check_permission(&access_key_descriptor, &access_vector)
3153 .context("In grant: check_permission failed.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003154
Janis Danisevskis66784c42021-01-27 08:40:25 -08003155 let grant_id = if let Some(grant_id) = tx
3156 .query_row(
3157 "SELECT id FROM persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003158 WHERE keyentryid = ? AND grantee = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08003159 params![key_id, grantee_uid],
3160 |row| row.get(0),
3161 )
3162 .optional()
3163 .context("In grant: Failed get optional existing grant id.")?
3164 {
3165 tx.execute(
3166 "UPDATE persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003167 SET access_vector = ?
3168 WHERE id = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08003169 params![i32::from(access_vector), grant_id],
Joel Galenson845f74b2020-09-09 14:11:55 -07003170 )
Janis Danisevskis66784c42021-01-27 08:40:25 -08003171 .context("In grant: Failed to update existing grant.")?;
3172 grant_id
3173 } else {
3174 Self::insert_with_retry(|id| {
3175 tx.execute(
3176 "INSERT INTO persistent.grant (id, grantee, keyentryid, access_vector)
3177 VALUES (?, ?, ?, ?);",
3178 params![id, grantee_uid, key_id, i32::from(access_vector)],
3179 )
3180 })
3181 .context("In grant")?
3182 };
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003183
Janis Danisevskis66784c42021-01-27 08:40:25 -08003184 Ok(KeyDescriptor { domain: Domain::GRANT, nspace: grant_id, alias: None, blob: None })
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003185 .no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08003186 })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003187 }
3188
3189 /// This function checks permissions like `grant` and `load_key_entry`
3190 /// before removing a grant from the grant table.
3191 pub fn ungrant(
3192 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08003193 key: &KeyDescriptor,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003194 caller_uid: u32,
3195 grantee_uid: u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08003196 check_permission: impl Fn(&KeyDescriptor) -> Result<()>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003197 ) -> Result<()> {
Janis Danisevskis850d4862021-05-05 08:41:14 -07003198 let _wp = wd::watch_millis("KeystoreDB::ungrant", 500);
3199
Janis Danisevskis66784c42021-01-27 08:40:25 -08003200 self.with_transaction(TransactionBehavior::Immediate, |tx| {
3201 // Load the key_id and complete the access control tuple.
3202 // We ignore the access vector here because grants cannot be granted.
3203 let (key_id, access_key_descriptor, _) =
Chris Wailesd5aaaef2021-07-27 16:04:33 -07003204 Self::load_access_tuple(tx, key, KeyType::Client, caller_uid)
Janis Danisevskis66784c42021-01-27 08:40:25 -08003205 .context("In ungrant.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003206
Janis Danisevskis66784c42021-01-27 08:40:25 -08003207 // Perform access control. We must return here if the permission
3208 // was denied. So do not touch the '?' at the end of this line.
3209 check_permission(&access_key_descriptor)
3210 .context("In grant: check_permission failed.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003211
Janis Danisevskis66784c42021-01-27 08:40:25 -08003212 tx.execute(
3213 "DELETE FROM persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003214 WHERE keyentryid = ? AND grantee = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08003215 params![key_id, grantee_uid],
3216 )
3217 .context("Failed to delete grant.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003218
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003219 Ok(()).no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08003220 })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003221 }
3222
Joel Galenson845f74b2020-09-09 14:11:55 -07003223 // Generates a random id and passes it to the given function, which will
3224 // try to insert it into a database. If that insertion fails, retry;
3225 // otherwise return the id.
3226 fn insert_with_retry(inserter: impl Fn(i64) -> rusqlite::Result<usize>) -> Result<i64> {
3227 loop {
Janis Danisevskiseed69842021-02-18 20:04:10 -08003228 let newid: i64 = match random() {
3229 Self::UNASSIGNED_KEY_ID => continue, // UNASSIGNED_KEY_ID cannot be assigned.
3230 i => i,
3231 };
Joel Galenson845f74b2020-09-09 14:11:55 -07003232 match inserter(newid) {
3233 // If the id already existed, try again.
3234 Err(rusqlite::Error::SqliteFailure(
3235 libsqlite3_sys::Error {
3236 code: libsqlite3_sys::ErrorCode::ConstraintViolation,
3237 extended_code: libsqlite3_sys::SQLITE_CONSTRAINT_UNIQUE,
3238 },
3239 _,
3240 )) => (),
3241 Err(e) => {
3242 return Err(e).context("In insert_with_retry: failed to insert into database.")
3243 }
3244 _ => return Ok(newid),
3245 }
3246 }
3247 }
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00003248
Matthew Maurerd7815ca2021-05-06 21:58:45 -07003249 /// Insert or replace the auth token based on (user_id, auth_id, auth_type)
3250 pub fn insert_auth_token(&mut self, auth_token: &HardwareAuthToken) {
3251 self.perboot.insert_auth_token_entry(AuthTokenEntry::new(
3252 auth_token.clone(),
3253 MonotonicRawTime::now(),
3254 ))
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00003255 }
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00003256
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08003257 /// Find the newest auth token matching the given predicate.
Matthew Maurerd7815ca2021-05-06 21:58:45 -07003258 pub fn find_auth_token_entry<F>(&self, p: F) -> Option<(AuthTokenEntry, MonotonicRawTime)>
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08003259 where
3260 F: Fn(&AuthTokenEntry) -> bool,
3261 {
Matthew Maurerd7815ca2021-05-06 21:58:45 -07003262 self.perboot.find_auth_token_entry(p).map(|entry| (entry, self.get_last_off_body()))
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00003263 }
3264
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08003265 /// Insert last_off_body into the metadata table at the initialization of auth token table
Matthew Maurerd7815ca2021-05-06 21:58:45 -07003266 pub fn insert_last_off_body(&self, last_off_body: MonotonicRawTime) {
3267 self.perboot.set_last_off_body(last_off_body)
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00003268 }
3269
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08003270 /// Update last_off_body when on_device_off_body is called
Matthew Maurerd7815ca2021-05-06 21:58:45 -07003271 pub fn update_last_off_body(&self, last_off_body: MonotonicRawTime) {
3272 self.perboot.set_last_off_body(last_off_body)
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00003273 }
3274
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08003275 /// Get last_off_body time when finding auth tokens
Matthew Maurerd7815ca2021-05-06 21:58:45 -07003276 fn get_last_off_body(&self) -> MonotonicRawTime {
3277 self.perboot.get_last_off_body()
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00003278 }
Pavel Grafovf45034a2021-05-12 22:35:45 +01003279
3280 /// Load descriptor of a key by key id
3281 pub fn load_key_descriptor(&mut self, key_id: i64) -> Result<Option<KeyDescriptor>> {
3282 let _wp = wd::watch_millis("KeystoreDB::load_key_descriptor", 500);
3283
3284 self.with_transaction(TransactionBehavior::Deferred, |tx| {
3285 tx.query_row(
3286 "SELECT domain, namespace, alias FROM persistent.keyentry WHERE id = ?;",
3287 params![key_id],
3288 |row| {
3289 Ok(KeyDescriptor {
3290 domain: Domain(row.get(0)?),
3291 nspace: row.get(1)?,
3292 alias: row.get(2)?,
3293 blob: None,
3294 })
3295 },
3296 )
3297 .optional()
3298 .context("Trying to load key descriptor")
3299 .no_gc()
3300 })
3301 .context("In load_key_descriptor.")
3302 }
Joel Galenson26f4d012020-07-17 14:57:21 -07003303}
3304
3305#[cfg(test)]
Seth Moore7ee79f92021-12-07 11:42:49 -08003306pub mod tests {
Joel Galenson26f4d012020-07-17 14:57:21 -07003307
3308 use super::*;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07003309 use crate::key_parameter::{
3310 Algorithm, BlockMode, Digest, EcCurve, HardwareAuthenticatorType, KeyOrigin, KeyParameter,
3311 KeyParameterValue, KeyPurpose, PaddingMode, SecurityLevel,
3312 };
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003313 use crate::key_perm_set;
3314 use crate::permission::{KeyPerm, KeyPermSet};
Janis Danisevskis11bd2592022-01-04 19:59:26 -08003315 use crate::super_key::{SuperKeyManager, USER_SUPER_KEY, SuperEncryptionAlgorithm, SuperKeyType};
Janis Danisevskis2a8330a2021-01-20 15:34:26 -08003316 use keystore2_test_utils::TempDir;
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00003317 use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
3318 HardwareAuthToken::HardwareAuthToken,
3319 HardwareAuthenticatorType::HardwareAuthenticatorType as kmhw_authenticator_type,
Janis Danisevskisc3a496b2021-01-05 10:37:22 -08003320 };
3321 use android_hardware_security_secureclock::aidl::android::hardware::security::secureclock::{
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00003322 Timestamp::Timestamp,
3323 };
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003324 use rusqlite::NO_PARAMS;
Matthew Maurerd7815ca2021-05-06 21:58:45 -07003325 use rusqlite::TransactionBehavior;
Joel Galenson0891bc12020-07-20 10:37:03 -07003326 use std::cell::RefCell;
Seth Moore78c091f2021-04-09 21:38:30 +00003327 use std::collections::BTreeMap;
3328 use std::fmt::Write;
Janis Danisevskisaec14592020-11-12 09:41:49 -08003329 use std::sync::atomic::{AtomicU8, Ordering};
Janis Danisevskis0fd25a62022-01-04 19:53:37 -08003330 use std::sync::{Arc, RwLock};
Janis Danisevskisaec14592020-11-12 09:41:49 -08003331 use std::thread;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00003332 use std::time::{Duration, SystemTime};
Janis Danisevskisf84d0b02022-01-26 14:11:14 -08003333 use crate::utils::AesGcm;
Janis Danisevskis66784c42021-01-27 08:40:25 -08003334 #[cfg(disabled)]
3335 use std::time::Instant;
Joel Galenson0891bc12020-07-20 10:37:03 -07003336
Seth Moore7ee79f92021-12-07 11:42:49 -08003337 pub fn new_test_db() -> Result<KeystoreDB> {
Matthew Maurerd7815ca2021-05-06 21:58:45 -07003338 let conn = KeystoreDB::make_connection("file::memory:")?;
Janis Danisevskis4df44f42020-08-26 14:40:03 -07003339
Matthew Maurerd7815ca2021-05-06 21:58:45 -07003340 let mut db = KeystoreDB { conn, gc: None, perboot: Arc::new(perboot::PerbootDB::new()) };
Janis Danisevskis66784c42021-01-27 08:40:25 -08003341 db.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003342 KeystoreDB::init_tables(tx).context("Failed to initialize tables.").no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08003343 })?;
3344 Ok(db)
Janis Danisevskis4df44f42020-08-26 14:40:03 -07003345 }
3346
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003347 fn new_test_db_with_gc<F>(path: &Path, cb: F) -> Result<KeystoreDB>
3348 where
3349 F: Fn(&Uuid, &[u8]) -> Result<()> + Send + 'static,
3350 {
Janis Danisevskis0fd25a62022-01-04 19:53:37 -08003351 let super_key: Arc<RwLock<SuperKeyManager>> = Default::default();
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00003352
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003353 let gc_db = KeystoreDB::new(path, None).expect("Failed to open test gc db_connection.");
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00003354 let gc = Gc::new_init_with(Default::default(), move || (Box::new(cb), gc_db, super_key));
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003355
Janis Danisevskis3395f862021-05-06 10:54:17 -07003356 KeystoreDB::new(path, Some(Arc::new(gc)))
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003357 }
3358
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003359 fn rebind_alias(
3360 db: &mut KeystoreDB,
3361 newid: &KeyIdGuard,
3362 alias: &str,
3363 domain: Domain,
3364 namespace: i64,
3365 ) -> Result<bool> {
3366 db.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis0cabd712021-05-25 11:07:10 -07003367 KeystoreDB::rebind_alias(tx, newid, alias, &domain, &namespace, KeyType::Client).no_gc()
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003368 })
3369 .context("In rebind_alias.")
3370 }
3371
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003372 #[test]
3373 fn datetime() -> Result<()> {
3374 let conn = Connection::open_in_memory()?;
3375 conn.execute("CREATE TABLE test (ts DATETIME);", NO_PARAMS)?;
3376 let now = SystemTime::now();
3377 let duration = Duration::from_secs(1000);
3378 let then = now.checked_sub(duration).unwrap();
3379 let soon = now.checked_add(duration).unwrap();
3380 conn.execute(
3381 "INSERT INTO test (ts) VALUES (?), (?), (?);",
3382 params![DateTime::try_from(now)?, DateTime::try_from(then)?, DateTime::try_from(soon)?],
3383 )?;
3384 let mut stmt = conn.prepare("SELECT ts FROM test ORDER BY ts ASC;")?;
3385 let mut rows = stmt.query(NO_PARAMS)?;
3386 assert_eq!(DateTime::try_from(then)?, rows.next()?.unwrap().get(0)?);
3387 assert_eq!(DateTime::try_from(now)?, rows.next()?.unwrap().get(0)?);
3388 assert_eq!(DateTime::try_from(soon)?, rows.next()?.unwrap().get(0)?);
3389 assert!(rows.next()?.is_none());
3390 assert!(DateTime::try_from(then)? < DateTime::try_from(now)?);
3391 assert!(DateTime::try_from(then)? < DateTime::try_from(soon)?);
3392 assert!(DateTime::try_from(now)? < DateTime::try_from(soon)?);
3393 Ok(())
3394 }
3395
Joel Galenson0891bc12020-07-20 10:37:03 -07003396 // Ensure that we're using the "injected" random function, not the real one.
3397 #[test]
3398 fn test_mocked_random() {
3399 let rand1 = random();
3400 let rand2 = random();
3401 let rand3 = random();
3402 if rand1 == rand2 {
3403 assert_eq!(rand2 + 1, rand3);
3404 } else {
3405 assert_eq!(rand1 + 1, rand2);
3406 assert_eq!(rand2, rand3);
3407 }
3408 }
Joel Galenson26f4d012020-07-17 14:57:21 -07003409
Joel Galenson26f4d012020-07-17 14:57:21 -07003410 // Test that we have the correct tables.
3411 #[test]
3412 fn test_tables() -> Result<()> {
Janis Danisevskis4df44f42020-08-26 14:40:03 -07003413 let db = new_test_db()?;
Joel Galenson26f4d012020-07-17 14:57:21 -07003414 let tables = db
3415 .conn
Joel Galenson2aab4432020-07-22 15:27:57 -07003416 .prepare("SELECT name from persistent.sqlite_master WHERE type='table' ORDER BY name;")?
Joel Galenson26f4d012020-07-17 14:57:21 -07003417 .query_map(params![], |row| row.get(0))?
3418 .collect::<rusqlite::Result<Vec<String>>>()?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003419 assert_eq!(tables.len(), 6);
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003420 assert_eq!(tables[0], "blobentry");
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003421 assert_eq!(tables[1], "blobmetadata");
3422 assert_eq!(tables[2], "grant");
3423 assert_eq!(tables[3], "keyentry");
3424 assert_eq!(tables[4], "keymetadata");
3425 assert_eq!(tables[5], "keyparameter");
Joel Galenson2aab4432020-07-22 15:27:57 -07003426 Ok(())
3427 }
3428
3429 #[test]
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00003430 fn test_auth_token_table_invariant() -> Result<()> {
3431 let mut db = new_test_db()?;
3432 let auth_token1 = HardwareAuthToken {
3433 challenge: i64::MAX,
3434 userId: 200,
3435 authenticatorId: 200,
3436 authenticatorType: kmhw_authenticator_type(kmhw_authenticator_type::PASSWORD.0),
3437 timestamp: Timestamp { milliSeconds: 500 },
3438 mac: String::from("mac").into_bytes(),
3439 };
Matthew Maurerd7815ca2021-05-06 21:58:45 -07003440 db.insert_auth_token(&auth_token1);
3441 let auth_tokens_returned = get_auth_tokens(&db);
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00003442 assert_eq!(auth_tokens_returned.len(), 1);
3443
3444 // insert another auth token with the same values for the columns in the UNIQUE constraint
3445 // of the auth token table and different value for timestamp
3446 let auth_token2 = HardwareAuthToken {
3447 challenge: i64::MAX,
3448 userId: 200,
3449 authenticatorId: 200,
3450 authenticatorType: kmhw_authenticator_type(kmhw_authenticator_type::PASSWORD.0),
3451 timestamp: Timestamp { milliSeconds: 600 },
3452 mac: String::from("mac").into_bytes(),
3453 };
3454
Matthew Maurerd7815ca2021-05-06 21:58:45 -07003455 db.insert_auth_token(&auth_token2);
3456 let mut auth_tokens_returned = get_auth_tokens(&db);
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00003457 assert_eq!(auth_tokens_returned.len(), 1);
3458
3459 if let Some(auth_token) = auth_tokens_returned.pop() {
3460 assert_eq!(auth_token.auth_token.timestamp.milliSeconds, 600);
3461 }
3462
3463 // insert another auth token with the different values for the columns in the UNIQUE
3464 // constraint of the auth token table
3465 let auth_token3 = HardwareAuthToken {
3466 challenge: i64::MAX,
3467 userId: 201,
3468 authenticatorId: 200,
3469 authenticatorType: kmhw_authenticator_type(kmhw_authenticator_type::PASSWORD.0),
3470 timestamp: Timestamp { milliSeconds: 600 },
3471 mac: String::from("mac").into_bytes(),
3472 };
3473
Matthew Maurerd7815ca2021-05-06 21:58:45 -07003474 db.insert_auth_token(&auth_token3);
3475 let auth_tokens_returned = get_auth_tokens(&db);
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00003476 assert_eq!(auth_tokens_returned.len(), 2);
3477
3478 Ok(())
3479 }
3480
3481 // utility function for test_auth_token_table_invariant()
Matthew Maurerd7815ca2021-05-06 21:58:45 -07003482 fn get_auth_tokens(db: &KeystoreDB) -> Vec<AuthTokenEntry> {
3483 db.perboot.get_all_auth_token_entries()
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00003484 }
3485
3486 #[test]
Joel Galenson2aab4432020-07-22 15:27:57 -07003487 fn test_persistence_for_files() -> Result<()> {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08003488 let temp_dir = TempDir::new("persistent_db_test")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003489 let mut db = KeystoreDB::new(temp_dir.path(), None)?;
Joel Galenson2aab4432020-07-22 15:27:57 -07003490
Janis Danisevskis0cabd712021-05-25 11:07:10 -07003491 db.create_key_entry(&Domain::APP, &100, KeyType::Client, &KEYSTORE_UUID)?;
Joel Galenson2aab4432020-07-22 15:27:57 -07003492 let entries = get_keyentry(&db)?;
3493 assert_eq!(entries.len(), 1);
Janis Danisevskisbf15d732020-12-08 10:35:26 -08003494
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003495 let db = KeystoreDB::new(temp_dir.path(), None)?;
Joel Galenson2aab4432020-07-22 15:27:57 -07003496
3497 let entries_new = get_keyentry(&db)?;
3498 assert_eq!(entries, entries_new);
3499 Ok(())
3500 }
3501
3502 #[test]
Joel Galenson0891bc12020-07-20 10:37:03 -07003503 fn test_create_key_entry() -> Result<()> {
Max Bires8e93d2b2021-01-14 13:17:59 -08003504 fn extractor(ke: &KeyEntryRow) -> (Domain, i64, Option<&str>, Uuid) {
3505 (ke.domain.unwrap(), ke.namespace.unwrap(), ke.alias.as_deref(), ke.km_uuid.unwrap())
Joel Galenson0891bc12020-07-20 10:37:03 -07003506 }
3507
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003508 let mut db = new_test_db()?;
Joel Galenson0891bc12020-07-20 10:37:03 -07003509
Janis Danisevskis0cabd712021-05-25 11:07:10 -07003510 db.create_key_entry(&Domain::APP, &100, KeyType::Client, &KEYSTORE_UUID)?;
3511 db.create_key_entry(&Domain::SELINUX, &101, KeyType::Client, &KEYSTORE_UUID)?;
Joel Galenson0891bc12020-07-20 10:37:03 -07003512
3513 let entries = get_keyentry(&db)?;
3514 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08003515 assert_eq!(extractor(&entries[0]), (Domain::APP, 100, None, KEYSTORE_UUID));
3516 assert_eq!(extractor(&entries[1]), (Domain::SELINUX, 101, None, KEYSTORE_UUID));
Joel Galenson0891bc12020-07-20 10:37:03 -07003517
3518 // Test that we must pass in a valid Domain.
3519 check_result_is_error_containing_string(
Janis Danisevskis0cabd712021-05-25 11:07:10 -07003520 db.create_key_entry(&Domain::GRANT, &102, KeyType::Client, &KEYSTORE_UUID),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003521 "Domain Domain(1) must be either App or SELinux.",
Joel Galenson0891bc12020-07-20 10:37:03 -07003522 );
3523 check_result_is_error_containing_string(
Janis Danisevskis0cabd712021-05-25 11:07:10 -07003524 db.create_key_entry(&Domain::BLOB, &103, KeyType::Client, &KEYSTORE_UUID),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003525 "Domain Domain(3) must be either App or SELinux.",
Joel Galenson0891bc12020-07-20 10:37:03 -07003526 );
3527 check_result_is_error_containing_string(
Janis Danisevskis0cabd712021-05-25 11:07:10 -07003528 db.create_key_entry(&Domain::KEY_ID, &104, KeyType::Client, &KEYSTORE_UUID),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003529 "Domain Domain(4) must be either App or SELinux.",
Joel Galenson0891bc12020-07-20 10:37:03 -07003530 );
3531
3532 Ok(())
3533 }
3534
Joel Galenson33c04ad2020-08-03 11:04:38 -07003535 #[test]
Max Bires2b2e6562020-09-22 11:22:36 -07003536 fn test_add_unsigned_key() -> Result<()> {
3537 let mut db = new_test_db()?;
3538 let public_key: Vec<u8> = vec![0x01, 0x02, 0x03];
3539 let private_key: Vec<u8> = vec![0x04, 0x05, 0x06];
3540 let raw_public_key: Vec<u8> = vec![0x07, 0x08, 0x09];
3541 db.create_attestation_key_entry(
3542 &public_key,
3543 &raw_public_key,
3544 &private_key,
3545 &KEYSTORE_UUID,
3546 )?;
3547 let keys = db.fetch_unsigned_attestation_keys(5, &KEYSTORE_UUID)?;
3548 assert_eq!(keys.len(), 1);
3549 assert_eq!(keys[0], public_key);
3550 Ok(())
3551 }
3552
3553 #[test]
3554 fn test_store_signed_attestation_certificate_chain() -> Result<()> {
3555 let mut db = new_test_db()?;
Max Birescd7f7412022-02-11 13:47:36 -08003556 let expiration_date: i64 =
3557 SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_millis() as i64
3558 + EXPIRATION_BUFFER_MS
3559 + 10000;
Max Bires2b2e6562020-09-22 11:22:36 -07003560 let namespace: i64 = 30;
3561 let base_byte: u8 = 1;
3562 let loaded_values =
3563 load_attestation_key_pool(&mut db, expiration_date, namespace, base_byte)?;
3564 let chain =
3565 db.retrieve_attestation_key_and_cert_chain(Domain::APP, namespace, &KEYSTORE_UUID)?;
Chris Wailes3877f292021-07-26 19:24:18 -07003566 assert!(chain.is_some());
Max Bires55620ff2022-02-11 13:34:15 -08003567 let (_, cert_chain) = chain.unwrap();
Max Biresb2e1d032021-02-08 21:35:05 -08003568 assert_eq!(cert_chain.private_key.to_vec(), loaded_values.priv_key);
Max Bires97f96812021-02-23 23:44:57 -08003569 assert_eq!(cert_chain.batch_cert, loaded_values.batch_cert);
3570 assert_eq!(cert_chain.cert_chain, loaded_values.cert_chain);
Max Bires2b2e6562020-09-22 11:22:36 -07003571 Ok(())
3572 }
3573
3574 #[test]
3575 fn test_get_attestation_pool_status() -> Result<()> {
3576 let mut db = new_test_db()?;
3577 let namespace: i64 = 30;
3578 load_attestation_key_pool(
3579 &mut db, 10, /* expiration */
3580 namespace, 0x01, /* base_byte */
3581 )?;
3582 load_attestation_key_pool(&mut db, 20 /* expiration */, namespace + 1, 0x02)?;
3583 load_attestation_key_pool(&mut db, 40 /* expiration */, namespace + 2, 0x03)?;
3584 let mut status = db.get_attestation_pool_status(9 /* expiration */, &KEYSTORE_UUID)?;
3585 assert_eq!(status.expiring, 0);
3586 assert_eq!(status.attested, 3);
3587 assert_eq!(status.unassigned, 0);
3588 assert_eq!(status.total, 3);
3589 assert_eq!(
3590 db.get_attestation_pool_status(15 /* expiration */, &KEYSTORE_UUID)?.expiring,
3591 1
3592 );
3593 assert_eq!(
3594 db.get_attestation_pool_status(25 /* expiration */, &KEYSTORE_UUID)?.expiring,
3595 2
3596 );
3597 assert_eq!(
3598 db.get_attestation_pool_status(60 /* expiration */, &KEYSTORE_UUID)?.expiring,
3599 3
3600 );
3601 let public_key: Vec<u8> = vec![0x01, 0x02, 0x03];
3602 let private_key: Vec<u8> = vec![0x04, 0x05, 0x06];
3603 let raw_public_key: Vec<u8> = vec![0x07, 0x08, 0x09];
3604 let cert_chain: Vec<u8> = vec![0x0a, 0x0b, 0x0c];
Max Biresb2e1d032021-02-08 21:35:05 -08003605 let batch_cert: Vec<u8> = vec![0x0d, 0x0e, 0x0f];
Max Bires2b2e6562020-09-22 11:22:36 -07003606 db.create_attestation_key_entry(
3607 &public_key,
3608 &raw_public_key,
3609 &private_key,
3610 &KEYSTORE_UUID,
3611 )?;
3612 status = db.get_attestation_pool_status(0 /* expiration */, &KEYSTORE_UUID)?;
3613 assert_eq!(status.attested, 3);
3614 assert_eq!(status.unassigned, 0);
3615 assert_eq!(status.total, 4);
3616 db.store_signed_attestation_certificate_chain(
3617 &raw_public_key,
Max Biresb2e1d032021-02-08 21:35:05 -08003618 &batch_cert,
Max Bires2b2e6562020-09-22 11:22:36 -07003619 &cert_chain,
3620 20,
3621 &KEYSTORE_UUID,
3622 )?;
3623 status = db.get_attestation_pool_status(0 /* expiration */, &KEYSTORE_UUID)?;
3624 assert_eq!(status.attested, 4);
3625 assert_eq!(status.unassigned, 1);
3626 assert_eq!(status.total, 4);
3627 Ok(())
3628 }
3629
3630 #[test]
3631 fn test_remove_expired_certs() -> Result<()> {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003632 let temp_dir =
3633 TempDir::new("test_remove_expired_certs_").expect("Failed to create temp dir.");
3634 let mut db = new_test_db_with_gc(temp_dir.path(), |_, _| Ok(()))?;
Max Bires2b2e6562020-09-22 11:22:36 -07003635 let expiration_date: i64 =
Max Birescd7f7412022-02-11 13:47:36 -08003636 SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_millis() as i64
3637 + EXPIRATION_BUFFER_MS
3638 + 10000;
Max Bires2b2e6562020-09-22 11:22:36 -07003639 let namespace: i64 = 30;
3640 let namespace_del1: i64 = 45;
3641 let namespace_del2: i64 = 60;
3642 let entry_values = load_attestation_key_pool(
3643 &mut db,
3644 expiration_date,
3645 namespace,
3646 0x01, /* base_byte */
3647 )?;
3648 load_attestation_key_pool(&mut db, 45, namespace_del1, 0x02)?;
Max Birescd7f7412022-02-11 13:47:36 -08003649 load_attestation_key_pool(&mut db, expiration_date - 10001, namespace_del2, 0x03)?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003650
3651 let blob_entry_row_count: u32 = db
3652 .conn
3653 .query_row("SELECT COUNT(id) FROM persistent.blobentry;", NO_PARAMS, |row| row.get(0))
3654 .expect("Failed to get blob entry row count.");
Max Biresb2e1d032021-02-08 21:35:05 -08003655 // We expect 9 rows here because there are three blobs per attestation key, i.e.,
3656 // one key, one certificate chain, and one certificate.
3657 assert_eq!(blob_entry_row_count, 9);
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003658
Max Bires2b2e6562020-09-22 11:22:36 -07003659 assert_eq!(db.delete_expired_attestation_keys()?, 2);
3660
3661 let mut cert_chain =
3662 db.retrieve_attestation_key_and_cert_chain(Domain::APP, namespace, &KEYSTORE_UUID)?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003663 assert!(cert_chain.is_some());
Max Bires55620ff2022-02-11 13:34:15 -08003664 let (_, value) = cert_chain.unwrap();
Max Bires97f96812021-02-23 23:44:57 -08003665 assert_eq!(entry_values.batch_cert, value.batch_cert);
3666 assert_eq!(entry_values.cert_chain, value.cert_chain);
Max Biresb2e1d032021-02-08 21:35:05 -08003667 assert_eq!(entry_values.priv_key, value.private_key.to_vec());
Max Bires2b2e6562020-09-22 11:22:36 -07003668
3669 cert_chain = db.retrieve_attestation_key_and_cert_chain(
3670 Domain::APP,
3671 namespace_del1,
3672 &KEYSTORE_UUID,
3673 )?;
Chariseea1e1c482022-02-26 01:26:35 +00003674 assert!(cert_chain.is_none());
Max Bires2b2e6562020-09-22 11:22:36 -07003675 cert_chain = db.retrieve_attestation_key_and_cert_chain(
3676 Domain::APP,
3677 namespace_del2,
3678 &KEYSTORE_UUID,
3679 )?;
Chariseea1e1c482022-02-26 01:26:35 +00003680 assert!(cert_chain.is_none());
Max Bires2b2e6562020-09-22 11:22:36 -07003681
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003682 // Give the garbage collector half a second to catch up.
3683 std::thread::sleep(Duration::from_millis(500));
Max Bires2b2e6562020-09-22 11:22:36 -07003684
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003685 let blob_entry_row_count: u32 = db
3686 .conn
3687 .query_row("SELECT COUNT(id) FROM persistent.blobentry;", NO_PARAMS, |row| row.get(0))
3688 .expect("Failed to get blob entry row count.");
Max Biresb2e1d032021-02-08 21:35:05 -08003689 // There shound be 3 blob entries left, because we deleted two of the attestation
3690 // key entries with three blobs each.
3691 assert_eq!(blob_entry_row_count, 3);
Max Bires2b2e6562020-09-22 11:22:36 -07003692
Max Bires2b2e6562020-09-22 11:22:36 -07003693 Ok(())
3694 }
3695
Max Birescd7f7412022-02-11 13:47:36 -08003696 fn compare_rem_prov_values(
3697 expected: &RemoteProvValues,
3698 actual: Option<(KeyIdGuard, CertificateChain)>,
3699 ) {
3700 assert!(actual.is_some());
3701 let (_, value) = actual.unwrap();
3702 assert_eq!(expected.batch_cert, value.batch_cert);
3703 assert_eq!(expected.cert_chain, value.cert_chain);
3704 assert_eq!(expected.priv_key, value.private_key.to_vec());
3705 }
3706
3707 #[test]
3708 fn test_dont_remove_valid_certs() -> Result<()> {
3709 let temp_dir =
3710 TempDir::new("test_remove_expired_certs_").expect("Failed to create temp dir.");
3711 let mut db = new_test_db_with_gc(temp_dir.path(), |_, _| Ok(()))?;
3712 let expiration_date: i64 =
3713 SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_millis() as i64
3714 + EXPIRATION_BUFFER_MS
3715 + 10000;
3716 let namespace1: i64 = 30;
3717 let namespace2: i64 = 45;
3718 let namespace3: i64 = 60;
3719 let entry_values1 = load_attestation_key_pool(
3720 &mut db,
3721 expiration_date,
3722 namespace1,
3723 0x01, /* base_byte */
3724 )?;
3725 let entry_values2 =
3726 load_attestation_key_pool(&mut db, expiration_date + 40000, namespace2, 0x02)?;
3727 let entry_values3 =
3728 load_attestation_key_pool(&mut db, expiration_date - 9000, namespace3, 0x03)?;
3729
3730 let blob_entry_row_count: u32 = db
3731 .conn
3732 .query_row("SELECT COUNT(id) FROM persistent.blobentry;", NO_PARAMS, |row| row.get(0))
3733 .expect("Failed to get blob entry row count.");
3734 // We expect 9 rows here because there are three blobs per attestation key, i.e.,
3735 // one key, one certificate chain, and one certificate.
3736 assert_eq!(blob_entry_row_count, 9);
3737
3738 let mut cert_chain =
3739 db.retrieve_attestation_key_and_cert_chain(Domain::APP, namespace1, &KEYSTORE_UUID)?;
3740 compare_rem_prov_values(&entry_values1, cert_chain);
3741
3742 cert_chain =
3743 db.retrieve_attestation_key_and_cert_chain(Domain::APP, namespace2, &KEYSTORE_UUID)?;
3744 compare_rem_prov_values(&entry_values2, cert_chain);
3745
3746 cert_chain =
3747 db.retrieve_attestation_key_and_cert_chain(Domain::APP, namespace3, &KEYSTORE_UUID)?;
3748 compare_rem_prov_values(&entry_values3, cert_chain);
3749
3750 // Give the garbage collector half a second to catch up.
3751 std::thread::sleep(Duration::from_millis(500));
3752
3753 let blob_entry_row_count: u32 = db
3754 .conn
3755 .query_row("SELECT COUNT(id) FROM persistent.blobentry;", NO_PARAMS, |row| row.get(0))
3756 .expect("Failed to get blob entry row count.");
3757 // There shound be 9 blob entries left, because all three keys are valid with
3758 // three blobs each.
3759 assert_eq!(blob_entry_row_count, 9);
3760
3761 Ok(())
3762 }
Max Bires2b2e6562020-09-22 11:22:36 -07003763 #[test]
Max Bires60d7ed12021-03-05 15:59:22 -08003764 fn test_delete_all_attestation_keys() -> Result<()> {
3765 let mut db = new_test_db()?;
3766 load_attestation_key_pool(&mut db, 45 /* expiration */, 1 /* namespace */, 0x02)?;
3767 load_attestation_key_pool(&mut db, 80 /* expiration */, 2 /* namespace */, 0x03)?;
Janis Danisevskis0cabd712021-05-25 11:07:10 -07003768 db.create_key_entry(&Domain::APP, &42, KeyType::Client, &KEYSTORE_UUID)?;
Max Bires60d7ed12021-03-05 15:59:22 -08003769 let result = db.delete_all_attestation_keys()?;
3770
3771 // Give the garbage collector half a second to catch up.
3772 std::thread::sleep(Duration::from_millis(500));
3773
3774 // Attestation keys should be deleted, and the regular key should remain.
3775 assert_eq!(result, 2);
3776
3777 Ok(())
3778 }
3779
3780 #[test]
Joel Galenson33c04ad2020-08-03 11:04:38 -07003781 fn test_rebind_alias() -> Result<()> {
Max Bires8e93d2b2021-01-14 13:17:59 -08003782 fn extractor(
3783 ke: &KeyEntryRow,
3784 ) -> (Option<Domain>, Option<i64>, Option<&str>, Option<Uuid>) {
3785 (ke.domain, ke.namespace, ke.alias.as_deref(), ke.km_uuid)
Joel Galenson33c04ad2020-08-03 11:04:38 -07003786 }
3787
Janis Danisevskis4df44f42020-08-26 14:40:03 -07003788 let mut db = new_test_db()?;
Janis Danisevskis0cabd712021-05-25 11:07:10 -07003789 db.create_key_entry(&Domain::APP, &42, KeyType::Client, &KEYSTORE_UUID)?;
3790 db.create_key_entry(&Domain::APP, &42, KeyType::Client, &KEYSTORE_UUID)?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07003791 let entries = get_keyentry(&db)?;
3792 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08003793 assert_eq!(
3794 extractor(&entries[0]),
3795 (Some(Domain::APP), Some(42), None, Some(KEYSTORE_UUID))
3796 );
3797 assert_eq!(
3798 extractor(&entries[1]),
3799 (Some(Domain::APP), Some(42), None, Some(KEYSTORE_UUID))
3800 );
Joel Galenson33c04ad2020-08-03 11:04:38 -07003801
3802 // Test that the first call to rebind_alias sets the alias.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003803 rebind_alias(&mut db, &KEY_ID_LOCK.get(entries[0].id), "foo", Domain::APP, 42)?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07003804 let entries = get_keyentry(&db)?;
3805 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08003806 assert_eq!(
3807 extractor(&entries[0]),
3808 (Some(Domain::APP), Some(42), Some("foo"), Some(KEYSTORE_UUID))
3809 );
3810 assert_eq!(
3811 extractor(&entries[1]),
3812 (Some(Domain::APP), Some(42), None, Some(KEYSTORE_UUID))
3813 );
Joel Galenson33c04ad2020-08-03 11:04:38 -07003814
3815 // Test that the second call to rebind_alias also empties the old one.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003816 rebind_alias(&mut db, &KEY_ID_LOCK.get(entries[1].id), "foo", Domain::APP, 42)?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07003817 let entries = get_keyentry(&db)?;
3818 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08003819 assert_eq!(extractor(&entries[0]), (None, None, None, Some(KEYSTORE_UUID)));
3820 assert_eq!(
3821 extractor(&entries[1]),
3822 (Some(Domain::APP), Some(42), Some("foo"), Some(KEYSTORE_UUID))
3823 );
Joel Galenson33c04ad2020-08-03 11:04:38 -07003824
3825 // Test that we must pass in a valid Domain.
3826 check_result_is_error_containing_string(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003827 rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::GRANT, 42),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003828 "Domain Domain(1) must be either App or SELinux.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07003829 );
3830 check_result_is_error_containing_string(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003831 rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::BLOB, 42),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003832 "Domain Domain(3) must be either App or SELinux.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07003833 );
3834 check_result_is_error_containing_string(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003835 rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::KEY_ID, 42),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003836 "Domain Domain(4) must be either App or SELinux.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07003837 );
3838
3839 // Test that we correctly handle setting an alias for something that does not exist.
3840 check_result_is_error_containing_string(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003841 rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::SELINUX, 42),
Joel Galenson33c04ad2020-08-03 11:04:38 -07003842 "Expected to update a single entry but instead updated 0",
3843 );
3844 // Test that we correctly abort the transaction in this case.
3845 let entries = get_keyentry(&db)?;
3846 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08003847 assert_eq!(extractor(&entries[0]), (None, None, None, Some(KEYSTORE_UUID)));
3848 assert_eq!(
3849 extractor(&entries[1]),
3850 (Some(Domain::APP), Some(42), Some("foo"), Some(KEYSTORE_UUID))
3851 );
Joel Galenson33c04ad2020-08-03 11:04:38 -07003852
3853 Ok(())
3854 }
3855
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003856 #[test]
3857 fn test_grant_ungrant() -> Result<()> {
3858 const CALLER_UID: u32 = 15;
3859 const GRANTEE_UID: u32 = 12;
3860 const SELINUX_NAMESPACE: i64 = 7;
3861
3862 let mut db = new_test_db()?;
3863 db.conn.execute(
Max Bires8e93d2b2021-01-14 13:17:59 -08003864 "INSERT INTO persistent.keyentry (id, key_type, domain, namespace, alias, state, km_uuid)
3865 VALUES (1, 0, 0, 15, 'key', 1, ?), (2, 0, 2, 7, 'yek', 1, ?);",
3866 params![KEYSTORE_UUID, KEYSTORE_UUID],
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003867 )?;
3868 let app_key = KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003869 domain: super::Domain::APP,
3870 nspace: 0,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003871 alias: Some("key".to_string()),
3872 blob: None,
3873 };
Janis Danisevskis39d57e72021-10-19 16:56:20 -07003874 const PVEC1: KeyPermSet = key_perm_set![KeyPerm::Use, KeyPerm::GetInfo];
3875 const PVEC2: KeyPermSet = key_perm_set![KeyPerm::Use];
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003876
3877 // Reset totally predictable random number generator in case we
3878 // are not the first test running on this thread.
3879 reset_random();
3880 let next_random = 0i64;
3881
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003882 let app_granted_key = db
Janis Danisevskis66784c42021-01-27 08:40:25 -08003883 .grant(&app_key, CALLER_UID, GRANTEE_UID, PVEC1, |k, a| {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003884 assert_eq!(*a, PVEC1);
3885 assert_eq!(
3886 *k,
3887 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003888 domain: super::Domain::APP,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003889 // namespace must be set to the caller_uid.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003890 nspace: CALLER_UID as i64,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003891 alias: Some("key".to_string()),
3892 blob: None,
3893 }
3894 );
3895 Ok(())
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003896 })
3897 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003898
3899 assert_eq!(
3900 app_granted_key,
3901 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003902 domain: super::Domain::GRANT,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003903 // The grantid is next_random due to the mock random number generator.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003904 nspace: next_random,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003905 alias: None,
3906 blob: None,
3907 }
3908 );
3909
3910 let selinux_key = KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003911 domain: super::Domain::SELINUX,
3912 nspace: SELINUX_NAMESPACE,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003913 alias: Some("yek".to_string()),
3914 blob: None,
3915 };
3916
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003917 let selinux_granted_key = db
Janis Danisevskis66784c42021-01-27 08:40:25 -08003918 .grant(&selinux_key, CALLER_UID, 12, PVEC1, |k, a| {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003919 assert_eq!(*a, PVEC1);
3920 assert_eq!(
3921 *k,
3922 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003923 domain: super::Domain::SELINUX,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003924 // namespace must be the supplied SELinux
3925 // namespace.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003926 nspace: SELINUX_NAMESPACE,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003927 alias: Some("yek".to_string()),
3928 blob: None,
3929 }
3930 );
3931 Ok(())
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003932 })
3933 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003934
3935 assert_eq!(
3936 selinux_granted_key,
3937 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003938 domain: super::Domain::GRANT,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003939 // The grantid is next_random + 1 due to the mock random number generator.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003940 nspace: next_random + 1,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003941 alias: None,
3942 blob: None,
3943 }
3944 );
3945
3946 // This should update the existing grant with PVEC2.
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003947 let selinux_granted_key = db
Janis Danisevskis66784c42021-01-27 08:40:25 -08003948 .grant(&selinux_key, CALLER_UID, 12, PVEC2, |k, a| {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003949 assert_eq!(*a, PVEC2);
3950 assert_eq!(
3951 *k,
3952 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003953 domain: super::Domain::SELINUX,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003954 // namespace must be the supplied SELinux
3955 // namespace.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003956 nspace: SELINUX_NAMESPACE,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003957 alias: Some("yek".to_string()),
3958 blob: None,
3959 }
3960 );
3961 Ok(())
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003962 })
3963 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003964
3965 assert_eq!(
3966 selinux_granted_key,
3967 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003968 domain: super::Domain::GRANT,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003969 // Same grant id as before. The entry was only updated.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003970 nspace: next_random + 1,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003971 alias: None,
3972 blob: None,
3973 }
3974 );
3975
3976 {
3977 // Limiting scope of stmt, because it borrows db.
3978 let mut stmt = db
3979 .conn
Janis Danisevskisbf15d732020-12-08 10:35:26 -08003980 .prepare("SELECT id, grantee, keyentryid, access_vector FROM persistent.grant;")?;
Janis Danisevskisee10b5f2020-09-22 16:42:35 -07003981 let mut rows =
3982 stmt.query_map::<(i64, u32, i64, KeyPermSet), _, _>(NO_PARAMS, |row| {
3983 Ok((
3984 row.get(0)?,
3985 row.get(1)?,
3986 row.get(2)?,
3987 KeyPermSet::from(row.get::<_, i32>(3)?),
3988 ))
3989 })?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003990
3991 let r = rows.next().unwrap().unwrap();
Janis Danisevskisee10b5f2020-09-22 16:42:35 -07003992 assert_eq!(r, (next_random, GRANTEE_UID, 1, PVEC1));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003993 let r = rows.next().unwrap().unwrap();
Janis Danisevskisee10b5f2020-09-22 16:42:35 -07003994 assert_eq!(r, (next_random + 1, GRANTEE_UID, 2, PVEC2));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003995 assert!(rows.next().is_none());
3996 }
3997
3998 debug_dump_keyentry_table(&mut db)?;
3999 println!("app_key {:?}", app_key);
4000 println!("selinux_key {:?}", selinux_key);
4001
Janis Danisevskis66784c42021-01-27 08:40:25 -08004002 db.ungrant(&app_key, CALLER_UID, GRANTEE_UID, |_| Ok(()))?;
4003 db.ungrant(&selinux_key, CALLER_UID, GRANTEE_UID, |_| Ok(()))?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004004
4005 Ok(())
4006 }
4007
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004008 static TEST_KEY_BLOB: &[u8] = b"my test blob";
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004009 static TEST_CERT_BLOB: &[u8] = b"my test cert";
4010 static TEST_CERT_CHAIN_BLOB: &[u8] = b"my test cert_chain";
4011
4012 #[test]
Janis Danisevskis377d1002021-01-27 19:07:48 -08004013 fn test_set_blob() -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004014 let key_id = KEY_ID_LOCK.get(3000);
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004015 let mut db = new_test_db()?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004016 let mut blob_metadata = BlobMetaData::new();
4017 blob_metadata.add(BlobMetaEntry::KmUuid(KEYSTORE_UUID));
4018 db.set_blob(
4019 &key_id,
4020 SubComponentType::KEY_BLOB,
4021 Some(TEST_KEY_BLOB),
4022 Some(&blob_metadata),
4023 )?;
4024 db.set_blob(&key_id, SubComponentType::CERT, Some(TEST_CERT_BLOB), None)?;
4025 db.set_blob(&key_id, SubComponentType::CERT_CHAIN, Some(TEST_CERT_CHAIN_BLOB), None)?;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004026 drop(key_id);
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004027
4028 let mut stmt = db.conn.prepare(
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004029 "SELECT subcomponent_type, keyentryid, blob, id FROM persistent.blobentry
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004030 ORDER BY subcomponent_type ASC;",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004031 )?;
4032 let mut rows = stmt
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004033 .query_map::<((SubComponentType, i64, Vec<u8>), i64), _, _>(NO_PARAMS, |row| {
4034 Ok(((row.get(0)?, row.get(1)?, row.get(2)?), row.get(3)?))
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004035 })?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004036 let (r, id) = rows.next().unwrap().unwrap();
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004037 assert_eq!(r, (SubComponentType::KEY_BLOB, 3000, TEST_KEY_BLOB.to_vec()));
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004038 let (r, _) = rows.next().unwrap().unwrap();
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004039 assert_eq!(r, (SubComponentType::CERT, 3000, TEST_CERT_BLOB.to_vec()));
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004040 let (r, _) = rows.next().unwrap().unwrap();
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004041 assert_eq!(r, (SubComponentType::CERT_CHAIN, 3000, TEST_CERT_CHAIN_BLOB.to_vec()));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004042
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004043 drop(rows);
4044 drop(stmt);
4045
4046 assert_eq!(
4047 db.with_transaction(TransactionBehavior::Immediate, |tx| {
4048 BlobMetaData::load_from_db(id, tx).no_gc()
4049 })
4050 .expect("Should find blob metadata."),
4051 blob_metadata
4052 );
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004053 Ok(())
4054 }
4055
4056 static TEST_ALIAS: &str = "my super duper key";
4057
4058 #[test]
4059 fn test_insert_and_load_full_keyentry_domain_app() -> Result<()> {
4060 let mut db = new_test_db()?;
Qi Wub9433b52020-12-01 14:52:46 +08004061 let key_id = make_test_key_entry(&mut db, Domain::APP, 1, TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08004062 .context("test_insert_and_load_full_keyentry_domain_app")?
4063 .0;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004064 let (_key_guard, key_entry) = db
4065 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004066 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004067 domain: Domain::APP,
4068 nspace: 0,
4069 alias: Some(TEST_ALIAS.to_string()),
4070 blob: None,
4071 },
4072 KeyType::Client,
4073 KeyEntryLoadBits::BOTH,
4074 1,
4075 |_k, _av| Ok(()),
4076 )
4077 .unwrap();
Qi Wub9433b52020-12-01 14:52:46 +08004078 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004079
4080 db.unbind_key(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004081 &KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07004082 domain: Domain::APP,
4083 nspace: 0,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004084 alias: Some(TEST_ALIAS.to_string()),
4085 blob: None,
4086 },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004087 KeyType::Client,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004088 1,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004089 |_, _| Ok(()),
4090 )
4091 .unwrap();
4092
4093 assert_eq!(
4094 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
4095 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004096 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004097 domain: Domain::APP,
4098 nspace: 0,
4099 alias: Some(TEST_ALIAS.to_string()),
4100 blob: None,
4101 },
4102 KeyType::Client,
4103 KeyEntryLoadBits::NONE,
4104 1,
4105 |_k, _av| Ok(()),
4106 )
4107 .unwrap_err()
4108 .root_cause()
4109 .downcast_ref::<KsError>()
4110 );
4111
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004112 Ok(())
4113 }
4114
4115 #[test]
Janis Danisevskis377d1002021-01-27 19:07:48 -08004116 fn test_insert_and_load_certificate_entry_domain_app() -> Result<()> {
4117 let mut db = new_test_db()?;
4118
4119 db.store_new_certificate(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004120 &KeyDescriptor {
Janis Danisevskis377d1002021-01-27 19:07:48 -08004121 domain: Domain::APP,
4122 nspace: 1,
4123 alias: Some(TEST_ALIAS.to_string()),
4124 blob: None,
4125 },
Janis Danisevskis0cabd712021-05-25 11:07:10 -07004126 KeyType::Client,
Janis Danisevskis377d1002021-01-27 19:07:48 -08004127 TEST_CERT_BLOB,
Max Bires8e93d2b2021-01-14 13:17:59 -08004128 &KEYSTORE_UUID,
Janis Danisevskis377d1002021-01-27 19:07:48 -08004129 )
4130 .expect("Trying to insert cert.");
4131
4132 let (_key_guard, mut key_entry) = db
4133 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004134 &KeyDescriptor {
Janis Danisevskis377d1002021-01-27 19:07:48 -08004135 domain: Domain::APP,
4136 nspace: 1,
4137 alias: Some(TEST_ALIAS.to_string()),
4138 blob: None,
4139 },
4140 KeyType::Client,
4141 KeyEntryLoadBits::PUBLIC,
4142 1,
4143 |_k, _av| Ok(()),
4144 )
4145 .expect("Trying to read certificate entry.");
4146
4147 assert!(key_entry.pure_cert());
4148 assert!(key_entry.cert().is_none());
4149 assert_eq!(key_entry.take_cert_chain(), Some(TEST_CERT_BLOB.to_vec()));
4150
4151 db.unbind_key(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004152 &KeyDescriptor {
Janis Danisevskis377d1002021-01-27 19:07:48 -08004153 domain: Domain::APP,
4154 nspace: 1,
4155 alias: Some(TEST_ALIAS.to_string()),
4156 blob: None,
4157 },
4158 KeyType::Client,
4159 1,
4160 |_, _| Ok(()),
4161 )
4162 .unwrap();
4163
4164 assert_eq!(
4165 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
4166 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004167 &KeyDescriptor {
Janis Danisevskis377d1002021-01-27 19:07:48 -08004168 domain: Domain::APP,
4169 nspace: 1,
4170 alias: Some(TEST_ALIAS.to_string()),
4171 blob: None,
4172 },
4173 KeyType::Client,
4174 KeyEntryLoadBits::NONE,
4175 1,
4176 |_k, _av| Ok(()),
4177 )
4178 .unwrap_err()
4179 .root_cause()
4180 .downcast_ref::<KsError>()
4181 );
4182
4183 Ok(())
4184 }
4185
4186 #[test]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004187 fn test_insert_and_load_full_keyentry_domain_selinux() -> Result<()> {
4188 let mut db = new_test_db()?;
Qi Wub9433b52020-12-01 14:52:46 +08004189 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08004190 .context("test_insert_and_load_full_keyentry_domain_selinux")?
4191 .0;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004192 let (_key_guard, key_entry) = db
4193 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004194 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004195 domain: Domain::SELINUX,
4196 nspace: 1,
4197 alias: Some(TEST_ALIAS.to_string()),
4198 blob: None,
4199 },
4200 KeyType::Client,
4201 KeyEntryLoadBits::BOTH,
4202 1,
4203 |_k, _av| Ok(()),
4204 )
4205 .unwrap();
Qi Wub9433b52020-12-01 14:52:46 +08004206 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004207
4208 db.unbind_key(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004209 &KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07004210 domain: Domain::SELINUX,
4211 nspace: 1,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004212 alias: Some(TEST_ALIAS.to_string()),
4213 blob: None,
4214 },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004215 KeyType::Client,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004216 1,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004217 |_, _| Ok(()),
4218 )
4219 .unwrap();
4220
4221 assert_eq!(
4222 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
4223 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004224 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004225 domain: Domain::SELINUX,
4226 nspace: 1,
4227 alias: Some(TEST_ALIAS.to_string()),
4228 blob: None,
4229 },
4230 KeyType::Client,
4231 KeyEntryLoadBits::NONE,
4232 1,
4233 |_k, _av| Ok(()),
4234 )
4235 .unwrap_err()
4236 .root_cause()
4237 .downcast_ref::<KsError>()
4238 );
4239
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004240 Ok(())
4241 }
4242
4243 #[test]
4244 fn test_insert_and_load_full_keyentry_domain_key_id() -> Result<()> {
4245 let mut db = new_test_db()?;
Qi Wub9433b52020-12-01 14:52:46 +08004246 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08004247 .context("test_insert_and_load_full_keyentry_domain_key_id")?
4248 .0;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004249 let (_, key_entry) = db
4250 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004251 &KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004252 KeyType::Client,
4253 KeyEntryLoadBits::BOTH,
4254 1,
4255 |_k, _av| Ok(()),
4256 )
4257 .unwrap();
4258
Qi Wub9433b52020-12-01 14:52:46 +08004259 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004260
4261 db.unbind_key(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004262 &KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004263 KeyType::Client,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004264 1,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004265 |_, _| Ok(()),
4266 )
4267 .unwrap();
4268
4269 assert_eq!(
4270 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
4271 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004272 &KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004273 KeyType::Client,
4274 KeyEntryLoadBits::NONE,
4275 1,
4276 |_k, _av| Ok(()),
4277 )
4278 .unwrap_err()
4279 .root_cause()
4280 .downcast_ref::<KsError>()
4281 );
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004282
4283 Ok(())
4284 }
4285
4286 #[test]
Qi Wub9433b52020-12-01 14:52:46 +08004287 fn test_check_and_update_key_usage_count_with_limited_use_key() -> Result<()> {
4288 let mut db = new_test_db()?;
4289 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, Some(123))
4290 .context("test_check_and_update_key_usage_count_with_limited_use_key")?
4291 .0;
4292 // Update the usage count of the limited use key.
4293 db.check_and_update_key_usage_count(key_id)?;
4294
4295 let (_key_guard, key_entry) = db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004296 &KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
Qi Wub9433b52020-12-01 14:52:46 +08004297 KeyType::Client,
4298 KeyEntryLoadBits::BOTH,
4299 1,
4300 |_k, _av| Ok(()),
4301 )?;
4302
4303 // The usage count is decremented now.
4304 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, Some(122)));
4305
4306 Ok(())
4307 }
4308
4309 #[test]
4310 fn test_check_and_update_key_usage_count_with_exhausted_limited_use_key() -> Result<()> {
4311 let mut db = new_test_db()?;
4312 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, Some(1))
4313 .context("test_check_and_update_key_usage_count_with_exhausted_limited_use_key")?
4314 .0;
4315 // Update the usage count of the limited use key.
4316 db.check_and_update_key_usage_count(key_id).expect(concat!(
4317 "In test_check_and_update_key_usage_count_with_exhausted_limited_use_key: ",
4318 "This should succeed."
4319 ));
4320
4321 // Try to update the exhausted limited use key.
4322 let e = db.check_and_update_key_usage_count(key_id).expect_err(concat!(
4323 "In test_check_and_update_key_usage_count_with_exhausted_limited_use_key: ",
4324 "This should fail."
4325 ));
4326 assert_eq!(
4327 &KsError::Km(ErrorCode::INVALID_KEY_BLOB),
4328 e.root_cause().downcast_ref::<KsError>().unwrap()
4329 );
4330
4331 Ok(())
4332 }
4333
4334 #[test]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004335 fn test_insert_and_load_full_keyentry_from_grant() -> Result<()> {
4336 let mut db = new_test_db()?;
Qi Wub9433b52020-12-01 14:52:46 +08004337 let key_id = make_test_key_entry(&mut db, Domain::APP, 1, TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08004338 .context("test_insert_and_load_full_keyentry_from_grant")?
4339 .0;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004340
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004341 let granted_key = db
4342 .grant(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004343 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004344 domain: Domain::APP,
4345 nspace: 0,
4346 alias: Some(TEST_ALIAS.to_string()),
4347 blob: None,
4348 },
4349 1,
4350 2,
Janis Danisevskis39d57e72021-10-19 16:56:20 -07004351 key_perm_set![KeyPerm::Use],
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004352 |_k, _av| Ok(()),
4353 )
4354 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004355
4356 debug_dump_grant_table(&mut db)?;
4357
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004358 let (_key_guard, key_entry) = db
Janis Danisevskis66784c42021-01-27 08:40:25 -08004359 .load_key_entry(&granted_key, KeyType::Client, KeyEntryLoadBits::BOTH, 2, |k, av| {
4360 assert_eq!(Domain::GRANT, k.domain);
Janis Danisevskis39d57e72021-10-19 16:56:20 -07004361 assert!(av.unwrap().includes(KeyPerm::Use));
Janis Danisevskis66784c42021-01-27 08:40:25 -08004362 Ok(())
4363 })
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004364 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004365
Qi Wub9433b52020-12-01 14:52:46 +08004366 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004367
Janis Danisevskis66784c42021-01-27 08:40:25 -08004368 db.unbind_key(&granted_key, KeyType::Client, 2, |_, _| Ok(())).unwrap();
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004369
4370 assert_eq!(
4371 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
4372 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004373 &granted_key,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004374 KeyType::Client,
4375 KeyEntryLoadBits::NONE,
4376 2,
4377 |_k, _av| Ok(()),
4378 )
4379 .unwrap_err()
4380 .root_cause()
4381 .downcast_ref::<KsError>()
4382 );
4383
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004384 Ok(())
4385 }
4386
Janis Danisevskis45760022021-01-19 16:34:10 -08004387 // This test attempts to load a key by key id while the caller is not the owner
4388 // but a grant exists for the given key and the caller.
4389 #[test]
4390 fn test_insert_and_load_full_keyentry_from_grant_by_key_id() -> Result<()> {
4391 let mut db = new_test_db()?;
4392 const OWNER_UID: u32 = 1u32;
4393 const GRANTEE_UID: u32 = 2u32;
4394 const SOMEONE_ELSE_UID: u32 = 3u32;
4395 let key_id = make_test_key_entry(&mut db, Domain::APP, OWNER_UID as i64, TEST_ALIAS, None)
4396 .context("test_insert_and_load_full_keyentry_from_grant_by_key_id")?
4397 .0;
4398
4399 db.grant(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004400 &KeyDescriptor {
Janis Danisevskis45760022021-01-19 16:34:10 -08004401 domain: Domain::APP,
4402 nspace: 0,
4403 alias: Some(TEST_ALIAS.to_string()),
4404 blob: None,
4405 },
4406 OWNER_UID,
4407 GRANTEE_UID,
Janis Danisevskis39d57e72021-10-19 16:56:20 -07004408 key_perm_set![KeyPerm::Use],
Janis Danisevskis45760022021-01-19 16:34:10 -08004409 |_k, _av| Ok(()),
4410 )
4411 .unwrap();
4412
4413 debug_dump_grant_table(&mut db)?;
4414
4415 let id_descriptor =
4416 KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, ..Default::default() };
4417
4418 let (_, key_entry) = db
4419 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004420 &id_descriptor,
Janis Danisevskis45760022021-01-19 16:34:10 -08004421 KeyType::Client,
4422 KeyEntryLoadBits::BOTH,
4423 GRANTEE_UID,
4424 |k, av| {
4425 assert_eq!(Domain::APP, k.domain);
4426 assert_eq!(OWNER_UID as i64, k.nspace);
Janis Danisevskis39d57e72021-10-19 16:56:20 -07004427 assert!(av.unwrap().includes(KeyPerm::Use));
Janis Danisevskis45760022021-01-19 16:34:10 -08004428 Ok(())
4429 },
4430 )
4431 .unwrap();
4432
4433 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
4434
4435 let (_, key_entry) = db
4436 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004437 &id_descriptor,
Janis Danisevskis45760022021-01-19 16:34:10 -08004438 KeyType::Client,
4439 KeyEntryLoadBits::BOTH,
4440 SOMEONE_ELSE_UID,
4441 |k, av| {
4442 assert_eq!(Domain::APP, k.domain);
4443 assert_eq!(OWNER_UID as i64, k.nspace);
4444 assert!(av.is_none());
4445 Ok(())
4446 },
4447 )
4448 .unwrap();
4449
4450 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
4451
Janis Danisevskis66784c42021-01-27 08:40:25 -08004452 db.unbind_key(&id_descriptor, KeyType::Client, OWNER_UID, |_, _| Ok(())).unwrap();
Janis Danisevskis45760022021-01-19 16:34:10 -08004453
4454 assert_eq!(
4455 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
4456 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004457 &id_descriptor,
Janis Danisevskis45760022021-01-19 16:34:10 -08004458 KeyType::Client,
4459 KeyEntryLoadBits::NONE,
4460 GRANTEE_UID,
4461 |_k, _av| Ok(()),
4462 )
4463 .unwrap_err()
4464 .root_cause()
4465 .downcast_ref::<KsError>()
4466 );
4467
4468 Ok(())
4469 }
4470
Janis Danisevskiscdcf4e52021-04-14 15:44:36 -07004471 // Creates a key migrates it to a different location and then tries to access it by the old
4472 // and new location.
4473 #[test]
4474 fn test_migrate_key_app_to_app() -> Result<()> {
4475 let mut db = new_test_db()?;
4476 const SOURCE_UID: u32 = 1u32;
4477 const DESTINATION_UID: u32 = 2u32;
Chris Wailesd5aaaef2021-07-27 16:04:33 -07004478 static SOURCE_ALIAS: &str = "SOURCE_ALIAS";
4479 static DESTINATION_ALIAS: &str = "DESTINATION_ALIAS";
Janis Danisevskiscdcf4e52021-04-14 15:44:36 -07004480 let key_id_guard =
4481 make_test_key_entry(&mut db, Domain::APP, SOURCE_UID as i64, SOURCE_ALIAS, None)
4482 .context("test_insert_and_load_full_keyentry_from_grant_by_key_id")?;
4483
4484 let source_descriptor: KeyDescriptor = KeyDescriptor {
4485 domain: Domain::APP,
4486 nspace: -1,
4487 alias: Some(SOURCE_ALIAS.to_string()),
4488 blob: None,
4489 };
4490
4491 let destination_descriptor: KeyDescriptor = KeyDescriptor {
4492 domain: Domain::APP,
4493 nspace: -1,
4494 alias: Some(DESTINATION_ALIAS.to_string()),
4495 blob: None,
4496 };
4497
4498 let key_id = key_id_guard.id();
4499
4500 db.migrate_key_namespace(key_id_guard, &destination_descriptor, DESTINATION_UID, |_k| {
4501 Ok(())
4502 })
4503 .unwrap();
4504
4505 let (_, key_entry) = db
4506 .load_key_entry(
4507 &destination_descriptor,
4508 KeyType::Client,
4509 KeyEntryLoadBits::BOTH,
4510 DESTINATION_UID,
4511 |k, av| {
4512 assert_eq!(Domain::APP, k.domain);
4513 assert_eq!(DESTINATION_UID as i64, k.nspace);
4514 assert!(av.is_none());
4515 Ok(())
4516 },
4517 )
4518 .unwrap();
4519
4520 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
4521
4522 assert_eq!(
4523 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
4524 db.load_key_entry(
4525 &source_descriptor,
4526 KeyType::Client,
4527 KeyEntryLoadBits::NONE,
4528 SOURCE_UID,
4529 |_k, _av| Ok(()),
4530 )
4531 .unwrap_err()
4532 .root_cause()
4533 .downcast_ref::<KsError>()
4534 );
4535
4536 Ok(())
4537 }
4538
4539 // Creates a key migrates it to a different location and then tries to access it by the old
4540 // and new location.
4541 #[test]
4542 fn test_migrate_key_app_to_selinux() -> Result<()> {
4543 let mut db = new_test_db()?;
4544 const SOURCE_UID: u32 = 1u32;
4545 const DESTINATION_UID: u32 = 2u32;
4546 const DESTINATION_NAMESPACE: i64 = 1000i64;
Chris Wailesd5aaaef2021-07-27 16:04:33 -07004547 static SOURCE_ALIAS: &str = "SOURCE_ALIAS";
4548 static DESTINATION_ALIAS: &str = "DESTINATION_ALIAS";
Janis Danisevskiscdcf4e52021-04-14 15:44:36 -07004549 let key_id_guard =
4550 make_test_key_entry(&mut db, Domain::APP, SOURCE_UID as i64, SOURCE_ALIAS, None)
4551 .context("test_insert_and_load_full_keyentry_from_grant_by_key_id")?;
4552
4553 let source_descriptor: KeyDescriptor = KeyDescriptor {
4554 domain: Domain::APP,
4555 nspace: -1,
4556 alias: Some(SOURCE_ALIAS.to_string()),
4557 blob: None,
4558 };
4559
4560 let destination_descriptor: KeyDescriptor = KeyDescriptor {
4561 domain: Domain::SELINUX,
4562 nspace: DESTINATION_NAMESPACE,
4563 alias: Some(DESTINATION_ALIAS.to_string()),
4564 blob: None,
4565 };
4566
4567 let key_id = key_id_guard.id();
4568
4569 db.migrate_key_namespace(key_id_guard, &destination_descriptor, DESTINATION_UID, |_k| {
4570 Ok(())
4571 })
4572 .unwrap();
4573
4574 let (_, key_entry) = db
4575 .load_key_entry(
4576 &destination_descriptor,
4577 KeyType::Client,
4578 KeyEntryLoadBits::BOTH,
4579 DESTINATION_UID,
4580 |k, av| {
4581 assert_eq!(Domain::SELINUX, k.domain);
4582 assert_eq!(DESTINATION_NAMESPACE as i64, k.nspace);
4583 assert!(av.is_none());
4584 Ok(())
4585 },
4586 )
4587 .unwrap();
4588
4589 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
4590
4591 assert_eq!(
4592 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
4593 db.load_key_entry(
4594 &source_descriptor,
4595 KeyType::Client,
4596 KeyEntryLoadBits::NONE,
4597 SOURCE_UID,
4598 |_k, _av| Ok(()),
4599 )
4600 .unwrap_err()
4601 .root_cause()
4602 .downcast_ref::<KsError>()
4603 );
4604
4605 Ok(())
4606 }
4607
4608 // Creates two keys and tries to migrate the first to the location of the second which
4609 // is expected to fail.
4610 #[test]
4611 fn test_migrate_key_destination_occupied() -> Result<()> {
4612 let mut db = new_test_db()?;
4613 const SOURCE_UID: u32 = 1u32;
4614 const DESTINATION_UID: u32 = 2u32;
Chris Wailesd5aaaef2021-07-27 16:04:33 -07004615 static SOURCE_ALIAS: &str = "SOURCE_ALIAS";
4616 static DESTINATION_ALIAS: &str = "DESTINATION_ALIAS";
Janis Danisevskiscdcf4e52021-04-14 15:44:36 -07004617 let key_id_guard =
4618 make_test_key_entry(&mut db, Domain::APP, SOURCE_UID as i64, SOURCE_ALIAS, None)
4619 .context("test_insert_and_load_full_keyentry_from_grant_by_key_id")?;
4620 make_test_key_entry(&mut db, Domain::APP, DESTINATION_UID as i64, DESTINATION_ALIAS, None)
4621 .context("test_insert_and_load_full_keyentry_from_grant_by_key_id")?;
4622
4623 let destination_descriptor: KeyDescriptor = KeyDescriptor {
4624 domain: Domain::APP,
4625 nspace: -1,
4626 alias: Some(DESTINATION_ALIAS.to_string()),
4627 blob: None,
4628 };
4629
4630 assert_eq!(
4631 Some(&KsError::Rc(ResponseCode::INVALID_ARGUMENT)),
4632 db.migrate_key_namespace(
4633 key_id_guard,
4634 &destination_descriptor,
4635 DESTINATION_UID,
4636 |_k| Ok(())
4637 )
4638 .unwrap_err()
4639 .root_cause()
4640 .downcast_ref::<KsError>()
4641 );
4642
4643 Ok(())
4644 }
4645
Janis Danisevskiscfaf9192021-05-26 16:31:02 -07004646 #[test]
4647 fn test_upgrade_0_to_1() {
Chris Wailesd5aaaef2021-07-27 16:04:33 -07004648 const ALIAS1: &str = "test_upgrade_0_to_1_1";
4649 const ALIAS2: &str = "test_upgrade_0_to_1_2";
4650 const ALIAS3: &str = "test_upgrade_0_to_1_3";
Janis Danisevskiscfaf9192021-05-26 16:31:02 -07004651 const UID: u32 = 33;
4652 let temp_dir = Arc::new(TempDir::new("test_upgrade_0_to_1").unwrap());
4653 let mut db = KeystoreDB::new(temp_dir.path(), None).unwrap();
4654 let key_id_untouched1 =
4655 make_test_key_entry(&mut db, Domain::APP, UID as i64, ALIAS1, None).unwrap().id();
4656 let key_id_untouched2 =
4657 make_bootlevel_key_entry(&mut db, Domain::APP, UID as i64, ALIAS2, false).unwrap().id();
4658 let key_id_deleted =
4659 make_bootlevel_key_entry(&mut db, Domain::APP, UID as i64, ALIAS3, true).unwrap().id();
4660
4661 let (_, key_entry) = db
4662 .load_key_entry(
4663 &KeyDescriptor {
4664 domain: Domain::APP,
4665 nspace: -1,
4666 alias: Some(ALIAS1.to_string()),
4667 blob: None,
4668 },
4669 KeyType::Client,
4670 KeyEntryLoadBits::BOTH,
4671 UID,
4672 |k, av| {
4673 assert_eq!(Domain::APP, k.domain);
4674 assert_eq!(UID as i64, k.nspace);
4675 assert!(av.is_none());
4676 Ok(())
4677 },
4678 )
4679 .unwrap();
4680 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id_untouched1, None));
4681 let (_, key_entry) = db
4682 .load_key_entry(
4683 &KeyDescriptor {
4684 domain: Domain::APP,
4685 nspace: -1,
4686 alias: Some(ALIAS2.to_string()),
4687 blob: None,
4688 },
4689 KeyType::Client,
4690 KeyEntryLoadBits::BOTH,
4691 UID,
4692 |k, av| {
4693 assert_eq!(Domain::APP, k.domain);
4694 assert_eq!(UID as i64, k.nspace);
4695 assert!(av.is_none());
4696 Ok(())
4697 },
4698 )
4699 .unwrap();
4700 assert_eq!(key_entry, make_bootlevel_test_key_entry_test_vector(key_id_untouched2, false));
4701 let (_, key_entry) = db
4702 .load_key_entry(
4703 &KeyDescriptor {
4704 domain: Domain::APP,
4705 nspace: -1,
4706 alias: Some(ALIAS3.to_string()),
4707 blob: None,
4708 },
4709 KeyType::Client,
4710 KeyEntryLoadBits::BOTH,
4711 UID,
4712 |k, av| {
4713 assert_eq!(Domain::APP, k.domain);
4714 assert_eq!(UID as i64, k.nspace);
4715 assert!(av.is_none());
4716 Ok(())
4717 },
4718 )
4719 .unwrap();
4720 assert_eq!(key_entry, make_bootlevel_test_key_entry_test_vector(key_id_deleted, true));
4721
4722 db.with_transaction(TransactionBehavior::Immediate, |tx| {
4723 KeystoreDB::from_0_to_1(tx).no_gc()
4724 })
4725 .unwrap();
4726
4727 let (_, key_entry) = db
4728 .load_key_entry(
4729 &KeyDescriptor {
4730 domain: Domain::APP,
4731 nspace: -1,
4732 alias: Some(ALIAS1.to_string()),
4733 blob: None,
4734 },
4735 KeyType::Client,
4736 KeyEntryLoadBits::BOTH,
4737 UID,
4738 |k, av| {
4739 assert_eq!(Domain::APP, k.domain);
4740 assert_eq!(UID as i64, k.nspace);
4741 assert!(av.is_none());
4742 Ok(())
4743 },
4744 )
4745 .unwrap();
4746 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id_untouched1, None));
4747 let (_, key_entry) = db
4748 .load_key_entry(
4749 &KeyDescriptor {
4750 domain: Domain::APP,
4751 nspace: -1,
4752 alias: Some(ALIAS2.to_string()),
4753 blob: None,
4754 },
4755 KeyType::Client,
4756 KeyEntryLoadBits::BOTH,
4757 UID,
4758 |k, av| {
4759 assert_eq!(Domain::APP, k.domain);
4760 assert_eq!(UID as i64, k.nspace);
4761 assert!(av.is_none());
4762 Ok(())
4763 },
4764 )
4765 .unwrap();
4766 assert_eq!(key_entry, make_bootlevel_test_key_entry_test_vector(key_id_untouched2, false));
4767 assert_eq!(
4768 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
4769 db.load_key_entry(
4770 &KeyDescriptor {
4771 domain: Domain::APP,
4772 nspace: -1,
4773 alias: Some(ALIAS3.to_string()),
4774 blob: None,
4775 },
4776 KeyType::Client,
4777 KeyEntryLoadBits::BOTH,
4778 UID,
4779 |k, av| {
4780 assert_eq!(Domain::APP, k.domain);
4781 assert_eq!(UID as i64, k.nspace);
4782 assert!(av.is_none());
4783 Ok(())
4784 },
4785 )
4786 .unwrap_err()
4787 .root_cause()
4788 .downcast_ref::<KsError>()
4789 );
4790 }
4791
Janis Danisevskisaec14592020-11-12 09:41:49 -08004792 static KEY_LOCK_TEST_ALIAS: &str = "my super duper locked key";
4793
Janis Danisevskisaec14592020-11-12 09:41:49 -08004794 #[test]
4795 fn test_insert_and_load_full_keyentry_domain_app_concurrently() -> Result<()> {
4796 let handle = {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08004797 let temp_dir = Arc::new(TempDir::new("id_lock_test")?);
4798 let temp_dir_clone = temp_dir.clone();
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004799 let mut db = KeystoreDB::new(temp_dir.path(), None)?;
Qi Wub9433b52020-12-01 14:52:46 +08004800 let key_id = make_test_key_entry(&mut db, Domain::APP, 33, KEY_LOCK_TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08004801 .context("test_insert_and_load_full_keyentry_domain_app")?
4802 .0;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004803 let (_key_guard, key_entry) = db
4804 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004805 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004806 domain: Domain::APP,
4807 nspace: 0,
4808 alias: Some(KEY_LOCK_TEST_ALIAS.to_string()),
4809 blob: None,
4810 },
4811 KeyType::Client,
4812 KeyEntryLoadBits::BOTH,
4813 33,
4814 |_k, _av| Ok(()),
4815 )
4816 .unwrap();
Qi Wub9433b52020-12-01 14:52:46 +08004817 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskisaec14592020-11-12 09:41:49 -08004818 let state = Arc::new(AtomicU8::new(1));
4819 let state2 = state.clone();
4820
4821 // Spawning a second thread that attempts to acquire the key id lock
4822 // for the same key as the primary thread. The primary thread then
4823 // waits, thereby forcing the secondary thread into the second stage
4824 // of acquiring the lock (see KEY ID LOCK 2/2 above).
4825 // The test succeeds if the secondary thread observes the transition
4826 // of `state` from 1 to 2, despite having a whole second to overtake
4827 // the primary thread.
4828 let handle = thread::spawn(move || {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08004829 let temp_dir = temp_dir_clone;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004830 let mut db = KeystoreDB::new(temp_dir.path(), None).unwrap();
Janis Danisevskisaec14592020-11-12 09:41:49 -08004831 assert!(db
4832 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004833 &KeyDescriptor {
Janis Danisevskisaec14592020-11-12 09:41:49 -08004834 domain: Domain::APP,
4835 nspace: 0,
4836 alias: Some(KEY_LOCK_TEST_ALIAS.to_string()),
4837 blob: None,
4838 },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004839 KeyType::Client,
Janis Danisevskisaec14592020-11-12 09:41:49 -08004840 KeyEntryLoadBits::BOTH,
4841 33,
4842 |_k, _av| Ok(()),
4843 )
4844 .is_ok());
4845 // We should only see a 2 here because we can only return
4846 // from load_key_entry when the `_key_guard` expires,
4847 // which happens at the end of the scope.
4848 assert_eq!(2, state2.load(Ordering::Relaxed));
4849 });
4850
4851 thread::sleep(std::time::Duration::from_millis(1000));
4852
4853 assert_eq!(Ok(1), state.compare_exchange(1, 2, Ordering::Relaxed, Ordering::Relaxed));
4854
4855 // Return the handle from this scope so we can join with the
4856 // secondary thread after the key id lock has expired.
4857 handle
4858 // This is where the `_key_guard` goes out of scope,
4859 // which is the reason for concurrent load_key_entry on the same key
4860 // to unblock.
4861 };
4862 // Join with the secondary thread and unwrap, to propagate failing asserts to the
4863 // main test thread. We will not see failing asserts in secondary threads otherwise.
4864 handle.join().unwrap();
4865 Ok(())
4866 }
4867
Janis Danisevskise92a5e62020-12-02 12:57:41 -08004868 #[test]
Janis Danisevskiscdcf4e52021-04-14 15:44:36 -07004869 fn test_database_busy_error_code() {
Janis Danisevskis66784c42021-01-27 08:40:25 -08004870 let temp_dir =
4871 TempDir::new("test_database_busy_error_code_").expect("Failed to create temp dir.");
4872
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004873 let mut db1 = KeystoreDB::new(temp_dir.path(), None).expect("Failed to open database1.");
4874 let mut db2 = KeystoreDB::new(temp_dir.path(), None).expect("Failed to open database2.");
Janis Danisevskis66784c42021-01-27 08:40:25 -08004875
4876 let _tx1 = db1
4877 .conn
4878 .transaction_with_behavior(TransactionBehavior::Immediate)
4879 .expect("Failed to create first transaction.");
4880
4881 let error = db2
4882 .conn
4883 .transaction_with_behavior(TransactionBehavior::Immediate)
4884 .context("Transaction begin failed.")
4885 .expect_err("This should fail.");
4886 let root_cause = error.root_cause();
4887 if let Some(rusqlite::ffi::Error { code: rusqlite::ErrorCode::DatabaseBusy, .. }) =
4888 root_cause.downcast_ref::<rusqlite::ffi::Error>()
4889 {
4890 return;
4891 }
4892 panic!(
4893 "Unexpected error {:?} \n{:?} \n{:?}",
4894 error,
4895 root_cause,
4896 root_cause.downcast_ref::<rusqlite::ffi::Error>()
4897 )
4898 }
4899
4900 #[cfg(disabled)]
4901 #[test]
4902 fn test_large_number_of_concurrent_db_manipulations() -> Result<()> {
4903 let temp_dir = Arc::new(
4904 TempDir::new("test_large_number_of_concurrent_db_manipulations_")
4905 .expect("Failed to create temp dir."),
4906 );
4907
4908 let test_begin = Instant::now();
4909
Janis Danisevskis66784c42021-01-27 08:40:25 -08004910 const KEY_COUNT: u32 = 500u32;
Seth Moore444b51a2021-06-11 09:49:49 -07004911 let mut db =
4912 new_test_db_with_gc(temp_dir.path(), |_, _| Ok(())).expect("Failed to open database.");
Janis Danisevskis66784c42021-01-27 08:40:25 -08004913 const OPEN_DB_COUNT: u32 = 50u32;
4914
4915 let mut actual_key_count = KEY_COUNT;
4916 // First insert KEY_COUNT keys.
4917 for count in 0..KEY_COUNT {
4918 if Instant::now().duration_since(test_begin) >= Duration::from_secs(15) {
4919 actual_key_count = count;
4920 break;
4921 }
4922 let alias = format!("test_alias_{}", count);
4923 make_test_key_entry(&mut db, Domain::APP, 1, &alias, None)
4924 .expect("Failed to make key entry.");
4925 }
4926
4927 // Insert more keys from a different thread and into a different namespace.
4928 let temp_dir1 = temp_dir.clone();
4929 let handle1 = thread::spawn(move || {
Seth Moore444b51a2021-06-11 09:49:49 -07004930 let mut db = new_test_db_with_gc(temp_dir1.path(), |_, _| Ok(()))
4931 .expect("Failed to open database.");
Janis Danisevskis66784c42021-01-27 08:40:25 -08004932
4933 for count in 0..actual_key_count {
4934 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
4935 return;
4936 }
4937 let alias = format!("test_alias_{}", count);
4938 make_test_key_entry(&mut db, Domain::APP, 2, &alias, None)
4939 .expect("Failed to make key entry.");
4940 }
4941
4942 // then unbind them again.
4943 for count in 0..actual_key_count {
4944 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
4945 return;
4946 }
4947 let key = KeyDescriptor {
4948 domain: Domain::APP,
4949 nspace: -1,
4950 alias: Some(format!("test_alias_{}", count)),
4951 blob: None,
4952 };
4953 db.unbind_key(&key, KeyType::Client, 2, |_, _| Ok(())).expect("Unbind Failed.");
4954 }
4955 });
4956
4957 // And start unbinding the first set of keys.
4958 let temp_dir2 = temp_dir.clone();
4959 let handle2 = thread::spawn(move || {
Seth Moore444b51a2021-06-11 09:49:49 -07004960 let mut db = new_test_db_with_gc(temp_dir2.path(), |_, _| Ok(()))
4961 .expect("Failed to open database.");
Janis Danisevskis66784c42021-01-27 08:40:25 -08004962
4963 for count in 0..actual_key_count {
4964 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
4965 return;
4966 }
4967 let key = KeyDescriptor {
4968 domain: Domain::APP,
4969 nspace: -1,
4970 alias: Some(format!("test_alias_{}", count)),
4971 blob: None,
4972 };
4973 db.unbind_key(&key, KeyType::Client, 1, |_, _| Ok(())).expect("Unbind Failed.");
4974 }
4975 });
4976
Janis Danisevskis66784c42021-01-27 08:40:25 -08004977 // While a lot of inserting and deleting is going on we have to open database connections
4978 // successfully and use them.
4979 // This clone is not redundant, because temp_dir needs to be kept alive until db goes
4980 // out of scope.
4981 #[allow(clippy::redundant_clone)]
4982 let temp_dir4 = temp_dir.clone();
4983 let handle4 = thread::spawn(move || {
4984 for count in 0..OPEN_DB_COUNT {
4985 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
4986 return;
4987 }
Seth Moore444b51a2021-06-11 09:49:49 -07004988 let mut db = new_test_db_with_gc(temp_dir4.path(), |_, _| Ok(()))
4989 .expect("Failed to open database.");
Janis Danisevskis66784c42021-01-27 08:40:25 -08004990
4991 let alias = format!("test_alias_{}", count);
4992 make_test_key_entry(&mut db, Domain::APP, 3, &alias, None)
4993 .expect("Failed to make key entry.");
4994 let key = KeyDescriptor {
4995 domain: Domain::APP,
4996 nspace: -1,
4997 alias: Some(alias),
4998 blob: None,
4999 };
5000 db.unbind_key(&key, KeyType::Client, 3, |_, _| Ok(())).expect("Unbind Failed.");
5001 }
5002 });
5003
5004 handle1.join().expect("Thread 1 panicked.");
5005 handle2.join().expect("Thread 2 panicked.");
5006 handle4.join().expect("Thread 4 panicked.");
5007
Janis Danisevskis66784c42021-01-27 08:40:25 -08005008 Ok(())
5009 }
5010
5011 #[test]
Janis Danisevskise92a5e62020-12-02 12:57:41 -08005012 fn list() -> Result<()> {
5013 let temp_dir = TempDir::new("list_test")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08005014 let mut db = KeystoreDB::new(temp_dir.path(), None)?;
Janis Danisevskise92a5e62020-12-02 12:57:41 -08005015 static LIST_O_ENTRIES: &[(Domain, i64, &str)] = &[
5016 (Domain::APP, 1, "test1"),
5017 (Domain::APP, 1, "test2"),
5018 (Domain::APP, 1, "test3"),
5019 (Domain::APP, 1, "test4"),
5020 (Domain::APP, 1, "test5"),
5021 (Domain::APP, 1, "test6"),
5022 (Domain::APP, 1, "test7"),
5023 (Domain::APP, 2, "test1"),
5024 (Domain::APP, 2, "test2"),
5025 (Domain::APP, 2, "test3"),
5026 (Domain::APP, 2, "test4"),
5027 (Domain::APP, 2, "test5"),
5028 (Domain::APP, 2, "test6"),
5029 (Domain::APP, 2, "test8"),
5030 (Domain::SELINUX, 100, "test1"),
5031 (Domain::SELINUX, 100, "test2"),
5032 (Domain::SELINUX, 100, "test3"),
5033 (Domain::SELINUX, 100, "test4"),
5034 (Domain::SELINUX, 100, "test5"),
5035 (Domain::SELINUX, 100, "test6"),
5036 (Domain::SELINUX, 100, "test9"),
5037 ];
5038
5039 let list_o_keys: Vec<(i64, i64)> = LIST_O_ENTRIES
5040 .iter()
5041 .map(|(domain, ns, alias)| {
Qi Wub9433b52020-12-01 14:52:46 +08005042 let entry = make_test_key_entry(&mut db, *domain, *ns, *alias, None)
5043 .unwrap_or_else(|e| {
Janis Danisevskise92a5e62020-12-02 12:57:41 -08005044 panic!("Failed to insert {:?} {} {}. Error {:?}", domain, ns, alias, e)
5045 });
5046 (entry.id(), *ns)
5047 })
5048 .collect();
5049
5050 for (domain, namespace) in
5051 &[(Domain::APP, 1i64), (Domain::APP, 2i64), (Domain::SELINUX, 100i64)]
5052 {
5053 let mut list_o_descriptors: Vec<KeyDescriptor> = LIST_O_ENTRIES
5054 .iter()
5055 .filter_map(|(domain, ns, alias)| match ns {
5056 ns if *ns == *namespace => Some(KeyDescriptor {
5057 domain: *domain,
5058 nspace: *ns,
5059 alias: Some(alias.to_string()),
5060 blob: None,
5061 }),
5062 _ => None,
5063 })
5064 .collect();
5065 list_o_descriptors.sort();
Janis Danisevskis18313832021-05-17 13:30:32 -07005066 let mut list_result = db.list(*domain, *namespace, KeyType::Client)?;
Janis Danisevskise92a5e62020-12-02 12:57:41 -08005067 list_result.sort();
5068 assert_eq!(list_o_descriptors, list_result);
5069
5070 let mut list_o_ids: Vec<i64> = list_o_descriptors
5071 .into_iter()
5072 .map(|d| {
5073 let (_, entry) = db
Janis Danisevskisb42fc182020-12-15 08:41:27 -08005074 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08005075 &d,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08005076 KeyType::Client,
5077 KeyEntryLoadBits::NONE,
5078 *namespace as u32,
5079 |_, _| Ok(()),
5080 )
Janis Danisevskise92a5e62020-12-02 12:57:41 -08005081 .unwrap();
5082 entry.id()
5083 })
5084 .collect();
5085 list_o_ids.sort_unstable();
5086 let mut loaded_entries: Vec<i64> = list_o_keys
5087 .iter()
5088 .filter_map(|(id, ns)| match ns {
5089 ns if *ns == *namespace => Some(*id),
5090 _ => None,
5091 })
5092 .collect();
5093 loaded_entries.sort_unstable();
5094 assert_eq!(list_o_ids, loaded_entries);
5095 }
Janis Danisevskis18313832021-05-17 13:30:32 -07005096 assert_eq!(Vec::<KeyDescriptor>::new(), db.list(Domain::SELINUX, 101, KeyType::Client)?);
Janis Danisevskise92a5e62020-12-02 12:57:41 -08005097
5098 Ok(())
5099 }
5100
Joel Galenson0891bc12020-07-20 10:37:03 -07005101 // Helpers
5102
5103 // Checks that the given result is an error containing the given string.
5104 fn check_result_is_error_containing_string<T>(result: Result<T>, target: &str) {
5105 let error_str = format!(
5106 "{:#?}",
5107 result.err().unwrap_or_else(|| panic!("Expected the error: {}", target))
5108 );
5109 assert!(
5110 error_str.contains(target),
5111 "The string \"{}\" should contain \"{}\"",
5112 error_str,
5113 target
5114 );
5115 }
5116
Joel Galenson2aab4432020-07-22 15:27:57 -07005117 #[derive(Debug, PartialEq)]
Joel Galenson0891bc12020-07-20 10:37:03 -07005118 struct KeyEntryRow {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07005119 id: i64,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08005120 key_type: KeyType,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07005121 domain: Option<Domain>,
Joel Galenson0891bc12020-07-20 10:37:03 -07005122 namespace: Option<i64>,
5123 alias: Option<String>,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08005124 state: KeyLifeCycle,
Max Bires8e93d2b2021-01-14 13:17:59 -08005125 km_uuid: Option<Uuid>,
Joel Galenson0891bc12020-07-20 10:37:03 -07005126 }
5127
5128 fn get_keyentry(db: &KeystoreDB) -> Result<Vec<KeyEntryRow>> {
5129 db.conn
Joel Galenson2aab4432020-07-22 15:27:57 -07005130 .prepare("SELECT * FROM persistent.keyentry;")?
Joel Galenson0891bc12020-07-20 10:37:03 -07005131 .query_map(NO_PARAMS, |row| {
Joel Galenson0891bc12020-07-20 10:37:03 -07005132 Ok(KeyEntryRow {
5133 id: row.get(0)?,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08005134 key_type: row.get(1)?,
Chris Wailes3583a512021-07-22 16:22:51 -07005135 domain: row.get::<_, Option<_>>(2)?.map(Domain),
Joel Galenson0891bc12020-07-20 10:37:03 -07005136 namespace: row.get(3)?,
5137 alias: row.get(4)?,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08005138 state: row.get(5)?,
Max Bires8e93d2b2021-01-14 13:17:59 -08005139 km_uuid: row.get(6)?,
Joel Galenson0891bc12020-07-20 10:37:03 -07005140 })
5141 })?
5142 .map(|r| r.context("Could not read keyentry row."))
5143 .collect::<Result<Vec<_>>>()
5144 }
5145
Max Biresb2e1d032021-02-08 21:35:05 -08005146 struct RemoteProvValues {
5147 cert_chain: Vec<u8>,
5148 priv_key: Vec<u8>,
5149 batch_cert: Vec<u8>,
5150 }
5151
Max Bires2b2e6562020-09-22 11:22:36 -07005152 fn load_attestation_key_pool(
5153 db: &mut KeystoreDB,
5154 expiration_date: i64,
5155 namespace: i64,
5156 base_byte: u8,
Max Biresb2e1d032021-02-08 21:35:05 -08005157 ) -> Result<RemoteProvValues> {
Max Bires2b2e6562020-09-22 11:22:36 -07005158 let public_key: Vec<u8> = vec![base_byte, 0x02 * base_byte];
5159 let cert_chain: Vec<u8> = vec![0x03 * base_byte, 0x04 * base_byte];
5160 let priv_key: Vec<u8> = vec![0x05 * base_byte, 0x06 * base_byte];
5161 let raw_public_key: Vec<u8> = vec![0x0b * base_byte, 0x0c * base_byte];
Max Biresb2e1d032021-02-08 21:35:05 -08005162 let batch_cert: Vec<u8> = vec![base_byte * 0x0d, base_byte * 0x0e];
Max Bires2b2e6562020-09-22 11:22:36 -07005163 db.create_attestation_key_entry(&public_key, &raw_public_key, &priv_key, &KEYSTORE_UUID)?;
5164 db.store_signed_attestation_certificate_chain(
5165 &raw_public_key,
Max Biresb2e1d032021-02-08 21:35:05 -08005166 &batch_cert,
Max Bires2b2e6562020-09-22 11:22:36 -07005167 &cert_chain,
5168 expiration_date,
5169 &KEYSTORE_UUID,
5170 )?;
5171 db.assign_attestation_key(Domain::APP, namespace, &KEYSTORE_UUID)?;
Max Biresb2e1d032021-02-08 21:35:05 -08005172 Ok(RemoteProvValues { cert_chain, priv_key, batch_cert })
Max Bires2b2e6562020-09-22 11:22:36 -07005173 }
5174
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07005175 // Note: The parameters and SecurityLevel associations are nonsensical. This
5176 // collection is only used to check if the parameters are preserved as expected by the
5177 // database.
Qi Wub9433b52020-12-01 14:52:46 +08005178 fn make_test_params(max_usage_count: Option<i32>) -> Vec<KeyParameter> {
5179 let mut params = vec![
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07005180 KeyParameter::new(KeyParameterValue::Invalid, SecurityLevel::TRUSTED_ENVIRONMENT),
5181 KeyParameter::new(
5182 KeyParameterValue::KeyPurpose(KeyPurpose::SIGN),
5183 SecurityLevel::TRUSTED_ENVIRONMENT,
5184 ),
5185 KeyParameter::new(
5186 KeyParameterValue::KeyPurpose(KeyPurpose::DECRYPT),
5187 SecurityLevel::TRUSTED_ENVIRONMENT,
5188 ),
5189 KeyParameter::new(
5190 KeyParameterValue::Algorithm(Algorithm::RSA),
5191 SecurityLevel::TRUSTED_ENVIRONMENT,
5192 ),
5193 KeyParameter::new(KeyParameterValue::KeySize(1024), SecurityLevel::TRUSTED_ENVIRONMENT),
5194 KeyParameter::new(
5195 KeyParameterValue::BlockMode(BlockMode::ECB),
5196 SecurityLevel::TRUSTED_ENVIRONMENT,
5197 ),
5198 KeyParameter::new(
5199 KeyParameterValue::BlockMode(BlockMode::GCM),
5200 SecurityLevel::TRUSTED_ENVIRONMENT,
5201 ),
5202 KeyParameter::new(KeyParameterValue::Digest(Digest::NONE), SecurityLevel::STRONGBOX),
5203 KeyParameter::new(
5204 KeyParameterValue::Digest(Digest::MD5),
5205 SecurityLevel::TRUSTED_ENVIRONMENT,
5206 ),
5207 KeyParameter::new(
5208 KeyParameterValue::Digest(Digest::SHA_2_224),
5209 SecurityLevel::TRUSTED_ENVIRONMENT,
5210 ),
5211 KeyParameter::new(
5212 KeyParameterValue::Digest(Digest::SHA_2_256),
5213 SecurityLevel::STRONGBOX,
5214 ),
5215 KeyParameter::new(
5216 KeyParameterValue::PaddingMode(PaddingMode::NONE),
5217 SecurityLevel::TRUSTED_ENVIRONMENT,
5218 ),
5219 KeyParameter::new(
5220 KeyParameterValue::PaddingMode(PaddingMode::RSA_OAEP),
5221 SecurityLevel::TRUSTED_ENVIRONMENT,
5222 ),
5223 KeyParameter::new(
5224 KeyParameterValue::PaddingMode(PaddingMode::RSA_PSS),
5225 SecurityLevel::STRONGBOX,
5226 ),
5227 KeyParameter::new(
5228 KeyParameterValue::PaddingMode(PaddingMode::RSA_PKCS1_1_5_SIGN),
5229 SecurityLevel::TRUSTED_ENVIRONMENT,
5230 ),
5231 KeyParameter::new(KeyParameterValue::CallerNonce, SecurityLevel::TRUSTED_ENVIRONMENT),
5232 KeyParameter::new(KeyParameterValue::MinMacLength(256), SecurityLevel::STRONGBOX),
5233 KeyParameter::new(
5234 KeyParameterValue::EcCurve(EcCurve::P_224),
5235 SecurityLevel::TRUSTED_ENVIRONMENT,
5236 ),
5237 KeyParameter::new(KeyParameterValue::EcCurve(EcCurve::P_256), SecurityLevel::STRONGBOX),
5238 KeyParameter::new(
5239 KeyParameterValue::EcCurve(EcCurve::P_384),
5240 SecurityLevel::TRUSTED_ENVIRONMENT,
5241 ),
5242 KeyParameter::new(
5243 KeyParameterValue::EcCurve(EcCurve::P_521),
5244 SecurityLevel::TRUSTED_ENVIRONMENT,
5245 ),
5246 KeyParameter::new(
5247 KeyParameterValue::RSAPublicExponent(3),
5248 SecurityLevel::TRUSTED_ENVIRONMENT,
5249 ),
5250 KeyParameter::new(
5251 KeyParameterValue::IncludeUniqueID,
5252 SecurityLevel::TRUSTED_ENVIRONMENT,
5253 ),
5254 KeyParameter::new(KeyParameterValue::BootLoaderOnly, SecurityLevel::STRONGBOX),
5255 KeyParameter::new(KeyParameterValue::RollbackResistance, SecurityLevel::STRONGBOX),
5256 KeyParameter::new(
5257 KeyParameterValue::ActiveDateTime(1234567890),
5258 SecurityLevel::STRONGBOX,
5259 ),
5260 KeyParameter::new(
5261 KeyParameterValue::OriginationExpireDateTime(1234567890),
5262 SecurityLevel::TRUSTED_ENVIRONMENT,
5263 ),
5264 KeyParameter::new(
5265 KeyParameterValue::UsageExpireDateTime(1234567890),
5266 SecurityLevel::TRUSTED_ENVIRONMENT,
5267 ),
5268 KeyParameter::new(
5269 KeyParameterValue::MinSecondsBetweenOps(1234567890),
5270 SecurityLevel::TRUSTED_ENVIRONMENT,
5271 ),
5272 KeyParameter::new(
5273 KeyParameterValue::MaxUsesPerBoot(1234567890),
5274 SecurityLevel::TRUSTED_ENVIRONMENT,
5275 ),
5276 KeyParameter::new(KeyParameterValue::UserID(1), SecurityLevel::STRONGBOX),
5277 KeyParameter::new(KeyParameterValue::UserSecureID(42), SecurityLevel::STRONGBOX),
5278 KeyParameter::new(
5279 KeyParameterValue::NoAuthRequired,
5280 SecurityLevel::TRUSTED_ENVIRONMENT,
5281 ),
5282 KeyParameter::new(
5283 KeyParameterValue::HardwareAuthenticatorType(HardwareAuthenticatorType::PASSWORD),
5284 SecurityLevel::TRUSTED_ENVIRONMENT,
5285 ),
5286 KeyParameter::new(KeyParameterValue::AuthTimeout(1234567890), SecurityLevel::SOFTWARE),
5287 KeyParameter::new(KeyParameterValue::AllowWhileOnBody, SecurityLevel::SOFTWARE),
5288 KeyParameter::new(
5289 KeyParameterValue::TrustedUserPresenceRequired,
5290 SecurityLevel::TRUSTED_ENVIRONMENT,
5291 ),
5292 KeyParameter::new(
5293 KeyParameterValue::TrustedConfirmationRequired,
5294 SecurityLevel::TRUSTED_ENVIRONMENT,
5295 ),
5296 KeyParameter::new(
5297 KeyParameterValue::UnlockedDeviceRequired,
5298 SecurityLevel::TRUSTED_ENVIRONMENT,
5299 ),
5300 KeyParameter::new(
5301 KeyParameterValue::ApplicationID(vec![1u8, 2u8, 3u8, 4u8]),
5302 SecurityLevel::SOFTWARE,
5303 ),
5304 KeyParameter::new(
5305 KeyParameterValue::ApplicationData(vec![4u8, 3u8, 2u8, 1u8]),
5306 SecurityLevel::SOFTWARE,
5307 ),
5308 KeyParameter::new(
5309 KeyParameterValue::CreationDateTime(12345677890),
5310 SecurityLevel::SOFTWARE,
5311 ),
5312 KeyParameter::new(
5313 KeyParameterValue::KeyOrigin(KeyOrigin::GENERATED),
5314 SecurityLevel::TRUSTED_ENVIRONMENT,
5315 ),
5316 KeyParameter::new(
5317 KeyParameterValue::RootOfTrust(vec![3u8, 2u8, 1u8, 4u8]),
5318 SecurityLevel::TRUSTED_ENVIRONMENT,
5319 ),
5320 KeyParameter::new(KeyParameterValue::OSVersion(1), SecurityLevel::TRUSTED_ENVIRONMENT),
5321 KeyParameter::new(KeyParameterValue::OSPatchLevel(2), SecurityLevel::SOFTWARE),
5322 KeyParameter::new(
5323 KeyParameterValue::UniqueID(vec![4u8, 3u8, 1u8, 2u8]),
5324 SecurityLevel::SOFTWARE,
5325 ),
5326 KeyParameter::new(
5327 KeyParameterValue::AttestationChallenge(vec![4u8, 3u8, 1u8, 2u8]),
5328 SecurityLevel::TRUSTED_ENVIRONMENT,
5329 ),
5330 KeyParameter::new(
5331 KeyParameterValue::AttestationApplicationID(vec![4u8, 3u8, 1u8, 2u8]),
5332 SecurityLevel::TRUSTED_ENVIRONMENT,
5333 ),
5334 KeyParameter::new(
5335 KeyParameterValue::AttestationIdBrand(vec![4u8, 3u8, 1u8, 2u8]),
5336 SecurityLevel::TRUSTED_ENVIRONMENT,
5337 ),
5338 KeyParameter::new(
5339 KeyParameterValue::AttestationIdDevice(vec![4u8, 3u8, 1u8, 2u8]),
5340 SecurityLevel::TRUSTED_ENVIRONMENT,
5341 ),
5342 KeyParameter::new(
5343 KeyParameterValue::AttestationIdProduct(vec![4u8, 3u8, 1u8, 2u8]),
5344 SecurityLevel::TRUSTED_ENVIRONMENT,
5345 ),
5346 KeyParameter::new(
5347 KeyParameterValue::AttestationIdSerial(vec![4u8, 3u8, 1u8, 2u8]),
5348 SecurityLevel::TRUSTED_ENVIRONMENT,
5349 ),
5350 KeyParameter::new(
5351 KeyParameterValue::AttestationIdIMEI(vec![4u8, 3u8, 1u8, 2u8]),
5352 SecurityLevel::TRUSTED_ENVIRONMENT,
5353 ),
5354 KeyParameter::new(
5355 KeyParameterValue::AttestationIdMEID(vec![4u8, 3u8, 1u8, 2u8]),
5356 SecurityLevel::TRUSTED_ENVIRONMENT,
5357 ),
5358 KeyParameter::new(
5359 KeyParameterValue::AttestationIdManufacturer(vec![4u8, 3u8, 1u8, 2u8]),
5360 SecurityLevel::TRUSTED_ENVIRONMENT,
5361 ),
5362 KeyParameter::new(
5363 KeyParameterValue::AttestationIdModel(vec![4u8, 3u8, 1u8, 2u8]),
5364 SecurityLevel::TRUSTED_ENVIRONMENT,
5365 ),
5366 KeyParameter::new(
5367 KeyParameterValue::VendorPatchLevel(3),
5368 SecurityLevel::TRUSTED_ENVIRONMENT,
5369 ),
5370 KeyParameter::new(
5371 KeyParameterValue::BootPatchLevel(4),
5372 SecurityLevel::TRUSTED_ENVIRONMENT,
5373 ),
5374 KeyParameter::new(
5375 KeyParameterValue::AssociatedData(vec![4u8, 3u8, 1u8, 2u8]),
5376 SecurityLevel::TRUSTED_ENVIRONMENT,
5377 ),
5378 KeyParameter::new(
5379 KeyParameterValue::Nonce(vec![4u8, 3u8, 1u8, 2u8]),
5380 SecurityLevel::TRUSTED_ENVIRONMENT,
5381 ),
5382 KeyParameter::new(
5383 KeyParameterValue::MacLength(256),
5384 SecurityLevel::TRUSTED_ENVIRONMENT,
5385 ),
5386 KeyParameter::new(
5387 KeyParameterValue::ResetSinceIdRotation,
5388 SecurityLevel::TRUSTED_ENVIRONMENT,
5389 ),
5390 KeyParameter::new(
5391 KeyParameterValue::ConfirmationToken(vec![5u8, 5u8, 5u8, 5u8]),
5392 SecurityLevel::TRUSTED_ENVIRONMENT,
5393 ),
Qi Wub9433b52020-12-01 14:52:46 +08005394 ];
5395 if let Some(value) = max_usage_count {
5396 params.push(KeyParameter::new(
5397 KeyParameterValue::UsageCountLimit(value),
5398 SecurityLevel::SOFTWARE,
5399 ));
5400 }
5401 params
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07005402 }
5403
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07005404 fn make_test_key_entry(
5405 db: &mut KeystoreDB,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07005406 domain: Domain,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07005407 namespace: i64,
5408 alias: &str,
Qi Wub9433b52020-12-01 14:52:46 +08005409 max_usage_count: Option<i32>,
Janis Danisevskisaec14592020-11-12 09:41:49 -08005410 ) -> Result<KeyIdGuard> {
Janis Danisevskis0cabd712021-05-25 11:07:10 -07005411 let key_id = db.create_key_entry(&domain, &namespace, KeyType::Client, &KEYSTORE_UUID)?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08005412 let mut blob_metadata = BlobMetaData::new();
5413 blob_metadata.add(BlobMetaEntry::EncryptedBy(EncryptedBy::Password));
5414 blob_metadata.add(BlobMetaEntry::Salt(vec![1, 2, 3]));
5415 blob_metadata.add(BlobMetaEntry::Iv(vec![2, 3, 1]));
5416 blob_metadata.add(BlobMetaEntry::AeadTag(vec![3, 1, 2]));
5417 blob_metadata.add(BlobMetaEntry::KmUuid(KEYSTORE_UUID));
5418
5419 db.set_blob(
5420 &key_id,
5421 SubComponentType::KEY_BLOB,
5422 Some(TEST_KEY_BLOB),
5423 Some(&blob_metadata),
5424 )?;
5425 db.set_blob(&key_id, SubComponentType::CERT, Some(TEST_CERT_BLOB), None)?;
5426 db.set_blob(&key_id, SubComponentType::CERT_CHAIN, Some(TEST_CERT_CHAIN_BLOB), None)?;
Qi Wub9433b52020-12-01 14:52:46 +08005427
5428 let params = make_test_params(max_usage_count);
5429 db.insert_keyparameter(&key_id, &params)?;
5430
Janis Danisevskisb42fc182020-12-15 08:41:27 -08005431 let mut metadata = KeyMetaData::new();
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08005432 metadata.add(KeyMetaEntry::CreationDate(DateTime::from_millis_epoch(123456789)));
Janis Danisevskisb42fc182020-12-15 08:41:27 -08005433 db.insert_key_metadata(&key_id, &metadata)?;
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08005434 rebind_alias(db, &key_id, alias, domain, namespace)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07005435 Ok(key_id)
5436 }
5437
Qi Wub9433b52020-12-01 14:52:46 +08005438 fn make_test_key_entry_test_vector(key_id: i64, max_usage_count: Option<i32>) -> KeyEntry {
5439 let params = make_test_params(max_usage_count);
5440
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08005441 let mut blob_metadata = BlobMetaData::new();
5442 blob_metadata.add(BlobMetaEntry::EncryptedBy(EncryptedBy::Password));
5443 blob_metadata.add(BlobMetaEntry::Salt(vec![1, 2, 3]));
5444 blob_metadata.add(BlobMetaEntry::Iv(vec![2, 3, 1]));
5445 blob_metadata.add(BlobMetaEntry::AeadTag(vec![3, 1, 2]));
5446 blob_metadata.add(BlobMetaEntry::KmUuid(KEYSTORE_UUID));
5447
Janis Danisevskisb42fc182020-12-15 08:41:27 -08005448 let mut metadata = KeyMetaData::new();
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08005449 metadata.add(KeyMetaEntry::CreationDate(DateTime::from_millis_epoch(123456789)));
Janis Danisevskisb42fc182020-12-15 08:41:27 -08005450
5451 KeyEntry {
5452 id: key_id,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08005453 key_blob_info: Some((TEST_KEY_BLOB.to_vec(), blob_metadata)),
Janis Danisevskisb42fc182020-12-15 08:41:27 -08005454 cert: Some(TEST_CERT_BLOB.to_vec()),
5455 cert_chain: Some(TEST_CERT_CHAIN_BLOB.to_vec()),
Max Bires8e93d2b2021-01-14 13:17:59 -08005456 km_uuid: KEYSTORE_UUID,
Qi Wub9433b52020-12-01 14:52:46 +08005457 parameters: params,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08005458 metadata,
Janis Danisevskis377d1002021-01-27 19:07:48 -08005459 pure_cert: false,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08005460 }
5461 }
5462
Janis Danisevskiscfaf9192021-05-26 16:31:02 -07005463 fn make_bootlevel_key_entry(
5464 db: &mut KeystoreDB,
5465 domain: Domain,
5466 namespace: i64,
5467 alias: &str,
5468 logical_only: bool,
5469 ) -> Result<KeyIdGuard> {
5470 let key_id = db.create_key_entry(&domain, &namespace, KeyType::Client, &KEYSTORE_UUID)?;
5471 let mut blob_metadata = BlobMetaData::new();
5472 if !logical_only {
5473 blob_metadata.add(BlobMetaEntry::MaxBootLevel(3));
5474 }
5475 blob_metadata.add(BlobMetaEntry::KmUuid(KEYSTORE_UUID));
5476
5477 db.set_blob(
5478 &key_id,
5479 SubComponentType::KEY_BLOB,
5480 Some(TEST_KEY_BLOB),
5481 Some(&blob_metadata),
5482 )?;
5483 db.set_blob(&key_id, SubComponentType::CERT, Some(TEST_CERT_BLOB), None)?;
5484 db.set_blob(&key_id, SubComponentType::CERT_CHAIN, Some(TEST_CERT_CHAIN_BLOB), None)?;
5485
5486 let mut params = make_test_params(None);
5487 params.push(KeyParameter::new(KeyParameterValue::MaxBootLevel(3), SecurityLevel::KEYSTORE));
5488
5489 db.insert_keyparameter(&key_id, &params)?;
5490
5491 let mut metadata = KeyMetaData::new();
5492 metadata.add(KeyMetaEntry::CreationDate(DateTime::from_millis_epoch(123456789)));
5493 db.insert_key_metadata(&key_id, &metadata)?;
5494 rebind_alias(db, &key_id, alias, domain, namespace)?;
5495 Ok(key_id)
5496 }
5497
5498 fn make_bootlevel_test_key_entry_test_vector(key_id: i64, logical_only: bool) -> KeyEntry {
5499 let mut params = make_test_params(None);
5500 params.push(KeyParameter::new(KeyParameterValue::MaxBootLevel(3), SecurityLevel::KEYSTORE));
5501
5502 let mut blob_metadata = BlobMetaData::new();
5503 if !logical_only {
5504 blob_metadata.add(BlobMetaEntry::MaxBootLevel(3));
5505 }
5506 blob_metadata.add(BlobMetaEntry::KmUuid(KEYSTORE_UUID));
5507
5508 let mut metadata = KeyMetaData::new();
5509 metadata.add(KeyMetaEntry::CreationDate(DateTime::from_millis_epoch(123456789)));
5510
5511 KeyEntry {
5512 id: key_id,
5513 key_blob_info: Some((TEST_KEY_BLOB.to_vec(), blob_metadata)),
5514 cert: Some(TEST_CERT_BLOB.to_vec()),
5515 cert_chain: Some(TEST_CERT_CHAIN_BLOB.to_vec()),
5516 km_uuid: KEYSTORE_UUID,
5517 parameters: params,
5518 metadata,
5519 pure_cert: false,
5520 }
5521 }
5522
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07005523 fn debug_dump_keyentry_table(db: &mut KeystoreDB) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08005524 let mut stmt = db.conn.prepare(
Max Bires8e93d2b2021-01-14 13:17:59 -08005525 "SELECT id, key_type, domain, namespace, alias, state, km_uuid FROM persistent.keyentry;",
Janis Danisevskis93927dd2020-12-23 12:23:08 -08005526 )?;
Max Bires8e93d2b2021-01-14 13:17:59 -08005527 let rows = stmt.query_map::<(i64, KeyType, i32, i64, String, KeyLifeCycle, Uuid), _, _>(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08005528 NO_PARAMS,
5529 |row| {
Max Bires8e93d2b2021-01-14 13:17:59 -08005530 Ok((
5531 row.get(0)?,
5532 row.get(1)?,
5533 row.get(2)?,
5534 row.get(3)?,
5535 row.get(4)?,
5536 row.get(5)?,
5537 row.get(6)?,
5538 ))
Janis Danisevskis93927dd2020-12-23 12:23:08 -08005539 },
5540 )?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07005541
5542 println!("Key entry table rows:");
5543 for r in rows {
Max Bires8e93d2b2021-01-14 13:17:59 -08005544 let (id, key_type, domain, namespace, alias, state, km_uuid) = r.unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07005545 println!(
Max Bires8e93d2b2021-01-14 13:17:59 -08005546 " id: {} KeyType: {:?} Domain: {} Namespace: {} Alias: {} State: {:?} KmUuid: {:?}",
5547 id, key_type, domain, namespace, alias, state, km_uuid
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07005548 );
5549 }
5550 Ok(())
5551 }
5552
5553 fn debug_dump_grant_table(db: &mut KeystoreDB) -> Result<()> {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08005554 let mut stmt = db
5555 .conn
5556 .prepare("SELECT id, grantee, keyentryid, access_vector FROM persistent.grant;")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07005557 let rows = stmt.query_map::<(i64, i64, i64, i64), _, _>(NO_PARAMS, |row| {
5558 Ok((row.get(0)?, row.get(1)?, row.get(2)?, row.get(3)?))
5559 })?;
5560
5561 println!("Grant table rows:");
5562 for r in rows {
5563 let (id, gt, ki, av) = r.unwrap();
5564 println!(" id: {} grantee: {} key_id: {} access_vector: {}", id, gt, ki, av);
5565 }
5566 Ok(())
5567 }
5568
Joel Galenson0891bc12020-07-20 10:37:03 -07005569 // Use a custom random number generator that repeats each number once.
5570 // This allows us to test repeated elements.
5571
5572 thread_local! {
5573 static RANDOM_COUNTER: RefCell<i64> = RefCell::new(0);
5574 }
5575
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07005576 fn reset_random() {
5577 RANDOM_COUNTER.with(|counter| {
5578 *counter.borrow_mut() = 0;
5579 })
5580 }
5581
Joel Galenson0891bc12020-07-20 10:37:03 -07005582 pub fn random() -> i64 {
5583 RANDOM_COUNTER.with(|counter| {
5584 let result = *counter.borrow() / 2;
5585 *counter.borrow_mut() += 1;
5586 result
5587 })
5588 }
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00005589
5590 #[test]
5591 fn test_last_off_body() -> Result<()> {
5592 let mut db = new_test_db()?;
Matthew Maurerd7815ca2021-05-06 21:58:45 -07005593 db.insert_last_off_body(MonotonicRawTime::now());
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00005594 let tx = db.conn.transaction_with_behavior(TransactionBehavior::Immediate)?;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00005595 tx.commit()?;
Matthew Maurerd7815ca2021-05-06 21:58:45 -07005596 let last_off_body_1 = db.get_last_off_body();
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00005597 let one_second = Duration::from_secs(1);
5598 thread::sleep(one_second);
Matthew Maurerd7815ca2021-05-06 21:58:45 -07005599 db.update_last_off_body(MonotonicRawTime::now());
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00005600 let tx2 = db.conn.transaction_with_behavior(TransactionBehavior::Immediate)?;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00005601 tx2.commit()?;
Matthew Maurerd7815ca2021-05-06 21:58:45 -07005602 let last_off_body_2 = db.get_last_off_body();
Hasini Gunasinghe66a24602021-05-12 19:03:12 +00005603 assert!(last_off_body_1 < last_off_body_2);
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00005604 Ok(())
5605 }
Hasini Gunasingheda895552021-01-27 19:34:37 +00005606
5607 #[test]
5608 fn test_unbind_keys_for_user() -> Result<()> {
5609 let mut db = new_test_db()?;
5610 db.unbind_keys_for_user(1, false)?;
5611
5612 make_test_key_entry(&mut db, Domain::APP, 210000, TEST_ALIAS, None)?;
5613 make_test_key_entry(&mut db, Domain::APP, 110000, TEST_ALIAS, None)?;
5614 db.unbind_keys_for_user(2, false)?;
5615
Janis Danisevskis18313832021-05-17 13:30:32 -07005616 assert_eq!(1, db.list(Domain::APP, 110000, KeyType::Client)?.len());
5617 assert_eq!(0, db.list(Domain::APP, 210000, KeyType::Client)?.len());
Hasini Gunasingheda895552021-01-27 19:34:37 +00005618
5619 db.unbind_keys_for_user(1, true)?;
Janis Danisevskis18313832021-05-17 13:30:32 -07005620 assert_eq!(0, db.list(Domain::APP, 110000, KeyType::Client)?.len());
Hasini Gunasingheda895552021-01-27 19:34:37 +00005621
5622 Ok(())
5623 }
5624
5625 #[test]
Janis Danisevskis11bd2592022-01-04 19:59:26 -08005626 fn test_unbind_keys_for_user_removes_superkeys() -> Result<()> {
5627 let mut db = new_test_db()?;
5628 let super_key = keystore2_crypto::generate_aes256_key()?;
5629 let pw: keystore2_crypto::Password = (&b"xyzabc"[..]).into();
5630 let (encrypted_super_key, metadata) =
5631 SuperKeyManager::encrypt_with_password(&super_key, &pw)?;
5632
5633 let key_name_enc = SuperKeyType {
5634 alias: "test_super_key_1",
5635 algorithm: SuperEncryptionAlgorithm::Aes256Gcm,
5636 };
5637
5638 let key_name_nonenc = SuperKeyType {
5639 alias: "test_super_key_2",
5640 algorithm: SuperEncryptionAlgorithm::Aes256Gcm,
5641 };
5642
5643 // Install two super keys.
5644 db.store_super_key(
5645 1,
5646 &key_name_nonenc,
5647 &super_key,
5648 &BlobMetaData::new(),
5649 &KeyMetaData::new(),
5650 )?;
5651 db.store_super_key(1, &key_name_enc, &encrypted_super_key, &metadata, &KeyMetaData::new())?;
5652
5653 // Check that both can be found in the database.
5654 assert!(db.load_super_key(&key_name_enc, 1)?.is_some());
5655 assert!(db.load_super_key(&key_name_nonenc, 1)?.is_some());
5656
5657 // Install the same keys for a different user.
5658 db.store_super_key(
5659 2,
5660 &key_name_nonenc,
5661 &super_key,
5662 &BlobMetaData::new(),
5663 &KeyMetaData::new(),
5664 )?;
5665 db.store_super_key(2, &key_name_enc, &encrypted_super_key, &metadata, &KeyMetaData::new())?;
5666
5667 // Check that the second pair of keys can be found in the database.
5668 assert!(db.load_super_key(&key_name_enc, 2)?.is_some());
5669 assert!(db.load_super_key(&key_name_nonenc, 2)?.is_some());
5670
5671 // Delete only encrypted keys.
5672 db.unbind_keys_for_user(1, true)?;
5673
5674 // The encrypted superkey should be gone now.
5675 assert!(db.load_super_key(&key_name_enc, 1)?.is_none());
5676 assert!(db.load_super_key(&key_name_nonenc, 1)?.is_some());
5677
5678 // Reinsert the encrypted key.
5679 db.store_super_key(1, &key_name_enc, &encrypted_super_key, &metadata, &KeyMetaData::new())?;
5680
5681 // Check that both can be found in the database, again..
5682 assert!(db.load_super_key(&key_name_enc, 1)?.is_some());
5683 assert!(db.load_super_key(&key_name_nonenc, 1)?.is_some());
5684
5685 // Delete all even unencrypted keys.
5686 db.unbind_keys_for_user(1, false)?;
5687
5688 // Both should be gone now.
5689 assert!(db.load_super_key(&key_name_enc, 1)?.is_none());
5690 assert!(db.load_super_key(&key_name_nonenc, 1)?.is_none());
5691
5692 // Check that the second pair of keys was untouched.
5693 assert!(db.load_super_key(&key_name_enc, 2)?.is_some());
5694 assert!(db.load_super_key(&key_name_nonenc, 2)?.is_some());
5695
5696 Ok(())
5697 }
5698
5699 #[test]
Hasini Gunasingheda895552021-01-27 19:34:37 +00005700 fn test_store_super_key() -> Result<()> {
5701 let mut db = new_test_db()?;
Paul Crowleyf61fee72021-03-17 14:38:44 -07005702 let pw: keystore2_crypto::Password = (&b"xyzabc"[..]).into();
Hasini Gunasingheda895552021-01-27 19:34:37 +00005703 let super_key = keystore2_crypto::generate_aes256_key()?;
Paul Crowley7a658392021-03-18 17:08:20 -07005704 let secret_bytes = b"keystore2 is great.";
Hasini Gunasingheda895552021-01-27 19:34:37 +00005705 let (encrypted_secret, iv, tag) =
Paul Crowley7a658392021-03-18 17:08:20 -07005706 keystore2_crypto::aes_gcm_encrypt(secret_bytes, &super_key)?;
Hasini Gunasingheda895552021-01-27 19:34:37 +00005707
5708 let (encrypted_super_key, metadata) =
5709 SuperKeyManager::encrypt_with_password(&super_key, &pw)?;
Paul Crowley8d5b2532021-03-19 10:53:07 -07005710 db.store_super_key(
5711 1,
5712 &USER_SUPER_KEY,
5713 &encrypted_super_key,
5714 &metadata,
5715 &KeyMetaData::new(),
5716 )?;
Hasini Gunasingheda895552021-01-27 19:34:37 +00005717
Janis Danisevskis11bd2592022-01-04 19:59:26 -08005718 // Check if super key exists.
Chris Wailesd5aaaef2021-07-27 16:04:33 -07005719 assert!(db.key_exists(Domain::APP, 1, USER_SUPER_KEY.alias, KeyType::Super)?);
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00005720
Paul Crowley7a658392021-03-18 17:08:20 -07005721 let (_, key_entry) = db.load_super_key(&USER_SUPER_KEY, 1)?.unwrap();
Paul Crowley8d5b2532021-03-19 10:53:07 -07005722 let loaded_super_key = SuperKeyManager::extract_super_key_from_key_entry(
5723 USER_SUPER_KEY.algorithm,
5724 key_entry,
5725 &pw,
5726 None,
5727 )?;
Hasini Gunasingheda895552021-01-27 19:34:37 +00005728
Janis Danisevskisf84d0b02022-01-26 14:11:14 -08005729 let decrypted_secret_bytes = loaded_super_key.decrypt(&encrypted_secret, &iv, &tag)?;
Paul Crowley7a658392021-03-18 17:08:20 -07005730 assert_eq!(secret_bytes, &*decrypted_secret_bytes);
Janis Danisevskis11bd2592022-01-04 19:59:26 -08005731
Hasini Gunasingheda895552021-01-27 19:34:37 +00005732 Ok(())
5733 }
Seth Moore78c091f2021-04-09 21:38:30 +00005734
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00005735 fn get_valid_statsd_storage_types() -> Vec<MetricsStorage> {
Seth Moore78c091f2021-04-09 21:38:30 +00005736 vec![
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00005737 MetricsStorage::KEY_ENTRY,
5738 MetricsStorage::KEY_ENTRY_ID_INDEX,
5739 MetricsStorage::KEY_ENTRY_DOMAIN_NAMESPACE_INDEX,
5740 MetricsStorage::BLOB_ENTRY,
5741 MetricsStorage::BLOB_ENTRY_KEY_ENTRY_ID_INDEX,
5742 MetricsStorage::KEY_PARAMETER,
5743 MetricsStorage::KEY_PARAMETER_KEY_ENTRY_ID_INDEX,
5744 MetricsStorage::KEY_METADATA,
5745 MetricsStorage::KEY_METADATA_KEY_ENTRY_ID_INDEX,
5746 MetricsStorage::GRANT,
5747 MetricsStorage::AUTH_TOKEN,
5748 MetricsStorage::BLOB_METADATA,
5749 MetricsStorage::BLOB_METADATA_BLOB_ENTRY_ID_INDEX,
Seth Moore78c091f2021-04-09 21:38:30 +00005750 ]
5751 }
5752
5753 /// Perform a simple check to ensure that we can query all the storage types
5754 /// that are supported by the DB. Check for reasonable values.
5755 #[test]
5756 fn test_query_all_valid_table_sizes() -> Result<()> {
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00005757 const PAGE_SIZE: i32 = 4096;
Seth Moore78c091f2021-04-09 21:38:30 +00005758
5759 let mut db = new_test_db()?;
5760
5761 for t in get_valid_statsd_storage_types() {
5762 let stat = db.get_storage_stat(t)?;
Matthew Maurerd7815ca2021-05-06 21:58:45 -07005763 // AuthToken can be less than a page since it's in a btree, not sqlite
5764 // TODO(b/187474736) stop using if-let here
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00005765 if let MetricsStorage::AUTH_TOKEN = t {
Matthew Maurerd7815ca2021-05-06 21:58:45 -07005766 } else {
5767 assert!(stat.size >= PAGE_SIZE);
5768 }
Seth Moore78c091f2021-04-09 21:38:30 +00005769 assert!(stat.size >= stat.unused_size);
5770 }
5771
5772 Ok(())
5773 }
5774
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00005775 fn get_storage_stats_map(db: &mut KeystoreDB) -> BTreeMap<i32, StorageStats> {
Seth Moore78c091f2021-04-09 21:38:30 +00005776 get_valid_statsd_storage_types()
5777 .into_iter()
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00005778 .map(|t| (t.0, db.get_storage_stat(t).unwrap()))
Seth Moore78c091f2021-04-09 21:38:30 +00005779 .collect()
5780 }
5781
5782 fn assert_storage_increased(
5783 db: &mut KeystoreDB,
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00005784 increased_storage_types: Vec<MetricsStorage>,
5785 baseline: &mut BTreeMap<i32, StorageStats>,
Seth Moore78c091f2021-04-09 21:38:30 +00005786 ) {
5787 for storage in increased_storage_types {
5788 // Verify the expected storage increased.
5789 let new = db.get_storage_stat(storage).unwrap();
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00005790 let storage = storage;
5791 let old = &baseline[&storage.0];
5792 assert!(new.size >= old.size, "{}: {} >= {}", storage.0, new.size, old.size);
Seth Moore78c091f2021-04-09 21:38:30 +00005793 assert!(
5794 new.unused_size <= old.unused_size,
5795 "{}: {} <= {}",
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00005796 storage.0,
Seth Moore78c091f2021-04-09 21:38:30 +00005797 new.unused_size,
5798 old.unused_size
5799 );
5800
5801 // Update the baseline with the new value so that it succeeds in the
5802 // later comparison.
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00005803 baseline.insert(storage.0, new);
Seth Moore78c091f2021-04-09 21:38:30 +00005804 }
5805
5806 // Get an updated map of the storage and verify there were no unexpected changes.
5807 let updated_stats = get_storage_stats_map(db);
5808 assert_eq!(updated_stats.len(), baseline.len());
5809
5810 for &k in baseline.keys() {
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00005811 let stringify = |map: &BTreeMap<i32, StorageStats>| -> String {
Seth Moore78c091f2021-04-09 21:38:30 +00005812 let mut s = String::new();
5813 for &k in map.keys() {
5814 writeln!(&mut s, " {}: {}, {}", &k, map[&k].size, map[&k].unused_size)
5815 .expect("string concat failed");
5816 }
5817 s
5818 };
5819
5820 assert!(
5821 updated_stats[&k].size == baseline[&k].size
5822 && updated_stats[&k].unused_size == baseline[&k].unused_size,
5823 "updated_stats:\n{}\nbaseline:\n{}",
5824 stringify(&updated_stats),
Chris Wailesd5aaaef2021-07-27 16:04:33 -07005825 stringify(baseline)
Seth Moore78c091f2021-04-09 21:38:30 +00005826 );
5827 }
5828 }
5829
5830 #[test]
5831 fn test_verify_key_table_size_reporting() -> Result<()> {
5832 let mut db = new_test_db()?;
5833 let mut working_stats = get_storage_stats_map(&mut db);
5834
Janis Danisevskis0cabd712021-05-25 11:07:10 -07005835 let key_id = db.create_key_entry(&Domain::APP, &42, KeyType::Client, &KEYSTORE_UUID)?;
Seth Moore78c091f2021-04-09 21:38:30 +00005836 assert_storage_increased(
5837 &mut db,
5838 vec![
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00005839 MetricsStorage::KEY_ENTRY,
5840 MetricsStorage::KEY_ENTRY_ID_INDEX,
5841 MetricsStorage::KEY_ENTRY_DOMAIN_NAMESPACE_INDEX,
Seth Moore78c091f2021-04-09 21:38:30 +00005842 ],
5843 &mut working_stats,
5844 );
5845
5846 let mut blob_metadata = BlobMetaData::new();
5847 blob_metadata.add(BlobMetaEntry::EncryptedBy(EncryptedBy::Password));
5848 db.set_blob(&key_id, SubComponentType::KEY_BLOB, Some(TEST_KEY_BLOB), None)?;
5849 assert_storage_increased(
5850 &mut db,
5851 vec![
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00005852 MetricsStorage::BLOB_ENTRY,
5853 MetricsStorage::BLOB_ENTRY_KEY_ENTRY_ID_INDEX,
5854 MetricsStorage::BLOB_METADATA,
5855 MetricsStorage::BLOB_METADATA_BLOB_ENTRY_ID_INDEX,
Seth Moore78c091f2021-04-09 21:38:30 +00005856 ],
5857 &mut working_stats,
5858 );
5859
5860 let params = make_test_params(None);
5861 db.insert_keyparameter(&key_id, &params)?;
5862 assert_storage_increased(
5863 &mut db,
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00005864 vec![MetricsStorage::KEY_PARAMETER, MetricsStorage::KEY_PARAMETER_KEY_ENTRY_ID_INDEX],
Seth Moore78c091f2021-04-09 21:38:30 +00005865 &mut working_stats,
5866 );
5867
5868 let mut metadata = KeyMetaData::new();
5869 metadata.add(KeyMetaEntry::CreationDate(DateTime::from_millis_epoch(123456789)));
5870 db.insert_key_metadata(&key_id, &metadata)?;
5871 assert_storage_increased(
5872 &mut db,
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00005873 vec![MetricsStorage::KEY_METADATA, MetricsStorage::KEY_METADATA_KEY_ENTRY_ID_INDEX],
Seth Moore78c091f2021-04-09 21:38:30 +00005874 &mut working_stats,
5875 );
5876
5877 let mut sum = 0;
5878 for stat in working_stats.values() {
5879 sum += stat.size;
5880 }
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00005881 let total = db.get_storage_stat(MetricsStorage::DATABASE)?.size;
Seth Moore78c091f2021-04-09 21:38:30 +00005882 assert!(sum <= total, "Expected sum <= total. sum: {}, total: {}", sum, total);
5883
5884 Ok(())
5885 }
5886
5887 #[test]
5888 fn test_verify_auth_table_size_reporting() -> Result<()> {
5889 let mut db = new_test_db()?;
5890 let mut working_stats = get_storage_stats_map(&mut db);
5891 db.insert_auth_token(&HardwareAuthToken {
5892 challenge: 123,
5893 userId: 456,
5894 authenticatorId: 789,
5895 authenticatorType: kmhw_authenticator_type::ANY,
5896 timestamp: Timestamp { milliSeconds: 10 },
5897 mac: b"mac".to_vec(),
Matthew Maurerd7815ca2021-05-06 21:58:45 -07005898 });
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00005899 assert_storage_increased(&mut db, vec![MetricsStorage::AUTH_TOKEN], &mut working_stats);
Seth Moore78c091f2021-04-09 21:38:30 +00005900 Ok(())
5901 }
5902
5903 #[test]
5904 fn test_verify_grant_table_size_reporting() -> Result<()> {
5905 const OWNER: i64 = 1;
5906 let mut db = new_test_db()?;
5907 make_test_key_entry(&mut db, Domain::APP, OWNER, TEST_ALIAS, None)?;
5908
5909 let mut working_stats = get_storage_stats_map(&mut db);
5910 db.grant(
5911 &KeyDescriptor {
5912 domain: Domain::APP,
5913 nspace: 0,
5914 alias: Some(TEST_ALIAS.to_string()),
5915 blob: None,
5916 },
5917 OWNER as u32,
5918 123,
Janis Danisevskis39d57e72021-10-19 16:56:20 -07005919 key_perm_set![KeyPerm::Use],
Seth Moore78c091f2021-04-09 21:38:30 +00005920 |_, _| Ok(()),
5921 )?;
5922
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00005923 assert_storage_increased(&mut db, vec![MetricsStorage::GRANT], &mut working_stats);
Seth Moore78c091f2021-04-09 21:38:30 +00005924
5925 Ok(())
5926 }
Matthew Maurerd7815ca2021-05-06 21:58:45 -07005927
5928 #[test]
5929 fn find_auth_token_entry_returns_latest() -> Result<()> {
5930 let mut db = new_test_db()?;
5931 db.insert_auth_token(&HardwareAuthToken {
5932 challenge: 123,
5933 userId: 456,
5934 authenticatorId: 789,
5935 authenticatorType: kmhw_authenticator_type::ANY,
5936 timestamp: Timestamp { milliSeconds: 10 },
5937 mac: b"mac0".to_vec(),
5938 });
5939 std::thread::sleep(std::time::Duration::from_millis(1));
5940 db.insert_auth_token(&HardwareAuthToken {
5941 challenge: 123,
5942 userId: 457,
5943 authenticatorId: 789,
5944 authenticatorType: kmhw_authenticator_type::ANY,
5945 timestamp: Timestamp { milliSeconds: 12 },
5946 mac: b"mac1".to_vec(),
5947 });
5948 std::thread::sleep(std::time::Duration::from_millis(1));
5949 db.insert_auth_token(&HardwareAuthToken {
5950 challenge: 123,
5951 userId: 458,
5952 authenticatorId: 789,
5953 authenticatorType: kmhw_authenticator_type::ANY,
5954 timestamp: Timestamp { milliSeconds: 3 },
5955 mac: b"mac2".to_vec(),
5956 });
5957 // All three entries are in the database
5958 assert_eq!(db.perboot.auth_tokens_len(), 3);
5959 // It selected the most recent timestamp
5960 assert_eq!(db.find_auth_token_entry(|_| true).unwrap().0.auth_token.mac, b"mac2".to_vec());
5961 Ok(())
5962 }
Seth Moore472fcbb2021-05-12 10:07:51 -07005963
5964 #[test]
Pavel Grafovf45034a2021-05-12 22:35:45 +01005965 fn test_load_key_descriptor() -> Result<()> {
5966 let mut db = new_test_db()?;
5967 let key_id = make_test_key_entry(&mut db, Domain::APP, 1, TEST_ALIAS, None)?.0;
5968
5969 let key = db.load_key_descriptor(key_id)?.unwrap();
5970
5971 assert_eq!(key.domain, Domain::APP);
5972 assert_eq!(key.nspace, 1);
5973 assert_eq!(key.alias, Some(TEST_ALIAS.to_string()));
5974
5975 // No such id
5976 assert_eq!(db.load_key_descriptor(key_id + 1)?, None);
5977 Ok(())
5978 }
Joel Galenson26f4d012020-07-17 14:57:21 -07005979}