blob: 9f27b5a3769eef4e081a6ae9424c62726587fb9f [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
David Drysdale2566fb32024-07-09 14:46:37 +010048#[cfg(test)]
49pub mod tests;
50
Janis Danisevskis11bd2592022-01-04 19:59:26 -080051use crate::gc::Gc;
David Drysdalef1ba3812024-05-08 17:50:13 +010052use crate::impl_metadata; // This is in database/utils.rs
Eric Biggersb0478cf2023-10-27 03:55:29 +000053use crate::key_parameter::{KeyParameter, KeyParameterValue, Tag};
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +000054use crate::ks_err;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -070055use crate::permission::KeyPermSet;
Hasini Gunasinghe66a24602021-05-12 19:03:12 +000056use crate::utils::{get_current_time_in_milliseconds, watchdog as wd, AID_USER_OFFSET};
Janis Danisevskis7e8b4622021-02-13 10:01:59 -080057use crate::{
Paul Crowley7a658392021-03-18 17:08:20 -070058 error::{Error as KsError, ErrorCode, ResponseCode},
59 super_key::SuperKeyType,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -080060};
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +000061use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
Tri Voa1634bb2022-12-01 15:54:19 -080062 HardwareAuthToken::HardwareAuthToken, HardwareAuthenticatorType::HardwareAuthenticatorType,
63 SecurityLevel::SecurityLevel,
64};
65use android_security_metrics::aidl::android::security::metrics::{
Tri Vo0346bbe2023-05-12 14:16:31 -040066 Storage::Storage as MetricsStorage, StorageStats::StorageStats,
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};
Shaquille Johnson7f5a8152023-09-27 18:46:27 +010071use anyhow::{anyhow, Context, Result};
72use keystore2_flags;
Andrew Walbrana4bc1a92024-09-03 13:08:17 +010073use std::{convert::TryFrom, convert::TryInto, ops::Deref, sync::LazyLock, time::SystemTimeError};
Shaquille Johnson7f5a8152023-09-27 18:46:27 +010074use utils as db_utils;
75use utils::SqlField;
Max Bires2b2e6562020-09-22 11:22:36 -070076
77use keystore2_crypto::ZVec;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +000078use log::error;
Joel Galenson0891bc12020-07-20 10:37:03 -070079#[cfg(not(test))]
80use rand::prelude::random;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -070081use rusqlite::{
Joel Galensonff79e362021-05-25 16:30:17 -070082 params, params_from_iter,
Janis Danisevskisb42fc182020-12-15 08:41:27 -080083 types::FromSql,
84 types::FromSqlResult,
85 types::ToSqlOutput,
86 types::{FromSqlError, Value, ValueRef},
David Drysdale7b9ca232024-05-23 18:19:46 +010087 Connection, OptionalExtension, ToSql, Transaction,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -070088};
Max Bires2b2e6562020-09-22 11:22:36 -070089
Janis Danisevskisaec14592020-11-12 09:41:49 -080090use std::{
Janis Danisevskisb42fc182020-12-15 08:41:27 -080091 collections::{HashMap, HashSet},
Janis Danisevskisbf15d732020-12-08 10:35:26 -080092 path::Path,
Janis Danisevskis3395f862021-05-06 10:54:17 -070093 sync::{Arc, Condvar, Mutex},
Janis Danisevskisb42fc182020-12-15 08:41:27 -080094 time::{Duration, SystemTime},
Janis Danisevskisaec14592020-11-12 09:41:49 -080095};
Max Bires2b2e6562020-09-22 11:22:36 -070096
David Drysdale7b9ca232024-05-23 18:19:46 +010097use TransactionBehavior::Immediate;
98
Joel Galenson0891bc12020-07-20 10:37:03 -070099#[cfg(test)]
100use tests::random;
Joel Galenson26f4d012020-07-17 14:57:21 -0700101
David Drysdale7b9ca232024-05-23 18:19:46 +0100102/// Wrapper for `rusqlite::TransactionBehavior` which includes information about the transaction
103/// being performed.
104#[derive(Clone, Copy)]
105enum TransactionBehavior {
106 Deferred,
107 Immediate(&'static str),
108}
109
110impl From<TransactionBehavior> for rusqlite::TransactionBehavior {
111 fn from(val: TransactionBehavior) -> Self {
112 match val {
113 TransactionBehavior::Deferred => rusqlite::TransactionBehavior::Deferred,
114 TransactionBehavior::Immediate(_) => rusqlite::TransactionBehavior::Immediate,
115 }
116 }
117}
118
119impl TransactionBehavior {
120 fn name(&self) -> Option<&'static str> {
121 match self {
122 TransactionBehavior::Deferred => None,
123 TransactionBehavior::Immediate(v) => Some(v),
124 }
125 }
126}
127
David Drysdaleef897ec2024-10-22 12:55:06 +0100128/// Access information for a key.
129#[derive(Debug)]
130struct KeyAccessInfo {
131 key_id: i64,
132 descriptor: KeyDescriptor,
133 vector: Option<KeyPermSet>,
134}
135
David Drysdale115c4722024-04-15 14:11:52 +0100136/// If the database returns a busy error code, retry after this interval.
137const DB_BUSY_RETRY_INTERVAL: Duration = Duration::from_micros(500);
David Drysdale115c4722024-04-15 14:11:52 +0100138
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800139impl_metadata!(
140 /// A set of metadata for key entries.
141 #[derive(Debug, Default, Eq, PartialEq)]
142 pub struct KeyMetaData;
143 /// A metadata entry for key entries.
144 #[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
145 pub enum KeyMetaEntry {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800146 /// Date of the creation of the key entry.
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800147 CreationDate(DateTime) with accessor creation_date,
148 /// Expiration date for attestation keys.
149 AttestationExpirationDate(DateTime) with accessor attestation_expiration_date,
Max Bires2b2e6562020-09-22 11:22:36 -0700150 /// CBOR Blob that represents a COSE_Key and associated metadata needed for remote
151 /// provisioning
152 AttestationMacedPublicKey(Vec<u8>) with accessor attestation_maced_public_key,
153 /// Vector representing the raw public key so results from the server can be matched
154 /// to the right entry
155 AttestationRawPubKey(Vec<u8>) with accessor attestation_raw_pub_key,
Paul Crowley8d5b2532021-03-19 10:53:07 -0700156 /// SEC1 public key for ECDH encryption
157 Sec1PublicKey(Vec<u8>) with accessor sec1_public_key,
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800158 // --- ADD NEW META DATA FIELDS HERE ---
159 // For backwards compatibility add new entries only to
160 // end of this list and above this comment.
161 };
162);
163
164impl KeyMetaData {
165 fn load_from_db(key_id: i64, tx: &Transaction) -> Result<Self> {
166 let mut stmt = tx
167 .prepare(
168 "SELECT tag, data from persistent.keymetadata
169 WHERE keyentryid = ?;",
170 )
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000171 .context(ks_err!("KeyMetaData::load_from_db: prepare statement failed."))?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800172
173 let mut metadata: HashMap<i64, KeyMetaEntry> = Default::default();
174
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000175 let mut rows = stmt
176 .query(params![key_id])
177 .context(ks_err!("KeyMetaData::load_from_db: query failed."))?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800178 db_utils::with_rows_extract_all(&mut rows, |row| {
179 let db_tag: i64 = row.get(0).context("Failed to read tag.")?;
180 metadata.insert(
181 db_tag,
Chris Wailesd5aaaef2021-07-27 16:04:33 -0700182 KeyMetaEntry::new_from_sql(db_tag, &SqlField::new(1, row))
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800183 .context("Failed to read KeyMetaEntry.")?,
184 );
185 Ok(())
186 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000187 .context(ks_err!("KeyMetaData::load_from_db."))?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800188
189 Ok(Self { data: metadata })
190 }
191
192 fn store_in_db(&self, key_id: i64, tx: &Transaction) -> Result<()> {
193 let mut stmt = tx
194 .prepare(
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000195 "INSERT or REPLACE INTO persistent.keymetadata (keyentryid, tag, data)
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800196 VALUES (?, ?, ?);",
197 )
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000198 .context(ks_err!("KeyMetaData::store_in_db: Failed to prepare statement."))?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800199
200 let iter = self.data.iter();
201 for (tag, entry) in iter {
202 stmt.insert(params![key_id, tag, entry,]).with_context(|| {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000203 ks_err!("KeyMetaData::store_in_db: Failed to insert {:?}", entry)
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800204 })?;
205 }
206 Ok(())
207 }
208}
209
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800210impl_metadata!(
211 /// A set of metadata for key blobs.
212 #[derive(Debug, Default, Eq, PartialEq)]
213 pub struct BlobMetaData;
214 /// A metadata entry for key blobs.
215 #[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
216 pub enum BlobMetaEntry {
217 /// If present, indicates that the blob is encrypted with another key or a key derived
218 /// from a password.
219 EncryptedBy(EncryptedBy) with accessor encrypted_by,
220 /// If the blob is password encrypted this field is set to the
221 /// salt used for the key derivation.
222 Salt(Vec<u8>) with accessor salt,
223 /// If the blob is encrypted, this field is set to the initialization vector.
224 Iv(Vec<u8>) with accessor iv,
225 /// If the blob is encrypted, this field holds the AEAD TAG.
226 AeadTag(Vec<u8>) with accessor aead_tag,
227 /// The uuid of the owning KeyMint instance.
228 KmUuid(Uuid) with accessor km_uuid,
Paul Crowley8d5b2532021-03-19 10:53:07 -0700229 /// If the key is ECDH encrypted, this is the ephemeral public key
230 PublicKey(Vec<u8>) with accessor public_key,
Paul Crowley44c02da2021-04-08 17:04:43 +0000231 /// If the key is encrypted with a MaxBootLevel key, this is the boot level
232 /// of that key
233 MaxBootLevel(i32) with accessor max_boot_level,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800234 // --- ADD NEW META DATA FIELDS HERE ---
235 // For backwards compatibility add new entries only to
236 // end of this list and above this comment.
237 };
238);
239
240impl BlobMetaData {
241 fn load_from_db(blob_id: i64, tx: &Transaction) -> Result<Self> {
242 let mut stmt = tx
243 .prepare(
244 "SELECT tag, data from persistent.blobmetadata
245 WHERE blobentryid = ?;",
246 )
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000247 .context(ks_err!("BlobMetaData::load_from_db: prepare statement failed."))?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800248
249 let mut metadata: HashMap<i64, BlobMetaEntry> = Default::default();
250
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000251 let mut rows = stmt.query(params![blob_id]).context(ks_err!("query failed."))?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800252 db_utils::with_rows_extract_all(&mut rows, |row| {
253 let db_tag: i64 = row.get(0).context("Failed to read tag.")?;
254 metadata.insert(
255 db_tag,
Chris Wailesd5aaaef2021-07-27 16:04:33 -0700256 BlobMetaEntry::new_from_sql(db_tag, &SqlField::new(1, row))
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800257 .context("Failed to read BlobMetaEntry.")?,
258 );
259 Ok(())
260 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000261 .context(ks_err!("BlobMetaData::load_from_db"))?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800262
263 Ok(Self { data: metadata })
264 }
265
266 fn store_in_db(&self, blob_id: i64, tx: &Transaction) -> Result<()> {
267 let mut stmt = tx
268 .prepare(
269 "INSERT or REPLACE INTO persistent.blobmetadata (blobentryid, tag, data)
270 VALUES (?, ?, ?);",
271 )
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000272 .context(ks_err!("BlobMetaData::store_in_db: Failed to prepare statement.",))?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800273
274 let iter = self.data.iter();
275 for (tag, entry) in iter {
276 stmt.insert(params![blob_id, tag, entry,]).with_context(|| {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000277 ks_err!("BlobMetaData::store_in_db: Failed to insert {:?}", entry)
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800278 })?;
279 }
280 Ok(())
281 }
282}
283
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800284/// Indicates the type of the keyentry.
285#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
286pub enum KeyType {
287 /// This is a client key type. These keys are created or imported through the Keystore 2.0
288 /// AIDL interface android.system.keystore2.
289 Client,
290 /// This is a super key type. These keys are created by keystore itself and used to encrypt
291 /// other key blobs to provide LSKF binding.
292 Super,
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800293}
294
295impl ToSql for KeyType {
296 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
297 Ok(ToSqlOutput::Owned(Value::Integer(match self {
298 KeyType::Client => 0,
299 KeyType::Super => 1,
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800300 })))
301 }
302}
303
304impl FromSql for KeyType {
305 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
306 match i64::column_result(value)? {
307 0 => Ok(KeyType::Client),
308 1 => Ok(KeyType::Super),
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800309 v => Err(FromSqlError::OutOfRange(v)),
310 }
311 }
312}
313
Max Bires8e93d2b2021-01-14 13:17:59 -0800314/// Uuid representation that can be stored in the database.
315/// Right now it can only be initialized from SecurityLevel.
316/// Once KeyMint provides a UUID type a corresponding From impl shall be added.
317#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
318pub struct Uuid([u8; 16]);
319
320impl Deref for Uuid {
321 type Target = [u8; 16];
322
323 fn deref(&self) -> &Self::Target {
324 &self.0
325 }
326}
327
328impl From<SecurityLevel> for Uuid {
329 fn from(sec_level: SecurityLevel) -> Self {
330 Self((sec_level.0 as u128).to_be_bytes())
331 }
332}
333
334impl ToSql for Uuid {
335 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
336 self.0.to_sql()
337 }
338}
339
340impl FromSql for Uuid {
341 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
342 let blob = Vec::<u8>::column_result(value)?;
343 if blob.len() != 16 {
344 return Err(FromSqlError::OutOfRange(blob.len() as i64));
345 }
346 let mut arr = [0u8; 16];
347 arr.copy_from_slice(&blob);
348 Ok(Self(arr))
349 }
350}
351
352/// Key entries that are not associated with any KeyMint instance, such as pure certificate
353/// entries are associated with this UUID.
354pub static KEYSTORE_UUID: Uuid = Uuid([
355 0x41, 0xe3, 0xb9, 0xce, 0x27, 0x58, 0x4e, 0x91, 0xbc, 0xfd, 0xa5, 0x5d, 0x91, 0x85, 0xab, 0x11,
356]);
357
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800358/// Indicates how the sensitive part of this key blob is encrypted.
359#[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
360pub enum EncryptedBy {
361 /// The keyblob is encrypted by a user password.
362 /// In the database this variant is represented as NULL.
363 Password,
364 /// The keyblob is encrypted by another key with wrapped key id.
365 /// In the database this variant is represented as non NULL value
366 /// that is convertible to i64, typically NUMERIC.
367 KeyId(i64),
368}
369
370impl ToSql for EncryptedBy {
371 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
372 match self {
373 Self::Password => Ok(ToSqlOutput::Owned(Value::Null)),
374 Self::KeyId(id) => id.to_sql(),
375 }
376 }
377}
378
379impl FromSql for EncryptedBy {
380 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
381 match value {
382 ValueRef::Null => Ok(Self::Password),
383 _ => Ok(Self::KeyId(i64::column_result(value)?)),
384 }
385 }
386}
387
388/// A database representation of wall clock time. DateTime stores unix epoch time as
389/// i64 in milliseconds.
390#[derive(Debug, Copy, Clone, Default, Eq, PartialEq, Ord, PartialOrd)]
391pub struct DateTime(i64);
392
393/// Error type returned when creating DateTime or converting it from and to
394/// SystemTime.
395#[derive(thiserror::Error, Debug)]
396pub enum DateTimeError {
397 /// This is returned when SystemTime and Duration computations fail.
398 #[error(transparent)]
399 SystemTimeError(#[from] SystemTimeError),
400
401 /// This is returned when type conversions fail.
402 #[error(transparent)]
403 TypeConversion(#[from] std::num::TryFromIntError),
404
405 /// This is returned when checked time arithmetic failed.
406 #[error("Time arithmetic failed.")]
407 TimeArithmetic,
408}
409
410impl DateTime {
411 /// Constructs a new DateTime object denoting the current time. This may fail during
412 /// conversion to unix epoch time and during conversion to the internal i64 representation.
413 pub fn now() -> Result<Self, DateTimeError> {
414 Ok(Self(SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_millis().try_into()?))
415 }
416
417 /// Constructs a new DateTime object from milliseconds.
418 pub fn from_millis_epoch(millis: i64) -> Self {
419 Self(millis)
420 }
421
422 /// Returns unix epoch time in milliseconds.
Chris Wailes3877f292021-07-26 19:24:18 -0700423 pub fn to_millis_epoch(self) -> i64 {
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800424 self.0
425 }
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800426}
427
428impl ToSql for DateTime {
429 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
430 Ok(ToSqlOutput::Owned(Value::Integer(self.0)))
431 }
432}
433
434impl FromSql for DateTime {
435 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
436 Ok(Self(i64::column_result(value)?))
437 }
438}
439
440impl TryInto<SystemTime> for DateTime {
441 type Error = DateTimeError;
442
443 fn try_into(self) -> Result<SystemTime, Self::Error> {
444 // We want to construct a SystemTime representation equivalent to self, denoting
445 // a point in time THEN, but we cannot set the time directly. We can only construct
446 // a SystemTime denoting NOW, and we can get the duration between EPOCH and NOW,
447 // and between EPOCH and THEN. With this common reference we can construct the
448 // duration between NOW and THEN which we can add to our SystemTime representation
449 // of NOW to get a SystemTime representation of THEN.
450 // Durations can only be positive, thus the if statement below.
451 let now = SystemTime::now();
452 let now_epoch = now.duration_since(SystemTime::UNIX_EPOCH)?;
453 let then_epoch = Duration::from_millis(self.0.try_into()?);
454 Ok(if now_epoch > then_epoch {
455 // then = now - (now_epoch - then_epoch)
456 now_epoch
457 .checked_sub(then_epoch)
458 .and_then(|d| now.checked_sub(d))
459 .ok_or(DateTimeError::TimeArithmetic)?
460 } else {
461 // then = now + (then_epoch - now_epoch)
462 then_epoch
463 .checked_sub(now_epoch)
464 .and_then(|d| now.checked_add(d))
465 .ok_or(DateTimeError::TimeArithmetic)?
466 })
467 }
468}
469
470impl TryFrom<SystemTime> for DateTime {
471 type Error = DateTimeError;
472
473 fn try_from(t: SystemTime) -> Result<Self, Self::Error> {
474 Ok(Self(t.duration_since(SystemTime::UNIX_EPOCH)?.as_millis().try_into()?))
475 }
476}
477
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800478#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone)]
479enum KeyLifeCycle {
480 /// Existing keys have a key ID but are not fully populated yet.
481 /// This is a transient state. If Keystore finds any such keys when it starts up, it must move
482 /// them to Unreferenced for garbage collection.
483 Existing,
484 /// A live key is fully populated and usable by clients.
485 Live,
486 /// An unreferenced key is scheduled for garbage collection.
487 Unreferenced,
488}
489
490impl ToSql for KeyLifeCycle {
491 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
492 match self {
493 Self::Existing => Ok(ToSqlOutput::Owned(Value::Integer(0))),
494 Self::Live => Ok(ToSqlOutput::Owned(Value::Integer(1))),
495 Self::Unreferenced => Ok(ToSqlOutput::Owned(Value::Integer(2))),
496 }
497 }
498}
499
500impl FromSql for KeyLifeCycle {
501 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
502 match i64::column_result(value)? {
503 0 => Ok(KeyLifeCycle::Existing),
504 1 => Ok(KeyLifeCycle::Live),
505 2 => Ok(KeyLifeCycle::Unreferenced),
506 v => Err(FromSqlError::OutOfRange(v)),
507 }
508 }
509}
510
David Drysdale8da288c2024-07-29 15:57:01 +0100511/// Current state of a `blobentry` row.
512#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone, Default)]
513enum BlobState {
514 #[default]
515 /// Current blobentry (of its `subcomponent_type`) for the associated key.
516 Current,
517 /// Blobentry that is no longer the current blob (of its `subcomponent_type`) for the associated
518 /// key.
519 Superseded,
520 /// Blobentry for a key that no longer exists.
521 Orphaned,
522}
523
524impl ToSql for BlobState {
525 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
526 match self {
527 Self::Current => Ok(ToSqlOutput::Owned(Value::Integer(0))),
528 Self::Superseded => Ok(ToSqlOutput::Owned(Value::Integer(1))),
529 Self::Orphaned => Ok(ToSqlOutput::Owned(Value::Integer(2))),
530 }
531 }
532}
533
534impl FromSql for BlobState {
535 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
536 match i64::column_result(value)? {
537 0 => Ok(Self::Current),
538 1 => Ok(Self::Superseded),
539 2 => Ok(Self::Orphaned),
540 v => Err(FromSqlError::OutOfRange(v)),
541 }
542 }
543}
544
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700545/// Keys have a KeyMint blob component and optional public certificate and
546/// certificate chain components.
547/// KeyEntryLoadBits is a bitmap that indicates to `KeystoreDB::load_key_entry`
548/// which components shall be loaded from the database if present.
Janis Danisevskis66784c42021-01-27 08:40:25 -0800549#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700550pub struct KeyEntryLoadBits(u32);
551
552impl KeyEntryLoadBits {
553 /// Indicate to `KeystoreDB::load_key_entry` that no component shall be loaded.
554 pub const NONE: KeyEntryLoadBits = Self(0);
555 /// Indicate to `KeystoreDB::load_key_entry` that the KeyMint component shall be loaded.
556 pub const KM: KeyEntryLoadBits = Self(1);
557 /// Indicate to `KeystoreDB::load_key_entry` that the Public components shall be loaded.
558 pub const PUBLIC: KeyEntryLoadBits = Self(2);
559 /// Indicate to `KeystoreDB::load_key_entry` that both components shall be loaded.
560 pub const BOTH: KeyEntryLoadBits = Self(3);
561
562 /// Returns true if this object indicates that the public components shall be loaded.
563 pub const fn load_public(&self) -> bool {
564 self.0 & Self::PUBLIC.0 != 0
565 }
566
567 /// Returns true if the object indicates that the KeyMint component shall be loaded.
568 pub const fn load_km(&self) -> bool {
569 self.0 & Self::KM.0 != 0
570 }
571}
572
Andrew Walbrana4bc1a92024-09-03 13:08:17 +0100573static KEY_ID_LOCK: LazyLock<KeyIdLockDb> = LazyLock::new(KeyIdLockDb::new);
Janis Danisevskisaec14592020-11-12 09:41:49 -0800574
575struct KeyIdLockDb {
576 locked_keys: Mutex<HashSet<i64>>,
577 cond_var: Condvar,
578}
579
580/// A locked key. While a guard exists for a given key id, the same key cannot be loaded
581/// from the database a second time. Most functions manipulating the key blob database
582/// require a KeyIdGuard.
583#[derive(Debug)]
584pub struct KeyIdGuard(i64);
585
586impl KeyIdLockDb {
587 fn new() -> Self {
588 Self { locked_keys: Mutex::new(HashSet::new()), cond_var: Condvar::new() }
589 }
590
591 /// This function blocks until an exclusive lock for the given key entry id can
592 /// be acquired. It returns a guard object, that represents the lifecycle of the
593 /// acquired lock.
David Drysdale8c4c4f32023-10-31 12:14:11 +0000594 fn get(&self, key_id: i64) -> KeyIdGuard {
Janis Danisevskisaec14592020-11-12 09:41:49 -0800595 let mut locked_keys = self.locked_keys.lock().unwrap();
596 while locked_keys.contains(&key_id) {
597 locked_keys = self.cond_var.wait(locked_keys).unwrap();
598 }
599 locked_keys.insert(key_id);
600 KeyIdGuard(key_id)
601 }
602
603 /// This function attempts to acquire an exclusive lock on a given key id. If the
604 /// given key id is already taken the function returns None immediately. If a lock
605 /// can be acquired this function returns a guard object, that represents the
606 /// lifecycle of the acquired lock.
David Drysdale8c4c4f32023-10-31 12:14:11 +0000607 fn try_get(&self, key_id: i64) -> Option<KeyIdGuard> {
Janis Danisevskisaec14592020-11-12 09:41:49 -0800608 let mut locked_keys = self.locked_keys.lock().unwrap();
609 if locked_keys.insert(key_id) {
610 Some(KeyIdGuard(key_id))
611 } else {
612 None
613 }
614 }
615}
616
617impl KeyIdGuard {
618 /// Get the numeric key id of the locked key.
619 pub fn id(&self) -> i64 {
620 self.0
621 }
622}
623
624impl Drop for KeyIdGuard {
625 fn drop(&mut self) {
626 let mut locked_keys = KEY_ID_LOCK.locked_keys.lock().unwrap();
627 locked_keys.remove(&self.0);
Janis Danisevskis7fd53582020-11-23 13:40:34 -0800628 drop(locked_keys);
Janis Danisevskisaec14592020-11-12 09:41:49 -0800629 KEY_ID_LOCK.cond_var.notify_all();
630 }
631}
632
Max Bires8e93d2b2021-01-14 13:17:59 -0800633/// This type represents a certificate and certificate chain entry for a key.
Max Bires2b2e6562020-09-22 11:22:36 -0700634#[derive(Debug, Default)]
Max Bires8e93d2b2021-01-14 13:17:59 -0800635pub struct CertificateInfo {
636 cert: Option<Vec<u8>>,
637 cert_chain: Option<Vec<u8>>,
638}
639
Janis Danisevskisf84d0b02022-01-26 14:11:14 -0800640/// This type represents a Blob with its metadata and an optional superseded blob.
641#[derive(Debug)]
642pub struct BlobInfo<'a> {
643 blob: &'a [u8],
644 metadata: &'a BlobMetaData,
645 /// Superseded blobs are an artifact of legacy import. In some rare occasions
646 /// the key blob needs to be upgraded during import. In that case two
647 /// blob are imported, the superseded one will have to be imported first,
648 /// so that the garbage collector can reap it.
649 superseded_blob: Option<(&'a [u8], &'a BlobMetaData)>,
650}
651
652impl<'a> BlobInfo<'a> {
653 /// Create a new instance of blob info with blob and corresponding metadata
654 /// and no superseded blob info.
655 pub fn new(blob: &'a [u8], metadata: &'a BlobMetaData) -> Self {
656 Self { blob, metadata, superseded_blob: None }
657 }
658
659 /// Create a new instance of blob info with blob and corresponding metadata
660 /// as well as superseded blob info.
661 pub fn new_with_superseded(
662 blob: &'a [u8],
663 metadata: &'a BlobMetaData,
664 superseded_blob: Option<(&'a [u8], &'a BlobMetaData)>,
665 ) -> Self {
666 Self { blob, metadata, superseded_blob }
667 }
668}
669
Max Bires8e93d2b2021-01-14 13:17:59 -0800670impl CertificateInfo {
671 /// Constructs a new CertificateInfo object from `cert` and `cert_chain`
672 pub fn new(cert: Option<Vec<u8>>, cert_chain: Option<Vec<u8>>) -> Self {
673 Self { cert, cert_chain }
674 }
675
676 /// Take the cert
677 pub fn take_cert(&mut self) -> Option<Vec<u8>> {
678 self.cert.take()
679 }
680
681 /// Take the cert chain
682 pub fn take_cert_chain(&mut self) -> Option<Vec<u8>> {
683 self.cert_chain.take()
684 }
685}
686
Max Bires2b2e6562020-09-22 11:22:36 -0700687/// This type represents a certificate chain with a private key corresponding to the leaf
688/// 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 -0700689pub struct CertificateChain {
Max Bires97f96812021-02-23 23:44:57 -0800690 /// A KM key blob
691 pub private_key: ZVec,
692 /// A batch cert for private_key
693 pub batch_cert: Vec<u8>,
694 /// A full certificate chain from root signing authority to private_key, including batch_cert
695 /// for convenience.
696 pub cert_chain: Vec<u8>,
Max Bires2b2e6562020-09-22 11:22:36 -0700697}
698
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700699/// This type represents a Keystore 2.0 key entry.
700/// An entry has a unique `id` by which it can be found in the database.
701/// It has a security level field, key parameters, and three optional fields
702/// for the KeyMint blob, public certificate and a public certificate chain.
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800703#[derive(Debug, Default, Eq, PartialEq)]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700704pub struct KeyEntry {
705 id: i64,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800706 key_blob_info: Option<(Vec<u8>, BlobMetaData)>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700707 cert: Option<Vec<u8>>,
708 cert_chain: Option<Vec<u8>>,
Max Bires8e93d2b2021-01-14 13:17:59 -0800709 km_uuid: Uuid,
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700710 parameters: Vec<KeyParameter>,
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800711 metadata: KeyMetaData,
Janis Danisevskis377d1002021-01-27 19:07:48 -0800712 pure_cert: bool,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700713}
714
715impl KeyEntry {
716 /// Returns the unique id of the Key entry.
717 pub fn id(&self) -> i64 {
718 self.id
719 }
720 /// Exposes the optional KeyMint blob.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800721 pub fn key_blob_info(&self) -> &Option<(Vec<u8>, BlobMetaData)> {
722 &self.key_blob_info
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700723 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800724 /// Extracts the Optional KeyMint blob including its metadata.
725 pub fn take_key_blob_info(&mut self) -> Option<(Vec<u8>, BlobMetaData)> {
726 self.key_blob_info.take()
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700727 }
728 /// Exposes the optional public certificate.
729 pub fn cert(&self) -> &Option<Vec<u8>> {
730 &self.cert
731 }
732 /// Extracts the optional public certificate.
733 pub fn take_cert(&mut self) -> Option<Vec<u8>> {
734 self.cert.take()
735 }
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700736 /// Extracts the optional public certificate_chain.
737 pub fn take_cert_chain(&mut self) -> Option<Vec<u8>> {
738 self.cert_chain.take()
739 }
Max Bires8e93d2b2021-01-14 13:17:59 -0800740 /// Returns the uuid of the owning KeyMint instance.
741 pub fn km_uuid(&self) -> &Uuid {
742 &self.km_uuid
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700743 }
Janis Danisevskis04b02832020-10-26 09:21:40 -0700744 /// Consumes this key entry and extracts the keyparameters from it.
745 pub fn into_key_parameters(self) -> Vec<KeyParameter> {
746 self.parameters
747 }
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800748 /// Exposes the key metadata of this key entry.
749 pub fn metadata(&self) -> &KeyMetaData {
750 &self.metadata
751 }
Janis Danisevskis377d1002021-01-27 19:07:48 -0800752 /// This returns true if the entry is a pure certificate entry with no
753 /// private key component.
754 pub fn pure_cert(&self) -> bool {
755 self.pure_cert
756 }
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700757}
758
759/// Indicates the sub component of a key entry for persistent storage.
Janis Danisevskis377d1002021-01-27 19:07:48 -0800760#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700761pub struct SubComponentType(u32);
762impl SubComponentType {
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800763 /// Persistent identifier for a key blob.
764 pub const KEY_BLOB: SubComponentType = Self(0);
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700765 /// Persistent identifier for a certificate blob.
766 pub const CERT: SubComponentType = Self(1);
767 /// Persistent identifier for a certificate chain blob.
768 pub const CERT_CHAIN: SubComponentType = Self(2);
769}
770
771impl ToSql for SubComponentType {
772 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
773 self.0.to_sql()
774 }
775}
776
777impl FromSql for SubComponentType {
778 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
779 Ok(Self(u32::column_result(value)?))
780 }
781}
782
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800783/// This trait is private to the database module. It is used to convey whether or not the garbage
784/// collector shall be invoked after a database access. All closures passed to
785/// `KeystoreDB::with_transaction` return a tuple (bool, T) where the bool indicates if the
786/// gc needs to be triggered. This convenience function allows to turn any anyhow::Result<T>
787/// into anyhow::Result<(bool, T)> by simply appending one of `.do_gc(bool)`, `.no_gc()`, or
788/// `.need_gc()`.
789trait DoGc<T> {
790 fn do_gc(self, need_gc: bool) -> Result<(bool, T)>;
791
792 fn no_gc(self) -> Result<(bool, T)>;
793
794 fn need_gc(self) -> Result<(bool, T)>;
795}
796
797impl<T> DoGc<T> for Result<T> {
798 fn do_gc(self, need_gc: bool) -> Result<(bool, T)> {
799 self.map(|r| (need_gc, r))
800 }
801
802 fn no_gc(self) -> Result<(bool, T)> {
803 self.do_gc(false)
804 }
805
806 fn need_gc(self) -> Result<(bool, T)> {
807 self.do_gc(true)
808 }
809}
810
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700811/// KeystoreDB wraps a connection to an SQLite database and tracks its
812/// ownership. It also implements all of Keystore 2.0's database functionality.
Joel Galenson26f4d012020-07-17 14:57:21 -0700813pub struct KeystoreDB {
Joel Galenson26f4d012020-07-17 14:57:21 -0700814 conn: Connection,
Janis Danisevskis3395f862021-05-06 10:54:17 -0700815 gc: Option<Arc<Gc>>,
Matthew Maurerd7815ca2021-05-06 21:58:45 -0700816 perboot: Arc<perboot::PerbootDB>,
Joel Galenson26f4d012020-07-17 14:57:21 -0700817}
818
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000819/// Database representation of the monotonic time retrieved from the system call clock_gettime with
Eric Biggers19b3b0d2024-01-31 22:46:47 +0000820/// CLOCK_BOOTTIME. Stores monotonic time as i64 in milliseconds.
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000821#[derive(Debug, Copy, Clone, Default, Eq, PartialEq, Ord, PartialOrd)]
Eric Biggers19b3b0d2024-01-31 22:46:47 +0000822pub struct BootTime(i64);
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000823
Eric Biggers19b3b0d2024-01-31 22:46:47 +0000824impl BootTime {
825 /// Constructs a new BootTime
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000826 pub fn now() -> Self {
Hasini Gunasinghe66a24602021-05-12 19:03:12 +0000827 Self(get_current_time_in_milliseconds())
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000828 }
829
Eric Biggers19b3b0d2024-01-31 22:46:47 +0000830 /// Returns the value of BootTime in milliseconds as i64
Hasini Gunasinghe66a24602021-05-12 19:03:12 +0000831 pub fn milliseconds(&self) -> i64 {
832 self.0
David Drysdale0e45a612021-02-25 17:24:36 +0000833 }
834
Eric Biggers19b3b0d2024-01-31 22:46:47 +0000835 /// Returns the integer value of BootTime as i64
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000836 pub fn seconds(&self) -> i64 {
Hasini Gunasinghe66a24602021-05-12 19:03:12 +0000837 self.0 / 1000
Hasini Gunasingheb3715fb2021-02-26 20:34:45 +0000838 }
839
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800840 /// Like i64::checked_sub.
841 pub fn checked_sub(&self, other: &Self) -> Option<Self> {
842 self.0.checked_sub(other.0).map(Self)
843 }
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000844}
845
Eric Biggers19b3b0d2024-01-31 22:46:47 +0000846impl ToSql for BootTime {
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000847 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
848 Ok(ToSqlOutput::Owned(Value::Integer(self.0)))
849 }
850}
851
Eric Biggers19b3b0d2024-01-31 22:46:47 +0000852impl FromSql for BootTime {
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000853 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
854 Ok(Self(i64::column_result(value)?))
855 }
856}
857
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000858/// This struct encapsulates the information to be stored in the database about the auth tokens
859/// received by keystore.
Matthew Maurerd7815ca2021-05-06 21:58:45 -0700860#[derive(Clone)]
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000861pub struct AuthTokenEntry {
862 auth_token: HardwareAuthToken,
Hasini Gunasinghe66a24602021-05-12 19:03:12 +0000863 // Time received in milliseconds
Eric Biggers19b3b0d2024-01-31 22:46:47 +0000864 time_received: BootTime,
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000865}
866
867impl AuthTokenEntry {
Eric Biggers19b3b0d2024-01-31 22:46:47 +0000868 fn new(auth_token: HardwareAuthToken, time_received: BootTime) -> Self {
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000869 AuthTokenEntry { auth_token, time_received }
870 }
871
872 /// Checks if this auth token satisfies the given authentication information.
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800873 pub fn satisfies(&self, user_secure_ids: &[i64], auth_type: HardwareAuthenticatorType) -> bool {
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000874 user_secure_ids.iter().any(|&sid| {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800875 (sid == self.auth_token.userId || sid == self.auth_token.authenticatorId)
Charisee03e00842023-01-25 01:41:23 +0000876 && ((auth_type.0 & self.auth_token.authenticatorType.0) != 0)
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000877 })
878 }
879
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000880 /// Returns the auth token wrapped by the AuthTokenEntry
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800881 pub fn auth_token(&self) -> &HardwareAuthToken {
882 &self.auth_token
883 }
884
885 /// Returns the auth token wrapped by the AuthTokenEntry
886 pub fn take_auth_token(self) -> HardwareAuthToken {
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000887 self.auth_token
888 }
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800889
890 /// Returns the time that this auth token was received.
Eric Biggers19b3b0d2024-01-31 22:46:47 +0000891 pub fn time_received(&self) -> BootTime {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800892 self.time_received
893 }
Hasini Gunasingheb3715fb2021-02-26 20:34:45 +0000894
895 /// Returns the challenge value of the auth token.
896 pub fn challenge(&self) -> i64 {
897 self.auth_token.challenge
898 }
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000899}
900
David Drysdalef1ba3812024-05-08 17:50:13 +0100901/// Information about a superseded blob (a blob that is no longer the
902/// most recent blob of that type for a given key, due to upgrade or
903/// replacement).
904pub struct SupersededBlob {
905 /// ID
906 pub blob_id: i64,
907 /// Contents.
908 pub blob: Vec<u8>,
909 /// Metadata.
910 pub metadata: BlobMetaData,
911}
912
Joel Galenson26f4d012020-07-17 14:57:21 -0700913impl KeystoreDB {
Janis Danisevskiseed69842021-02-18 20:04:10 -0800914 const UNASSIGNED_KEY_ID: i64 = -1i64;
David Drysdale8da288c2024-07-29 15:57:01 +0100915 const CURRENT_DB_VERSION: u32 = 2;
916 const UPGRADERS: &'static [fn(&Transaction) -> Result<u32>] =
917 &[Self::from_0_to_1, Self::from_1_to_2];
Janis Danisevskisb00ebd02021-02-02 21:52:24 -0800918
Seth Moore78c091f2021-04-09 21:38:30 +0000919 /// Name of the file that holds the cross-boot persistent database.
Chris Wailesd5aaaef2021-07-27 16:04:33 -0700920 pub const PERSISTENT_DB_FILENAME: &'static str = "persistent.sqlite";
Seth Moore78c091f2021-04-09 21:38:30 +0000921
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700922 /// This will create a new database connection connecting the two
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800923 /// files persistent.sqlite and perboot.sqlite in the given directory.
924 /// It also attempts to initialize all of the tables.
925 /// KeystoreDB cannot be used by multiple threads.
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700926 /// Each thread should open their own connection using `thread_local!`.
Janis Danisevskis3395f862021-05-06 10:54:17 -0700927 pub fn new(db_root: &Path, gc: Option<Arc<Gc>>) -> Result<Self> {
David Drysdale541846b2024-05-23 13:16:07 +0100928 let _wp = wd::watch("KeystoreDB::new");
Janis Danisevskis850d4862021-05-05 08:41:14 -0700929
Chris Wailesd5aaaef2021-07-27 16:04:33 -0700930 let persistent_path = Self::make_persistent_path(db_root)?;
Seth Moore472fcbb2021-05-12 10:07:51 -0700931 let conn = Self::make_connection(&persistent_path)?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800932
Matthew Maurerd7815ca2021-05-06 21:58:45 -0700933 let mut db = Self { conn, gc, perboot: perboot::PERBOOT_DB.clone() };
David Drysdale7b9ca232024-05-23 18:19:46 +0100934 db.with_transaction(Immediate("TX_new"), |tx| {
Janis Danisevskiscfaf9192021-05-26 16:31:02 -0700935 versioning::upgrade_database(tx, Self::CURRENT_DB_VERSION, Self::UPGRADERS)
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000936 .context(ks_err!("KeystoreDB::new: trying to upgrade database."))?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800937 Self::init_tables(tx).context("Trying to initialize tables.").no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -0800938 })?;
939 Ok(db)
Joel Galenson2aab4432020-07-22 15:27:57 -0700940 }
941
Janis Danisevskiscfaf9192021-05-26 16:31:02 -0700942 // This upgrade function deletes all MAX_BOOT_LEVEL keys, that were generated before
943 // cryptographic binding to the boot level keys was implemented.
944 fn from_0_to_1(tx: &Transaction) -> Result<u32> {
945 tx.execute(
946 "UPDATE persistent.keyentry SET state = ?
947 WHERE
948 id IN (SELECT keyentryid FROM persistent.keyparameter WHERE tag = ?)
949 AND
950 id NOT IN (
951 SELECT keyentryid FROM persistent.blobentry
952 WHERE id IN (
953 SELECT blobentryid FROM persistent.blobmetadata WHERE tag = ?
954 )
955 );",
956 params![KeyLifeCycle::Unreferenced, Tag::MAX_BOOT_LEVEL.0, BlobMetaData::MaxBootLevel],
957 )
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000958 .context(ks_err!("Failed to delete logical boot level keys."))?;
David Drysdale8da288c2024-07-29 15:57:01 +0100959
960 // DB version is now 1.
Janis Danisevskiscfaf9192021-05-26 16:31:02 -0700961 Ok(1)
962 }
963
David Drysdale8da288c2024-07-29 15:57:01 +0100964 // This upgrade function adds an additional `state INTEGER` column to the blobentry
965 // table, and populates it based on whether each blob is the most recent of its type for
966 // the corresponding key.
967 fn from_1_to_2(tx: &Transaction) -> Result<u32> {
968 tx.execute(
969 "ALTER TABLE persistent.blobentry ADD COLUMN state INTEGER DEFAULT 0;",
970 params![],
971 )
972 .context(ks_err!("Failed to add state column"))?;
973
974 // Mark keyblobs that are not the most recent for their corresponding key.
975 // This may take a while if there are excessive numbers of keys in the database.
976 let _wp = wd::watch("KeystoreDB::from_1_to_2 mark all non-current keyblobs");
977 let sc_key_blob = SubComponentType::KEY_BLOB;
978 let mut stmt = tx
979 .prepare(
980 "UPDATE persistent.blobentry SET state=?
981 WHERE subcomponent_type = ?
982 AND id NOT IN (
983 SELECT MAX(id) FROM persistent.blobentry
984 WHERE subcomponent_type = ?
985 GROUP BY keyentryid, subcomponent_type
986 );",
987 )
988 .context("Trying to prepare query to mark superseded keyblobs")?;
989 stmt.execute(params![BlobState::Superseded, sc_key_blob, sc_key_blob])
990 .context(ks_err!("Failed to set state=superseded state for keyblobs"))?;
991 log::info!("marked non-current blobentry rows for keyblobs as superseded");
992
993 // Mark keyblobs that don't have a corresponding key.
994 // This may take a while if there are excessive numbers of keys in the database.
995 let _wp = wd::watch("KeystoreDB::from_1_to_2 mark all orphaned keyblobs");
996 let mut stmt = tx
997 .prepare(
998 "UPDATE persistent.blobentry SET state=?
999 WHERE subcomponent_type = ?
1000 AND NOT EXISTS (SELECT id FROM persistent.keyentry
1001 WHERE id = keyentryid);",
1002 )
1003 .context("Trying to prepare query to mark orphaned keyblobs")?;
1004 stmt.execute(params![BlobState::Orphaned, sc_key_blob])
1005 .context(ks_err!("Failed to set state=orphaned for keyblobs"))?;
1006 log::info!("marked orphaned blobentry rows for keyblobs");
1007
1008 // Add an index to make it fast to find out of date blobentry rows.
1009 let _wp = wd::watch("KeystoreDB::from_1_to_2 add blobentry index");
1010 tx.execute(
1011 "CREATE INDEX IF NOT EXISTS persistent.blobentry_state_index
1012 ON blobentry(subcomponent_type, state);",
1013 [],
1014 )
1015 .context("Failed to create index blobentry_state_index.")?;
1016
1017 // Add an index to make it fast to find unreferenced keyentry rows.
1018 let _wp = wd::watch("KeystoreDB::from_1_to_2 add keyentry state index");
1019 tx.execute(
1020 "CREATE INDEX IF NOT EXISTS persistent.keyentry_state_index
1021 ON keyentry(state);",
1022 [],
1023 )
1024 .context("Failed to create index keyentry_state_index.")?;
1025
1026 // DB version is now 2.
1027 Ok(2)
1028 }
1029
Janis Danisevskis66784c42021-01-27 08:40:25 -08001030 fn init_tables(tx: &Transaction) -> Result<()> {
1031 tx.execute(
Janis Danisevskis4df44f42020-08-26 14:40:03 -07001032 "CREATE TABLE IF NOT EXISTS persistent.keyentry (
Joel Galenson0891bc12020-07-20 10:37:03 -07001033 id INTEGER UNIQUE,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001034 key_type INTEGER,
Joel Galenson0891bc12020-07-20 10:37:03 -07001035 domain INTEGER,
1036 namespace INTEGER,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001037 alias BLOB,
Max Bires8e93d2b2021-01-14 13:17:59 -08001038 state INTEGER,
1039 km_uuid BLOB);",
Andrew Walbran78abb1e2023-05-30 16:20:56 +00001040 [],
Janis Danisevskis4df44f42020-08-26 14:40:03 -07001041 )
1042 .context("Failed to initialize \"keyentry\" table.")?;
1043
Janis Danisevskis66784c42021-01-27 08:40:25 -08001044 tx.execute(
Janis Danisevskisa5438182021-02-02 14:22:59 -08001045 "CREATE INDEX IF NOT EXISTS persistent.keyentry_id_index
1046 ON keyentry(id);",
Andrew Walbran78abb1e2023-05-30 16:20:56 +00001047 [],
Janis Danisevskisa5438182021-02-02 14:22:59 -08001048 )
1049 .context("Failed to create index keyentry_id_index.")?;
1050
1051 tx.execute(
1052 "CREATE INDEX IF NOT EXISTS persistent.keyentry_domain_namespace_index
1053 ON keyentry(domain, namespace, alias);",
Andrew Walbran78abb1e2023-05-30 16:20:56 +00001054 [],
Janis Danisevskisa5438182021-02-02 14:22:59 -08001055 )
1056 .context("Failed to create index keyentry_domain_namespace_index.")?;
1057
David Drysdale8da288c2024-07-29 15:57:01 +01001058 // Index added in v2 of database schema.
1059 tx.execute(
1060 "CREATE INDEX IF NOT EXISTS persistent.keyentry_state_index
1061 ON keyentry(state);",
1062 [],
1063 )
1064 .context("Failed to create index keyentry_state_index.")?;
1065
Janis Danisevskisa5438182021-02-02 14:22:59 -08001066 tx.execute(
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001067 "CREATE TABLE IF NOT EXISTS persistent.blobentry (
1068 id INTEGER PRIMARY KEY,
1069 subcomponent_type INTEGER,
1070 keyentryid INTEGER,
David Drysdale8da288c2024-07-29 15:57:01 +01001071 blob BLOB,
1072 state INTEGER DEFAULT 0);", // `state` added in v2 of schema
Andrew Walbran78abb1e2023-05-30 16:20:56 +00001073 [],
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001074 )
1075 .context("Failed to initialize \"blobentry\" table.")?;
1076
Janis Danisevskis66784c42021-01-27 08:40:25 -08001077 tx.execute(
Janis Danisevskisa5438182021-02-02 14:22:59 -08001078 "CREATE INDEX IF NOT EXISTS persistent.blobentry_keyentryid_index
1079 ON blobentry(keyentryid);",
Andrew Walbran78abb1e2023-05-30 16:20:56 +00001080 [],
Janis Danisevskisa5438182021-02-02 14:22:59 -08001081 )
1082 .context("Failed to create index blobentry_keyentryid_index.")?;
1083
David Drysdale8da288c2024-07-29 15:57:01 +01001084 // Index added in v2 of database schema.
1085 tx.execute(
1086 "CREATE INDEX IF NOT EXISTS persistent.blobentry_state_index
1087 ON blobentry(subcomponent_type, state);",
1088 [],
1089 )
1090 .context("Failed to create index blobentry_state_index.")?;
1091
Janis Danisevskisa5438182021-02-02 14:22:59 -08001092 tx.execute(
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001093 "CREATE TABLE IF NOT EXISTS persistent.blobmetadata (
1094 id INTEGER PRIMARY KEY,
1095 blobentryid INTEGER,
1096 tag INTEGER,
1097 data ANY,
1098 UNIQUE (blobentryid, tag));",
Andrew Walbran78abb1e2023-05-30 16:20:56 +00001099 [],
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001100 )
1101 .context("Failed to initialize \"blobmetadata\" table.")?;
1102
1103 tx.execute(
1104 "CREATE INDEX IF NOT EXISTS persistent.blobmetadata_blobentryid_index
1105 ON blobmetadata(blobentryid);",
Andrew Walbran78abb1e2023-05-30 16:20:56 +00001106 [],
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001107 )
1108 .context("Failed to create index blobmetadata_blobentryid_index.")?;
1109
1110 tx.execute(
Janis Danisevskis4df44f42020-08-26 14:40:03 -07001111 "CREATE TABLE IF NOT EXISTS persistent.keyparameter (
Hasini Gunasingheaf993662020-07-24 18:40:20 +00001112 keyentryid INTEGER,
1113 tag INTEGER,
1114 data ANY,
1115 security_level INTEGER);",
Andrew Walbran78abb1e2023-05-30 16:20:56 +00001116 [],
Janis Danisevskis4df44f42020-08-26 14:40:03 -07001117 )
1118 .context("Failed to initialize \"keyparameter\" table.")?;
1119
Janis Danisevskis66784c42021-01-27 08:40:25 -08001120 tx.execute(
Janis Danisevskisa5438182021-02-02 14:22:59 -08001121 "CREATE INDEX IF NOT EXISTS persistent.keyparameter_keyentryid_index
1122 ON keyparameter(keyentryid);",
Andrew Walbran78abb1e2023-05-30 16:20:56 +00001123 [],
Janis Danisevskisa5438182021-02-02 14:22:59 -08001124 )
1125 .context("Failed to create index keyparameter_keyentryid_index.")?;
1126
1127 tx.execute(
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001128 "CREATE TABLE IF NOT EXISTS persistent.keymetadata (
1129 keyentryid INTEGER,
1130 tag INTEGER,
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00001131 data ANY,
1132 UNIQUE (keyentryid, tag));",
Andrew Walbran78abb1e2023-05-30 16:20:56 +00001133 [],
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001134 )
1135 .context("Failed to initialize \"keymetadata\" table.")?;
1136
Janis Danisevskis66784c42021-01-27 08:40:25 -08001137 tx.execute(
Janis Danisevskisa5438182021-02-02 14:22:59 -08001138 "CREATE INDEX IF NOT EXISTS persistent.keymetadata_keyentryid_index
1139 ON keymetadata(keyentryid);",
Andrew Walbran78abb1e2023-05-30 16:20:56 +00001140 [],
Janis Danisevskisa5438182021-02-02 14:22:59 -08001141 )
1142 .context("Failed to create index keymetadata_keyentryid_index.")?;
1143
1144 tx.execute(
Janis Danisevskisbf15d732020-12-08 10:35:26 -08001145 "CREATE TABLE IF NOT EXISTS persistent.grant (
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001146 id INTEGER UNIQUE,
1147 grantee INTEGER,
1148 keyentryid INTEGER,
1149 access_vector INTEGER);",
Andrew Walbran78abb1e2023-05-30 16:20:56 +00001150 [],
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001151 )
1152 .context("Failed to initialize \"grant\" table.")?;
1153
Joel Galenson0891bc12020-07-20 10:37:03 -07001154 Ok(())
1155 }
1156
Seth Moore472fcbb2021-05-12 10:07:51 -07001157 fn make_persistent_path(db_root: &Path) -> Result<String> {
1158 // Build the path to the sqlite file.
1159 let mut persistent_path = db_root.to_path_buf();
1160 persistent_path.push(Self::PERSISTENT_DB_FILENAME);
1161
1162 // Now convert them to strings prefixed with "file:"
1163 let mut persistent_path_str = "file:".to_owned();
1164 persistent_path_str.push_str(&persistent_path.to_string_lossy());
1165
Shaquille Johnson52b8c932023-12-19 19:45:32 +00001166 // Connect to database in specific mode
1167 let persistent_path_mode = if keystore2_flags::wal_db_journalmode_v3() {
1168 "?journal_mode=WAL".to_owned()
1169 } else {
1170 "?journal_mode=DELETE".to_owned()
1171 };
1172 persistent_path_str.push_str(&persistent_path_mode);
1173
Seth Moore472fcbb2021-05-12 10:07:51 -07001174 Ok(persistent_path_str)
1175 }
1176
Matthew Maurerd7815ca2021-05-06 21:58:45 -07001177 fn make_connection(persistent_file: &str) -> Result<Connection> {
Janis Danisevskis4df44f42020-08-26 14:40:03 -07001178 let conn =
1179 Connection::open_in_memory().context("Failed to initialize SQLite connection.")?;
1180
Janis Danisevskis66784c42021-01-27 08:40:25 -08001181 loop {
1182 if let Err(e) = conn
1183 .execute("ATTACH DATABASE ? as persistent;", params![persistent_file])
1184 .context("Failed to attach database persistent.")
1185 {
1186 if Self::is_locked_error(&e) {
David Drysdale115c4722024-04-15 14:11:52 +01001187 std::thread::sleep(DB_BUSY_RETRY_INTERVAL);
Janis Danisevskis66784c42021-01-27 08:40:25 -08001188 continue;
1189 } else {
1190 return Err(e);
1191 }
1192 }
1193 break;
1194 }
Janis Danisevskis4df44f42020-08-26 14:40:03 -07001195
Matthew Maurer4fb19112021-05-06 15:40:44 -07001196 // Drop the cache size from default (2M) to 0.5M
1197 conn.execute("PRAGMA persistent.cache_size = -500;", params![])
1198 .context("Failed to decrease cache size for persistent db")?;
Matthew Maurer4fb19112021-05-06 15:40:44 -07001199
Janis Danisevskis4df44f42020-08-26 14:40:03 -07001200 Ok(conn)
1201 }
1202
Seth Moore78c091f2021-04-09 21:38:30 +00001203 fn do_table_size_query(
1204 &mut self,
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001205 storage_type: MetricsStorage,
Seth Moore78c091f2021-04-09 21:38:30 +00001206 query: &str,
1207 params: &[&str],
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001208 ) -> Result<StorageStats> {
Seth Moore78c091f2021-04-09 21:38:30 +00001209 let (total, unused) = self.with_transaction(TransactionBehavior::Deferred, |tx| {
Joel Galensonff79e362021-05-25 16:30:17 -07001210 tx.query_row(query, params_from_iter(params), |row| Ok((row.get(0)?, row.get(1)?)))
Seth Moore78c091f2021-04-09 21:38:30 +00001211 .with_context(|| {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001212 ks_err!("get_storage_stat: Error size of storage type {}", storage_type.0)
Seth Moore78c091f2021-04-09 21:38:30 +00001213 })
1214 .no_gc()
1215 })?;
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001216 Ok(StorageStats { storage_type, size: total, unused_size: unused })
Seth Moore78c091f2021-04-09 21:38:30 +00001217 }
1218
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001219 fn get_total_size(&mut self) -> Result<StorageStats> {
Seth Moore78c091f2021-04-09 21:38:30 +00001220 self.do_table_size_query(
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001221 MetricsStorage::DATABASE,
Seth Moore78c091f2021-04-09 21:38:30 +00001222 "SELECT page_count * page_size, freelist_count * page_size
1223 FROM pragma_page_count('persistent'),
1224 pragma_page_size('persistent'),
1225 persistent.pragma_freelist_count();",
1226 &[],
1227 )
1228 }
1229
1230 fn get_table_size(
1231 &mut self,
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001232 storage_type: MetricsStorage,
Seth Moore78c091f2021-04-09 21:38:30 +00001233 schema: &str,
1234 table: &str,
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001235 ) -> Result<StorageStats> {
Seth Moore78c091f2021-04-09 21:38:30 +00001236 self.do_table_size_query(
1237 storage_type,
1238 "SELECT pgsize,unused FROM dbstat(?1)
1239 WHERE name=?2 AND aggregate=TRUE;",
1240 &[schema, table],
1241 )
1242 }
1243
David Drysdale0fefae32024-09-16 13:32:27 +01001244 /// Fetches a storage statistics atom for a given storage type. For storage
Seth Moore78c091f2021-04-09 21:38:30 +00001245 /// types that map to a table, information about the table's storage is
1246 /// returned. Requests for storage types that are not DB tables return None.
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001247 pub fn get_storage_stat(&mut self, storage_type: MetricsStorage) -> Result<StorageStats> {
David Drysdale703bcc12024-11-26 14:15:03 +00001248 let _wp = wd::watch_millis_with("KeystoreDB::get_storage_stat", 500, storage_type);
Janis Danisevskis850d4862021-05-05 08:41:14 -07001249
Seth Moore78c091f2021-04-09 21:38:30 +00001250 match storage_type {
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001251 MetricsStorage::DATABASE => self.get_total_size(),
1252 MetricsStorage::KEY_ENTRY => {
Seth Moore78c091f2021-04-09 21:38:30 +00001253 self.get_table_size(storage_type, "persistent", "keyentry")
1254 }
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001255 MetricsStorage::KEY_ENTRY_ID_INDEX => {
Seth Moore78c091f2021-04-09 21:38:30 +00001256 self.get_table_size(storage_type, "persistent", "keyentry_id_index")
1257 }
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001258 MetricsStorage::KEY_ENTRY_DOMAIN_NAMESPACE_INDEX => {
Seth Moore78c091f2021-04-09 21:38:30 +00001259 self.get_table_size(storage_type, "persistent", "keyentry_domain_namespace_index")
1260 }
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001261 MetricsStorage::BLOB_ENTRY => {
Seth Moore78c091f2021-04-09 21:38:30 +00001262 self.get_table_size(storage_type, "persistent", "blobentry")
1263 }
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001264 MetricsStorage::BLOB_ENTRY_KEY_ENTRY_ID_INDEX => {
Seth Moore78c091f2021-04-09 21:38:30 +00001265 self.get_table_size(storage_type, "persistent", "blobentry_keyentryid_index")
1266 }
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001267 MetricsStorage::KEY_PARAMETER => {
Seth Moore78c091f2021-04-09 21:38:30 +00001268 self.get_table_size(storage_type, "persistent", "keyparameter")
1269 }
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001270 MetricsStorage::KEY_PARAMETER_KEY_ENTRY_ID_INDEX => {
Seth Moore78c091f2021-04-09 21:38:30 +00001271 self.get_table_size(storage_type, "persistent", "keyparameter_keyentryid_index")
1272 }
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001273 MetricsStorage::KEY_METADATA => {
Seth Moore78c091f2021-04-09 21:38:30 +00001274 self.get_table_size(storage_type, "persistent", "keymetadata")
1275 }
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001276 MetricsStorage::KEY_METADATA_KEY_ENTRY_ID_INDEX => {
Seth Moore78c091f2021-04-09 21:38:30 +00001277 self.get_table_size(storage_type, "persistent", "keymetadata_keyentryid_index")
1278 }
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001279 MetricsStorage::GRANT => self.get_table_size(storage_type, "persistent", "grant"),
1280 MetricsStorage::AUTH_TOKEN => {
Matthew Maurerd7815ca2021-05-06 21:58:45 -07001281 // Since the table is actually a BTreeMap now, unused_size is not meaningfully
1282 // reportable
1283 // Size provided is only an approximation
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001284 Ok(StorageStats {
Matthew Maurerd7815ca2021-05-06 21:58:45 -07001285 storage_type,
1286 size: (self.perboot.auth_tokens_len() * std::mem::size_of::<AuthTokenEntry>())
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001287 as i32,
Matthew Maurerd7815ca2021-05-06 21:58:45 -07001288 unused_size: 0,
1289 })
Seth Moore78c091f2021-04-09 21:38:30 +00001290 }
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001291 MetricsStorage::BLOB_METADATA => {
Seth Moore78c091f2021-04-09 21:38:30 +00001292 self.get_table_size(storage_type, "persistent", "blobmetadata")
1293 }
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001294 MetricsStorage::BLOB_METADATA_BLOB_ENTRY_ID_INDEX => {
Seth Moore78c091f2021-04-09 21:38:30 +00001295 self.get_table_size(storage_type, "persistent", "blobmetadata_blobentryid_index")
1296 }
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001297 _ => Err(anyhow::Error::msg(format!("Unsupported storage type: {}", storage_type.0))),
Seth Moore78c091f2021-04-09 21:38:30 +00001298 }
1299 }
1300
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001301 /// This function is intended to be used by the garbage collector.
Janis Danisevskis3395f862021-05-06 10:54:17 -07001302 /// It deletes the blobs given by `blob_ids_to_delete`. It then tries to find up to `max_blobs`
1303 /// superseded key blobs that might need special handling by the garbage collector.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001304 /// If no further superseded blobs can be found it deletes all other superseded blobs that don't
1305 /// need special handling and returns None.
Janis Danisevskis3395f862021-05-06 10:54:17 -07001306 pub fn handle_next_superseded_blobs(
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001307 &mut self,
Janis Danisevskis3395f862021-05-06 10:54:17 -07001308 blob_ids_to_delete: &[i64],
1309 max_blobs: usize,
David Drysdalef1ba3812024-05-08 17:50:13 +01001310 ) -> Result<Vec<SupersededBlob>> {
David Drysdale541846b2024-05-23 13:16:07 +01001311 let _wp = wd::watch("KeystoreDB::handle_next_superseded_blob");
David Drysdale7b9ca232024-05-23 18:19:46 +01001312 self.with_transaction(Immediate("TX_handle_next_superseded_blob"), |tx| {
Janis Danisevskis3395f862021-05-06 10:54:17 -07001313 // Delete the given blobs.
1314 for blob_id in blob_ids_to_delete {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001315 tx.execute(
1316 "DELETE FROM persistent.blobmetadata WHERE blobentryid = ?;",
Janis Danisevskis3395f862021-05-06 10:54:17 -07001317 params![blob_id],
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001318 )
Shaquille Johnsonf23fc942024-02-13 17:01:29 +00001319 .context(ks_err!("Trying to delete blob metadata: {:?}", blob_id))?;
Janis Danisevskis3395f862021-05-06 10:54:17 -07001320 tx.execute("DELETE FROM persistent.blobentry WHERE id = ?;", params![blob_id])
Shaquille Johnsonf23fc942024-02-13 17:01:29 +00001321 .context(ks_err!("Trying to delete blob: {:?}", blob_id))?;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001322 }
Janis Danisevskis3cba10d2021-05-06 17:02:19 -07001323
1324 Self::cleanup_unreferenced(tx).context("Trying to cleanup unreferenced.")?;
1325
David Drysdale8da288c2024-07-29 15:57:01 +01001326 // Find up to `max_blobs` more out-of-date key blobs, load their metadata and return it.
1327 let result: Vec<(i64, Vec<u8>)> = if keystore2_flags::use_blob_state_column() {
1328 let _wp = wd::watch("KeystoreDB::handle_next_superseded_blob find_next v2");
1329 let mut stmt = tx
1330 .prepare(
1331 "SELECT id, blob FROM persistent.blobentry
1332 WHERE subcomponent_type = ? AND state != ?
1333 LIMIT ?;",
1334 )
1335 .context("Trying to prepare query for superseded blobs.")?;
1336
1337 let rows = stmt
1338 .query_map(
1339 params![SubComponentType::KEY_BLOB, BlobState::Current, max_blobs as i64],
1340 |row| Ok((row.get(0)?, row.get(1)?)),
1341 )
1342 .context("Trying to query superseded blob.")?;
1343
1344 rows.collect::<Result<Vec<(i64, Vec<u8>)>, rusqlite::Error>>()
1345 .context("Trying to extract superseded blobs.")?
1346 } else {
1347 let _wp = wd::watch("KeystoreDB::handle_next_superseded_blob find_next v1");
Janis Danisevskis3395f862021-05-06 10:54:17 -07001348 let mut stmt = tx
1349 .prepare(
1350 "SELECT id, blob FROM persistent.blobentry
1351 WHERE subcomponent_type = ?
1352 AND (
1353 id NOT IN (
1354 SELECT MAX(id) FROM persistent.blobentry
1355 WHERE subcomponent_type = ?
1356 GROUP BY keyentryid, subcomponent_type
1357 )
1358 OR keyentryid NOT IN (SELECT id FROM persistent.keyentry)
1359 ) LIMIT ?;",
1360 )
1361 .context("Trying to prepare query for superseded blobs.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001362
Janis Danisevskis3395f862021-05-06 10:54:17 -07001363 let rows = stmt
1364 .query_map(
1365 params![
1366 SubComponentType::KEY_BLOB,
1367 SubComponentType::KEY_BLOB,
1368 max_blobs as i64,
1369 ],
1370 |row| Ok((row.get(0)?, row.get(1)?)),
1371 )
1372 .context("Trying to query superseded blob.")?;
1373
1374 rows.collect::<Result<Vec<(i64, Vec<u8>)>, rusqlite::Error>>()
1375 .context("Trying to extract superseded blobs.")?
1376 };
1377
David Drysdalec652f6c2024-07-18 13:01:23 +01001378 let _wp = wd::watch("KeystoreDB::handle_next_superseded_blob load_metadata");
Janis Danisevskis3395f862021-05-06 10:54:17 -07001379 let result = result
1380 .into_iter()
1381 .map(|(blob_id, blob)| {
David Drysdalef1ba3812024-05-08 17:50:13 +01001382 Ok(SupersededBlob {
1383 blob_id,
1384 blob,
1385 metadata: BlobMetaData::load_from_db(blob_id, tx)?,
1386 })
Janis Danisevskis3395f862021-05-06 10:54:17 -07001387 })
David Drysdalef1ba3812024-05-08 17:50:13 +01001388 .collect::<Result<Vec<_>>>()
Janis Danisevskis3395f862021-05-06 10:54:17 -07001389 .context("Trying to load blob metadata.")?;
1390 if !result.is_empty() {
1391 return Ok(result).no_gc();
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001392 }
1393
David Drysdale8da288c2024-07-29 15:57:01 +01001394 // We did not find any out-of-date key blobs, so let's remove other types of superseded
1395 // blob in one transaction.
1396 if keystore2_flags::use_blob_state_column() {
1397 let _wp = wd::watch("KeystoreDB::handle_next_superseded_blob delete v2");
1398 tx.execute(
1399 "DELETE FROM persistent.blobentry
1400 WHERE subcomponent_type != ? AND state != ?;",
1401 params![SubComponentType::KEY_BLOB, BlobState::Current],
1402 )
1403 .context("Trying to purge out-of-date blobs (other than keyblobs)")?;
1404 } else {
1405 let _wp = wd::watch("KeystoreDB::handle_next_superseded_blob delete v1");
1406 tx.execute(
1407 "DELETE FROM persistent.blobentry
1408 WHERE NOT subcomponent_type = ?
1409 AND (
1410 id NOT IN (
1411 SELECT MAX(id) FROM persistent.blobentry
1412 WHERE NOT subcomponent_type = ?
1413 GROUP BY keyentryid, subcomponent_type
1414 ) OR keyentryid NOT IN (SELECT id FROM persistent.keyentry)
1415 );",
1416 params![SubComponentType::KEY_BLOB, SubComponentType::KEY_BLOB],
1417 )
1418 .context("Trying to purge superseded blobs.")?;
1419 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001420
Janis Danisevskis3395f862021-05-06 10:54:17 -07001421 Ok(vec![]).no_gc()
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001422 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001423 .context(ks_err!())
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001424 }
1425
1426 /// This maintenance function should be called only once before the database is used for the
1427 /// first time. It restores the invariant that `KeyLifeCycle::Existing` is a transient state.
1428 /// The function transitions all key entries from Existing to Unreferenced unconditionally and
1429 /// returns the number of rows affected. If this returns a value greater than 0, it means that
1430 /// Keystore crashed at some point during key generation. Callers may want to log such
1431 /// occurrences.
1432 /// Unlike with `mark_unreferenced`, we don't need to purge grants, because only keys that made
1433 /// it to `KeyLifeCycle::Live` may have grants.
1434 pub fn cleanup_leftovers(&mut self) -> Result<usize> {
David Drysdale541846b2024-05-23 13:16:07 +01001435 let _wp = wd::watch("KeystoreDB::cleanup_leftovers");
Janis Danisevskis850d4862021-05-05 08:41:14 -07001436
David Drysdale7b9ca232024-05-23 18:19:46 +01001437 self.with_transaction(Immediate("TX_cleanup_leftovers"), |tx| {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001438 tx.execute(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001439 "UPDATE persistent.keyentry SET state = ? WHERE state = ?;",
1440 params![KeyLifeCycle::Unreferenced, KeyLifeCycle::Existing],
1441 )
Janis Danisevskis66784c42021-01-27 08:40:25 -08001442 .context("Failed to execute query.")
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001443 .need_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08001444 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001445 .context(ks_err!())
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001446 }
1447
Hasini Gunasinghe0e161452021-01-27 19:34:37 +00001448 /// Checks if a key exists with given key type and key descriptor properties.
1449 pub fn key_exists(
1450 &mut self,
1451 domain: Domain,
1452 nspace: i64,
1453 alias: &str,
1454 key_type: KeyType,
1455 ) -> Result<bool> {
David Drysdale541846b2024-05-23 13:16:07 +01001456 let _wp = wd::watch("KeystoreDB::key_exists");
Janis Danisevskis850d4862021-05-05 08:41:14 -07001457
David Drysdale7b9ca232024-05-23 18:19:46 +01001458 self.with_transaction(Immediate("TX_key_exists"), |tx| {
Hasini Gunasinghe0e161452021-01-27 19:34:37 +00001459 let key_descriptor =
1460 KeyDescriptor { domain, nspace, alias: Some(alias.to_string()), blob: None };
Chris Wailesd5aaaef2021-07-27 16:04:33 -07001461 let result = Self::load_key_entry_id(tx, &key_descriptor, key_type);
Hasini Gunasinghe0e161452021-01-27 19:34:37 +00001462 match result {
1463 Ok(_) => Ok(true),
1464 Err(error) => match error.root_cause().downcast_ref::<KsError>() {
1465 Some(KsError::Rc(ResponseCode::KEY_NOT_FOUND)) => Ok(false),
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001466 _ => Err(error).context(ks_err!("Failed to find if the key exists.")),
Hasini Gunasinghe0e161452021-01-27 19:34:37 +00001467 },
1468 }
1469 .no_gc()
1470 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001471 .context(ks_err!())
Hasini Gunasinghe0e161452021-01-27 19:34:37 +00001472 }
1473
Hasini Gunasingheda895552021-01-27 19:34:37 +00001474 /// Stores a super key in the database.
1475 pub fn store_super_key(
1476 &mut self,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +00001477 user_id: u32,
Paul Crowley7a658392021-03-18 17:08:20 -07001478 key_type: &SuperKeyType,
1479 blob: &[u8],
1480 blob_metadata: &BlobMetaData,
Paul Crowley8d5b2532021-03-19 10:53:07 -07001481 key_metadata: &KeyMetaData,
Hasini Gunasingheda895552021-01-27 19:34:37 +00001482 ) -> Result<KeyEntry> {
David Drysdale541846b2024-05-23 13:16:07 +01001483 let _wp = wd::watch("KeystoreDB::store_super_key");
Janis Danisevskis850d4862021-05-05 08:41:14 -07001484
David Drysdale7b9ca232024-05-23 18:19:46 +01001485 self.with_transaction(Immediate("TX_store_super_key"), |tx| {
Hasini Gunasingheda895552021-01-27 19:34:37 +00001486 let key_id = Self::insert_with_retry(|id| {
1487 tx.execute(
1488 "INSERT into persistent.keyentry
1489 (id, key_type, domain, namespace, alias, state, km_uuid)
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00001490 VALUES(?, ?, ?, ?, ?, ?, ?);",
Hasini Gunasingheda895552021-01-27 19:34:37 +00001491 params![
1492 id,
1493 KeyType::Super,
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00001494 Domain::APP.0,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +00001495 user_id as i64,
Paul Crowley7a658392021-03-18 17:08:20 -07001496 key_type.alias,
Hasini Gunasingheda895552021-01-27 19:34:37 +00001497 KeyLifeCycle::Live,
1498 &KEYSTORE_UUID,
1499 ],
1500 )
1501 })
1502 .context("Failed to insert into keyentry table.")?;
1503
Paul Crowley8d5b2532021-03-19 10:53:07 -07001504 key_metadata.store_in_db(key_id, tx).context("KeyMetaData::store_in_db failed")?;
1505
Hasini Gunasingheda895552021-01-27 19:34:37 +00001506 Self::set_blob_internal(
Chris Wailesd5aaaef2021-07-27 16:04:33 -07001507 tx,
Hasini Gunasingheda895552021-01-27 19:34:37 +00001508 key_id,
1509 SubComponentType::KEY_BLOB,
1510 Some(blob),
1511 Some(blob_metadata),
1512 )
1513 .context("Failed to store key blob.")?;
1514
1515 Self::load_key_components(tx, KeyEntryLoadBits::KM, key_id)
1516 .context("Trying to load key components.")
1517 .no_gc()
1518 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001519 .context(ks_err!())
Hasini Gunasingheda895552021-01-27 19:34:37 +00001520 }
1521
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +00001522 /// Loads super key of a given user, if exists
Paul Crowley7a658392021-03-18 17:08:20 -07001523 pub fn load_super_key(
1524 &mut self,
1525 key_type: &SuperKeyType,
1526 user_id: u32,
1527 ) -> Result<Option<(KeyIdGuard, KeyEntry)>> {
David Drysdale541846b2024-05-23 13:16:07 +01001528 let _wp = wd::watch("KeystoreDB::load_super_key");
Janis Danisevskis850d4862021-05-05 08:41:14 -07001529
David Drysdale7b9ca232024-05-23 18:19:46 +01001530 self.with_transaction(Immediate("TX_load_super_key"), |tx| {
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +00001531 let key_descriptor = KeyDescriptor {
1532 domain: Domain::APP,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +00001533 nspace: user_id as i64,
Paul Crowley7a658392021-03-18 17:08:20 -07001534 alias: Some(key_type.alias.into()),
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +00001535 blob: None,
1536 };
Chris Wailesd5aaaef2021-07-27 16:04:33 -07001537 let id = Self::load_key_entry_id(tx, &key_descriptor, KeyType::Super);
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +00001538 match id {
1539 Ok(id) => {
Chris Wailesd5aaaef2021-07-27 16:04:33 -07001540 let key_entry = Self::load_key_components(tx, KeyEntryLoadBits::KM, id)
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001541 .context(ks_err!("Failed to load key entry."))?;
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +00001542 Ok(Some((KEY_ID_LOCK.get(id), key_entry)))
1543 }
1544 Err(error) => match error.root_cause().downcast_ref::<KsError>() {
1545 Some(KsError::Rc(ResponseCode::KEY_NOT_FOUND)) => Ok(None),
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001546 _ => Err(error).context(ks_err!()),
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +00001547 },
1548 }
1549 .no_gc()
1550 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001551 .context(ks_err!())
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +00001552 }
1553
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001554 /// Creates a transaction with the given behavior and executes f with the new transaction.
Janis Danisevskis66784c42021-01-27 08:40:25 -08001555 /// The transaction is committed only if f returns Ok and retried if DatabaseBusy
1556 /// or DatabaseLocked is encountered.
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001557 fn with_transaction<T, F>(&mut self, behavior: TransactionBehavior, f: F) -> Result<T>
1558 where
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001559 F: Fn(&Transaction) -> Result<(bool, T)>,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001560 {
David Drysdale7b9ca232024-05-23 18:19:46 +01001561 let name = behavior.name();
Janis Danisevskis66784c42021-01-27 08:40:25 -08001562 loop {
James Farrellefe1a2f2024-02-28 21:36:47 +00001563 let result = self
Janis Danisevskis66784c42021-01-27 08:40:25 -08001564 .conn
David Drysdale7b9ca232024-05-23 18:19:46 +01001565 .transaction_with_behavior(behavior.into())
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001566 .context(ks_err!())
David Drysdale7b9ca232024-05-23 18:19:46 +01001567 .and_then(|tx| {
1568 let _wp = name.map(wd::watch);
1569 f(&tx).map(|result| (result, tx))
1570 })
Janis Danisevskis66784c42021-01-27 08:40:25 -08001571 .and_then(|(result, tx)| {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001572 tx.commit().context(ks_err!("Failed to commit transaction."))?;
Janis Danisevskis66784c42021-01-27 08:40:25 -08001573 Ok(result)
James Farrellefe1a2f2024-02-28 21:36:47 +00001574 });
1575 match result {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001576 Ok(result) => break Ok(result),
1577 Err(e) => {
1578 if Self::is_locked_error(&e) {
David Drysdale115c4722024-04-15 14:11:52 +01001579 std::thread::sleep(DB_BUSY_RETRY_INTERVAL);
Janis Danisevskis66784c42021-01-27 08:40:25 -08001580 continue;
1581 } else {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001582 return Err(e).context(ks_err!());
Janis Danisevskis66784c42021-01-27 08:40:25 -08001583 }
1584 }
1585 }
1586 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001587 .map(|(need_gc, result)| {
1588 if need_gc {
1589 if let Some(ref gc) = self.gc {
1590 gc.notify_gc();
1591 }
1592 }
1593 result
1594 })
Janis Danisevskis66784c42021-01-27 08:40:25 -08001595 }
1596
1597 fn is_locked_error(e: &anyhow::Error) -> bool {
Paul Crowleyf61fee72021-03-17 14:38:44 -07001598 matches!(
1599 e.root_cause().downcast_ref::<rusqlite::ffi::Error>(),
1600 Some(rusqlite::ffi::Error { code: rusqlite::ErrorCode::DatabaseBusy, .. })
1601 | Some(rusqlite::ffi::Error { code: rusqlite::ErrorCode::DatabaseLocked, .. })
1602 )
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001603 }
1604
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001605 fn create_key_entry_internal(
1606 tx: &Transaction,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001607 domain: &Domain,
1608 namespace: &i64,
Janis Danisevskis0cabd712021-05-25 11:07:10 -07001609 key_type: KeyType,
Max Bires8e93d2b2021-01-14 13:17:59 -08001610 km_uuid: &Uuid,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001611 ) -> Result<KeyIdGuard> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001612 match *domain {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001613 Domain::APP | Domain::SELINUX => {}
Joel Galenson0891bc12020-07-20 10:37:03 -07001614 _ => {
1615 return Err(KsError::sys())
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001616 .context(ks_err!("Domain {:?} must be either App or SELinux.", domain));
Joel Galenson0891bc12020-07-20 10:37:03 -07001617 }
1618 }
Janis Danisevskisaec14592020-11-12 09:41:49 -08001619 Ok(KEY_ID_LOCK.get(
1620 Self::insert_with_retry(|id| {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001621 tx.execute(
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001622 "INSERT into persistent.keyentry
Max Bires8e93d2b2021-01-14 13:17:59 -08001623 (id, key_type, domain, namespace, alias, state, km_uuid)
1624 VALUES(?, ?, ?, ?, NULL, ?, ?);",
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001625 params![
1626 id,
Janis Danisevskis0cabd712021-05-25 11:07:10 -07001627 key_type,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001628 domain.0 as u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001629 *namespace,
Max Bires8e93d2b2021-01-14 13:17:59 -08001630 KeyLifeCycle::Existing,
1631 km_uuid,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001632 ],
Janis Danisevskisaec14592020-11-12 09:41:49 -08001633 )
1634 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001635 .context(ks_err!())?,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001636 ))
Joel Galenson26f4d012020-07-17 14:57:21 -07001637 }
Joel Galenson33c04ad2020-08-03 11:04:38 -07001638
Janis Danisevskis377d1002021-01-27 19:07:48 -08001639 /// Set a new blob and associates it with the given key id. Each blob
1640 /// has a sub component type.
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001641 /// Each key can have one of each sub component type associated. If more
1642 /// are added only the most recent can be retrieved, and superseded blobs
Janis Danisevskis377d1002021-01-27 19:07:48 -08001643 /// will get garbage collected.
1644 /// Components SubComponentType::CERT and SubComponentType::CERT_CHAIN can be
1645 /// removed by setting blob to None.
1646 pub fn set_blob(
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001647 &mut self,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001648 key_id: &KeyIdGuard,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001649 sc_type: SubComponentType,
Janis Danisevskis377d1002021-01-27 19:07:48 -08001650 blob: Option<&[u8]>,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001651 blob_metadata: Option<&BlobMetaData>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001652 ) -> Result<()> {
David Drysdale541846b2024-05-23 13:16:07 +01001653 let _wp = wd::watch("KeystoreDB::set_blob");
Janis Danisevskis850d4862021-05-05 08:41:14 -07001654
David Drysdale7b9ca232024-05-23 18:19:46 +01001655 self.with_transaction(Immediate("TX_set_blob"), |tx| {
Chris Wailesd5aaaef2021-07-27 16:04:33 -07001656 Self::set_blob_internal(tx, key_id.0, sc_type, blob, blob_metadata).need_gc()
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001657 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001658 .context(ks_err!())
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001659 }
1660
Janis Danisevskiseed69842021-02-18 20:04:10 -08001661 /// Why would we insert a deleted blob? This weird function is for the purpose of legacy
1662 /// key migration in the case where we bulk delete all the keys of an app or even a user.
1663 /// We use this to insert key blobs into the database which can then be garbage collected
1664 /// lazily by the key garbage collector.
1665 pub fn set_deleted_blob(&mut self, blob: &[u8], blob_metadata: &BlobMetaData) -> Result<()> {
David Drysdale541846b2024-05-23 13:16:07 +01001666 let _wp = wd::watch("KeystoreDB::set_deleted_blob");
Janis Danisevskis850d4862021-05-05 08:41:14 -07001667
David Drysdale7b9ca232024-05-23 18:19:46 +01001668 self.with_transaction(Immediate("TX_set_deleted_blob"), |tx| {
Janis Danisevskiseed69842021-02-18 20:04:10 -08001669 Self::set_blob_internal(
Chris Wailesd5aaaef2021-07-27 16:04:33 -07001670 tx,
Janis Danisevskiseed69842021-02-18 20:04:10 -08001671 Self::UNASSIGNED_KEY_ID,
1672 SubComponentType::KEY_BLOB,
1673 Some(blob),
1674 Some(blob_metadata),
1675 )
1676 .need_gc()
1677 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001678 .context(ks_err!())
Janis Danisevskiseed69842021-02-18 20:04:10 -08001679 }
1680
Janis Danisevskis377d1002021-01-27 19:07:48 -08001681 fn set_blob_internal(
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001682 tx: &Transaction,
1683 key_id: i64,
1684 sc_type: SubComponentType,
Janis Danisevskis377d1002021-01-27 19:07:48 -08001685 blob: Option<&[u8]>,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001686 blob_metadata: Option<&BlobMetaData>,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001687 ) -> Result<()> {
Janis Danisevskis377d1002021-01-27 19:07:48 -08001688 match (blob, sc_type) {
1689 (Some(blob), _) => {
David Drysdale8da288c2024-07-29 15:57:01 +01001690 // Mark any previous blobentry(s) of the same type for the same key as superseded.
1691 tx.execute(
1692 "UPDATE persistent.blobentry SET state = ?
1693 WHERE keyentryid = ? AND subcomponent_type = ?",
1694 params![BlobState::Superseded, key_id, sc_type],
1695 )
1696 .context(ks_err!(
1697 "Failed to mark prior {sc_type:?} blobentrys for {key_id} as superseded"
1698 ))?;
1699
1700 // Now insert the new, un-superseded, blob. (If this fails, the marking of
1701 // old blobs as superseded will be rolled back, because we're inside a
1702 // transaction.)
Janis Danisevskis377d1002021-01-27 19:07:48 -08001703 tx.execute(
1704 "INSERT INTO persistent.blobentry
1705 (subcomponent_type, keyentryid, blob) VALUES (?, ?, ?);",
1706 params![sc_type, key_id, blob],
1707 )
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001708 .context(ks_err!("Failed to insert blob."))?;
David Drysdale8da288c2024-07-29 15:57:01 +01001709
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001710 if let Some(blob_metadata) = blob_metadata {
1711 let blob_id = tx
Andrew Walbran78abb1e2023-05-30 16:20:56 +00001712 .query_row("SELECT MAX(id) FROM persistent.blobentry;", [], |row| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001713 row.get(0)
1714 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001715 .context(ks_err!("Failed to get new blob id."))?;
David Drysdale8da288c2024-07-29 15:57:01 +01001716
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001717 blob_metadata
1718 .store_in_db(blob_id, tx)
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001719 .context(ks_err!("Trying to store blob metadata."))?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001720 }
Janis Danisevskis377d1002021-01-27 19:07:48 -08001721 }
1722 (None, SubComponentType::CERT) | (None, SubComponentType::CERT_CHAIN) => {
1723 tx.execute(
1724 "DELETE FROM persistent.blobentry
1725 WHERE subcomponent_type = ? AND keyentryid = ?;",
1726 params![sc_type, key_id],
1727 )
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001728 .context(ks_err!("Failed to delete blob."))?;
Janis Danisevskis377d1002021-01-27 19:07:48 -08001729 }
1730 (None, _) => {
1731 return Err(KsError::sys())
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001732 .context(ks_err!("Other blobs cannot be deleted in this way."));
Janis Danisevskis377d1002021-01-27 19:07:48 -08001733 }
1734 }
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001735 Ok(())
1736 }
1737
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001738 /// Inserts a collection of key parameters into the `persistent.keyparameter` table
1739 /// and associates them with the given `key_id`.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001740 #[cfg(test)]
1741 fn insert_keyparameter(&mut self, key_id: &KeyIdGuard, params: &[KeyParameter]) -> Result<()> {
David Drysdale7b9ca232024-05-23 18:19:46 +01001742 self.with_transaction(Immediate("TX_insert_keyparameter"), |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001743 Self::insert_keyparameter_internal(tx, key_id, params).no_gc()
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001744 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001745 .context(ks_err!())
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001746 }
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001747
Janis Danisevskis66784c42021-01-27 08:40:25 -08001748 fn insert_keyparameter_internal(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001749 tx: &Transaction,
1750 key_id: &KeyIdGuard,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001751 params: &[KeyParameter],
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001752 ) -> Result<()> {
1753 let mut stmt = tx
1754 .prepare(
1755 "INSERT into persistent.keyparameter (keyentryid, tag, data, security_level)
1756 VALUES (?, ?, ?, ?);",
1757 )
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001758 .context(ks_err!("Failed to prepare statement."))?;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001759
Janis Danisevskis66784c42021-01-27 08:40:25 -08001760 for p in params.iter() {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001761 stmt.insert(params![
1762 key_id.0,
1763 p.get_tag().0,
1764 p.key_parameter_value(),
1765 p.security_level().0
1766 ])
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001767 .with_context(|| ks_err!("Failed to insert {:?}", p))?;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001768 }
1769 Ok(())
1770 }
1771
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001772 /// Insert a set of key entry specific metadata into the database.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001773 #[cfg(test)]
1774 fn insert_key_metadata(&mut self, key_id: &KeyIdGuard, metadata: &KeyMetaData) -> Result<()> {
David Drysdale7b9ca232024-05-23 18:19:46 +01001775 self.with_transaction(Immediate("TX_insert_key_metadata"), |tx| {
Chris Wailesd5aaaef2021-07-27 16:04:33 -07001776 metadata.store_in_db(key_id.0, tx).no_gc()
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001777 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001778 .context(ks_err!())
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001779 }
1780
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001781 /// Updates the alias column of the given key id `newid` with the given alias,
1782 /// and atomically, removes the alias, domain, and namespace from another row
1783 /// with the same alias-domain-namespace tuple if such row exits.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001784 /// Returns Ok(true) if an old key was marked unreferenced as a hint to the garbage
1785 /// collector.
1786 fn rebind_alias(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001787 tx: &Transaction,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001788 newid: &KeyIdGuard,
Joel Galenson33c04ad2020-08-03 11:04:38 -07001789 alias: &str,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001790 domain: &Domain,
1791 namespace: &i64,
Janis Danisevskis0cabd712021-05-25 11:07:10 -07001792 key_type: KeyType,
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001793 ) -> Result<bool> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001794 match *domain {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001795 Domain::APP | Domain::SELINUX => {}
Joel Galenson33c04ad2020-08-03 11:04:38 -07001796 _ => {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001797 return Err(KsError::sys())
1798 .context(ks_err!("Domain {:?} must be either App or SELinux.", domain));
Joel Galenson33c04ad2020-08-03 11:04:38 -07001799 }
1800 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001801 let updated = tx
1802 .execute(
1803 "UPDATE persistent.keyentry
1804 SET alias = NULL, domain = NULL, namespace = NULL, state = ?
Janis Danisevskis0cabd712021-05-25 11:07:10 -07001805 WHERE alias = ? AND domain = ? AND namespace = ? AND key_type = ?;",
1806 params![KeyLifeCycle::Unreferenced, alias, domain.0 as u32, namespace, key_type],
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001807 )
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001808 .context(ks_err!("Failed to rebind existing entry."))?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07001809 let result = tx
1810 .execute(
1811 "UPDATE persistent.keyentry
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001812 SET alias = ?, state = ?
Janis Danisevskis0cabd712021-05-25 11:07:10 -07001813 WHERE id = ? AND domain = ? AND namespace = ? AND state = ? AND key_type = ?;",
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001814 params![
1815 alias,
1816 KeyLifeCycle::Live,
1817 newid.0,
1818 domain.0 as u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001819 *namespace,
Max Bires8e93d2b2021-01-14 13:17:59 -08001820 KeyLifeCycle::Existing,
Janis Danisevskis0cabd712021-05-25 11:07:10 -07001821 key_type,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001822 ],
Joel Galenson33c04ad2020-08-03 11:04:38 -07001823 )
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001824 .context(ks_err!("Failed to set alias."))?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07001825 if result != 1 {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001826 return Err(KsError::sys()).context(ks_err!(
1827 "Expected to update a single entry but instead updated {}.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07001828 result
1829 ));
1830 }
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001831 Ok(updated != 0)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001832 }
1833
Janis Danisevskiscdcf4e52021-04-14 15:44:36 -07001834 /// Moves the key given by KeyIdGuard to the new location at `destination`. If the destination
1835 /// is already occupied by a key, this function fails with `ResponseCode::INVALID_ARGUMENT`.
1836 pub fn migrate_key_namespace(
1837 &mut self,
1838 key_id_guard: KeyIdGuard,
1839 destination: &KeyDescriptor,
1840 caller_uid: u32,
1841 check_permission: impl Fn(&KeyDescriptor) -> Result<()>,
1842 ) -> Result<()> {
David Drysdale541846b2024-05-23 13:16:07 +01001843 let _wp = wd::watch("KeystoreDB::migrate_key_namespace");
Janis Danisevskis850d4862021-05-05 08:41:14 -07001844
Janis Danisevskiscdcf4e52021-04-14 15:44:36 -07001845 let destination = match destination.domain {
1846 Domain::APP => KeyDescriptor { nspace: caller_uid as i64, ..(*destination).clone() },
1847 Domain::SELINUX => (*destination).clone(),
1848 domain => {
1849 return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT))
1850 .context(format!("Domain {:?} must be either APP or SELINUX.", domain));
1851 }
1852 };
1853
1854 // Security critical: Must return immediately on failure. Do not remove the '?';
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001855 check_permission(&destination).context(ks_err!("Trying to check permission."))?;
Janis Danisevskiscdcf4e52021-04-14 15:44:36 -07001856
1857 let alias = destination
1858 .alias
1859 .as_ref()
1860 .ok_or(KsError::Rc(ResponseCode::INVALID_ARGUMENT))
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001861 .context(ks_err!("Alias must be specified."))?;
Janis Danisevskiscdcf4e52021-04-14 15:44:36 -07001862
David Drysdale7b9ca232024-05-23 18:19:46 +01001863 self.with_transaction(Immediate("TX_migrate_key_namespace"), |tx| {
Janis Danisevskiscdcf4e52021-04-14 15:44:36 -07001864 // Query the destination location. If there is a key, the migration request fails.
1865 if tx
1866 .query_row(
1867 "SELECT id FROM persistent.keyentry
1868 WHERE alias = ? AND domain = ? AND namespace = ?;",
1869 params![alias, destination.domain.0, destination.nspace],
1870 |_| Ok(()),
1871 )
1872 .optional()
1873 .context("Failed to query destination.")?
1874 .is_some()
1875 {
1876 return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT))
1877 .context("Target already exists.");
1878 }
1879
1880 let updated = tx
1881 .execute(
1882 "UPDATE persistent.keyentry
1883 SET alias = ?, domain = ?, namespace = ?
1884 WHERE id = ?;",
1885 params![alias, destination.domain.0, destination.nspace, key_id_guard.id()],
1886 )
1887 .context("Failed to update key entry.")?;
1888
1889 if updated != 1 {
1890 return Err(KsError::sys())
1891 .context(format!("Update succeeded, but {} rows were updated.", updated));
1892 }
1893 Ok(()).no_gc()
1894 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001895 .context(ks_err!())
Janis Danisevskiscdcf4e52021-04-14 15:44:36 -07001896 }
1897
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001898 /// Store a new key in a single transaction.
1899 /// The function creates a new key entry, populates the blob, key parameter, and metadata
1900 /// fields, and rebinds the given alias to the new key.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001901 /// The boolean returned is a hint for the garbage collector. If true, a key was replaced,
1902 /// is now unreferenced and needs to be collected.
Chris Wailes3877f292021-07-26 19:24:18 -07001903 #[allow(clippy::too_many_arguments)]
Janis Danisevskis66784c42021-01-27 08:40:25 -08001904 pub fn store_new_key(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001905 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001906 key: &KeyDescriptor,
Janis Danisevskis0cabd712021-05-25 11:07:10 -07001907 key_type: KeyType,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001908 params: &[KeyParameter],
Janis Danisevskisf84d0b02022-01-26 14:11:14 -08001909 blob_info: &BlobInfo,
Max Bires8e93d2b2021-01-14 13:17:59 -08001910 cert_info: &CertificateInfo,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001911 metadata: &KeyMetaData,
Max Bires8e93d2b2021-01-14 13:17:59 -08001912 km_uuid: &Uuid,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001913 ) -> Result<KeyIdGuard> {
David Drysdale541846b2024-05-23 13:16:07 +01001914 let _wp = wd::watch("KeystoreDB::store_new_key");
Janis Danisevskis850d4862021-05-05 08:41:14 -07001915
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001916 let (alias, domain, namespace) = match key {
1917 KeyDescriptor { alias: Some(alias), domain: Domain::APP, nspace, blob: None }
1918 | KeyDescriptor { alias: Some(alias), domain: Domain::SELINUX, nspace, blob: None } => {
1919 (alias, key.domain, nspace)
1920 }
1921 _ => {
1922 return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT))
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001923 .context(ks_err!("Need alias and domain must be APP or SELINUX."));
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001924 }
1925 };
David Drysdale7b9ca232024-05-23 18:19:46 +01001926 self.with_transaction(Immediate("TX_store_new_key"), |tx| {
Janis Danisevskis0cabd712021-05-25 11:07:10 -07001927 let key_id = Self::create_key_entry_internal(tx, &domain, namespace, key_type, km_uuid)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001928 .context("Trying to create new key entry.")?;
Janis Danisevskisf84d0b02022-01-26 14:11:14 -08001929 let BlobInfo { blob, metadata: blob_metadata, superseded_blob } = *blob_info;
1930
1931 // In some occasions the key blob is already upgraded during the import.
1932 // In order to make sure it gets properly deleted it is inserted into the
1933 // database here and then immediately replaced by the superseding blob.
1934 // The garbage collector will then subject the blob to deleteKey of the
1935 // KM back end to permanently invalidate the key.
1936 let need_gc = if let Some((blob, blob_metadata)) = superseded_blob {
1937 Self::set_blob_internal(
1938 tx,
1939 key_id.id(),
1940 SubComponentType::KEY_BLOB,
1941 Some(blob),
1942 Some(blob_metadata),
1943 )
1944 .context("Trying to insert superseded key blob.")?;
1945 true
1946 } else {
1947 false
1948 };
1949
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001950 Self::set_blob_internal(
1951 tx,
1952 key_id.id(),
1953 SubComponentType::KEY_BLOB,
1954 Some(blob),
Chris Wailesd5aaaef2021-07-27 16:04:33 -07001955 Some(blob_metadata),
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001956 )
1957 .context("Trying to insert the key blob.")?;
Max Bires8e93d2b2021-01-14 13:17:59 -08001958 if let Some(cert) = &cert_info.cert {
Chris Wailesd5aaaef2021-07-27 16:04:33 -07001959 Self::set_blob_internal(tx, key_id.id(), SubComponentType::CERT, Some(cert), None)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001960 .context("Trying to insert the certificate.")?;
1961 }
Max Bires8e93d2b2021-01-14 13:17:59 -08001962 if let Some(cert_chain) = &cert_info.cert_chain {
Janis Danisevskis377d1002021-01-27 19:07:48 -08001963 Self::set_blob_internal(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001964 tx,
1965 key_id.id(),
1966 SubComponentType::CERT_CHAIN,
Chris Wailesd5aaaef2021-07-27 16:04:33 -07001967 Some(cert_chain),
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001968 None,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001969 )
1970 .context("Trying to insert the certificate chain.")?;
1971 }
1972 Self::insert_keyparameter_internal(tx, &key_id, params)
1973 .context("Trying to insert key parameters.")?;
Janis Danisevskis377d1002021-01-27 19:07:48 -08001974 metadata.store_in_db(key_id.id(), tx).context("Trying to insert key metadata.")?;
Chris Wailesd5aaaef2021-07-27 16:04:33 -07001975 let need_gc = Self::rebind_alias(tx, &key_id, alias, &domain, namespace, key_type)
Janis Danisevskisf84d0b02022-01-26 14:11:14 -08001976 .context("Trying to rebind alias.")?
1977 || need_gc;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001978 Ok(key_id).do_gc(need_gc)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001979 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001980 .context(ks_err!())
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001981 }
1982
Janis Danisevskis377d1002021-01-27 19:07:48 -08001983 /// Store a new certificate
1984 /// The function creates a new key entry, populates the blob field and metadata, and rebinds
1985 /// the given alias to the new cert.
Max Bires8e93d2b2021-01-14 13:17:59 -08001986 pub fn store_new_certificate(
1987 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001988 key: &KeyDescriptor,
Janis Danisevskis0cabd712021-05-25 11:07:10 -07001989 key_type: KeyType,
Max Bires8e93d2b2021-01-14 13:17:59 -08001990 cert: &[u8],
1991 km_uuid: &Uuid,
1992 ) -> Result<KeyIdGuard> {
David Drysdale541846b2024-05-23 13:16:07 +01001993 let _wp = wd::watch("KeystoreDB::store_new_certificate");
Janis Danisevskis850d4862021-05-05 08:41:14 -07001994
Janis Danisevskis377d1002021-01-27 19:07:48 -08001995 let (alias, domain, namespace) = match key {
1996 KeyDescriptor { alias: Some(alias), domain: Domain::APP, nspace, blob: None }
1997 | KeyDescriptor { alias: Some(alias), domain: Domain::SELINUX, nspace, blob: None } => {
1998 (alias, key.domain, nspace)
1999 }
2000 _ => {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002001 return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT))
2002 .context(ks_err!("Need alias and domain must be APP or SELINUX."));
Janis Danisevskis377d1002021-01-27 19:07:48 -08002003 }
2004 };
David Drysdale7b9ca232024-05-23 18:19:46 +01002005 self.with_transaction(Immediate("TX_store_new_certificate"), |tx| {
Janis Danisevskis0cabd712021-05-25 11:07:10 -07002006 let key_id = Self::create_key_entry_internal(tx, &domain, namespace, key_type, km_uuid)
Janis Danisevskis377d1002021-01-27 19:07:48 -08002007 .context("Trying to create new key entry.")?;
2008
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002009 Self::set_blob_internal(
2010 tx,
2011 key_id.id(),
2012 SubComponentType::CERT_CHAIN,
2013 Some(cert),
2014 None,
2015 )
2016 .context("Trying to insert certificate.")?;
Janis Danisevskis377d1002021-01-27 19:07:48 -08002017
2018 let mut metadata = KeyMetaData::new();
2019 metadata.add(KeyMetaEntry::CreationDate(
2020 DateTime::now().context("Trying to make creation time.")?,
2021 ));
2022
2023 metadata.store_in_db(key_id.id(), tx).context("Trying to insert key metadata.")?;
2024
Chris Wailesd5aaaef2021-07-27 16:04:33 -07002025 let need_gc = Self::rebind_alias(tx, &key_id, alias, &domain, namespace, key_type)
Janis Danisevskis377d1002021-01-27 19:07:48 -08002026 .context("Trying to rebind alias.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002027 Ok(key_id).do_gc(need_gc)
Janis Danisevskis377d1002021-01-27 19:07:48 -08002028 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002029 .context(ks_err!())
Janis Danisevskis377d1002021-01-27 19:07:48 -08002030 }
2031
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002032 // Helper function loading the key_id given the key descriptor
2033 // tuple comprising domain, namespace, and alias.
2034 // Requires a valid transaction.
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002035 fn load_key_entry_id(tx: &Transaction, key: &KeyDescriptor, key_type: KeyType) -> Result<i64> {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002036 let alias = key
2037 .alias
2038 .as_ref()
2039 .map_or_else(|| Err(KsError::sys()), Ok)
2040 .context("In load_key_entry_id: Alias must be specified.")?;
2041 let mut stmt = tx
2042 .prepare(
2043 "SELECT id FROM persistent.keyentry
2044 WHERE
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00002045 key_type = ?
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002046 AND domain = ?
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002047 AND namespace = ?
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002048 AND alias = ?
2049 AND state = ?;",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002050 )
2051 .context("In load_key_entry_id: Failed to select from keyentry table.")?;
2052 let mut rows = stmt
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002053 .query(params![key_type, key.domain.0 as u32, key.nspace, alias, KeyLifeCycle::Live])
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002054 .context("In load_key_entry_id: Failed to read from keyentry table.")?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002055 db_utils::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002056 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002057 .get(0)
2058 .context("Failed to unpack id.")
2059 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002060 .context(ks_err!())
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002061 }
2062
2063 /// This helper function completes the access tuple of a key, which is required
2064 /// to perform access control. The strategy depends on the `domain` field in the
2065 /// key descriptor.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002066 /// * Domain::SELINUX: The access tuple is complete and this function only loads
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002067 /// the key_id for further processing.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002068 /// * Domain::APP: Like Domain::SELINUX, but the tuple is completed by `caller_uid`
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002069 /// which serves as the namespace.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002070 /// * Domain::GRANT: The grant table is queried for the `key_id` and the
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002071 /// `access_vector`.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002072 /// * Domain::KEY_ID: The keyentry table is queried for the owning `domain` and
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002073 /// `namespace`.
Chris Wailes1806f972024-08-19 16:37:40 -07002074 ///
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002075 /// In each case the information returned is sufficient to perform the access
2076 /// check and the key id can be used to load further key artifacts.
2077 fn load_access_tuple(
2078 tx: &Transaction,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002079 key: &KeyDescriptor,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002080 key_type: KeyType,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002081 caller_uid: u32,
David Drysdaleef897ec2024-10-22 12:55:06 +01002082 ) -> Result<KeyAccessInfo> {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002083 match key.domain {
2084 // Domain App or SELinux. In this case we load the key_id from
2085 // the keyentry database for further loading of key components.
2086 // We already have the full access tuple to perform access control.
2087 // The only distinction is that we use the caller_uid instead
2088 // of the caller supplied namespace if the domain field is
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002089 // Domain::APP.
2090 Domain::APP | Domain::SELINUX => {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002091 let mut access_key = key.clone();
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002092 if access_key.domain == Domain::APP {
2093 access_key.nspace = caller_uid as i64;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002094 }
Chris Wailesd5aaaef2021-07-27 16:04:33 -07002095 let key_id = Self::load_key_entry_id(tx, &access_key, key_type)
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002096 .with_context(|| format!("With key.domain = {:?}.", access_key.domain))?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002097
David Drysdaleef897ec2024-10-22 12:55:06 +01002098 Ok(KeyAccessInfo { key_id, descriptor: access_key, vector: None })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002099 }
2100
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002101 // Domain::GRANT. In this case we load the key_id and the access_vector
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002102 // from the grant table.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002103 Domain::GRANT => {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002104 let mut stmt = tx
2105 .prepare(
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002106 "SELECT keyentryid, access_vector FROM persistent.grant
Hasini Gunasinghee70a0ec2021-05-10 21:12:34 +00002107 WHERE grantee = ? AND id = ? AND
2108 (SELECT state FROM persistent.keyentry WHERE id = keyentryid) = ?;",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002109 )
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002110 .context("Domain::GRANT prepare statement failed")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002111 let mut rows = stmt
Hasini Gunasinghee70a0ec2021-05-10 21:12:34 +00002112 .query(params![caller_uid as i64, key.nspace, KeyLifeCycle::Live])
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002113 .context("Domain:Grant: query failed.")?;
2114 let (key_id, access_vector): (i64, i32) =
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002115 db_utils::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002116 let r =
2117 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002118 Ok((
2119 r.get(0).context("Failed to unpack key_id.")?,
2120 r.get(1).context("Failed to unpack access_vector.")?,
2121 ))
2122 })
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002123 .context("Domain::GRANT.")?;
David Drysdaleef897ec2024-10-22 12:55:06 +01002124 Ok(KeyAccessInfo {
2125 key_id,
2126 descriptor: key.clone(),
2127 vector: Some(access_vector.into()),
2128 })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002129 }
2130
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002131 // Domain::KEY_ID. In this case we load the domain and namespace from the
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002132 // keyentry database because we need them for access control.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002133 Domain::KEY_ID => {
Janis Danisevskis45760022021-01-19 16:34:10 -08002134 let (domain, namespace): (Domain, i64) = {
2135 let mut stmt = tx
2136 .prepare(
2137 "SELECT domain, namespace FROM persistent.keyentry
2138 WHERE
2139 id = ?
2140 AND state = ?;",
2141 )
2142 .context("Domain::KEY_ID: prepare statement failed")?;
2143 let mut rows = stmt
2144 .query(params![key.nspace, KeyLifeCycle::Live])
2145 .context("Domain::KEY_ID: query failed.")?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002146 db_utils::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002147 let r =
2148 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002149 Ok((
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002150 Domain(r.get(0).context("Failed to unpack domain.")?),
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002151 r.get(1).context("Failed to unpack namespace.")?,
2152 ))
2153 })
Janis Danisevskis45760022021-01-19 16:34:10 -08002154 .context("Domain::KEY_ID.")?
2155 };
2156
2157 // We may use a key by id after loading it by grant.
2158 // In this case we have to check if the caller has a grant for this particular
2159 // key. We can skip this if we already know that the caller is the owner.
2160 // But we cannot know this if domain is anything but App. E.g. in the case
2161 // of Domain::SELINUX we have to speculatively check for grants because we have to
2162 // consult the SEPolicy before we know if the caller is the owner.
2163 let access_vector: Option<KeyPermSet> =
2164 if domain != Domain::APP || namespace != caller_uid as i64 {
2165 let access_vector: Option<i32> = tx
2166 .query_row(
2167 "SELECT access_vector FROM persistent.grant
2168 WHERE grantee = ? AND keyentryid = ?;",
2169 params![caller_uid as i64, key.nspace],
2170 |row| row.get(0),
2171 )
2172 .optional()
2173 .context("Domain::KEY_ID: query grant failed.")?;
2174 access_vector.map(|p| p.into())
2175 } else {
2176 None
2177 };
2178
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002179 let key_id = key.nspace;
Janis Danisevskis66784c42021-01-27 08:40:25 -08002180 let mut access_key: KeyDescriptor = key.clone();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002181 access_key.domain = domain;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002182 access_key.nspace = namespace;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002183
David Drysdaleef897ec2024-10-22 12:55:06 +01002184 Ok(KeyAccessInfo { key_id, descriptor: access_key, vector: access_vector })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002185 }
Rajesh Nyamagoud625e5892022-05-18 01:31:26 +00002186 _ => Err(anyhow!(KsError::Rc(ResponseCode::INVALID_ARGUMENT))),
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002187 }
2188 }
2189
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002190 fn load_blob_components(
2191 key_id: i64,
2192 load_bits: KeyEntryLoadBits,
2193 tx: &Transaction,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002194 ) -> Result<(bool, Option<(Vec<u8>, BlobMetaData)>, Option<Vec<u8>>, Option<Vec<u8>>)> {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002195 let mut stmt = tx
2196 .prepare(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002197 "SELECT MAX(id), subcomponent_type, blob FROM persistent.blobentry
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002198 WHERE keyentryid = ? GROUP BY subcomponent_type;",
2199 )
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002200 .context(ks_err!("prepare statement failed."))?;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002201
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002202 let mut rows = stmt.query(params![key_id]).context(ks_err!("query failed."))?;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002203
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002204 let mut key_blob: Option<(i64, Vec<u8>)> = None;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002205 let mut cert_blob: Option<Vec<u8>> = None;
2206 let mut cert_chain_blob: Option<Vec<u8>> = None;
Janis Danisevskis377d1002021-01-27 19:07:48 -08002207 let mut has_km_blob: bool = false;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002208 db_utils::with_rows_extract_all(&mut rows, |row| {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002209 let sub_type: SubComponentType =
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002210 row.get(1).context("Failed to extract subcomponent_type.")?;
Janis Danisevskis377d1002021-01-27 19:07:48 -08002211 has_km_blob = has_km_blob || sub_type == SubComponentType::KEY_BLOB;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002212 match (sub_type, load_bits.load_public(), load_bits.load_km()) {
2213 (SubComponentType::KEY_BLOB, _, true) => {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002214 key_blob = Some((
2215 row.get(0).context("Failed to extract key blob id.")?,
2216 row.get(2).context("Failed to extract key blob.")?,
2217 ));
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002218 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002219 (SubComponentType::CERT, true, _) => {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002220 cert_blob =
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002221 Some(row.get(2).context("Failed to extract public certificate blob.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002222 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002223 (SubComponentType::CERT_CHAIN, true, _) => {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002224 cert_chain_blob =
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002225 Some(row.get(2).context("Failed to extract certificate chain blob.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002226 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002227 (SubComponentType::CERT, _, _)
2228 | (SubComponentType::CERT_CHAIN, _, _)
2229 | (SubComponentType::KEY_BLOB, _, _) => {}
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002230 _ => Err(KsError::sys()).context("Unknown subcomponent type.")?,
2231 }
2232 Ok(())
2233 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002234 .context(ks_err!())?;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002235
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002236 let blob_info = key_blob.map_or::<Result<_>, _>(Ok(None), |(blob_id, blob)| {
2237 Ok(Some((
2238 blob,
2239 BlobMetaData::load_from_db(blob_id, tx)
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002240 .context(ks_err!("Trying to load blob_metadata."))?,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002241 )))
2242 })?;
2243
2244 Ok((has_km_blob, blob_info, cert_blob, cert_chain_blob))
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002245 }
2246
2247 fn load_key_parameters(key_id: i64, tx: &Transaction) -> Result<Vec<KeyParameter>> {
2248 let mut stmt = tx
2249 .prepare(
2250 "SELECT tag, data, security_level from persistent.keyparameter
2251 WHERE keyentryid = ?;",
2252 )
2253 .context("In load_key_parameters: prepare statement failed.")?;
2254
2255 let mut parameters: Vec<KeyParameter> = Vec::new();
2256
2257 let mut rows =
2258 stmt.query(params![key_id]).context("In load_key_parameters: query failed.")?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002259 db_utils::with_rows_extract_all(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002260 let tag = Tag(row.get(0).context("Failed to read tag.")?);
2261 let sec_level = SecurityLevel(row.get(2).context("Failed to read sec_level.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002262 parameters.push(
Chris Wailesd5aaaef2021-07-27 16:04:33 -07002263 KeyParameter::new_from_sql(tag, &SqlField::new(1, row), sec_level)
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002264 .context("Failed to read KeyParameter.")?,
2265 );
2266 Ok(())
2267 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002268 .context(ks_err!())?;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002269
2270 Ok(parameters)
2271 }
2272
Qi Wub9433b52020-12-01 14:52:46 +08002273 /// Decrements the usage count of a limited use key. This function first checks whether the
2274 /// usage has been exhausted, if not, decreases the usage count. If the usage count reaches
2275 /// zero, the key also gets marked unreferenced and scheduled for deletion.
2276 /// Returns Ok(true) if the key was marked unreferenced as a hint to the garbage collector.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002277 pub fn check_and_update_key_usage_count(&mut self, key_id: i64) -> Result<()> {
David Drysdale541846b2024-05-23 13:16:07 +01002278 let _wp = wd::watch("KeystoreDB::check_and_update_key_usage_count");
Janis Danisevskis850d4862021-05-05 08:41:14 -07002279
David Drysdale7b9ca232024-05-23 18:19:46 +01002280 self.with_transaction(Immediate("TX_check_and_update_key_usage_count"), |tx| {
Qi Wub9433b52020-12-01 14:52:46 +08002281 let limit: Option<i32> = tx
2282 .query_row(
2283 "SELECT data FROM persistent.keyparameter WHERE keyentryid = ? AND tag = ?;",
2284 params![key_id, Tag::USAGE_COUNT_LIMIT.0],
2285 |row| row.get(0),
2286 )
2287 .optional()
2288 .context("Trying to load usage count")?;
2289
2290 let limit = limit
2291 .ok_or(KsError::Km(ErrorCode::INVALID_KEY_BLOB))
2292 .context("The Key no longer exists. Key is exhausted.")?;
2293
2294 tx.execute(
2295 "UPDATE persistent.keyparameter
2296 SET data = data - 1
2297 WHERE keyentryid = ? AND tag = ? AND data > 0;",
2298 params![key_id, Tag::USAGE_COUNT_LIMIT.0],
2299 )
2300 .context("Failed to update key usage count.")?;
2301
2302 match limit {
2303 1 => Self::mark_unreferenced(tx, key_id)
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002304 .map(|need_gc| (need_gc, ()))
Qi Wub9433b52020-12-01 14:52:46 +08002305 .context("Trying to mark limited use key for deletion."),
2306 0 => Err(KsError::Km(ErrorCode::INVALID_KEY_BLOB)).context("Key is exhausted."),
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002307 _ => Ok(()).no_gc(),
Qi Wub9433b52020-12-01 14:52:46 +08002308 }
2309 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002310 .context(ks_err!())
Qi Wub9433b52020-12-01 14:52:46 +08002311 }
2312
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002313 /// Load a key entry by the given key descriptor.
2314 /// It uses the `check_permission` callback to verify if the access is allowed
2315 /// given the key access tuple read from the database using `load_access_tuple`.
2316 /// With `load_bits` the caller may specify which blobs shall be loaded from
2317 /// the blob database.
2318 pub fn load_key_entry(
2319 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002320 key: &KeyDescriptor,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002321 key_type: KeyType,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002322 load_bits: KeyEntryLoadBits,
2323 caller_uid: u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002324 check_permission: impl Fn(&KeyDescriptor, Option<KeyPermSet>) -> Result<()>,
2325 ) -> Result<(KeyIdGuard, KeyEntry)> {
David Drysdale541846b2024-05-23 13:16:07 +01002326 let _wp = wd::watch("KeystoreDB::load_key_entry");
Janis Danisevskis850d4862021-05-05 08:41:14 -07002327
Janis Danisevskis66784c42021-01-27 08:40:25 -08002328 loop {
2329 match self.load_key_entry_internal(
2330 key,
2331 key_type,
2332 load_bits,
2333 caller_uid,
2334 &check_permission,
2335 ) {
2336 Ok(result) => break Ok(result),
2337 Err(e) => {
2338 if Self::is_locked_error(&e) {
David Drysdale115c4722024-04-15 14:11:52 +01002339 std::thread::sleep(DB_BUSY_RETRY_INTERVAL);
Janis Danisevskis66784c42021-01-27 08:40:25 -08002340 continue;
2341 } else {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002342 return Err(e).context(ks_err!());
Janis Danisevskis66784c42021-01-27 08:40:25 -08002343 }
2344 }
2345 }
2346 }
2347 }
2348
2349 fn load_key_entry_internal(
2350 &mut self,
2351 key: &KeyDescriptor,
2352 key_type: KeyType,
2353 load_bits: KeyEntryLoadBits,
2354 caller_uid: u32,
2355 check_permission: &impl Fn(&KeyDescriptor, Option<KeyPermSet>) -> Result<()>,
Janis Danisevskisaec14592020-11-12 09:41:49 -08002356 ) -> Result<(KeyIdGuard, KeyEntry)> {
2357 // KEY ID LOCK 1/2
2358 // If we got a key descriptor with a key id we can get the lock right away.
2359 // Otherwise we have to defer it until we know the key id.
2360 let key_id_guard = match key.domain {
2361 Domain::KEY_ID => Some(KEY_ID_LOCK.get(key.nspace)),
2362 _ => None,
2363 };
2364
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002365 let tx = self
2366 .conn
Janis Danisevskisaec14592020-11-12 09:41:49 -08002367 .unchecked_transaction()
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002368 .context(ks_err!("Failed to initialize transaction."))?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002369
2370 // Load the key_id and complete the access control tuple.
David Drysdaleef897ec2024-10-22 12:55:06 +01002371 let access = Self::load_access_tuple(&tx, key, key_type, caller_uid).context(ks_err!())?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002372
2373 // Perform access control. It is vital that we return here if the permission is denied.
2374 // So do not touch that '?' at the end.
David Drysdaleef897ec2024-10-22 12:55:06 +01002375 check_permission(&access.descriptor, access.vector).context(ks_err!())?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002376
Janis Danisevskisaec14592020-11-12 09:41:49 -08002377 // KEY ID LOCK 2/2
2378 // If we did not get a key id lock by now, it was because we got a key descriptor
2379 // without a key id. At this point we got the key id, so we can try and get a lock.
2380 // However, we cannot block here, because we are in the middle of the transaction.
2381 // So first we try to get the lock non blocking. If that fails, we roll back the
2382 // transaction and block until we get the lock. After we successfully got the lock,
2383 // we start a new transaction and load the access tuple again.
2384 //
2385 // We don't need to perform access control again, because we already established
2386 // that the caller had access to the given key. But we need to make sure that the
2387 // key id still exists. So we have to load the key entry by key id this time.
2388 let (key_id_guard, tx) = match key_id_guard {
David Drysdaleef897ec2024-10-22 12:55:06 +01002389 None => match KEY_ID_LOCK.try_get(access.key_id) {
Janis Danisevskisaec14592020-11-12 09:41:49 -08002390 None => {
2391 // Roll back the transaction.
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002392 tx.rollback().context(ks_err!("Failed to roll back transaction."))?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002393
Janis Danisevskisaec14592020-11-12 09:41:49 -08002394 // Block until we have a key id lock.
David Drysdaleef897ec2024-10-22 12:55:06 +01002395 let key_id_guard = KEY_ID_LOCK.get(access.key_id);
Janis Danisevskisaec14592020-11-12 09:41:49 -08002396
2397 // Create a new transaction.
Janis Danisevskis66784c42021-01-27 08:40:25 -08002398 let tx = self
2399 .conn
2400 .unchecked_transaction()
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002401 .context(ks_err!("Failed to initialize transaction."))?;
Janis Danisevskisaec14592020-11-12 09:41:49 -08002402
2403 Self::load_access_tuple(
2404 &tx,
2405 // This time we have to load the key by the retrieved key id, because the
2406 // alias may have been rebound after we rolled back the transaction.
Janis Danisevskis66784c42021-01-27 08:40:25 -08002407 &KeyDescriptor {
Janis Danisevskisaec14592020-11-12 09:41:49 -08002408 domain: Domain::KEY_ID,
David Drysdaleef897ec2024-10-22 12:55:06 +01002409 nspace: access.key_id,
Janis Danisevskisaec14592020-11-12 09:41:49 -08002410 ..Default::default()
2411 },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002412 key_type,
Janis Danisevskisaec14592020-11-12 09:41:49 -08002413 caller_uid,
2414 )
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002415 .context(ks_err!("(deferred key lock)"))?;
Janis Danisevskisaec14592020-11-12 09:41:49 -08002416 (key_id_guard, tx)
2417 }
2418 Some(l) => (l, tx),
2419 },
2420 Some(key_id_guard) => (key_id_guard, tx),
2421 };
2422
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002423 let key_entry =
2424 Self::load_key_components(&tx, load_bits, key_id_guard.id()).context(ks_err!())?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002425
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002426 tx.commit().context(ks_err!("Failed to commit transaction."))?;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002427
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002428 Ok((key_id_guard, key_entry))
2429 }
2430
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002431 fn mark_unreferenced(tx: &Transaction, key_id: i64) -> Result<bool> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002432 let updated = tx
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002433 .execute("DELETE FROM persistent.keyentry WHERE id = ?;", params![key_id])
2434 .context("Trying to delete keyentry.")?;
2435 tx.execute("DELETE FROM persistent.keymetadata WHERE keyentryid = ?;", params![key_id])
2436 .context("Trying to delete keymetadata.")?;
2437 tx.execute("DELETE FROM persistent.keyparameter WHERE keyentryid = ?;", params![key_id])
2438 .context("Trying to delete keyparameters.")?;
2439 tx.execute("DELETE FROM persistent.grant WHERE keyentryid = ?;", params![key_id])
2440 .context("Trying to delete grants.")?;
David Drysdale8da288c2024-07-29 15:57:01 +01002441 // The associated blobentry rows are not immediately deleted when the owning keyentry is
2442 // removed, because a KeyMint `deleteKey()` invocation is needed (specifically for the
2443 // `KEY_BLOB`). Mark the affected rows with `state=Orphaned` so a subsequent garbage
2444 // collection can do this.
2445 tx.execute(
2446 "UPDATE persistent.blobentry SET state = ? WHERE keyentryid = ?",
2447 params![BlobState::Orphaned, key_id],
2448 )
2449 .context("Trying to mark blobentrys as superseded")?;
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002450 Ok(updated != 0)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002451 }
2452
2453 /// Marks the given key as unreferenced and removes all of the grants to this key.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002454 /// Returns Ok(true) if a key was marked unreferenced as a hint for the garbage collector.
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002455 pub fn unbind_key(
2456 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002457 key: &KeyDescriptor,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002458 key_type: KeyType,
2459 caller_uid: u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002460 check_permission: impl Fn(&KeyDescriptor, Option<KeyPermSet>) -> Result<()>,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002461 ) -> Result<()> {
David Drysdale541846b2024-05-23 13:16:07 +01002462 let _wp = wd::watch("KeystoreDB::unbind_key");
Janis Danisevskis850d4862021-05-05 08:41:14 -07002463
David Drysdale7b9ca232024-05-23 18:19:46 +01002464 self.with_transaction(Immediate("TX_unbind_key"), |tx| {
David Drysdaleef897ec2024-10-22 12:55:06 +01002465 let access = Self::load_access_tuple(tx, key, key_type, caller_uid)
2466 .context("Trying to get access tuple.")?;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002467
2468 // Perform access control. It is vital that we return here if the permission is denied.
2469 // So do not touch that '?' at the end.
David Drysdaleef897ec2024-10-22 12:55:06 +01002470 check_permission(&access.descriptor, access.vector)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002471 .context("While checking permission.")?;
2472
David Drysdaleef897ec2024-10-22 12:55:06 +01002473 Self::mark_unreferenced(tx, access.key_id)
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002474 .map(|need_gc| (need_gc, ()))
2475 .context("Trying to mark the key unreferenced.")
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002476 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002477 .context(ks_err!())
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002478 }
2479
Max Bires8e93d2b2021-01-14 13:17:59 -08002480 fn get_key_km_uuid(tx: &Transaction, key_id: i64) -> Result<Uuid> {
2481 tx.query_row(
2482 "SELECT km_uuid FROM persistent.keyentry WHERE id = ?",
2483 params![key_id],
2484 |row| row.get(0),
2485 )
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002486 .context(ks_err!())
Max Bires8e93d2b2021-01-14 13:17:59 -08002487 }
2488
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002489 /// Delete all artifacts belonging to the namespace given by the domain-namespace tuple.
2490 /// This leaves all of the blob entries orphaned for subsequent garbage collection.
2491 pub fn unbind_keys_for_namespace(&mut self, domain: Domain, namespace: i64) -> Result<()> {
David Drysdale541846b2024-05-23 13:16:07 +01002492 let _wp = wd::watch("KeystoreDB::unbind_keys_for_namespace");
Janis Danisevskis850d4862021-05-05 08:41:14 -07002493
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002494 if !(domain == Domain::APP || domain == Domain::SELINUX) {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002495 return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT)).context(ks_err!());
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002496 }
David Drysdale7b9ca232024-05-23 18:19:46 +01002497 self.with_transaction(Immediate("TX_unbind_keys_for_namespace"), |tx| {
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002498 tx.execute(
2499 "DELETE FROM persistent.keymetadata
2500 WHERE keyentryid IN (
2501 SELECT id FROM persistent.keyentry
Tri Vo0346bbe2023-05-12 14:16:31 -04002502 WHERE domain = ? AND namespace = ? AND key_type = ?
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002503 );",
Tri Vo0346bbe2023-05-12 14:16:31 -04002504 params![domain.0, namespace, KeyType::Client],
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002505 )
2506 .context("Trying to delete keymetadata.")?;
2507 tx.execute(
2508 "DELETE FROM persistent.keyparameter
2509 WHERE keyentryid IN (
2510 SELECT id FROM persistent.keyentry
Tri Vo0346bbe2023-05-12 14:16:31 -04002511 WHERE domain = ? AND namespace = ? AND key_type = ?
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002512 );",
Tri Vo0346bbe2023-05-12 14:16:31 -04002513 params![domain.0, namespace, KeyType::Client],
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002514 )
2515 .context("Trying to delete keyparameters.")?;
2516 tx.execute(
2517 "DELETE FROM persistent.grant
2518 WHERE keyentryid IN (
2519 SELECT id FROM persistent.keyentry
Tri Vo0346bbe2023-05-12 14:16:31 -04002520 WHERE domain = ? AND namespace = ? AND key_type = ?
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002521 );",
Tri Vo0346bbe2023-05-12 14:16:31 -04002522 params![domain.0, namespace, KeyType::Client],
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002523 )
2524 .context("Trying to delete grants.")?;
2525 tx.execute(
Janis Danisevskisb146f312021-05-06 15:05:45 -07002526 "DELETE FROM persistent.keyentry
Tri Vo0346bbe2023-05-12 14:16:31 -04002527 WHERE domain = ? AND namespace = ? AND key_type = ?;",
2528 params![domain.0, namespace, KeyType::Client],
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002529 )
2530 .context("Trying to delete keyentry.")?;
2531 Ok(()).need_gc()
2532 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002533 .context(ks_err!())
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002534 }
2535
Janis Danisevskis3cba10d2021-05-06 17:02:19 -07002536 fn cleanup_unreferenced(tx: &Transaction) -> Result<()> {
David Drysdale541846b2024-05-23 13:16:07 +01002537 let _wp = wd::watch("KeystoreDB::cleanup_unreferenced");
Janis Danisevskis3cba10d2021-05-06 17:02:19 -07002538 {
2539 tx.execute(
2540 "DELETE FROM persistent.keymetadata
2541 WHERE keyentryid IN (
2542 SELECT id FROM persistent.keyentry
2543 WHERE state = ?
2544 );",
2545 params![KeyLifeCycle::Unreferenced],
2546 )
2547 .context("Trying to delete keymetadata.")?;
2548 tx.execute(
2549 "DELETE FROM persistent.keyparameter
2550 WHERE keyentryid IN (
2551 SELECT id FROM persistent.keyentry
2552 WHERE state = ?
2553 );",
2554 params![KeyLifeCycle::Unreferenced],
2555 )
2556 .context("Trying to delete keyparameters.")?;
2557 tx.execute(
2558 "DELETE FROM persistent.grant
2559 WHERE keyentryid IN (
2560 SELECT id FROM persistent.keyentry
2561 WHERE state = ?
2562 );",
2563 params![KeyLifeCycle::Unreferenced],
2564 )
2565 .context("Trying to delete grants.")?;
2566 tx.execute(
2567 "DELETE FROM persistent.keyentry
2568 WHERE state = ?;",
2569 params![KeyLifeCycle::Unreferenced],
2570 )
2571 .context("Trying to delete keyentry.")?;
2572 Result::<()>::Ok(())
2573 }
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002574 .context(ks_err!())
Janis Danisevskis3cba10d2021-05-06 17:02:19 -07002575 }
2576
Eric Biggers9f7ebeb2024-06-20 14:59:32 +00002577 /// Deletes all keys for the given user, including both client keys and super keys.
2578 pub fn unbind_keys_for_user(&mut self, user_id: u32) -> Result<()> {
David Drysdale541846b2024-05-23 13:16:07 +01002579 let _wp = wd::watch("KeystoreDB::unbind_keys_for_user");
Janis Danisevskis850d4862021-05-05 08:41:14 -07002580
David Drysdale7b9ca232024-05-23 18:19:46 +01002581 self.with_transaction(Immediate("TX_unbind_keys_for_user"), |tx| {
Hasini Gunasingheda895552021-01-27 19:34:37 +00002582 let mut stmt = tx
2583 .prepare(&format!(
2584 "SELECT id from persistent.keyentry
2585 WHERE (
2586 key_type = ?
2587 AND domain = ?
2588 AND cast ( (namespace/{aid_user_offset}) as int) = ?
2589 AND state = ?
2590 ) OR (
2591 key_type = ?
2592 AND namespace = ?
Hasini Gunasingheda895552021-01-27 19:34:37 +00002593 AND state = ?
2594 );",
2595 aid_user_offset = AID_USER_OFFSET
2596 ))
2597 .context(concat!(
2598 "In unbind_keys_for_user. ",
2599 "Failed to prepare the query to find the keys created by apps."
2600 ))?;
2601
2602 let mut rows = stmt
2603 .query(params![
2604 // WHERE client key:
2605 KeyType::Client,
2606 Domain::APP.0 as u32,
2607 user_id,
2608 KeyLifeCycle::Live,
2609 // OR super key:
2610 KeyType::Super,
2611 user_id,
Hasini Gunasingheda895552021-01-27 19:34:37 +00002612 KeyLifeCycle::Live
2613 ])
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002614 .context(ks_err!("Failed to query the keys created by apps."))?;
Hasini Gunasingheda895552021-01-27 19:34:37 +00002615
2616 let mut key_ids: Vec<i64> = Vec::new();
2617 db_utils::with_rows_extract_all(&mut rows, |row| {
2618 key_ids
2619 .push(row.get(0).context("Failed to read key id of a key created by an app.")?);
2620 Ok(())
2621 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002622 .context(ks_err!())?;
Hasini Gunasingheda895552021-01-27 19:34:37 +00002623
2624 let mut notify_gc = false;
2625 for key_id in key_ids {
Chris Wailesd5aaaef2021-07-27 16:04:33 -07002626 notify_gc = Self::mark_unreferenced(tx, key_id)
Hasini Gunasingheda895552021-01-27 19:34:37 +00002627 .context("In unbind_keys_for_user.")?
2628 || notify_gc;
2629 }
2630 Ok(()).do_gc(notify_gc)
2631 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002632 .context(ks_err!())
Hasini Gunasingheda895552021-01-27 19:34:37 +00002633 }
2634
Eric Biggersb0478cf2023-10-27 03:55:29 +00002635 /// Deletes all auth-bound keys, i.e. keys that require user authentication, for the given user.
2636 /// This runs when the user's lock screen is being changed to Swipe or None.
2637 ///
2638 /// This intentionally does *not* delete keys that require that the device be unlocked, unless
2639 /// such keys also require user authentication. Keystore's concept of user authentication is
2640 /// fairly strong, and it requires that keys that require authentication be deleted as soon as
2641 /// authentication is no longer possible. In contrast, keys that just require that the device
2642 /// be unlocked should remain usable when the lock screen is set to Swipe or None, as the device
2643 /// is always considered "unlocked" in that case.
2644 pub fn unbind_auth_bound_keys_for_user(&mut self, user_id: u32) -> Result<()> {
David Drysdale541846b2024-05-23 13:16:07 +01002645 let _wp = wd::watch("KeystoreDB::unbind_auth_bound_keys_for_user");
Eric Biggersb0478cf2023-10-27 03:55:29 +00002646
David Drysdale7b9ca232024-05-23 18:19:46 +01002647 self.with_transaction(Immediate("TX_unbind_auth_bound_keys_for_user"), |tx| {
Eric Biggersb0478cf2023-10-27 03:55:29 +00002648 let mut stmt = tx
2649 .prepare(&format!(
2650 "SELECT id from persistent.keyentry
2651 WHERE key_type = ?
2652 AND domain = ?
2653 AND cast ( (namespace/{aid_user_offset}) as int) = ?
2654 AND state = ?;",
2655 aid_user_offset = AID_USER_OFFSET
2656 ))
2657 .context(concat!(
2658 "In unbind_auth_bound_keys_for_user. ",
2659 "Failed to prepare the query to find the keys created by apps."
2660 ))?;
2661
2662 let mut rows = stmt
2663 .query(params![KeyType::Client, Domain::APP.0 as u32, user_id, KeyLifeCycle::Live,])
2664 .context(ks_err!("Failed to query the keys created by apps."))?;
2665
2666 let mut key_ids: Vec<i64> = Vec::new();
2667 db_utils::with_rows_extract_all(&mut rows, |row| {
2668 key_ids
2669 .push(row.get(0).context("Failed to read key id of a key created by an app.")?);
2670 Ok(())
2671 })
2672 .context(ks_err!())?;
2673
2674 let mut notify_gc = false;
2675 let mut num_unbound = 0;
2676 for key_id in key_ids {
2677 // Load the key parameters and filter out non-auth-bound keys. To identify
2678 // auth-bound keys, use the presence of UserSecureID. The absence of NoAuthRequired
2679 // could also be used, but UserSecureID is what Keystore treats as authoritative
2680 // when actually enforcing the key parameters (it might not matter, though).
2681 let params = Self::load_key_parameters(key_id, tx)
2682 .context("Failed to load key parameters.")?;
2683 let is_auth_bound_key = params.iter().any(|kp| {
2684 matches!(kp.key_parameter_value(), KeyParameterValue::UserSecureID(_))
2685 });
2686 if is_auth_bound_key {
2687 notify_gc = Self::mark_unreferenced(tx, key_id)
2688 .context("In unbind_auth_bound_keys_for_user.")?
2689 || notify_gc;
2690 num_unbound += 1;
2691 }
2692 }
2693 log::info!("Deleting {num_unbound} auth-bound keys for user {user_id}");
2694 Ok(()).do_gc(notify_gc)
2695 })
2696 .context(ks_err!())
2697 }
2698
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002699 fn load_key_components(
2700 tx: &Transaction,
2701 load_bits: KeyEntryLoadBits,
2702 key_id: i64,
2703 ) -> Result<KeyEntry> {
Chris Wailesd5aaaef2021-07-27 16:04:33 -07002704 let metadata = KeyMetaData::load_from_db(key_id, tx).context("In load_key_components.")?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002705
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002706 let (has_km_blob, key_blob_info, cert_blob, cert_chain_blob) =
Chris Wailesd5aaaef2021-07-27 16:04:33 -07002707 Self::load_blob_components(key_id, load_bits, tx).context("In load_key_components.")?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002708
Chris Wailesd5aaaef2021-07-27 16:04:33 -07002709 let parameters = Self::load_key_parameters(key_id, tx)
Max Bires8e93d2b2021-01-14 13:17:59 -08002710 .context("In load_key_components: Trying to load key parameters.")?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002711
Chris Wailesd5aaaef2021-07-27 16:04:33 -07002712 let km_uuid = Self::get_key_km_uuid(tx, key_id)
Max Bires8e93d2b2021-01-14 13:17:59 -08002713 .context("In load_key_components: Trying to get KM uuid.")?;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002714
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002715 Ok(KeyEntry {
2716 id: key_id,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002717 key_blob_info,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002718 cert: cert_blob,
2719 cert_chain: cert_chain_blob,
Max Bires8e93d2b2021-01-14 13:17:59 -08002720 km_uuid,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002721 parameters,
2722 metadata,
Janis Danisevskis377d1002021-01-27 19:07:48 -08002723 pure_cert: !has_km_blob,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002724 })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002725 }
2726
Eran Messeri24f31972023-01-25 17:00:33 +00002727 /// Returns a list of KeyDescriptors in the selected domain/namespace whose
2728 /// aliases are greater than the specified 'start_past_alias'. If no value
2729 /// is provided, returns all KeyDescriptors.
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002730 /// The key descriptors will have the domain, nspace, and alias field set.
Eran Messeri24f31972023-01-25 17:00:33 +00002731 /// The returned list will be sorted by alias.
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002732 /// Domain must be APP or SELINUX, the caller must make sure of that.
David Drysdale8da288c2024-07-29 15:57:01 +01002733 /// Number of returned values is limited to 10,000 (which is empirically roughly
2734 /// what will fit in a Binder message).
Eran Messeri24f31972023-01-25 17:00:33 +00002735 pub fn list_past_alias(
Janis Danisevskis18313832021-05-17 13:30:32 -07002736 &mut self,
2737 domain: Domain,
2738 namespace: i64,
2739 key_type: KeyType,
Eran Messeri24f31972023-01-25 17:00:33 +00002740 start_past_alias: Option<&str>,
Janis Danisevskis18313832021-05-17 13:30:32 -07002741 ) -> Result<Vec<KeyDescriptor>> {
David Drysdale541846b2024-05-23 13:16:07 +01002742 let _wp = wd::watch("KeystoreDB::list_past_alias");
Janis Danisevskis850d4862021-05-05 08:41:14 -07002743
Eran Messeri24f31972023-01-25 17:00:33 +00002744 let query = format!(
2745 "SELECT DISTINCT alias FROM persistent.keyentry
Janis Danisevskis18313832021-05-17 13:30:32 -07002746 WHERE domain = ?
2747 AND namespace = ?
2748 AND alias IS NOT NULL
2749 AND state = ?
Eran Messeri24f31972023-01-25 17:00:33 +00002750 AND key_type = ?
2751 {}
David Drysdale8da288c2024-07-29 15:57:01 +01002752 ORDER BY alias ASC
2753 LIMIT 10000;",
Eran Messeri24f31972023-01-25 17:00:33 +00002754 if start_past_alias.is_some() { " AND alias > ?" } else { "" }
2755 );
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002756
Eran Messeri24f31972023-01-25 17:00:33 +00002757 self.with_transaction(TransactionBehavior::Deferred, |tx| {
2758 let mut stmt = tx.prepare(&query).context(ks_err!("Failed to prepare."))?;
2759
2760 let mut rows = match start_past_alias {
2761 Some(past_alias) => stmt
2762 .query(params![
2763 domain.0 as u32,
2764 namespace,
2765 KeyLifeCycle::Live,
2766 key_type,
2767 past_alias
2768 ])
2769 .context(ks_err!("Failed to query."))?,
2770 None => stmt
2771 .query(params![domain.0 as u32, namespace, KeyLifeCycle::Live, key_type,])
2772 .context(ks_err!("Failed to query."))?,
2773 };
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002774
Janis Danisevskis66784c42021-01-27 08:40:25 -08002775 let mut descriptors: Vec<KeyDescriptor> = Vec::new();
2776 db_utils::with_rows_extract_all(&mut rows, |row| {
2777 descriptors.push(KeyDescriptor {
2778 domain,
2779 nspace: namespace,
2780 alias: Some(row.get(0).context("Trying to extract alias.")?),
2781 blob: None,
2782 });
2783 Ok(())
2784 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002785 .context(ks_err!("Failed to extract rows."))?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002786 Ok(descriptors).no_gc()
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002787 })
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002788 }
2789
Eran Messeri24f31972023-01-25 17:00:33 +00002790 /// Returns a number of KeyDescriptors in the selected domain/namespace.
2791 /// Domain must be APP or SELINUX, the caller must make sure of that.
2792 pub fn count_keys(
2793 &mut self,
2794 domain: Domain,
2795 namespace: i64,
2796 key_type: KeyType,
2797 ) -> Result<usize> {
David Drysdale541846b2024-05-23 13:16:07 +01002798 let _wp = wd::watch("KeystoreDB::countKeys");
Eran Messeri24f31972023-01-25 17:00:33 +00002799
2800 let num_keys = self.with_transaction(TransactionBehavior::Deferred, |tx| {
2801 tx.query_row(
2802 "SELECT COUNT(alias) FROM persistent.keyentry
2803 WHERE domain = ?
2804 AND namespace = ?
2805 AND alias IS NOT NULL
2806 AND state = ?
2807 AND key_type = ?;",
2808 params![domain.0 as u32, namespace, KeyLifeCycle::Live, key_type],
2809 |row| row.get(0),
2810 )
2811 .context(ks_err!("Failed to count number of keys."))
2812 .no_gc()
2813 })?;
2814 Ok(num_keys)
2815 }
2816
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002817 /// Adds a grant to the grant table.
2818 /// Like `load_key_entry` this function loads the access tuple before
2819 /// it uses the callback for a permission check. Upon success,
2820 /// it inserts the `grantee_uid`, `key_id`, and `access_vector` into the
2821 /// grant table. The new row will have a randomized id, which is used as
2822 /// grant id in the namespace field of the resulting KeyDescriptor.
2823 pub fn grant(
2824 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002825 key: &KeyDescriptor,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002826 caller_uid: u32,
2827 grantee_uid: u32,
2828 access_vector: KeyPermSet,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002829 check_permission: impl Fn(&KeyDescriptor, &KeyPermSet) -> Result<()>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002830 ) -> Result<KeyDescriptor> {
David Drysdale541846b2024-05-23 13:16:07 +01002831 let _wp = wd::watch("KeystoreDB::grant");
Janis Danisevskis850d4862021-05-05 08:41:14 -07002832
David Drysdale7b9ca232024-05-23 18:19:46 +01002833 self.with_transaction(Immediate("TX_grant"), |tx| {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002834 // Load the key_id and complete the access control tuple.
2835 // We ignore the access vector here because grants cannot be granted.
2836 // The access vector returned here expresses the permissions the
2837 // grantee has if key.domain == Domain::GRANT. But this vector
2838 // cannot include the grant permission by design, so there is no way the
2839 // subsequent permission check can pass.
2840 // We could check key.domain == Domain::GRANT and fail early.
2841 // But even if we load the access tuple by grant here, the permission
2842 // check denies the attempt to create a grant by grant descriptor.
David Drysdaleef897ec2024-10-22 12:55:06 +01002843 let access =
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002844 Self::load_access_tuple(tx, key, KeyType::Client, caller_uid).context(ks_err!())?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002845
Janis Danisevskis66784c42021-01-27 08:40:25 -08002846 // Perform access control. It is vital that we return here if the permission
2847 // was denied. So do not touch that '?' at the end of the line.
2848 // This permission check checks if the caller has the grant permission
2849 // for the given key and in addition to all of the permissions
2850 // expressed in `access_vector`.
David Drysdaleef897ec2024-10-22 12:55:06 +01002851 check_permission(&access.descriptor, &access_vector)
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002852 .context(ks_err!("check_permission failed"))?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002853
Janis Danisevskis66784c42021-01-27 08:40:25 -08002854 let grant_id = if let Some(grant_id) = tx
2855 .query_row(
2856 "SELECT id FROM persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002857 WHERE keyentryid = ? AND grantee = ?;",
David Drysdaleef897ec2024-10-22 12:55:06 +01002858 params![access.key_id, grantee_uid],
Janis Danisevskis66784c42021-01-27 08:40:25 -08002859 |row| row.get(0),
2860 )
2861 .optional()
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002862 .context(ks_err!("Failed get optional existing grant id."))?
Janis Danisevskis66784c42021-01-27 08:40:25 -08002863 {
2864 tx.execute(
2865 "UPDATE persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002866 SET access_vector = ?
2867 WHERE id = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08002868 params![i32::from(access_vector), grant_id],
Joel Galenson845f74b2020-09-09 14:11:55 -07002869 )
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002870 .context(ks_err!("Failed to update existing grant."))?;
Janis Danisevskis66784c42021-01-27 08:40:25 -08002871 grant_id
2872 } else {
2873 Self::insert_with_retry(|id| {
2874 tx.execute(
2875 "INSERT INTO persistent.grant (id, grantee, keyentryid, access_vector)
2876 VALUES (?, ?, ?, ?);",
David Drysdaleef897ec2024-10-22 12:55:06 +01002877 params![id, grantee_uid, access.key_id, i32::from(access_vector)],
Janis Danisevskis66784c42021-01-27 08:40:25 -08002878 )
2879 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002880 .context(ks_err!())?
Janis Danisevskis66784c42021-01-27 08:40:25 -08002881 };
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002882
Janis Danisevskis66784c42021-01-27 08:40:25 -08002883 Ok(KeyDescriptor { domain: Domain::GRANT, nspace: grant_id, alias: None, blob: None })
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002884 .no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08002885 })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002886 }
2887
2888 /// This function checks permissions like `grant` and `load_key_entry`
2889 /// before removing a grant from the grant table.
2890 pub fn ungrant(
2891 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002892 key: &KeyDescriptor,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002893 caller_uid: u32,
2894 grantee_uid: u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002895 check_permission: impl Fn(&KeyDescriptor) -> Result<()>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002896 ) -> Result<()> {
David Drysdale541846b2024-05-23 13:16:07 +01002897 let _wp = wd::watch("KeystoreDB::ungrant");
Janis Danisevskis850d4862021-05-05 08:41:14 -07002898
David Drysdale7b9ca232024-05-23 18:19:46 +01002899 self.with_transaction(Immediate("TX_ungrant"), |tx| {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002900 // Load the key_id and complete the access control tuple.
2901 // We ignore the access vector here because grants cannot be granted.
David Drysdaleef897ec2024-10-22 12:55:06 +01002902 let access =
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002903 Self::load_access_tuple(tx, key, KeyType::Client, caller_uid).context(ks_err!())?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002904
Janis Danisevskis66784c42021-01-27 08:40:25 -08002905 // Perform access control. We must return here if the permission
2906 // was denied. So do not touch the '?' at the end of this line.
David Drysdaleef897ec2024-10-22 12:55:06 +01002907 check_permission(&access.descriptor).context(ks_err!("check_permission failed."))?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002908
Janis Danisevskis66784c42021-01-27 08:40:25 -08002909 tx.execute(
2910 "DELETE FROM persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002911 WHERE keyentryid = ? AND grantee = ?;",
David Drysdaleef897ec2024-10-22 12:55:06 +01002912 params![access.key_id, grantee_uid],
Janis Danisevskis66784c42021-01-27 08:40:25 -08002913 )
2914 .context("Failed to delete grant.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002915
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002916 Ok(()).no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08002917 })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002918 }
2919
Joel Galenson845f74b2020-09-09 14:11:55 -07002920 // Generates a random id and passes it to the given function, which will
2921 // try to insert it into a database. If that insertion fails, retry;
2922 // otherwise return the id.
2923 fn insert_with_retry(inserter: impl Fn(i64) -> rusqlite::Result<usize>) -> Result<i64> {
2924 loop {
Janis Danisevskiseed69842021-02-18 20:04:10 -08002925 let newid: i64 = match random() {
2926 Self::UNASSIGNED_KEY_ID => continue, // UNASSIGNED_KEY_ID cannot be assigned.
2927 i => i,
2928 };
Joel Galenson845f74b2020-09-09 14:11:55 -07002929 match inserter(newid) {
2930 // If the id already existed, try again.
2931 Err(rusqlite::Error::SqliteFailure(
2932 libsqlite3_sys::Error {
2933 code: libsqlite3_sys::ErrorCode::ConstraintViolation,
2934 extended_code: libsqlite3_sys::SQLITE_CONSTRAINT_UNIQUE,
2935 },
2936 _,
2937 )) => (),
2938 Err(e) => {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002939 return Err(e).context(ks_err!("failed to insert into database."));
Joel Galenson845f74b2020-09-09 14:11:55 -07002940 }
2941 _ => return Ok(newid),
2942 }
2943 }
2944 }
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002945
Matthew Maurerd7815ca2021-05-06 21:58:45 -07002946 /// Insert or replace the auth token based on (user_id, auth_id, auth_type)
2947 pub fn insert_auth_token(&mut self, auth_token: &HardwareAuthToken) {
Eric Biggers19b3b0d2024-01-31 22:46:47 +00002948 self.perboot
2949 .insert_auth_token_entry(AuthTokenEntry::new(auth_token.clone(), BootTime::now()))
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002950 }
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002951
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002952 /// Find the newest auth token matching the given predicate.
Eric Biggersb5613da2024-03-13 19:31:42 +00002953 pub fn find_auth_token_entry<F>(&self, p: F) -> Option<AuthTokenEntry>
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002954 where
2955 F: Fn(&AuthTokenEntry) -> bool,
2956 {
Eric Biggersb5613da2024-03-13 19:31:42 +00002957 self.perboot.find_auth_token_entry(p)
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002958 }
Pavel Grafovf45034a2021-05-12 22:35:45 +01002959
2960 /// Load descriptor of a key by key id
2961 pub fn load_key_descriptor(&mut self, key_id: i64) -> Result<Option<KeyDescriptor>> {
David Drysdale541846b2024-05-23 13:16:07 +01002962 let _wp = wd::watch("KeystoreDB::load_key_descriptor");
Pavel Grafovf45034a2021-05-12 22:35:45 +01002963
2964 self.with_transaction(TransactionBehavior::Deferred, |tx| {
2965 tx.query_row(
2966 "SELECT domain, namespace, alias FROM persistent.keyentry WHERE id = ?;",
2967 params![key_id],
2968 |row| {
2969 Ok(KeyDescriptor {
2970 domain: Domain(row.get(0)?),
2971 nspace: row.get(1)?,
2972 alias: row.get(2)?,
2973 blob: None,
2974 })
2975 },
2976 )
2977 .optional()
2978 .context("Trying to load key descriptor")
2979 .no_gc()
2980 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002981 .context(ks_err!())
Pavel Grafovf45034a2021-05-12 22:35:45 +01002982 }
Eran Messeri4dc27b52024-01-09 12:43:31 +00002983
2984 /// Returns a list of app UIDs that have keys authenticated by the given secure_user_id
2985 /// (for the given user_id).
2986 /// This is helpful for finding out which apps will have their keys invalidated when
2987 /// the user changes biometrics enrollment or removes their LSKF.
2988 pub fn get_app_uids_affected_by_sid(
2989 &mut self,
2990 user_id: i32,
2991 secure_user_id: i64,
2992 ) -> Result<Vec<i64>> {
David Drysdale541846b2024-05-23 13:16:07 +01002993 let _wp = wd::watch("KeystoreDB::get_app_uids_affected_by_sid");
Eran Messeri4dc27b52024-01-09 12:43:31 +00002994
David Drysdale7b9ca232024-05-23 18:19:46 +01002995 let ids = self.with_transaction(Immediate("TX_get_app_uids_affected_by_sid"), |tx| {
Eran Messeri4dc27b52024-01-09 12:43:31 +00002996 let mut stmt = tx
2997 .prepare(&format!(
2998 "SELECT id, namespace from persistent.keyentry
2999 WHERE key_type = ?
3000 AND domain = ?
3001 AND cast ( (namespace/{AID_USER_OFFSET}) as int) = ?
3002 AND state = ?;",
3003 ))
3004 .context(concat!(
3005 "In get_app_uids_affected_by_sid, ",
3006 "failed to prepare the query to find the keys created by apps."
3007 ))?;
3008
3009 let mut rows = stmt
3010 .query(params![KeyType::Client, Domain::APP.0 as u32, user_id, KeyLifeCycle::Live,])
3011 .context(ks_err!("Failed to query the keys created by apps."))?;
3012
3013 let mut key_ids_and_app_uids: HashMap<i64, i64> = Default::default();
3014 db_utils::with_rows_extract_all(&mut rows, |row| {
3015 key_ids_and_app_uids.insert(
3016 row.get(0).context("Failed to read key id of a key created by an app.")?,
3017 row.get(1).context("Failed to read the app uid")?,
3018 );
3019 Ok(())
3020 })?;
3021 Ok(key_ids_and_app_uids).no_gc()
3022 })?;
3023 let mut app_uids_affected_by_sid: HashSet<i64> = Default::default();
David Drysdale7b9ca232024-05-23 18:19:46 +01003024 for (key_id, app_uid) in ids {
Eran Messeri4dc27b52024-01-09 12:43:31 +00003025 // Read the key parameters for each key in its own transaction. It is OK to ignore
3026 // an error to get the properties of a particular key since it might have been deleted
3027 // under our feet after the previous transaction concluded. If the key was deleted
3028 // then it is no longer applicable if it was auth-bound or not.
3029 if let Ok(is_key_bound_to_sid) =
David Drysdale7b9ca232024-05-23 18:19:46 +01003030 self.with_transaction(Immediate("TX_get_app_uids_affects_by_sid 2"), |tx| {
Eran Messeri4dc27b52024-01-09 12:43:31 +00003031 let params = Self::load_key_parameters(key_id, tx)
3032 .context("Failed to load key parameters.")?;
3033 // Check if the key is bound to this secure user ID.
3034 let is_key_bound_to_sid = params.iter().any(|kp| {
3035 matches!(
3036 kp.key_parameter_value(),
3037 KeyParameterValue::UserSecureID(sid) if *sid == secure_user_id
3038 )
3039 });
3040 Ok(is_key_bound_to_sid).no_gc()
3041 })
3042 {
3043 if is_key_bound_to_sid {
3044 app_uids_affected_by_sid.insert(app_uid);
3045 }
3046 }
3047 }
3048
3049 let app_uids_vec: Vec<i64> = app_uids_affected_by_sid.into_iter().collect();
3050 Ok(app_uids_vec)
3051 }
Joel Galenson26f4d012020-07-17 14:57:21 -07003052}