blob: 84576034e263e55b22b705773dcaceca7649263f [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
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700503/// Keys have a KeyMint blob component and optional public certificate and
504/// certificate chain components.
505/// KeyEntryLoadBits is a bitmap that indicates to `KeystoreDB::load_key_entry`
506/// which components shall be loaded from the database if present.
Janis Danisevskis66784c42021-01-27 08:40:25 -0800507#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700508pub struct KeyEntryLoadBits(u32);
509
510impl KeyEntryLoadBits {
511 /// Indicate to `KeystoreDB::load_key_entry` that no component shall be loaded.
512 pub const NONE: KeyEntryLoadBits = Self(0);
513 /// Indicate to `KeystoreDB::load_key_entry` that the KeyMint component shall be loaded.
514 pub const KM: KeyEntryLoadBits = Self(1);
515 /// Indicate to `KeystoreDB::load_key_entry` that the Public components shall be loaded.
516 pub const PUBLIC: KeyEntryLoadBits = Self(2);
517 /// Indicate to `KeystoreDB::load_key_entry` that both components shall be loaded.
518 pub const BOTH: KeyEntryLoadBits = Self(3);
519
520 /// Returns true if this object indicates that the public components shall be loaded.
521 pub const fn load_public(&self) -> bool {
522 self.0 & Self::PUBLIC.0 != 0
523 }
524
525 /// Returns true if the object indicates that the KeyMint component shall be loaded.
526 pub const fn load_km(&self) -> bool {
527 self.0 & Self::KM.0 != 0
528 }
529}
530
Andrew Walbrana4bc1a92024-09-03 13:08:17 +0100531static KEY_ID_LOCK: LazyLock<KeyIdLockDb> = LazyLock::new(KeyIdLockDb::new);
Janis Danisevskisaec14592020-11-12 09:41:49 -0800532
533struct KeyIdLockDb {
534 locked_keys: Mutex<HashSet<i64>>,
535 cond_var: Condvar,
536}
537
538/// A locked key. While a guard exists for a given key id, the same key cannot be loaded
539/// from the database a second time. Most functions manipulating the key blob database
540/// require a KeyIdGuard.
541#[derive(Debug)]
542pub struct KeyIdGuard(i64);
543
544impl KeyIdLockDb {
545 fn new() -> Self {
546 Self { locked_keys: Mutex::new(HashSet::new()), cond_var: Condvar::new() }
547 }
548
549 /// This function blocks until an exclusive lock for the given key entry id can
550 /// be acquired. It returns a guard object, that represents the lifecycle of the
551 /// acquired lock.
David Drysdale8c4c4f32023-10-31 12:14:11 +0000552 fn get(&self, key_id: i64) -> KeyIdGuard {
Janis Danisevskisaec14592020-11-12 09:41:49 -0800553 let mut locked_keys = self.locked_keys.lock().unwrap();
554 while locked_keys.contains(&key_id) {
555 locked_keys = self.cond_var.wait(locked_keys).unwrap();
556 }
557 locked_keys.insert(key_id);
558 KeyIdGuard(key_id)
559 }
560
561 /// This function attempts to acquire an exclusive lock on a given key id. If the
562 /// given key id is already taken the function returns None immediately. If a lock
563 /// can be acquired this function returns a guard object, that represents the
564 /// lifecycle of the acquired lock.
David Drysdale8c4c4f32023-10-31 12:14:11 +0000565 fn try_get(&self, key_id: i64) -> Option<KeyIdGuard> {
Janis Danisevskisaec14592020-11-12 09:41:49 -0800566 let mut locked_keys = self.locked_keys.lock().unwrap();
567 if locked_keys.insert(key_id) {
568 Some(KeyIdGuard(key_id))
569 } else {
570 None
571 }
572 }
573}
574
575impl KeyIdGuard {
576 /// Get the numeric key id of the locked key.
577 pub fn id(&self) -> i64 {
578 self.0
579 }
580}
581
582impl Drop for KeyIdGuard {
583 fn drop(&mut self) {
584 let mut locked_keys = KEY_ID_LOCK.locked_keys.lock().unwrap();
585 locked_keys.remove(&self.0);
Janis Danisevskis7fd53582020-11-23 13:40:34 -0800586 drop(locked_keys);
Janis Danisevskisaec14592020-11-12 09:41:49 -0800587 KEY_ID_LOCK.cond_var.notify_all();
588 }
589}
590
Max Bires8e93d2b2021-01-14 13:17:59 -0800591/// This type represents a certificate and certificate chain entry for a key.
Max Bires2b2e6562020-09-22 11:22:36 -0700592#[derive(Debug, Default)]
Max Bires8e93d2b2021-01-14 13:17:59 -0800593pub struct CertificateInfo {
594 cert: Option<Vec<u8>>,
595 cert_chain: Option<Vec<u8>>,
596}
597
Janis Danisevskisf84d0b02022-01-26 14:11:14 -0800598/// This type represents a Blob with its metadata and an optional superseded blob.
599#[derive(Debug)]
600pub struct BlobInfo<'a> {
601 blob: &'a [u8],
602 metadata: &'a BlobMetaData,
603 /// Superseded blobs are an artifact of legacy import. In some rare occasions
604 /// the key blob needs to be upgraded during import. In that case two
605 /// blob are imported, the superseded one will have to be imported first,
606 /// so that the garbage collector can reap it.
607 superseded_blob: Option<(&'a [u8], &'a BlobMetaData)>,
608}
609
610impl<'a> BlobInfo<'a> {
611 /// Create a new instance of blob info with blob and corresponding metadata
612 /// and no superseded blob info.
613 pub fn new(blob: &'a [u8], metadata: &'a BlobMetaData) -> Self {
614 Self { blob, metadata, superseded_blob: None }
615 }
616
617 /// Create a new instance of blob info with blob and corresponding metadata
618 /// as well as superseded blob info.
619 pub fn new_with_superseded(
620 blob: &'a [u8],
621 metadata: &'a BlobMetaData,
622 superseded_blob: Option<(&'a [u8], &'a BlobMetaData)>,
623 ) -> Self {
624 Self { blob, metadata, superseded_blob }
625 }
626}
627
Max Bires8e93d2b2021-01-14 13:17:59 -0800628impl CertificateInfo {
629 /// Constructs a new CertificateInfo object from `cert` and `cert_chain`
630 pub fn new(cert: Option<Vec<u8>>, cert_chain: Option<Vec<u8>>) -> Self {
631 Self { cert, cert_chain }
632 }
633
634 /// Take the cert
635 pub fn take_cert(&mut self) -> Option<Vec<u8>> {
636 self.cert.take()
637 }
638
639 /// Take the cert chain
640 pub fn take_cert_chain(&mut self) -> Option<Vec<u8>> {
641 self.cert_chain.take()
642 }
643}
644
Max Bires2b2e6562020-09-22 11:22:36 -0700645/// This type represents a certificate chain with a private key corresponding to the leaf
646/// 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 -0700647pub struct CertificateChain {
Max Bires97f96812021-02-23 23:44:57 -0800648 /// A KM key blob
649 pub private_key: ZVec,
650 /// A batch cert for private_key
651 pub batch_cert: Vec<u8>,
652 /// A full certificate chain from root signing authority to private_key, including batch_cert
653 /// for convenience.
654 pub cert_chain: Vec<u8>,
Max Bires2b2e6562020-09-22 11:22:36 -0700655}
656
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700657/// This type represents a Keystore 2.0 key entry.
658/// An entry has a unique `id` by which it can be found in the database.
659/// It has a security level field, key parameters, and three optional fields
660/// for the KeyMint blob, public certificate and a public certificate chain.
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800661#[derive(Debug, Default, Eq, PartialEq)]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700662pub struct KeyEntry {
663 id: i64,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800664 key_blob_info: Option<(Vec<u8>, BlobMetaData)>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700665 cert: Option<Vec<u8>>,
666 cert_chain: Option<Vec<u8>>,
Max Bires8e93d2b2021-01-14 13:17:59 -0800667 km_uuid: Uuid,
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700668 parameters: Vec<KeyParameter>,
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800669 metadata: KeyMetaData,
Janis Danisevskis377d1002021-01-27 19:07:48 -0800670 pure_cert: bool,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700671}
672
673impl KeyEntry {
674 /// Returns the unique id of the Key entry.
675 pub fn id(&self) -> i64 {
676 self.id
677 }
678 /// Exposes the optional KeyMint blob.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800679 pub fn key_blob_info(&self) -> &Option<(Vec<u8>, BlobMetaData)> {
680 &self.key_blob_info
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700681 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800682 /// Extracts the Optional KeyMint blob including its metadata.
683 pub fn take_key_blob_info(&mut self) -> Option<(Vec<u8>, BlobMetaData)> {
684 self.key_blob_info.take()
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700685 }
686 /// Exposes the optional public certificate.
687 pub fn cert(&self) -> &Option<Vec<u8>> {
688 &self.cert
689 }
690 /// Extracts the optional public certificate.
691 pub fn take_cert(&mut self) -> Option<Vec<u8>> {
692 self.cert.take()
693 }
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700694 /// Extracts the optional public certificate_chain.
695 pub fn take_cert_chain(&mut self) -> Option<Vec<u8>> {
696 self.cert_chain.take()
697 }
Max Bires8e93d2b2021-01-14 13:17:59 -0800698 /// Returns the uuid of the owning KeyMint instance.
699 pub fn km_uuid(&self) -> &Uuid {
700 &self.km_uuid
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700701 }
Janis Danisevskis04b02832020-10-26 09:21:40 -0700702 /// Consumes this key entry and extracts the keyparameters from it.
703 pub fn into_key_parameters(self) -> Vec<KeyParameter> {
704 self.parameters
705 }
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800706 /// Exposes the key metadata of this key entry.
707 pub fn metadata(&self) -> &KeyMetaData {
708 &self.metadata
709 }
Janis Danisevskis377d1002021-01-27 19:07:48 -0800710 /// This returns true if the entry is a pure certificate entry with no
711 /// private key component.
712 pub fn pure_cert(&self) -> bool {
713 self.pure_cert
714 }
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700715}
716
717/// Indicates the sub component of a key entry for persistent storage.
Janis Danisevskis377d1002021-01-27 19:07:48 -0800718#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700719pub struct SubComponentType(u32);
720impl SubComponentType {
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800721 /// Persistent identifier for a key blob.
722 pub const KEY_BLOB: SubComponentType = Self(0);
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700723 /// Persistent identifier for a certificate blob.
724 pub const CERT: SubComponentType = Self(1);
725 /// Persistent identifier for a certificate chain blob.
726 pub const CERT_CHAIN: SubComponentType = Self(2);
727}
728
729impl ToSql for SubComponentType {
730 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
731 self.0.to_sql()
732 }
733}
734
735impl FromSql for SubComponentType {
736 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
737 Ok(Self(u32::column_result(value)?))
738 }
739}
740
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800741/// This trait is private to the database module. It is used to convey whether or not the garbage
742/// collector shall be invoked after a database access. All closures passed to
743/// `KeystoreDB::with_transaction` return a tuple (bool, T) where the bool indicates if the
744/// gc needs to be triggered. This convenience function allows to turn any anyhow::Result<T>
745/// into anyhow::Result<(bool, T)> by simply appending one of `.do_gc(bool)`, `.no_gc()`, or
746/// `.need_gc()`.
747trait DoGc<T> {
748 fn do_gc(self, need_gc: bool) -> Result<(bool, T)>;
749
750 fn no_gc(self) -> Result<(bool, T)>;
751
752 fn need_gc(self) -> Result<(bool, T)>;
753}
754
755impl<T> DoGc<T> for Result<T> {
756 fn do_gc(self, need_gc: bool) -> Result<(bool, T)> {
757 self.map(|r| (need_gc, r))
758 }
759
760 fn no_gc(self) -> Result<(bool, T)> {
761 self.do_gc(false)
762 }
763
764 fn need_gc(self) -> Result<(bool, T)> {
765 self.do_gc(true)
766 }
767}
768
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700769/// KeystoreDB wraps a connection to an SQLite database and tracks its
770/// ownership. It also implements all of Keystore 2.0's database functionality.
Joel Galenson26f4d012020-07-17 14:57:21 -0700771pub struct KeystoreDB {
Joel Galenson26f4d012020-07-17 14:57:21 -0700772 conn: Connection,
Janis Danisevskis3395f862021-05-06 10:54:17 -0700773 gc: Option<Arc<Gc>>,
Matthew Maurerd7815ca2021-05-06 21:58:45 -0700774 perboot: Arc<perboot::PerbootDB>,
Joel Galenson26f4d012020-07-17 14:57:21 -0700775}
776
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000777/// Database representation of the monotonic time retrieved from the system call clock_gettime with
Eric Biggers19b3b0d2024-01-31 22:46:47 +0000778/// CLOCK_BOOTTIME. Stores monotonic time as i64 in milliseconds.
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000779#[derive(Debug, Copy, Clone, Default, Eq, PartialEq, Ord, PartialOrd)]
Eric Biggers19b3b0d2024-01-31 22:46:47 +0000780pub struct BootTime(i64);
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000781
Eric Biggers19b3b0d2024-01-31 22:46:47 +0000782impl BootTime {
783 /// Constructs a new BootTime
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000784 pub fn now() -> Self {
Hasini Gunasinghe66a24602021-05-12 19:03:12 +0000785 Self(get_current_time_in_milliseconds())
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000786 }
787
Eric Biggers19b3b0d2024-01-31 22:46:47 +0000788 /// Returns the value of BootTime in milliseconds as i64
Hasini Gunasinghe66a24602021-05-12 19:03:12 +0000789 pub fn milliseconds(&self) -> i64 {
790 self.0
David Drysdale0e45a612021-02-25 17:24:36 +0000791 }
792
Eric Biggers19b3b0d2024-01-31 22:46:47 +0000793 /// Returns the integer value of BootTime as i64
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000794 pub fn seconds(&self) -> i64 {
Hasini Gunasinghe66a24602021-05-12 19:03:12 +0000795 self.0 / 1000
Hasini Gunasingheb3715fb2021-02-26 20:34:45 +0000796 }
797
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800798 /// Like i64::checked_sub.
799 pub fn checked_sub(&self, other: &Self) -> Option<Self> {
800 self.0.checked_sub(other.0).map(Self)
801 }
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000802}
803
Eric Biggers19b3b0d2024-01-31 22:46:47 +0000804impl ToSql for BootTime {
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000805 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
806 Ok(ToSqlOutput::Owned(Value::Integer(self.0)))
807 }
808}
809
Eric Biggers19b3b0d2024-01-31 22:46:47 +0000810impl FromSql for BootTime {
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000811 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
812 Ok(Self(i64::column_result(value)?))
813 }
814}
815
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000816/// This struct encapsulates the information to be stored in the database about the auth tokens
817/// received by keystore.
Matthew Maurerd7815ca2021-05-06 21:58:45 -0700818#[derive(Clone)]
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000819pub struct AuthTokenEntry {
820 auth_token: HardwareAuthToken,
Hasini Gunasinghe66a24602021-05-12 19:03:12 +0000821 // Time received in milliseconds
Eric Biggers19b3b0d2024-01-31 22:46:47 +0000822 time_received: BootTime,
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000823}
824
825impl AuthTokenEntry {
Eric Biggers19b3b0d2024-01-31 22:46:47 +0000826 fn new(auth_token: HardwareAuthToken, time_received: BootTime) -> Self {
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000827 AuthTokenEntry { auth_token, time_received }
828 }
829
830 /// Checks if this auth token satisfies the given authentication information.
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800831 pub fn satisfies(&self, user_secure_ids: &[i64], auth_type: HardwareAuthenticatorType) -> bool {
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000832 user_secure_ids.iter().any(|&sid| {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800833 (sid == self.auth_token.userId || sid == self.auth_token.authenticatorId)
Charisee03e00842023-01-25 01:41:23 +0000834 && ((auth_type.0 & self.auth_token.authenticatorType.0) != 0)
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000835 })
836 }
837
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000838 /// Returns the auth token wrapped by the AuthTokenEntry
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800839 pub fn auth_token(&self) -> &HardwareAuthToken {
840 &self.auth_token
841 }
842
843 /// Returns the auth token wrapped by the AuthTokenEntry
844 pub fn take_auth_token(self) -> HardwareAuthToken {
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000845 self.auth_token
846 }
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800847
848 /// Returns the time that this auth token was received.
Eric Biggers19b3b0d2024-01-31 22:46:47 +0000849 pub fn time_received(&self) -> BootTime {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800850 self.time_received
851 }
Hasini Gunasingheb3715fb2021-02-26 20:34:45 +0000852
853 /// Returns the challenge value of the auth token.
854 pub fn challenge(&self) -> i64 {
855 self.auth_token.challenge
856 }
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000857}
858
David Drysdalef1ba3812024-05-08 17:50:13 +0100859/// Information about a superseded blob (a blob that is no longer the
860/// most recent blob of that type for a given key, due to upgrade or
861/// replacement).
862pub struct SupersededBlob {
863 /// ID
864 pub blob_id: i64,
865 /// Contents.
866 pub blob: Vec<u8>,
867 /// Metadata.
868 pub metadata: BlobMetaData,
869}
870
Joel Galenson26f4d012020-07-17 14:57:21 -0700871impl KeystoreDB {
Janis Danisevskiseed69842021-02-18 20:04:10 -0800872 const UNASSIGNED_KEY_ID: i64 = -1i64;
Janis Danisevskiscfaf9192021-05-26 16:31:02 -0700873 const CURRENT_DB_VERSION: u32 = 1;
874 const UPGRADERS: &'static [fn(&Transaction) -> Result<u32>] = &[Self::from_0_to_1];
Janis Danisevskisb00ebd02021-02-02 21:52:24 -0800875
Seth Moore78c091f2021-04-09 21:38:30 +0000876 /// Name of the file that holds the cross-boot persistent database.
Chris Wailesd5aaaef2021-07-27 16:04:33 -0700877 pub const PERSISTENT_DB_FILENAME: &'static str = "persistent.sqlite";
Seth Moore78c091f2021-04-09 21:38:30 +0000878
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700879 /// This will create a new database connection connecting the two
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800880 /// files persistent.sqlite and perboot.sqlite in the given directory.
881 /// It also attempts to initialize all of the tables.
882 /// KeystoreDB cannot be used by multiple threads.
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700883 /// Each thread should open their own connection using `thread_local!`.
Janis Danisevskis3395f862021-05-06 10:54:17 -0700884 pub fn new(db_root: &Path, gc: Option<Arc<Gc>>) -> Result<Self> {
David Drysdale541846b2024-05-23 13:16:07 +0100885 let _wp = wd::watch("KeystoreDB::new");
Janis Danisevskis850d4862021-05-05 08:41:14 -0700886
Chris Wailesd5aaaef2021-07-27 16:04:33 -0700887 let persistent_path = Self::make_persistent_path(db_root)?;
Seth Moore472fcbb2021-05-12 10:07:51 -0700888 let conn = Self::make_connection(&persistent_path)?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800889
Matthew Maurerd7815ca2021-05-06 21:58:45 -0700890 let mut db = Self { conn, gc, perboot: perboot::PERBOOT_DB.clone() };
David Drysdale7b9ca232024-05-23 18:19:46 +0100891 db.with_transaction(Immediate("TX_new"), |tx| {
Janis Danisevskiscfaf9192021-05-26 16:31:02 -0700892 versioning::upgrade_database(tx, Self::CURRENT_DB_VERSION, Self::UPGRADERS)
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000893 .context(ks_err!("KeystoreDB::new: trying to upgrade database."))?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800894 Self::init_tables(tx).context("Trying to initialize tables.").no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -0800895 })?;
896 Ok(db)
Joel Galenson2aab4432020-07-22 15:27:57 -0700897 }
898
Janis Danisevskiscfaf9192021-05-26 16:31:02 -0700899 // This upgrade function deletes all MAX_BOOT_LEVEL keys, that were generated before
900 // cryptographic binding to the boot level keys was implemented.
901 fn from_0_to_1(tx: &Transaction) -> Result<u32> {
902 tx.execute(
903 "UPDATE persistent.keyentry SET state = ?
904 WHERE
905 id IN (SELECT keyentryid FROM persistent.keyparameter WHERE tag = ?)
906 AND
907 id NOT IN (
908 SELECT keyentryid FROM persistent.blobentry
909 WHERE id IN (
910 SELECT blobentryid FROM persistent.blobmetadata WHERE tag = ?
911 )
912 );",
913 params![KeyLifeCycle::Unreferenced, Tag::MAX_BOOT_LEVEL.0, BlobMetaData::MaxBootLevel],
914 )
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000915 .context(ks_err!("Failed to delete logical boot level keys."))?;
Janis Danisevskiscfaf9192021-05-26 16:31:02 -0700916 Ok(1)
917 }
918
Janis Danisevskis66784c42021-01-27 08:40:25 -0800919 fn init_tables(tx: &Transaction) -> Result<()> {
920 tx.execute(
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700921 "CREATE TABLE IF NOT EXISTS persistent.keyentry (
Joel Galenson0891bc12020-07-20 10:37:03 -0700922 id INTEGER UNIQUE,
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800923 key_type INTEGER,
Joel Galenson0891bc12020-07-20 10:37:03 -0700924 domain INTEGER,
925 namespace INTEGER,
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800926 alias BLOB,
Max Bires8e93d2b2021-01-14 13:17:59 -0800927 state INTEGER,
928 km_uuid BLOB);",
Andrew Walbran78abb1e2023-05-30 16:20:56 +0000929 [],
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700930 )
931 .context("Failed to initialize \"keyentry\" table.")?;
932
Janis Danisevskis66784c42021-01-27 08:40:25 -0800933 tx.execute(
Janis Danisevskisa5438182021-02-02 14:22:59 -0800934 "CREATE INDEX IF NOT EXISTS persistent.keyentry_id_index
935 ON keyentry(id);",
Andrew Walbran78abb1e2023-05-30 16:20:56 +0000936 [],
Janis Danisevskisa5438182021-02-02 14:22:59 -0800937 )
938 .context("Failed to create index keyentry_id_index.")?;
939
940 tx.execute(
941 "CREATE INDEX IF NOT EXISTS persistent.keyentry_domain_namespace_index
942 ON keyentry(domain, namespace, alias);",
Andrew Walbran78abb1e2023-05-30 16:20:56 +0000943 [],
Janis Danisevskisa5438182021-02-02 14:22:59 -0800944 )
945 .context("Failed to create index keyentry_domain_namespace_index.")?;
946
947 tx.execute(
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700948 "CREATE TABLE IF NOT EXISTS persistent.blobentry (
949 id INTEGER PRIMARY KEY,
950 subcomponent_type INTEGER,
951 keyentryid INTEGER,
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800952 blob BLOB);",
Andrew Walbran78abb1e2023-05-30 16:20:56 +0000953 [],
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700954 )
955 .context("Failed to initialize \"blobentry\" table.")?;
956
Janis Danisevskis66784c42021-01-27 08:40:25 -0800957 tx.execute(
Janis Danisevskisa5438182021-02-02 14:22:59 -0800958 "CREATE INDEX IF NOT EXISTS persistent.blobentry_keyentryid_index
959 ON blobentry(keyentryid);",
Andrew Walbran78abb1e2023-05-30 16:20:56 +0000960 [],
Janis Danisevskisa5438182021-02-02 14:22:59 -0800961 )
962 .context("Failed to create index blobentry_keyentryid_index.")?;
963
964 tx.execute(
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800965 "CREATE TABLE IF NOT EXISTS persistent.blobmetadata (
966 id INTEGER PRIMARY KEY,
967 blobentryid INTEGER,
968 tag INTEGER,
969 data ANY,
970 UNIQUE (blobentryid, tag));",
Andrew Walbran78abb1e2023-05-30 16:20:56 +0000971 [],
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800972 )
973 .context("Failed to initialize \"blobmetadata\" table.")?;
974
975 tx.execute(
976 "CREATE INDEX IF NOT EXISTS persistent.blobmetadata_blobentryid_index
977 ON blobmetadata(blobentryid);",
Andrew Walbran78abb1e2023-05-30 16:20:56 +0000978 [],
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800979 )
980 .context("Failed to create index blobmetadata_blobentryid_index.")?;
981
982 tx.execute(
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700983 "CREATE TABLE IF NOT EXISTS persistent.keyparameter (
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000984 keyentryid INTEGER,
985 tag INTEGER,
986 data ANY,
987 security_level INTEGER);",
Andrew Walbran78abb1e2023-05-30 16:20:56 +0000988 [],
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700989 )
990 .context("Failed to initialize \"keyparameter\" table.")?;
991
Janis Danisevskis66784c42021-01-27 08:40:25 -0800992 tx.execute(
Janis Danisevskisa5438182021-02-02 14:22:59 -0800993 "CREATE INDEX IF NOT EXISTS persistent.keyparameter_keyentryid_index
994 ON keyparameter(keyentryid);",
Andrew Walbran78abb1e2023-05-30 16:20:56 +0000995 [],
Janis Danisevskisa5438182021-02-02 14:22:59 -0800996 )
997 .context("Failed to create index keyparameter_keyentryid_index.")?;
998
999 tx.execute(
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001000 "CREATE TABLE IF NOT EXISTS persistent.keymetadata (
1001 keyentryid INTEGER,
1002 tag INTEGER,
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00001003 data ANY,
1004 UNIQUE (keyentryid, tag));",
Andrew Walbran78abb1e2023-05-30 16:20:56 +00001005 [],
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001006 )
1007 .context("Failed to initialize \"keymetadata\" table.")?;
1008
Janis Danisevskis66784c42021-01-27 08:40:25 -08001009 tx.execute(
Janis Danisevskisa5438182021-02-02 14:22:59 -08001010 "CREATE INDEX IF NOT EXISTS persistent.keymetadata_keyentryid_index
1011 ON keymetadata(keyentryid);",
Andrew Walbran78abb1e2023-05-30 16:20:56 +00001012 [],
Janis Danisevskisa5438182021-02-02 14:22:59 -08001013 )
1014 .context("Failed to create index keymetadata_keyentryid_index.")?;
1015
1016 tx.execute(
Janis Danisevskisbf15d732020-12-08 10:35:26 -08001017 "CREATE TABLE IF NOT EXISTS persistent.grant (
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001018 id INTEGER UNIQUE,
1019 grantee INTEGER,
1020 keyentryid INTEGER,
1021 access_vector INTEGER);",
Andrew Walbran78abb1e2023-05-30 16:20:56 +00001022 [],
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001023 )
1024 .context("Failed to initialize \"grant\" table.")?;
1025
Joel Galenson0891bc12020-07-20 10:37:03 -07001026 Ok(())
1027 }
1028
Seth Moore472fcbb2021-05-12 10:07:51 -07001029 fn make_persistent_path(db_root: &Path) -> Result<String> {
1030 // Build the path to the sqlite file.
1031 let mut persistent_path = db_root.to_path_buf();
1032 persistent_path.push(Self::PERSISTENT_DB_FILENAME);
1033
1034 // Now convert them to strings prefixed with "file:"
1035 let mut persistent_path_str = "file:".to_owned();
1036 persistent_path_str.push_str(&persistent_path.to_string_lossy());
1037
Shaquille Johnson52b8c932023-12-19 19:45:32 +00001038 // Connect to database in specific mode
1039 let persistent_path_mode = if keystore2_flags::wal_db_journalmode_v3() {
1040 "?journal_mode=WAL".to_owned()
1041 } else {
1042 "?journal_mode=DELETE".to_owned()
1043 };
1044 persistent_path_str.push_str(&persistent_path_mode);
1045
Seth Moore472fcbb2021-05-12 10:07:51 -07001046 Ok(persistent_path_str)
1047 }
1048
Matthew Maurerd7815ca2021-05-06 21:58:45 -07001049 fn make_connection(persistent_file: &str) -> Result<Connection> {
Janis Danisevskis4df44f42020-08-26 14:40:03 -07001050 let conn =
1051 Connection::open_in_memory().context("Failed to initialize SQLite connection.")?;
1052
Janis Danisevskis66784c42021-01-27 08:40:25 -08001053 loop {
1054 if let Err(e) = conn
1055 .execute("ATTACH DATABASE ? as persistent;", params![persistent_file])
1056 .context("Failed to attach database persistent.")
1057 {
1058 if Self::is_locked_error(&e) {
David Drysdale115c4722024-04-15 14:11:52 +01001059 std::thread::sleep(DB_BUSY_RETRY_INTERVAL);
Janis Danisevskis66784c42021-01-27 08:40:25 -08001060 continue;
1061 } else {
1062 return Err(e);
1063 }
1064 }
1065 break;
1066 }
Janis Danisevskis4df44f42020-08-26 14:40:03 -07001067
Matthew Maurer4fb19112021-05-06 15:40:44 -07001068 // Drop the cache size from default (2M) to 0.5M
1069 conn.execute("PRAGMA persistent.cache_size = -500;", params![])
1070 .context("Failed to decrease cache size for persistent db")?;
Matthew Maurer4fb19112021-05-06 15:40:44 -07001071
Janis Danisevskis4df44f42020-08-26 14:40:03 -07001072 Ok(conn)
1073 }
1074
Seth Moore78c091f2021-04-09 21:38:30 +00001075 fn do_table_size_query(
1076 &mut self,
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001077 storage_type: MetricsStorage,
Seth Moore78c091f2021-04-09 21:38:30 +00001078 query: &str,
1079 params: &[&str],
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001080 ) -> Result<StorageStats> {
Seth Moore78c091f2021-04-09 21:38:30 +00001081 let (total, unused) = self.with_transaction(TransactionBehavior::Deferred, |tx| {
Joel Galensonff79e362021-05-25 16:30:17 -07001082 tx.query_row(query, params_from_iter(params), |row| Ok((row.get(0)?, row.get(1)?)))
Seth Moore78c091f2021-04-09 21:38:30 +00001083 .with_context(|| {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001084 ks_err!("get_storage_stat: Error size of storage type {}", storage_type.0)
Seth Moore78c091f2021-04-09 21:38:30 +00001085 })
1086 .no_gc()
1087 })?;
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001088 Ok(StorageStats { storage_type, size: total, unused_size: unused })
Seth Moore78c091f2021-04-09 21:38:30 +00001089 }
1090
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001091 fn get_total_size(&mut self) -> Result<StorageStats> {
Seth Moore78c091f2021-04-09 21:38:30 +00001092 self.do_table_size_query(
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001093 MetricsStorage::DATABASE,
Seth Moore78c091f2021-04-09 21:38:30 +00001094 "SELECT page_count * page_size, freelist_count * page_size
1095 FROM pragma_page_count('persistent'),
1096 pragma_page_size('persistent'),
1097 persistent.pragma_freelist_count();",
1098 &[],
1099 )
1100 }
1101
1102 fn get_table_size(
1103 &mut self,
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001104 storage_type: MetricsStorage,
Seth Moore78c091f2021-04-09 21:38:30 +00001105 schema: &str,
1106 table: &str,
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001107 ) -> Result<StorageStats> {
Seth Moore78c091f2021-04-09 21:38:30 +00001108 self.do_table_size_query(
1109 storage_type,
1110 "SELECT pgsize,unused FROM dbstat(?1)
1111 WHERE name=?2 AND aggregate=TRUE;",
1112 &[schema, table],
1113 )
1114 }
1115
David Drysdale0fefae32024-09-16 13:32:27 +01001116 /// Fetches a storage statistics atom for a given storage type. For storage
Seth Moore78c091f2021-04-09 21:38:30 +00001117 /// types that map to a table, information about the table's storage is
1118 /// returned. Requests for storage types that are not DB tables return None.
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001119 pub fn get_storage_stat(&mut self, storage_type: MetricsStorage) -> Result<StorageStats> {
David Drysdale541846b2024-05-23 13:16:07 +01001120 let _wp = wd::watch("KeystoreDB::get_storage_stat");
Janis Danisevskis850d4862021-05-05 08:41:14 -07001121
Seth Moore78c091f2021-04-09 21:38:30 +00001122 match storage_type {
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001123 MetricsStorage::DATABASE => self.get_total_size(),
1124 MetricsStorage::KEY_ENTRY => {
Seth Moore78c091f2021-04-09 21:38:30 +00001125 self.get_table_size(storage_type, "persistent", "keyentry")
1126 }
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001127 MetricsStorage::KEY_ENTRY_ID_INDEX => {
Seth Moore78c091f2021-04-09 21:38:30 +00001128 self.get_table_size(storage_type, "persistent", "keyentry_id_index")
1129 }
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001130 MetricsStorage::KEY_ENTRY_DOMAIN_NAMESPACE_INDEX => {
Seth Moore78c091f2021-04-09 21:38:30 +00001131 self.get_table_size(storage_type, "persistent", "keyentry_domain_namespace_index")
1132 }
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001133 MetricsStorage::BLOB_ENTRY => {
Seth Moore78c091f2021-04-09 21:38:30 +00001134 self.get_table_size(storage_type, "persistent", "blobentry")
1135 }
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001136 MetricsStorage::BLOB_ENTRY_KEY_ENTRY_ID_INDEX => {
Seth Moore78c091f2021-04-09 21:38:30 +00001137 self.get_table_size(storage_type, "persistent", "blobentry_keyentryid_index")
1138 }
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001139 MetricsStorage::KEY_PARAMETER => {
Seth Moore78c091f2021-04-09 21:38:30 +00001140 self.get_table_size(storage_type, "persistent", "keyparameter")
1141 }
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001142 MetricsStorage::KEY_PARAMETER_KEY_ENTRY_ID_INDEX => {
Seth Moore78c091f2021-04-09 21:38:30 +00001143 self.get_table_size(storage_type, "persistent", "keyparameter_keyentryid_index")
1144 }
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001145 MetricsStorage::KEY_METADATA => {
Seth Moore78c091f2021-04-09 21:38:30 +00001146 self.get_table_size(storage_type, "persistent", "keymetadata")
1147 }
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001148 MetricsStorage::KEY_METADATA_KEY_ENTRY_ID_INDEX => {
Seth Moore78c091f2021-04-09 21:38:30 +00001149 self.get_table_size(storage_type, "persistent", "keymetadata_keyentryid_index")
1150 }
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001151 MetricsStorage::GRANT => self.get_table_size(storage_type, "persistent", "grant"),
1152 MetricsStorage::AUTH_TOKEN => {
Matthew Maurerd7815ca2021-05-06 21:58:45 -07001153 // Since the table is actually a BTreeMap now, unused_size is not meaningfully
1154 // reportable
1155 // Size provided is only an approximation
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001156 Ok(StorageStats {
Matthew Maurerd7815ca2021-05-06 21:58:45 -07001157 storage_type,
1158 size: (self.perboot.auth_tokens_len() * std::mem::size_of::<AuthTokenEntry>())
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001159 as i32,
Matthew Maurerd7815ca2021-05-06 21:58:45 -07001160 unused_size: 0,
1161 })
Seth Moore78c091f2021-04-09 21:38:30 +00001162 }
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001163 MetricsStorage::BLOB_METADATA => {
Seth Moore78c091f2021-04-09 21:38:30 +00001164 self.get_table_size(storage_type, "persistent", "blobmetadata")
1165 }
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001166 MetricsStorage::BLOB_METADATA_BLOB_ENTRY_ID_INDEX => {
Seth Moore78c091f2021-04-09 21:38:30 +00001167 self.get_table_size(storage_type, "persistent", "blobmetadata_blobentryid_index")
1168 }
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001169 _ => Err(anyhow::Error::msg(format!("Unsupported storage type: {}", storage_type.0))),
Seth Moore78c091f2021-04-09 21:38:30 +00001170 }
1171 }
1172
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001173 /// This function is intended to be used by the garbage collector.
Janis Danisevskis3395f862021-05-06 10:54:17 -07001174 /// It deletes the blobs given by `blob_ids_to_delete`. It then tries to find up to `max_blobs`
1175 /// superseded key blobs that might need special handling by the garbage collector.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001176 /// If no further superseded blobs can be found it deletes all other superseded blobs that don't
1177 /// need special handling and returns None.
Janis Danisevskis3395f862021-05-06 10:54:17 -07001178 pub fn handle_next_superseded_blobs(
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001179 &mut self,
Janis Danisevskis3395f862021-05-06 10:54:17 -07001180 blob_ids_to_delete: &[i64],
1181 max_blobs: usize,
David Drysdalef1ba3812024-05-08 17:50:13 +01001182 ) -> Result<Vec<SupersededBlob>> {
David Drysdale541846b2024-05-23 13:16:07 +01001183 let _wp = wd::watch("KeystoreDB::handle_next_superseded_blob");
David Drysdale7b9ca232024-05-23 18:19:46 +01001184 self.with_transaction(Immediate("TX_handle_next_superseded_blob"), |tx| {
Janis Danisevskis3395f862021-05-06 10:54:17 -07001185 // Delete the given blobs.
1186 for blob_id in blob_ids_to_delete {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001187 tx.execute(
1188 "DELETE FROM persistent.blobmetadata WHERE blobentryid = ?;",
Janis Danisevskis3395f862021-05-06 10:54:17 -07001189 params![blob_id],
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001190 )
Shaquille Johnsonf23fc942024-02-13 17:01:29 +00001191 .context(ks_err!("Trying to delete blob metadata: {:?}", blob_id))?;
Janis Danisevskis3395f862021-05-06 10:54:17 -07001192 tx.execute("DELETE FROM persistent.blobentry WHERE id = ?;", params![blob_id])
Shaquille Johnsonf23fc942024-02-13 17:01:29 +00001193 .context(ks_err!("Trying to delete blob: {:?}", blob_id))?;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001194 }
Janis Danisevskis3cba10d2021-05-06 17:02:19 -07001195
1196 Self::cleanup_unreferenced(tx).context("Trying to cleanup unreferenced.")?;
1197
David Drysdalef1ba3812024-05-08 17:50:13 +01001198 // Find up to `max_blobs` more superseded key blobs, load their metadata and return it.
Janis Danisevskis3395f862021-05-06 10:54:17 -07001199 let result: Vec<(i64, Vec<u8>)> = {
David Drysdalec652f6c2024-07-18 13:01:23 +01001200 let _wp = wd::watch("KeystoreDB::handle_next_superseded_blob find_next");
Janis Danisevskis3395f862021-05-06 10:54:17 -07001201 let mut stmt = tx
1202 .prepare(
1203 "SELECT id, blob FROM persistent.blobentry
1204 WHERE subcomponent_type = ?
1205 AND (
1206 id NOT IN (
1207 SELECT MAX(id) FROM persistent.blobentry
1208 WHERE subcomponent_type = ?
1209 GROUP BY keyentryid, subcomponent_type
1210 )
1211 OR keyentryid NOT IN (SELECT id FROM persistent.keyentry)
1212 ) LIMIT ?;",
1213 )
1214 .context("Trying to prepare query for superseded blobs.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001215
Janis Danisevskis3395f862021-05-06 10:54:17 -07001216 let rows = stmt
1217 .query_map(
1218 params![
1219 SubComponentType::KEY_BLOB,
1220 SubComponentType::KEY_BLOB,
1221 max_blobs as i64,
1222 ],
1223 |row| Ok((row.get(0)?, row.get(1)?)),
1224 )
1225 .context("Trying to query superseded blob.")?;
1226
1227 rows.collect::<Result<Vec<(i64, Vec<u8>)>, rusqlite::Error>>()
1228 .context("Trying to extract superseded blobs.")?
1229 };
1230
David Drysdalec652f6c2024-07-18 13:01:23 +01001231 let _wp = wd::watch("KeystoreDB::handle_next_superseded_blob load_metadata");
Janis Danisevskis3395f862021-05-06 10:54:17 -07001232 let result = result
1233 .into_iter()
1234 .map(|(blob_id, blob)| {
David Drysdalef1ba3812024-05-08 17:50:13 +01001235 Ok(SupersededBlob {
1236 blob_id,
1237 blob,
1238 metadata: BlobMetaData::load_from_db(blob_id, tx)?,
1239 })
Janis Danisevskis3395f862021-05-06 10:54:17 -07001240 })
David Drysdalef1ba3812024-05-08 17:50:13 +01001241 .collect::<Result<Vec<_>>>()
Janis Danisevskis3395f862021-05-06 10:54:17 -07001242 .context("Trying to load blob metadata.")?;
1243 if !result.is_empty() {
1244 return Ok(result).no_gc();
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001245 }
1246
1247 // We did not find any superseded key blob, so let's remove other superseded blob in
1248 // one transaction.
David Drysdalec652f6c2024-07-18 13:01:23 +01001249 let _wp = wd::watch("KeystoreDB::handle_next_superseded_blob delete");
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001250 tx.execute(
1251 "DELETE FROM persistent.blobentry
1252 WHERE NOT subcomponent_type = ?
1253 AND (
1254 id NOT IN (
1255 SELECT MAX(id) FROM persistent.blobentry
1256 WHERE NOT subcomponent_type = ?
1257 GROUP BY keyentryid, subcomponent_type
1258 ) OR keyentryid NOT IN (SELECT id FROM persistent.keyentry)
1259 );",
1260 params![SubComponentType::KEY_BLOB, SubComponentType::KEY_BLOB],
1261 )
1262 .context("Trying to purge superseded blobs.")?;
1263
Janis Danisevskis3395f862021-05-06 10:54:17 -07001264 Ok(vec![]).no_gc()
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001265 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001266 .context(ks_err!())
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001267 }
1268
1269 /// This maintenance function should be called only once before the database is used for the
1270 /// first time. It restores the invariant that `KeyLifeCycle::Existing` is a transient state.
1271 /// The function transitions all key entries from Existing to Unreferenced unconditionally and
1272 /// returns the number of rows affected. If this returns a value greater than 0, it means that
1273 /// Keystore crashed at some point during key generation. Callers may want to log such
1274 /// occurrences.
1275 /// Unlike with `mark_unreferenced`, we don't need to purge grants, because only keys that made
1276 /// it to `KeyLifeCycle::Live` may have grants.
1277 pub fn cleanup_leftovers(&mut self) -> Result<usize> {
David Drysdale541846b2024-05-23 13:16:07 +01001278 let _wp = wd::watch("KeystoreDB::cleanup_leftovers");
Janis Danisevskis850d4862021-05-05 08:41:14 -07001279
David Drysdale7b9ca232024-05-23 18:19:46 +01001280 self.with_transaction(Immediate("TX_cleanup_leftovers"), |tx| {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001281 tx.execute(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001282 "UPDATE persistent.keyentry SET state = ? WHERE state = ?;",
1283 params![KeyLifeCycle::Unreferenced, KeyLifeCycle::Existing],
1284 )
Janis Danisevskis66784c42021-01-27 08:40:25 -08001285 .context("Failed to execute query.")
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001286 .need_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08001287 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001288 .context(ks_err!())
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001289 }
1290
Hasini Gunasinghe0e161452021-01-27 19:34:37 +00001291 /// Checks if a key exists with given key type and key descriptor properties.
1292 pub fn key_exists(
1293 &mut self,
1294 domain: Domain,
1295 nspace: i64,
1296 alias: &str,
1297 key_type: KeyType,
1298 ) -> Result<bool> {
David Drysdale541846b2024-05-23 13:16:07 +01001299 let _wp = wd::watch("KeystoreDB::key_exists");
Janis Danisevskis850d4862021-05-05 08:41:14 -07001300
David Drysdale7b9ca232024-05-23 18:19:46 +01001301 self.with_transaction(Immediate("TX_key_exists"), |tx| {
Hasini Gunasinghe0e161452021-01-27 19:34:37 +00001302 let key_descriptor =
1303 KeyDescriptor { domain, nspace, alias: Some(alias.to_string()), blob: None };
Chris Wailesd5aaaef2021-07-27 16:04:33 -07001304 let result = Self::load_key_entry_id(tx, &key_descriptor, key_type);
Hasini Gunasinghe0e161452021-01-27 19:34:37 +00001305 match result {
1306 Ok(_) => Ok(true),
1307 Err(error) => match error.root_cause().downcast_ref::<KsError>() {
1308 Some(KsError::Rc(ResponseCode::KEY_NOT_FOUND)) => Ok(false),
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001309 _ => Err(error).context(ks_err!("Failed to find if the key exists.")),
Hasini Gunasinghe0e161452021-01-27 19:34:37 +00001310 },
1311 }
1312 .no_gc()
1313 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001314 .context(ks_err!())
Hasini Gunasinghe0e161452021-01-27 19:34:37 +00001315 }
1316
Hasini Gunasingheda895552021-01-27 19:34:37 +00001317 /// Stores a super key in the database.
1318 pub fn store_super_key(
1319 &mut self,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +00001320 user_id: u32,
Paul Crowley7a658392021-03-18 17:08:20 -07001321 key_type: &SuperKeyType,
1322 blob: &[u8],
1323 blob_metadata: &BlobMetaData,
Paul Crowley8d5b2532021-03-19 10:53:07 -07001324 key_metadata: &KeyMetaData,
Hasini Gunasingheda895552021-01-27 19:34:37 +00001325 ) -> Result<KeyEntry> {
David Drysdale541846b2024-05-23 13:16:07 +01001326 let _wp = wd::watch("KeystoreDB::store_super_key");
Janis Danisevskis850d4862021-05-05 08:41:14 -07001327
David Drysdale7b9ca232024-05-23 18:19:46 +01001328 self.with_transaction(Immediate("TX_store_super_key"), |tx| {
Hasini Gunasingheda895552021-01-27 19:34:37 +00001329 let key_id = Self::insert_with_retry(|id| {
1330 tx.execute(
1331 "INSERT into persistent.keyentry
1332 (id, key_type, domain, namespace, alias, state, km_uuid)
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00001333 VALUES(?, ?, ?, ?, ?, ?, ?);",
Hasini Gunasingheda895552021-01-27 19:34:37 +00001334 params![
1335 id,
1336 KeyType::Super,
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00001337 Domain::APP.0,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +00001338 user_id as i64,
Paul Crowley7a658392021-03-18 17:08:20 -07001339 key_type.alias,
Hasini Gunasingheda895552021-01-27 19:34:37 +00001340 KeyLifeCycle::Live,
1341 &KEYSTORE_UUID,
1342 ],
1343 )
1344 })
1345 .context("Failed to insert into keyentry table.")?;
1346
Paul Crowley8d5b2532021-03-19 10:53:07 -07001347 key_metadata.store_in_db(key_id, tx).context("KeyMetaData::store_in_db failed")?;
1348
Hasini Gunasingheda895552021-01-27 19:34:37 +00001349 Self::set_blob_internal(
Chris Wailesd5aaaef2021-07-27 16:04:33 -07001350 tx,
Hasini Gunasingheda895552021-01-27 19:34:37 +00001351 key_id,
1352 SubComponentType::KEY_BLOB,
1353 Some(blob),
1354 Some(blob_metadata),
1355 )
1356 .context("Failed to store key blob.")?;
1357
1358 Self::load_key_components(tx, KeyEntryLoadBits::KM, key_id)
1359 .context("Trying to load key components.")
1360 .no_gc()
1361 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001362 .context(ks_err!())
Hasini Gunasingheda895552021-01-27 19:34:37 +00001363 }
1364
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +00001365 /// Loads super key of a given user, if exists
Paul Crowley7a658392021-03-18 17:08:20 -07001366 pub fn load_super_key(
1367 &mut self,
1368 key_type: &SuperKeyType,
1369 user_id: u32,
1370 ) -> Result<Option<(KeyIdGuard, KeyEntry)>> {
David Drysdale541846b2024-05-23 13:16:07 +01001371 let _wp = wd::watch("KeystoreDB::load_super_key");
Janis Danisevskis850d4862021-05-05 08:41:14 -07001372
David Drysdale7b9ca232024-05-23 18:19:46 +01001373 self.with_transaction(Immediate("TX_load_super_key"), |tx| {
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +00001374 let key_descriptor = KeyDescriptor {
1375 domain: Domain::APP,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +00001376 nspace: user_id as i64,
Paul Crowley7a658392021-03-18 17:08:20 -07001377 alias: Some(key_type.alias.into()),
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +00001378 blob: None,
1379 };
Chris Wailesd5aaaef2021-07-27 16:04:33 -07001380 let id = Self::load_key_entry_id(tx, &key_descriptor, KeyType::Super);
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +00001381 match id {
1382 Ok(id) => {
Chris Wailesd5aaaef2021-07-27 16:04:33 -07001383 let key_entry = Self::load_key_components(tx, KeyEntryLoadBits::KM, id)
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001384 .context(ks_err!("Failed to load key entry."))?;
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +00001385 Ok(Some((KEY_ID_LOCK.get(id), key_entry)))
1386 }
1387 Err(error) => match error.root_cause().downcast_ref::<KsError>() {
1388 Some(KsError::Rc(ResponseCode::KEY_NOT_FOUND)) => Ok(None),
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001389 _ => Err(error).context(ks_err!()),
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +00001390 },
1391 }
1392 .no_gc()
1393 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001394 .context(ks_err!())
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +00001395 }
1396
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001397 /// Creates a transaction with the given behavior and executes f with the new transaction.
Janis Danisevskis66784c42021-01-27 08:40:25 -08001398 /// The transaction is committed only if f returns Ok and retried if DatabaseBusy
1399 /// or DatabaseLocked is encountered.
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001400 fn with_transaction<T, F>(&mut self, behavior: TransactionBehavior, f: F) -> Result<T>
1401 where
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001402 F: Fn(&Transaction) -> Result<(bool, T)>,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001403 {
David Drysdale7b9ca232024-05-23 18:19:46 +01001404 let name = behavior.name();
Janis Danisevskis66784c42021-01-27 08:40:25 -08001405 loop {
James Farrellefe1a2f2024-02-28 21:36:47 +00001406 let result = self
Janis Danisevskis66784c42021-01-27 08:40:25 -08001407 .conn
David Drysdale7b9ca232024-05-23 18:19:46 +01001408 .transaction_with_behavior(behavior.into())
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001409 .context(ks_err!())
David Drysdale7b9ca232024-05-23 18:19:46 +01001410 .and_then(|tx| {
1411 let _wp = name.map(wd::watch);
1412 f(&tx).map(|result| (result, tx))
1413 })
Janis Danisevskis66784c42021-01-27 08:40:25 -08001414 .and_then(|(result, tx)| {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001415 tx.commit().context(ks_err!("Failed to commit transaction."))?;
Janis Danisevskis66784c42021-01-27 08:40:25 -08001416 Ok(result)
James Farrellefe1a2f2024-02-28 21:36:47 +00001417 });
1418 match result {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001419 Ok(result) => break Ok(result),
1420 Err(e) => {
1421 if Self::is_locked_error(&e) {
David Drysdale115c4722024-04-15 14:11:52 +01001422 std::thread::sleep(DB_BUSY_RETRY_INTERVAL);
Janis Danisevskis66784c42021-01-27 08:40:25 -08001423 continue;
1424 } else {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001425 return Err(e).context(ks_err!());
Janis Danisevskis66784c42021-01-27 08:40:25 -08001426 }
1427 }
1428 }
1429 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001430 .map(|(need_gc, result)| {
1431 if need_gc {
1432 if let Some(ref gc) = self.gc {
1433 gc.notify_gc();
1434 }
1435 }
1436 result
1437 })
Janis Danisevskis66784c42021-01-27 08:40:25 -08001438 }
1439
1440 fn is_locked_error(e: &anyhow::Error) -> bool {
Paul Crowleyf61fee72021-03-17 14:38:44 -07001441 matches!(
1442 e.root_cause().downcast_ref::<rusqlite::ffi::Error>(),
1443 Some(rusqlite::ffi::Error { code: rusqlite::ErrorCode::DatabaseBusy, .. })
1444 | Some(rusqlite::ffi::Error { code: rusqlite::ErrorCode::DatabaseLocked, .. })
1445 )
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001446 }
1447
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001448 fn create_key_entry_internal(
1449 tx: &Transaction,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001450 domain: &Domain,
1451 namespace: &i64,
Janis Danisevskis0cabd712021-05-25 11:07:10 -07001452 key_type: KeyType,
Max Bires8e93d2b2021-01-14 13:17:59 -08001453 km_uuid: &Uuid,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001454 ) -> Result<KeyIdGuard> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001455 match *domain {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001456 Domain::APP | Domain::SELINUX => {}
Joel Galenson0891bc12020-07-20 10:37:03 -07001457 _ => {
1458 return Err(KsError::sys())
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001459 .context(ks_err!("Domain {:?} must be either App or SELinux.", domain));
Joel Galenson0891bc12020-07-20 10:37:03 -07001460 }
1461 }
Janis Danisevskisaec14592020-11-12 09:41:49 -08001462 Ok(KEY_ID_LOCK.get(
1463 Self::insert_with_retry(|id| {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001464 tx.execute(
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001465 "INSERT into persistent.keyentry
Max Bires8e93d2b2021-01-14 13:17:59 -08001466 (id, key_type, domain, namespace, alias, state, km_uuid)
1467 VALUES(?, ?, ?, ?, NULL, ?, ?);",
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001468 params![
1469 id,
Janis Danisevskis0cabd712021-05-25 11:07:10 -07001470 key_type,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001471 domain.0 as u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001472 *namespace,
Max Bires8e93d2b2021-01-14 13:17:59 -08001473 KeyLifeCycle::Existing,
1474 km_uuid,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001475 ],
Janis Danisevskisaec14592020-11-12 09:41:49 -08001476 )
1477 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001478 .context(ks_err!())?,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001479 ))
Joel Galenson26f4d012020-07-17 14:57:21 -07001480 }
Joel Galenson33c04ad2020-08-03 11:04:38 -07001481
Janis Danisevskis377d1002021-01-27 19:07:48 -08001482 /// Set a new blob and associates it with the given key id. Each blob
1483 /// has a sub component type.
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001484 /// Each key can have one of each sub component type associated. If more
1485 /// are added only the most recent can be retrieved, and superseded blobs
Janis Danisevskis377d1002021-01-27 19:07:48 -08001486 /// will get garbage collected.
1487 /// Components SubComponentType::CERT and SubComponentType::CERT_CHAIN can be
1488 /// removed by setting blob to None.
1489 pub fn set_blob(
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001490 &mut self,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001491 key_id: &KeyIdGuard,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001492 sc_type: SubComponentType,
Janis Danisevskis377d1002021-01-27 19:07:48 -08001493 blob: Option<&[u8]>,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001494 blob_metadata: Option<&BlobMetaData>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001495 ) -> Result<()> {
David Drysdale541846b2024-05-23 13:16:07 +01001496 let _wp = wd::watch("KeystoreDB::set_blob");
Janis Danisevskis850d4862021-05-05 08:41:14 -07001497
David Drysdale7b9ca232024-05-23 18:19:46 +01001498 self.with_transaction(Immediate("TX_set_blob"), |tx| {
Chris Wailesd5aaaef2021-07-27 16:04:33 -07001499 Self::set_blob_internal(tx, key_id.0, sc_type, blob, blob_metadata).need_gc()
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001500 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001501 .context(ks_err!())
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001502 }
1503
Janis Danisevskiseed69842021-02-18 20:04:10 -08001504 /// Why would we insert a deleted blob? This weird function is for the purpose of legacy
1505 /// key migration in the case where we bulk delete all the keys of an app or even a user.
1506 /// We use this to insert key blobs into the database which can then be garbage collected
1507 /// lazily by the key garbage collector.
1508 pub fn set_deleted_blob(&mut self, blob: &[u8], blob_metadata: &BlobMetaData) -> Result<()> {
David Drysdale541846b2024-05-23 13:16:07 +01001509 let _wp = wd::watch("KeystoreDB::set_deleted_blob");
Janis Danisevskis850d4862021-05-05 08:41:14 -07001510
David Drysdale7b9ca232024-05-23 18:19:46 +01001511 self.with_transaction(Immediate("TX_set_deleted_blob"), |tx| {
Janis Danisevskiseed69842021-02-18 20:04:10 -08001512 Self::set_blob_internal(
Chris Wailesd5aaaef2021-07-27 16:04:33 -07001513 tx,
Janis Danisevskiseed69842021-02-18 20:04:10 -08001514 Self::UNASSIGNED_KEY_ID,
1515 SubComponentType::KEY_BLOB,
1516 Some(blob),
1517 Some(blob_metadata),
1518 )
1519 .need_gc()
1520 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001521 .context(ks_err!())
Janis Danisevskiseed69842021-02-18 20:04:10 -08001522 }
1523
Janis Danisevskis377d1002021-01-27 19:07:48 -08001524 fn set_blob_internal(
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001525 tx: &Transaction,
1526 key_id: i64,
1527 sc_type: SubComponentType,
Janis Danisevskis377d1002021-01-27 19:07:48 -08001528 blob: Option<&[u8]>,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001529 blob_metadata: Option<&BlobMetaData>,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001530 ) -> Result<()> {
Janis Danisevskis377d1002021-01-27 19:07:48 -08001531 match (blob, sc_type) {
1532 (Some(blob), _) => {
1533 tx.execute(
1534 "INSERT INTO persistent.blobentry
1535 (subcomponent_type, keyentryid, blob) VALUES (?, ?, ?);",
1536 params![sc_type, key_id, blob],
1537 )
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001538 .context(ks_err!("Failed to insert blob."))?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001539 if let Some(blob_metadata) = blob_metadata {
1540 let blob_id = tx
Andrew Walbran78abb1e2023-05-30 16:20:56 +00001541 .query_row("SELECT MAX(id) FROM persistent.blobentry;", [], |row| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001542 row.get(0)
1543 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001544 .context(ks_err!("Failed to get new blob id."))?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001545 blob_metadata
1546 .store_in_db(blob_id, tx)
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001547 .context(ks_err!("Trying to store blob metadata."))?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001548 }
Janis Danisevskis377d1002021-01-27 19:07:48 -08001549 }
1550 (None, SubComponentType::CERT) | (None, SubComponentType::CERT_CHAIN) => {
1551 tx.execute(
1552 "DELETE FROM persistent.blobentry
1553 WHERE subcomponent_type = ? AND keyentryid = ?;",
1554 params![sc_type, key_id],
1555 )
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001556 .context(ks_err!("Failed to delete blob."))?;
Janis Danisevskis377d1002021-01-27 19:07:48 -08001557 }
1558 (None, _) => {
1559 return Err(KsError::sys())
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001560 .context(ks_err!("Other blobs cannot be deleted in this way."));
Janis Danisevskis377d1002021-01-27 19:07:48 -08001561 }
1562 }
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001563 Ok(())
1564 }
1565
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001566 /// Inserts a collection of key parameters into the `persistent.keyparameter` table
1567 /// and associates them with the given `key_id`.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001568 #[cfg(test)]
1569 fn insert_keyparameter(&mut self, key_id: &KeyIdGuard, params: &[KeyParameter]) -> Result<()> {
David Drysdale7b9ca232024-05-23 18:19:46 +01001570 self.with_transaction(Immediate("TX_insert_keyparameter"), |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001571 Self::insert_keyparameter_internal(tx, key_id, params).no_gc()
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001572 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001573 .context(ks_err!())
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001574 }
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001575
Janis Danisevskis66784c42021-01-27 08:40:25 -08001576 fn insert_keyparameter_internal(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001577 tx: &Transaction,
1578 key_id: &KeyIdGuard,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001579 params: &[KeyParameter],
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001580 ) -> Result<()> {
1581 let mut stmt = tx
1582 .prepare(
1583 "INSERT into persistent.keyparameter (keyentryid, tag, data, security_level)
1584 VALUES (?, ?, ?, ?);",
1585 )
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001586 .context(ks_err!("Failed to prepare statement."))?;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001587
Janis Danisevskis66784c42021-01-27 08:40:25 -08001588 for p in params.iter() {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001589 stmt.insert(params![
1590 key_id.0,
1591 p.get_tag().0,
1592 p.key_parameter_value(),
1593 p.security_level().0
1594 ])
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001595 .with_context(|| ks_err!("Failed to insert {:?}", p))?;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001596 }
1597 Ok(())
1598 }
1599
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001600 /// Insert a set of key entry specific metadata into the database.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001601 #[cfg(test)]
1602 fn insert_key_metadata(&mut self, key_id: &KeyIdGuard, metadata: &KeyMetaData) -> Result<()> {
David Drysdale7b9ca232024-05-23 18:19:46 +01001603 self.with_transaction(Immediate("TX_insert_key_metadata"), |tx| {
Chris Wailesd5aaaef2021-07-27 16:04:33 -07001604 metadata.store_in_db(key_id.0, tx).no_gc()
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001605 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001606 .context(ks_err!())
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001607 }
1608
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001609 /// Updates the alias column of the given key id `newid` with the given alias,
1610 /// and atomically, removes the alias, domain, and namespace from another row
1611 /// with the same alias-domain-namespace tuple if such row exits.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001612 /// Returns Ok(true) if an old key was marked unreferenced as a hint to the garbage
1613 /// collector.
1614 fn rebind_alias(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001615 tx: &Transaction,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001616 newid: &KeyIdGuard,
Joel Galenson33c04ad2020-08-03 11:04:38 -07001617 alias: &str,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001618 domain: &Domain,
1619 namespace: &i64,
Janis Danisevskis0cabd712021-05-25 11:07:10 -07001620 key_type: KeyType,
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001621 ) -> Result<bool> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001622 match *domain {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001623 Domain::APP | Domain::SELINUX => {}
Joel Galenson33c04ad2020-08-03 11:04:38 -07001624 _ => {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001625 return Err(KsError::sys())
1626 .context(ks_err!("Domain {:?} must be either App or SELinux.", domain));
Joel Galenson33c04ad2020-08-03 11:04:38 -07001627 }
1628 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001629 let updated = tx
1630 .execute(
1631 "UPDATE persistent.keyentry
1632 SET alias = NULL, domain = NULL, namespace = NULL, state = ?
Janis Danisevskis0cabd712021-05-25 11:07:10 -07001633 WHERE alias = ? AND domain = ? AND namespace = ? AND key_type = ?;",
1634 params![KeyLifeCycle::Unreferenced, alias, domain.0 as u32, namespace, key_type],
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001635 )
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001636 .context(ks_err!("Failed to rebind existing entry."))?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07001637 let result = tx
1638 .execute(
1639 "UPDATE persistent.keyentry
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001640 SET alias = ?, state = ?
Janis Danisevskis0cabd712021-05-25 11:07:10 -07001641 WHERE id = ? AND domain = ? AND namespace = ? AND state = ? AND key_type = ?;",
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001642 params![
1643 alias,
1644 KeyLifeCycle::Live,
1645 newid.0,
1646 domain.0 as u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001647 *namespace,
Max Bires8e93d2b2021-01-14 13:17:59 -08001648 KeyLifeCycle::Existing,
Janis Danisevskis0cabd712021-05-25 11:07:10 -07001649 key_type,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001650 ],
Joel Galenson33c04ad2020-08-03 11:04:38 -07001651 )
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001652 .context(ks_err!("Failed to set alias."))?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07001653 if result != 1 {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001654 return Err(KsError::sys()).context(ks_err!(
1655 "Expected to update a single entry but instead updated {}.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07001656 result
1657 ));
1658 }
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001659 Ok(updated != 0)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001660 }
1661
Janis Danisevskiscdcf4e52021-04-14 15:44:36 -07001662 /// Moves the key given by KeyIdGuard to the new location at `destination`. If the destination
1663 /// is already occupied by a key, this function fails with `ResponseCode::INVALID_ARGUMENT`.
1664 pub fn migrate_key_namespace(
1665 &mut self,
1666 key_id_guard: KeyIdGuard,
1667 destination: &KeyDescriptor,
1668 caller_uid: u32,
1669 check_permission: impl Fn(&KeyDescriptor) -> Result<()>,
1670 ) -> Result<()> {
David Drysdale541846b2024-05-23 13:16:07 +01001671 let _wp = wd::watch("KeystoreDB::migrate_key_namespace");
Janis Danisevskis850d4862021-05-05 08:41:14 -07001672
Janis Danisevskiscdcf4e52021-04-14 15:44:36 -07001673 let destination = match destination.domain {
1674 Domain::APP => KeyDescriptor { nspace: caller_uid as i64, ..(*destination).clone() },
1675 Domain::SELINUX => (*destination).clone(),
1676 domain => {
1677 return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT))
1678 .context(format!("Domain {:?} must be either APP or SELINUX.", domain));
1679 }
1680 };
1681
1682 // Security critical: Must return immediately on failure. Do not remove the '?';
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001683 check_permission(&destination).context(ks_err!("Trying to check permission."))?;
Janis Danisevskiscdcf4e52021-04-14 15:44:36 -07001684
1685 let alias = destination
1686 .alias
1687 .as_ref()
1688 .ok_or(KsError::Rc(ResponseCode::INVALID_ARGUMENT))
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001689 .context(ks_err!("Alias must be specified."))?;
Janis Danisevskiscdcf4e52021-04-14 15:44:36 -07001690
David Drysdale7b9ca232024-05-23 18:19:46 +01001691 self.with_transaction(Immediate("TX_migrate_key_namespace"), |tx| {
Janis Danisevskiscdcf4e52021-04-14 15:44:36 -07001692 // Query the destination location. If there is a key, the migration request fails.
1693 if tx
1694 .query_row(
1695 "SELECT id FROM persistent.keyentry
1696 WHERE alias = ? AND domain = ? AND namespace = ?;",
1697 params![alias, destination.domain.0, destination.nspace],
1698 |_| Ok(()),
1699 )
1700 .optional()
1701 .context("Failed to query destination.")?
1702 .is_some()
1703 {
1704 return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT))
1705 .context("Target already exists.");
1706 }
1707
1708 let updated = tx
1709 .execute(
1710 "UPDATE persistent.keyentry
1711 SET alias = ?, domain = ?, namespace = ?
1712 WHERE id = ?;",
1713 params![alias, destination.domain.0, destination.nspace, key_id_guard.id()],
1714 )
1715 .context("Failed to update key entry.")?;
1716
1717 if updated != 1 {
1718 return Err(KsError::sys())
1719 .context(format!("Update succeeded, but {} rows were updated.", updated));
1720 }
1721 Ok(()).no_gc()
1722 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001723 .context(ks_err!())
Janis Danisevskiscdcf4e52021-04-14 15:44:36 -07001724 }
1725
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001726 /// Store a new key in a single transaction.
1727 /// The function creates a new key entry, populates the blob, key parameter, and metadata
1728 /// fields, and rebinds the given alias to the new key.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001729 /// The boolean returned is a hint for the garbage collector. If true, a key was replaced,
1730 /// is now unreferenced and needs to be collected.
Chris Wailes3877f292021-07-26 19:24:18 -07001731 #[allow(clippy::too_many_arguments)]
Janis Danisevskis66784c42021-01-27 08:40:25 -08001732 pub fn store_new_key(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001733 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001734 key: &KeyDescriptor,
Janis Danisevskis0cabd712021-05-25 11:07:10 -07001735 key_type: KeyType,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001736 params: &[KeyParameter],
Janis Danisevskisf84d0b02022-01-26 14:11:14 -08001737 blob_info: &BlobInfo,
Max Bires8e93d2b2021-01-14 13:17:59 -08001738 cert_info: &CertificateInfo,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001739 metadata: &KeyMetaData,
Max Bires8e93d2b2021-01-14 13:17:59 -08001740 km_uuid: &Uuid,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001741 ) -> Result<KeyIdGuard> {
David Drysdale541846b2024-05-23 13:16:07 +01001742 let _wp = wd::watch("KeystoreDB::store_new_key");
Janis Danisevskis850d4862021-05-05 08:41:14 -07001743
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001744 let (alias, domain, namespace) = match key {
1745 KeyDescriptor { alias: Some(alias), domain: Domain::APP, nspace, blob: None }
1746 | KeyDescriptor { alias: Some(alias), domain: Domain::SELINUX, nspace, blob: None } => {
1747 (alias, key.domain, nspace)
1748 }
1749 _ => {
1750 return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT))
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001751 .context(ks_err!("Need alias and domain must be APP or SELINUX."));
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001752 }
1753 };
David Drysdale7b9ca232024-05-23 18:19:46 +01001754 self.with_transaction(Immediate("TX_store_new_key"), |tx| {
Janis Danisevskis0cabd712021-05-25 11:07:10 -07001755 let key_id = Self::create_key_entry_internal(tx, &domain, namespace, key_type, km_uuid)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001756 .context("Trying to create new key entry.")?;
Janis Danisevskisf84d0b02022-01-26 14:11:14 -08001757 let BlobInfo { blob, metadata: blob_metadata, superseded_blob } = *blob_info;
1758
1759 // In some occasions the key blob is already upgraded during the import.
1760 // In order to make sure it gets properly deleted it is inserted into the
1761 // database here and then immediately replaced by the superseding blob.
1762 // The garbage collector will then subject the blob to deleteKey of the
1763 // KM back end to permanently invalidate the key.
1764 let need_gc = if let Some((blob, blob_metadata)) = superseded_blob {
1765 Self::set_blob_internal(
1766 tx,
1767 key_id.id(),
1768 SubComponentType::KEY_BLOB,
1769 Some(blob),
1770 Some(blob_metadata),
1771 )
1772 .context("Trying to insert superseded key blob.")?;
1773 true
1774 } else {
1775 false
1776 };
1777
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001778 Self::set_blob_internal(
1779 tx,
1780 key_id.id(),
1781 SubComponentType::KEY_BLOB,
1782 Some(blob),
Chris Wailesd5aaaef2021-07-27 16:04:33 -07001783 Some(blob_metadata),
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001784 )
1785 .context("Trying to insert the key blob.")?;
Max Bires8e93d2b2021-01-14 13:17:59 -08001786 if let Some(cert) = &cert_info.cert {
Chris Wailesd5aaaef2021-07-27 16:04:33 -07001787 Self::set_blob_internal(tx, key_id.id(), SubComponentType::CERT, Some(cert), None)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001788 .context("Trying to insert the certificate.")?;
1789 }
Max Bires8e93d2b2021-01-14 13:17:59 -08001790 if let Some(cert_chain) = &cert_info.cert_chain {
Janis Danisevskis377d1002021-01-27 19:07:48 -08001791 Self::set_blob_internal(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001792 tx,
1793 key_id.id(),
1794 SubComponentType::CERT_CHAIN,
Chris Wailesd5aaaef2021-07-27 16:04:33 -07001795 Some(cert_chain),
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001796 None,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001797 )
1798 .context("Trying to insert the certificate chain.")?;
1799 }
1800 Self::insert_keyparameter_internal(tx, &key_id, params)
1801 .context("Trying to insert key parameters.")?;
Janis Danisevskis377d1002021-01-27 19:07:48 -08001802 metadata.store_in_db(key_id.id(), tx).context("Trying to insert key metadata.")?;
Chris Wailesd5aaaef2021-07-27 16:04:33 -07001803 let need_gc = Self::rebind_alias(tx, &key_id, alias, &domain, namespace, key_type)
Janis Danisevskisf84d0b02022-01-26 14:11:14 -08001804 .context("Trying to rebind alias.")?
1805 || need_gc;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001806 Ok(key_id).do_gc(need_gc)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001807 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001808 .context(ks_err!())
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001809 }
1810
Janis Danisevskis377d1002021-01-27 19:07:48 -08001811 /// Store a new certificate
1812 /// The function creates a new key entry, populates the blob field and metadata, and rebinds
1813 /// the given alias to the new cert.
Max Bires8e93d2b2021-01-14 13:17:59 -08001814 pub fn store_new_certificate(
1815 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001816 key: &KeyDescriptor,
Janis Danisevskis0cabd712021-05-25 11:07:10 -07001817 key_type: KeyType,
Max Bires8e93d2b2021-01-14 13:17:59 -08001818 cert: &[u8],
1819 km_uuid: &Uuid,
1820 ) -> Result<KeyIdGuard> {
David Drysdale541846b2024-05-23 13:16:07 +01001821 let _wp = wd::watch("KeystoreDB::store_new_certificate");
Janis Danisevskis850d4862021-05-05 08:41:14 -07001822
Janis Danisevskis377d1002021-01-27 19:07:48 -08001823 let (alias, domain, namespace) = match key {
1824 KeyDescriptor { alias: Some(alias), domain: Domain::APP, nspace, blob: None }
1825 | KeyDescriptor { alias: Some(alias), domain: Domain::SELINUX, nspace, blob: None } => {
1826 (alias, key.domain, nspace)
1827 }
1828 _ => {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001829 return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT))
1830 .context(ks_err!("Need alias and domain must be APP or SELINUX."));
Janis Danisevskis377d1002021-01-27 19:07:48 -08001831 }
1832 };
David Drysdale7b9ca232024-05-23 18:19:46 +01001833 self.with_transaction(Immediate("TX_store_new_certificate"), |tx| {
Janis Danisevskis0cabd712021-05-25 11:07:10 -07001834 let key_id = Self::create_key_entry_internal(tx, &domain, namespace, key_type, km_uuid)
Janis Danisevskis377d1002021-01-27 19:07:48 -08001835 .context("Trying to create new key entry.")?;
1836
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001837 Self::set_blob_internal(
1838 tx,
1839 key_id.id(),
1840 SubComponentType::CERT_CHAIN,
1841 Some(cert),
1842 None,
1843 )
1844 .context("Trying to insert certificate.")?;
Janis Danisevskis377d1002021-01-27 19:07:48 -08001845
1846 let mut metadata = KeyMetaData::new();
1847 metadata.add(KeyMetaEntry::CreationDate(
1848 DateTime::now().context("Trying to make creation time.")?,
1849 ));
1850
1851 metadata.store_in_db(key_id.id(), tx).context("Trying to insert key metadata.")?;
1852
Chris Wailesd5aaaef2021-07-27 16:04:33 -07001853 let need_gc = Self::rebind_alias(tx, &key_id, alias, &domain, namespace, key_type)
Janis Danisevskis377d1002021-01-27 19:07:48 -08001854 .context("Trying to rebind alias.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001855 Ok(key_id).do_gc(need_gc)
Janis Danisevskis377d1002021-01-27 19:07:48 -08001856 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001857 .context(ks_err!())
Janis Danisevskis377d1002021-01-27 19:07:48 -08001858 }
1859
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001860 // Helper function loading the key_id given the key descriptor
1861 // tuple comprising domain, namespace, and alias.
1862 // Requires a valid transaction.
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001863 fn load_key_entry_id(tx: &Transaction, key: &KeyDescriptor, key_type: KeyType) -> Result<i64> {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001864 let alias = key
1865 .alias
1866 .as_ref()
1867 .map_or_else(|| Err(KsError::sys()), Ok)
1868 .context("In load_key_entry_id: Alias must be specified.")?;
1869 let mut stmt = tx
1870 .prepare(
1871 "SELECT id FROM persistent.keyentry
1872 WHERE
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00001873 key_type = ?
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001874 AND domain = ?
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001875 AND namespace = ?
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001876 AND alias = ?
1877 AND state = ?;",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001878 )
1879 .context("In load_key_entry_id: Failed to select from keyentry table.")?;
1880 let mut rows = stmt
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001881 .query(params![key_type, key.domain.0 as u32, key.nspace, alias, KeyLifeCycle::Live])
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001882 .context("In load_key_entry_id: Failed to read from keyentry table.")?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08001883 db_utils::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001884 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001885 .get(0)
1886 .context("Failed to unpack id.")
1887 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001888 .context(ks_err!())
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001889 }
1890
1891 /// This helper function completes the access tuple of a key, which is required
1892 /// to perform access control. The strategy depends on the `domain` field in the
1893 /// key descriptor.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001894 /// * Domain::SELINUX: The access tuple is complete and this function only loads
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001895 /// the key_id for further processing.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001896 /// * Domain::APP: Like Domain::SELINUX, but the tuple is completed by `caller_uid`
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001897 /// which serves as the namespace.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001898 /// * Domain::GRANT: The grant table is queried for the `key_id` and the
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001899 /// `access_vector`.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001900 /// * Domain::KEY_ID: The keyentry table is queried for the owning `domain` and
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001901 /// `namespace`.
Chris Wailes1806f972024-08-19 16:37:40 -07001902 ///
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001903 /// In each case the information returned is sufficient to perform the access
1904 /// check and the key id can be used to load further key artifacts.
1905 fn load_access_tuple(
1906 tx: &Transaction,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001907 key: &KeyDescriptor,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001908 key_type: KeyType,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001909 caller_uid: u32,
1910 ) -> Result<(i64, KeyDescriptor, Option<KeyPermSet>)> {
1911 match key.domain {
1912 // Domain App or SELinux. In this case we load the key_id from
1913 // the keyentry database for further loading of key components.
1914 // We already have the full access tuple to perform access control.
1915 // The only distinction is that we use the caller_uid instead
1916 // of the caller supplied namespace if the domain field is
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001917 // Domain::APP.
1918 Domain::APP | Domain::SELINUX => {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001919 let mut access_key = key.clone();
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001920 if access_key.domain == Domain::APP {
1921 access_key.nspace = caller_uid as i64;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001922 }
Chris Wailesd5aaaef2021-07-27 16:04:33 -07001923 let key_id = Self::load_key_entry_id(tx, &access_key, key_type)
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001924 .with_context(|| format!("With key.domain = {:?}.", access_key.domain))?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001925
1926 Ok((key_id, access_key, None))
1927 }
1928
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001929 // Domain::GRANT. In this case we load the key_id and the access_vector
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001930 // from the grant table.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001931 Domain::GRANT => {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001932 let mut stmt = tx
1933 .prepare(
Janis Danisevskisbf15d732020-12-08 10:35:26 -08001934 "SELECT keyentryid, access_vector FROM persistent.grant
Hasini Gunasinghee70a0ec2021-05-10 21:12:34 +00001935 WHERE grantee = ? AND id = ? AND
1936 (SELECT state FROM persistent.keyentry WHERE id = keyentryid) = ?;",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001937 )
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001938 .context("Domain::GRANT prepare statement failed")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001939 let mut rows = stmt
Hasini Gunasinghee70a0ec2021-05-10 21:12:34 +00001940 .query(params![caller_uid as i64, key.nspace, KeyLifeCycle::Live])
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001941 .context("Domain:Grant: query failed.")?;
1942 let (key_id, access_vector): (i64, i32) =
Janis Danisevskisbf15d732020-12-08 10:35:26 -08001943 db_utils::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001944 let r =
1945 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001946 Ok((
1947 r.get(0).context("Failed to unpack key_id.")?,
1948 r.get(1).context("Failed to unpack access_vector.")?,
1949 ))
1950 })
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001951 .context("Domain::GRANT.")?;
Janis Danisevskis66784c42021-01-27 08:40:25 -08001952 Ok((key_id, key.clone(), Some(access_vector.into())))
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001953 }
1954
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001955 // Domain::KEY_ID. In this case we load the domain and namespace from the
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001956 // keyentry database because we need them for access control.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001957 Domain::KEY_ID => {
Janis Danisevskis45760022021-01-19 16:34:10 -08001958 let (domain, namespace): (Domain, i64) = {
1959 let mut stmt = tx
1960 .prepare(
1961 "SELECT domain, namespace FROM persistent.keyentry
1962 WHERE
1963 id = ?
1964 AND state = ?;",
1965 )
1966 .context("Domain::KEY_ID: prepare statement failed")?;
1967 let mut rows = stmt
1968 .query(params![key.nspace, KeyLifeCycle::Live])
1969 .context("Domain::KEY_ID: query failed.")?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08001970 db_utils::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001971 let r =
1972 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001973 Ok((
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001974 Domain(r.get(0).context("Failed to unpack domain.")?),
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001975 r.get(1).context("Failed to unpack namespace.")?,
1976 ))
1977 })
Janis Danisevskis45760022021-01-19 16:34:10 -08001978 .context("Domain::KEY_ID.")?
1979 };
1980
1981 // We may use a key by id after loading it by grant.
1982 // In this case we have to check if the caller has a grant for this particular
1983 // key. We can skip this if we already know that the caller is the owner.
1984 // But we cannot know this if domain is anything but App. E.g. in the case
1985 // of Domain::SELINUX we have to speculatively check for grants because we have to
1986 // consult the SEPolicy before we know if the caller is the owner.
1987 let access_vector: Option<KeyPermSet> =
1988 if domain != Domain::APP || namespace != caller_uid as i64 {
1989 let access_vector: Option<i32> = tx
1990 .query_row(
1991 "SELECT access_vector FROM persistent.grant
1992 WHERE grantee = ? AND keyentryid = ?;",
1993 params![caller_uid as i64, key.nspace],
1994 |row| row.get(0),
1995 )
1996 .optional()
1997 .context("Domain::KEY_ID: query grant failed.")?;
1998 access_vector.map(|p| p.into())
1999 } else {
2000 None
2001 };
2002
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002003 let key_id = key.nspace;
Janis Danisevskis66784c42021-01-27 08:40:25 -08002004 let mut access_key: KeyDescriptor = key.clone();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002005 access_key.domain = domain;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002006 access_key.nspace = namespace;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002007
Janis Danisevskis45760022021-01-19 16:34:10 -08002008 Ok((key_id, access_key, access_vector))
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002009 }
Rajesh Nyamagoud625e5892022-05-18 01:31:26 +00002010 _ => Err(anyhow!(KsError::Rc(ResponseCode::INVALID_ARGUMENT))),
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002011 }
2012 }
2013
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002014 fn load_blob_components(
2015 key_id: i64,
2016 load_bits: KeyEntryLoadBits,
2017 tx: &Transaction,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002018 ) -> Result<(bool, Option<(Vec<u8>, BlobMetaData)>, Option<Vec<u8>>, Option<Vec<u8>>)> {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002019 let mut stmt = tx
2020 .prepare(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002021 "SELECT MAX(id), subcomponent_type, blob FROM persistent.blobentry
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002022 WHERE keyentryid = ? GROUP BY subcomponent_type;",
2023 )
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002024 .context(ks_err!("prepare statement failed."))?;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002025
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002026 let mut rows = stmt.query(params![key_id]).context(ks_err!("query failed."))?;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002027
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002028 let mut key_blob: Option<(i64, Vec<u8>)> = None;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002029 let mut cert_blob: Option<Vec<u8>> = None;
2030 let mut cert_chain_blob: Option<Vec<u8>> = None;
Janis Danisevskis377d1002021-01-27 19:07:48 -08002031 let mut has_km_blob: bool = false;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002032 db_utils::with_rows_extract_all(&mut rows, |row| {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002033 let sub_type: SubComponentType =
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002034 row.get(1).context("Failed to extract subcomponent_type.")?;
Janis Danisevskis377d1002021-01-27 19:07:48 -08002035 has_km_blob = has_km_blob || sub_type == SubComponentType::KEY_BLOB;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002036 match (sub_type, load_bits.load_public(), load_bits.load_km()) {
2037 (SubComponentType::KEY_BLOB, _, true) => {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002038 key_blob = Some((
2039 row.get(0).context("Failed to extract key blob id.")?,
2040 row.get(2).context("Failed to extract key blob.")?,
2041 ));
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002042 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002043 (SubComponentType::CERT, true, _) => {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002044 cert_blob =
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002045 Some(row.get(2).context("Failed to extract public certificate blob.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002046 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002047 (SubComponentType::CERT_CHAIN, true, _) => {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002048 cert_chain_blob =
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002049 Some(row.get(2).context("Failed to extract certificate chain blob.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002050 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002051 (SubComponentType::CERT, _, _)
2052 | (SubComponentType::CERT_CHAIN, _, _)
2053 | (SubComponentType::KEY_BLOB, _, _) => {}
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002054 _ => Err(KsError::sys()).context("Unknown subcomponent type.")?,
2055 }
2056 Ok(())
2057 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002058 .context(ks_err!())?;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002059
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002060 let blob_info = key_blob.map_or::<Result<_>, _>(Ok(None), |(blob_id, blob)| {
2061 Ok(Some((
2062 blob,
2063 BlobMetaData::load_from_db(blob_id, tx)
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002064 .context(ks_err!("Trying to load blob_metadata."))?,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002065 )))
2066 })?;
2067
2068 Ok((has_km_blob, blob_info, cert_blob, cert_chain_blob))
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002069 }
2070
2071 fn load_key_parameters(key_id: i64, tx: &Transaction) -> Result<Vec<KeyParameter>> {
2072 let mut stmt = tx
2073 .prepare(
2074 "SELECT tag, data, security_level from persistent.keyparameter
2075 WHERE keyentryid = ?;",
2076 )
2077 .context("In load_key_parameters: prepare statement failed.")?;
2078
2079 let mut parameters: Vec<KeyParameter> = Vec::new();
2080
2081 let mut rows =
2082 stmt.query(params![key_id]).context("In load_key_parameters: query failed.")?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002083 db_utils::with_rows_extract_all(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002084 let tag = Tag(row.get(0).context("Failed to read tag.")?);
2085 let sec_level = SecurityLevel(row.get(2).context("Failed to read sec_level.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002086 parameters.push(
Chris Wailesd5aaaef2021-07-27 16:04:33 -07002087 KeyParameter::new_from_sql(tag, &SqlField::new(1, row), sec_level)
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002088 .context("Failed to read KeyParameter.")?,
2089 );
2090 Ok(())
2091 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002092 .context(ks_err!())?;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002093
2094 Ok(parameters)
2095 }
2096
Qi Wub9433b52020-12-01 14:52:46 +08002097 /// Decrements the usage count of a limited use key. This function first checks whether the
2098 /// usage has been exhausted, if not, decreases the usage count. If the usage count reaches
2099 /// zero, the key also gets marked unreferenced and scheduled for deletion.
2100 /// Returns Ok(true) if the key was marked unreferenced as a hint to the garbage collector.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002101 pub fn check_and_update_key_usage_count(&mut self, key_id: i64) -> Result<()> {
David Drysdale541846b2024-05-23 13:16:07 +01002102 let _wp = wd::watch("KeystoreDB::check_and_update_key_usage_count");
Janis Danisevskis850d4862021-05-05 08:41:14 -07002103
David Drysdale7b9ca232024-05-23 18:19:46 +01002104 self.with_transaction(Immediate("TX_check_and_update_key_usage_count"), |tx| {
Qi Wub9433b52020-12-01 14:52:46 +08002105 let limit: Option<i32> = tx
2106 .query_row(
2107 "SELECT data FROM persistent.keyparameter WHERE keyentryid = ? AND tag = ?;",
2108 params![key_id, Tag::USAGE_COUNT_LIMIT.0],
2109 |row| row.get(0),
2110 )
2111 .optional()
2112 .context("Trying to load usage count")?;
2113
2114 let limit = limit
2115 .ok_or(KsError::Km(ErrorCode::INVALID_KEY_BLOB))
2116 .context("The Key no longer exists. Key is exhausted.")?;
2117
2118 tx.execute(
2119 "UPDATE persistent.keyparameter
2120 SET data = data - 1
2121 WHERE keyentryid = ? AND tag = ? AND data > 0;",
2122 params![key_id, Tag::USAGE_COUNT_LIMIT.0],
2123 )
2124 .context("Failed to update key usage count.")?;
2125
2126 match limit {
2127 1 => Self::mark_unreferenced(tx, key_id)
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002128 .map(|need_gc| (need_gc, ()))
Qi Wub9433b52020-12-01 14:52:46 +08002129 .context("Trying to mark limited use key for deletion."),
2130 0 => Err(KsError::Km(ErrorCode::INVALID_KEY_BLOB)).context("Key is exhausted."),
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002131 _ => Ok(()).no_gc(),
Qi Wub9433b52020-12-01 14:52:46 +08002132 }
2133 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002134 .context(ks_err!())
Qi Wub9433b52020-12-01 14:52:46 +08002135 }
2136
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002137 /// Load a key entry by the given key descriptor.
2138 /// It uses the `check_permission` callback to verify if the access is allowed
2139 /// given the key access tuple read from the database using `load_access_tuple`.
2140 /// With `load_bits` the caller may specify which blobs shall be loaded from
2141 /// the blob database.
2142 pub fn load_key_entry(
2143 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002144 key: &KeyDescriptor,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002145 key_type: KeyType,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002146 load_bits: KeyEntryLoadBits,
2147 caller_uid: u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002148 check_permission: impl Fn(&KeyDescriptor, Option<KeyPermSet>) -> Result<()>,
2149 ) -> Result<(KeyIdGuard, KeyEntry)> {
David Drysdale541846b2024-05-23 13:16:07 +01002150 let _wp = wd::watch("KeystoreDB::load_key_entry");
Janis Danisevskis850d4862021-05-05 08:41:14 -07002151
Janis Danisevskis66784c42021-01-27 08:40:25 -08002152 loop {
2153 match self.load_key_entry_internal(
2154 key,
2155 key_type,
2156 load_bits,
2157 caller_uid,
2158 &check_permission,
2159 ) {
2160 Ok(result) => break Ok(result),
2161 Err(e) => {
2162 if Self::is_locked_error(&e) {
David Drysdale115c4722024-04-15 14:11:52 +01002163 std::thread::sleep(DB_BUSY_RETRY_INTERVAL);
Janis Danisevskis66784c42021-01-27 08:40:25 -08002164 continue;
2165 } else {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002166 return Err(e).context(ks_err!());
Janis Danisevskis66784c42021-01-27 08:40:25 -08002167 }
2168 }
2169 }
2170 }
2171 }
2172
2173 fn load_key_entry_internal(
2174 &mut self,
2175 key: &KeyDescriptor,
2176 key_type: KeyType,
2177 load_bits: KeyEntryLoadBits,
2178 caller_uid: u32,
2179 check_permission: &impl Fn(&KeyDescriptor, Option<KeyPermSet>) -> Result<()>,
Janis Danisevskisaec14592020-11-12 09:41:49 -08002180 ) -> Result<(KeyIdGuard, KeyEntry)> {
2181 // KEY ID LOCK 1/2
2182 // If we got a key descriptor with a key id we can get the lock right away.
2183 // Otherwise we have to defer it until we know the key id.
2184 let key_id_guard = match key.domain {
2185 Domain::KEY_ID => Some(KEY_ID_LOCK.get(key.nspace)),
2186 _ => None,
2187 };
2188
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002189 let tx = self
2190 .conn
Janis Danisevskisaec14592020-11-12 09:41:49 -08002191 .unchecked_transaction()
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002192 .context(ks_err!("Failed to initialize transaction."))?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002193
2194 // Load the key_id and complete the access control tuple.
2195 let (key_id, access_key_descriptor, access_vector) =
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002196 Self::load_access_tuple(&tx, key, key_type, caller_uid).context(ks_err!())?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002197
2198 // Perform access control. It is vital that we return here if the permission is denied.
2199 // So do not touch that '?' at the end.
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002200 check_permission(&access_key_descriptor, access_vector).context(ks_err!())?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002201
Janis Danisevskisaec14592020-11-12 09:41:49 -08002202 // KEY ID LOCK 2/2
2203 // If we did not get a key id lock by now, it was because we got a key descriptor
2204 // without a key id. At this point we got the key id, so we can try and get a lock.
2205 // However, we cannot block here, because we are in the middle of the transaction.
2206 // So first we try to get the lock non blocking. If that fails, we roll back the
2207 // transaction and block until we get the lock. After we successfully got the lock,
2208 // we start a new transaction and load the access tuple again.
2209 //
2210 // We don't need to perform access control again, because we already established
2211 // that the caller had access to the given key. But we need to make sure that the
2212 // key id still exists. So we have to load the key entry by key id this time.
2213 let (key_id_guard, tx) = match key_id_guard {
2214 None => match KEY_ID_LOCK.try_get(key_id) {
2215 None => {
2216 // Roll back the transaction.
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002217 tx.rollback().context(ks_err!("Failed to roll back transaction."))?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002218
Janis Danisevskisaec14592020-11-12 09:41:49 -08002219 // Block until we have a key id lock.
2220 let key_id_guard = KEY_ID_LOCK.get(key_id);
2221
2222 // Create a new transaction.
Janis Danisevskis66784c42021-01-27 08:40:25 -08002223 let tx = self
2224 .conn
2225 .unchecked_transaction()
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002226 .context(ks_err!("Failed to initialize transaction."))?;
Janis Danisevskisaec14592020-11-12 09:41:49 -08002227
2228 Self::load_access_tuple(
2229 &tx,
2230 // This time we have to load the key by the retrieved key id, because the
2231 // alias may have been rebound after we rolled back the transaction.
Janis Danisevskis66784c42021-01-27 08:40:25 -08002232 &KeyDescriptor {
Janis Danisevskisaec14592020-11-12 09:41:49 -08002233 domain: Domain::KEY_ID,
2234 nspace: key_id,
2235 ..Default::default()
2236 },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002237 key_type,
Janis Danisevskisaec14592020-11-12 09:41:49 -08002238 caller_uid,
2239 )
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002240 .context(ks_err!("(deferred key lock)"))?;
Janis Danisevskisaec14592020-11-12 09:41:49 -08002241 (key_id_guard, tx)
2242 }
2243 Some(l) => (l, tx),
2244 },
2245 Some(key_id_guard) => (key_id_guard, tx),
2246 };
2247
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002248 let key_entry =
2249 Self::load_key_components(&tx, load_bits, key_id_guard.id()).context(ks_err!())?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002250
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002251 tx.commit().context(ks_err!("Failed to commit transaction."))?;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002252
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002253 Ok((key_id_guard, key_entry))
2254 }
2255
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002256 fn mark_unreferenced(tx: &Transaction, key_id: i64) -> Result<bool> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002257 let updated = tx
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002258 .execute("DELETE FROM persistent.keyentry WHERE id = ?;", params![key_id])
2259 .context("Trying to delete keyentry.")?;
2260 tx.execute("DELETE FROM persistent.keymetadata WHERE keyentryid = ?;", params![key_id])
2261 .context("Trying to delete keymetadata.")?;
2262 tx.execute("DELETE FROM persistent.keyparameter WHERE keyentryid = ?;", params![key_id])
2263 .context("Trying to delete keyparameters.")?;
2264 tx.execute("DELETE FROM persistent.grant WHERE keyentryid = ?;", params![key_id])
2265 .context("Trying to delete grants.")?;
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002266 Ok(updated != 0)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002267 }
2268
2269 /// Marks the given key as unreferenced and removes all of the grants to this key.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002270 /// Returns Ok(true) if a key was marked unreferenced as a hint for the garbage collector.
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002271 pub fn unbind_key(
2272 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002273 key: &KeyDescriptor,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002274 key_type: KeyType,
2275 caller_uid: u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002276 check_permission: impl Fn(&KeyDescriptor, Option<KeyPermSet>) -> Result<()>,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002277 ) -> Result<()> {
David Drysdale541846b2024-05-23 13:16:07 +01002278 let _wp = wd::watch("KeystoreDB::unbind_key");
Janis Danisevskis850d4862021-05-05 08:41:14 -07002279
David Drysdale7b9ca232024-05-23 18:19:46 +01002280 self.with_transaction(Immediate("TX_unbind_key"), |tx| {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002281 let (key_id, access_key_descriptor, access_vector) =
2282 Self::load_access_tuple(tx, key, key_type, caller_uid)
2283 .context("Trying to get access tuple.")?;
2284
2285 // Perform access control. It is vital that we return here if the permission is denied.
2286 // So do not touch that '?' at the end.
2287 check_permission(&access_key_descriptor, access_vector)
2288 .context("While checking permission.")?;
2289
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002290 Self::mark_unreferenced(tx, key_id)
2291 .map(|need_gc| (need_gc, ()))
2292 .context("Trying to mark the key unreferenced.")
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002293 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002294 .context(ks_err!())
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002295 }
2296
Max Bires8e93d2b2021-01-14 13:17:59 -08002297 fn get_key_km_uuid(tx: &Transaction, key_id: i64) -> Result<Uuid> {
2298 tx.query_row(
2299 "SELECT km_uuid FROM persistent.keyentry WHERE id = ?",
2300 params![key_id],
2301 |row| row.get(0),
2302 )
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002303 .context(ks_err!())
Max Bires8e93d2b2021-01-14 13:17:59 -08002304 }
2305
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002306 /// Delete all artifacts belonging to the namespace given by the domain-namespace tuple.
2307 /// This leaves all of the blob entries orphaned for subsequent garbage collection.
2308 pub fn unbind_keys_for_namespace(&mut self, domain: Domain, namespace: i64) -> Result<()> {
David Drysdale541846b2024-05-23 13:16:07 +01002309 let _wp = wd::watch("KeystoreDB::unbind_keys_for_namespace");
Janis Danisevskis850d4862021-05-05 08:41:14 -07002310
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002311 if !(domain == Domain::APP || domain == Domain::SELINUX) {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002312 return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT)).context(ks_err!());
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002313 }
David Drysdale7b9ca232024-05-23 18:19:46 +01002314 self.with_transaction(Immediate("TX_unbind_keys_for_namespace"), |tx| {
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002315 tx.execute(
2316 "DELETE FROM persistent.keymetadata
2317 WHERE keyentryid IN (
2318 SELECT id FROM persistent.keyentry
Tri Vo0346bbe2023-05-12 14:16:31 -04002319 WHERE domain = ? AND namespace = ? AND key_type = ?
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002320 );",
Tri Vo0346bbe2023-05-12 14:16:31 -04002321 params![domain.0, namespace, KeyType::Client],
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002322 )
2323 .context("Trying to delete keymetadata.")?;
2324 tx.execute(
2325 "DELETE FROM persistent.keyparameter
2326 WHERE keyentryid IN (
2327 SELECT id FROM persistent.keyentry
Tri Vo0346bbe2023-05-12 14:16:31 -04002328 WHERE domain = ? AND namespace = ? AND key_type = ?
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002329 );",
Tri Vo0346bbe2023-05-12 14:16:31 -04002330 params![domain.0, namespace, KeyType::Client],
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002331 )
2332 .context("Trying to delete keyparameters.")?;
2333 tx.execute(
2334 "DELETE FROM persistent.grant
2335 WHERE keyentryid IN (
2336 SELECT id FROM persistent.keyentry
Tri Vo0346bbe2023-05-12 14:16:31 -04002337 WHERE domain = ? AND namespace = ? AND key_type = ?
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002338 );",
Tri Vo0346bbe2023-05-12 14:16:31 -04002339 params![domain.0, namespace, KeyType::Client],
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002340 )
2341 .context("Trying to delete grants.")?;
2342 tx.execute(
Janis Danisevskisb146f312021-05-06 15:05:45 -07002343 "DELETE FROM persistent.keyentry
Tri Vo0346bbe2023-05-12 14:16:31 -04002344 WHERE domain = ? AND namespace = ? AND key_type = ?;",
2345 params![domain.0, namespace, KeyType::Client],
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002346 )
2347 .context("Trying to delete keyentry.")?;
2348 Ok(()).need_gc()
2349 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002350 .context(ks_err!())
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002351 }
2352
Janis Danisevskis3cba10d2021-05-06 17:02:19 -07002353 fn cleanup_unreferenced(tx: &Transaction) -> Result<()> {
David Drysdale541846b2024-05-23 13:16:07 +01002354 let _wp = wd::watch("KeystoreDB::cleanup_unreferenced");
Janis Danisevskis3cba10d2021-05-06 17:02:19 -07002355 {
2356 tx.execute(
2357 "DELETE FROM persistent.keymetadata
2358 WHERE keyentryid IN (
2359 SELECT id FROM persistent.keyentry
2360 WHERE state = ?
2361 );",
2362 params![KeyLifeCycle::Unreferenced],
2363 )
2364 .context("Trying to delete keymetadata.")?;
2365 tx.execute(
2366 "DELETE FROM persistent.keyparameter
2367 WHERE keyentryid IN (
2368 SELECT id FROM persistent.keyentry
2369 WHERE state = ?
2370 );",
2371 params![KeyLifeCycle::Unreferenced],
2372 )
2373 .context("Trying to delete keyparameters.")?;
2374 tx.execute(
2375 "DELETE FROM persistent.grant
2376 WHERE keyentryid IN (
2377 SELECT id FROM persistent.keyentry
2378 WHERE state = ?
2379 );",
2380 params![KeyLifeCycle::Unreferenced],
2381 )
2382 .context("Trying to delete grants.")?;
2383 tx.execute(
2384 "DELETE FROM persistent.keyentry
2385 WHERE state = ?;",
2386 params![KeyLifeCycle::Unreferenced],
2387 )
2388 .context("Trying to delete keyentry.")?;
2389 Result::<()>::Ok(())
2390 }
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002391 .context(ks_err!())
Janis Danisevskis3cba10d2021-05-06 17:02:19 -07002392 }
2393
Eric Biggers9f7ebeb2024-06-20 14:59:32 +00002394 /// Deletes all keys for the given user, including both client keys and super keys.
2395 pub fn unbind_keys_for_user(&mut self, user_id: u32) -> Result<()> {
David Drysdale541846b2024-05-23 13:16:07 +01002396 let _wp = wd::watch("KeystoreDB::unbind_keys_for_user");
Janis Danisevskis850d4862021-05-05 08:41:14 -07002397
David Drysdale7b9ca232024-05-23 18:19:46 +01002398 self.with_transaction(Immediate("TX_unbind_keys_for_user"), |tx| {
Hasini Gunasingheda895552021-01-27 19:34:37 +00002399 let mut stmt = tx
2400 .prepare(&format!(
2401 "SELECT id from persistent.keyentry
2402 WHERE (
2403 key_type = ?
2404 AND domain = ?
2405 AND cast ( (namespace/{aid_user_offset}) as int) = ?
2406 AND state = ?
2407 ) OR (
2408 key_type = ?
2409 AND namespace = ?
Hasini Gunasingheda895552021-01-27 19:34:37 +00002410 AND state = ?
2411 );",
2412 aid_user_offset = AID_USER_OFFSET
2413 ))
2414 .context(concat!(
2415 "In unbind_keys_for_user. ",
2416 "Failed to prepare the query to find the keys created by apps."
2417 ))?;
2418
2419 let mut rows = stmt
2420 .query(params![
2421 // WHERE client key:
2422 KeyType::Client,
2423 Domain::APP.0 as u32,
2424 user_id,
2425 KeyLifeCycle::Live,
2426 // OR super key:
2427 KeyType::Super,
2428 user_id,
Hasini Gunasingheda895552021-01-27 19:34:37 +00002429 KeyLifeCycle::Live
2430 ])
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002431 .context(ks_err!("Failed to query the keys created by apps."))?;
Hasini Gunasingheda895552021-01-27 19:34:37 +00002432
2433 let mut key_ids: Vec<i64> = Vec::new();
2434 db_utils::with_rows_extract_all(&mut rows, |row| {
2435 key_ids
2436 .push(row.get(0).context("Failed to read key id of a key created by an app.")?);
2437 Ok(())
2438 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002439 .context(ks_err!())?;
Hasini Gunasingheda895552021-01-27 19:34:37 +00002440
2441 let mut notify_gc = false;
2442 for key_id in key_ids {
Chris Wailesd5aaaef2021-07-27 16:04:33 -07002443 notify_gc = Self::mark_unreferenced(tx, key_id)
Hasini Gunasingheda895552021-01-27 19:34:37 +00002444 .context("In unbind_keys_for_user.")?
2445 || notify_gc;
2446 }
2447 Ok(()).do_gc(notify_gc)
2448 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002449 .context(ks_err!())
Hasini Gunasingheda895552021-01-27 19:34:37 +00002450 }
2451
Eric Biggersb0478cf2023-10-27 03:55:29 +00002452 /// Deletes all auth-bound keys, i.e. keys that require user authentication, for the given user.
2453 /// This runs when the user's lock screen is being changed to Swipe or None.
2454 ///
2455 /// This intentionally does *not* delete keys that require that the device be unlocked, unless
2456 /// such keys also require user authentication. Keystore's concept of user authentication is
2457 /// fairly strong, and it requires that keys that require authentication be deleted as soon as
2458 /// authentication is no longer possible. In contrast, keys that just require that the device
2459 /// be unlocked should remain usable when the lock screen is set to Swipe or None, as the device
2460 /// is always considered "unlocked" in that case.
2461 pub fn unbind_auth_bound_keys_for_user(&mut self, user_id: u32) -> Result<()> {
David Drysdale541846b2024-05-23 13:16:07 +01002462 let _wp = wd::watch("KeystoreDB::unbind_auth_bound_keys_for_user");
Eric Biggersb0478cf2023-10-27 03:55:29 +00002463
David Drysdale7b9ca232024-05-23 18:19:46 +01002464 self.with_transaction(Immediate("TX_unbind_auth_bound_keys_for_user"), |tx| {
Eric Biggersb0478cf2023-10-27 03:55:29 +00002465 let mut stmt = tx
2466 .prepare(&format!(
2467 "SELECT id from persistent.keyentry
2468 WHERE key_type = ?
2469 AND domain = ?
2470 AND cast ( (namespace/{aid_user_offset}) as int) = ?
2471 AND state = ?;",
2472 aid_user_offset = AID_USER_OFFSET
2473 ))
2474 .context(concat!(
2475 "In unbind_auth_bound_keys_for_user. ",
2476 "Failed to prepare the query to find the keys created by apps."
2477 ))?;
2478
2479 let mut rows = stmt
2480 .query(params![KeyType::Client, Domain::APP.0 as u32, user_id, KeyLifeCycle::Live,])
2481 .context(ks_err!("Failed to query the keys created by apps."))?;
2482
2483 let mut key_ids: Vec<i64> = Vec::new();
2484 db_utils::with_rows_extract_all(&mut rows, |row| {
2485 key_ids
2486 .push(row.get(0).context("Failed to read key id of a key created by an app.")?);
2487 Ok(())
2488 })
2489 .context(ks_err!())?;
2490
2491 let mut notify_gc = false;
2492 let mut num_unbound = 0;
2493 for key_id in key_ids {
2494 // Load the key parameters and filter out non-auth-bound keys. To identify
2495 // auth-bound keys, use the presence of UserSecureID. The absence of NoAuthRequired
2496 // could also be used, but UserSecureID is what Keystore treats as authoritative
2497 // when actually enforcing the key parameters (it might not matter, though).
2498 let params = Self::load_key_parameters(key_id, tx)
2499 .context("Failed to load key parameters.")?;
2500 let is_auth_bound_key = params.iter().any(|kp| {
2501 matches!(kp.key_parameter_value(), KeyParameterValue::UserSecureID(_))
2502 });
2503 if is_auth_bound_key {
2504 notify_gc = Self::mark_unreferenced(tx, key_id)
2505 .context("In unbind_auth_bound_keys_for_user.")?
2506 || notify_gc;
2507 num_unbound += 1;
2508 }
2509 }
2510 log::info!("Deleting {num_unbound} auth-bound keys for user {user_id}");
2511 Ok(()).do_gc(notify_gc)
2512 })
2513 .context(ks_err!())
2514 }
2515
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002516 fn load_key_components(
2517 tx: &Transaction,
2518 load_bits: KeyEntryLoadBits,
2519 key_id: i64,
2520 ) -> Result<KeyEntry> {
Chris Wailesd5aaaef2021-07-27 16:04:33 -07002521 let metadata = KeyMetaData::load_from_db(key_id, tx).context("In load_key_components.")?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002522
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002523 let (has_km_blob, key_blob_info, cert_blob, cert_chain_blob) =
Chris Wailesd5aaaef2021-07-27 16:04:33 -07002524 Self::load_blob_components(key_id, load_bits, tx).context("In load_key_components.")?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002525
Chris Wailesd5aaaef2021-07-27 16:04:33 -07002526 let parameters = Self::load_key_parameters(key_id, tx)
Max Bires8e93d2b2021-01-14 13:17:59 -08002527 .context("In load_key_components: Trying to load key parameters.")?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002528
Chris Wailesd5aaaef2021-07-27 16:04:33 -07002529 let km_uuid = Self::get_key_km_uuid(tx, key_id)
Max Bires8e93d2b2021-01-14 13:17:59 -08002530 .context("In load_key_components: Trying to get KM uuid.")?;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002531
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002532 Ok(KeyEntry {
2533 id: key_id,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002534 key_blob_info,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002535 cert: cert_blob,
2536 cert_chain: cert_chain_blob,
Max Bires8e93d2b2021-01-14 13:17:59 -08002537 km_uuid,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002538 parameters,
2539 metadata,
Janis Danisevskis377d1002021-01-27 19:07:48 -08002540 pure_cert: !has_km_blob,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002541 })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002542 }
2543
Eran Messeri24f31972023-01-25 17:00:33 +00002544 /// Returns a list of KeyDescriptors in the selected domain/namespace whose
2545 /// aliases are greater than the specified 'start_past_alias'. If no value
2546 /// is provided, returns all KeyDescriptors.
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002547 /// The key descriptors will have the domain, nspace, and alias field set.
Eran Messeri24f31972023-01-25 17:00:33 +00002548 /// The returned list will be sorted by alias.
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002549 /// Domain must be APP or SELINUX, the caller must make sure of that.
Eran Messeri24f31972023-01-25 17:00:33 +00002550 pub fn list_past_alias(
Janis Danisevskis18313832021-05-17 13:30:32 -07002551 &mut self,
2552 domain: Domain,
2553 namespace: i64,
2554 key_type: KeyType,
Eran Messeri24f31972023-01-25 17:00:33 +00002555 start_past_alias: Option<&str>,
Janis Danisevskis18313832021-05-17 13:30:32 -07002556 ) -> Result<Vec<KeyDescriptor>> {
David Drysdale541846b2024-05-23 13:16:07 +01002557 let _wp = wd::watch("KeystoreDB::list_past_alias");
Janis Danisevskis850d4862021-05-05 08:41:14 -07002558
Eran Messeri24f31972023-01-25 17:00:33 +00002559 let query = format!(
2560 "SELECT DISTINCT alias FROM persistent.keyentry
Janis Danisevskis18313832021-05-17 13:30:32 -07002561 WHERE domain = ?
2562 AND namespace = ?
2563 AND alias IS NOT NULL
2564 AND state = ?
Eran Messeri24f31972023-01-25 17:00:33 +00002565 AND key_type = ?
2566 {}
2567 ORDER BY alias ASC;",
2568 if start_past_alias.is_some() { " AND alias > ?" } else { "" }
2569 );
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002570
Eran Messeri24f31972023-01-25 17:00:33 +00002571 self.with_transaction(TransactionBehavior::Deferred, |tx| {
2572 let mut stmt = tx.prepare(&query).context(ks_err!("Failed to prepare."))?;
2573
2574 let mut rows = match start_past_alias {
2575 Some(past_alias) => stmt
2576 .query(params![
2577 domain.0 as u32,
2578 namespace,
2579 KeyLifeCycle::Live,
2580 key_type,
2581 past_alias
2582 ])
2583 .context(ks_err!("Failed to query."))?,
2584 None => stmt
2585 .query(params![domain.0 as u32, namespace, KeyLifeCycle::Live, key_type,])
2586 .context(ks_err!("Failed to query."))?,
2587 };
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002588
Janis Danisevskis66784c42021-01-27 08:40:25 -08002589 let mut descriptors: Vec<KeyDescriptor> = Vec::new();
2590 db_utils::with_rows_extract_all(&mut rows, |row| {
2591 descriptors.push(KeyDescriptor {
2592 domain,
2593 nspace: namespace,
2594 alias: Some(row.get(0).context("Trying to extract alias.")?),
2595 blob: None,
2596 });
2597 Ok(())
2598 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002599 .context(ks_err!("Failed to extract rows."))?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002600 Ok(descriptors).no_gc()
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002601 })
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002602 }
2603
Eran Messeri24f31972023-01-25 17:00:33 +00002604 /// Returns a number of KeyDescriptors in the selected domain/namespace.
2605 /// Domain must be APP or SELINUX, the caller must make sure of that.
2606 pub fn count_keys(
2607 &mut self,
2608 domain: Domain,
2609 namespace: i64,
2610 key_type: KeyType,
2611 ) -> Result<usize> {
David Drysdale541846b2024-05-23 13:16:07 +01002612 let _wp = wd::watch("KeystoreDB::countKeys");
Eran Messeri24f31972023-01-25 17:00:33 +00002613
2614 let num_keys = self.with_transaction(TransactionBehavior::Deferred, |tx| {
2615 tx.query_row(
2616 "SELECT COUNT(alias) FROM persistent.keyentry
2617 WHERE domain = ?
2618 AND namespace = ?
2619 AND alias IS NOT NULL
2620 AND state = ?
2621 AND key_type = ?;",
2622 params![domain.0 as u32, namespace, KeyLifeCycle::Live, key_type],
2623 |row| row.get(0),
2624 )
2625 .context(ks_err!("Failed to count number of keys."))
2626 .no_gc()
2627 })?;
2628 Ok(num_keys)
2629 }
2630
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002631 /// Adds a grant to the grant table.
2632 /// Like `load_key_entry` this function loads the access tuple before
2633 /// it uses the callback for a permission check. Upon success,
2634 /// it inserts the `grantee_uid`, `key_id`, and `access_vector` into the
2635 /// grant table. The new row will have a randomized id, which is used as
2636 /// grant id in the namespace field of the resulting KeyDescriptor.
2637 pub fn grant(
2638 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002639 key: &KeyDescriptor,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002640 caller_uid: u32,
2641 grantee_uid: u32,
2642 access_vector: KeyPermSet,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002643 check_permission: impl Fn(&KeyDescriptor, &KeyPermSet) -> Result<()>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002644 ) -> Result<KeyDescriptor> {
David Drysdale541846b2024-05-23 13:16:07 +01002645 let _wp = wd::watch("KeystoreDB::grant");
Janis Danisevskis850d4862021-05-05 08:41:14 -07002646
David Drysdale7b9ca232024-05-23 18:19:46 +01002647 self.with_transaction(Immediate("TX_grant"), |tx| {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002648 // Load the key_id and complete the access control tuple.
2649 // We ignore the access vector here because grants cannot be granted.
2650 // The access vector returned here expresses the permissions the
2651 // grantee has if key.domain == Domain::GRANT. But this vector
2652 // cannot include the grant permission by design, so there is no way the
2653 // subsequent permission check can pass.
2654 // We could check key.domain == Domain::GRANT and fail early.
2655 // But even if we load the access tuple by grant here, the permission
2656 // check denies the attempt to create a grant by grant descriptor.
2657 let (key_id, access_key_descriptor, _) =
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002658 Self::load_access_tuple(tx, key, KeyType::Client, caller_uid).context(ks_err!())?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002659
Janis Danisevskis66784c42021-01-27 08:40:25 -08002660 // Perform access control. It is vital that we return here if the permission
2661 // was denied. So do not touch that '?' at the end of the line.
2662 // This permission check checks if the caller has the grant permission
2663 // for the given key and in addition to all of the permissions
2664 // expressed in `access_vector`.
2665 check_permission(&access_key_descriptor, &access_vector)
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002666 .context(ks_err!("check_permission failed"))?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002667
Janis Danisevskis66784c42021-01-27 08:40:25 -08002668 let grant_id = if let Some(grant_id) = tx
2669 .query_row(
2670 "SELECT id FROM persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002671 WHERE keyentryid = ? AND grantee = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08002672 params![key_id, grantee_uid],
2673 |row| row.get(0),
2674 )
2675 .optional()
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002676 .context(ks_err!("Failed get optional existing grant id."))?
Janis Danisevskis66784c42021-01-27 08:40:25 -08002677 {
2678 tx.execute(
2679 "UPDATE persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002680 SET access_vector = ?
2681 WHERE id = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08002682 params![i32::from(access_vector), grant_id],
Joel Galenson845f74b2020-09-09 14:11:55 -07002683 )
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002684 .context(ks_err!("Failed to update existing grant."))?;
Janis Danisevskis66784c42021-01-27 08:40:25 -08002685 grant_id
2686 } else {
2687 Self::insert_with_retry(|id| {
2688 tx.execute(
2689 "INSERT INTO persistent.grant (id, grantee, keyentryid, access_vector)
2690 VALUES (?, ?, ?, ?);",
2691 params![id, grantee_uid, key_id, i32::from(access_vector)],
2692 )
2693 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002694 .context(ks_err!())?
Janis Danisevskis66784c42021-01-27 08:40:25 -08002695 };
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002696
Janis Danisevskis66784c42021-01-27 08:40:25 -08002697 Ok(KeyDescriptor { domain: Domain::GRANT, nspace: grant_id, alias: None, blob: None })
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002698 .no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08002699 })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002700 }
2701
2702 /// This function checks permissions like `grant` and `load_key_entry`
2703 /// before removing a grant from the grant table.
2704 pub fn ungrant(
2705 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002706 key: &KeyDescriptor,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002707 caller_uid: u32,
2708 grantee_uid: u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002709 check_permission: impl Fn(&KeyDescriptor) -> Result<()>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002710 ) -> Result<()> {
David Drysdale541846b2024-05-23 13:16:07 +01002711 let _wp = wd::watch("KeystoreDB::ungrant");
Janis Danisevskis850d4862021-05-05 08:41:14 -07002712
David Drysdale7b9ca232024-05-23 18:19:46 +01002713 self.with_transaction(Immediate("TX_ungrant"), |tx| {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002714 // Load the key_id and complete the access control tuple.
2715 // We ignore the access vector here because grants cannot be granted.
2716 let (key_id, access_key_descriptor, _) =
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002717 Self::load_access_tuple(tx, key, KeyType::Client, caller_uid).context(ks_err!())?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002718
Janis Danisevskis66784c42021-01-27 08:40:25 -08002719 // Perform access control. We must return here if the permission
2720 // was denied. So do not touch the '?' at the end of this line.
2721 check_permission(&access_key_descriptor)
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002722 .context(ks_err!("check_permission failed."))?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002723
Janis Danisevskis66784c42021-01-27 08:40:25 -08002724 tx.execute(
2725 "DELETE FROM persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002726 WHERE keyentryid = ? AND grantee = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08002727 params![key_id, grantee_uid],
2728 )
2729 .context("Failed to delete grant.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002730
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002731 Ok(()).no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08002732 })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002733 }
2734
Joel Galenson845f74b2020-09-09 14:11:55 -07002735 // Generates a random id and passes it to the given function, which will
2736 // try to insert it into a database. If that insertion fails, retry;
2737 // otherwise return the id.
2738 fn insert_with_retry(inserter: impl Fn(i64) -> rusqlite::Result<usize>) -> Result<i64> {
2739 loop {
Janis Danisevskiseed69842021-02-18 20:04:10 -08002740 let newid: i64 = match random() {
2741 Self::UNASSIGNED_KEY_ID => continue, // UNASSIGNED_KEY_ID cannot be assigned.
2742 i => i,
2743 };
Joel Galenson845f74b2020-09-09 14:11:55 -07002744 match inserter(newid) {
2745 // If the id already existed, try again.
2746 Err(rusqlite::Error::SqliteFailure(
2747 libsqlite3_sys::Error {
2748 code: libsqlite3_sys::ErrorCode::ConstraintViolation,
2749 extended_code: libsqlite3_sys::SQLITE_CONSTRAINT_UNIQUE,
2750 },
2751 _,
2752 )) => (),
2753 Err(e) => {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002754 return Err(e).context(ks_err!("failed to insert into database."));
Joel Galenson845f74b2020-09-09 14:11:55 -07002755 }
2756 _ => return Ok(newid),
2757 }
2758 }
2759 }
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002760
Matthew Maurerd7815ca2021-05-06 21:58:45 -07002761 /// Insert or replace the auth token based on (user_id, auth_id, auth_type)
2762 pub fn insert_auth_token(&mut self, auth_token: &HardwareAuthToken) {
Eric Biggers19b3b0d2024-01-31 22:46:47 +00002763 self.perboot
2764 .insert_auth_token_entry(AuthTokenEntry::new(auth_token.clone(), BootTime::now()))
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002765 }
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002766
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002767 /// Find the newest auth token matching the given predicate.
Eric Biggersb5613da2024-03-13 19:31:42 +00002768 pub fn find_auth_token_entry<F>(&self, p: F) -> Option<AuthTokenEntry>
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002769 where
2770 F: Fn(&AuthTokenEntry) -> bool,
2771 {
Eric Biggersb5613da2024-03-13 19:31:42 +00002772 self.perboot.find_auth_token_entry(p)
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002773 }
Pavel Grafovf45034a2021-05-12 22:35:45 +01002774
2775 /// Load descriptor of a key by key id
2776 pub fn load_key_descriptor(&mut self, key_id: i64) -> Result<Option<KeyDescriptor>> {
David Drysdale541846b2024-05-23 13:16:07 +01002777 let _wp = wd::watch("KeystoreDB::load_key_descriptor");
Pavel Grafovf45034a2021-05-12 22:35:45 +01002778
2779 self.with_transaction(TransactionBehavior::Deferred, |tx| {
2780 tx.query_row(
2781 "SELECT domain, namespace, alias FROM persistent.keyentry WHERE id = ?;",
2782 params![key_id],
2783 |row| {
2784 Ok(KeyDescriptor {
2785 domain: Domain(row.get(0)?),
2786 nspace: row.get(1)?,
2787 alias: row.get(2)?,
2788 blob: None,
2789 })
2790 },
2791 )
2792 .optional()
2793 .context("Trying to load key descriptor")
2794 .no_gc()
2795 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002796 .context(ks_err!())
Pavel Grafovf45034a2021-05-12 22:35:45 +01002797 }
Eran Messeri4dc27b52024-01-09 12:43:31 +00002798
2799 /// Returns a list of app UIDs that have keys authenticated by the given secure_user_id
2800 /// (for the given user_id).
2801 /// This is helpful for finding out which apps will have their keys invalidated when
2802 /// the user changes biometrics enrollment or removes their LSKF.
2803 pub fn get_app_uids_affected_by_sid(
2804 &mut self,
2805 user_id: i32,
2806 secure_user_id: i64,
2807 ) -> Result<Vec<i64>> {
David Drysdale541846b2024-05-23 13:16:07 +01002808 let _wp = wd::watch("KeystoreDB::get_app_uids_affected_by_sid");
Eran Messeri4dc27b52024-01-09 12:43:31 +00002809
David Drysdale7b9ca232024-05-23 18:19:46 +01002810 let ids = self.with_transaction(Immediate("TX_get_app_uids_affected_by_sid"), |tx| {
Eran Messeri4dc27b52024-01-09 12:43:31 +00002811 let mut stmt = tx
2812 .prepare(&format!(
2813 "SELECT id, namespace from persistent.keyentry
2814 WHERE key_type = ?
2815 AND domain = ?
2816 AND cast ( (namespace/{AID_USER_OFFSET}) as int) = ?
2817 AND state = ?;",
2818 ))
2819 .context(concat!(
2820 "In get_app_uids_affected_by_sid, ",
2821 "failed to prepare the query to find the keys created by apps."
2822 ))?;
2823
2824 let mut rows = stmt
2825 .query(params![KeyType::Client, Domain::APP.0 as u32, user_id, KeyLifeCycle::Live,])
2826 .context(ks_err!("Failed to query the keys created by apps."))?;
2827
2828 let mut key_ids_and_app_uids: HashMap<i64, i64> = Default::default();
2829 db_utils::with_rows_extract_all(&mut rows, |row| {
2830 key_ids_and_app_uids.insert(
2831 row.get(0).context("Failed to read key id of a key created by an app.")?,
2832 row.get(1).context("Failed to read the app uid")?,
2833 );
2834 Ok(())
2835 })?;
2836 Ok(key_ids_and_app_uids).no_gc()
2837 })?;
2838 let mut app_uids_affected_by_sid: HashSet<i64> = Default::default();
David Drysdale7b9ca232024-05-23 18:19:46 +01002839 for (key_id, app_uid) in ids {
Eran Messeri4dc27b52024-01-09 12:43:31 +00002840 // Read the key parameters for each key in its own transaction. It is OK to ignore
2841 // an error to get the properties of a particular key since it might have been deleted
2842 // under our feet after the previous transaction concluded. If the key was deleted
2843 // then it is no longer applicable if it was auth-bound or not.
2844 if let Ok(is_key_bound_to_sid) =
David Drysdale7b9ca232024-05-23 18:19:46 +01002845 self.with_transaction(Immediate("TX_get_app_uids_affects_by_sid 2"), |tx| {
Eran Messeri4dc27b52024-01-09 12:43:31 +00002846 let params = Self::load_key_parameters(key_id, tx)
2847 .context("Failed to load key parameters.")?;
2848 // Check if the key is bound to this secure user ID.
2849 let is_key_bound_to_sid = params.iter().any(|kp| {
2850 matches!(
2851 kp.key_parameter_value(),
2852 KeyParameterValue::UserSecureID(sid) if *sid == secure_user_id
2853 )
2854 });
2855 Ok(is_key_bound_to_sid).no_gc()
2856 })
2857 {
2858 if is_key_bound_to_sid {
2859 app_uids_affected_by_sid.insert(app_uid);
2860 }
2861 }
2862 }
2863
2864 let app_uids_vec: Vec<i64> = app_uids_affected_by_sid.into_iter().collect();
2865 Ok(app_uids_vec)
2866 }
Joel Galenson26f4d012020-07-17 14:57:21 -07002867}