blob: 34e0c5989d9578f225545c3d4c815aa713a18e70 [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
1166 Ok(persistent_path_str)
1167 }
1168
Matthew Maurerd7815ca2021-05-06 21:58:45 -07001169 fn make_connection(persistent_file: &str) -> Result<Connection> {
Janis Danisevskis4df44f42020-08-26 14:40:03 -07001170 let conn =
1171 Connection::open_in_memory().context("Failed to initialize SQLite connection.")?;
1172
Janis Danisevskis66784c42021-01-27 08:40:25 -08001173 loop {
1174 if let Err(e) = conn
1175 .execute("ATTACH DATABASE ? as persistent;", params![persistent_file])
1176 .context("Failed to attach database persistent.")
1177 {
1178 if Self::is_locked_error(&e) {
David Drysdale115c4722024-04-15 14:11:52 +01001179 std::thread::sleep(DB_BUSY_RETRY_INTERVAL);
Janis Danisevskis66784c42021-01-27 08:40:25 -08001180 continue;
1181 } else {
1182 return Err(e);
1183 }
1184 }
1185 break;
1186 }
Janis Danisevskis4df44f42020-08-26 14:40:03 -07001187
Matthew Maurer4fb19112021-05-06 15:40:44 -07001188 // Drop the cache size from default (2M) to 0.5M
1189 conn.execute("PRAGMA persistent.cache_size = -500;", params![])
1190 .context("Failed to decrease cache size for persistent db")?;
Matthew Maurer4fb19112021-05-06 15:40:44 -07001191
Janis Danisevskis4df44f42020-08-26 14:40:03 -07001192 Ok(conn)
1193 }
1194
Seth Moore78c091f2021-04-09 21:38:30 +00001195 fn do_table_size_query(
1196 &mut self,
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001197 storage_type: MetricsStorage,
Seth Moore78c091f2021-04-09 21:38:30 +00001198 query: &str,
1199 params: &[&str],
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001200 ) -> Result<StorageStats> {
Seth Moore78c091f2021-04-09 21:38:30 +00001201 let (total, unused) = self.with_transaction(TransactionBehavior::Deferred, |tx| {
Joel Galensonff79e362021-05-25 16:30:17 -07001202 tx.query_row(query, params_from_iter(params), |row| Ok((row.get(0)?, row.get(1)?)))
Seth Moore78c091f2021-04-09 21:38:30 +00001203 .with_context(|| {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001204 ks_err!("get_storage_stat: Error size of storage type {}", storage_type.0)
Seth Moore78c091f2021-04-09 21:38:30 +00001205 })
1206 .no_gc()
1207 })?;
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001208 Ok(StorageStats { storage_type, size: total, unused_size: unused })
Seth Moore78c091f2021-04-09 21:38:30 +00001209 }
1210
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001211 fn get_total_size(&mut self) -> Result<StorageStats> {
Seth Moore78c091f2021-04-09 21:38:30 +00001212 self.do_table_size_query(
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001213 MetricsStorage::DATABASE,
Seth Moore78c091f2021-04-09 21:38:30 +00001214 "SELECT page_count * page_size, freelist_count * page_size
1215 FROM pragma_page_count('persistent'),
1216 pragma_page_size('persistent'),
1217 persistent.pragma_freelist_count();",
1218 &[],
1219 )
1220 }
1221
1222 fn get_table_size(
1223 &mut self,
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001224 storage_type: MetricsStorage,
Seth Moore78c091f2021-04-09 21:38:30 +00001225 schema: &str,
1226 table: &str,
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001227 ) -> Result<StorageStats> {
Seth Moore78c091f2021-04-09 21:38:30 +00001228 self.do_table_size_query(
1229 storage_type,
1230 "SELECT pgsize,unused FROM dbstat(?1)
1231 WHERE name=?2 AND aggregate=TRUE;",
1232 &[schema, table],
1233 )
1234 }
1235
David Drysdale0fefae32024-09-16 13:32:27 +01001236 /// Fetches a storage statistics atom for a given storage type. For storage
Seth Moore78c091f2021-04-09 21:38:30 +00001237 /// types that map to a table, information about the table's storage is
1238 /// returned. Requests for storage types that are not DB tables return None.
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001239 pub fn get_storage_stat(&mut self, storage_type: MetricsStorage) -> Result<StorageStats> {
David Drysdale703bcc12024-11-26 14:15:03 +00001240 let _wp = wd::watch_millis_with("KeystoreDB::get_storage_stat", 500, storage_type);
Janis Danisevskis850d4862021-05-05 08:41:14 -07001241
Seth Moore78c091f2021-04-09 21:38:30 +00001242 match storage_type {
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001243 MetricsStorage::DATABASE => self.get_total_size(),
1244 MetricsStorage::KEY_ENTRY => {
Seth Moore78c091f2021-04-09 21:38:30 +00001245 self.get_table_size(storage_type, "persistent", "keyentry")
1246 }
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001247 MetricsStorage::KEY_ENTRY_ID_INDEX => {
Seth Moore78c091f2021-04-09 21:38:30 +00001248 self.get_table_size(storage_type, "persistent", "keyentry_id_index")
1249 }
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001250 MetricsStorage::KEY_ENTRY_DOMAIN_NAMESPACE_INDEX => {
Seth Moore78c091f2021-04-09 21:38:30 +00001251 self.get_table_size(storage_type, "persistent", "keyentry_domain_namespace_index")
1252 }
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001253 MetricsStorage::BLOB_ENTRY => {
Seth Moore78c091f2021-04-09 21:38:30 +00001254 self.get_table_size(storage_type, "persistent", "blobentry")
1255 }
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001256 MetricsStorage::BLOB_ENTRY_KEY_ENTRY_ID_INDEX => {
Seth Moore78c091f2021-04-09 21:38:30 +00001257 self.get_table_size(storage_type, "persistent", "blobentry_keyentryid_index")
1258 }
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001259 MetricsStorage::KEY_PARAMETER => {
Seth Moore78c091f2021-04-09 21:38:30 +00001260 self.get_table_size(storage_type, "persistent", "keyparameter")
1261 }
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001262 MetricsStorage::KEY_PARAMETER_KEY_ENTRY_ID_INDEX => {
Seth Moore78c091f2021-04-09 21:38:30 +00001263 self.get_table_size(storage_type, "persistent", "keyparameter_keyentryid_index")
1264 }
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001265 MetricsStorage::KEY_METADATA => {
Seth Moore78c091f2021-04-09 21:38:30 +00001266 self.get_table_size(storage_type, "persistent", "keymetadata")
1267 }
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001268 MetricsStorage::KEY_METADATA_KEY_ENTRY_ID_INDEX => {
Seth Moore78c091f2021-04-09 21:38:30 +00001269 self.get_table_size(storage_type, "persistent", "keymetadata_keyentryid_index")
1270 }
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001271 MetricsStorage::GRANT => self.get_table_size(storage_type, "persistent", "grant"),
1272 MetricsStorage::AUTH_TOKEN => {
Matthew Maurerd7815ca2021-05-06 21:58:45 -07001273 // Since the table is actually a BTreeMap now, unused_size is not meaningfully
1274 // reportable
1275 // Size provided is only an approximation
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001276 Ok(StorageStats {
Matthew Maurerd7815ca2021-05-06 21:58:45 -07001277 storage_type,
1278 size: (self.perboot.auth_tokens_len() * std::mem::size_of::<AuthTokenEntry>())
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001279 as i32,
Matthew Maurerd7815ca2021-05-06 21:58:45 -07001280 unused_size: 0,
1281 })
Seth Moore78c091f2021-04-09 21:38:30 +00001282 }
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001283 MetricsStorage::BLOB_METADATA => {
Seth Moore78c091f2021-04-09 21:38:30 +00001284 self.get_table_size(storage_type, "persistent", "blobmetadata")
1285 }
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001286 MetricsStorage::BLOB_METADATA_BLOB_ENTRY_ID_INDEX => {
Seth Moore78c091f2021-04-09 21:38:30 +00001287 self.get_table_size(storage_type, "persistent", "blobmetadata_blobentryid_index")
1288 }
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001289 _ => Err(anyhow::Error::msg(format!("Unsupported storage type: {}", storage_type.0))),
Seth Moore78c091f2021-04-09 21:38:30 +00001290 }
1291 }
1292
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001293 /// This function is intended to be used by the garbage collector.
Janis Danisevskis3395f862021-05-06 10:54:17 -07001294 /// It deletes the blobs given by `blob_ids_to_delete`. It then tries to find up to `max_blobs`
1295 /// superseded key blobs that might need special handling by the garbage collector.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001296 /// If no further superseded blobs can be found it deletes all other superseded blobs that don't
1297 /// need special handling and returns None.
Janis Danisevskis3395f862021-05-06 10:54:17 -07001298 pub fn handle_next_superseded_blobs(
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001299 &mut self,
Janis Danisevskis3395f862021-05-06 10:54:17 -07001300 blob_ids_to_delete: &[i64],
1301 max_blobs: usize,
David Drysdalef1ba3812024-05-08 17:50:13 +01001302 ) -> Result<Vec<SupersededBlob>> {
David Drysdale541846b2024-05-23 13:16:07 +01001303 let _wp = wd::watch("KeystoreDB::handle_next_superseded_blob");
David Drysdale7b9ca232024-05-23 18:19:46 +01001304 self.with_transaction(Immediate("TX_handle_next_superseded_blob"), |tx| {
Janis Danisevskis3395f862021-05-06 10:54:17 -07001305 // Delete the given blobs.
1306 for blob_id in blob_ids_to_delete {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001307 tx.execute(
1308 "DELETE FROM persistent.blobmetadata WHERE blobentryid = ?;",
Janis Danisevskis3395f862021-05-06 10:54:17 -07001309 params![blob_id],
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001310 )
Shaquille Johnsonf23fc942024-02-13 17:01:29 +00001311 .context(ks_err!("Trying to delete blob metadata: {:?}", blob_id))?;
Janis Danisevskis3395f862021-05-06 10:54:17 -07001312 tx.execute("DELETE FROM persistent.blobentry WHERE id = ?;", params![blob_id])
Shaquille Johnsonf23fc942024-02-13 17:01:29 +00001313 .context(ks_err!("Trying to delete blob: {:?}", blob_id))?;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001314 }
Janis Danisevskis3cba10d2021-05-06 17:02:19 -07001315
1316 Self::cleanup_unreferenced(tx).context("Trying to cleanup unreferenced.")?;
1317
David Drysdale8da288c2024-07-29 15:57:01 +01001318 // Find up to `max_blobs` more out-of-date key blobs, load their metadata and return it.
1319 let result: Vec<(i64, Vec<u8>)> = if keystore2_flags::use_blob_state_column() {
1320 let _wp = wd::watch("KeystoreDB::handle_next_superseded_blob find_next v2");
1321 let mut stmt = tx
1322 .prepare(
1323 "SELECT id, blob FROM persistent.blobentry
1324 WHERE subcomponent_type = ? AND state != ?
1325 LIMIT ?;",
1326 )
1327 .context("Trying to prepare query for superseded blobs.")?;
1328
1329 let rows = stmt
1330 .query_map(
1331 params![SubComponentType::KEY_BLOB, BlobState::Current, max_blobs as i64],
1332 |row| Ok((row.get(0)?, row.get(1)?)),
1333 )
1334 .context("Trying to query superseded blob.")?;
1335
1336 rows.collect::<Result<Vec<(i64, Vec<u8>)>, rusqlite::Error>>()
1337 .context("Trying to extract superseded blobs.")?
1338 } else {
1339 let _wp = wd::watch("KeystoreDB::handle_next_superseded_blob find_next v1");
Janis Danisevskis3395f862021-05-06 10:54:17 -07001340 let mut stmt = tx
1341 .prepare(
1342 "SELECT id, blob FROM persistent.blobentry
1343 WHERE subcomponent_type = ?
1344 AND (
1345 id NOT IN (
1346 SELECT MAX(id) FROM persistent.blobentry
1347 WHERE subcomponent_type = ?
1348 GROUP BY keyentryid, subcomponent_type
1349 )
1350 OR keyentryid NOT IN (SELECT id FROM persistent.keyentry)
1351 ) LIMIT ?;",
1352 )
1353 .context("Trying to prepare query for superseded blobs.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001354
Janis Danisevskis3395f862021-05-06 10:54:17 -07001355 let rows = stmt
1356 .query_map(
1357 params![
1358 SubComponentType::KEY_BLOB,
1359 SubComponentType::KEY_BLOB,
1360 max_blobs as i64,
1361 ],
1362 |row| Ok((row.get(0)?, row.get(1)?)),
1363 )
1364 .context("Trying to query superseded blob.")?;
1365
1366 rows.collect::<Result<Vec<(i64, Vec<u8>)>, rusqlite::Error>>()
1367 .context("Trying to extract superseded blobs.")?
1368 };
1369
David Drysdalec652f6c2024-07-18 13:01:23 +01001370 let _wp = wd::watch("KeystoreDB::handle_next_superseded_blob load_metadata");
Janis Danisevskis3395f862021-05-06 10:54:17 -07001371 let result = result
1372 .into_iter()
1373 .map(|(blob_id, blob)| {
David Drysdalef1ba3812024-05-08 17:50:13 +01001374 Ok(SupersededBlob {
1375 blob_id,
1376 blob,
1377 metadata: BlobMetaData::load_from_db(blob_id, tx)?,
1378 })
Janis Danisevskis3395f862021-05-06 10:54:17 -07001379 })
David Drysdalef1ba3812024-05-08 17:50:13 +01001380 .collect::<Result<Vec<_>>>()
Janis Danisevskis3395f862021-05-06 10:54:17 -07001381 .context("Trying to load blob metadata.")?;
1382 if !result.is_empty() {
1383 return Ok(result).no_gc();
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001384 }
1385
David Drysdale8da288c2024-07-29 15:57:01 +01001386 // We did not find any out-of-date key blobs, so let's remove other types of superseded
1387 // blob in one transaction.
1388 if keystore2_flags::use_blob_state_column() {
1389 let _wp = wd::watch("KeystoreDB::handle_next_superseded_blob delete v2");
1390 tx.execute(
1391 "DELETE FROM persistent.blobentry
1392 WHERE subcomponent_type != ? AND state != ?;",
1393 params![SubComponentType::KEY_BLOB, BlobState::Current],
1394 )
1395 .context("Trying to purge out-of-date blobs (other than keyblobs)")?;
1396 } else {
1397 let _wp = wd::watch("KeystoreDB::handle_next_superseded_blob delete v1");
1398 tx.execute(
1399 "DELETE FROM persistent.blobentry
1400 WHERE NOT subcomponent_type = ?
1401 AND (
1402 id NOT IN (
1403 SELECT MAX(id) FROM persistent.blobentry
1404 WHERE NOT subcomponent_type = ?
1405 GROUP BY keyentryid, subcomponent_type
1406 ) OR keyentryid NOT IN (SELECT id FROM persistent.keyentry)
1407 );",
1408 params![SubComponentType::KEY_BLOB, SubComponentType::KEY_BLOB],
1409 )
1410 .context("Trying to purge superseded blobs.")?;
1411 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001412
Janis Danisevskis3395f862021-05-06 10:54:17 -07001413 Ok(vec![]).no_gc()
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001414 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001415 .context(ks_err!())
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001416 }
1417
1418 /// This maintenance function should be called only once before the database is used for the
1419 /// first time. It restores the invariant that `KeyLifeCycle::Existing` is a transient state.
1420 /// The function transitions all key entries from Existing to Unreferenced unconditionally and
1421 /// returns the number of rows affected. If this returns a value greater than 0, it means that
1422 /// Keystore crashed at some point during key generation. Callers may want to log such
1423 /// occurrences.
1424 /// Unlike with `mark_unreferenced`, we don't need to purge grants, because only keys that made
1425 /// it to `KeyLifeCycle::Live` may have grants.
1426 pub fn cleanup_leftovers(&mut self) -> Result<usize> {
David Drysdale541846b2024-05-23 13:16:07 +01001427 let _wp = wd::watch("KeystoreDB::cleanup_leftovers");
Janis Danisevskis850d4862021-05-05 08:41:14 -07001428
David Drysdale7b9ca232024-05-23 18:19:46 +01001429 self.with_transaction(Immediate("TX_cleanup_leftovers"), |tx| {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001430 tx.execute(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001431 "UPDATE persistent.keyentry SET state = ? WHERE state = ?;",
1432 params![KeyLifeCycle::Unreferenced, KeyLifeCycle::Existing],
1433 )
Janis Danisevskis66784c42021-01-27 08:40:25 -08001434 .context("Failed to execute query.")
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001435 .need_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08001436 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001437 .context(ks_err!())
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001438 }
1439
Hasini Gunasinghe0e161452021-01-27 19:34:37 +00001440 /// Checks if a key exists with given key type and key descriptor properties.
1441 pub fn key_exists(
1442 &mut self,
1443 domain: Domain,
1444 nspace: i64,
1445 alias: &str,
1446 key_type: KeyType,
1447 ) -> Result<bool> {
David Drysdale541846b2024-05-23 13:16:07 +01001448 let _wp = wd::watch("KeystoreDB::key_exists");
Janis Danisevskis850d4862021-05-05 08:41:14 -07001449
David Drysdale7b9ca232024-05-23 18:19:46 +01001450 self.with_transaction(Immediate("TX_key_exists"), |tx| {
Hasini Gunasinghe0e161452021-01-27 19:34:37 +00001451 let key_descriptor =
1452 KeyDescriptor { domain, nspace, alias: Some(alias.to_string()), blob: None };
Chris Wailesd5aaaef2021-07-27 16:04:33 -07001453 let result = Self::load_key_entry_id(tx, &key_descriptor, key_type);
Hasini Gunasinghe0e161452021-01-27 19:34:37 +00001454 match result {
1455 Ok(_) => Ok(true),
1456 Err(error) => match error.root_cause().downcast_ref::<KsError>() {
1457 Some(KsError::Rc(ResponseCode::KEY_NOT_FOUND)) => Ok(false),
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001458 _ => Err(error).context(ks_err!("Failed to find if the key exists.")),
Hasini Gunasinghe0e161452021-01-27 19:34:37 +00001459 },
1460 }
1461 .no_gc()
1462 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001463 .context(ks_err!())
Hasini Gunasinghe0e161452021-01-27 19:34:37 +00001464 }
1465
Hasini Gunasingheda895552021-01-27 19:34:37 +00001466 /// Stores a super key in the database.
1467 pub fn store_super_key(
1468 &mut self,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +00001469 user_id: u32,
Paul Crowley7a658392021-03-18 17:08:20 -07001470 key_type: &SuperKeyType,
1471 blob: &[u8],
1472 blob_metadata: &BlobMetaData,
Paul Crowley8d5b2532021-03-19 10:53:07 -07001473 key_metadata: &KeyMetaData,
Hasini Gunasingheda895552021-01-27 19:34:37 +00001474 ) -> Result<KeyEntry> {
David Drysdale541846b2024-05-23 13:16:07 +01001475 let _wp = wd::watch("KeystoreDB::store_super_key");
Janis Danisevskis850d4862021-05-05 08:41:14 -07001476
David Drysdale7b9ca232024-05-23 18:19:46 +01001477 self.with_transaction(Immediate("TX_store_super_key"), |tx| {
Hasini Gunasingheda895552021-01-27 19:34:37 +00001478 let key_id = Self::insert_with_retry(|id| {
1479 tx.execute(
1480 "INSERT into persistent.keyentry
1481 (id, key_type, domain, namespace, alias, state, km_uuid)
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00001482 VALUES(?, ?, ?, ?, ?, ?, ?);",
Hasini Gunasingheda895552021-01-27 19:34:37 +00001483 params![
1484 id,
1485 KeyType::Super,
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00001486 Domain::APP.0,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +00001487 user_id as i64,
Paul Crowley7a658392021-03-18 17:08:20 -07001488 key_type.alias,
Hasini Gunasingheda895552021-01-27 19:34:37 +00001489 KeyLifeCycle::Live,
1490 &KEYSTORE_UUID,
1491 ],
1492 )
1493 })
1494 .context("Failed to insert into keyentry table.")?;
1495
Paul Crowley8d5b2532021-03-19 10:53:07 -07001496 key_metadata.store_in_db(key_id, tx).context("KeyMetaData::store_in_db failed")?;
1497
Hasini Gunasingheda895552021-01-27 19:34:37 +00001498 Self::set_blob_internal(
Chris Wailesd5aaaef2021-07-27 16:04:33 -07001499 tx,
Hasini Gunasingheda895552021-01-27 19:34:37 +00001500 key_id,
1501 SubComponentType::KEY_BLOB,
1502 Some(blob),
1503 Some(blob_metadata),
1504 )
1505 .context("Failed to store key blob.")?;
1506
1507 Self::load_key_components(tx, KeyEntryLoadBits::KM, key_id)
1508 .context("Trying to load key components.")
1509 .no_gc()
1510 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001511 .context(ks_err!())
Hasini Gunasingheda895552021-01-27 19:34:37 +00001512 }
1513
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +00001514 /// Loads super key of a given user, if exists
Paul Crowley7a658392021-03-18 17:08:20 -07001515 pub fn load_super_key(
1516 &mut self,
1517 key_type: &SuperKeyType,
1518 user_id: u32,
1519 ) -> Result<Option<(KeyIdGuard, KeyEntry)>> {
David Drysdale541846b2024-05-23 13:16:07 +01001520 let _wp = wd::watch("KeystoreDB::load_super_key");
Janis Danisevskis850d4862021-05-05 08:41:14 -07001521
David Drysdale7b9ca232024-05-23 18:19:46 +01001522 self.with_transaction(Immediate("TX_load_super_key"), |tx| {
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +00001523 let key_descriptor = KeyDescriptor {
1524 domain: Domain::APP,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +00001525 nspace: user_id as i64,
Paul Crowley7a658392021-03-18 17:08:20 -07001526 alias: Some(key_type.alias.into()),
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +00001527 blob: None,
1528 };
Chris Wailesd5aaaef2021-07-27 16:04:33 -07001529 let id = Self::load_key_entry_id(tx, &key_descriptor, KeyType::Super);
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +00001530 match id {
1531 Ok(id) => {
Chris Wailesd5aaaef2021-07-27 16:04:33 -07001532 let key_entry = Self::load_key_components(tx, KeyEntryLoadBits::KM, id)
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001533 .context(ks_err!("Failed to load key entry."))?;
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +00001534 Ok(Some((KEY_ID_LOCK.get(id), key_entry)))
1535 }
1536 Err(error) => match error.root_cause().downcast_ref::<KsError>() {
1537 Some(KsError::Rc(ResponseCode::KEY_NOT_FOUND)) => Ok(None),
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001538 _ => Err(error).context(ks_err!()),
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +00001539 },
1540 }
1541 .no_gc()
1542 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001543 .context(ks_err!())
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +00001544 }
1545
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001546 /// Creates a transaction with the given behavior and executes f with the new transaction.
Janis Danisevskis66784c42021-01-27 08:40:25 -08001547 /// The transaction is committed only if f returns Ok and retried if DatabaseBusy
1548 /// or DatabaseLocked is encountered.
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001549 fn with_transaction<T, F>(&mut self, behavior: TransactionBehavior, f: F) -> Result<T>
1550 where
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001551 F: Fn(&Transaction) -> Result<(bool, T)>,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001552 {
David Drysdale7b9ca232024-05-23 18:19:46 +01001553 let name = behavior.name();
Janis Danisevskis66784c42021-01-27 08:40:25 -08001554 loop {
James Farrellefe1a2f2024-02-28 21:36:47 +00001555 let result = self
Janis Danisevskis66784c42021-01-27 08:40:25 -08001556 .conn
David Drysdale7b9ca232024-05-23 18:19:46 +01001557 .transaction_with_behavior(behavior.into())
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001558 .context(ks_err!())
David Drysdale7b9ca232024-05-23 18:19:46 +01001559 .and_then(|tx| {
1560 let _wp = name.map(wd::watch);
1561 f(&tx).map(|result| (result, tx))
1562 })
Janis Danisevskis66784c42021-01-27 08:40:25 -08001563 .and_then(|(result, tx)| {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001564 tx.commit().context(ks_err!("Failed to commit transaction."))?;
Janis Danisevskis66784c42021-01-27 08:40:25 -08001565 Ok(result)
James Farrellefe1a2f2024-02-28 21:36:47 +00001566 });
1567 match result {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001568 Ok(result) => break Ok(result),
1569 Err(e) => {
1570 if Self::is_locked_error(&e) {
David Drysdale115c4722024-04-15 14:11:52 +01001571 std::thread::sleep(DB_BUSY_RETRY_INTERVAL);
Janis Danisevskis66784c42021-01-27 08:40:25 -08001572 continue;
1573 } else {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001574 return Err(e).context(ks_err!());
Janis Danisevskis66784c42021-01-27 08:40:25 -08001575 }
1576 }
1577 }
1578 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001579 .map(|(need_gc, result)| {
1580 if need_gc {
1581 if let Some(ref gc) = self.gc {
1582 gc.notify_gc();
1583 }
1584 }
1585 result
1586 })
Janis Danisevskis66784c42021-01-27 08:40:25 -08001587 }
1588
1589 fn is_locked_error(e: &anyhow::Error) -> bool {
Paul Crowleyf61fee72021-03-17 14:38:44 -07001590 matches!(
1591 e.root_cause().downcast_ref::<rusqlite::ffi::Error>(),
1592 Some(rusqlite::ffi::Error { code: rusqlite::ErrorCode::DatabaseBusy, .. })
1593 | Some(rusqlite::ffi::Error { code: rusqlite::ErrorCode::DatabaseLocked, .. })
1594 )
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001595 }
1596
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001597 fn create_key_entry_internal(
1598 tx: &Transaction,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001599 domain: &Domain,
1600 namespace: &i64,
Janis Danisevskis0cabd712021-05-25 11:07:10 -07001601 key_type: KeyType,
Max Bires8e93d2b2021-01-14 13:17:59 -08001602 km_uuid: &Uuid,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001603 ) -> Result<KeyIdGuard> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001604 match *domain {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001605 Domain::APP | Domain::SELINUX => {}
Joel Galenson0891bc12020-07-20 10:37:03 -07001606 _ => {
1607 return Err(KsError::sys())
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001608 .context(ks_err!("Domain {:?} must be either App or SELinux.", domain));
Joel Galenson0891bc12020-07-20 10:37:03 -07001609 }
1610 }
Janis Danisevskisaec14592020-11-12 09:41:49 -08001611 Ok(KEY_ID_LOCK.get(
1612 Self::insert_with_retry(|id| {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001613 tx.execute(
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001614 "INSERT into persistent.keyentry
Max Bires8e93d2b2021-01-14 13:17:59 -08001615 (id, key_type, domain, namespace, alias, state, km_uuid)
1616 VALUES(?, ?, ?, ?, NULL, ?, ?);",
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001617 params![
1618 id,
Janis Danisevskis0cabd712021-05-25 11:07:10 -07001619 key_type,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001620 domain.0 as u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001621 *namespace,
Max Bires8e93d2b2021-01-14 13:17:59 -08001622 KeyLifeCycle::Existing,
1623 km_uuid,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001624 ],
Janis Danisevskisaec14592020-11-12 09:41:49 -08001625 )
1626 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001627 .context(ks_err!())?,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001628 ))
Joel Galenson26f4d012020-07-17 14:57:21 -07001629 }
Joel Galenson33c04ad2020-08-03 11:04:38 -07001630
Janis Danisevskis377d1002021-01-27 19:07:48 -08001631 /// Set a new blob and associates it with the given key id. Each blob
1632 /// has a sub component type.
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001633 /// Each key can have one of each sub component type associated. If more
1634 /// are added only the most recent can be retrieved, and superseded blobs
Janis Danisevskis377d1002021-01-27 19:07:48 -08001635 /// will get garbage collected.
1636 /// Components SubComponentType::CERT and SubComponentType::CERT_CHAIN can be
1637 /// removed by setting blob to None.
1638 pub fn set_blob(
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001639 &mut self,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001640 key_id: &KeyIdGuard,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001641 sc_type: SubComponentType,
Janis Danisevskis377d1002021-01-27 19:07:48 -08001642 blob: Option<&[u8]>,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001643 blob_metadata: Option<&BlobMetaData>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001644 ) -> Result<()> {
David Drysdale541846b2024-05-23 13:16:07 +01001645 let _wp = wd::watch("KeystoreDB::set_blob");
Janis Danisevskis850d4862021-05-05 08:41:14 -07001646
David Drysdale7b9ca232024-05-23 18:19:46 +01001647 self.with_transaction(Immediate("TX_set_blob"), |tx| {
Chris Wailesd5aaaef2021-07-27 16:04:33 -07001648 Self::set_blob_internal(tx, key_id.0, sc_type, blob, blob_metadata).need_gc()
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001649 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001650 .context(ks_err!())
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001651 }
1652
Janis Danisevskiseed69842021-02-18 20:04:10 -08001653 /// Why would we insert a deleted blob? This weird function is for the purpose of legacy
1654 /// key migration in the case where we bulk delete all the keys of an app or even a user.
1655 /// We use this to insert key blobs into the database which can then be garbage collected
1656 /// lazily by the key garbage collector.
1657 pub fn set_deleted_blob(&mut self, blob: &[u8], blob_metadata: &BlobMetaData) -> Result<()> {
David Drysdale541846b2024-05-23 13:16:07 +01001658 let _wp = wd::watch("KeystoreDB::set_deleted_blob");
Janis Danisevskis850d4862021-05-05 08:41:14 -07001659
David Drysdale7b9ca232024-05-23 18:19:46 +01001660 self.with_transaction(Immediate("TX_set_deleted_blob"), |tx| {
Janis Danisevskiseed69842021-02-18 20:04:10 -08001661 Self::set_blob_internal(
Chris Wailesd5aaaef2021-07-27 16:04:33 -07001662 tx,
Janis Danisevskiseed69842021-02-18 20:04:10 -08001663 Self::UNASSIGNED_KEY_ID,
1664 SubComponentType::KEY_BLOB,
1665 Some(blob),
1666 Some(blob_metadata),
1667 )
1668 .need_gc()
1669 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001670 .context(ks_err!())
Janis Danisevskiseed69842021-02-18 20:04:10 -08001671 }
1672
Janis Danisevskis377d1002021-01-27 19:07:48 -08001673 fn set_blob_internal(
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001674 tx: &Transaction,
1675 key_id: i64,
1676 sc_type: SubComponentType,
Janis Danisevskis377d1002021-01-27 19:07:48 -08001677 blob: Option<&[u8]>,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001678 blob_metadata: Option<&BlobMetaData>,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001679 ) -> Result<()> {
Janis Danisevskis377d1002021-01-27 19:07:48 -08001680 match (blob, sc_type) {
1681 (Some(blob), _) => {
David Drysdale8da288c2024-07-29 15:57:01 +01001682 // Mark any previous blobentry(s) of the same type for the same key as superseded.
1683 tx.execute(
1684 "UPDATE persistent.blobentry SET state = ?
1685 WHERE keyentryid = ? AND subcomponent_type = ?",
1686 params![BlobState::Superseded, key_id, sc_type],
1687 )
1688 .context(ks_err!(
1689 "Failed to mark prior {sc_type:?} blobentrys for {key_id} as superseded"
1690 ))?;
1691
1692 // Now insert the new, un-superseded, blob. (If this fails, the marking of
1693 // old blobs as superseded will be rolled back, because we're inside a
1694 // transaction.)
Janis Danisevskis377d1002021-01-27 19:07:48 -08001695 tx.execute(
1696 "INSERT INTO persistent.blobentry
1697 (subcomponent_type, keyentryid, blob) VALUES (?, ?, ?);",
1698 params![sc_type, key_id, blob],
1699 )
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001700 .context(ks_err!("Failed to insert blob."))?;
David Drysdale8da288c2024-07-29 15:57:01 +01001701
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001702 if let Some(blob_metadata) = blob_metadata {
1703 let blob_id = tx
Andrew Walbran78abb1e2023-05-30 16:20:56 +00001704 .query_row("SELECT MAX(id) FROM persistent.blobentry;", [], |row| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001705 row.get(0)
1706 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001707 .context(ks_err!("Failed to get new blob id."))?;
David Drysdale8da288c2024-07-29 15:57:01 +01001708
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001709 blob_metadata
1710 .store_in_db(blob_id, tx)
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001711 .context(ks_err!("Trying to store blob metadata."))?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001712 }
Janis Danisevskis377d1002021-01-27 19:07:48 -08001713 }
1714 (None, SubComponentType::CERT) | (None, SubComponentType::CERT_CHAIN) => {
1715 tx.execute(
1716 "DELETE FROM persistent.blobentry
1717 WHERE subcomponent_type = ? AND keyentryid = ?;",
1718 params![sc_type, key_id],
1719 )
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001720 .context(ks_err!("Failed to delete blob."))?;
Janis Danisevskis377d1002021-01-27 19:07:48 -08001721 }
1722 (None, _) => {
1723 return Err(KsError::sys())
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001724 .context(ks_err!("Other blobs cannot be deleted in this way."));
Janis Danisevskis377d1002021-01-27 19:07:48 -08001725 }
1726 }
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001727 Ok(())
1728 }
1729
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001730 /// Inserts a collection of key parameters into the `persistent.keyparameter` table
1731 /// and associates them with the given `key_id`.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001732 #[cfg(test)]
1733 fn insert_keyparameter(&mut self, key_id: &KeyIdGuard, params: &[KeyParameter]) -> Result<()> {
David Drysdale7b9ca232024-05-23 18:19:46 +01001734 self.with_transaction(Immediate("TX_insert_keyparameter"), |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001735 Self::insert_keyparameter_internal(tx, key_id, params).no_gc()
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001736 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001737 .context(ks_err!())
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001738 }
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001739
Janis Danisevskis66784c42021-01-27 08:40:25 -08001740 fn insert_keyparameter_internal(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001741 tx: &Transaction,
1742 key_id: &KeyIdGuard,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001743 params: &[KeyParameter],
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001744 ) -> Result<()> {
1745 let mut stmt = tx
1746 .prepare(
1747 "INSERT into persistent.keyparameter (keyentryid, tag, data, security_level)
1748 VALUES (?, ?, ?, ?);",
1749 )
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001750 .context(ks_err!("Failed to prepare statement."))?;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001751
Janis Danisevskis66784c42021-01-27 08:40:25 -08001752 for p in params.iter() {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001753 stmt.insert(params![
1754 key_id.0,
1755 p.get_tag().0,
1756 p.key_parameter_value(),
1757 p.security_level().0
1758 ])
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001759 .with_context(|| ks_err!("Failed to insert {:?}", p))?;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001760 }
1761 Ok(())
1762 }
1763
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001764 /// Insert a set of key entry specific metadata into the database.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001765 #[cfg(test)]
1766 fn insert_key_metadata(&mut self, key_id: &KeyIdGuard, metadata: &KeyMetaData) -> Result<()> {
David Drysdale7b9ca232024-05-23 18:19:46 +01001767 self.with_transaction(Immediate("TX_insert_key_metadata"), |tx| {
Chris Wailesd5aaaef2021-07-27 16:04:33 -07001768 metadata.store_in_db(key_id.0, tx).no_gc()
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001769 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001770 .context(ks_err!())
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001771 }
1772
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001773 /// Updates the alias column of the given key id `newid` with the given alias,
1774 /// and atomically, removes the alias, domain, and namespace from another row
1775 /// with the same alias-domain-namespace tuple if such row exits.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001776 /// Returns Ok(true) if an old key was marked unreferenced as a hint to the garbage
1777 /// collector.
1778 fn rebind_alias(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001779 tx: &Transaction,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001780 newid: &KeyIdGuard,
Joel Galenson33c04ad2020-08-03 11:04:38 -07001781 alias: &str,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001782 domain: &Domain,
1783 namespace: &i64,
Janis Danisevskis0cabd712021-05-25 11:07:10 -07001784 key_type: KeyType,
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001785 ) -> Result<bool> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001786 match *domain {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001787 Domain::APP | Domain::SELINUX => {}
Joel Galenson33c04ad2020-08-03 11:04:38 -07001788 _ => {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001789 return Err(KsError::sys())
1790 .context(ks_err!("Domain {:?} must be either App or SELinux.", domain));
Joel Galenson33c04ad2020-08-03 11:04:38 -07001791 }
1792 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001793 let updated = tx
1794 .execute(
1795 "UPDATE persistent.keyentry
1796 SET alias = NULL, domain = NULL, namespace = NULL, state = ?
Janis Danisevskis0cabd712021-05-25 11:07:10 -07001797 WHERE alias = ? AND domain = ? AND namespace = ? AND key_type = ?;",
1798 params![KeyLifeCycle::Unreferenced, alias, domain.0 as u32, namespace, key_type],
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001799 )
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001800 .context(ks_err!("Failed to rebind existing entry."))?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07001801 let result = tx
1802 .execute(
1803 "UPDATE persistent.keyentry
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001804 SET alias = ?, state = ?
Janis Danisevskis0cabd712021-05-25 11:07:10 -07001805 WHERE id = ? AND domain = ? AND namespace = ? AND state = ? AND key_type = ?;",
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001806 params![
1807 alias,
1808 KeyLifeCycle::Live,
1809 newid.0,
1810 domain.0 as u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001811 *namespace,
Max Bires8e93d2b2021-01-14 13:17:59 -08001812 KeyLifeCycle::Existing,
Janis Danisevskis0cabd712021-05-25 11:07:10 -07001813 key_type,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001814 ],
Joel Galenson33c04ad2020-08-03 11:04:38 -07001815 )
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001816 .context(ks_err!("Failed to set alias."))?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07001817 if result != 1 {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001818 return Err(KsError::sys()).context(ks_err!(
1819 "Expected to update a single entry but instead updated {}.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07001820 result
1821 ));
1822 }
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001823 Ok(updated != 0)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001824 }
1825
Janis Danisevskiscdcf4e52021-04-14 15:44:36 -07001826 /// Moves the key given by KeyIdGuard to the new location at `destination`. If the destination
1827 /// is already occupied by a key, this function fails with `ResponseCode::INVALID_ARGUMENT`.
1828 pub fn migrate_key_namespace(
1829 &mut self,
1830 key_id_guard: KeyIdGuard,
1831 destination: &KeyDescriptor,
1832 caller_uid: u32,
1833 check_permission: impl Fn(&KeyDescriptor) -> Result<()>,
1834 ) -> Result<()> {
David Drysdale541846b2024-05-23 13:16:07 +01001835 let _wp = wd::watch("KeystoreDB::migrate_key_namespace");
Janis Danisevskis850d4862021-05-05 08:41:14 -07001836
Janis Danisevskiscdcf4e52021-04-14 15:44:36 -07001837 let destination = match destination.domain {
1838 Domain::APP => KeyDescriptor { nspace: caller_uid as i64, ..(*destination).clone() },
1839 Domain::SELINUX => (*destination).clone(),
1840 domain => {
1841 return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT))
1842 .context(format!("Domain {:?} must be either APP or SELINUX.", domain));
1843 }
1844 };
1845
1846 // Security critical: Must return immediately on failure. Do not remove the '?';
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001847 check_permission(&destination).context(ks_err!("Trying to check permission."))?;
Janis Danisevskiscdcf4e52021-04-14 15:44:36 -07001848
1849 let alias = destination
1850 .alias
1851 .as_ref()
1852 .ok_or(KsError::Rc(ResponseCode::INVALID_ARGUMENT))
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001853 .context(ks_err!("Alias must be specified."))?;
Janis Danisevskiscdcf4e52021-04-14 15:44:36 -07001854
David Drysdale7b9ca232024-05-23 18:19:46 +01001855 self.with_transaction(Immediate("TX_migrate_key_namespace"), |tx| {
Janis Danisevskiscdcf4e52021-04-14 15:44:36 -07001856 // Query the destination location. If there is a key, the migration request fails.
1857 if tx
1858 .query_row(
1859 "SELECT id FROM persistent.keyentry
1860 WHERE alias = ? AND domain = ? AND namespace = ?;",
1861 params![alias, destination.domain.0, destination.nspace],
1862 |_| Ok(()),
1863 )
1864 .optional()
1865 .context("Failed to query destination.")?
1866 .is_some()
1867 {
1868 return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT))
1869 .context("Target already exists.");
1870 }
1871
1872 let updated = tx
1873 .execute(
1874 "UPDATE persistent.keyentry
1875 SET alias = ?, domain = ?, namespace = ?
1876 WHERE id = ?;",
1877 params![alias, destination.domain.0, destination.nspace, key_id_guard.id()],
1878 )
1879 .context("Failed to update key entry.")?;
1880
1881 if updated != 1 {
1882 return Err(KsError::sys())
1883 .context(format!("Update succeeded, but {} rows were updated.", updated));
1884 }
1885 Ok(()).no_gc()
1886 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001887 .context(ks_err!())
Janis Danisevskiscdcf4e52021-04-14 15:44:36 -07001888 }
1889
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001890 /// Store a new key in a single transaction.
1891 /// The function creates a new key entry, populates the blob, key parameter, and metadata
1892 /// fields, and rebinds the given alias to the new key.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001893 /// The boolean returned is a hint for the garbage collector. If true, a key was replaced,
1894 /// is now unreferenced and needs to be collected.
Chris Wailes3877f292021-07-26 19:24:18 -07001895 #[allow(clippy::too_many_arguments)]
Janis Danisevskis66784c42021-01-27 08:40:25 -08001896 pub fn store_new_key(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001897 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001898 key: &KeyDescriptor,
Janis Danisevskis0cabd712021-05-25 11:07:10 -07001899 key_type: KeyType,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001900 params: &[KeyParameter],
Janis Danisevskisf84d0b02022-01-26 14:11:14 -08001901 blob_info: &BlobInfo,
Max Bires8e93d2b2021-01-14 13:17:59 -08001902 cert_info: &CertificateInfo,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001903 metadata: &KeyMetaData,
Max Bires8e93d2b2021-01-14 13:17:59 -08001904 km_uuid: &Uuid,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001905 ) -> Result<KeyIdGuard> {
David Drysdale541846b2024-05-23 13:16:07 +01001906 let _wp = wd::watch("KeystoreDB::store_new_key");
Janis Danisevskis850d4862021-05-05 08:41:14 -07001907
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001908 let (alias, domain, namespace) = match key {
1909 KeyDescriptor { alias: Some(alias), domain: Domain::APP, nspace, blob: None }
1910 | KeyDescriptor { alias: Some(alias), domain: Domain::SELINUX, nspace, blob: None } => {
1911 (alias, key.domain, nspace)
1912 }
1913 _ => {
1914 return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT))
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001915 .context(ks_err!("Need alias and domain must be APP or SELINUX."));
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001916 }
1917 };
David Drysdale7b9ca232024-05-23 18:19:46 +01001918 self.with_transaction(Immediate("TX_store_new_key"), |tx| {
Janis Danisevskis0cabd712021-05-25 11:07:10 -07001919 let key_id = Self::create_key_entry_internal(tx, &domain, namespace, key_type, km_uuid)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001920 .context("Trying to create new key entry.")?;
Janis Danisevskisf84d0b02022-01-26 14:11:14 -08001921 let BlobInfo { blob, metadata: blob_metadata, superseded_blob } = *blob_info;
1922
1923 // In some occasions the key blob is already upgraded during the import.
1924 // In order to make sure it gets properly deleted it is inserted into the
1925 // database here and then immediately replaced by the superseding blob.
1926 // The garbage collector will then subject the blob to deleteKey of the
1927 // KM back end to permanently invalidate the key.
1928 let need_gc = if let Some((blob, blob_metadata)) = superseded_blob {
1929 Self::set_blob_internal(
1930 tx,
1931 key_id.id(),
1932 SubComponentType::KEY_BLOB,
1933 Some(blob),
1934 Some(blob_metadata),
1935 )
1936 .context("Trying to insert superseded key blob.")?;
1937 true
1938 } else {
1939 false
1940 };
1941
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001942 Self::set_blob_internal(
1943 tx,
1944 key_id.id(),
1945 SubComponentType::KEY_BLOB,
1946 Some(blob),
Chris Wailesd5aaaef2021-07-27 16:04:33 -07001947 Some(blob_metadata),
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001948 )
1949 .context("Trying to insert the key blob.")?;
Max Bires8e93d2b2021-01-14 13:17:59 -08001950 if let Some(cert) = &cert_info.cert {
Chris Wailesd5aaaef2021-07-27 16:04:33 -07001951 Self::set_blob_internal(tx, key_id.id(), SubComponentType::CERT, Some(cert), None)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001952 .context("Trying to insert the certificate.")?;
1953 }
Max Bires8e93d2b2021-01-14 13:17:59 -08001954 if let Some(cert_chain) = &cert_info.cert_chain {
Janis Danisevskis377d1002021-01-27 19:07:48 -08001955 Self::set_blob_internal(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001956 tx,
1957 key_id.id(),
1958 SubComponentType::CERT_CHAIN,
Chris Wailesd5aaaef2021-07-27 16:04:33 -07001959 Some(cert_chain),
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001960 None,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001961 )
1962 .context("Trying to insert the certificate chain.")?;
1963 }
1964 Self::insert_keyparameter_internal(tx, &key_id, params)
1965 .context("Trying to insert key parameters.")?;
Janis Danisevskis377d1002021-01-27 19:07:48 -08001966 metadata.store_in_db(key_id.id(), tx).context("Trying to insert key metadata.")?;
Chris Wailesd5aaaef2021-07-27 16:04:33 -07001967 let need_gc = Self::rebind_alias(tx, &key_id, alias, &domain, namespace, key_type)
Janis Danisevskisf84d0b02022-01-26 14:11:14 -08001968 .context("Trying to rebind alias.")?
1969 || need_gc;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001970 Ok(key_id).do_gc(need_gc)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001971 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001972 .context(ks_err!())
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001973 }
1974
Janis Danisevskis377d1002021-01-27 19:07:48 -08001975 /// Store a new certificate
1976 /// The function creates a new key entry, populates the blob field and metadata, and rebinds
1977 /// the given alias to the new cert.
Max Bires8e93d2b2021-01-14 13:17:59 -08001978 pub fn store_new_certificate(
1979 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001980 key: &KeyDescriptor,
Janis Danisevskis0cabd712021-05-25 11:07:10 -07001981 key_type: KeyType,
Max Bires8e93d2b2021-01-14 13:17:59 -08001982 cert: &[u8],
1983 km_uuid: &Uuid,
1984 ) -> Result<KeyIdGuard> {
David Drysdale541846b2024-05-23 13:16:07 +01001985 let _wp = wd::watch("KeystoreDB::store_new_certificate");
Janis Danisevskis850d4862021-05-05 08:41:14 -07001986
Janis Danisevskis377d1002021-01-27 19:07:48 -08001987 let (alias, domain, namespace) = match key {
1988 KeyDescriptor { alias: Some(alias), domain: Domain::APP, nspace, blob: None }
1989 | KeyDescriptor { alias: Some(alias), domain: Domain::SELINUX, nspace, blob: None } => {
1990 (alias, key.domain, nspace)
1991 }
1992 _ => {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001993 return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT))
1994 .context(ks_err!("Need alias and domain must be APP or SELINUX."));
Janis Danisevskis377d1002021-01-27 19:07:48 -08001995 }
1996 };
David Drysdale7b9ca232024-05-23 18:19:46 +01001997 self.with_transaction(Immediate("TX_store_new_certificate"), |tx| {
Janis Danisevskis0cabd712021-05-25 11:07:10 -07001998 let key_id = Self::create_key_entry_internal(tx, &domain, namespace, key_type, km_uuid)
Janis Danisevskis377d1002021-01-27 19:07:48 -08001999 .context("Trying to create new key entry.")?;
2000
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002001 Self::set_blob_internal(
2002 tx,
2003 key_id.id(),
2004 SubComponentType::CERT_CHAIN,
2005 Some(cert),
2006 None,
2007 )
2008 .context("Trying to insert certificate.")?;
Janis Danisevskis377d1002021-01-27 19:07:48 -08002009
2010 let mut metadata = KeyMetaData::new();
2011 metadata.add(KeyMetaEntry::CreationDate(
2012 DateTime::now().context("Trying to make creation time.")?,
2013 ));
2014
2015 metadata.store_in_db(key_id.id(), tx).context("Trying to insert key metadata.")?;
2016
Chris Wailesd5aaaef2021-07-27 16:04:33 -07002017 let need_gc = Self::rebind_alias(tx, &key_id, alias, &domain, namespace, key_type)
Janis Danisevskis377d1002021-01-27 19:07:48 -08002018 .context("Trying to rebind alias.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002019 Ok(key_id).do_gc(need_gc)
Janis Danisevskis377d1002021-01-27 19:07:48 -08002020 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002021 .context(ks_err!())
Janis Danisevskis377d1002021-01-27 19:07:48 -08002022 }
2023
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002024 // Helper function loading the key_id given the key descriptor
2025 // tuple comprising domain, namespace, and alias.
2026 // Requires a valid transaction.
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002027 fn load_key_entry_id(tx: &Transaction, key: &KeyDescriptor, key_type: KeyType) -> Result<i64> {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002028 let alias = key
2029 .alias
2030 .as_ref()
2031 .map_or_else(|| Err(KsError::sys()), Ok)
2032 .context("In load_key_entry_id: Alias must be specified.")?;
2033 let mut stmt = tx
2034 .prepare(
2035 "SELECT id FROM persistent.keyentry
2036 WHERE
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00002037 key_type = ?
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002038 AND domain = ?
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002039 AND namespace = ?
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002040 AND alias = ?
2041 AND state = ?;",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002042 )
2043 .context("In load_key_entry_id: Failed to select from keyentry table.")?;
2044 let mut rows = stmt
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002045 .query(params![key_type, key.domain.0 as u32, key.nspace, alias, KeyLifeCycle::Live])
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002046 .context("In load_key_entry_id: Failed to read from keyentry table.")?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002047 db_utils::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002048 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002049 .get(0)
2050 .context("Failed to unpack id.")
2051 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002052 .context(ks_err!())
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002053 }
2054
2055 /// This helper function completes the access tuple of a key, which is required
2056 /// to perform access control. The strategy depends on the `domain` field in the
2057 /// key descriptor.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002058 /// * Domain::SELINUX: The access tuple is complete and this function only loads
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002059 /// the key_id for further processing.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002060 /// * Domain::APP: Like Domain::SELINUX, but the tuple is completed by `caller_uid`
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002061 /// which serves as the namespace.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002062 /// * Domain::GRANT: The grant table is queried for the `key_id` and the
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002063 /// `access_vector`.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002064 /// * Domain::KEY_ID: The keyentry table is queried for the owning `domain` and
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002065 /// `namespace`.
Chris Wailes1806f972024-08-19 16:37:40 -07002066 ///
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002067 /// In each case the information returned is sufficient to perform the access
2068 /// check and the key id can be used to load further key artifacts.
2069 fn load_access_tuple(
2070 tx: &Transaction,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002071 key: &KeyDescriptor,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002072 key_type: KeyType,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002073 caller_uid: u32,
David Drysdaleef897ec2024-10-22 12:55:06 +01002074 ) -> Result<KeyAccessInfo> {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002075 match key.domain {
2076 // Domain App or SELinux. In this case we load the key_id from
2077 // the keyentry database for further loading of key components.
2078 // We already have the full access tuple to perform access control.
2079 // The only distinction is that we use the caller_uid instead
2080 // of the caller supplied namespace if the domain field is
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002081 // Domain::APP.
2082 Domain::APP | Domain::SELINUX => {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002083 let mut access_key = key.clone();
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002084 if access_key.domain == Domain::APP {
2085 access_key.nspace = caller_uid as i64;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002086 }
Chris Wailesd5aaaef2021-07-27 16:04:33 -07002087 let key_id = Self::load_key_entry_id(tx, &access_key, key_type)
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002088 .with_context(|| format!("With key.domain = {:?}.", access_key.domain))?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002089
David Drysdaleef897ec2024-10-22 12:55:06 +01002090 Ok(KeyAccessInfo { key_id, descriptor: access_key, vector: None })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002091 }
2092
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002093 // Domain::GRANT. In this case we load the key_id and the access_vector
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002094 // from the grant table.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002095 Domain::GRANT => {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002096 let mut stmt = tx
2097 .prepare(
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002098 "SELECT keyentryid, access_vector FROM persistent.grant
Hasini Gunasinghee70a0ec2021-05-10 21:12:34 +00002099 WHERE grantee = ? AND id = ? AND
2100 (SELECT state FROM persistent.keyentry WHERE id = keyentryid) = ?;",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002101 )
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002102 .context("Domain::GRANT prepare statement failed")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002103 let mut rows = stmt
Hasini Gunasinghee70a0ec2021-05-10 21:12:34 +00002104 .query(params![caller_uid as i64, key.nspace, KeyLifeCycle::Live])
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002105 .context("Domain:Grant: query failed.")?;
2106 let (key_id, access_vector): (i64, i32) =
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002107 db_utils::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002108 let r =
2109 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002110 Ok((
2111 r.get(0).context("Failed to unpack key_id.")?,
2112 r.get(1).context("Failed to unpack access_vector.")?,
2113 ))
2114 })
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002115 .context("Domain::GRANT.")?;
David Drysdaleef897ec2024-10-22 12:55:06 +01002116 Ok(KeyAccessInfo {
2117 key_id,
2118 descriptor: key.clone(),
2119 vector: Some(access_vector.into()),
2120 })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002121 }
2122
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002123 // Domain::KEY_ID. In this case we load the domain and namespace from the
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002124 // keyentry database because we need them for access control.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002125 Domain::KEY_ID => {
Janis Danisevskis45760022021-01-19 16:34:10 -08002126 let (domain, namespace): (Domain, i64) = {
2127 let mut stmt = tx
2128 .prepare(
2129 "SELECT domain, namespace FROM persistent.keyentry
2130 WHERE
2131 id = ?
2132 AND state = ?;",
2133 )
2134 .context("Domain::KEY_ID: prepare statement failed")?;
2135 let mut rows = stmt
2136 .query(params![key.nspace, KeyLifeCycle::Live])
2137 .context("Domain::KEY_ID: query failed.")?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002138 db_utils::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002139 let r =
2140 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002141 Ok((
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002142 Domain(r.get(0).context("Failed to unpack domain.")?),
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002143 r.get(1).context("Failed to unpack namespace.")?,
2144 ))
2145 })
Janis Danisevskis45760022021-01-19 16:34:10 -08002146 .context("Domain::KEY_ID.")?
2147 };
2148
2149 // We may use a key by id after loading it by grant.
2150 // In this case we have to check if the caller has a grant for this particular
2151 // key. We can skip this if we already know that the caller is the owner.
2152 // But we cannot know this if domain is anything but App. E.g. in the case
2153 // of Domain::SELINUX we have to speculatively check for grants because we have to
2154 // consult the SEPolicy before we know if the caller is the owner.
2155 let access_vector: Option<KeyPermSet> =
2156 if domain != Domain::APP || namespace != caller_uid as i64 {
2157 let access_vector: Option<i32> = tx
2158 .query_row(
2159 "SELECT access_vector FROM persistent.grant
2160 WHERE grantee = ? AND keyentryid = ?;",
2161 params![caller_uid as i64, key.nspace],
2162 |row| row.get(0),
2163 )
2164 .optional()
2165 .context("Domain::KEY_ID: query grant failed.")?;
2166 access_vector.map(|p| p.into())
2167 } else {
2168 None
2169 };
2170
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002171 let key_id = key.nspace;
Janis Danisevskis66784c42021-01-27 08:40:25 -08002172 let mut access_key: KeyDescriptor = key.clone();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002173 access_key.domain = domain;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002174 access_key.nspace = namespace;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002175
David Drysdaleef897ec2024-10-22 12:55:06 +01002176 Ok(KeyAccessInfo { key_id, descriptor: access_key, vector: access_vector })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002177 }
Rajesh Nyamagoud625e5892022-05-18 01:31:26 +00002178 _ => Err(anyhow!(KsError::Rc(ResponseCode::INVALID_ARGUMENT))),
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002179 }
2180 }
2181
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002182 fn load_blob_components(
2183 key_id: i64,
2184 load_bits: KeyEntryLoadBits,
2185 tx: &Transaction,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002186 ) -> Result<(bool, Option<(Vec<u8>, BlobMetaData)>, Option<Vec<u8>>, Option<Vec<u8>>)> {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002187 let mut stmt = tx
2188 .prepare(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002189 "SELECT MAX(id), subcomponent_type, blob FROM persistent.blobentry
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002190 WHERE keyentryid = ? GROUP BY subcomponent_type;",
2191 )
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002192 .context(ks_err!("prepare statement failed."))?;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002193
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002194 let mut rows = stmt.query(params![key_id]).context(ks_err!("query failed."))?;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002195
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002196 let mut key_blob: Option<(i64, Vec<u8>)> = None;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002197 let mut cert_blob: Option<Vec<u8>> = None;
2198 let mut cert_chain_blob: Option<Vec<u8>> = None;
Janis Danisevskis377d1002021-01-27 19:07:48 -08002199 let mut has_km_blob: bool = false;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002200 db_utils::with_rows_extract_all(&mut rows, |row| {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002201 let sub_type: SubComponentType =
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002202 row.get(1).context("Failed to extract subcomponent_type.")?;
Janis Danisevskis377d1002021-01-27 19:07:48 -08002203 has_km_blob = has_km_blob || sub_type == SubComponentType::KEY_BLOB;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002204 match (sub_type, load_bits.load_public(), load_bits.load_km()) {
2205 (SubComponentType::KEY_BLOB, _, true) => {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002206 key_blob = Some((
2207 row.get(0).context("Failed to extract key blob id.")?,
2208 row.get(2).context("Failed to extract key blob.")?,
2209 ));
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002210 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002211 (SubComponentType::CERT, true, _) => {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002212 cert_blob =
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002213 Some(row.get(2).context("Failed to extract public certificate blob.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002214 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002215 (SubComponentType::CERT_CHAIN, true, _) => {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002216 cert_chain_blob =
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002217 Some(row.get(2).context("Failed to extract certificate chain blob.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002218 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002219 (SubComponentType::CERT, _, _)
2220 | (SubComponentType::CERT_CHAIN, _, _)
2221 | (SubComponentType::KEY_BLOB, _, _) => {}
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002222 _ => Err(KsError::sys()).context("Unknown subcomponent type.")?,
2223 }
2224 Ok(())
2225 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002226 .context(ks_err!())?;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002227
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002228 let blob_info = key_blob.map_or::<Result<_>, _>(Ok(None), |(blob_id, blob)| {
2229 Ok(Some((
2230 blob,
2231 BlobMetaData::load_from_db(blob_id, tx)
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002232 .context(ks_err!("Trying to load blob_metadata."))?,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002233 )))
2234 })?;
2235
2236 Ok((has_km_blob, blob_info, cert_blob, cert_chain_blob))
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002237 }
2238
2239 fn load_key_parameters(key_id: i64, tx: &Transaction) -> Result<Vec<KeyParameter>> {
2240 let mut stmt = tx
2241 .prepare(
2242 "SELECT tag, data, security_level from persistent.keyparameter
2243 WHERE keyentryid = ?;",
2244 )
2245 .context("In load_key_parameters: prepare statement failed.")?;
2246
2247 let mut parameters: Vec<KeyParameter> = Vec::new();
2248
2249 let mut rows =
2250 stmt.query(params![key_id]).context("In load_key_parameters: query failed.")?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002251 db_utils::with_rows_extract_all(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002252 let tag = Tag(row.get(0).context("Failed to read tag.")?);
2253 let sec_level = SecurityLevel(row.get(2).context("Failed to read sec_level.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002254 parameters.push(
Chris Wailesd5aaaef2021-07-27 16:04:33 -07002255 KeyParameter::new_from_sql(tag, &SqlField::new(1, row), sec_level)
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002256 .context("Failed to read KeyParameter.")?,
2257 );
2258 Ok(())
2259 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002260 .context(ks_err!())?;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002261
2262 Ok(parameters)
2263 }
2264
Qi Wub9433b52020-12-01 14:52:46 +08002265 /// Decrements the usage count of a limited use key. This function first checks whether the
2266 /// usage has been exhausted, if not, decreases the usage count. If the usage count reaches
2267 /// zero, the key also gets marked unreferenced and scheduled for deletion.
2268 /// Returns Ok(true) if the key was marked unreferenced as a hint to the garbage collector.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002269 pub fn check_and_update_key_usage_count(&mut self, key_id: i64) -> Result<()> {
David Drysdale541846b2024-05-23 13:16:07 +01002270 let _wp = wd::watch("KeystoreDB::check_and_update_key_usage_count");
Janis Danisevskis850d4862021-05-05 08:41:14 -07002271
David Drysdale7b9ca232024-05-23 18:19:46 +01002272 self.with_transaction(Immediate("TX_check_and_update_key_usage_count"), |tx| {
Qi Wub9433b52020-12-01 14:52:46 +08002273 let limit: Option<i32> = tx
2274 .query_row(
2275 "SELECT data FROM persistent.keyparameter WHERE keyentryid = ? AND tag = ?;",
2276 params![key_id, Tag::USAGE_COUNT_LIMIT.0],
2277 |row| row.get(0),
2278 )
2279 .optional()
2280 .context("Trying to load usage count")?;
2281
2282 let limit = limit
2283 .ok_or(KsError::Km(ErrorCode::INVALID_KEY_BLOB))
2284 .context("The Key no longer exists. Key is exhausted.")?;
2285
2286 tx.execute(
2287 "UPDATE persistent.keyparameter
2288 SET data = data - 1
2289 WHERE keyentryid = ? AND tag = ? AND data > 0;",
2290 params![key_id, Tag::USAGE_COUNT_LIMIT.0],
2291 )
2292 .context("Failed to update key usage count.")?;
2293
2294 match limit {
2295 1 => Self::mark_unreferenced(tx, key_id)
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002296 .map(|need_gc| (need_gc, ()))
Qi Wub9433b52020-12-01 14:52:46 +08002297 .context("Trying to mark limited use key for deletion."),
2298 0 => Err(KsError::Km(ErrorCode::INVALID_KEY_BLOB)).context("Key is exhausted."),
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002299 _ => Ok(()).no_gc(),
Qi Wub9433b52020-12-01 14:52:46 +08002300 }
2301 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002302 .context(ks_err!())
Qi Wub9433b52020-12-01 14:52:46 +08002303 }
2304
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002305 /// Load a key entry by the given key descriptor.
2306 /// It uses the `check_permission` callback to verify if the access is allowed
2307 /// given the key access tuple read from the database using `load_access_tuple`.
2308 /// With `load_bits` the caller may specify which blobs shall be loaded from
2309 /// the blob database.
2310 pub fn load_key_entry(
2311 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002312 key: &KeyDescriptor,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002313 key_type: KeyType,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002314 load_bits: KeyEntryLoadBits,
2315 caller_uid: u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002316 check_permission: impl Fn(&KeyDescriptor, Option<KeyPermSet>) -> Result<()>,
2317 ) -> Result<(KeyIdGuard, KeyEntry)> {
David Drysdale541846b2024-05-23 13:16:07 +01002318 let _wp = wd::watch("KeystoreDB::load_key_entry");
Janis Danisevskis850d4862021-05-05 08:41:14 -07002319
Janis Danisevskis66784c42021-01-27 08:40:25 -08002320 loop {
2321 match self.load_key_entry_internal(
2322 key,
2323 key_type,
2324 load_bits,
2325 caller_uid,
2326 &check_permission,
2327 ) {
2328 Ok(result) => break Ok(result),
2329 Err(e) => {
2330 if Self::is_locked_error(&e) {
David Drysdale115c4722024-04-15 14:11:52 +01002331 std::thread::sleep(DB_BUSY_RETRY_INTERVAL);
Janis Danisevskis66784c42021-01-27 08:40:25 -08002332 continue;
2333 } else {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002334 return Err(e).context(ks_err!());
Janis Danisevskis66784c42021-01-27 08:40:25 -08002335 }
2336 }
2337 }
2338 }
2339 }
2340
2341 fn load_key_entry_internal(
2342 &mut self,
2343 key: &KeyDescriptor,
2344 key_type: KeyType,
2345 load_bits: KeyEntryLoadBits,
2346 caller_uid: u32,
2347 check_permission: &impl Fn(&KeyDescriptor, Option<KeyPermSet>) -> Result<()>,
Janis Danisevskisaec14592020-11-12 09:41:49 -08002348 ) -> Result<(KeyIdGuard, KeyEntry)> {
2349 // KEY ID LOCK 1/2
2350 // If we got a key descriptor with a key id we can get the lock right away.
2351 // Otherwise we have to defer it until we know the key id.
2352 let key_id_guard = match key.domain {
2353 Domain::KEY_ID => Some(KEY_ID_LOCK.get(key.nspace)),
2354 _ => None,
2355 };
2356
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002357 let tx = self
2358 .conn
Janis Danisevskisaec14592020-11-12 09:41:49 -08002359 .unchecked_transaction()
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002360 .context(ks_err!("Failed to initialize transaction."))?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002361
2362 // Load the key_id and complete the access control tuple.
David Drysdaleef897ec2024-10-22 12:55:06 +01002363 let access = Self::load_access_tuple(&tx, key, key_type, caller_uid).context(ks_err!())?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002364
2365 // Perform access control. It is vital that we return here if the permission is denied.
2366 // So do not touch that '?' at the end.
David Drysdaleef897ec2024-10-22 12:55:06 +01002367 check_permission(&access.descriptor, access.vector).context(ks_err!())?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002368
Janis Danisevskisaec14592020-11-12 09:41:49 -08002369 // KEY ID LOCK 2/2
2370 // If we did not get a key id lock by now, it was because we got a key descriptor
2371 // without a key id. At this point we got the key id, so we can try and get a lock.
2372 // However, we cannot block here, because we are in the middle of the transaction.
2373 // So first we try to get the lock non blocking. If that fails, we roll back the
2374 // transaction and block until we get the lock. After we successfully got the lock,
2375 // we start a new transaction and load the access tuple again.
2376 //
2377 // We don't need to perform access control again, because we already established
2378 // that the caller had access to the given key. But we need to make sure that the
2379 // key id still exists. So we have to load the key entry by key id this time.
2380 let (key_id_guard, tx) = match key_id_guard {
David Drysdaleef897ec2024-10-22 12:55:06 +01002381 None => match KEY_ID_LOCK.try_get(access.key_id) {
Janis Danisevskisaec14592020-11-12 09:41:49 -08002382 None => {
2383 // Roll back the transaction.
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002384 tx.rollback().context(ks_err!("Failed to roll back transaction."))?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002385
Janis Danisevskisaec14592020-11-12 09:41:49 -08002386 // Block until we have a key id lock.
David Drysdaleef897ec2024-10-22 12:55:06 +01002387 let key_id_guard = KEY_ID_LOCK.get(access.key_id);
Janis Danisevskisaec14592020-11-12 09:41:49 -08002388
2389 // Create a new transaction.
Janis Danisevskis66784c42021-01-27 08:40:25 -08002390 let tx = self
2391 .conn
2392 .unchecked_transaction()
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002393 .context(ks_err!("Failed to initialize transaction."))?;
Janis Danisevskisaec14592020-11-12 09:41:49 -08002394
2395 Self::load_access_tuple(
2396 &tx,
2397 // This time we have to load the key by the retrieved key id, because the
2398 // alias may have been rebound after we rolled back the transaction.
Janis Danisevskis66784c42021-01-27 08:40:25 -08002399 &KeyDescriptor {
Janis Danisevskisaec14592020-11-12 09:41:49 -08002400 domain: Domain::KEY_ID,
David Drysdaleef897ec2024-10-22 12:55:06 +01002401 nspace: access.key_id,
Janis Danisevskisaec14592020-11-12 09:41:49 -08002402 ..Default::default()
2403 },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002404 key_type,
Janis Danisevskisaec14592020-11-12 09:41:49 -08002405 caller_uid,
2406 )
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002407 .context(ks_err!("(deferred key lock)"))?;
Janis Danisevskisaec14592020-11-12 09:41:49 -08002408 (key_id_guard, tx)
2409 }
2410 Some(l) => (l, tx),
2411 },
2412 Some(key_id_guard) => (key_id_guard, tx),
2413 };
2414
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002415 let key_entry =
2416 Self::load_key_components(&tx, load_bits, key_id_guard.id()).context(ks_err!())?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002417
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002418 tx.commit().context(ks_err!("Failed to commit transaction."))?;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002419
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002420 Ok((key_id_guard, key_entry))
2421 }
2422
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002423 fn mark_unreferenced(tx: &Transaction, key_id: i64) -> Result<bool> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002424 let updated = tx
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002425 .execute("DELETE FROM persistent.keyentry WHERE id = ?;", params![key_id])
2426 .context("Trying to delete keyentry.")?;
2427 tx.execute("DELETE FROM persistent.keymetadata WHERE keyentryid = ?;", params![key_id])
2428 .context("Trying to delete keymetadata.")?;
2429 tx.execute("DELETE FROM persistent.keyparameter WHERE keyentryid = ?;", params![key_id])
2430 .context("Trying to delete keyparameters.")?;
2431 tx.execute("DELETE FROM persistent.grant WHERE keyentryid = ?;", params![key_id])
2432 .context("Trying to delete grants.")?;
David Drysdale8da288c2024-07-29 15:57:01 +01002433 // The associated blobentry rows are not immediately deleted when the owning keyentry is
2434 // removed, because a KeyMint `deleteKey()` invocation is needed (specifically for the
David Drysdale940a0ff2025-01-13 14:19:16 +00002435 // `KEY_BLOB`). That should not be done from within the database transaction. Also, calls
2436 // to `deleteKey()` need to be delayed until the boot has completed, to avoid making
2437 // permanent changes during an OTA before the point of no return. Mark the affected rows
2438 // with `state=Orphaned` so a subsequent garbage collection can do the `deleteKey()`.
David Drysdale8da288c2024-07-29 15:57:01 +01002439 tx.execute(
2440 "UPDATE persistent.blobentry SET state = ? WHERE keyentryid = ?",
2441 params![BlobState::Orphaned, key_id],
2442 )
2443 .context("Trying to mark blobentrys as superseded")?;
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002444 Ok(updated != 0)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002445 }
2446
2447 /// Marks the given key as unreferenced and removes all of the grants to this key.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002448 /// Returns Ok(true) if a key was marked unreferenced as a hint for the garbage collector.
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002449 pub fn unbind_key(
2450 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002451 key: &KeyDescriptor,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002452 key_type: KeyType,
2453 caller_uid: u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002454 check_permission: impl Fn(&KeyDescriptor, Option<KeyPermSet>) -> Result<()>,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002455 ) -> Result<()> {
David Drysdale541846b2024-05-23 13:16:07 +01002456 let _wp = wd::watch("KeystoreDB::unbind_key");
Janis Danisevskis850d4862021-05-05 08:41:14 -07002457
David Drysdale7b9ca232024-05-23 18:19:46 +01002458 self.with_transaction(Immediate("TX_unbind_key"), |tx| {
David Drysdaleef897ec2024-10-22 12:55:06 +01002459 let access = Self::load_access_tuple(tx, key, key_type, caller_uid)
2460 .context("Trying to get access tuple.")?;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002461
2462 // Perform access control. It is vital that we return here if the permission is denied.
2463 // So do not touch that '?' at the end.
David Drysdaleef897ec2024-10-22 12:55:06 +01002464 check_permission(&access.descriptor, access.vector)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002465 .context("While checking permission.")?;
2466
David Drysdaleef897ec2024-10-22 12:55:06 +01002467 Self::mark_unreferenced(tx, access.key_id)
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002468 .map(|need_gc| (need_gc, ()))
2469 .context("Trying to mark the key unreferenced.")
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002470 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002471 .context(ks_err!())
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002472 }
2473
Max Bires8e93d2b2021-01-14 13:17:59 -08002474 fn get_key_km_uuid(tx: &Transaction, key_id: i64) -> Result<Uuid> {
2475 tx.query_row(
2476 "SELECT km_uuid FROM persistent.keyentry WHERE id = ?",
2477 params![key_id],
2478 |row| row.get(0),
2479 )
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002480 .context(ks_err!())
Max Bires8e93d2b2021-01-14 13:17:59 -08002481 }
2482
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002483 /// Delete all artifacts belonging to the namespace given by the domain-namespace tuple.
2484 /// This leaves all of the blob entries orphaned for subsequent garbage collection.
2485 pub fn unbind_keys_for_namespace(&mut self, domain: Domain, namespace: i64) -> Result<()> {
David Drysdale541846b2024-05-23 13:16:07 +01002486 let _wp = wd::watch("KeystoreDB::unbind_keys_for_namespace");
Janis Danisevskis850d4862021-05-05 08:41:14 -07002487
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002488 if !(domain == Domain::APP || domain == Domain::SELINUX) {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002489 return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT)).context(ks_err!());
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002490 }
David Drysdale7b9ca232024-05-23 18:19:46 +01002491 self.with_transaction(Immediate("TX_unbind_keys_for_namespace"), |tx| {
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002492 tx.execute(
2493 "DELETE FROM persistent.keymetadata
2494 WHERE keyentryid IN (
2495 SELECT id FROM persistent.keyentry
Tri Vo0346bbe2023-05-12 14:16:31 -04002496 WHERE domain = ? AND namespace = ? AND key_type = ?
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002497 );",
Tri Vo0346bbe2023-05-12 14:16:31 -04002498 params![domain.0, namespace, KeyType::Client],
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002499 )
2500 .context("Trying to delete keymetadata.")?;
2501 tx.execute(
2502 "DELETE FROM persistent.keyparameter
2503 WHERE keyentryid IN (
2504 SELECT id FROM persistent.keyentry
Tri Vo0346bbe2023-05-12 14:16:31 -04002505 WHERE domain = ? AND namespace = ? AND key_type = ?
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002506 );",
Tri Vo0346bbe2023-05-12 14:16:31 -04002507 params![domain.0, namespace, KeyType::Client],
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002508 )
2509 .context("Trying to delete keyparameters.")?;
2510 tx.execute(
2511 "DELETE FROM persistent.grant
2512 WHERE keyentryid IN (
2513 SELECT id FROM persistent.keyentry
Tri Vo0346bbe2023-05-12 14:16:31 -04002514 WHERE domain = ? AND namespace = ? AND key_type = ?
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002515 );",
Tri Vo0346bbe2023-05-12 14:16:31 -04002516 params![domain.0, namespace, KeyType::Client],
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002517 )
2518 .context("Trying to delete grants.")?;
2519 tx.execute(
Janis Danisevskisb146f312021-05-06 15:05:45 -07002520 "DELETE FROM persistent.keyentry
Tri Vo0346bbe2023-05-12 14:16:31 -04002521 WHERE domain = ? AND namespace = ? AND key_type = ?;",
2522 params![domain.0, namespace, KeyType::Client],
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002523 )
2524 .context("Trying to delete keyentry.")?;
2525 Ok(()).need_gc()
2526 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002527 .context(ks_err!())
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002528 }
2529
Janis Danisevskis3cba10d2021-05-06 17:02:19 -07002530 fn cleanup_unreferenced(tx: &Transaction) -> Result<()> {
David Drysdale541846b2024-05-23 13:16:07 +01002531 let _wp = wd::watch("KeystoreDB::cleanup_unreferenced");
Janis Danisevskis3cba10d2021-05-06 17:02:19 -07002532 {
2533 tx.execute(
2534 "DELETE FROM persistent.keymetadata
2535 WHERE keyentryid IN (
2536 SELECT id FROM persistent.keyentry
2537 WHERE state = ?
2538 );",
2539 params![KeyLifeCycle::Unreferenced],
2540 )
2541 .context("Trying to delete keymetadata.")?;
2542 tx.execute(
2543 "DELETE FROM persistent.keyparameter
2544 WHERE keyentryid IN (
2545 SELECT id FROM persistent.keyentry
2546 WHERE state = ?
2547 );",
2548 params![KeyLifeCycle::Unreferenced],
2549 )
2550 .context("Trying to delete keyparameters.")?;
2551 tx.execute(
2552 "DELETE FROM persistent.grant
2553 WHERE keyentryid IN (
2554 SELECT id FROM persistent.keyentry
2555 WHERE state = ?
2556 );",
2557 params![KeyLifeCycle::Unreferenced],
2558 )
2559 .context("Trying to delete grants.")?;
2560 tx.execute(
2561 "DELETE FROM persistent.keyentry
2562 WHERE state = ?;",
2563 params![KeyLifeCycle::Unreferenced],
2564 )
2565 .context("Trying to delete keyentry.")?;
2566 Result::<()>::Ok(())
2567 }
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002568 .context(ks_err!())
Janis Danisevskis3cba10d2021-05-06 17:02:19 -07002569 }
2570
Eric Biggers9f7ebeb2024-06-20 14:59:32 +00002571 /// Deletes all keys for the given user, including both client keys and super keys.
2572 pub fn unbind_keys_for_user(&mut self, user_id: u32) -> Result<()> {
David Drysdale541846b2024-05-23 13:16:07 +01002573 let _wp = wd::watch("KeystoreDB::unbind_keys_for_user");
Janis Danisevskis850d4862021-05-05 08:41:14 -07002574
David Drysdale7b9ca232024-05-23 18:19:46 +01002575 self.with_transaction(Immediate("TX_unbind_keys_for_user"), |tx| {
Hasini Gunasingheda895552021-01-27 19:34:37 +00002576 let mut stmt = tx
2577 .prepare(&format!(
2578 "SELECT id from persistent.keyentry
2579 WHERE (
2580 key_type = ?
2581 AND domain = ?
2582 AND cast ( (namespace/{aid_user_offset}) as int) = ?
2583 AND state = ?
2584 ) OR (
2585 key_type = ?
2586 AND namespace = ?
Hasini Gunasingheda895552021-01-27 19:34:37 +00002587 AND state = ?
2588 );",
2589 aid_user_offset = AID_USER_OFFSET
2590 ))
2591 .context(concat!(
2592 "In unbind_keys_for_user. ",
2593 "Failed to prepare the query to find the keys created by apps."
2594 ))?;
2595
2596 let mut rows = stmt
2597 .query(params![
2598 // WHERE client key:
2599 KeyType::Client,
2600 Domain::APP.0 as u32,
2601 user_id,
2602 KeyLifeCycle::Live,
2603 // OR super key:
2604 KeyType::Super,
2605 user_id,
Hasini Gunasingheda895552021-01-27 19:34:37 +00002606 KeyLifeCycle::Live
2607 ])
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002608 .context(ks_err!("Failed to query the keys created by apps."))?;
Hasini Gunasingheda895552021-01-27 19:34:37 +00002609
2610 let mut key_ids: Vec<i64> = Vec::new();
2611 db_utils::with_rows_extract_all(&mut rows, |row| {
2612 key_ids
2613 .push(row.get(0).context("Failed to read key id of a key created by an app.")?);
2614 Ok(())
2615 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002616 .context(ks_err!())?;
Hasini Gunasingheda895552021-01-27 19:34:37 +00002617
2618 let mut notify_gc = false;
2619 for key_id in key_ids {
Chris Wailesd5aaaef2021-07-27 16:04:33 -07002620 notify_gc = Self::mark_unreferenced(tx, key_id)
Hasini Gunasingheda895552021-01-27 19:34:37 +00002621 .context("In unbind_keys_for_user.")?
2622 || notify_gc;
2623 }
2624 Ok(()).do_gc(notify_gc)
2625 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002626 .context(ks_err!())
Hasini Gunasingheda895552021-01-27 19:34:37 +00002627 }
2628
Eric Biggersb0478cf2023-10-27 03:55:29 +00002629 /// Deletes all auth-bound keys, i.e. keys that require user authentication, for the given user.
2630 /// This runs when the user's lock screen is being changed to Swipe or None.
2631 ///
2632 /// This intentionally does *not* delete keys that require that the device be unlocked, unless
2633 /// such keys also require user authentication. Keystore's concept of user authentication is
2634 /// fairly strong, and it requires that keys that require authentication be deleted as soon as
2635 /// authentication is no longer possible. In contrast, keys that just require that the device
2636 /// be unlocked should remain usable when the lock screen is set to Swipe or None, as the device
2637 /// is always considered "unlocked" in that case.
2638 pub fn unbind_auth_bound_keys_for_user(&mut self, user_id: u32) -> Result<()> {
David Drysdale541846b2024-05-23 13:16:07 +01002639 let _wp = wd::watch("KeystoreDB::unbind_auth_bound_keys_for_user");
Eric Biggersb0478cf2023-10-27 03:55:29 +00002640
David Drysdale7b9ca232024-05-23 18:19:46 +01002641 self.with_transaction(Immediate("TX_unbind_auth_bound_keys_for_user"), |tx| {
Eric Biggersb0478cf2023-10-27 03:55:29 +00002642 let mut stmt = tx
2643 .prepare(&format!(
2644 "SELECT id from persistent.keyentry
2645 WHERE key_type = ?
2646 AND domain = ?
2647 AND cast ( (namespace/{aid_user_offset}) as int) = ?
2648 AND state = ?;",
2649 aid_user_offset = AID_USER_OFFSET
2650 ))
2651 .context(concat!(
2652 "In unbind_auth_bound_keys_for_user. ",
2653 "Failed to prepare the query to find the keys created by apps."
2654 ))?;
2655
2656 let mut rows = stmt
2657 .query(params![KeyType::Client, Domain::APP.0 as u32, user_id, KeyLifeCycle::Live,])
2658 .context(ks_err!("Failed to query the keys created by apps."))?;
2659
2660 let mut key_ids: Vec<i64> = Vec::new();
2661 db_utils::with_rows_extract_all(&mut rows, |row| {
2662 key_ids
2663 .push(row.get(0).context("Failed to read key id of a key created by an app.")?);
2664 Ok(())
2665 })
2666 .context(ks_err!())?;
2667
2668 let mut notify_gc = false;
2669 let mut num_unbound = 0;
2670 for key_id in key_ids {
2671 // Load the key parameters and filter out non-auth-bound keys. To identify
2672 // auth-bound keys, use the presence of UserSecureID. The absence of NoAuthRequired
2673 // could also be used, but UserSecureID is what Keystore treats as authoritative
2674 // when actually enforcing the key parameters (it might not matter, though).
2675 let params = Self::load_key_parameters(key_id, tx)
2676 .context("Failed to load key parameters.")?;
2677 let is_auth_bound_key = params.iter().any(|kp| {
2678 matches!(kp.key_parameter_value(), KeyParameterValue::UserSecureID(_))
2679 });
2680 if is_auth_bound_key {
2681 notify_gc = Self::mark_unreferenced(tx, key_id)
2682 .context("In unbind_auth_bound_keys_for_user.")?
2683 || notify_gc;
2684 num_unbound += 1;
2685 }
2686 }
2687 log::info!("Deleting {num_unbound} auth-bound keys for user {user_id}");
2688 Ok(()).do_gc(notify_gc)
2689 })
2690 .context(ks_err!())
2691 }
2692
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002693 fn load_key_components(
2694 tx: &Transaction,
2695 load_bits: KeyEntryLoadBits,
2696 key_id: i64,
2697 ) -> Result<KeyEntry> {
Chris Wailesd5aaaef2021-07-27 16:04:33 -07002698 let metadata = KeyMetaData::load_from_db(key_id, tx).context("In load_key_components.")?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002699
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002700 let (has_km_blob, key_blob_info, cert_blob, cert_chain_blob) =
Chris Wailesd5aaaef2021-07-27 16:04:33 -07002701 Self::load_blob_components(key_id, load_bits, tx).context("In load_key_components.")?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002702
Chris Wailesd5aaaef2021-07-27 16:04:33 -07002703 let parameters = Self::load_key_parameters(key_id, tx)
Max Bires8e93d2b2021-01-14 13:17:59 -08002704 .context("In load_key_components: Trying to load key parameters.")?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002705
Chris Wailesd5aaaef2021-07-27 16:04:33 -07002706 let km_uuid = Self::get_key_km_uuid(tx, key_id)
Max Bires8e93d2b2021-01-14 13:17:59 -08002707 .context("In load_key_components: Trying to get KM uuid.")?;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002708
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002709 Ok(KeyEntry {
2710 id: key_id,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002711 key_blob_info,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002712 cert: cert_blob,
2713 cert_chain: cert_chain_blob,
Max Bires8e93d2b2021-01-14 13:17:59 -08002714 km_uuid,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002715 parameters,
2716 metadata,
Janis Danisevskis377d1002021-01-27 19:07:48 -08002717 pure_cert: !has_km_blob,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002718 })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002719 }
2720
Eran Messeri24f31972023-01-25 17:00:33 +00002721 /// Returns a list of KeyDescriptors in the selected domain/namespace whose
2722 /// aliases are greater than the specified 'start_past_alias'. If no value
2723 /// is provided, returns all KeyDescriptors.
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002724 /// The key descriptors will have the domain, nspace, and alias field set.
Eran Messeri24f31972023-01-25 17:00:33 +00002725 /// The returned list will be sorted by alias.
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002726 /// Domain must be APP or SELINUX, the caller must make sure of that.
David Drysdale8da288c2024-07-29 15:57:01 +01002727 /// Number of returned values is limited to 10,000 (which is empirically roughly
2728 /// what will fit in a Binder message).
Eran Messeri24f31972023-01-25 17:00:33 +00002729 pub fn list_past_alias(
Janis Danisevskis18313832021-05-17 13:30:32 -07002730 &mut self,
2731 domain: Domain,
2732 namespace: i64,
2733 key_type: KeyType,
Eran Messeri24f31972023-01-25 17:00:33 +00002734 start_past_alias: Option<&str>,
Janis Danisevskis18313832021-05-17 13:30:32 -07002735 ) -> Result<Vec<KeyDescriptor>> {
David Drysdale541846b2024-05-23 13:16:07 +01002736 let _wp = wd::watch("KeystoreDB::list_past_alias");
Janis Danisevskis850d4862021-05-05 08:41:14 -07002737
Eran Messeri24f31972023-01-25 17:00:33 +00002738 let query = format!(
2739 "SELECT DISTINCT alias FROM persistent.keyentry
Janis Danisevskis18313832021-05-17 13:30:32 -07002740 WHERE domain = ?
2741 AND namespace = ?
2742 AND alias IS NOT NULL
2743 AND state = ?
Eran Messeri24f31972023-01-25 17:00:33 +00002744 AND key_type = ?
2745 {}
David Drysdale8da288c2024-07-29 15:57:01 +01002746 ORDER BY alias ASC
2747 LIMIT 10000;",
Eran Messeri24f31972023-01-25 17:00:33 +00002748 if start_past_alias.is_some() { " AND alias > ?" } else { "" }
2749 );
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002750
Eran Messeri24f31972023-01-25 17:00:33 +00002751 self.with_transaction(TransactionBehavior::Deferred, |tx| {
2752 let mut stmt = tx.prepare(&query).context(ks_err!("Failed to prepare."))?;
2753
2754 let mut rows = match start_past_alias {
2755 Some(past_alias) => stmt
2756 .query(params![
2757 domain.0 as u32,
2758 namespace,
2759 KeyLifeCycle::Live,
2760 key_type,
2761 past_alias
2762 ])
2763 .context(ks_err!("Failed to query."))?,
2764 None => stmt
2765 .query(params![domain.0 as u32, namespace, KeyLifeCycle::Live, key_type,])
2766 .context(ks_err!("Failed to query."))?,
2767 };
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002768
Janis Danisevskis66784c42021-01-27 08:40:25 -08002769 let mut descriptors: Vec<KeyDescriptor> = Vec::new();
2770 db_utils::with_rows_extract_all(&mut rows, |row| {
2771 descriptors.push(KeyDescriptor {
2772 domain,
2773 nspace: namespace,
2774 alias: Some(row.get(0).context("Trying to extract alias.")?),
2775 blob: None,
2776 });
2777 Ok(())
2778 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002779 .context(ks_err!("Failed to extract rows."))?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002780 Ok(descriptors).no_gc()
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002781 })
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002782 }
2783
Eran Messeri24f31972023-01-25 17:00:33 +00002784 /// Returns a number of KeyDescriptors in the selected domain/namespace.
2785 /// Domain must be APP or SELINUX, the caller must make sure of that.
2786 pub fn count_keys(
2787 &mut self,
2788 domain: Domain,
2789 namespace: i64,
2790 key_type: KeyType,
2791 ) -> Result<usize> {
David Drysdale541846b2024-05-23 13:16:07 +01002792 let _wp = wd::watch("KeystoreDB::countKeys");
Eran Messeri24f31972023-01-25 17:00:33 +00002793
2794 let num_keys = self.with_transaction(TransactionBehavior::Deferred, |tx| {
2795 tx.query_row(
2796 "SELECT COUNT(alias) FROM persistent.keyentry
2797 WHERE domain = ?
2798 AND namespace = ?
2799 AND alias IS NOT NULL
2800 AND state = ?
2801 AND key_type = ?;",
2802 params![domain.0 as u32, namespace, KeyLifeCycle::Live, key_type],
2803 |row| row.get(0),
2804 )
2805 .context(ks_err!("Failed to count number of keys."))
2806 .no_gc()
2807 })?;
2808 Ok(num_keys)
2809 }
2810
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002811 /// Adds a grant to the grant table.
2812 /// Like `load_key_entry` this function loads the access tuple before
2813 /// it uses the callback for a permission check. Upon success,
2814 /// it inserts the `grantee_uid`, `key_id`, and `access_vector` into the
2815 /// grant table. The new row will have a randomized id, which is used as
2816 /// grant id in the namespace field of the resulting KeyDescriptor.
2817 pub fn grant(
2818 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002819 key: &KeyDescriptor,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002820 caller_uid: u32,
2821 grantee_uid: u32,
2822 access_vector: KeyPermSet,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002823 check_permission: impl Fn(&KeyDescriptor, &KeyPermSet) -> Result<()>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002824 ) -> Result<KeyDescriptor> {
David Drysdale541846b2024-05-23 13:16:07 +01002825 let _wp = wd::watch("KeystoreDB::grant");
Janis Danisevskis850d4862021-05-05 08:41:14 -07002826
David Drysdale7b9ca232024-05-23 18:19:46 +01002827 self.with_transaction(Immediate("TX_grant"), |tx| {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002828 // Load the key_id and complete the access control tuple.
2829 // We ignore the access vector here because grants cannot be granted.
2830 // The access vector returned here expresses the permissions the
2831 // grantee has if key.domain == Domain::GRANT. But this vector
2832 // cannot include the grant permission by design, so there is no way the
2833 // subsequent permission check can pass.
2834 // We could check key.domain == Domain::GRANT and fail early.
2835 // But even if we load the access tuple by grant here, the permission
2836 // check denies the attempt to create a grant by grant descriptor.
David Drysdaleef897ec2024-10-22 12:55:06 +01002837 let access =
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002838 Self::load_access_tuple(tx, key, KeyType::Client, caller_uid).context(ks_err!())?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002839
Janis Danisevskis66784c42021-01-27 08:40:25 -08002840 // Perform access control. It is vital that we return here if the permission
2841 // was denied. So do not touch that '?' at the end of the line.
2842 // This permission check checks if the caller has the grant permission
2843 // for the given key and in addition to all of the permissions
2844 // expressed in `access_vector`.
David Drysdaleef897ec2024-10-22 12:55:06 +01002845 check_permission(&access.descriptor, &access_vector)
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002846 .context(ks_err!("check_permission failed"))?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002847
Janis Danisevskis66784c42021-01-27 08:40:25 -08002848 let grant_id = if let Some(grant_id) = tx
2849 .query_row(
2850 "SELECT id FROM persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002851 WHERE keyentryid = ? AND grantee = ?;",
David Drysdaleef897ec2024-10-22 12:55:06 +01002852 params![access.key_id, grantee_uid],
Janis Danisevskis66784c42021-01-27 08:40:25 -08002853 |row| row.get(0),
2854 )
2855 .optional()
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002856 .context(ks_err!("Failed get optional existing grant id."))?
Janis Danisevskis66784c42021-01-27 08:40:25 -08002857 {
2858 tx.execute(
2859 "UPDATE persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002860 SET access_vector = ?
2861 WHERE id = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08002862 params![i32::from(access_vector), grant_id],
Joel Galenson845f74b2020-09-09 14:11:55 -07002863 )
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002864 .context(ks_err!("Failed to update existing grant."))?;
Janis Danisevskis66784c42021-01-27 08:40:25 -08002865 grant_id
2866 } else {
2867 Self::insert_with_retry(|id| {
2868 tx.execute(
2869 "INSERT INTO persistent.grant (id, grantee, keyentryid, access_vector)
2870 VALUES (?, ?, ?, ?);",
David Drysdaleef897ec2024-10-22 12:55:06 +01002871 params![id, grantee_uid, access.key_id, i32::from(access_vector)],
Janis Danisevskis66784c42021-01-27 08:40:25 -08002872 )
2873 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002874 .context(ks_err!())?
Janis Danisevskis66784c42021-01-27 08:40:25 -08002875 };
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002876
Janis Danisevskis66784c42021-01-27 08:40:25 -08002877 Ok(KeyDescriptor { domain: Domain::GRANT, nspace: grant_id, alias: None, blob: None })
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002878 .no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08002879 })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002880 }
2881
2882 /// This function checks permissions like `grant` and `load_key_entry`
2883 /// before removing a grant from the grant table.
2884 pub fn ungrant(
2885 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002886 key: &KeyDescriptor,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002887 caller_uid: u32,
2888 grantee_uid: u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002889 check_permission: impl Fn(&KeyDescriptor) -> Result<()>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002890 ) -> Result<()> {
David Drysdale541846b2024-05-23 13:16:07 +01002891 let _wp = wd::watch("KeystoreDB::ungrant");
Janis Danisevskis850d4862021-05-05 08:41:14 -07002892
David Drysdale7b9ca232024-05-23 18:19:46 +01002893 self.with_transaction(Immediate("TX_ungrant"), |tx| {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002894 // Load the key_id and complete the access control tuple.
2895 // We ignore the access vector here because grants cannot be granted.
David Drysdaleef897ec2024-10-22 12:55:06 +01002896 let access =
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002897 Self::load_access_tuple(tx, key, KeyType::Client, caller_uid).context(ks_err!())?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002898
Janis Danisevskis66784c42021-01-27 08:40:25 -08002899 // Perform access control. We must return here if the permission
2900 // was denied. So do not touch the '?' at the end of this line.
David Drysdaleef897ec2024-10-22 12:55:06 +01002901 check_permission(&access.descriptor).context(ks_err!("check_permission failed."))?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002902
Janis Danisevskis66784c42021-01-27 08:40:25 -08002903 tx.execute(
2904 "DELETE FROM persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002905 WHERE keyentryid = ? AND grantee = ?;",
David Drysdaleef897ec2024-10-22 12:55:06 +01002906 params![access.key_id, grantee_uid],
Janis Danisevskis66784c42021-01-27 08:40:25 -08002907 )
2908 .context("Failed to delete grant.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002909
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002910 Ok(()).no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08002911 })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002912 }
2913
Joel Galenson845f74b2020-09-09 14:11:55 -07002914 // Generates a random id and passes it to the given function, which will
2915 // try to insert it into a database. If that insertion fails, retry;
2916 // otherwise return the id.
2917 fn insert_with_retry(inserter: impl Fn(i64) -> rusqlite::Result<usize>) -> Result<i64> {
2918 loop {
Janis Danisevskiseed69842021-02-18 20:04:10 -08002919 let newid: i64 = match random() {
2920 Self::UNASSIGNED_KEY_ID => continue, // UNASSIGNED_KEY_ID cannot be assigned.
2921 i => i,
2922 };
Joel Galenson845f74b2020-09-09 14:11:55 -07002923 match inserter(newid) {
2924 // If the id already existed, try again.
2925 Err(rusqlite::Error::SqliteFailure(
2926 libsqlite3_sys::Error {
2927 code: libsqlite3_sys::ErrorCode::ConstraintViolation,
2928 extended_code: libsqlite3_sys::SQLITE_CONSTRAINT_UNIQUE,
2929 },
2930 _,
2931 )) => (),
2932 Err(e) => {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002933 return Err(e).context(ks_err!("failed to insert into database."));
Joel Galenson845f74b2020-09-09 14:11:55 -07002934 }
2935 _ => return Ok(newid),
2936 }
2937 }
2938 }
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002939
Matthew Maurerd7815ca2021-05-06 21:58:45 -07002940 /// Insert or replace the auth token based on (user_id, auth_id, auth_type)
2941 pub fn insert_auth_token(&mut self, auth_token: &HardwareAuthToken) {
Eric Biggers19b3b0d2024-01-31 22:46:47 +00002942 self.perboot
2943 .insert_auth_token_entry(AuthTokenEntry::new(auth_token.clone(), BootTime::now()))
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002944 }
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002945
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002946 /// Find the newest auth token matching the given predicate.
Eric Biggersb5613da2024-03-13 19:31:42 +00002947 pub fn find_auth_token_entry<F>(&self, p: F) -> Option<AuthTokenEntry>
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002948 where
2949 F: Fn(&AuthTokenEntry) -> bool,
2950 {
Eric Biggersb5613da2024-03-13 19:31:42 +00002951 self.perboot.find_auth_token_entry(p)
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002952 }
Pavel Grafovf45034a2021-05-12 22:35:45 +01002953
2954 /// Load descriptor of a key by key id
2955 pub fn load_key_descriptor(&mut self, key_id: i64) -> Result<Option<KeyDescriptor>> {
David Drysdale541846b2024-05-23 13:16:07 +01002956 let _wp = wd::watch("KeystoreDB::load_key_descriptor");
Pavel Grafovf45034a2021-05-12 22:35:45 +01002957
2958 self.with_transaction(TransactionBehavior::Deferred, |tx| {
2959 tx.query_row(
2960 "SELECT domain, namespace, alias FROM persistent.keyentry WHERE id = ?;",
2961 params![key_id],
2962 |row| {
2963 Ok(KeyDescriptor {
2964 domain: Domain(row.get(0)?),
2965 nspace: row.get(1)?,
2966 alias: row.get(2)?,
2967 blob: None,
2968 })
2969 },
2970 )
2971 .optional()
2972 .context("Trying to load key descriptor")
2973 .no_gc()
2974 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002975 .context(ks_err!())
Pavel Grafovf45034a2021-05-12 22:35:45 +01002976 }
Eran Messeri4dc27b52024-01-09 12:43:31 +00002977
2978 /// Returns a list of app UIDs that have keys authenticated by the given secure_user_id
2979 /// (for the given user_id).
2980 /// This is helpful for finding out which apps will have their keys invalidated when
2981 /// the user changes biometrics enrollment or removes their LSKF.
2982 pub fn get_app_uids_affected_by_sid(
2983 &mut self,
2984 user_id: i32,
2985 secure_user_id: i64,
2986 ) -> Result<Vec<i64>> {
David Drysdale541846b2024-05-23 13:16:07 +01002987 let _wp = wd::watch("KeystoreDB::get_app_uids_affected_by_sid");
Eran Messeri4dc27b52024-01-09 12:43:31 +00002988
David Drysdale7b9ca232024-05-23 18:19:46 +01002989 let ids = self.with_transaction(Immediate("TX_get_app_uids_affected_by_sid"), |tx| {
Eran Messeri4dc27b52024-01-09 12:43:31 +00002990 let mut stmt = tx
2991 .prepare(&format!(
2992 "SELECT id, namespace from persistent.keyentry
2993 WHERE key_type = ?
2994 AND domain = ?
2995 AND cast ( (namespace/{AID_USER_OFFSET}) as int) = ?
2996 AND state = ?;",
2997 ))
2998 .context(concat!(
2999 "In get_app_uids_affected_by_sid, ",
3000 "failed to prepare the query to find the keys created by apps."
3001 ))?;
3002
3003 let mut rows = stmt
3004 .query(params![KeyType::Client, Domain::APP.0 as u32, user_id, KeyLifeCycle::Live,])
3005 .context(ks_err!("Failed to query the keys created by apps."))?;
3006
3007 let mut key_ids_and_app_uids: HashMap<i64, i64> = Default::default();
3008 db_utils::with_rows_extract_all(&mut rows, |row| {
3009 key_ids_and_app_uids.insert(
3010 row.get(0).context("Failed to read key id of a key created by an app.")?,
3011 row.get(1).context("Failed to read the app uid")?,
3012 );
3013 Ok(())
3014 })?;
3015 Ok(key_ids_and_app_uids).no_gc()
3016 })?;
3017 let mut app_uids_affected_by_sid: HashSet<i64> = Default::default();
David Drysdale7b9ca232024-05-23 18:19:46 +01003018 for (key_id, app_uid) in ids {
Eran Messeri4dc27b52024-01-09 12:43:31 +00003019 // Read the key parameters for each key in its own transaction. It is OK to ignore
3020 // an error to get the properties of a particular key since it might have been deleted
3021 // under our feet after the previous transaction concluded. If the key was deleted
3022 // then it is no longer applicable if it was auth-bound or not.
3023 if let Ok(is_key_bound_to_sid) =
David Drysdale7b9ca232024-05-23 18:19:46 +01003024 self.with_transaction(Immediate("TX_get_app_uids_affects_by_sid 2"), |tx| {
Eran Messeri4dc27b52024-01-09 12:43:31 +00003025 let params = Self::load_key_parameters(key_id, tx)
3026 .context("Failed to load key parameters.")?;
3027 // Check if the key is bound to this secure user ID.
3028 let is_key_bound_to_sid = params.iter().any(|kp| {
3029 matches!(
3030 kp.key_parameter_value(),
3031 KeyParameterValue::UserSecureID(sid) if *sid == secure_user_id
3032 )
3033 });
3034 Ok(is_key_bound_to_sid).no_gc()
3035 })
3036 {
3037 if is_key_bound_to_sid {
3038 app_uids_affected_by_sid.insert(app_uid);
3039 }
3040 }
3041 }
3042
3043 let app_uids_vec: Vec<i64> = app_uids_affected_by_sid.into_iter().collect();
3044 Ok(app_uids_vec)
3045 }
David Drysdale709c2092024-06-06 16:17:28 +01003046
3047 /// Retrieve a database PRAGMA config value.
3048 pub fn pragma<T: FromSql>(&mut self, name: &str) -> Result<T> {
3049 self.conn
3050 .query_row(&format!("PRAGMA persistent.{name}"), (), |row| row.get(0))
3051 .context(format!("failed to read pragma {name}"))
3052 }
Joel Galenson26f4d012020-07-17 14:57:21 -07003053}