blob: 8451a33e998b18edc6c789a8cc1ccc818049f6c5 [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 Drysdale115c4722024-04-15 14:11:52 +0100128/// If the database returns a busy error code, retry after this interval.
129const DB_BUSY_RETRY_INTERVAL: Duration = Duration::from_micros(500);
David Drysdale115c4722024-04-15 14:11:52 +0100130
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800131impl_metadata!(
132 /// A set of metadata for key entries.
133 #[derive(Debug, Default, Eq, PartialEq)]
134 pub struct KeyMetaData;
135 /// A metadata entry for key entries.
136 #[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
137 pub enum KeyMetaEntry {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800138 /// Date of the creation of the key entry.
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800139 CreationDate(DateTime) with accessor creation_date,
140 /// Expiration date for attestation keys.
141 AttestationExpirationDate(DateTime) with accessor attestation_expiration_date,
Max Bires2b2e6562020-09-22 11:22:36 -0700142 /// CBOR Blob that represents a COSE_Key and associated metadata needed for remote
143 /// provisioning
144 AttestationMacedPublicKey(Vec<u8>) with accessor attestation_maced_public_key,
145 /// Vector representing the raw public key so results from the server can be matched
146 /// to the right entry
147 AttestationRawPubKey(Vec<u8>) with accessor attestation_raw_pub_key,
Paul Crowley8d5b2532021-03-19 10:53:07 -0700148 /// SEC1 public key for ECDH encryption
149 Sec1PublicKey(Vec<u8>) with accessor sec1_public_key,
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800150 // --- ADD NEW META DATA FIELDS HERE ---
151 // For backwards compatibility add new entries only to
152 // end of this list and above this comment.
153 };
154);
155
156impl KeyMetaData {
157 fn load_from_db(key_id: i64, tx: &Transaction) -> Result<Self> {
158 let mut stmt = tx
159 .prepare(
160 "SELECT tag, data from persistent.keymetadata
161 WHERE keyentryid = ?;",
162 )
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000163 .context(ks_err!("KeyMetaData::load_from_db: prepare statement failed."))?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800164
165 let mut metadata: HashMap<i64, KeyMetaEntry> = Default::default();
166
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000167 let mut rows = stmt
168 .query(params![key_id])
169 .context(ks_err!("KeyMetaData::load_from_db: query failed."))?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800170 db_utils::with_rows_extract_all(&mut rows, |row| {
171 let db_tag: i64 = row.get(0).context("Failed to read tag.")?;
172 metadata.insert(
173 db_tag,
Chris Wailesd5aaaef2021-07-27 16:04:33 -0700174 KeyMetaEntry::new_from_sql(db_tag, &SqlField::new(1, row))
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800175 .context("Failed to read KeyMetaEntry.")?,
176 );
177 Ok(())
178 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000179 .context(ks_err!("KeyMetaData::load_from_db."))?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800180
181 Ok(Self { data: metadata })
182 }
183
184 fn store_in_db(&self, key_id: i64, tx: &Transaction) -> Result<()> {
185 let mut stmt = tx
186 .prepare(
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000187 "INSERT or REPLACE INTO persistent.keymetadata (keyentryid, tag, data)
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800188 VALUES (?, ?, ?);",
189 )
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000190 .context(ks_err!("KeyMetaData::store_in_db: Failed to prepare statement."))?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800191
192 let iter = self.data.iter();
193 for (tag, entry) in iter {
194 stmt.insert(params![key_id, tag, entry,]).with_context(|| {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000195 ks_err!("KeyMetaData::store_in_db: Failed to insert {:?}", entry)
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800196 })?;
197 }
198 Ok(())
199 }
200}
201
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800202impl_metadata!(
203 /// A set of metadata for key blobs.
204 #[derive(Debug, Default, Eq, PartialEq)]
205 pub struct BlobMetaData;
206 /// A metadata entry for key blobs.
207 #[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
208 pub enum BlobMetaEntry {
209 /// If present, indicates that the blob is encrypted with another key or a key derived
210 /// from a password.
211 EncryptedBy(EncryptedBy) with accessor encrypted_by,
212 /// If the blob is password encrypted this field is set to the
213 /// salt used for the key derivation.
214 Salt(Vec<u8>) with accessor salt,
215 /// If the blob is encrypted, this field is set to the initialization vector.
216 Iv(Vec<u8>) with accessor iv,
217 /// If the blob is encrypted, this field holds the AEAD TAG.
218 AeadTag(Vec<u8>) with accessor aead_tag,
219 /// The uuid of the owning KeyMint instance.
220 KmUuid(Uuid) with accessor km_uuid,
Paul Crowley8d5b2532021-03-19 10:53:07 -0700221 /// If the key is ECDH encrypted, this is the ephemeral public key
222 PublicKey(Vec<u8>) with accessor public_key,
Paul Crowley44c02da2021-04-08 17:04:43 +0000223 /// If the key is encrypted with a MaxBootLevel key, this is the boot level
224 /// of that key
225 MaxBootLevel(i32) with accessor max_boot_level,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800226 // --- ADD NEW META DATA FIELDS HERE ---
227 // For backwards compatibility add new entries only to
228 // end of this list and above this comment.
229 };
230);
231
232impl BlobMetaData {
233 fn load_from_db(blob_id: i64, tx: &Transaction) -> Result<Self> {
234 let mut stmt = tx
235 .prepare(
236 "SELECT tag, data from persistent.blobmetadata
237 WHERE blobentryid = ?;",
238 )
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000239 .context(ks_err!("BlobMetaData::load_from_db: prepare statement failed."))?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800240
241 let mut metadata: HashMap<i64, BlobMetaEntry> = Default::default();
242
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000243 let mut rows = stmt.query(params![blob_id]).context(ks_err!("query failed."))?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800244 db_utils::with_rows_extract_all(&mut rows, |row| {
245 let db_tag: i64 = row.get(0).context("Failed to read tag.")?;
246 metadata.insert(
247 db_tag,
Chris Wailesd5aaaef2021-07-27 16:04:33 -0700248 BlobMetaEntry::new_from_sql(db_tag, &SqlField::new(1, row))
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800249 .context("Failed to read BlobMetaEntry.")?,
250 );
251 Ok(())
252 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000253 .context(ks_err!("BlobMetaData::load_from_db"))?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800254
255 Ok(Self { data: metadata })
256 }
257
258 fn store_in_db(&self, blob_id: i64, tx: &Transaction) -> Result<()> {
259 let mut stmt = tx
260 .prepare(
261 "INSERT or REPLACE INTO persistent.blobmetadata (blobentryid, tag, data)
262 VALUES (?, ?, ?);",
263 )
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000264 .context(ks_err!("BlobMetaData::store_in_db: Failed to prepare statement.",))?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800265
266 let iter = self.data.iter();
267 for (tag, entry) in iter {
268 stmt.insert(params![blob_id, tag, entry,]).with_context(|| {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000269 ks_err!("BlobMetaData::store_in_db: Failed to insert {:?}", entry)
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800270 })?;
271 }
272 Ok(())
273 }
274}
275
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800276/// Indicates the type of the keyentry.
277#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
278pub enum KeyType {
279 /// This is a client key type. These keys are created or imported through the Keystore 2.0
280 /// AIDL interface android.system.keystore2.
281 Client,
282 /// This is a super key type. These keys are created by keystore itself and used to encrypt
283 /// other key blobs to provide LSKF binding.
284 Super,
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800285}
286
287impl ToSql for KeyType {
288 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
289 Ok(ToSqlOutput::Owned(Value::Integer(match self {
290 KeyType::Client => 0,
291 KeyType::Super => 1,
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800292 })))
293 }
294}
295
296impl FromSql for KeyType {
297 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
298 match i64::column_result(value)? {
299 0 => Ok(KeyType::Client),
300 1 => Ok(KeyType::Super),
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800301 v => Err(FromSqlError::OutOfRange(v)),
302 }
303 }
304}
305
Max Bires8e93d2b2021-01-14 13:17:59 -0800306/// Uuid representation that can be stored in the database.
307/// Right now it can only be initialized from SecurityLevel.
308/// Once KeyMint provides a UUID type a corresponding From impl shall be added.
309#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
310pub struct Uuid([u8; 16]);
311
312impl Deref for Uuid {
313 type Target = [u8; 16];
314
315 fn deref(&self) -> &Self::Target {
316 &self.0
317 }
318}
319
320impl From<SecurityLevel> for Uuid {
321 fn from(sec_level: SecurityLevel) -> Self {
322 Self((sec_level.0 as u128).to_be_bytes())
323 }
324}
325
326impl ToSql for Uuid {
327 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
328 self.0.to_sql()
329 }
330}
331
332impl FromSql for Uuid {
333 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
334 let blob = Vec::<u8>::column_result(value)?;
335 if blob.len() != 16 {
336 return Err(FromSqlError::OutOfRange(blob.len() as i64));
337 }
338 let mut arr = [0u8; 16];
339 arr.copy_from_slice(&blob);
340 Ok(Self(arr))
341 }
342}
343
344/// Key entries that are not associated with any KeyMint instance, such as pure certificate
345/// entries are associated with this UUID.
346pub static KEYSTORE_UUID: Uuid = Uuid([
347 0x41, 0xe3, 0xb9, 0xce, 0x27, 0x58, 0x4e, 0x91, 0xbc, 0xfd, 0xa5, 0x5d, 0x91, 0x85, 0xab, 0x11,
348]);
349
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800350/// Indicates how the sensitive part of this key blob is encrypted.
351#[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
352pub enum EncryptedBy {
353 /// The keyblob is encrypted by a user password.
354 /// In the database this variant is represented as NULL.
355 Password,
356 /// The keyblob is encrypted by another key with wrapped key id.
357 /// In the database this variant is represented as non NULL value
358 /// that is convertible to i64, typically NUMERIC.
359 KeyId(i64),
360}
361
362impl ToSql for EncryptedBy {
363 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
364 match self {
365 Self::Password => Ok(ToSqlOutput::Owned(Value::Null)),
366 Self::KeyId(id) => id.to_sql(),
367 }
368 }
369}
370
371impl FromSql for EncryptedBy {
372 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
373 match value {
374 ValueRef::Null => Ok(Self::Password),
375 _ => Ok(Self::KeyId(i64::column_result(value)?)),
376 }
377 }
378}
379
380/// A database representation of wall clock time. DateTime stores unix epoch time as
381/// i64 in milliseconds.
382#[derive(Debug, Copy, Clone, Default, Eq, PartialEq, Ord, PartialOrd)]
383pub struct DateTime(i64);
384
385/// Error type returned when creating DateTime or converting it from and to
386/// SystemTime.
387#[derive(thiserror::Error, Debug)]
388pub enum DateTimeError {
389 /// This is returned when SystemTime and Duration computations fail.
390 #[error(transparent)]
391 SystemTimeError(#[from] SystemTimeError),
392
393 /// This is returned when type conversions fail.
394 #[error(transparent)]
395 TypeConversion(#[from] std::num::TryFromIntError),
396
397 /// This is returned when checked time arithmetic failed.
398 #[error("Time arithmetic failed.")]
399 TimeArithmetic,
400}
401
402impl DateTime {
403 /// Constructs a new DateTime object denoting the current time. This may fail during
404 /// conversion to unix epoch time and during conversion to the internal i64 representation.
405 pub fn now() -> Result<Self, DateTimeError> {
406 Ok(Self(SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_millis().try_into()?))
407 }
408
409 /// Constructs a new DateTime object from milliseconds.
410 pub fn from_millis_epoch(millis: i64) -> Self {
411 Self(millis)
412 }
413
414 /// Returns unix epoch time in milliseconds.
Chris Wailes3877f292021-07-26 19:24:18 -0700415 pub fn to_millis_epoch(self) -> i64 {
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800416 self.0
417 }
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800418}
419
420impl ToSql for DateTime {
421 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
422 Ok(ToSqlOutput::Owned(Value::Integer(self.0)))
423 }
424}
425
426impl FromSql for DateTime {
427 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
428 Ok(Self(i64::column_result(value)?))
429 }
430}
431
432impl TryInto<SystemTime> for DateTime {
433 type Error = DateTimeError;
434
435 fn try_into(self) -> Result<SystemTime, Self::Error> {
436 // We want to construct a SystemTime representation equivalent to self, denoting
437 // a point in time THEN, but we cannot set the time directly. We can only construct
438 // a SystemTime denoting NOW, and we can get the duration between EPOCH and NOW,
439 // and between EPOCH and THEN. With this common reference we can construct the
440 // duration between NOW and THEN which we can add to our SystemTime representation
441 // of NOW to get a SystemTime representation of THEN.
442 // Durations can only be positive, thus the if statement below.
443 let now = SystemTime::now();
444 let now_epoch = now.duration_since(SystemTime::UNIX_EPOCH)?;
445 let then_epoch = Duration::from_millis(self.0.try_into()?);
446 Ok(if now_epoch > then_epoch {
447 // then = now - (now_epoch - then_epoch)
448 now_epoch
449 .checked_sub(then_epoch)
450 .and_then(|d| now.checked_sub(d))
451 .ok_or(DateTimeError::TimeArithmetic)?
452 } else {
453 // then = now + (then_epoch - now_epoch)
454 then_epoch
455 .checked_sub(now_epoch)
456 .and_then(|d| now.checked_add(d))
457 .ok_or(DateTimeError::TimeArithmetic)?
458 })
459 }
460}
461
462impl TryFrom<SystemTime> for DateTime {
463 type Error = DateTimeError;
464
465 fn try_from(t: SystemTime) -> Result<Self, Self::Error> {
466 Ok(Self(t.duration_since(SystemTime::UNIX_EPOCH)?.as_millis().try_into()?))
467 }
468}
469
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800470#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone)]
471enum KeyLifeCycle {
472 /// Existing keys have a key ID but are not fully populated yet.
473 /// This is a transient state. If Keystore finds any such keys when it starts up, it must move
474 /// them to Unreferenced for garbage collection.
475 Existing,
476 /// A live key is fully populated and usable by clients.
477 Live,
478 /// An unreferenced key is scheduled for garbage collection.
479 Unreferenced,
480}
481
482impl ToSql for KeyLifeCycle {
483 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
484 match self {
485 Self::Existing => Ok(ToSqlOutput::Owned(Value::Integer(0))),
486 Self::Live => Ok(ToSqlOutput::Owned(Value::Integer(1))),
487 Self::Unreferenced => Ok(ToSqlOutput::Owned(Value::Integer(2))),
488 }
489 }
490}
491
492impl FromSql for KeyLifeCycle {
493 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
494 match i64::column_result(value)? {
495 0 => Ok(KeyLifeCycle::Existing),
496 1 => Ok(KeyLifeCycle::Live),
497 2 => Ok(KeyLifeCycle::Unreferenced),
498 v => Err(FromSqlError::OutOfRange(v)),
499 }
500 }
501}
502
David Drysdale8da288c2024-07-29 15:57:01 +0100503/// Current state of a `blobentry` row.
504#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone, Default)]
505enum BlobState {
506 #[default]
507 /// Current blobentry (of its `subcomponent_type`) for the associated key.
508 Current,
509 /// Blobentry that is no longer the current blob (of its `subcomponent_type`) for the associated
510 /// key.
511 Superseded,
512 /// Blobentry for a key that no longer exists.
513 Orphaned,
514}
515
516impl ToSql for BlobState {
517 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
518 match self {
519 Self::Current => Ok(ToSqlOutput::Owned(Value::Integer(0))),
520 Self::Superseded => Ok(ToSqlOutput::Owned(Value::Integer(1))),
521 Self::Orphaned => Ok(ToSqlOutput::Owned(Value::Integer(2))),
522 }
523 }
524}
525
526impl FromSql for BlobState {
527 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
528 match i64::column_result(value)? {
529 0 => Ok(Self::Current),
530 1 => Ok(Self::Superseded),
531 2 => Ok(Self::Orphaned),
532 v => Err(FromSqlError::OutOfRange(v)),
533 }
534 }
535}
536
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700537/// Keys have a KeyMint blob component and optional public certificate and
538/// certificate chain components.
539/// KeyEntryLoadBits is a bitmap that indicates to `KeystoreDB::load_key_entry`
540/// which components shall be loaded from the database if present.
Janis Danisevskis66784c42021-01-27 08:40:25 -0800541#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700542pub struct KeyEntryLoadBits(u32);
543
544impl KeyEntryLoadBits {
545 /// Indicate to `KeystoreDB::load_key_entry` that no component shall be loaded.
546 pub const NONE: KeyEntryLoadBits = Self(0);
547 /// Indicate to `KeystoreDB::load_key_entry` that the KeyMint component shall be loaded.
548 pub const KM: KeyEntryLoadBits = Self(1);
549 /// Indicate to `KeystoreDB::load_key_entry` that the Public components shall be loaded.
550 pub const PUBLIC: KeyEntryLoadBits = Self(2);
551 /// Indicate to `KeystoreDB::load_key_entry` that both components shall be loaded.
552 pub const BOTH: KeyEntryLoadBits = Self(3);
553
554 /// Returns true if this object indicates that the public components shall be loaded.
555 pub const fn load_public(&self) -> bool {
556 self.0 & Self::PUBLIC.0 != 0
557 }
558
559 /// Returns true if the object indicates that the KeyMint component shall be loaded.
560 pub const fn load_km(&self) -> bool {
561 self.0 & Self::KM.0 != 0
562 }
563}
564
Andrew Walbrana4bc1a92024-09-03 13:08:17 +0100565static KEY_ID_LOCK: LazyLock<KeyIdLockDb> = LazyLock::new(KeyIdLockDb::new);
Janis Danisevskisaec14592020-11-12 09:41:49 -0800566
567struct KeyIdLockDb {
568 locked_keys: Mutex<HashSet<i64>>,
569 cond_var: Condvar,
570}
571
572/// A locked key. While a guard exists for a given key id, the same key cannot be loaded
573/// from the database a second time. Most functions manipulating the key blob database
574/// require a KeyIdGuard.
575#[derive(Debug)]
576pub struct KeyIdGuard(i64);
577
578impl KeyIdLockDb {
579 fn new() -> Self {
580 Self { locked_keys: Mutex::new(HashSet::new()), cond_var: Condvar::new() }
581 }
582
583 /// This function blocks until an exclusive lock for the given key entry id can
584 /// be acquired. It returns a guard object, that represents the lifecycle of the
585 /// acquired lock.
David Drysdale8c4c4f32023-10-31 12:14:11 +0000586 fn get(&self, key_id: i64) -> KeyIdGuard {
Janis Danisevskisaec14592020-11-12 09:41:49 -0800587 let mut locked_keys = self.locked_keys.lock().unwrap();
588 while locked_keys.contains(&key_id) {
589 locked_keys = self.cond_var.wait(locked_keys).unwrap();
590 }
591 locked_keys.insert(key_id);
592 KeyIdGuard(key_id)
593 }
594
595 /// This function attempts to acquire an exclusive lock on a given key id. If the
596 /// given key id is already taken the function returns None immediately. If a lock
597 /// can be acquired this function returns a guard object, that represents the
598 /// lifecycle of the acquired lock.
David Drysdale8c4c4f32023-10-31 12:14:11 +0000599 fn try_get(&self, key_id: i64) -> Option<KeyIdGuard> {
Janis Danisevskisaec14592020-11-12 09:41:49 -0800600 let mut locked_keys = self.locked_keys.lock().unwrap();
601 if locked_keys.insert(key_id) {
602 Some(KeyIdGuard(key_id))
603 } else {
604 None
605 }
606 }
607}
608
609impl KeyIdGuard {
610 /// Get the numeric key id of the locked key.
611 pub fn id(&self) -> i64 {
612 self.0
613 }
614}
615
616impl Drop for KeyIdGuard {
617 fn drop(&mut self) {
618 let mut locked_keys = KEY_ID_LOCK.locked_keys.lock().unwrap();
619 locked_keys.remove(&self.0);
Janis Danisevskis7fd53582020-11-23 13:40:34 -0800620 drop(locked_keys);
Janis Danisevskisaec14592020-11-12 09:41:49 -0800621 KEY_ID_LOCK.cond_var.notify_all();
622 }
623}
624
Max Bires8e93d2b2021-01-14 13:17:59 -0800625/// This type represents a certificate and certificate chain entry for a key.
Max Bires2b2e6562020-09-22 11:22:36 -0700626#[derive(Debug, Default)]
Max Bires8e93d2b2021-01-14 13:17:59 -0800627pub struct CertificateInfo {
628 cert: Option<Vec<u8>>,
629 cert_chain: Option<Vec<u8>>,
630}
631
Janis Danisevskisf84d0b02022-01-26 14:11:14 -0800632/// This type represents a Blob with its metadata and an optional superseded blob.
633#[derive(Debug)]
634pub struct BlobInfo<'a> {
635 blob: &'a [u8],
636 metadata: &'a BlobMetaData,
637 /// Superseded blobs are an artifact of legacy import. In some rare occasions
638 /// the key blob needs to be upgraded during import. In that case two
639 /// blob are imported, the superseded one will have to be imported first,
640 /// so that the garbage collector can reap it.
641 superseded_blob: Option<(&'a [u8], &'a BlobMetaData)>,
642}
643
644impl<'a> BlobInfo<'a> {
645 /// Create a new instance of blob info with blob and corresponding metadata
646 /// and no superseded blob info.
647 pub fn new(blob: &'a [u8], metadata: &'a BlobMetaData) -> Self {
648 Self { blob, metadata, superseded_blob: None }
649 }
650
651 /// Create a new instance of blob info with blob and corresponding metadata
652 /// as well as superseded blob info.
653 pub fn new_with_superseded(
654 blob: &'a [u8],
655 metadata: &'a BlobMetaData,
656 superseded_blob: Option<(&'a [u8], &'a BlobMetaData)>,
657 ) -> Self {
658 Self { blob, metadata, superseded_blob }
659 }
660}
661
Max Bires8e93d2b2021-01-14 13:17:59 -0800662impl CertificateInfo {
663 /// Constructs a new CertificateInfo object from `cert` and `cert_chain`
664 pub fn new(cert: Option<Vec<u8>>, cert_chain: Option<Vec<u8>>) -> Self {
665 Self { cert, cert_chain }
666 }
667
668 /// Take the cert
669 pub fn take_cert(&mut self) -> Option<Vec<u8>> {
670 self.cert.take()
671 }
672
673 /// Take the cert chain
674 pub fn take_cert_chain(&mut self) -> Option<Vec<u8>> {
675 self.cert_chain.take()
676 }
677}
678
Max Bires2b2e6562020-09-22 11:22:36 -0700679/// This type represents a certificate chain with a private key corresponding to the leaf
680/// 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 -0700681pub struct CertificateChain {
Max Bires97f96812021-02-23 23:44:57 -0800682 /// A KM key blob
683 pub private_key: ZVec,
684 /// A batch cert for private_key
685 pub batch_cert: Vec<u8>,
686 /// A full certificate chain from root signing authority to private_key, including batch_cert
687 /// for convenience.
688 pub cert_chain: Vec<u8>,
Max Bires2b2e6562020-09-22 11:22:36 -0700689}
690
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700691/// This type represents a Keystore 2.0 key entry.
692/// An entry has a unique `id` by which it can be found in the database.
693/// It has a security level field, key parameters, and three optional fields
694/// for the KeyMint blob, public certificate and a public certificate chain.
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800695#[derive(Debug, Default, Eq, PartialEq)]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700696pub struct KeyEntry {
697 id: i64,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800698 key_blob_info: Option<(Vec<u8>, BlobMetaData)>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700699 cert: Option<Vec<u8>>,
700 cert_chain: Option<Vec<u8>>,
Max Bires8e93d2b2021-01-14 13:17:59 -0800701 km_uuid: Uuid,
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700702 parameters: Vec<KeyParameter>,
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800703 metadata: KeyMetaData,
Janis Danisevskis377d1002021-01-27 19:07:48 -0800704 pure_cert: bool,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700705}
706
707impl KeyEntry {
708 /// Returns the unique id of the Key entry.
709 pub fn id(&self) -> i64 {
710 self.id
711 }
712 /// Exposes the optional KeyMint blob.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800713 pub fn key_blob_info(&self) -> &Option<(Vec<u8>, BlobMetaData)> {
714 &self.key_blob_info
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700715 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800716 /// Extracts the Optional KeyMint blob including its metadata.
717 pub fn take_key_blob_info(&mut self) -> Option<(Vec<u8>, BlobMetaData)> {
718 self.key_blob_info.take()
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700719 }
720 /// Exposes the optional public certificate.
721 pub fn cert(&self) -> &Option<Vec<u8>> {
722 &self.cert
723 }
724 /// Extracts the optional public certificate.
725 pub fn take_cert(&mut self) -> Option<Vec<u8>> {
726 self.cert.take()
727 }
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700728 /// Extracts the optional public certificate_chain.
729 pub fn take_cert_chain(&mut self) -> Option<Vec<u8>> {
730 self.cert_chain.take()
731 }
Max Bires8e93d2b2021-01-14 13:17:59 -0800732 /// Returns the uuid of the owning KeyMint instance.
733 pub fn km_uuid(&self) -> &Uuid {
734 &self.km_uuid
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700735 }
Janis Danisevskis04b02832020-10-26 09:21:40 -0700736 /// Consumes this key entry and extracts the keyparameters from it.
737 pub fn into_key_parameters(self) -> Vec<KeyParameter> {
738 self.parameters
739 }
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800740 /// Exposes the key metadata of this key entry.
741 pub fn metadata(&self) -> &KeyMetaData {
742 &self.metadata
743 }
Janis Danisevskis377d1002021-01-27 19:07:48 -0800744 /// This returns true if the entry is a pure certificate entry with no
745 /// private key component.
746 pub fn pure_cert(&self) -> bool {
747 self.pure_cert
748 }
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700749}
750
751/// Indicates the sub component of a key entry for persistent storage.
Janis Danisevskis377d1002021-01-27 19:07:48 -0800752#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700753pub struct SubComponentType(u32);
754impl SubComponentType {
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800755 /// Persistent identifier for a key blob.
756 pub const KEY_BLOB: SubComponentType = Self(0);
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700757 /// Persistent identifier for a certificate blob.
758 pub const CERT: SubComponentType = Self(1);
759 /// Persistent identifier for a certificate chain blob.
760 pub const CERT_CHAIN: SubComponentType = Self(2);
761}
762
763impl ToSql for SubComponentType {
764 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
765 self.0.to_sql()
766 }
767}
768
769impl FromSql for SubComponentType {
770 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
771 Ok(Self(u32::column_result(value)?))
772 }
773}
774
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800775/// This trait is private to the database module. It is used to convey whether or not the garbage
776/// collector shall be invoked after a database access. All closures passed to
777/// `KeystoreDB::with_transaction` return a tuple (bool, T) where the bool indicates if the
778/// gc needs to be triggered. This convenience function allows to turn any anyhow::Result<T>
779/// into anyhow::Result<(bool, T)> by simply appending one of `.do_gc(bool)`, `.no_gc()`, or
780/// `.need_gc()`.
781trait DoGc<T> {
782 fn do_gc(self, need_gc: bool) -> Result<(bool, T)>;
783
784 fn no_gc(self) -> Result<(bool, T)>;
785
786 fn need_gc(self) -> Result<(bool, T)>;
787}
788
789impl<T> DoGc<T> for Result<T> {
790 fn do_gc(self, need_gc: bool) -> Result<(bool, T)> {
791 self.map(|r| (need_gc, r))
792 }
793
794 fn no_gc(self) -> Result<(bool, T)> {
795 self.do_gc(false)
796 }
797
798 fn need_gc(self) -> Result<(bool, T)> {
799 self.do_gc(true)
800 }
801}
802
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700803/// KeystoreDB wraps a connection to an SQLite database and tracks its
804/// ownership. It also implements all of Keystore 2.0's database functionality.
Joel Galenson26f4d012020-07-17 14:57:21 -0700805pub struct KeystoreDB {
Joel Galenson26f4d012020-07-17 14:57:21 -0700806 conn: Connection,
Janis Danisevskis3395f862021-05-06 10:54:17 -0700807 gc: Option<Arc<Gc>>,
Matthew Maurerd7815ca2021-05-06 21:58:45 -0700808 perboot: Arc<perboot::PerbootDB>,
Joel Galenson26f4d012020-07-17 14:57:21 -0700809}
810
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000811/// Database representation of the monotonic time retrieved from the system call clock_gettime with
Eric Biggers19b3b0d2024-01-31 22:46:47 +0000812/// CLOCK_BOOTTIME. Stores monotonic time as i64 in milliseconds.
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000813#[derive(Debug, Copy, Clone, Default, Eq, PartialEq, Ord, PartialOrd)]
Eric Biggers19b3b0d2024-01-31 22:46:47 +0000814pub struct BootTime(i64);
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000815
Eric Biggers19b3b0d2024-01-31 22:46:47 +0000816impl BootTime {
817 /// Constructs a new BootTime
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000818 pub fn now() -> Self {
Hasini Gunasinghe66a24602021-05-12 19:03:12 +0000819 Self(get_current_time_in_milliseconds())
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000820 }
821
Eric Biggers19b3b0d2024-01-31 22:46:47 +0000822 /// Returns the value of BootTime in milliseconds as i64
Hasini Gunasinghe66a24602021-05-12 19:03:12 +0000823 pub fn milliseconds(&self) -> i64 {
824 self.0
David Drysdale0e45a612021-02-25 17:24:36 +0000825 }
826
Eric Biggers19b3b0d2024-01-31 22:46:47 +0000827 /// Returns the integer value of BootTime as i64
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000828 pub fn seconds(&self) -> i64 {
Hasini Gunasinghe66a24602021-05-12 19:03:12 +0000829 self.0 / 1000
Hasini Gunasingheb3715fb2021-02-26 20:34:45 +0000830 }
831
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800832 /// Like i64::checked_sub.
833 pub fn checked_sub(&self, other: &Self) -> Option<Self> {
834 self.0.checked_sub(other.0).map(Self)
835 }
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000836}
837
Eric Biggers19b3b0d2024-01-31 22:46:47 +0000838impl ToSql for BootTime {
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000839 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
840 Ok(ToSqlOutput::Owned(Value::Integer(self.0)))
841 }
842}
843
Eric Biggers19b3b0d2024-01-31 22:46:47 +0000844impl FromSql for BootTime {
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000845 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
846 Ok(Self(i64::column_result(value)?))
847 }
848}
849
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000850/// This struct encapsulates the information to be stored in the database about the auth tokens
851/// received by keystore.
Matthew Maurerd7815ca2021-05-06 21:58:45 -0700852#[derive(Clone)]
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000853pub struct AuthTokenEntry {
854 auth_token: HardwareAuthToken,
Hasini Gunasinghe66a24602021-05-12 19:03:12 +0000855 // Time received in milliseconds
Eric Biggers19b3b0d2024-01-31 22:46:47 +0000856 time_received: BootTime,
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000857}
858
859impl AuthTokenEntry {
Eric Biggers19b3b0d2024-01-31 22:46:47 +0000860 fn new(auth_token: HardwareAuthToken, time_received: BootTime) -> Self {
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000861 AuthTokenEntry { auth_token, time_received }
862 }
863
864 /// Checks if this auth token satisfies the given authentication information.
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800865 pub fn satisfies(&self, user_secure_ids: &[i64], auth_type: HardwareAuthenticatorType) -> bool {
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000866 user_secure_ids.iter().any(|&sid| {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800867 (sid == self.auth_token.userId || sid == self.auth_token.authenticatorId)
Charisee03e00842023-01-25 01:41:23 +0000868 && ((auth_type.0 & self.auth_token.authenticatorType.0) != 0)
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000869 })
870 }
871
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000872 /// Returns the auth token wrapped by the AuthTokenEntry
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800873 pub fn auth_token(&self) -> &HardwareAuthToken {
874 &self.auth_token
875 }
876
877 /// Returns the auth token wrapped by the AuthTokenEntry
878 pub fn take_auth_token(self) -> HardwareAuthToken {
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000879 self.auth_token
880 }
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800881
882 /// Returns the time that this auth token was received.
Eric Biggers19b3b0d2024-01-31 22:46:47 +0000883 pub fn time_received(&self) -> BootTime {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800884 self.time_received
885 }
Hasini Gunasingheb3715fb2021-02-26 20:34:45 +0000886
887 /// Returns the challenge value of the auth token.
888 pub fn challenge(&self) -> i64 {
889 self.auth_token.challenge
890 }
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000891}
892
David Drysdalef1ba3812024-05-08 17:50:13 +0100893/// Information about a superseded blob (a blob that is no longer the
894/// most recent blob of that type for a given key, due to upgrade or
895/// replacement).
896pub struct SupersededBlob {
897 /// ID
898 pub blob_id: i64,
899 /// Contents.
900 pub blob: Vec<u8>,
901 /// Metadata.
902 pub metadata: BlobMetaData,
903}
904
Joel Galenson26f4d012020-07-17 14:57:21 -0700905impl KeystoreDB {
Janis Danisevskiseed69842021-02-18 20:04:10 -0800906 const UNASSIGNED_KEY_ID: i64 = -1i64;
David Drysdale8da288c2024-07-29 15:57:01 +0100907 const CURRENT_DB_VERSION: u32 = 2;
908 const UPGRADERS: &'static [fn(&Transaction) -> Result<u32>] =
909 &[Self::from_0_to_1, Self::from_1_to_2];
Janis Danisevskisb00ebd02021-02-02 21:52:24 -0800910
Seth Moore78c091f2021-04-09 21:38:30 +0000911 /// Name of the file that holds the cross-boot persistent database.
Chris Wailesd5aaaef2021-07-27 16:04:33 -0700912 pub const PERSISTENT_DB_FILENAME: &'static str = "persistent.sqlite";
Seth Moore78c091f2021-04-09 21:38:30 +0000913
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700914 /// This will create a new database connection connecting the two
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800915 /// files persistent.sqlite and perboot.sqlite in the given directory.
916 /// It also attempts to initialize all of the tables.
917 /// KeystoreDB cannot be used by multiple threads.
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700918 /// Each thread should open their own connection using `thread_local!`.
Janis Danisevskis3395f862021-05-06 10:54:17 -0700919 pub fn new(db_root: &Path, gc: Option<Arc<Gc>>) -> Result<Self> {
David Drysdale541846b2024-05-23 13:16:07 +0100920 let _wp = wd::watch("KeystoreDB::new");
Janis Danisevskis850d4862021-05-05 08:41:14 -0700921
Chris Wailesd5aaaef2021-07-27 16:04:33 -0700922 let persistent_path = Self::make_persistent_path(db_root)?;
Seth Moore472fcbb2021-05-12 10:07:51 -0700923 let conn = Self::make_connection(&persistent_path)?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800924
Matthew Maurerd7815ca2021-05-06 21:58:45 -0700925 let mut db = Self { conn, gc, perboot: perboot::PERBOOT_DB.clone() };
David Drysdale7b9ca232024-05-23 18:19:46 +0100926 db.with_transaction(Immediate("TX_new"), |tx| {
Janis Danisevskiscfaf9192021-05-26 16:31:02 -0700927 versioning::upgrade_database(tx, Self::CURRENT_DB_VERSION, Self::UPGRADERS)
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000928 .context(ks_err!("KeystoreDB::new: trying to upgrade database."))?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800929 Self::init_tables(tx).context("Trying to initialize tables.").no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -0800930 })?;
931 Ok(db)
Joel Galenson2aab4432020-07-22 15:27:57 -0700932 }
933
Janis Danisevskiscfaf9192021-05-26 16:31:02 -0700934 // This upgrade function deletes all MAX_BOOT_LEVEL keys, that were generated before
935 // cryptographic binding to the boot level keys was implemented.
936 fn from_0_to_1(tx: &Transaction) -> Result<u32> {
937 tx.execute(
938 "UPDATE persistent.keyentry SET state = ?
939 WHERE
940 id IN (SELECT keyentryid FROM persistent.keyparameter WHERE tag = ?)
941 AND
942 id NOT IN (
943 SELECT keyentryid FROM persistent.blobentry
944 WHERE id IN (
945 SELECT blobentryid FROM persistent.blobmetadata WHERE tag = ?
946 )
947 );",
948 params![KeyLifeCycle::Unreferenced, Tag::MAX_BOOT_LEVEL.0, BlobMetaData::MaxBootLevel],
949 )
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000950 .context(ks_err!("Failed to delete logical boot level keys."))?;
David Drysdale8da288c2024-07-29 15:57:01 +0100951
952 // DB version is now 1.
Janis Danisevskiscfaf9192021-05-26 16:31:02 -0700953 Ok(1)
954 }
955
David Drysdale8da288c2024-07-29 15:57:01 +0100956 // This upgrade function adds an additional `state INTEGER` column to the blobentry
957 // table, and populates it based on whether each blob is the most recent of its type for
958 // the corresponding key.
959 fn from_1_to_2(tx: &Transaction) -> Result<u32> {
960 tx.execute(
961 "ALTER TABLE persistent.blobentry ADD COLUMN state INTEGER DEFAULT 0;",
962 params![],
963 )
964 .context(ks_err!("Failed to add state column"))?;
965
966 // Mark keyblobs that are not the most recent for their corresponding key.
967 // This may take a while if there are excessive numbers of keys in the database.
968 let _wp = wd::watch("KeystoreDB::from_1_to_2 mark all non-current keyblobs");
969 let sc_key_blob = SubComponentType::KEY_BLOB;
970 let mut stmt = tx
971 .prepare(
972 "UPDATE persistent.blobentry SET state=?
973 WHERE subcomponent_type = ?
974 AND id NOT IN (
975 SELECT MAX(id) FROM persistent.blobentry
976 WHERE subcomponent_type = ?
977 GROUP BY keyentryid, subcomponent_type
978 );",
979 )
980 .context("Trying to prepare query to mark superseded keyblobs")?;
981 stmt.execute(params![BlobState::Superseded, sc_key_blob, sc_key_blob])
982 .context(ks_err!("Failed to set state=superseded state for keyblobs"))?;
983 log::info!("marked non-current blobentry rows for keyblobs as superseded");
984
985 // Mark keyblobs that don't have a corresponding key.
986 // This may take a while if there are excessive numbers of keys in the database.
987 let _wp = wd::watch("KeystoreDB::from_1_to_2 mark all orphaned keyblobs");
988 let mut stmt = tx
989 .prepare(
990 "UPDATE persistent.blobentry SET state=?
991 WHERE subcomponent_type = ?
992 AND NOT EXISTS (SELECT id FROM persistent.keyentry
993 WHERE id = keyentryid);",
994 )
995 .context("Trying to prepare query to mark orphaned keyblobs")?;
996 stmt.execute(params![BlobState::Orphaned, sc_key_blob])
997 .context(ks_err!("Failed to set state=orphaned for keyblobs"))?;
998 log::info!("marked orphaned blobentry rows for keyblobs");
999
1000 // Add an index to make it fast to find out of date blobentry rows.
1001 let _wp = wd::watch("KeystoreDB::from_1_to_2 add blobentry index");
1002 tx.execute(
1003 "CREATE INDEX IF NOT EXISTS persistent.blobentry_state_index
1004 ON blobentry(subcomponent_type, state);",
1005 [],
1006 )
1007 .context("Failed to create index blobentry_state_index.")?;
1008
1009 // Add an index to make it fast to find unreferenced keyentry rows.
1010 let _wp = wd::watch("KeystoreDB::from_1_to_2 add keyentry state index");
1011 tx.execute(
1012 "CREATE INDEX IF NOT EXISTS persistent.keyentry_state_index
1013 ON keyentry(state);",
1014 [],
1015 )
1016 .context("Failed to create index keyentry_state_index.")?;
1017
1018 // DB version is now 2.
1019 Ok(2)
1020 }
1021
Janis Danisevskis66784c42021-01-27 08:40:25 -08001022 fn init_tables(tx: &Transaction) -> Result<()> {
1023 tx.execute(
Janis Danisevskis4df44f42020-08-26 14:40:03 -07001024 "CREATE TABLE IF NOT EXISTS persistent.keyentry (
Joel Galenson0891bc12020-07-20 10:37:03 -07001025 id INTEGER UNIQUE,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001026 key_type INTEGER,
Joel Galenson0891bc12020-07-20 10:37:03 -07001027 domain INTEGER,
1028 namespace INTEGER,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001029 alias BLOB,
Max Bires8e93d2b2021-01-14 13:17:59 -08001030 state INTEGER,
1031 km_uuid BLOB);",
Andrew Walbran78abb1e2023-05-30 16:20:56 +00001032 [],
Janis Danisevskis4df44f42020-08-26 14:40:03 -07001033 )
1034 .context("Failed to initialize \"keyentry\" table.")?;
1035
Janis Danisevskis66784c42021-01-27 08:40:25 -08001036 tx.execute(
Janis Danisevskisa5438182021-02-02 14:22:59 -08001037 "CREATE INDEX IF NOT EXISTS persistent.keyentry_id_index
1038 ON keyentry(id);",
Andrew Walbran78abb1e2023-05-30 16:20:56 +00001039 [],
Janis Danisevskisa5438182021-02-02 14:22:59 -08001040 )
1041 .context("Failed to create index keyentry_id_index.")?;
1042
1043 tx.execute(
1044 "CREATE INDEX IF NOT EXISTS persistent.keyentry_domain_namespace_index
1045 ON keyentry(domain, namespace, alias);",
Andrew Walbran78abb1e2023-05-30 16:20:56 +00001046 [],
Janis Danisevskisa5438182021-02-02 14:22:59 -08001047 )
1048 .context("Failed to create index keyentry_domain_namespace_index.")?;
1049
David Drysdale8da288c2024-07-29 15:57:01 +01001050 // Index added in v2 of database schema.
1051 tx.execute(
1052 "CREATE INDEX IF NOT EXISTS persistent.keyentry_state_index
1053 ON keyentry(state);",
1054 [],
1055 )
1056 .context("Failed to create index keyentry_state_index.")?;
1057
Janis Danisevskisa5438182021-02-02 14:22:59 -08001058 tx.execute(
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001059 "CREATE TABLE IF NOT EXISTS persistent.blobentry (
1060 id INTEGER PRIMARY KEY,
1061 subcomponent_type INTEGER,
1062 keyentryid INTEGER,
David Drysdale8da288c2024-07-29 15:57:01 +01001063 blob BLOB,
1064 state INTEGER DEFAULT 0);", // `state` added in v2 of schema
Andrew Walbran78abb1e2023-05-30 16:20:56 +00001065 [],
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001066 )
1067 .context("Failed to initialize \"blobentry\" table.")?;
1068
Janis Danisevskis66784c42021-01-27 08:40:25 -08001069 tx.execute(
Janis Danisevskisa5438182021-02-02 14:22:59 -08001070 "CREATE INDEX IF NOT EXISTS persistent.blobentry_keyentryid_index
1071 ON blobentry(keyentryid);",
Andrew Walbran78abb1e2023-05-30 16:20:56 +00001072 [],
Janis Danisevskisa5438182021-02-02 14:22:59 -08001073 )
1074 .context("Failed to create index blobentry_keyentryid_index.")?;
1075
David Drysdale8da288c2024-07-29 15:57:01 +01001076 // Index added in v2 of database schema.
1077 tx.execute(
1078 "CREATE INDEX IF NOT EXISTS persistent.blobentry_state_index
1079 ON blobentry(subcomponent_type, state);",
1080 [],
1081 )
1082 .context("Failed to create index blobentry_state_index.")?;
1083
Janis Danisevskisa5438182021-02-02 14:22:59 -08001084 tx.execute(
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001085 "CREATE TABLE IF NOT EXISTS persistent.blobmetadata (
1086 id INTEGER PRIMARY KEY,
1087 blobentryid INTEGER,
1088 tag INTEGER,
1089 data ANY,
1090 UNIQUE (blobentryid, tag));",
Andrew Walbran78abb1e2023-05-30 16:20:56 +00001091 [],
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001092 )
1093 .context("Failed to initialize \"blobmetadata\" table.")?;
1094
1095 tx.execute(
1096 "CREATE INDEX IF NOT EXISTS persistent.blobmetadata_blobentryid_index
1097 ON blobmetadata(blobentryid);",
Andrew Walbran78abb1e2023-05-30 16:20:56 +00001098 [],
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001099 )
1100 .context("Failed to create index blobmetadata_blobentryid_index.")?;
1101
1102 tx.execute(
Janis Danisevskis4df44f42020-08-26 14:40:03 -07001103 "CREATE TABLE IF NOT EXISTS persistent.keyparameter (
Hasini Gunasingheaf993662020-07-24 18:40:20 +00001104 keyentryid INTEGER,
1105 tag INTEGER,
1106 data ANY,
1107 security_level INTEGER);",
Andrew Walbran78abb1e2023-05-30 16:20:56 +00001108 [],
Janis Danisevskis4df44f42020-08-26 14:40:03 -07001109 )
1110 .context("Failed to initialize \"keyparameter\" table.")?;
1111
Janis Danisevskis66784c42021-01-27 08:40:25 -08001112 tx.execute(
Janis Danisevskisa5438182021-02-02 14:22:59 -08001113 "CREATE INDEX IF NOT EXISTS persistent.keyparameter_keyentryid_index
1114 ON keyparameter(keyentryid);",
Andrew Walbran78abb1e2023-05-30 16:20:56 +00001115 [],
Janis Danisevskisa5438182021-02-02 14:22:59 -08001116 )
1117 .context("Failed to create index keyparameter_keyentryid_index.")?;
1118
1119 tx.execute(
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001120 "CREATE TABLE IF NOT EXISTS persistent.keymetadata (
1121 keyentryid INTEGER,
1122 tag INTEGER,
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00001123 data ANY,
1124 UNIQUE (keyentryid, tag));",
Andrew Walbran78abb1e2023-05-30 16:20:56 +00001125 [],
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001126 )
1127 .context("Failed to initialize \"keymetadata\" table.")?;
1128
Janis Danisevskis66784c42021-01-27 08:40:25 -08001129 tx.execute(
Janis Danisevskisa5438182021-02-02 14:22:59 -08001130 "CREATE INDEX IF NOT EXISTS persistent.keymetadata_keyentryid_index
1131 ON keymetadata(keyentryid);",
Andrew Walbran78abb1e2023-05-30 16:20:56 +00001132 [],
Janis Danisevskisa5438182021-02-02 14:22:59 -08001133 )
1134 .context("Failed to create index keymetadata_keyentryid_index.")?;
1135
1136 tx.execute(
Janis Danisevskisbf15d732020-12-08 10:35:26 -08001137 "CREATE TABLE IF NOT EXISTS persistent.grant (
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001138 id INTEGER UNIQUE,
1139 grantee INTEGER,
1140 keyentryid INTEGER,
1141 access_vector INTEGER);",
Andrew Walbran78abb1e2023-05-30 16:20:56 +00001142 [],
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001143 )
1144 .context("Failed to initialize \"grant\" table.")?;
1145
Joel Galenson0891bc12020-07-20 10:37:03 -07001146 Ok(())
1147 }
1148
Seth Moore472fcbb2021-05-12 10:07:51 -07001149 fn make_persistent_path(db_root: &Path) -> Result<String> {
1150 // Build the path to the sqlite file.
1151 let mut persistent_path = db_root.to_path_buf();
1152 persistent_path.push(Self::PERSISTENT_DB_FILENAME);
1153
1154 // Now convert them to strings prefixed with "file:"
1155 let mut persistent_path_str = "file:".to_owned();
1156 persistent_path_str.push_str(&persistent_path.to_string_lossy());
1157
Shaquille Johnson52b8c932023-12-19 19:45:32 +00001158 // Connect to database in specific mode
1159 let persistent_path_mode = if keystore2_flags::wal_db_journalmode_v3() {
1160 "?journal_mode=WAL".to_owned()
1161 } else {
1162 "?journal_mode=DELETE".to_owned()
1163 };
1164 persistent_path_str.push_str(&persistent_path_mode);
1165
Seth Moore472fcbb2021-05-12 10:07:51 -07001166 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 Drysdale541846b2024-05-23 13:16:07 +01001240 let _wp = wd::watch("KeystoreDB::get_storage_stat");
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,
2074 ) -> Result<(i64, KeyDescriptor, Option<KeyPermSet>)> {
2075 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
2090 Ok((key_id, access_key, None))
2091 }
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.")?;
Janis Danisevskis66784c42021-01-27 08:40:25 -08002116 Ok((key_id, key.clone(), Some(access_vector.into())))
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002117 }
2118
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002119 // Domain::KEY_ID. In this case we load the domain and namespace from the
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002120 // keyentry database because we need them for access control.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002121 Domain::KEY_ID => {
Janis Danisevskis45760022021-01-19 16:34:10 -08002122 let (domain, namespace): (Domain, i64) = {
2123 let mut stmt = tx
2124 .prepare(
2125 "SELECT domain, namespace FROM persistent.keyentry
2126 WHERE
2127 id = ?
2128 AND state = ?;",
2129 )
2130 .context("Domain::KEY_ID: prepare statement failed")?;
2131 let mut rows = stmt
2132 .query(params![key.nspace, KeyLifeCycle::Live])
2133 .context("Domain::KEY_ID: query failed.")?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002134 db_utils::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002135 let r =
2136 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002137 Ok((
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002138 Domain(r.get(0).context("Failed to unpack domain.")?),
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002139 r.get(1).context("Failed to unpack namespace.")?,
2140 ))
2141 })
Janis Danisevskis45760022021-01-19 16:34:10 -08002142 .context("Domain::KEY_ID.")?
2143 };
2144
2145 // We may use a key by id after loading it by grant.
2146 // In this case we have to check if the caller has a grant for this particular
2147 // key. We can skip this if we already know that the caller is the owner.
2148 // But we cannot know this if domain is anything but App. E.g. in the case
2149 // of Domain::SELINUX we have to speculatively check for grants because we have to
2150 // consult the SEPolicy before we know if the caller is the owner.
2151 let access_vector: Option<KeyPermSet> =
2152 if domain != Domain::APP || namespace != caller_uid as i64 {
2153 let access_vector: Option<i32> = tx
2154 .query_row(
2155 "SELECT access_vector FROM persistent.grant
2156 WHERE grantee = ? AND keyentryid = ?;",
2157 params![caller_uid as i64, key.nspace],
2158 |row| row.get(0),
2159 )
2160 .optional()
2161 .context("Domain::KEY_ID: query grant failed.")?;
2162 access_vector.map(|p| p.into())
2163 } else {
2164 None
2165 };
2166
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002167 let key_id = key.nspace;
Janis Danisevskis66784c42021-01-27 08:40:25 -08002168 let mut access_key: KeyDescriptor = key.clone();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002169 access_key.domain = domain;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002170 access_key.nspace = namespace;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002171
Janis Danisevskis45760022021-01-19 16:34:10 -08002172 Ok((key_id, access_key, access_vector))
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002173 }
Rajesh Nyamagoud625e5892022-05-18 01:31:26 +00002174 _ => Err(anyhow!(KsError::Rc(ResponseCode::INVALID_ARGUMENT))),
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002175 }
2176 }
2177
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002178 fn load_blob_components(
2179 key_id: i64,
2180 load_bits: KeyEntryLoadBits,
2181 tx: &Transaction,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002182 ) -> Result<(bool, Option<(Vec<u8>, BlobMetaData)>, Option<Vec<u8>>, Option<Vec<u8>>)> {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002183 let mut stmt = tx
2184 .prepare(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002185 "SELECT MAX(id), subcomponent_type, blob FROM persistent.blobentry
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002186 WHERE keyentryid = ? GROUP BY subcomponent_type;",
2187 )
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002188 .context(ks_err!("prepare statement failed."))?;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002189
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002190 let mut rows = stmt.query(params![key_id]).context(ks_err!("query failed."))?;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002191
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002192 let mut key_blob: Option<(i64, Vec<u8>)> = None;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002193 let mut cert_blob: Option<Vec<u8>> = None;
2194 let mut cert_chain_blob: Option<Vec<u8>> = None;
Janis Danisevskis377d1002021-01-27 19:07:48 -08002195 let mut has_km_blob: bool = false;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002196 db_utils::with_rows_extract_all(&mut rows, |row| {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002197 let sub_type: SubComponentType =
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002198 row.get(1).context("Failed to extract subcomponent_type.")?;
Janis Danisevskis377d1002021-01-27 19:07:48 -08002199 has_km_blob = has_km_blob || sub_type == SubComponentType::KEY_BLOB;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002200 match (sub_type, load_bits.load_public(), load_bits.load_km()) {
2201 (SubComponentType::KEY_BLOB, _, true) => {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002202 key_blob = Some((
2203 row.get(0).context("Failed to extract key blob id.")?,
2204 row.get(2).context("Failed to extract key blob.")?,
2205 ));
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002206 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002207 (SubComponentType::CERT, true, _) => {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002208 cert_blob =
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002209 Some(row.get(2).context("Failed to extract public certificate blob.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002210 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002211 (SubComponentType::CERT_CHAIN, true, _) => {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002212 cert_chain_blob =
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002213 Some(row.get(2).context("Failed to extract certificate chain blob.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002214 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002215 (SubComponentType::CERT, _, _)
2216 | (SubComponentType::CERT_CHAIN, _, _)
2217 | (SubComponentType::KEY_BLOB, _, _) => {}
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002218 _ => Err(KsError::sys()).context("Unknown subcomponent type.")?,
2219 }
2220 Ok(())
2221 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002222 .context(ks_err!())?;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002223
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002224 let blob_info = key_blob.map_or::<Result<_>, _>(Ok(None), |(blob_id, blob)| {
2225 Ok(Some((
2226 blob,
2227 BlobMetaData::load_from_db(blob_id, tx)
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002228 .context(ks_err!("Trying to load blob_metadata."))?,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002229 )))
2230 })?;
2231
2232 Ok((has_km_blob, blob_info, cert_blob, cert_chain_blob))
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002233 }
2234
2235 fn load_key_parameters(key_id: i64, tx: &Transaction) -> Result<Vec<KeyParameter>> {
2236 let mut stmt = tx
2237 .prepare(
2238 "SELECT tag, data, security_level from persistent.keyparameter
2239 WHERE keyentryid = ?;",
2240 )
2241 .context("In load_key_parameters: prepare statement failed.")?;
2242
2243 let mut parameters: Vec<KeyParameter> = Vec::new();
2244
2245 let mut rows =
2246 stmt.query(params![key_id]).context("In load_key_parameters: query failed.")?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002247 db_utils::with_rows_extract_all(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002248 let tag = Tag(row.get(0).context("Failed to read tag.")?);
2249 let sec_level = SecurityLevel(row.get(2).context("Failed to read sec_level.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002250 parameters.push(
Chris Wailesd5aaaef2021-07-27 16:04:33 -07002251 KeyParameter::new_from_sql(tag, &SqlField::new(1, row), sec_level)
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002252 .context("Failed to read KeyParameter.")?,
2253 );
2254 Ok(())
2255 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002256 .context(ks_err!())?;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002257
2258 Ok(parameters)
2259 }
2260
Qi Wub9433b52020-12-01 14:52:46 +08002261 /// Decrements the usage count of a limited use key. This function first checks whether the
2262 /// usage has been exhausted, if not, decreases the usage count. If the usage count reaches
2263 /// zero, the key also gets marked unreferenced and scheduled for deletion.
2264 /// Returns Ok(true) if the key was marked unreferenced as a hint to the garbage collector.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002265 pub fn check_and_update_key_usage_count(&mut self, key_id: i64) -> Result<()> {
David Drysdale541846b2024-05-23 13:16:07 +01002266 let _wp = wd::watch("KeystoreDB::check_and_update_key_usage_count");
Janis Danisevskis850d4862021-05-05 08:41:14 -07002267
David Drysdale7b9ca232024-05-23 18:19:46 +01002268 self.with_transaction(Immediate("TX_check_and_update_key_usage_count"), |tx| {
Qi Wub9433b52020-12-01 14:52:46 +08002269 let limit: Option<i32> = tx
2270 .query_row(
2271 "SELECT data FROM persistent.keyparameter WHERE keyentryid = ? AND tag = ?;",
2272 params![key_id, Tag::USAGE_COUNT_LIMIT.0],
2273 |row| row.get(0),
2274 )
2275 .optional()
2276 .context("Trying to load usage count")?;
2277
2278 let limit = limit
2279 .ok_or(KsError::Km(ErrorCode::INVALID_KEY_BLOB))
2280 .context("The Key no longer exists. Key is exhausted.")?;
2281
2282 tx.execute(
2283 "UPDATE persistent.keyparameter
2284 SET data = data - 1
2285 WHERE keyentryid = ? AND tag = ? AND data > 0;",
2286 params![key_id, Tag::USAGE_COUNT_LIMIT.0],
2287 )
2288 .context("Failed to update key usage count.")?;
2289
2290 match limit {
2291 1 => Self::mark_unreferenced(tx, key_id)
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002292 .map(|need_gc| (need_gc, ()))
Qi Wub9433b52020-12-01 14:52:46 +08002293 .context("Trying to mark limited use key for deletion."),
2294 0 => Err(KsError::Km(ErrorCode::INVALID_KEY_BLOB)).context("Key is exhausted."),
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002295 _ => Ok(()).no_gc(),
Qi Wub9433b52020-12-01 14:52:46 +08002296 }
2297 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002298 .context(ks_err!())
Qi Wub9433b52020-12-01 14:52:46 +08002299 }
2300
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002301 /// Load a key entry by the given key descriptor.
2302 /// It uses the `check_permission` callback to verify if the access is allowed
2303 /// given the key access tuple read from the database using `load_access_tuple`.
2304 /// With `load_bits` the caller may specify which blobs shall be loaded from
2305 /// the blob database.
2306 pub fn load_key_entry(
2307 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002308 key: &KeyDescriptor,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002309 key_type: KeyType,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002310 load_bits: KeyEntryLoadBits,
2311 caller_uid: u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002312 check_permission: impl Fn(&KeyDescriptor, Option<KeyPermSet>) -> Result<()>,
2313 ) -> Result<(KeyIdGuard, KeyEntry)> {
David Drysdale541846b2024-05-23 13:16:07 +01002314 let _wp = wd::watch("KeystoreDB::load_key_entry");
Janis Danisevskis850d4862021-05-05 08:41:14 -07002315
Janis Danisevskis66784c42021-01-27 08:40:25 -08002316 loop {
2317 match self.load_key_entry_internal(
2318 key,
2319 key_type,
2320 load_bits,
2321 caller_uid,
2322 &check_permission,
2323 ) {
2324 Ok(result) => break Ok(result),
2325 Err(e) => {
2326 if Self::is_locked_error(&e) {
David Drysdale115c4722024-04-15 14:11:52 +01002327 std::thread::sleep(DB_BUSY_RETRY_INTERVAL);
Janis Danisevskis66784c42021-01-27 08:40:25 -08002328 continue;
2329 } else {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002330 return Err(e).context(ks_err!());
Janis Danisevskis66784c42021-01-27 08:40:25 -08002331 }
2332 }
2333 }
2334 }
2335 }
2336
2337 fn load_key_entry_internal(
2338 &mut self,
2339 key: &KeyDescriptor,
2340 key_type: KeyType,
2341 load_bits: KeyEntryLoadBits,
2342 caller_uid: u32,
2343 check_permission: &impl Fn(&KeyDescriptor, Option<KeyPermSet>) -> Result<()>,
Janis Danisevskisaec14592020-11-12 09:41:49 -08002344 ) -> Result<(KeyIdGuard, KeyEntry)> {
2345 // KEY ID LOCK 1/2
2346 // If we got a key descriptor with a key id we can get the lock right away.
2347 // Otherwise we have to defer it until we know the key id.
2348 let key_id_guard = match key.domain {
2349 Domain::KEY_ID => Some(KEY_ID_LOCK.get(key.nspace)),
2350 _ => None,
2351 };
2352
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002353 let tx = self
2354 .conn
Janis Danisevskisaec14592020-11-12 09:41:49 -08002355 .unchecked_transaction()
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002356 .context(ks_err!("Failed to initialize transaction."))?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002357
2358 // Load the key_id and complete the access control tuple.
2359 let (key_id, access_key_descriptor, access_vector) =
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002360 Self::load_access_tuple(&tx, key, key_type, caller_uid).context(ks_err!())?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002361
2362 // Perform access control. It is vital that we return here if the permission is denied.
2363 // So do not touch that '?' at the end.
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002364 check_permission(&access_key_descriptor, access_vector).context(ks_err!())?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002365
Janis Danisevskisaec14592020-11-12 09:41:49 -08002366 // KEY ID LOCK 2/2
2367 // If we did not get a key id lock by now, it was because we got a key descriptor
2368 // without a key id. At this point we got the key id, so we can try and get a lock.
2369 // However, we cannot block here, because we are in the middle of the transaction.
2370 // So first we try to get the lock non blocking. If that fails, we roll back the
2371 // transaction and block until we get the lock. After we successfully got the lock,
2372 // we start a new transaction and load the access tuple again.
2373 //
2374 // We don't need to perform access control again, because we already established
2375 // that the caller had access to the given key. But we need to make sure that the
2376 // key id still exists. So we have to load the key entry by key id this time.
2377 let (key_id_guard, tx) = match key_id_guard {
2378 None => match KEY_ID_LOCK.try_get(key_id) {
2379 None => {
2380 // Roll back the transaction.
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002381 tx.rollback().context(ks_err!("Failed to roll back transaction."))?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002382
Janis Danisevskisaec14592020-11-12 09:41:49 -08002383 // Block until we have a key id lock.
2384 let key_id_guard = KEY_ID_LOCK.get(key_id);
2385
2386 // Create a new transaction.
Janis Danisevskis66784c42021-01-27 08:40:25 -08002387 let tx = self
2388 .conn
2389 .unchecked_transaction()
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002390 .context(ks_err!("Failed to initialize transaction."))?;
Janis Danisevskisaec14592020-11-12 09:41:49 -08002391
2392 Self::load_access_tuple(
2393 &tx,
2394 // This time we have to load the key by the retrieved key id, because the
2395 // alias may have been rebound after we rolled back the transaction.
Janis Danisevskis66784c42021-01-27 08:40:25 -08002396 &KeyDescriptor {
Janis Danisevskisaec14592020-11-12 09:41:49 -08002397 domain: Domain::KEY_ID,
2398 nspace: key_id,
2399 ..Default::default()
2400 },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002401 key_type,
Janis Danisevskisaec14592020-11-12 09:41:49 -08002402 caller_uid,
2403 )
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002404 .context(ks_err!("(deferred key lock)"))?;
Janis Danisevskisaec14592020-11-12 09:41:49 -08002405 (key_id_guard, tx)
2406 }
2407 Some(l) => (l, tx),
2408 },
2409 Some(key_id_guard) => (key_id_guard, tx),
2410 };
2411
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002412 let key_entry =
2413 Self::load_key_components(&tx, load_bits, key_id_guard.id()).context(ks_err!())?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002414
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002415 tx.commit().context(ks_err!("Failed to commit transaction."))?;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002416
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002417 Ok((key_id_guard, key_entry))
2418 }
2419
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002420 fn mark_unreferenced(tx: &Transaction, key_id: i64) -> Result<bool> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002421 let updated = tx
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002422 .execute("DELETE FROM persistent.keyentry WHERE id = ?;", params![key_id])
2423 .context("Trying to delete keyentry.")?;
2424 tx.execute("DELETE FROM persistent.keymetadata WHERE keyentryid = ?;", params![key_id])
2425 .context("Trying to delete keymetadata.")?;
2426 tx.execute("DELETE FROM persistent.keyparameter WHERE keyentryid = ?;", params![key_id])
2427 .context("Trying to delete keyparameters.")?;
2428 tx.execute("DELETE FROM persistent.grant WHERE keyentryid = ?;", params![key_id])
2429 .context("Trying to delete grants.")?;
David Drysdale8da288c2024-07-29 15:57:01 +01002430 // The associated blobentry rows are not immediately deleted when the owning keyentry is
2431 // removed, because a KeyMint `deleteKey()` invocation is needed (specifically for the
2432 // `KEY_BLOB`). Mark the affected rows with `state=Orphaned` so a subsequent garbage
2433 // collection can do this.
2434 tx.execute(
2435 "UPDATE persistent.blobentry SET state = ? WHERE keyentryid = ?",
2436 params![BlobState::Orphaned, key_id],
2437 )
2438 .context("Trying to mark blobentrys as superseded")?;
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002439 Ok(updated != 0)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002440 }
2441
2442 /// Marks the given key as unreferenced and removes all of the grants to this key.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002443 /// Returns Ok(true) if a key was marked unreferenced as a hint for the garbage collector.
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002444 pub fn unbind_key(
2445 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002446 key: &KeyDescriptor,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002447 key_type: KeyType,
2448 caller_uid: u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002449 check_permission: impl Fn(&KeyDescriptor, Option<KeyPermSet>) -> Result<()>,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002450 ) -> Result<()> {
David Drysdale541846b2024-05-23 13:16:07 +01002451 let _wp = wd::watch("KeystoreDB::unbind_key");
Janis Danisevskis850d4862021-05-05 08:41:14 -07002452
David Drysdale7b9ca232024-05-23 18:19:46 +01002453 self.with_transaction(Immediate("TX_unbind_key"), |tx| {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002454 let (key_id, access_key_descriptor, access_vector) =
2455 Self::load_access_tuple(tx, key, key_type, caller_uid)
2456 .context("Trying to get access tuple.")?;
2457
2458 // Perform access control. It is vital that we return here if the permission is denied.
2459 // So do not touch that '?' at the end.
2460 check_permission(&access_key_descriptor, access_vector)
2461 .context("While checking permission.")?;
2462
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002463 Self::mark_unreferenced(tx, key_id)
2464 .map(|need_gc| (need_gc, ()))
2465 .context("Trying to mark the key unreferenced.")
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002466 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002467 .context(ks_err!())
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002468 }
2469
Max Bires8e93d2b2021-01-14 13:17:59 -08002470 fn get_key_km_uuid(tx: &Transaction, key_id: i64) -> Result<Uuid> {
2471 tx.query_row(
2472 "SELECT km_uuid FROM persistent.keyentry WHERE id = ?",
2473 params![key_id],
2474 |row| row.get(0),
2475 )
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002476 .context(ks_err!())
Max Bires8e93d2b2021-01-14 13:17:59 -08002477 }
2478
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002479 /// Delete all artifacts belonging to the namespace given by the domain-namespace tuple.
2480 /// This leaves all of the blob entries orphaned for subsequent garbage collection.
2481 pub fn unbind_keys_for_namespace(&mut self, domain: Domain, namespace: i64) -> Result<()> {
David Drysdale541846b2024-05-23 13:16:07 +01002482 let _wp = wd::watch("KeystoreDB::unbind_keys_for_namespace");
Janis Danisevskis850d4862021-05-05 08:41:14 -07002483
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002484 if !(domain == Domain::APP || domain == Domain::SELINUX) {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002485 return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT)).context(ks_err!());
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002486 }
David Drysdale7b9ca232024-05-23 18:19:46 +01002487 self.with_transaction(Immediate("TX_unbind_keys_for_namespace"), |tx| {
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002488 tx.execute(
2489 "DELETE FROM persistent.keymetadata
2490 WHERE keyentryid IN (
2491 SELECT id FROM persistent.keyentry
Tri Vo0346bbe2023-05-12 14:16:31 -04002492 WHERE domain = ? AND namespace = ? AND key_type = ?
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002493 );",
Tri Vo0346bbe2023-05-12 14:16:31 -04002494 params![domain.0, namespace, KeyType::Client],
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002495 )
2496 .context("Trying to delete keymetadata.")?;
2497 tx.execute(
2498 "DELETE FROM persistent.keyparameter
2499 WHERE keyentryid IN (
2500 SELECT id FROM persistent.keyentry
Tri Vo0346bbe2023-05-12 14:16:31 -04002501 WHERE domain = ? AND namespace = ? AND key_type = ?
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002502 );",
Tri Vo0346bbe2023-05-12 14:16:31 -04002503 params![domain.0, namespace, KeyType::Client],
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002504 )
2505 .context("Trying to delete keyparameters.")?;
2506 tx.execute(
2507 "DELETE FROM persistent.grant
2508 WHERE keyentryid IN (
2509 SELECT id FROM persistent.keyentry
Tri Vo0346bbe2023-05-12 14:16:31 -04002510 WHERE domain = ? AND namespace = ? AND key_type = ?
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002511 );",
Tri Vo0346bbe2023-05-12 14:16:31 -04002512 params![domain.0, namespace, KeyType::Client],
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002513 )
2514 .context("Trying to delete grants.")?;
2515 tx.execute(
Janis Danisevskisb146f312021-05-06 15:05:45 -07002516 "DELETE FROM persistent.keyentry
Tri Vo0346bbe2023-05-12 14:16:31 -04002517 WHERE domain = ? AND namespace = ? AND key_type = ?;",
2518 params![domain.0, namespace, KeyType::Client],
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002519 )
2520 .context("Trying to delete keyentry.")?;
2521 Ok(()).need_gc()
2522 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002523 .context(ks_err!())
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002524 }
2525
Janis Danisevskis3cba10d2021-05-06 17:02:19 -07002526 fn cleanup_unreferenced(tx: &Transaction) -> Result<()> {
David Drysdale541846b2024-05-23 13:16:07 +01002527 let _wp = wd::watch("KeystoreDB::cleanup_unreferenced");
Janis Danisevskis3cba10d2021-05-06 17:02:19 -07002528 {
2529 tx.execute(
2530 "DELETE FROM persistent.keymetadata
2531 WHERE keyentryid IN (
2532 SELECT id FROM persistent.keyentry
2533 WHERE state = ?
2534 );",
2535 params![KeyLifeCycle::Unreferenced],
2536 )
2537 .context("Trying to delete keymetadata.")?;
2538 tx.execute(
2539 "DELETE FROM persistent.keyparameter
2540 WHERE keyentryid IN (
2541 SELECT id FROM persistent.keyentry
2542 WHERE state = ?
2543 );",
2544 params![KeyLifeCycle::Unreferenced],
2545 )
2546 .context("Trying to delete keyparameters.")?;
2547 tx.execute(
2548 "DELETE FROM persistent.grant
2549 WHERE keyentryid IN (
2550 SELECT id FROM persistent.keyentry
2551 WHERE state = ?
2552 );",
2553 params![KeyLifeCycle::Unreferenced],
2554 )
2555 .context("Trying to delete grants.")?;
2556 tx.execute(
2557 "DELETE FROM persistent.keyentry
2558 WHERE state = ?;",
2559 params![KeyLifeCycle::Unreferenced],
2560 )
2561 .context("Trying to delete keyentry.")?;
2562 Result::<()>::Ok(())
2563 }
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002564 .context(ks_err!())
Janis Danisevskis3cba10d2021-05-06 17:02:19 -07002565 }
2566
Eric Biggers9f7ebeb2024-06-20 14:59:32 +00002567 /// Deletes all keys for the given user, including both client keys and super keys.
2568 pub fn unbind_keys_for_user(&mut self, user_id: u32) -> Result<()> {
David Drysdale541846b2024-05-23 13:16:07 +01002569 let _wp = wd::watch("KeystoreDB::unbind_keys_for_user");
Janis Danisevskis850d4862021-05-05 08:41:14 -07002570
David Drysdale7b9ca232024-05-23 18:19:46 +01002571 self.with_transaction(Immediate("TX_unbind_keys_for_user"), |tx| {
Hasini Gunasingheda895552021-01-27 19:34:37 +00002572 let mut stmt = tx
2573 .prepare(&format!(
2574 "SELECT id from persistent.keyentry
2575 WHERE (
2576 key_type = ?
2577 AND domain = ?
2578 AND cast ( (namespace/{aid_user_offset}) as int) = ?
2579 AND state = ?
2580 ) OR (
2581 key_type = ?
2582 AND namespace = ?
Hasini Gunasingheda895552021-01-27 19:34:37 +00002583 AND state = ?
2584 );",
2585 aid_user_offset = AID_USER_OFFSET
2586 ))
2587 .context(concat!(
2588 "In unbind_keys_for_user. ",
2589 "Failed to prepare the query to find the keys created by apps."
2590 ))?;
2591
2592 let mut rows = stmt
2593 .query(params![
2594 // WHERE client key:
2595 KeyType::Client,
2596 Domain::APP.0 as u32,
2597 user_id,
2598 KeyLifeCycle::Live,
2599 // OR super key:
2600 KeyType::Super,
2601 user_id,
Hasini Gunasingheda895552021-01-27 19:34:37 +00002602 KeyLifeCycle::Live
2603 ])
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002604 .context(ks_err!("Failed to query the keys created by apps."))?;
Hasini Gunasingheda895552021-01-27 19:34:37 +00002605
2606 let mut key_ids: Vec<i64> = Vec::new();
2607 db_utils::with_rows_extract_all(&mut rows, |row| {
2608 key_ids
2609 .push(row.get(0).context("Failed to read key id of a key created by an app.")?);
2610 Ok(())
2611 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002612 .context(ks_err!())?;
Hasini Gunasingheda895552021-01-27 19:34:37 +00002613
2614 let mut notify_gc = false;
2615 for key_id in key_ids {
Chris Wailesd5aaaef2021-07-27 16:04:33 -07002616 notify_gc = Self::mark_unreferenced(tx, key_id)
Hasini Gunasingheda895552021-01-27 19:34:37 +00002617 .context("In unbind_keys_for_user.")?
2618 || notify_gc;
2619 }
2620 Ok(()).do_gc(notify_gc)
2621 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002622 .context(ks_err!())
Hasini Gunasingheda895552021-01-27 19:34:37 +00002623 }
2624
Eric Biggersb0478cf2023-10-27 03:55:29 +00002625 /// Deletes all auth-bound keys, i.e. keys that require user authentication, for the given user.
2626 /// This runs when the user's lock screen is being changed to Swipe or None.
2627 ///
2628 /// This intentionally does *not* delete keys that require that the device be unlocked, unless
2629 /// such keys also require user authentication. Keystore's concept of user authentication is
2630 /// fairly strong, and it requires that keys that require authentication be deleted as soon as
2631 /// authentication is no longer possible. In contrast, keys that just require that the device
2632 /// be unlocked should remain usable when the lock screen is set to Swipe or None, as the device
2633 /// is always considered "unlocked" in that case.
2634 pub fn unbind_auth_bound_keys_for_user(&mut self, user_id: u32) -> Result<()> {
David Drysdale541846b2024-05-23 13:16:07 +01002635 let _wp = wd::watch("KeystoreDB::unbind_auth_bound_keys_for_user");
Eric Biggersb0478cf2023-10-27 03:55:29 +00002636
David Drysdale7b9ca232024-05-23 18:19:46 +01002637 self.with_transaction(Immediate("TX_unbind_auth_bound_keys_for_user"), |tx| {
Eric Biggersb0478cf2023-10-27 03:55:29 +00002638 let mut stmt = tx
2639 .prepare(&format!(
2640 "SELECT id from persistent.keyentry
2641 WHERE key_type = ?
2642 AND domain = ?
2643 AND cast ( (namespace/{aid_user_offset}) as int) = ?
2644 AND state = ?;",
2645 aid_user_offset = AID_USER_OFFSET
2646 ))
2647 .context(concat!(
2648 "In unbind_auth_bound_keys_for_user. ",
2649 "Failed to prepare the query to find the keys created by apps."
2650 ))?;
2651
2652 let mut rows = stmt
2653 .query(params![KeyType::Client, Domain::APP.0 as u32, user_id, KeyLifeCycle::Live,])
2654 .context(ks_err!("Failed to query the keys created by apps."))?;
2655
2656 let mut key_ids: Vec<i64> = Vec::new();
2657 db_utils::with_rows_extract_all(&mut rows, |row| {
2658 key_ids
2659 .push(row.get(0).context("Failed to read key id of a key created by an app.")?);
2660 Ok(())
2661 })
2662 .context(ks_err!())?;
2663
2664 let mut notify_gc = false;
2665 let mut num_unbound = 0;
2666 for key_id in key_ids {
2667 // Load the key parameters and filter out non-auth-bound keys. To identify
2668 // auth-bound keys, use the presence of UserSecureID. The absence of NoAuthRequired
2669 // could also be used, but UserSecureID is what Keystore treats as authoritative
2670 // when actually enforcing the key parameters (it might not matter, though).
2671 let params = Self::load_key_parameters(key_id, tx)
2672 .context("Failed to load key parameters.")?;
2673 let is_auth_bound_key = params.iter().any(|kp| {
2674 matches!(kp.key_parameter_value(), KeyParameterValue::UserSecureID(_))
2675 });
2676 if is_auth_bound_key {
2677 notify_gc = Self::mark_unreferenced(tx, key_id)
2678 .context("In unbind_auth_bound_keys_for_user.")?
2679 || notify_gc;
2680 num_unbound += 1;
2681 }
2682 }
2683 log::info!("Deleting {num_unbound} auth-bound keys for user {user_id}");
2684 Ok(()).do_gc(notify_gc)
2685 })
2686 .context(ks_err!())
2687 }
2688
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002689 fn load_key_components(
2690 tx: &Transaction,
2691 load_bits: KeyEntryLoadBits,
2692 key_id: i64,
2693 ) -> Result<KeyEntry> {
Chris Wailesd5aaaef2021-07-27 16:04:33 -07002694 let metadata = KeyMetaData::load_from_db(key_id, tx).context("In load_key_components.")?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002695
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002696 let (has_km_blob, key_blob_info, cert_blob, cert_chain_blob) =
Chris Wailesd5aaaef2021-07-27 16:04:33 -07002697 Self::load_blob_components(key_id, load_bits, tx).context("In load_key_components.")?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002698
Chris Wailesd5aaaef2021-07-27 16:04:33 -07002699 let parameters = Self::load_key_parameters(key_id, tx)
Max Bires8e93d2b2021-01-14 13:17:59 -08002700 .context("In load_key_components: Trying to load key parameters.")?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002701
Chris Wailesd5aaaef2021-07-27 16:04:33 -07002702 let km_uuid = Self::get_key_km_uuid(tx, key_id)
Max Bires8e93d2b2021-01-14 13:17:59 -08002703 .context("In load_key_components: Trying to get KM uuid.")?;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002704
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002705 Ok(KeyEntry {
2706 id: key_id,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002707 key_blob_info,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002708 cert: cert_blob,
2709 cert_chain: cert_chain_blob,
Max Bires8e93d2b2021-01-14 13:17:59 -08002710 km_uuid,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002711 parameters,
2712 metadata,
Janis Danisevskis377d1002021-01-27 19:07:48 -08002713 pure_cert: !has_km_blob,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002714 })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002715 }
2716
Eran Messeri24f31972023-01-25 17:00:33 +00002717 /// Returns a list of KeyDescriptors in the selected domain/namespace whose
2718 /// aliases are greater than the specified 'start_past_alias'. If no value
2719 /// is provided, returns all KeyDescriptors.
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002720 /// The key descriptors will have the domain, nspace, and alias field set.
Eran Messeri24f31972023-01-25 17:00:33 +00002721 /// The returned list will be sorted by alias.
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002722 /// Domain must be APP or SELINUX, the caller must make sure of that.
David Drysdale8da288c2024-07-29 15:57:01 +01002723 /// Number of returned values is limited to 10,000 (which is empirically roughly
2724 /// what will fit in a Binder message).
Eran Messeri24f31972023-01-25 17:00:33 +00002725 pub fn list_past_alias(
Janis Danisevskis18313832021-05-17 13:30:32 -07002726 &mut self,
2727 domain: Domain,
2728 namespace: i64,
2729 key_type: KeyType,
Eran Messeri24f31972023-01-25 17:00:33 +00002730 start_past_alias: Option<&str>,
Janis Danisevskis18313832021-05-17 13:30:32 -07002731 ) -> Result<Vec<KeyDescriptor>> {
David Drysdale541846b2024-05-23 13:16:07 +01002732 let _wp = wd::watch("KeystoreDB::list_past_alias");
Janis Danisevskis850d4862021-05-05 08:41:14 -07002733
Eran Messeri24f31972023-01-25 17:00:33 +00002734 let query = format!(
2735 "SELECT DISTINCT alias FROM persistent.keyentry
Janis Danisevskis18313832021-05-17 13:30:32 -07002736 WHERE domain = ?
2737 AND namespace = ?
2738 AND alias IS NOT NULL
2739 AND state = ?
Eran Messeri24f31972023-01-25 17:00:33 +00002740 AND key_type = ?
2741 {}
David Drysdale8da288c2024-07-29 15:57:01 +01002742 ORDER BY alias ASC
2743 LIMIT 10000;",
Eran Messeri24f31972023-01-25 17:00:33 +00002744 if start_past_alias.is_some() { " AND alias > ?" } else { "" }
2745 );
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002746
Eran Messeri24f31972023-01-25 17:00:33 +00002747 self.with_transaction(TransactionBehavior::Deferred, |tx| {
2748 let mut stmt = tx.prepare(&query).context(ks_err!("Failed to prepare."))?;
2749
2750 let mut rows = match start_past_alias {
2751 Some(past_alias) => stmt
2752 .query(params![
2753 domain.0 as u32,
2754 namespace,
2755 KeyLifeCycle::Live,
2756 key_type,
2757 past_alias
2758 ])
2759 .context(ks_err!("Failed to query."))?,
2760 None => stmt
2761 .query(params![domain.0 as u32, namespace, KeyLifeCycle::Live, key_type,])
2762 .context(ks_err!("Failed to query."))?,
2763 };
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002764
Janis Danisevskis66784c42021-01-27 08:40:25 -08002765 let mut descriptors: Vec<KeyDescriptor> = Vec::new();
2766 db_utils::with_rows_extract_all(&mut rows, |row| {
2767 descriptors.push(KeyDescriptor {
2768 domain,
2769 nspace: namespace,
2770 alias: Some(row.get(0).context("Trying to extract alias.")?),
2771 blob: None,
2772 });
2773 Ok(())
2774 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002775 .context(ks_err!("Failed to extract rows."))?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002776 Ok(descriptors).no_gc()
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002777 })
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002778 }
2779
Eran Messeri24f31972023-01-25 17:00:33 +00002780 /// Returns a number of KeyDescriptors in the selected domain/namespace.
2781 /// Domain must be APP or SELINUX, the caller must make sure of that.
2782 pub fn count_keys(
2783 &mut self,
2784 domain: Domain,
2785 namespace: i64,
2786 key_type: KeyType,
2787 ) -> Result<usize> {
David Drysdale541846b2024-05-23 13:16:07 +01002788 let _wp = wd::watch("KeystoreDB::countKeys");
Eran Messeri24f31972023-01-25 17:00:33 +00002789
2790 let num_keys = self.with_transaction(TransactionBehavior::Deferred, |tx| {
2791 tx.query_row(
2792 "SELECT COUNT(alias) FROM persistent.keyentry
2793 WHERE domain = ?
2794 AND namespace = ?
2795 AND alias IS NOT NULL
2796 AND state = ?
2797 AND key_type = ?;",
2798 params![domain.0 as u32, namespace, KeyLifeCycle::Live, key_type],
2799 |row| row.get(0),
2800 )
2801 .context(ks_err!("Failed to count number of keys."))
2802 .no_gc()
2803 })?;
2804 Ok(num_keys)
2805 }
2806
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002807 /// Adds a grant to the grant table.
2808 /// Like `load_key_entry` this function loads the access tuple before
2809 /// it uses the callback for a permission check. Upon success,
2810 /// it inserts the `grantee_uid`, `key_id`, and `access_vector` into the
2811 /// grant table. The new row will have a randomized id, which is used as
2812 /// grant id in the namespace field of the resulting KeyDescriptor.
2813 pub fn grant(
2814 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002815 key: &KeyDescriptor,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002816 caller_uid: u32,
2817 grantee_uid: u32,
2818 access_vector: KeyPermSet,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002819 check_permission: impl Fn(&KeyDescriptor, &KeyPermSet) -> Result<()>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002820 ) -> Result<KeyDescriptor> {
David Drysdale541846b2024-05-23 13:16:07 +01002821 let _wp = wd::watch("KeystoreDB::grant");
Janis Danisevskis850d4862021-05-05 08:41:14 -07002822
David Drysdale7b9ca232024-05-23 18:19:46 +01002823 self.with_transaction(Immediate("TX_grant"), |tx| {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002824 // Load the key_id and complete the access control tuple.
2825 // We ignore the access vector here because grants cannot be granted.
2826 // The access vector returned here expresses the permissions the
2827 // grantee has if key.domain == Domain::GRANT. But this vector
2828 // cannot include the grant permission by design, so there is no way the
2829 // subsequent permission check can pass.
2830 // We could check key.domain == Domain::GRANT and fail early.
2831 // But even if we load the access tuple by grant here, the permission
2832 // check denies the attempt to create a grant by grant descriptor.
2833 let (key_id, access_key_descriptor, _) =
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002834 Self::load_access_tuple(tx, key, KeyType::Client, caller_uid).context(ks_err!())?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002835
Janis Danisevskis66784c42021-01-27 08:40:25 -08002836 // Perform access control. It is vital that we return here if the permission
2837 // was denied. So do not touch that '?' at the end of the line.
2838 // This permission check checks if the caller has the grant permission
2839 // for the given key and in addition to all of the permissions
2840 // expressed in `access_vector`.
2841 check_permission(&access_key_descriptor, &access_vector)
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002842 .context(ks_err!("check_permission failed"))?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002843
Janis Danisevskis66784c42021-01-27 08:40:25 -08002844 let grant_id = if let Some(grant_id) = tx
2845 .query_row(
2846 "SELECT id FROM persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002847 WHERE keyentryid = ? AND grantee = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08002848 params![key_id, grantee_uid],
2849 |row| row.get(0),
2850 )
2851 .optional()
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002852 .context(ks_err!("Failed get optional existing grant id."))?
Janis Danisevskis66784c42021-01-27 08:40:25 -08002853 {
2854 tx.execute(
2855 "UPDATE persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002856 SET access_vector = ?
2857 WHERE id = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08002858 params![i32::from(access_vector), grant_id],
Joel Galenson845f74b2020-09-09 14:11:55 -07002859 )
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002860 .context(ks_err!("Failed to update existing grant."))?;
Janis Danisevskis66784c42021-01-27 08:40:25 -08002861 grant_id
2862 } else {
2863 Self::insert_with_retry(|id| {
2864 tx.execute(
2865 "INSERT INTO persistent.grant (id, grantee, keyentryid, access_vector)
2866 VALUES (?, ?, ?, ?);",
2867 params![id, grantee_uid, key_id, i32::from(access_vector)],
2868 )
2869 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002870 .context(ks_err!())?
Janis Danisevskis66784c42021-01-27 08:40:25 -08002871 };
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002872
Janis Danisevskis66784c42021-01-27 08:40:25 -08002873 Ok(KeyDescriptor { domain: Domain::GRANT, nspace: grant_id, alias: None, blob: None })
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002874 .no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08002875 })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002876 }
2877
2878 /// This function checks permissions like `grant` and `load_key_entry`
2879 /// before removing a grant from the grant table.
2880 pub fn ungrant(
2881 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002882 key: &KeyDescriptor,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002883 caller_uid: u32,
2884 grantee_uid: u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002885 check_permission: impl Fn(&KeyDescriptor) -> Result<()>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002886 ) -> Result<()> {
David Drysdale541846b2024-05-23 13:16:07 +01002887 let _wp = wd::watch("KeystoreDB::ungrant");
Janis Danisevskis850d4862021-05-05 08:41:14 -07002888
David Drysdale7b9ca232024-05-23 18:19:46 +01002889 self.with_transaction(Immediate("TX_ungrant"), |tx| {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002890 // Load the key_id and complete the access control tuple.
2891 // We ignore the access vector here because grants cannot be granted.
2892 let (key_id, access_key_descriptor, _) =
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002893 Self::load_access_tuple(tx, key, KeyType::Client, caller_uid).context(ks_err!())?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002894
Janis Danisevskis66784c42021-01-27 08:40:25 -08002895 // Perform access control. We must return here if the permission
2896 // was denied. So do not touch the '?' at the end of this line.
2897 check_permission(&access_key_descriptor)
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002898 .context(ks_err!("check_permission failed."))?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002899
Janis Danisevskis66784c42021-01-27 08:40:25 -08002900 tx.execute(
2901 "DELETE FROM persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002902 WHERE keyentryid = ? AND grantee = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08002903 params![key_id, grantee_uid],
2904 )
2905 .context("Failed to delete grant.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002906
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002907 Ok(()).no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08002908 })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002909 }
2910
Joel Galenson845f74b2020-09-09 14:11:55 -07002911 // Generates a random id and passes it to the given function, which will
2912 // try to insert it into a database. If that insertion fails, retry;
2913 // otherwise return the id.
2914 fn insert_with_retry(inserter: impl Fn(i64) -> rusqlite::Result<usize>) -> Result<i64> {
2915 loop {
Janis Danisevskiseed69842021-02-18 20:04:10 -08002916 let newid: i64 = match random() {
2917 Self::UNASSIGNED_KEY_ID => continue, // UNASSIGNED_KEY_ID cannot be assigned.
2918 i => i,
2919 };
Joel Galenson845f74b2020-09-09 14:11:55 -07002920 match inserter(newid) {
2921 // If the id already existed, try again.
2922 Err(rusqlite::Error::SqliteFailure(
2923 libsqlite3_sys::Error {
2924 code: libsqlite3_sys::ErrorCode::ConstraintViolation,
2925 extended_code: libsqlite3_sys::SQLITE_CONSTRAINT_UNIQUE,
2926 },
2927 _,
2928 )) => (),
2929 Err(e) => {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002930 return Err(e).context(ks_err!("failed to insert into database."));
Joel Galenson845f74b2020-09-09 14:11:55 -07002931 }
2932 _ => return Ok(newid),
2933 }
2934 }
2935 }
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002936
Matthew Maurerd7815ca2021-05-06 21:58:45 -07002937 /// Insert or replace the auth token based on (user_id, auth_id, auth_type)
2938 pub fn insert_auth_token(&mut self, auth_token: &HardwareAuthToken) {
Eric Biggers19b3b0d2024-01-31 22:46:47 +00002939 self.perboot
2940 .insert_auth_token_entry(AuthTokenEntry::new(auth_token.clone(), BootTime::now()))
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002941 }
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002942
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002943 /// Find the newest auth token matching the given predicate.
Eric Biggersb5613da2024-03-13 19:31:42 +00002944 pub fn find_auth_token_entry<F>(&self, p: F) -> Option<AuthTokenEntry>
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002945 where
2946 F: Fn(&AuthTokenEntry) -> bool,
2947 {
Eric Biggersb5613da2024-03-13 19:31:42 +00002948 self.perboot.find_auth_token_entry(p)
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002949 }
Pavel Grafovf45034a2021-05-12 22:35:45 +01002950
2951 /// Load descriptor of a key by key id
2952 pub fn load_key_descriptor(&mut self, key_id: i64) -> Result<Option<KeyDescriptor>> {
David Drysdale541846b2024-05-23 13:16:07 +01002953 let _wp = wd::watch("KeystoreDB::load_key_descriptor");
Pavel Grafovf45034a2021-05-12 22:35:45 +01002954
2955 self.with_transaction(TransactionBehavior::Deferred, |tx| {
2956 tx.query_row(
2957 "SELECT domain, namespace, alias FROM persistent.keyentry WHERE id = ?;",
2958 params![key_id],
2959 |row| {
2960 Ok(KeyDescriptor {
2961 domain: Domain(row.get(0)?),
2962 nspace: row.get(1)?,
2963 alias: row.get(2)?,
2964 blob: None,
2965 })
2966 },
2967 )
2968 .optional()
2969 .context("Trying to load key descriptor")
2970 .no_gc()
2971 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002972 .context(ks_err!())
Pavel Grafovf45034a2021-05-12 22:35:45 +01002973 }
Eran Messeri4dc27b52024-01-09 12:43:31 +00002974
2975 /// Returns a list of app UIDs that have keys authenticated by the given secure_user_id
2976 /// (for the given user_id).
2977 /// This is helpful for finding out which apps will have their keys invalidated when
2978 /// the user changes biometrics enrollment or removes their LSKF.
2979 pub fn get_app_uids_affected_by_sid(
2980 &mut self,
2981 user_id: i32,
2982 secure_user_id: i64,
2983 ) -> Result<Vec<i64>> {
David Drysdale541846b2024-05-23 13:16:07 +01002984 let _wp = wd::watch("KeystoreDB::get_app_uids_affected_by_sid");
Eran Messeri4dc27b52024-01-09 12:43:31 +00002985
David Drysdale7b9ca232024-05-23 18:19:46 +01002986 let ids = self.with_transaction(Immediate("TX_get_app_uids_affected_by_sid"), |tx| {
Eran Messeri4dc27b52024-01-09 12:43:31 +00002987 let mut stmt = tx
2988 .prepare(&format!(
2989 "SELECT id, namespace from persistent.keyentry
2990 WHERE key_type = ?
2991 AND domain = ?
2992 AND cast ( (namespace/{AID_USER_OFFSET}) as int) = ?
2993 AND state = ?;",
2994 ))
2995 .context(concat!(
2996 "In get_app_uids_affected_by_sid, ",
2997 "failed to prepare the query to find the keys created by apps."
2998 ))?;
2999
3000 let mut rows = stmt
3001 .query(params![KeyType::Client, Domain::APP.0 as u32, user_id, KeyLifeCycle::Live,])
3002 .context(ks_err!("Failed to query the keys created by apps."))?;
3003
3004 let mut key_ids_and_app_uids: HashMap<i64, i64> = Default::default();
3005 db_utils::with_rows_extract_all(&mut rows, |row| {
3006 key_ids_and_app_uids.insert(
3007 row.get(0).context("Failed to read key id of a key created by an app.")?,
3008 row.get(1).context("Failed to read the app uid")?,
3009 );
3010 Ok(())
3011 })?;
3012 Ok(key_ids_and_app_uids).no_gc()
3013 })?;
3014 let mut app_uids_affected_by_sid: HashSet<i64> = Default::default();
David Drysdale7b9ca232024-05-23 18:19:46 +01003015 for (key_id, app_uid) in ids {
Eran Messeri4dc27b52024-01-09 12:43:31 +00003016 // Read the key parameters for each key in its own transaction. It is OK to ignore
3017 // an error to get the properties of a particular key since it might have been deleted
3018 // under our feet after the previous transaction concluded. If the key was deleted
3019 // then it is no longer applicable if it was auth-bound or not.
3020 if let Ok(is_key_bound_to_sid) =
David Drysdale7b9ca232024-05-23 18:19:46 +01003021 self.with_transaction(Immediate("TX_get_app_uids_affects_by_sid 2"), |tx| {
Eran Messeri4dc27b52024-01-09 12:43:31 +00003022 let params = Self::load_key_parameters(key_id, tx)
3023 .context("Failed to load key parameters.")?;
3024 // Check if the key is bound to this secure user ID.
3025 let is_key_bound_to_sid = params.iter().any(|kp| {
3026 matches!(
3027 kp.key_parameter_value(),
3028 KeyParameterValue::UserSecureID(sid) if *sid == secure_user_id
3029 )
3030 });
3031 Ok(is_key_bound_to_sid).no_gc()
3032 })
3033 {
3034 if is_key_bound_to_sid {
3035 app_uids_affected_by_sid.insert(app_uid);
3036 }
3037 }
3038 }
3039
3040 let app_uids_vec: Vec<i64> = app_uids_affected_by_sid.into_iter().collect();
3041 Ok(app_uids_vec)
3042 }
Joel Galenson26f4d012020-07-17 14:57:21 -07003043}