blob: 9ce6506bb6c00c67ec452f929b69738bb43374ec [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;
73use std::{convert::TryFrom, convert::TryInto, ops::Deref, time::SystemTimeError};
74use utils as db_utils;
75use utils::SqlField;
Max Bires2b2e6562020-09-22 11:22:36 -070076
77use keystore2_crypto::ZVec;
Janis Danisevskisaec14592020-11-12 09:41:49 -080078use lazy_static::lazy_static;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +000079use log::error;
Joel Galenson0891bc12020-07-20 10:37:03 -070080#[cfg(not(test))]
81use rand::prelude::random;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -070082use rusqlite::{
Joel Galensonff79e362021-05-25 16:30:17 -070083 params, params_from_iter,
Janis Danisevskisb42fc182020-12-15 08:41:27 -080084 types::FromSql,
85 types::FromSqlResult,
86 types::ToSqlOutput,
87 types::{FromSqlError, Value, ValueRef},
David Drysdale7b9ca232024-05-23 18:19:46 +010088 Connection, OptionalExtension, ToSql, Transaction,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -070089};
Max Bires2b2e6562020-09-22 11:22:36 -070090
Janis Danisevskisaec14592020-11-12 09:41:49 -080091use std::{
Janis Danisevskisb42fc182020-12-15 08:41:27 -080092 collections::{HashMap, HashSet},
Janis Danisevskisbf15d732020-12-08 10:35:26 -080093 path::Path,
Janis Danisevskis3395f862021-05-06 10:54:17 -070094 sync::{Arc, Condvar, Mutex},
Janis Danisevskisb42fc182020-12-15 08:41:27 -080095 time::{Duration, SystemTime},
Janis Danisevskisaec14592020-11-12 09:41:49 -080096};
Max Bires2b2e6562020-09-22 11:22:36 -070097
David Drysdale7b9ca232024-05-23 18:19:46 +010098use TransactionBehavior::Immediate;
99
Joel Galenson0891bc12020-07-20 10:37:03 -0700100#[cfg(test)]
101use tests::random;
Joel Galenson26f4d012020-07-17 14:57:21 -0700102
David Drysdale7b9ca232024-05-23 18:19:46 +0100103/// Wrapper for `rusqlite::TransactionBehavior` which includes information about the transaction
104/// being performed.
105#[derive(Clone, Copy)]
106enum TransactionBehavior {
107 Deferred,
108 Immediate(&'static str),
109}
110
111impl From<TransactionBehavior> for rusqlite::TransactionBehavior {
112 fn from(val: TransactionBehavior) -> Self {
113 match val {
114 TransactionBehavior::Deferred => rusqlite::TransactionBehavior::Deferred,
115 TransactionBehavior::Immediate(_) => rusqlite::TransactionBehavior::Immediate,
116 }
117 }
118}
119
120impl TransactionBehavior {
121 fn name(&self) -> Option<&'static str> {
122 match self {
123 TransactionBehavior::Deferred => None,
124 TransactionBehavior::Immediate(v) => Some(v),
125 }
126 }
127}
128
David Drysdale115c4722024-04-15 14:11:52 +0100129/// If the database returns a busy error code, retry after this interval.
130const DB_BUSY_RETRY_INTERVAL: Duration = Duration::from_micros(500);
David Drysdale115c4722024-04-15 14:11:52 +0100131
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800132impl_metadata!(
133 /// A set of metadata for key entries.
134 #[derive(Debug, Default, Eq, PartialEq)]
135 pub struct KeyMetaData;
136 /// A metadata entry for key entries.
137 #[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
138 pub enum KeyMetaEntry {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800139 /// Date of the creation of the key entry.
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800140 CreationDate(DateTime) with accessor creation_date,
141 /// Expiration date for attestation keys.
142 AttestationExpirationDate(DateTime) with accessor attestation_expiration_date,
Max Bires2b2e6562020-09-22 11:22:36 -0700143 /// CBOR Blob that represents a COSE_Key and associated metadata needed for remote
144 /// provisioning
145 AttestationMacedPublicKey(Vec<u8>) with accessor attestation_maced_public_key,
146 /// Vector representing the raw public key so results from the server can be matched
147 /// to the right entry
148 AttestationRawPubKey(Vec<u8>) with accessor attestation_raw_pub_key,
Paul Crowley8d5b2532021-03-19 10:53:07 -0700149 /// SEC1 public key for ECDH encryption
150 Sec1PublicKey(Vec<u8>) with accessor sec1_public_key,
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800151 // --- ADD NEW META DATA FIELDS HERE ---
152 // For backwards compatibility add new entries only to
153 // end of this list and above this comment.
154 };
155);
156
157impl KeyMetaData {
158 fn load_from_db(key_id: i64, tx: &Transaction) -> Result<Self> {
159 let mut stmt = tx
160 .prepare(
161 "SELECT tag, data from persistent.keymetadata
162 WHERE keyentryid = ?;",
163 )
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000164 .context(ks_err!("KeyMetaData::load_from_db: prepare statement failed."))?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800165
166 let mut metadata: HashMap<i64, KeyMetaEntry> = Default::default();
167
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000168 let mut rows = stmt
169 .query(params![key_id])
170 .context(ks_err!("KeyMetaData::load_from_db: query failed."))?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800171 db_utils::with_rows_extract_all(&mut rows, |row| {
172 let db_tag: i64 = row.get(0).context("Failed to read tag.")?;
173 metadata.insert(
174 db_tag,
Chris Wailesd5aaaef2021-07-27 16:04:33 -0700175 KeyMetaEntry::new_from_sql(db_tag, &SqlField::new(1, row))
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800176 .context("Failed to read KeyMetaEntry.")?,
177 );
178 Ok(())
179 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000180 .context(ks_err!("KeyMetaData::load_from_db."))?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800181
182 Ok(Self { data: metadata })
183 }
184
185 fn store_in_db(&self, key_id: i64, tx: &Transaction) -> Result<()> {
186 let mut stmt = tx
187 .prepare(
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000188 "INSERT or REPLACE INTO persistent.keymetadata (keyentryid, tag, data)
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800189 VALUES (?, ?, ?);",
190 )
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000191 .context(ks_err!("KeyMetaData::store_in_db: Failed to prepare statement."))?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800192
193 let iter = self.data.iter();
194 for (tag, entry) in iter {
195 stmt.insert(params![key_id, tag, entry,]).with_context(|| {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000196 ks_err!("KeyMetaData::store_in_db: Failed to insert {:?}", entry)
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800197 })?;
198 }
199 Ok(())
200 }
201}
202
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800203impl_metadata!(
204 /// A set of metadata for key blobs.
205 #[derive(Debug, Default, Eq, PartialEq)]
206 pub struct BlobMetaData;
207 /// A metadata entry for key blobs.
208 #[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
209 pub enum BlobMetaEntry {
210 /// If present, indicates that the blob is encrypted with another key or a key derived
211 /// from a password.
212 EncryptedBy(EncryptedBy) with accessor encrypted_by,
213 /// If the blob is password encrypted this field is set to the
214 /// salt used for the key derivation.
215 Salt(Vec<u8>) with accessor salt,
216 /// If the blob is encrypted, this field is set to the initialization vector.
217 Iv(Vec<u8>) with accessor iv,
218 /// If the blob is encrypted, this field holds the AEAD TAG.
219 AeadTag(Vec<u8>) with accessor aead_tag,
220 /// The uuid of the owning KeyMint instance.
221 KmUuid(Uuid) with accessor km_uuid,
Paul Crowley8d5b2532021-03-19 10:53:07 -0700222 /// If the key is ECDH encrypted, this is the ephemeral public key
223 PublicKey(Vec<u8>) with accessor public_key,
Paul Crowley44c02da2021-04-08 17:04:43 +0000224 /// If the key is encrypted with a MaxBootLevel key, this is the boot level
225 /// of that key
226 MaxBootLevel(i32) with accessor max_boot_level,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800227 // --- ADD NEW META DATA FIELDS HERE ---
228 // For backwards compatibility add new entries only to
229 // end of this list and above this comment.
230 };
231);
232
233impl BlobMetaData {
234 fn load_from_db(blob_id: i64, tx: &Transaction) -> Result<Self> {
235 let mut stmt = tx
236 .prepare(
237 "SELECT tag, data from persistent.blobmetadata
238 WHERE blobentryid = ?;",
239 )
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000240 .context(ks_err!("BlobMetaData::load_from_db: prepare statement failed."))?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800241
242 let mut metadata: HashMap<i64, BlobMetaEntry> = Default::default();
243
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000244 let mut rows = stmt.query(params![blob_id]).context(ks_err!("query failed."))?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800245 db_utils::with_rows_extract_all(&mut rows, |row| {
246 let db_tag: i64 = row.get(0).context("Failed to read tag.")?;
247 metadata.insert(
248 db_tag,
Chris Wailesd5aaaef2021-07-27 16:04:33 -0700249 BlobMetaEntry::new_from_sql(db_tag, &SqlField::new(1, row))
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800250 .context("Failed to read BlobMetaEntry.")?,
251 );
252 Ok(())
253 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000254 .context(ks_err!("BlobMetaData::load_from_db"))?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800255
256 Ok(Self { data: metadata })
257 }
258
259 fn store_in_db(&self, blob_id: i64, tx: &Transaction) -> Result<()> {
260 let mut stmt = tx
261 .prepare(
262 "INSERT or REPLACE INTO persistent.blobmetadata (blobentryid, tag, data)
263 VALUES (?, ?, ?);",
264 )
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000265 .context(ks_err!("BlobMetaData::store_in_db: Failed to prepare statement.",))?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800266
267 let iter = self.data.iter();
268 for (tag, entry) in iter {
269 stmt.insert(params![blob_id, tag, entry,]).with_context(|| {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000270 ks_err!("BlobMetaData::store_in_db: Failed to insert {:?}", entry)
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800271 })?;
272 }
273 Ok(())
274 }
275}
276
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800277/// Indicates the type of the keyentry.
278#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
279pub enum KeyType {
280 /// This is a client key type. These keys are created or imported through the Keystore 2.0
281 /// AIDL interface android.system.keystore2.
282 Client,
283 /// This is a super key type. These keys are created by keystore itself and used to encrypt
284 /// other key blobs to provide LSKF binding.
285 Super,
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800286}
287
288impl ToSql for KeyType {
289 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
290 Ok(ToSqlOutput::Owned(Value::Integer(match self {
291 KeyType::Client => 0,
292 KeyType::Super => 1,
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800293 })))
294 }
295}
296
297impl FromSql for KeyType {
298 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
299 match i64::column_result(value)? {
300 0 => Ok(KeyType::Client),
301 1 => Ok(KeyType::Super),
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800302 v => Err(FromSqlError::OutOfRange(v)),
303 }
304 }
305}
306
Max Bires8e93d2b2021-01-14 13:17:59 -0800307/// Uuid representation that can be stored in the database.
308/// Right now it can only be initialized from SecurityLevel.
309/// Once KeyMint provides a UUID type a corresponding From impl shall be added.
310#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
311pub struct Uuid([u8; 16]);
312
313impl Deref for Uuid {
314 type Target = [u8; 16];
315
316 fn deref(&self) -> &Self::Target {
317 &self.0
318 }
319}
320
321impl From<SecurityLevel> for Uuid {
322 fn from(sec_level: SecurityLevel) -> Self {
323 Self((sec_level.0 as u128).to_be_bytes())
324 }
325}
326
327impl ToSql for Uuid {
328 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
329 self.0.to_sql()
330 }
331}
332
333impl FromSql for Uuid {
334 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
335 let blob = Vec::<u8>::column_result(value)?;
336 if blob.len() != 16 {
337 return Err(FromSqlError::OutOfRange(blob.len() as i64));
338 }
339 let mut arr = [0u8; 16];
340 arr.copy_from_slice(&blob);
341 Ok(Self(arr))
342 }
343}
344
345/// Key entries that are not associated with any KeyMint instance, such as pure certificate
346/// entries are associated with this UUID.
347pub static KEYSTORE_UUID: Uuid = Uuid([
348 0x41, 0xe3, 0xb9, 0xce, 0x27, 0x58, 0x4e, 0x91, 0xbc, 0xfd, 0xa5, 0x5d, 0x91, 0x85, 0xab, 0x11,
349]);
350
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800351/// Indicates how the sensitive part of this key blob is encrypted.
352#[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
353pub enum EncryptedBy {
354 /// The keyblob is encrypted by a user password.
355 /// In the database this variant is represented as NULL.
356 Password,
357 /// The keyblob is encrypted by another key with wrapped key id.
358 /// In the database this variant is represented as non NULL value
359 /// that is convertible to i64, typically NUMERIC.
360 KeyId(i64),
361}
362
363impl ToSql for EncryptedBy {
364 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
365 match self {
366 Self::Password => Ok(ToSqlOutput::Owned(Value::Null)),
367 Self::KeyId(id) => id.to_sql(),
368 }
369 }
370}
371
372impl FromSql for EncryptedBy {
373 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
374 match value {
375 ValueRef::Null => Ok(Self::Password),
376 _ => Ok(Self::KeyId(i64::column_result(value)?)),
377 }
378 }
379}
380
381/// A database representation of wall clock time. DateTime stores unix epoch time as
382/// i64 in milliseconds.
383#[derive(Debug, Copy, Clone, Default, Eq, PartialEq, Ord, PartialOrd)]
384pub struct DateTime(i64);
385
386/// Error type returned when creating DateTime or converting it from and to
387/// SystemTime.
388#[derive(thiserror::Error, Debug)]
389pub enum DateTimeError {
390 /// This is returned when SystemTime and Duration computations fail.
391 #[error(transparent)]
392 SystemTimeError(#[from] SystemTimeError),
393
394 /// This is returned when type conversions fail.
395 #[error(transparent)]
396 TypeConversion(#[from] std::num::TryFromIntError),
397
398 /// This is returned when checked time arithmetic failed.
399 #[error("Time arithmetic failed.")]
400 TimeArithmetic,
401}
402
403impl DateTime {
404 /// Constructs a new DateTime object denoting the current time. This may fail during
405 /// conversion to unix epoch time and during conversion to the internal i64 representation.
406 pub fn now() -> Result<Self, DateTimeError> {
407 Ok(Self(SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_millis().try_into()?))
408 }
409
410 /// Constructs a new DateTime object from milliseconds.
411 pub fn from_millis_epoch(millis: i64) -> Self {
412 Self(millis)
413 }
414
415 /// Returns unix epoch time in milliseconds.
Chris Wailes3877f292021-07-26 19:24:18 -0700416 pub fn to_millis_epoch(self) -> i64 {
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800417 self.0
418 }
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800419}
420
421impl ToSql for DateTime {
422 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
423 Ok(ToSqlOutput::Owned(Value::Integer(self.0)))
424 }
425}
426
427impl FromSql for DateTime {
428 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
429 Ok(Self(i64::column_result(value)?))
430 }
431}
432
433impl TryInto<SystemTime> for DateTime {
434 type Error = DateTimeError;
435
436 fn try_into(self) -> Result<SystemTime, Self::Error> {
437 // We want to construct a SystemTime representation equivalent to self, denoting
438 // a point in time THEN, but we cannot set the time directly. We can only construct
439 // a SystemTime denoting NOW, and we can get the duration between EPOCH and NOW,
440 // and between EPOCH and THEN. With this common reference we can construct the
441 // duration between NOW and THEN which we can add to our SystemTime representation
442 // of NOW to get a SystemTime representation of THEN.
443 // Durations can only be positive, thus the if statement below.
444 let now = SystemTime::now();
445 let now_epoch = now.duration_since(SystemTime::UNIX_EPOCH)?;
446 let then_epoch = Duration::from_millis(self.0.try_into()?);
447 Ok(if now_epoch > then_epoch {
448 // then = now - (now_epoch - then_epoch)
449 now_epoch
450 .checked_sub(then_epoch)
451 .and_then(|d| now.checked_sub(d))
452 .ok_or(DateTimeError::TimeArithmetic)?
453 } else {
454 // then = now + (then_epoch - now_epoch)
455 then_epoch
456 .checked_sub(now_epoch)
457 .and_then(|d| now.checked_add(d))
458 .ok_or(DateTimeError::TimeArithmetic)?
459 })
460 }
461}
462
463impl TryFrom<SystemTime> for DateTime {
464 type Error = DateTimeError;
465
466 fn try_from(t: SystemTime) -> Result<Self, Self::Error> {
467 Ok(Self(t.duration_since(SystemTime::UNIX_EPOCH)?.as_millis().try_into()?))
468 }
469}
470
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800471#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone)]
472enum KeyLifeCycle {
473 /// Existing keys have a key ID but are not fully populated yet.
474 /// This is a transient state. If Keystore finds any such keys when it starts up, it must move
475 /// them to Unreferenced for garbage collection.
476 Existing,
477 /// A live key is fully populated and usable by clients.
478 Live,
479 /// An unreferenced key is scheduled for garbage collection.
480 Unreferenced,
481}
482
483impl ToSql for KeyLifeCycle {
484 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
485 match self {
486 Self::Existing => Ok(ToSqlOutput::Owned(Value::Integer(0))),
487 Self::Live => Ok(ToSqlOutput::Owned(Value::Integer(1))),
488 Self::Unreferenced => Ok(ToSqlOutput::Owned(Value::Integer(2))),
489 }
490 }
491}
492
493impl FromSql for KeyLifeCycle {
494 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
495 match i64::column_result(value)? {
496 0 => Ok(KeyLifeCycle::Existing),
497 1 => Ok(KeyLifeCycle::Live),
498 2 => Ok(KeyLifeCycle::Unreferenced),
499 v => Err(FromSqlError::OutOfRange(v)),
500 }
501 }
502}
503
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700504/// Keys have a KeyMint blob component and optional public certificate and
505/// certificate chain components.
506/// KeyEntryLoadBits is a bitmap that indicates to `KeystoreDB::load_key_entry`
507/// which components shall be loaded from the database if present.
Janis Danisevskis66784c42021-01-27 08:40:25 -0800508#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700509pub struct KeyEntryLoadBits(u32);
510
511impl KeyEntryLoadBits {
512 /// Indicate to `KeystoreDB::load_key_entry` that no component shall be loaded.
513 pub const NONE: KeyEntryLoadBits = Self(0);
514 /// Indicate to `KeystoreDB::load_key_entry` that the KeyMint component shall be loaded.
515 pub const KM: KeyEntryLoadBits = Self(1);
516 /// Indicate to `KeystoreDB::load_key_entry` that the Public components shall be loaded.
517 pub const PUBLIC: KeyEntryLoadBits = Self(2);
518 /// Indicate to `KeystoreDB::load_key_entry` that both components shall be loaded.
519 pub const BOTH: KeyEntryLoadBits = Self(3);
520
521 /// Returns true if this object indicates that the public components shall be loaded.
522 pub const fn load_public(&self) -> bool {
523 self.0 & Self::PUBLIC.0 != 0
524 }
525
526 /// Returns true if the object indicates that the KeyMint component shall be loaded.
527 pub const fn load_km(&self) -> bool {
528 self.0 & Self::KM.0 != 0
529 }
530}
531
Janis Danisevskisaec14592020-11-12 09:41:49 -0800532lazy_static! {
533 static ref KEY_ID_LOCK: KeyIdLockDb = KeyIdLockDb::new();
534}
535
536struct KeyIdLockDb {
537 locked_keys: Mutex<HashSet<i64>>,
538 cond_var: Condvar,
539}
540
541/// A locked key. While a guard exists for a given key id, the same key cannot be loaded
542/// from the database a second time. Most functions manipulating the key blob database
543/// require a KeyIdGuard.
544#[derive(Debug)]
545pub struct KeyIdGuard(i64);
546
547impl KeyIdLockDb {
548 fn new() -> Self {
549 Self { locked_keys: Mutex::new(HashSet::new()), cond_var: Condvar::new() }
550 }
551
552 /// This function blocks until an exclusive lock for the given key entry id can
553 /// be acquired. It returns a guard object, that represents the lifecycle of the
554 /// acquired lock.
David Drysdale8c4c4f32023-10-31 12:14:11 +0000555 fn get(&self, key_id: i64) -> KeyIdGuard {
Janis Danisevskisaec14592020-11-12 09:41:49 -0800556 let mut locked_keys = self.locked_keys.lock().unwrap();
557 while locked_keys.contains(&key_id) {
558 locked_keys = self.cond_var.wait(locked_keys).unwrap();
559 }
560 locked_keys.insert(key_id);
561 KeyIdGuard(key_id)
562 }
563
564 /// This function attempts to acquire an exclusive lock on a given key id. If the
565 /// given key id is already taken the function returns None immediately. If a lock
566 /// can be acquired this function returns a guard object, that represents the
567 /// lifecycle of the acquired lock.
David Drysdale8c4c4f32023-10-31 12:14:11 +0000568 fn try_get(&self, key_id: i64) -> Option<KeyIdGuard> {
Janis Danisevskisaec14592020-11-12 09:41:49 -0800569 let mut locked_keys = self.locked_keys.lock().unwrap();
570 if locked_keys.insert(key_id) {
571 Some(KeyIdGuard(key_id))
572 } else {
573 None
574 }
575 }
576}
577
578impl KeyIdGuard {
579 /// Get the numeric key id of the locked key.
580 pub fn id(&self) -> i64 {
581 self.0
582 }
583}
584
585impl Drop for KeyIdGuard {
586 fn drop(&mut self) {
587 let mut locked_keys = KEY_ID_LOCK.locked_keys.lock().unwrap();
588 locked_keys.remove(&self.0);
Janis Danisevskis7fd53582020-11-23 13:40:34 -0800589 drop(locked_keys);
Janis Danisevskisaec14592020-11-12 09:41:49 -0800590 KEY_ID_LOCK.cond_var.notify_all();
591 }
592}
593
Max Bires8e93d2b2021-01-14 13:17:59 -0800594/// This type represents a certificate and certificate chain entry for a key.
Max Bires2b2e6562020-09-22 11:22:36 -0700595#[derive(Debug, Default)]
Max Bires8e93d2b2021-01-14 13:17:59 -0800596pub struct CertificateInfo {
597 cert: Option<Vec<u8>>,
598 cert_chain: Option<Vec<u8>>,
599}
600
Janis Danisevskisf84d0b02022-01-26 14:11:14 -0800601/// This type represents a Blob with its metadata and an optional superseded blob.
602#[derive(Debug)]
603pub struct BlobInfo<'a> {
604 blob: &'a [u8],
605 metadata: &'a BlobMetaData,
606 /// Superseded blobs are an artifact of legacy import. In some rare occasions
607 /// the key blob needs to be upgraded during import. In that case two
608 /// blob are imported, the superseded one will have to be imported first,
609 /// so that the garbage collector can reap it.
610 superseded_blob: Option<(&'a [u8], &'a BlobMetaData)>,
611}
612
613impl<'a> BlobInfo<'a> {
614 /// Create a new instance of blob info with blob and corresponding metadata
615 /// and no superseded blob info.
616 pub fn new(blob: &'a [u8], metadata: &'a BlobMetaData) -> Self {
617 Self { blob, metadata, superseded_blob: None }
618 }
619
620 /// Create a new instance of blob info with blob and corresponding metadata
621 /// as well as superseded blob info.
622 pub fn new_with_superseded(
623 blob: &'a [u8],
624 metadata: &'a BlobMetaData,
625 superseded_blob: Option<(&'a [u8], &'a BlobMetaData)>,
626 ) -> Self {
627 Self { blob, metadata, superseded_blob }
628 }
629}
630
Max Bires8e93d2b2021-01-14 13:17:59 -0800631impl CertificateInfo {
632 /// Constructs a new CertificateInfo object from `cert` and `cert_chain`
633 pub fn new(cert: Option<Vec<u8>>, cert_chain: Option<Vec<u8>>) -> Self {
634 Self { cert, cert_chain }
635 }
636
637 /// Take the cert
638 pub fn take_cert(&mut self) -> Option<Vec<u8>> {
639 self.cert.take()
640 }
641
642 /// Take the cert chain
643 pub fn take_cert_chain(&mut self) -> Option<Vec<u8>> {
644 self.cert_chain.take()
645 }
646}
647
Max Bires2b2e6562020-09-22 11:22:36 -0700648/// This type represents a certificate chain with a private key corresponding to the leaf
649/// 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 -0700650pub struct CertificateChain {
Max Bires97f96812021-02-23 23:44:57 -0800651 /// A KM key blob
652 pub private_key: ZVec,
653 /// A batch cert for private_key
654 pub batch_cert: Vec<u8>,
655 /// A full certificate chain from root signing authority to private_key, including batch_cert
656 /// for convenience.
657 pub cert_chain: Vec<u8>,
Max Bires2b2e6562020-09-22 11:22:36 -0700658}
659
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700660/// This type represents a Keystore 2.0 key entry.
661/// An entry has a unique `id` by which it can be found in the database.
662/// It has a security level field, key parameters, and three optional fields
663/// for the KeyMint blob, public certificate and a public certificate chain.
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800664#[derive(Debug, Default, Eq, PartialEq)]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700665pub struct KeyEntry {
666 id: i64,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800667 key_blob_info: Option<(Vec<u8>, BlobMetaData)>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700668 cert: Option<Vec<u8>>,
669 cert_chain: Option<Vec<u8>>,
Max Bires8e93d2b2021-01-14 13:17:59 -0800670 km_uuid: Uuid,
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700671 parameters: Vec<KeyParameter>,
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800672 metadata: KeyMetaData,
Janis Danisevskis377d1002021-01-27 19:07:48 -0800673 pure_cert: bool,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700674}
675
676impl KeyEntry {
677 /// Returns the unique id of the Key entry.
678 pub fn id(&self) -> i64 {
679 self.id
680 }
681 /// Exposes the optional KeyMint blob.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800682 pub fn key_blob_info(&self) -> &Option<(Vec<u8>, BlobMetaData)> {
683 &self.key_blob_info
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700684 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800685 /// Extracts the Optional KeyMint blob including its metadata.
686 pub fn take_key_blob_info(&mut self) -> Option<(Vec<u8>, BlobMetaData)> {
687 self.key_blob_info.take()
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700688 }
689 /// Exposes the optional public certificate.
690 pub fn cert(&self) -> &Option<Vec<u8>> {
691 &self.cert
692 }
693 /// Extracts the optional public certificate.
694 pub fn take_cert(&mut self) -> Option<Vec<u8>> {
695 self.cert.take()
696 }
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700697 /// Extracts the optional public certificate_chain.
698 pub fn take_cert_chain(&mut self) -> Option<Vec<u8>> {
699 self.cert_chain.take()
700 }
Max Bires8e93d2b2021-01-14 13:17:59 -0800701 /// Returns the uuid of the owning KeyMint instance.
702 pub fn km_uuid(&self) -> &Uuid {
703 &self.km_uuid
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700704 }
Janis Danisevskis04b02832020-10-26 09:21:40 -0700705 /// Consumes this key entry and extracts the keyparameters from it.
706 pub fn into_key_parameters(self) -> Vec<KeyParameter> {
707 self.parameters
708 }
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800709 /// Exposes the key metadata of this key entry.
710 pub fn metadata(&self) -> &KeyMetaData {
711 &self.metadata
712 }
Janis Danisevskis377d1002021-01-27 19:07:48 -0800713 /// This returns true if the entry is a pure certificate entry with no
714 /// private key component.
715 pub fn pure_cert(&self) -> bool {
716 self.pure_cert
717 }
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700718}
719
720/// Indicates the sub component of a key entry for persistent storage.
Janis Danisevskis377d1002021-01-27 19:07:48 -0800721#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700722pub struct SubComponentType(u32);
723impl SubComponentType {
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800724 /// Persistent identifier for a key blob.
725 pub const KEY_BLOB: SubComponentType = Self(0);
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700726 /// Persistent identifier for a certificate blob.
727 pub const CERT: SubComponentType = Self(1);
728 /// Persistent identifier for a certificate chain blob.
729 pub const CERT_CHAIN: SubComponentType = Self(2);
730}
731
732impl ToSql for SubComponentType {
733 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
734 self.0.to_sql()
735 }
736}
737
738impl FromSql for SubComponentType {
739 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
740 Ok(Self(u32::column_result(value)?))
741 }
742}
743
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800744/// This trait is private to the database module. It is used to convey whether or not the garbage
745/// collector shall be invoked after a database access. All closures passed to
746/// `KeystoreDB::with_transaction` return a tuple (bool, T) where the bool indicates if the
747/// gc needs to be triggered. This convenience function allows to turn any anyhow::Result<T>
748/// into anyhow::Result<(bool, T)> by simply appending one of `.do_gc(bool)`, `.no_gc()`, or
749/// `.need_gc()`.
750trait DoGc<T> {
751 fn do_gc(self, need_gc: bool) -> Result<(bool, T)>;
752
753 fn no_gc(self) -> Result<(bool, T)>;
754
755 fn need_gc(self) -> Result<(bool, T)>;
756}
757
758impl<T> DoGc<T> for Result<T> {
759 fn do_gc(self, need_gc: bool) -> Result<(bool, T)> {
760 self.map(|r| (need_gc, r))
761 }
762
763 fn no_gc(self) -> Result<(bool, T)> {
764 self.do_gc(false)
765 }
766
767 fn need_gc(self) -> Result<(bool, T)> {
768 self.do_gc(true)
769 }
770}
771
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700772/// KeystoreDB wraps a connection to an SQLite database and tracks its
773/// ownership. It also implements all of Keystore 2.0's database functionality.
Joel Galenson26f4d012020-07-17 14:57:21 -0700774pub struct KeystoreDB {
Joel Galenson26f4d012020-07-17 14:57:21 -0700775 conn: Connection,
Janis Danisevskis3395f862021-05-06 10:54:17 -0700776 gc: Option<Arc<Gc>>,
Matthew Maurerd7815ca2021-05-06 21:58:45 -0700777 perboot: Arc<perboot::PerbootDB>,
Joel Galenson26f4d012020-07-17 14:57:21 -0700778}
779
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000780/// Database representation of the monotonic time retrieved from the system call clock_gettime with
Eric Biggers19b3b0d2024-01-31 22:46:47 +0000781/// CLOCK_BOOTTIME. Stores monotonic time as i64 in milliseconds.
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000782#[derive(Debug, Copy, Clone, Default, Eq, PartialEq, Ord, PartialOrd)]
Eric Biggers19b3b0d2024-01-31 22:46:47 +0000783pub struct BootTime(i64);
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000784
Eric Biggers19b3b0d2024-01-31 22:46:47 +0000785impl BootTime {
786 /// Constructs a new BootTime
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000787 pub fn now() -> Self {
Hasini Gunasinghe66a24602021-05-12 19:03:12 +0000788 Self(get_current_time_in_milliseconds())
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000789 }
790
Eric Biggers19b3b0d2024-01-31 22:46:47 +0000791 /// Returns the value of BootTime in milliseconds as i64
Hasini Gunasinghe66a24602021-05-12 19:03:12 +0000792 pub fn milliseconds(&self) -> i64 {
793 self.0
David Drysdale0e45a612021-02-25 17:24:36 +0000794 }
795
Eric Biggers19b3b0d2024-01-31 22:46:47 +0000796 /// Returns the integer value of BootTime as i64
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000797 pub fn seconds(&self) -> i64 {
Hasini Gunasinghe66a24602021-05-12 19:03:12 +0000798 self.0 / 1000
Hasini Gunasingheb3715fb2021-02-26 20:34:45 +0000799 }
800
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800801 /// Like i64::checked_sub.
802 pub fn checked_sub(&self, other: &Self) -> Option<Self> {
803 self.0.checked_sub(other.0).map(Self)
804 }
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000805}
806
Eric Biggers19b3b0d2024-01-31 22:46:47 +0000807impl ToSql for BootTime {
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000808 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
809 Ok(ToSqlOutput::Owned(Value::Integer(self.0)))
810 }
811}
812
Eric Biggers19b3b0d2024-01-31 22:46:47 +0000813impl FromSql for BootTime {
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000814 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
815 Ok(Self(i64::column_result(value)?))
816 }
817}
818
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000819/// This struct encapsulates the information to be stored in the database about the auth tokens
820/// received by keystore.
Matthew Maurerd7815ca2021-05-06 21:58:45 -0700821#[derive(Clone)]
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000822pub struct AuthTokenEntry {
823 auth_token: HardwareAuthToken,
Hasini Gunasinghe66a24602021-05-12 19:03:12 +0000824 // Time received in milliseconds
Eric Biggers19b3b0d2024-01-31 22:46:47 +0000825 time_received: BootTime,
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000826}
827
828impl AuthTokenEntry {
Eric Biggers19b3b0d2024-01-31 22:46:47 +0000829 fn new(auth_token: HardwareAuthToken, time_received: BootTime) -> Self {
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000830 AuthTokenEntry { auth_token, time_received }
831 }
832
833 /// Checks if this auth token satisfies the given authentication information.
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800834 pub fn satisfies(&self, user_secure_ids: &[i64], auth_type: HardwareAuthenticatorType) -> bool {
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000835 user_secure_ids.iter().any(|&sid| {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800836 (sid == self.auth_token.userId || sid == self.auth_token.authenticatorId)
Charisee03e00842023-01-25 01:41:23 +0000837 && ((auth_type.0 & self.auth_token.authenticatorType.0) != 0)
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000838 })
839 }
840
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000841 /// Returns the auth token wrapped by the AuthTokenEntry
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800842 pub fn auth_token(&self) -> &HardwareAuthToken {
843 &self.auth_token
844 }
845
846 /// Returns the auth token wrapped by the AuthTokenEntry
847 pub fn take_auth_token(self) -> HardwareAuthToken {
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000848 self.auth_token
849 }
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800850
851 /// Returns the time that this auth token was received.
Eric Biggers19b3b0d2024-01-31 22:46:47 +0000852 pub fn time_received(&self) -> BootTime {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800853 self.time_received
854 }
Hasini Gunasingheb3715fb2021-02-26 20:34:45 +0000855
856 /// Returns the challenge value of the auth token.
857 pub fn challenge(&self) -> i64 {
858 self.auth_token.challenge
859 }
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000860}
861
David Drysdalef1ba3812024-05-08 17:50:13 +0100862/// Information about a superseded blob (a blob that is no longer the
863/// most recent blob of that type for a given key, due to upgrade or
864/// replacement).
865pub struct SupersededBlob {
866 /// ID
867 pub blob_id: i64,
868 /// Contents.
869 pub blob: Vec<u8>,
870 /// Metadata.
871 pub metadata: BlobMetaData,
872}
873
Joel Galenson26f4d012020-07-17 14:57:21 -0700874impl KeystoreDB {
Janis Danisevskiseed69842021-02-18 20:04:10 -0800875 const UNASSIGNED_KEY_ID: i64 = -1i64;
Janis Danisevskiscfaf9192021-05-26 16:31:02 -0700876 const CURRENT_DB_VERSION: u32 = 1;
877 const UPGRADERS: &'static [fn(&Transaction) -> Result<u32>] = &[Self::from_0_to_1];
Janis Danisevskisb00ebd02021-02-02 21:52:24 -0800878
Seth Moore78c091f2021-04-09 21:38:30 +0000879 /// Name of the file that holds the cross-boot persistent database.
Chris Wailesd5aaaef2021-07-27 16:04:33 -0700880 pub const PERSISTENT_DB_FILENAME: &'static str = "persistent.sqlite";
Seth Moore78c091f2021-04-09 21:38:30 +0000881
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700882 /// This will create a new database connection connecting the two
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800883 /// files persistent.sqlite and perboot.sqlite in the given directory.
884 /// It also attempts to initialize all of the tables.
885 /// KeystoreDB cannot be used by multiple threads.
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700886 /// Each thread should open their own connection using `thread_local!`.
Janis Danisevskis3395f862021-05-06 10:54:17 -0700887 pub fn new(db_root: &Path, gc: Option<Arc<Gc>>) -> Result<Self> {
David Drysdale541846b2024-05-23 13:16:07 +0100888 let _wp = wd::watch("KeystoreDB::new");
Janis Danisevskis850d4862021-05-05 08:41:14 -0700889
Chris Wailesd5aaaef2021-07-27 16:04:33 -0700890 let persistent_path = Self::make_persistent_path(db_root)?;
Seth Moore472fcbb2021-05-12 10:07:51 -0700891 let conn = Self::make_connection(&persistent_path)?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800892
Matthew Maurerd7815ca2021-05-06 21:58:45 -0700893 let mut db = Self { conn, gc, perboot: perboot::PERBOOT_DB.clone() };
David Drysdale7b9ca232024-05-23 18:19:46 +0100894 db.with_transaction(Immediate("TX_new"), |tx| {
Janis Danisevskiscfaf9192021-05-26 16:31:02 -0700895 versioning::upgrade_database(tx, Self::CURRENT_DB_VERSION, Self::UPGRADERS)
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000896 .context(ks_err!("KeystoreDB::new: trying to upgrade database."))?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800897 Self::init_tables(tx).context("Trying to initialize tables.").no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -0800898 })?;
899 Ok(db)
Joel Galenson2aab4432020-07-22 15:27:57 -0700900 }
901
Janis Danisevskiscfaf9192021-05-26 16:31:02 -0700902 // This upgrade function deletes all MAX_BOOT_LEVEL keys, that were generated before
903 // cryptographic binding to the boot level keys was implemented.
904 fn from_0_to_1(tx: &Transaction) -> Result<u32> {
905 tx.execute(
906 "UPDATE persistent.keyentry SET state = ?
907 WHERE
908 id IN (SELECT keyentryid FROM persistent.keyparameter WHERE tag = ?)
909 AND
910 id NOT IN (
911 SELECT keyentryid FROM persistent.blobentry
912 WHERE id IN (
913 SELECT blobentryid FROM persistent.blobmetadata WHERE tag = ?
914 )
915 );",
916 params![KeyLifeCycle::Unreferenced, Tag::MAX_BOOT_LEVEL.0, BlobMetaData::MaxBootLevel],
917 )
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000918 .context(ks_err!("Failed to delete logical boot level keys."))?;
Janis Danisevskiscfaf9192021-05-26 16:31:02 -0700919 Ok(1)
920 }
921
Janis Danisevskis66784c42021-01-27 08:40:25 -0800922 fn init_tables(tx: &Transaction) -> Result<()> {
923 tx.execute(
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700924 "CREATE TABLE IF NOT EXISTS persistent.keyentry (
Joel Galenson0891bc12020-07-20 10:37:03 -0700925 id INTEGER UNIQUE,
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800926 key_type INTEGER,
Joel Galenson0891bc12020-07-20 10:37:03 -0700927 domain INTEGER,
928 namespace INTEGER,
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800929 alias BLOB,
Max Bires8e93d2b2021-01-14 13:17:59 -0800930 state INTEGER,
931 km_uuid BLOB);",
Andrew Walbran78abb1e2023-05-30 16:20:56 +0000932 [],
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700933 )
934 .context("Failed to initialize \"keyentry\" table.")?;
935
Janis Danisevskis66784c42021-01-27 08:40:25 -0800936 tx.execute(
Janis Danisevskisa5438182021-02-02 14:22:59 -0800937 "CREATE INDEX IF NOT EXISTS persistent.keyentry_id_index
938 ON keyentry(id);",
Andrew Walbran78abb1e2023-05-30 16:20:56 +0000939 [],
Janis Danisevskisa5438182021-02-02 14:22:59 -0800940 )
941 .context("Failed to create index keyentry_id_index.")?;
942
943 tx.execute(
944 "CREATE INDEX IF NOT EXISTS persistent.keyentry_domain_namespace_index
945 ON keyentry(domain, namespace, alias);",
Andrew Walbran78abb1e2023-05-30 16:20:56 +0000946 [],
Janis Danisevskisa5438182021-02-02 14:22:59 -0800947 )
948 .context("Failed to create index keyentry_domain_namespace_index.")?;
949
950 tx.execute(
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700951 "CREATE TABLE IF NOT EXISTS persistent.blobentry (
952 id INTEGER PRIMARY KEY,
953 subcomponent_type INTEGER,
954 keyentryid INTEGER,
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800955 blob BLOB);",
Andrew Walbran78abb1e2023-05-30 16:20:56 +0000956 [],
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700957 )
958 .context("Failed to initialize \"blobentry\" table.")?;
959
Janis Danisevskis66784c42021-01-27 08:40:25 -0800960 tx.execute(
Janis Danisevskisa5438182021-02-02 14:22:59 -0800961 "CREATE INDEX IF NOT EXISTS persistent.blobentry_keyentryid_index
962 ON blobentry(keyentryid);",
Andrew Walbran78abb1e2023-05-30 16:20:56 +0000963 [],
Janis Danisevskisa5438182021-02-02 14:22:59 -0800964 )
965 .context("Failed to create index blobentry_keyentryid_index.")?;
966
967 tx.execute(
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800968 "CREATE TABLE IF NOT EXISTS persistent.blobmetadata (
969 id INTEGER PRIMARY KEY,
970 blobentryid INTEGER,
971 tag INTEGER,
972 data ANY,
973 UNIQUE (blobentryid, tag));",
Andrew Walbran78abb1e2023-05-30 16:20:56 +0000974 [],
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800975 )
976 .context("Failed to initialize \"blobmetadata\" table.")?;
977
978 tx.execute(
979 "CREATE INDEX IF NOT EXISTS persistent.blobmetadata_blobentryid_index
980 ON blobmetadata(blobentryid);",
Andrew Walbran78abb1e2023-05-30 16:20:56 +0000981 [],
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800982 )
983 .context("Failed to create index blobmetadata_blobentryid_index.")?;
984
985 tx.execute(
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700986 "CREATE TABLE IF NOT EXISTS persistent.keyparameter (
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000987 keyentryid INTEGER,
988 tag INTEGER,
989 data ANY,
990 security_level INTEGER);",
Andrew Walbran78abb1e2023-05-30 16:20:56 +0000991 [],
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700992 )
993 .context("Failed to initialize \"keyparameter\" table.")?;
994
Janis Danisevskis66784c42021-01-27 08:40:25 -0800995 tx.execute(
Janis Danisevskisa5438182021-02-02 14:22:59 -0800996 "CREATE INDEX IF NOT EXISTS persistent.keyparameter_keyentryid_index
997 ON keyparameter(keyentryid);",
Andrew Walbran78abb1e2023-05-30 16:20:56 +0000998 [],
Janis Danisevskisa5438182021-02-02 14:22:59 -0800999 )
1000 .context("Failed to create index keyparameter_keyentryid_index.")?;
1001
1002 tx.execute(
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001003 "CREATE TABLE IF NOT EXISTS persistent.keymetadata (
1004 keyentryid INTEGER,
1005 tag INTEGER,
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00001006 data ANY,
1007 UNIQUE (keyentryid, tag));",
Andrew Walbran78abb1e2023-05-30 16:20:56 +00001008 [],
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001009 )
1010 .context("Failed to initialize \"keymetadata\" table.")?;
1011
Janis Danisevskis66784c42021-01-27 08:40:25 -08001012 tx.execute(
Janis Danisevskisa5438182021-02-02 14:22:59 -08001013 "CREATE INDEX IF NOT EXISTS persistent.keymetadata_keyentryid_index
1014 ON keymetadata(keyentryid);",
Andrew Walbran78abb1e2023-05-30 16:20:56 +00001015 [],
Janis Danisevskisa5438182021-02-02 14:22:59 -08001016 )
1017 .context("Failed to create index keymetadata_keyentryid_index.")?;
1018
1019 tx.execute(
Janis Danisevskisbf15d732020-12-08 10:35:26 -08001020 "CREATE TABLE IF NOT EXISTS persistent.grant (
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001021 id INTEGER UNIQUE,
1022 grantee INTEGER,
1023 keyentryid INTEGER,
1024 access_vector INTEGER);",
Andrew Walbran78abb1e2023-05-30 16:20:56 +00001025 [],
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001026 )
1027 .context("Failed to initialize \"grant\" table.")?;
1028
Joel Galenson0891bc12020-07-20 10:37:03 -07001029 Ok(())
1030 }
1031
Seth Moore472fcbb2021-05-12 10:07:51 -07001032 fn make_persistent_path(db_root: &Path) -> Result<String> {
1033 // Build the path to the sqlite file.
1034 let mut persistent_path = db_root.to_path_buf();
1035 persistent_path.push(Self::PERSISTENT_DB_FILENAME);
1036
1037 // Now convert them to strings prefixed with "file:"
1038 let mut persistent_path_str = "file:".to_owned();
1039 persistent_path_str.push_str(&persistent_path.to_string_lossy());
1040
Shaquille Johnson52b8c932023-12-19 19:45:32 +00001041 // Connect to database in specific mode
1042 let persistent_path_mode = if keystore2_flags::wal_db_journalmode_v3() {
1043 "?journal_mode=WAL".to_owned()
1044 } else {
1045 "?journal_mode=DELETE".to_owned()
1046 };
1047 persistent_path_str.push_str(&persistent_path_mode);
1048
Seth Moore472fcbb2021-05-12 10:07:51 -07001049 Ok(persistent_path_str)
1050 }
1051
Matthew Maurerd7815ca2021-05-06 21:58:45 -07001052 fn make_connection(persistent_file: &str) -> Result<Connection> {
Janis Danisevskis4df44f42020-08-26 14:40:03 -07001053 let conn =
1054 Connection::open_in_memory().context("Failed to initialize SQLite connection.")?;
1055
Janis Danisevskis66784c42021-01-27 08:40:25 -08001056 loop {
1057 if let Err(e) = conn
1058 .execute("ATTACH DATABASE ? as persistent;", params![persistent_file])
1059 .context("Failed to attach database persistent.")
1060 {
1061 if Self::is_locked_error(&e) {
David Drysdale115c4722024-04-15 14:11:52 +01001062 std::thread::sleep(DB_BUSY_RETRY_INTERVAL);
Janis Danisevskis66784c42021-01-27 08:40:25 -08001063 continue;
1064 } else {
1065 return Err(e);
1066 }
1067 }
1068 break;
1069 }
Janis Danisevskis4df44f42020-08-26 14:40:03 -07001070
Matthew Maurer4fb19112021-05-06 15:40:44 -07001071 // Drop the cache size from default (2M) to 0.5M
1072 conn.execute("PRAGMA persistent.cache_size = -500;", params![])
1073 .context("Failed to decrease cache size for persistent db")?;
Matthew Maurer4fb19112021-05-06 15:40:44 -07001074
Janis Danisevskis4df44f42020-08-26 14:40:03 -07001075 Ok(conn)
1076 }
1077
Seth Moore78c091f2021-04-09 21:38:30 +00001078 fn do_table_size_query(
1079 &mut self,
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001080 storage_type: MetricsStorage,
Seth Moore78c091f2021-04-09 21:38:30 +00001081 query: &str,
1082 params: &[&str],
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001083 ) -> Result<StorageStats> {
Seth Moore78c091f2021-04-09 21:38:30 +00001084 let (total, unused) = self.with_transaction(TransactionBehavior::Deferred, |tx| {
Joel Galensonff79e362021-05-25 16:30:17 -07001085 tx.query_row(query, params_from_iter(params), |row| Ok((row.get(0)?, row.get(1)?)))
Seth Moore78c091f2021-04-09 21:38:30 +00001086 .with_context(|| {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001087 ks_err!("get_storage_stat: Error size of storage type {}", storage_type.0)
Seth Moore78c091f2021-04-09 21:38:30 +00001088 })
1089 .no_gc()
1090 })?;
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001091 Ok(StorageStats { storage_type, size: total, unused_size: unused })
Seth Moore78c091f2021-04-09 21:38:30 +00001092 }
1093
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001094 fn get_total_size(&mut self) -> Result<StorageStats> {
Seth Moore78c091f2021-04-09 21:38:30 +00001095 self.do_table_size_query(
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001096 MetricsStorage::DATABASE,
Seth Moore78c091f2021-04-09 21:38:30 +00001097 "SELECT page_count * page_size, freelist_count * page_size
1098 FROM pragma_page_count('persistent'),
1099 pragma_page_size('persistent'),
1100 persistent.pragma_freelist_count();",
1101 &[],
1102 )
1103 }
1104
1105 fn get_table_size(
1106 &mut self,
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001107 storage_type: MetricsStorage,
Seth Moore78c091f2021-04-09 21:38:30 +00001108 schema: &str,
1109 table: &str,
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001110 ) -> Result<StorageStats> {
Seth Moore78c091f2021-04-09 21:38:30 +00001111 self.do_table_size_query(
1112 storage_type,
1113 "SELECT pgsize,unused FROM dbstat(?1)
1114 WHERE name=?2 AND aggregate=TRUE;",
1115 &[schema, table],
1116 )
1117 }
1118
1119 /// Fetches a storage statisitics atom for a given storage type. For storage
1120 /// types that map to a table, information about the table's storage is
1121 /// returned. Requests for storage types that are not DB tables return None.
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001122 pub fn get_storage_stat(&mut self, storage_type: MetricsStorage) -> Result<StorageStats> {
David Drysdale541846b2024-05-23 13:16:07 +01001123 let _wp = wd::watch("KeystoreDB::get_storage_stat");
Janis Danisevskis850d4862021-05-05 08:41:14 -07001124
Seth Moore78c091f2021-04-09 21:38:30 +00001125 match storage_type {
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001126 MetricsStorage::DATABASE => self.get_total_size(),
1127 MetricsStorage::KEY_ENTRY => {
Seth Moore78c091f2021-04-09 21:38:30 +00001128 self.get_table_size(storage_type, "persistent", "keyentry")
1129 }
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001130 MetricsStorage::KEY_ENTRY_ID_INDEX => {
Seth Moore78c091f2021-04-09 21:38:30 +00001131 self.get_table_size(storage_type, "persistent", "keyentry_id_index")
1132 }
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001133 MetricsStorage::KEY_ENTRY_DOMAIN_NAMESPACE_INDEX => {
Seth Moore78c091f2021-04-09 21:38:30 +00001134 self.get_table_size(storage_type, "persistent", "keyentry_domain_namespace_index")
1135 }
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001136 MetricsStorage::BLOB_ENTRY => {
Seth Moore78c091f2021-04-09 21:38:30 +00001137 self.get_table_size(storage_type, "persistent", "blobentry")
1138 }
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001139 MetricsStorage::BLOB_ENTRY_KEY_ENTRY_ID_INDEX => {
Seth Moore78c091f2021-04-09 21:38:30 +00001140 self.get_table_size(storage_type, "persistent", "blobentry_keyentryid_index")
1141 }
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001142 MetricsStorage::KEY_PARAMETER => {
Seth Moore78c091f2021-04-09 21:38:30 +00001143 self.get_table_size(storage_type, "persistent", "keyparameter")
1144 }
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001145 MetricsStorage::KEY_PARAMETER_KEY_ENTRY_ID_INDEX => {
Seth Moore78c091f2021-04-09 21:38:30 +00001146 self.get_table_size(storage_type, "persistent", "keyparameter_keyentryid_index")
1147 }
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001148 MetricsStorage::KEY_METADATA => {
Seth Moore78c091f2021-04-09 21:38:30 +00001149 self.get_table_size(storage_type, "persistent", "keymetadata")
1150 }
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001151 MetricsStorage::KEY_METADATA_KEY_ENTRY_ID_INDEX => {
Seth Moore78c091f2021-04-09 21:38:30 +00001152 self.get_table_size(storage_type, "persistent", "keymetadata_keyentryid_index")
1153 }
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001154 MetricsStorage::GRANT => self.get_table_size(storage_type, "persistent", "grant"),
1155 MetricsStorage::AUTH_TOKEN => {
Matthew Maurerd7815ca2021-05-06 21:58:45 -07001156 // Since the table is actually a BTreeMap now, unused_size is not meaningfully
1157 // reportable
1158 // Size provided is only an approximation
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001159 Ok(StorageStats {
Matthew Maurerd7815ca2021-05-06 21:58:45 -07001160 storage_type,
1161 size: (self.perboot.auth_tokens_len() * std::mem::size_of::<AuthTokenEntry>())
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001162 as i32,
Matthew Maurerd7815ca2021-05-06 21:58:45 -07001163 unused_size: 0,
1164 })
Seth Moore78c091f2021-04-09 21:38:30 +00001165 }
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001166 MetricsStorage::BLOB_METADATA => {
Seth Moore78c091f2021-04-09 21:38:30 +00001167 self.get_table_size(storage_type, "persistent", "blobmetadata")
1168 }
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001169 MetricsStorage::BLOB_METADATA_BLOB_ENTRY_ID_INDEX => {
Seth Moore78c091f2021-04-09 21:38:30 +00001170 self.get_table_size(storage_type, "persistent", "blobmetadata_blobentryid_index")
1171 }
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001172 _ => Err(anyhow::Error::msg(format!("Unsupported storage type: {}", storage_type.0))),
Seth Moore78c091f2021-04-09 21:38:30 +00001173 }
1174 }
1175
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001176 /// This function is intended to be used by the garbage collector.
Janis Danisevskis3395f862021-05-06 10:54:17 -07001177 /// It deletes the blobs given by `blob_ids_to_delete`. It then tries to find up to `max_blobs`
1178 /// superseded key blobs that might need special handling by the garbage collector.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001179 /// If no further superseded blobs can be found it deletes all other superseded blobs that don't
1180 /// need special handling and returns None.
Janis Danisevskis3395f862021-05-06 10:54:17 -07001181 pub fn handle_next_superseded_blobs(
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001182 &mut self,
Janis Danisevskis3395f862021-05-06 10:54:17 -07001183 blob_ids_to_delete: &[i64],
1184 max_blobs: usize,
David Drysdalef1ba3812024-05-08 17:50:13 +01001185 ) -> Result<Vec<SupersededBlob>> {
David Drysdale541846b2024-05-23 13:16:07 +01001186 let _wp = wd::watch("KeystoreDB::handle_next_superseded_blob");
David Drysdale7b9ca232024-05-23 18:19:46 +01001187 self.with_transaction(Immediate("TX_handle_next_superseded_blob"), |tx| {
Janis Danisevskis3395f862021-05-06 10:54:17 -07001188 // Delete the given blobs.
1189 for blob_id in blob_ids_to_delete {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001190 tx.execute(
1191 "DELETE FROM persistent.blobmetadata WHERE blobentryid = ?;",
Janis Danisevskis3395f862021-05-06 10:54:17 -07001192 params![blob_id],
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001193 )
Shaquille Johnsonf23fc942024-02-13 17:01:29 +00001194 .context(ks_err!("Trying to delete blob metadata: {:?}", blob_id))?;
Janis Danisevskis3395f862021-05-06 10:54:17 -07001195 tx.execute("DELETE FROM persistent.blobentry WHERE id = ?;", params![blob_id])
Shaquille Johnsonf23fc942024-02-13 17:01:29 +00001196 .context(ks_err!("Trying to delete blob: {:?}", blob_id))?;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001197 }
Janis Danisevskis3cba10d2021-05-06 17:02:19 -07001198
1199 Self::cleanup_unreferenced(tx).context("Trying to cleanup unreferenced.")?;
1200
David Drysdalef1ba3812024-05-08 17:50:13 +01001201 // Find up to `max_blobs` more superseded key blobs, load their metadata and return it.
Janis Danisevskis3395f862021-05-06 10:54:17 -07001202 let result: Vec<(i64, Vec<u8>)> = {
David Drysdalec652f6c2024-07-18 13:01:23 +01001203 let _wp = wd::watch("KeystoreDB::handle_next_superseded_blob find_next");
Janis Danisevskis3395f862021-05-06 10:54:17 -07001204 let mut stmt = tx
1205 .prepare(
1206 "SELECT id, blob FROM persistent.blobentry
1207 WHERE subcomponent_type = ?
1208 AND (
1209 id NOT IN (
1210 SELECT MAX(id) FROM persistent.blobentry
1211 WHERE subcomponent_type = ?
1212 GROUP BY keyentryid, subcomponent_type
1213 )
1214 OR keyentryid NOT IN (SELECT id FROM persistent.keyentry)
1215 ) LIMIT ?;",
1216 )
1217 .context("Trying to prepare query for superseded blobs.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001218
Janis Danisevskis3395f862021-05-06 10:54:17 -07001219 let rows = stmt
1220 .query_map(
1221 params![
1222 SubComponentType::KEY_BLOB,
1223 SubComponentType::KEY_BLOB,
1224 max_blobs as i64,
1225 ],
1226 |row| Ok((row.get(0)?, row.get(1)?)),
1227 )
1228 .context("Trying to query superseded blob.")?;
1229
1230 rows.collect::<Result<Vec<(i64, Vec<u8>)>, rusqlite::Error>>()
1231 .context("Trying to extract superseded blobs.")?
1232 };
1233
David Drysdalec652f6c2024-07-18 13:01:23 +01001234 let _wp = wd::watch("KeystoreDB::handle_next_superseded_blob load_metadata");
Janis Danisevskis3395f862021-05-06 10:54:17 -07001235 let result = result
1236 .into_iter()
1237 .map(|(blob_id, blob)| {
David Drysdalef1ba3812024-05-08 17:50:13 +01001238 Ok(SupersededBlob {
1239 blob_id,
1240 blob,
1241 metadata: BlobMetaData::load_from_db(blob_id, tx)?,
1242 })
Janis Danisevskis3395f862021-05-06 10:54:17 -07001243 })
David Drysdalef1ba3812024-05-08 17:50:13 +01001244 .collect::<Result<Vec<_>>>()
Janis Danisevskis3395f862021-05-06 10:54:17 -07001245 .context("Trying to load blob metadata.")?;
1246 if !result.is_empty() {
1247 return Ok(result).no_gc();
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001248 }
1249
1250 // We did not find any superseded key blob, so let's remove other superseded blob in
1251 // one transaction.
David Drysdalec652f6c2024-07-18 13:01:23 +01001252 let _wp = wd::watch("KeystoreDB::handle_next_superseded_blob delete");
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001253 tx.execute(
1254 "DELETE FROM persistent.blobentry
1255 WHERE NOT subcomponent_type = ?
1256 AND (
1257 id NOT IN (
1258 SELECT MAX(id) FROM persistent.blobentry
1259 WHERE NOT subcomponent_type = ?
1260 GROUP BY keyentryid, subcomponent_type
1261 ) OR keyentryid NOT IN (SELECT id FROM persistent.keyentry)
1262 );",
1263 params![SubComponentType::KEY_BLOB, SubComponentType::KEY_BLOB],
1264 )
1265 .context("Trying to purge superseded blobs.")?;
1266
Janis Danisevskis3395f862021-05-06 10:54:17 -07001267 Ok(vec![]).no_gc()
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001268 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001269 .context(ks_err!())
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001270 }
1271
1272 /// This maintenance function should be called only once before the database is used for the
1273 /// first time. It restores the invariant that `KeyLifeCycle::Existing` is a transient state.
1274 /// The function transitions all key entries from Existing to Unreferenced unconditionally and
1275 /// returns the number of rows affected. If this returns a value greater than 0, it means that
1276 /// Keystore crashed at some point during key generation. Callers may want to log such
1277 /// occurrences.
1278 /// Unlike with `mark_unreferenced`, we don't need to purge grants, because only keys that made
1279 /// it to `KeyLifeCycle::Live` may have grants.
1280 pub fn cleanup_leftovers(&mut self) -> Result<usize> {
David Drysdale541846b2024-05-23 13:16:07 +01001281 let _wp = wd::watch("KeystoreDB::cleanup_leftovers");
Janis Danisevskis850d4862021-05-05 08:41:14 -07001282
David Drysdale7b9ca232024-05-23 18:19:46 +01001283 self.with_transaction(Immediate("TX_cleanup_leftovers"), |tx| {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001284 tx.execute(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001285 "UPDATE persistent.keyentry SET state = ? WHERE state = ?;",
1286 params![KeyLifeCycle::Unreferenced, KeyLifeCycle::Existing],
1287 )
Janis Danisevskis66784c42021-01-27 08:40:25 -08001288 .context("Failed to execute query.")
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001289 .need_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08001290 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001291 .context(ks_err!())
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001292 }
1293
Hasini Gunasinghe0e161452021-01-27 19:34:37 +00001294 /// Checks if a key exists with given key type and key descriptor properties.
1295 pub fn key_exists(
1296 &mut self,
1297 domain: Domain,
1298 nspace: i64,
1299 alias: &str,
1300 key_type: KeyType,
1301 ) -> Result<bool> {
David Drysdale541846b2024-05-23 13:16:07 +01001302 let _wp = wd::watch("KeystoreDB::key_exists");
Janis Danisevskis850d4862021-05-05 08:41:14 -07001303
David Drysdale7b9ca232024-05-23 18:19:46 +01001304 self.with_transaction(Immediate("TX_key_exists"), |tx| {
Hasini Gunasinghe0e161452021-01-27 19:34:37 +00001305 let key_descriptor =
1306 KeyDescriptor { domain, nspace, alias: Some(alias.to_string()), blob: None };
Chris Wailesd5aaaef2021-07-27 16:04:33 -07001307 let result = Self::load_key_entry_id(tx, &key_descriptor, key_type);
Hasini Gunasinghe0e161452021-01-27 19:34:37 +00001308 match result {
1309 Ok(_) => Ok(true),
1310 Err(error) => match error.root_cause().downcast_ref::<KsError>() {
1311 Some(KsError::Rc(ResponseCode::KEY_NOT_FOUND)) => Ok(false),
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001312 _ => Err(error).context(ks_err!("Failed to find if the key exists.")),
Hasini Gunasinghe0e161452021-01-27 19:34:37 +00001313 },
1314 }
1315 .no_gc()
1316 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001317 .context(ks_err!())
Hasini Gunasinghe0e161452021-01-27 19:34:37 +00001318 }
1319
Hasini Gunasingheda895552021-01-27 19:34:37 +00001320 /// Stores a super key in the database.
1321 pub fn store_super_key(
1322 &mut self,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +00001323 user_id: u32,
Paul Crowley7a658392021-03-18 17:08:20 -07001324 key_type: &SuperKeyType,
1325 blob: &[u8],
1326 blob_metadata: &BlobMetaData,
Paul Crowley8d5b2532021-03-19 10:53:07 -07001327 key_metadata: &KeyMetaData,
Hasini Gunasingheda895552021-01-27 19:34:37 +00001328 ) -> Result<KeyEntry> {
David Drysdale541846b2024-05-23 13:16:07 +01001329 let _wp = wd::watch("KeystoreDB::store_super_key");
Janis Danisevskis850d4862021-05-05 08:41:14 -07001330
David Drysdale7b9ca232024-05-23 18:19:46 +01001331 self.with_transaction(Immediate("TX_store_super_key"), |tx| {
Hasini Gunasingheda895552021-01-27 19:34:37 +00001332 let key_id = Self::insert_with_retry(|id| {
1333 tx.execute(
1334 "INSERT into persistent.keyentry
1335 (id, key_type, domain, namespace, alias, state, km_uuid)
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00001336 VALUES(?, ?, ?, ?, ?, ?, ?);",
Hasini Gunasingheda895552021-01-27 19:34:37 +00001337 params![
1338 id,
1339 KeyType::Super,
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00001340 Domain::APP.0,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +00001341 user_id as i64,
Paul Crowley7a658392021-03-18 17:08:20 -07001342 key_type.alias,
Hasini Gunasingheda895552021-01-27 19:34:37 +00001343 KeyLifeCycle::Live,
1344 &KEYSTORE_UUID,
1345 ],
1346 )
1347 })
1348 .context("Failed to insert into keyentry table.")?;
1349
Paul Crowley8d5b2532021-03-19 10:53:07 -07001350 key_metadata.store_in_db(key_id, tx).context("KeyMetaData::store_in_db failed")?;
1351
Hasini Gunasingheda895552021-01-27 19:34:37 +00001352 Self::set_blob_internal(
Chris Wailesd5aaaef2021-07-27 16:04:33 -07001353 tx,
Hasini Gunasingheda895552021-01-27 19:34:37 +00001354 key_id,
1355 SubComponentType::KEY_BLOB,
1356 Some(blob),
1357 Some(blob_metadata),
1358 )
1359 .context("Failed to store key blob.")?;
1360
1361 Self::load_key_components(tx, KeyEntryLoadBits::KM, key_id)
1362 .context("Trying to load key components.")
1363 .no_gc()
1364 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001365 .context(ks_err!())
Hasini Gunasingheda895552021-01-27 19:34:37 +00001366 }
1367
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +00001368 /// Loads super key of a given user, if exists
Paul Crowley7a658392021-03-18 17:08:20 -07001369 pub fn load_super_key(
1370 &mut self,
1371 key_type: &SuperKeyType,
1372 user_id: u32,
1373 ) -> Result<Option<(KeyIdGuard, KeyEntry)>> {
David Drysdale541846b2024-05-23 13:16:07 +01001374 let _wp = wd::watch("KeystoreDB::load_super_key");
Janis Danisevskis850d4862021-05-05 08:41:14 -07001375
David Drysdale7b9ca232024-05-23 18:19:46 +01001376 self.with_transaction(Immediate("TX_load_super_key"), |tx| {
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +00001377 let key_descriptor = KeyDescriptor {
1378 domain: Domain::APP,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +00001379 nspace: user_id as i64,
Paul Crowley7a658392021-03-18 17:08:20 -07001380 alias: Some(key_type.alias.into()),
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +00001381 blob: None,
1382 };
Chris Wailesd5aaaef2021-07-27 16:04:33 -07001383 let id = Self::load_key_entry_id(tx, &key_descriptor, KeyType::Super);
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +00001384 match id {
1385 Ok(id) => {
Chris Wailesd5aaaef2021-07-27 16:04:33 -07001386 let key_entry = Self::load_key_components(tx, KeyEntryLoadBits::KM, id)
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001387 .context(ks_err!("Failed to load key entry."))?;
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +00001388 Ok(Some((KEY_ID_LOCK.get(id), key_entry)))
1389 }
1390 Err(error) => match error.root_cause().downcast_ref::<KsError>() {
1391 Some(KsError::Rc(ResponseCode::KEY_NOT_FOUND)) => Ok(None),
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001392 _ => Err(error).context(ks_err!()),
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +00001393 },
1394 }
1395 .no_gc()
1396 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001397 .context(ks_err!())
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +00001398 }
1399
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001400 /// Creates a transaction with the given behavior and executes f with the new transaction.
Janis Danisevskis66784c42021-01-27 08:40:25 -08001401 /// The transaction is committed only if f returns Ok and retried if DatabaseBusy
1402 /// or DatabaseLocked is encountered.
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001403 fn with_transaction<T, F>(&mut self, behavior: TransactionBehavior, f: F) -> Result<T>
1404 where
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001405 F: Fn(&Transaction) -> Result<(bool, T)>,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001406 {
David Drysdale7b9ca232024-05-23 18:19:46 +01001407 let name = behavior.name();
Janis Danisevskis66784c42021-01-27 08:40:25 -08001408 loop {
James Farrellefe1a2f2024-02-28 21:36:47 +00001409 let result = self
Janis Danisevskis66784c42021-01-27 08:40:25 -08001410 .conn
David Drysdale7b9ca232024-05-23 18:19:46 +01001411 .transaction_with_behavior(behavior.into())
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001412 .context(ks_err!())
David Drysdale7b9ca232024-05-23 18:19:46 +01001413 .and_then(|tx| {
1414 let _wp = name.map(wd::watch);
1415 f(&tx).map(|result| (result, tx))
1416 })
Janis Danisevskis66784c42021-01-27 08:40:25 -08001417 .and_then(|(result, tx)| {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001418 tx.commit().context(ks_err!("Failed to commit transaction."))?;
Janis Danisevskis66784c42021-01-27 08:40:25 -08001419 Ok(result)
James Farrellefe1a2f2024-02-28 21:36:47 +00001420 });
1421 match result {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001422 Ok(result) => break Ok(result),
1423 Err(e) => {
1424 if Self::is_locked_error(&e) {
David Drysdale115c4722024-04-15 14:11:52 +01001425 std::thread::sleep(DB_BUSY_RETRY_INTERVAL);
Janis Danisevskis66784c42021-01-27 08:40:25 -08001426 continue;
1427 } else {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001428 return Err(e).context(ks_err!());
Janis Danisevskis66784c42021-01-27 08:40:25 -08001429 }
1430 }
1431 }
1432 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001433 .map(|(need_gc, result)| {
1434 if need_gc {
1435 if let Some(ref gc) = self.gc {
1436 gc.notify_gc();
1437 }
1438 }
1439 result
1440 })
Janis Danisevskis66784c42021-01-27 08:40:25 -08001441 }
1442
1443 fn is_locked_error(e: &anyhow::Error) -> bool {
Paul Crowleyf61fee72021-03-17 14:38:44 -07001444 matches!(
1445 e.root_cause().downcast_ref::<rusqlite::ffi::Error>(),
1446 Some(rusqlite::ffi::Error { code: rusqlite::ErrorCode::DatabaseBusy, .. })
1447 | Some(rusqlite::ffi::Error { code: rusqlite::ErrorCode::DatabaseLocked, .. })
1448 )
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001449 }
1450
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001451 fn create_key_entry_internal(
1452 tx: &Transaction,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001453 domain: &Domain,
1454 namespace: &i64,
Janis Danisevskis0cabd712021-05-25 11:07:10 -07001455 key_type: KeyType,
Max Bires8e93d2b2021-01-14 13:17:59 -08001456 km_uuid: &Uuid,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001457 ) -> Result<KeyIdGuard> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001458 match *domain {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001459 Domain::APP | Domain::SELINUX => {}
Joel Galenson0891bc12020-07-20 10:37:03 -07001460 _ => {
1461 return Err(KsError::sys())
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001462 .context(ks_err!("Domain {:?} must be either App or SELinux.", domain));
Joel Galenson0891bc12020-07-20 10:37:03 -07001463 }
1464 }
Janis Danisevskisaec14592020-11-12 09:41:49 -08001465 Ok(KEY_ID_LOCK.get(
1466 Self::insert_with_retry(|id| {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001467 tx.execute(
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001468 "INSERT into persistent.keyentry
Max Bires8e93d2b2021-01-14 13:17:59 -08001469 (id, key_type, domain, namespace, alias, state, km_uuid)
1470 VALUES(?, ?, ?, ?, NULL, ?, ?);",
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001471 params![
1472 id,
Janis Danisevskis0cabd712021-05-25 11:07:10 -07001473 key_type,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001474 domain.0 as u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001475 *namespace,
Max Bires8e93d2b2021-01-14 13:17:59 -08001476 KeyLifeCycle::Existing,
1477 km_uuid,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001478 ],
Janis Danisevskisaec14592020-11-12 09:41:49 -08001479 )
1480 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001481 .context(ks_err!())?,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001482 ))
Joel Galenson26f4d012020-07-17 14:57:21 -07001483 }
Joel Galenson33c04ad2020-08-03 11:04:38 -07001484
Janis Danisevskis377d1002021-01-27 19:07:48 -08001485 /// Set a new blob and associates it with the given key id. Each blob
1486 /// has a sub component type.
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001487 /// Each key can have one of each sub component type associated. If more
1488 /// are added only the most recent can be retrieved, and superseded blobs
Janis Danisevskis377d1002021-01-27 19:07:48 -08001489 /// will get garbage collected.
1490 /// Components SubComponentType::CERT and SubComponentType::CERT_CHAIN can be
1491 /// removed by setting blob to None.
1492 pub fn set_blob(
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001493 &mut self,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001494 key_id: &KeyIdGuard,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001495 sc_type: SubComponentType,
Janis Danisevskis377d1002021-01-27 19:07:48 -08001496 blob: Option<&[u8]>,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001497 blob_metadata: Option<&BlobMetaData>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001498 ) -> Result<()> {
David Drysdale541846b2024-05-23 13:16:07 +01001499 let _wp = wd::watch("KeystoreDB::set_blob");
Janis Danisevskis850d4862021-05-05 08:41:14 -07001500
David Drysdale7b9ca232024-05-23 18:19:46 +01001501 self.with_transaction(Immediate("TX_set_blob"), |tx| {
Chris Wailesd5aaaef2021-07-27 16:04:33 -07001502 Self::set_blob_internal(tx, key_id.0, sc_type, blob, blob_metadata).need_gc()
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001503 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001504 .context(ks_err!())
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001505 }
1506
Janis Danisevskiseed69842021-02-18 20:04:10 -08001507 /// Why would we insert a deleted blob? This weird function is for the purpose of legacy
1508 /// key migration in the case where we bulk delete all the keys of an app or even a user.
1509 /// We use this to insert key blobs into the database which can then be garbage collected
1510 /// lazily by the key garbage collector.
1511 pub fn set_deleted_blob(&mut self, blob: &[u8], blob_metadata: &BlobMetaData) -> Result<()> {
David Drysdale541846b2024-05-23 13:16:07 +01001512 let _wp = wd::watch("KeystoreDB::set_deleted_blob");
Janis Danisevskis850d4862021-05-05 08:41:14 -07001513
David Drysdale7b9ca232024-05-23 18:19:46 +01001514 self.with_transaction(Immediate("TX_set_deleted_blob"), |tx| {
Janis Danisevskiseed69842021-02-18 20:04:10 -08001515 Self::set_blob_internal(
Chris Wailesd5aaaef2021-07-27 16:04:33 -07001516 tx,
Janis Danisevskiseed69842021-02-18 20:04:10 -08001517 Self::UNASSIGNED_KEY_ID,
1518 SubComponentType::KEY_BLOB,
1519 Some(blob),
1520 Some(blob_metadata),
1521 )
1522 .need_gc()
1523 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001524 .context(ks_err!())
Janis Danisevskiseed69842021-02-18 20:04:10 -08001525 }
1526
Janis Danisevskis377d1002021-01-27 19:07:48 -08001527 fn set_blob_internal(
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001528 tx: &Transaction,
1529 key_id: i64,
1530 sc_type: SubComponentType,
Janis Danisevskis377d1002021-01-27 19:07:48 -08001531 blob: Option<&[u8]>,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001532 blob_metadata: Option<&BlobMetaData>,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001533 ) -> Result<()> {
Janis Danisevskis377d1002021-01-27 19:07:48 -08001534 match (blob, sc_type) {
1535 (Some(blob), _) => {
1536 tx.execute(
1537 "INSERT INTO persistent.blobentry
1538 (subcomponent_type, keyentryid, blob) VALUES (?, ?, ?);",
1539 params![sc_type, key_id, blob],
1540 )
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001541 .context(ks_err!("Failed to insert blob."))?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001542 if let Some(blob_metadata) = blob_metadata {
1543 let blob_id = tx
Andrew Walbran78abb1e2023-05-30 16:20:56 +00001544 .query_row("SELECT MAX(id) FROM persistent.blobentry;", [], |row| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001545 row.get(0)
1546 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001547 .context(ks_err!("Failed to get new blob id."))?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001548 blob_metadata
1549 .store_in_db(blob_id, tx)
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001550 .context(ks_err!("Trying to store blob metadata."))?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001551 }
Janis Danisevskis377d1002021-01-27 19:07:48 -08001552 }
1553 (None, SubComponentType::CERT) | (None, SubComponentType::CERT_CHAIN) => {
1554 tx.execute(
1555 "DELETE FROM persistent.blobentry
1556 WHERE subcomponent_type = ? AND keyentryid = ?;",
1557 params![sc_type, key_id],
1558 )
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001559 .context(ks_err!("Failed to delete blob."))?;
Janis Danisevskis377d1002021-01-27 19:07:48 -08001560 }
1561 (None, _) => {
1562 return Err(KsError::sys())
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001563 .context(ks_err!("Other blobs cannot be deleted in this way."));
Janis Danisevskis377d1002021-01-27 19:07:48 -08001564 }
1565 }
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001566 Ok(())
1567 }
1568
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001569 /// Inserts a collection of key parameters into the `persistent.keyparameter` table
1570 /// and associates them with the given `key_id`.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001571 #[cfg(test)]
1572 fn insert_keyparameter(&mut self, key_id: &KeyIdGuard, params: &[KeyParameter]) -> Result<()> {
David Drysdale7b9ca232024-05-23 18:19:46 +01001573 self.with_transaction(Immediate("TX_insert_keyparameter"), |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001574 Self::insert_keyparameter_internal(tx, key_id, params).no_gc()
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001575 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001576 .context(ks_err!())
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001577 }
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001578
Janis Danisevskis66784c42021-01-27 08:40:25 -08001579 fn insert_keyparameter_internal(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001580 tx: &Transaction,
1581 key_id: &KeyIdGuard,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001582 params: &[KeyParameter],
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001583 ) -> Result<()> {
1584 let mut stmt = tx
1585 .prepare(
1586 "INSERT into persistent.keyparameter (keyentryid, tag, data, security_level)
1587 VALUES (?, ?, ?, ?);",
1588 )
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001589 .context(ks_err!("Failed to prepare statement."))?;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001590
Janis Danisevskis66784c42021-01-27 08:40:25 -08001591 for p in params.iter() {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001592 stmt.insert(params![
1593 key_id.0,
1594 p.get_tag().0,
1595 p.key_parameter_value(),
1596 p.security_level().0
1597 ])
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001598 .with_context(|| ks_err!("Failed to insert {:?}", p))?;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001599 }
1600 Ok(())
1601 }
1602
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001603 /// Insert a set of key entry specific metadata into the database.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001604 #[cfg(test)]
1605 fn insert_key_metadata(&mut self, key_id: &KeyIdGuard, metadata: &KeyMetaData) -> Result<()> {
David Drysdale7b9ca232024-05-23 18:19:46 +01001606 self.with_transaction(Immediate("TX_insert_key_metadata"), |tx| {
Chris Wailesd5aaaef2021-07-27 16:04:33 -07001607 metadata.store_in_db(key_id.0, tx).no_gc()
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001608 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001609 .context(ks_err!())
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001610 }
1611
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001612 /// Updates the alias column of the given key id `newid` with the given alias,
1613 /// and atomically, removes the alias, domain, and namespace from another row
1614 /// with the same alias-domain-namespace tuple if such row exits.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001615 /// Returns Ok(true) if an old key was marked unreferenced as a hint to the garbage
1616 /// collector.
1617 fn rebind_alias(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001618 tx: &Transaction,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001619 newid: &KeyIdGuard,
Joel Galenson33c04ad2020-08-03 11:04:38 -07001620 alias: &str,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001621 domain: &Domain,
1622 namespace: &i64,
Janis Danisevskis0cabd712021-05-25 11:07:10 -07001623 key_type: KeyType,
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001624 ) -> Result<bool> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001625 match *domain {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001626 Domain::APP | Domain::SELINUX => {}
Joel Galenson33c04ad2020-08-03 11:04:38 -07001627 _ => {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001628 return Err(KsError::sys())
1629 .context(ks_err!("Domain {:?} must be either App or SELinux.", domain));
Joel Galenson33c04ad2020-08-03 11:04:38 -07001630 }
1631 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001632 let updated = tx
1633 .execute(
1634 "UPDATE persistent.keyentry
1635 SET alias = NULL, domain = NULL, namespace = NULL, state = ?
Janis Danisevskis0cabd712021-05-25 11:07:10 -07001636 WHERE alias = ? AND domain = ? AND namespace = ? AND key_type = ?;",
1637 params![KeyLifeCycle::Unreferenced, alias, domain.0 as u32, namespace, key_type],
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001638 )
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001639 .context(ks_err!("Failed to rebind existing entry."))?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07001640 let result = tx
1641 .execute(
1642 "UPDATE persistent.keyentry
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001643 SET alias = ?, state = ?
Janis Danisevskis0cabd712021-05-25 11:07:10 -07001644 WHERE id = ? AND domain = ? AND namespace = ? AND state = ? AND key_type = ?;",
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001645 params![
1646 alias,
1647 KeyLifeCycle::Live,
1648 newid.0,
1649 domain.0 as u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001650 *namespace,
Max Bires8e93d2b2021-01-14 13:17:59 -08001651 KeyLifeCycle::Existing,
Janis Danisevskis0cabd712021-05-25 11:07:10 -07001652 key_type,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001653 ],
Joel Galenson33c04ad2020-08-03 11:04:38 -07001654 )
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001655 .context(ks_err!("Failed to set alias."))?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07001656 if result != 1 {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001657 return Err(KsError::sys()).context(ks_err!(
1658 "Expected to update a single entry but instead updated {}.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07001659 result
1660 ));
1661 }
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001662 Ok(updated != 0)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001663 }
1664
Janis Danisevskiscdcf4e52021-04-14 15:44:36 -07001665 /// Moves the key given by KeyIdGuard to the new location at `destination`. If the destination
1666 /// is already occupied by a key, this function fails with `ResponseCode::INVALID_ARGUMENT`.
1667 pub fn migrate_key_namespace(
1668 &mut self,
1669 key_id_guard: KeyIdGuard,
1670 destination: &KeyDescriptor,
1671 caller_uid: u32,
1672 check_permission: impl Fn(&KeyDescriptor) -> Result<()>,
1673 ) -> Result<()> {
David Drysdale541846b2024-05-23 13:16:07 +01001674 let _wp = wd::watch("KeystoreDB::migrate_key_namespace");
Janis Danisevskis850d4862021-05-05 08:41:14 -07001675
Janis Danisevskiscdcf4e52021-04-14 15:44:36 -07001676 let destination = match destination.domain {
1677 Domain::APP => KeyDescriptor { nspace: caller_uid as i64, ..(*destination).clone() },
1678 Domain::SELINUX => (*destination).clone(),
1679 domain => {
1680 return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT))
1681 .context(format!("Domain {:?} must be either APP or SELINUX.", domain));
1682 }
1683 };
1684
1685 // Security critical: Must return immediately on failure. Do not remove the '?';
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001686 check_permission(&destination).context(ks_err!("Trying to check permission."))?;
Janis Danisevskiscdcf4e52021-04-14 15:44:36 -07001687
1688 let alias = destination
1689 .alias
1690 .as_ref()
1691 .ok_or(KsError::Rc(ResponseCode::INVALID_ARGUMENT))
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001692 .context(ks_err!("Alias must be specified."))?;
Janis Danisevskiscdcf4e52021-04-14 15:44:36 -07001693
David Drysdale7b9ca232024-05-23 18:19:46 +01001694 self.with_transaction(Immediate("TX_migrate_key_namespace"), |tx| {
Janis Danisevskiscdcf4e52021-04-14 15:44:36 -07001695 // Query the destination location. If there is a key, the migration request fails.
1696 if tx
1697 .query_row(
1698 "SELECT id FROM persistent.keyentry
1699 WHERE alias = ? AND domain = ? AND namespace = ?;",
1700 params![alias, destination.domain.0, destination.nspace],
1701 |_| Ok(()),
1702 )
1703 .optional()
1704 .context("Failed to query destination.")?
1705 .is_some()
1706 {
1707 return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT))
1708 .context("Target already exists.");
1709 }
1710
1711 let updated = tx
1712 .execute(
1713 "UPDATE persistent.keyentry
1714 SET alias = ?, domain = ?, namespace = ?
1715 WHERE id = ?;",
1716 params![alias, destination.domain.0, destination.nspace, key_id_guard.id()],
1717 )
1718 .context("Failed to update key entry.")?;
1719
1720 if updated != 1 {
1721 return Err(KsError::sys())
1722 .context(format!("Update succeeded, but {} rows were updated.", updated));
1723 }
1724 Ok(()).no_gc()
1725 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001726 .context(ks_err!())
Janis Danisevskiscdcf4e52021-04-14 15:44:36 -07001727 }
1728
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001729 /// Store a new key in a single transaction.
1730 /// The function creates a new key entry, populates the blob, key parameter, and metadata
1731 /// fields, and rebinds the given alias to the new key.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001732 /// The boolean returned is a hint for the garbage collector. If true, a key was replaced,
1733 /// is now unreferenced and needs to be collected.
Chris Wailes3877f292021-07-26 19:24:18 -07001734 #[allow(clippy::too_many_arguments)]
Janis Danisevskis66784c42021-01-27 08:40:25 -08001735 pub fn store_new_key(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001736 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001737 key: &KeyDescriptor,
Janis Danisevskis0cabd712021-05-25 11:07:10 -07001738 key_type: KeyType,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001739 params: &[KeyParameter],
Janis Danisevskisf84d0b02022-01-26 14:11:14 -08001740 blob_info: &BlobInfo,
Max Bires8e93d2b2021-01-14 13:17:59 -08001741 cert_info: &CertificateInfo,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001742 metadata: &KeyMetaData,
Max Bires8e93d2b2021-01-14 13:17:59 -08001743 km_uuid: &Uuid,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001744 ) -> Result<KeyIdGuard> {
David Drysdale541846b2024-05-23 13:16:07 +01001745 let _wp = wd::watch("KeystoreDB::store_new_key");
Janis Danisevskis850d4862021-05-05 08:41:14 -07001746
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001747 let (alias, domain, namespace) = match key {
1748 KeyDescriptor { alias: Some(alias), domain: Domain::APP, nspace, blob: None }
1749 | KeyDescriptor { alias: Some(alias), domain: Domain::SELINUX, nspace, blob: None } => {
1750 (alias, key.domain, nspace)
1751 }
1752 _ => {
1753 return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT))
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001754 .context(ks_err!("Need alias and domain must be APP or SELINUX."));
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001755 }
1756 };
David Drysdale7b9ca232024-05-23 18:19:46 +01001757 self.with_transaction(Immediate("TX_store_new_key"), |tx| {
Janis Danisevskis0cabd712021-05-25 11:07:10 -07001758 let key_id = Self::create_key_entry_internal(tx, &domain, namespace, key_type, km_uuid)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001759 .context("Trying to create new key entry.")?;
Janis Danisevskisf84d0b02022-01-26 14:11:14 -08001760 let BlobInfo { blob, metadata: blob_metadata, superseded_blob } = *blob_info;
1761
1762 // In some occasions the key blob is already upgraded during the import.
1763 // In order to make sure it gets properly deleted it is inserted into the
1764 // database here and then immediately replaced by the superseding blob.
1765 // The garbage collector will then subject the blob to deleteKey of the
1766 // KM back end to permanently invalidate the key.
1767 let need_gc = if let Some((blob, blob_metadata)) = superseded_blob {
1768 Self::set_blob_internal(
1769 tx,
1770 key_id.id(),
1771 SubComponentType::KEY_BLOB,
1772 Some(blob),
1773 Some(blob_metadata),
1774 )
1775 .context("Trying to insert superseded key blob.")?;
1776 true
1777 } else {
1778 false
1779 };
1780
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001781 Self::set_blob_internal(
1782 tx,
1783 key_id.id(),
1784 SubComponentType::KEY_BLOB,
1785 Some(blob),
Chris Wailesd5aaaef2021-07-27 16:04:33 -07001786 Some(blob_metadata),
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001787 )
1788 .context("Trying to insert the key blob.")?;
Max Bires8e93d2b2021-01-14 13:17:59 -08001789 if let Some(cert) = &cert_info.cert {
Chris Wailesd5aaaef2021-07-27 16:04:33 -07001790 Self::set_blob_internal(tx, key_id.id(), SubComponentType::CERT, Some(cert), None)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001791 .context("Trying to insert the certificate.")?;
1792 }
Max Bires8e93d2b2021-01-14 13:17:59 -08001793 if let Some(cert_chain) = &cert_info.cert_chain {
Janis Danisevskis377d1002021-01-27 19:07:48 -08001794 Self::set_blob_internal(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001795 tx,
1796 key_id.id(),
1797 SubComponentType::CERT_CHAIN,
Chris Wailesd5aaaef2021-07-27 16:04:33 -07001798 Some(cert_chain),
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001799 None,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001800 )
1801 .context("Trying to insert the certificate chain.")?;
1802 }
1803 Self::insert_keyparameter_internal(tx, &key_id, params)
1804 .context("Trying to insert key parameters.")?;
Janis Danisevskis377d1002021-01-27 19:07:48 -08001805 metadata.store_in_db(key_id.id(), tx).context("Trying to insert key metadata.")?;
Chris Wailesd5aaaef2021-07-27 16:04:33 -07001806 let need_gc = Self::rebind_alias(tx, &key_id, alias, &domain, namespace, key_type)
Janis Danisevskisf84d0b02022-01-26 14:11:14 -08001807 .context("Trying to rebind alias.")?
1808 || need_gc;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001809 Ok(key_id).do_gc(need_gc)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001810 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001811 .context(ks_err!())
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001812 }
1813
Janis Danisevskis377d1002021-01-27 19:07:48 -08001814 /// Store a new certificate
1815 /// The function creates a new key entry, populates the blob field and metadata, and rebinds
1816 /// the given alias to the new cert.
Max Bires8e93d2b2021-01-14 13:17:59 -08001817 pub fn store_new_certificate(
1818 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001819 key: &KeyDescriptor,
Janis Danisevskis0cabd712021-05-25 11:07:10 -07001820 key_type: KeyType,
Max Bires8e93d2b2021-01-14 13:17:59 -08001821 cert: &[u8],
1822 km_uuid: &Uuid,
1823 ) -> Result<KeyIdGuard> {
David Drysdale541846b2024-05-23 13:16:07 +01001824 let _wp = wd::watch("KeystoreDB::store_new_certificate");
Janis Danisevskis850d4862021-05-05 08:41:14 -07001825
Janis Danisevskis377d1002021-01-27 19:07:48 -08001826 let (alias, domain, namespace) = match key {
1827 KeyDescriptor { alias: Some(alias), domain: Domain::APP, nspace, blob: None }
1828 | KeyDescriptor { alias: Some(alias), domain: Domain::SELINUX, nspace, blob: None } => {
1829 (alias, key.domain, nspace)
1830 }
1831 _ => {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001832 return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT))
1833 .context(ks_err!("Need alias and domain must be APP or SELINUX."));
Janis Danisevskis377d1002021-01-27 19:07:48 -08001834 }
1835 };
David Drysdale7b9ca232024-05-23 18:19:46 +01001836 self.with_transaction(Immediate("TX_store_new_certificate"), |tx| {
Janis Danisevskis0cabd712021-05-25 11:07:10 -07001837 let key_id = Self::create_key_entry_internal(tx, &domain, namespace, key_type, km_uuid)
Janis Danisevskis377d1002021-01-27 19:07:48 -08001838 .context("Trying to create new key entry.")?;
1839
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001840 Self::set_blob_internal(
1841 tx,
1842 key_id.id(),
1843 SubComponentType::CERT_CHAIN,
1844 Some(cert),
1845 None,
1846 )
1847 .context("Trying to insert certificate.")?;
Janis Danisevskis377d1002021-01-27 19:07:48 -08001848
1849 let mut metadata = KeyMetaData::new();
1850 metadata.add(KeyMetaEntry::CreationDate(
1851 DateTime::now().context("Trying to make creation time.")?,
1852 ));
1853
1854 metadata.store_in_db(key_id.id(), tx).context("Trying to insert key metadata.")?;
1855
Chris Wailesd5aaaef2021-07-27 16:04:33 -07001856 let need_gc = Self::rebind_alias(tx, &key_id, alias, &domain, namespace, key_type)
Janis Danisevskis377d1002021-01-27 19:07:48 -08001857 .context("Trying to rebind alias.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001858 Ok(key_id).do_gc(need_gc)
Janis Danisevskis377d1002021-01-27 19:07:48 -08001859 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001860 .context(ks_err!())
Janis Danisevskis377d1002021-01-27 19:07:48 -08001861 }
1862
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001863 // Helper function loading the key_id given the key descriptor
1864 // tuple comprising domain, namespace, and alias.
1865 // Requires a valid transaction.
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001866 fn load_key_entry_id(tx: &Transaction, key: &KeyDescriptor, key_type: KeyType) -> Result<i64> {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001867 let alias = key
1868 .alias
1869 .as_ref()
1870 .map_or_else(|| Err(KsError::sys()), Ok)
1871 .context("In load_key_entry_id: Alias must be specified.")?;
1872 let mut stmt = tx
1873 .prepare(
1874 "SELECT id FROM persistent.keyentry
1875 WHERE
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00001876 key_type = ?
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001877 AND domain = ?
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001878 AND namespace = ?
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001879 AND alias = ?
1880 AND state = ?;",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001881 )
1882 .context("In load_key_entry_id: Failed to select from keyentry table.")?;
1883 let mut rows = stmt
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001884 .query(params![key_type, key.domain.0 as u32, key.nspace, alias, KeyLifeCycle::Live])
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001885 .context("In load_key_entry_id: Failed to read from keyentry table.")?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08001886 db_utils::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001887 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001888 .get(0)
1889 .context("Failed to unpack id.")
1890 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00001891 .context(ks_err!())
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001892 }
1893
1894 /// This helper function completes the access tuple of a key, which is required
1895 /// to perform access control. The strategy depends on the `domain` field in the
1896 /// key descriptor.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001897 /// * Domain::SELINUX: The access tuple is complete and this function only loads
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001898 /// the key_id for further processing.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001899 /// * Domain::APP: Like Domain::SELINUX, but the tuple is completed by `caller_uid`
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001900 /// which serves as the namespace.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001901 /// * Domain::GRANT: The grant table is queried for the `key_id` and the
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001902 /// `access_vector`.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001903 /// * Domain::KEY_ID: The keyentry table is queried for the owning `domain` and
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001904 /// `namespace`.
1905 /// In each case the information returned is sufficient to perform the access
1906 /// check and the key id can be used to load further key artifacts.
1907 fn load_access_tuple(
1908 tx: &Transaction,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001909 key: &KeyDescriptor,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001910 key_type: KeyType,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001911 caller_uid: u32,
1912 ) -> Result<(i64, KeyDescriptor, Option<KeyPermSet>)> {
1913 match key.domain {
1914 // Domain App or SELinux. In this case we load the key_id from
1915 // the keyentry database for further loading of key components.
1916 // We already have the full access tuple to perform access control.
1917 // The only distinction is that we use the caller_uid instead
1918 // of the caller supplied namespace if the domain field is
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001919 // Domain::APP.
1920 Domain::APP | Domain::SELINUX => {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001921 let mut access_key = key.clone();
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001922 if access_key.domain == Domain::APP {
1923 access_key.nspace = caller_uid as i64;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001924 }
Chris Wailesd5aaaef2021-07-27 16:04:33 -07001925 let key_id = Self::load_key_entry_id(tx, &access_key, key_type)
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001926 .with_context(|| format!("With key.domain = {:?}.", access_key.domain))?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001927
1928 Ok((key_id, access_key, None))
1929 }
1930
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001931 // Domain::GRANT. In this case we load the key_id and the access_vector
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001932 // from the grant table.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001933 Domain::GRANT => {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001934 let mut stmt = tx
1935 .prepare(
Janis Danisevskisbf15d732020-12-08 10:35:26 -08001936 "SELECT keyentryid, access_vector FROM persistent.grant
Hasini Gunasinghee70a0ec2021-05-10 21:12:34 +00001937 WHERE grantee = ? AND id = ? AND
1938 (SELECT state FROM persistent.keyentry WHERE id = keyentryid) = ?;",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001939 )
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001940 .context("Domain::GRANT prepare statement failed")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001941 let mut rows = stmt
Hasini Gunasinghee70a0ec2021-05-10 21:12:34 +00001942 .query(params![caller_uid as i64, key.nspace, KeyLifeCycle::Live])
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001943 .context("Domain:Grant: query failed.")?;
1944 let (key_id, access_vector): (i64, i32) =
Janis Danisevskisbf15d732020-12-08 10:35:26 -08001945 db_utils::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001946 let r =
1947 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001948 Ok((
1949 r.get(0).context("Failed to unpack key_id.")?,
1950 r.get(1).context("Failed to unpack access_vector.")?,
1951 ))
1952 })
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001953 .context("Domain::GRANT.")?;
Janis Danisevskis66784c42021-01-27 08:40:25 -08001954 Ok((key_id, key.clone(), Some(access_vector.into())))
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001955 }
1956
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001957 // Domain::KEY_ID. In this case we load the domain and namespace from the
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001958 // keyentry database because we need them for access control.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001959 Domain::KEY_ID => {
Janis Danisevskis45760022021-01-19 16:34:10 -08001960 let (domain, namespace): (Domain, i64) = {
1961 let mut stmt = tx
1962 .prepare(
1963 "SELECT domain, namespace FROM persistent.keyentry
1964 WHERE
1965 id = ?
1966 AND state = ?;",
1967 )
1968 .context("Domain::KEY_ID: prepare statement failed")?;
1969 let mut rows = stmt
1970 .query(params![key.nspace, KeyLifeCycle::Live])
1971 .context("Domain::KEY_ID: query failed.")?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08001972 db_utils::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001973 let r =
1974 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001975 Ok((
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001976 Domain(r.get(0).context("Failed to unpack domain.")?),
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001977 r.get(1).context("Failed to unpack namespace.")?,
1978 ))
1979 })
Janis Danisevskis45760022021-01-19 16:34:10 -08001980 .context("Domain::KEY_ID.")?
1981 };
1982
1983 // We may use a key by id after loading it by grant.
1984 // In this case we have to check if the caller has a grant for this particular
1985 // key. We can skip this if we already know that the caller is the owner.
1986 // But we cannot know this if domain is anything but App. E.g. in the case
1987 // of Domain::SELINUX we have to speculatively check for grants because we have to
1988 // consult the SEPolicy before we know if the caller is the owner.
1989 let access_vector: Option<KeyPermSet> =
1990 if domain != Domain::APP || namespace != caller_uid as i64 {
1991 let access_vector: Option<i32> = tx
1992 .query_row(
1993 "SELECT access_vector FROM persistent.grant
1994 WHERE grantee = ? AND keyentryid = ?;",
1995 params![caller_uid as i64, key.nspace],
1996 |row| row.get(0),
1997 )
1998 .optional()
1999 .context("Domain::KEY_ID: query grant failed.")?;
2000 access_vector.map(|p| p.into())
2001 } else {
2002 None
2003 };
2004
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002005 let key_id = key.nspace;
Janis Danisevskis66784c42021-01-27 08:40:25 -08002006 let mut access_key: KeyDescriptor = key.clone();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002007 access_key.domain = domain;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002008 access_key.nspace = namespace;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002009
Janis Danisevskis45760022021-01-19 16:34:10 -08002010 Ok((key_id, access_key, access_vector))
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002011 }
Rajesh Nyamagoud625e5892022-05-18 01:31:26 +00002012 _ => Err(anyhow!(KsError::Rc(ResponseCode::INVALID_ARGUMENT))),
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002013 }
2014 }
2015
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002016 fn load_blob_components(
2017 key_id: i64,
2018 load_bits: KeyEntryLoadBits,
2019 tx: &Transaction,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002020 ) -> Result<(bool, Option<(Vec<u8>, BlobMetaData)>, Option<Vec<u8>>, Option<Vec<u8>>)> {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002021 let mut stmt = tx
2022 .prepare(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002023 "SELECT MAX(id), subcomponent_type, blob FROM persistent.blobentry
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002024 WHERE keyentryid = ? GROUP BY subcomponent_type;",
2025 )
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002026 .context(ks_err!("prepare statement failed."))?;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002027
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002028 let mut rows = stmt.query(params![key_id]).context(ks_err!("query failed."))?;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002029
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002030 let mut key_blob: Option<(i64, Vec<u8>)> = None;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002031 let mut cert_blob: Option<Vec<u8>> = None;
2032 let mut cert_chain_blob: Option<Vec<u8>> = None;
Janis Danisevskis377d1002021-01-27 19:07:48 -08002033 let mut has_km_blob: bool = false;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002034 db_utils::with_rows_extract_all(&mut rows, |row| {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002035 let sub_type: SubComponentType =
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002036 row.get(1).context("Failed to extract subcomponent_type.")?;
Janis Danisevskis377d1002021-01-27 19:07:48 -08002037 has_km_blob = has_km_blob || sub_type == SubComponentType::KEY_BLOB;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002038 match (sub_type, load_bits.load_public(), load_bits.load_km()) {
2039 (SubComponentType::KEY_BLOB, _, true) => {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002040 key_blob = Some((
2041 row.get(0).context("Failed to extract key blob id.")?,
2042 row.get(2).context("Failed to extract key blob.")?,
2043 ));
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002044 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002045 (SubComponentType::CERT, true, _) => {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002046 cert_blob =
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002047 Some(row.get(2).context("Failed to extract public certificate blob.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002048 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002049 (SubComponentType::CERT_CHAIN, true, _) => {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002050 cert_chain_blob =
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002051 Some(row.get(2).context("Failed to extract certificate chain blob.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002052 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002053 (SubComponentType::CERT, _, _)
2054 | (SubComponentType::CERT_CHAIN, _, _)
2055 | (SubComponentType::KEY_BLOB, _, _) => {}
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002056 _ => Err(KsError::sys()).context("Unknown subcomponent type.")?,
2057 }
2058 Ok(())
2059 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002060 .context(ks_err!())?;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002061
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002062 let blob_info = key_blob.map_or::<Result<_>, _>(Ok(None), |(blob_id, blob)| {
2063 Ok(Some((
2064 blob,
2065 BlobMetaData::load_from_db(blob_id, tx)
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002066 .context(ks_err!("Trying to load blob_metadata."))?,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002067 )))
2068 })?;
2069
2070 Ok((has_km_blob, blob_info, cert_blob, cert_chain_blob))
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002071 }
2072
2073 fn load_key_parameters(key_id: i64, tx: &Transaction) -> Result<Vec<KeyParameter>> {
2074 let mut stmt = tx
2075 .prepare(
2076 "SELECT tag, data, security_level from persistent.keyparameter
2077 WHERE keyentryid = ?;",
2078 )
2079 .context("In load_key_parameters: prepare statement failed.")?;
2080
2081 let mut parameters: Vec<KeyParameter> = Vec::new();
2082
2083 let mut rows =
2084 stmt.query(params![key_id]).context("In load_key_parameters: query failed.")?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002085 db_utils::with_rows_extract_all(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002086 let tag = Tag(row.get(0).context("Failed to read tag.")?);
2087 let sec_level = SecurityLevel(row.get(2).context("Failed to read sec_level.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002088 parameters.push(
Chris Wailesd5aaaef2021-07-27 16:04:33 -07002089 KeyParameter::new_from_sql(tag, &SqlField::new(1, row), sec_level)
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002090 .context("Failed to read KeyParameter.")?,
2091 );
2092 Ok(())
2093 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002094 .context(ks_err!())?;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002095
2096 Ok(parameters)
2097 }
2098
Qi Wub9433b52020-12-01 14:52:46 +08002099 /// Decrements the usage count of a limited use key. This function first checks whether the
2100 /// usage has been exhausted, if not, decreases the usage count. If the usage count reaches
2101 /// zero, the key also gets marked unreferenced and scheduled for deletion.
2102 /// Returns Ok(true) if the key was marked unreferenced as a hint to the garbage collector.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002103 pub fn check_and_update_key_usage_count(&mut self, key_id: i64) -> Result<()> {
David Drysdale541846b2024-05-23 13:16:07 +01002104 let _wp = wd::watch("KeystoreDB::check_and_update_key_usage_count");
Janis Danisevskis850d4862021-05-05 08:41:14 -07002105
David Drysdale7b9ca232024-05-23 18:19:46 +01002106 self.with_transaction(Immediate("TX_check_and_update_key_usage_count"), |tx| {
Qi Wub9433b52020-12-01 14:52:46 +08002107 let limit: Option<i32> = tx
2108 .query_row(
2109 "SELECT data FROM persistent.keyparameter WHERE keyentryid = ? AND tag = ?;",
2110 params![key_id, Tag::USAGE_COUNT_LIMIT.0],
2111 |row| row.get(0),
2112 )
2113 .optional()
2114 .context("Trying to load usage count")?;
2115
2116 let limit = limit
2117 .ok_or(KsError::Km(ErrorCode::INVALID_KEY_BLOB))
2118 .context("The Key no longer exists. Key is exhausted.")?;
2119
2120 tx.execute(
2121 "UPDATE persistent.keyparameter
2122 SET data = data - 1
2123 WHERE keyentryid = ? AND tag = ? AND data > 0;",
2124 params![key_id, Tag::USAGE_COUNT_LIMIT.0],
2125 )
2126 .context("Failed to update key usage count.")?;
2127
2128 match limit {
2129 1 => Self::mark_unreferenced(tx, key_id)
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002130 .map(|need_gc| (need_gc, ()))
Qi Wub9433b52020-12-01 14:52:46 +08002131 .context("Trying to mark limited use key for deletion."),
2132 0 => Err(KsError::Km(ErrorCode::INVALID_KEY_BLOB)).context("Key is exhausted."),
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002133 _ => Ok(()).no_gc(),
Qi Wub9433b52020-12-01 14:52:46 +08002134 }
2135 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002136 .context(ks_err!())
Qi Wub9433b52020-12-01 14:52:46 +08002137 }
2138
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002139 /// Load a key entry by the given key descriptor.
2140 /// It uses the `check_permission` callback to verify if the access is allowed
2141 /// given the key access tuple read from the database using `load_access_tuple`.
2142 /// With `load_bits` the caller may specify which blobs shall be loaded from
2143 /// the blob database.
2144 pub fn load_key_entry(
2145 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002146 key: &KeyDescriptor,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002147 key_type: KeyType,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002148 load_bits: KeyEntryLoadBits,
2149 caller_uid: u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002150 check_permission: impl Fn(&KeyDescriptor, Option<KeyPermSet>) -> Result<()>,
2151 ) -> Result<(KeyIdGuard, KeyEntry)> {
David Drysdale541846b2024-05-23 13:16:07 +01002152 let _wp = wd::watch("KeystoreDB::load_key_entry");
Janis Danisevskis850d4862021-05-05 08:41:14 -07002153
Janis Danisevskis66784c42021-01-27 08:40:25 -08002154 loop {
2155 match self.load_key_entry_internal(
2156 key,
2157 key_type,
2158 load_bits,
2159 caller_uid,
2160 &check_permission,
2161 ) {
2162 Ok(result) => break Ok(result),
2163 Err(e) => {
2164 if Self::is_locked_error(&e) {
David Drysdale115c4722024-04-15 14:11:52 +01002165 std::thread::sleep(DB_BUSY_RETRY_INTERVAL);
Janis Danisevskis66784c42021-01-27 08:40:25 -08002166 continue;
2167 } else {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002168 return Err(e).context(ks_err!());
Janis Danisevskis66784c42021-01-27 08:40:25 -08002169 }
2170 }
2171 }
2172 }
2173 }
2174
2175 fn load_key_entry_internal(
2176 &mut self,
2177 key: &KeyDescriptor,
2178 key_type: KeyType,
2179 load_bits: KeyEntryLoadBits,
2180 caller_uid: u32,
2181 check_permission: &impl Fn(&KeyDescriptor, Option<KeyPermSet>) -> Result<()>,
Janis Danisevskisaec14592020-11-12 09:41:49 -08002182 ) -> Result<(KeyIdGuard, KeyEntry)> {
2183 // KEY ID LOCK 1/2
2184 // If we got a key descriptor with a key id we can get the lock right away.
2185 // Otherwise we have to defer it until we know the key id.
2186 let key_id_guard = match key.domain {
2187 Domain::KEY_ID => Some(KEY_ID_LOCK.get(key.nspace)),
2188 _ => None,
2189 };
2190
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002191 let tx = self
2192 .conn
Janis Danisevskisaec14592020-11-12 09:41:49 -08002193 .unchecked_transaction()
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002194 .context(ks_err!("Failed to initialize transaction."))?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002195
2196 // Load the key_id and complete the access control tuple.
2197 let (key_id, access_key_descriptor, access_vector) =
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002198 Self::load_access_tuple(&tx, key, key_type, caller_uid).context(ks_err!())?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002199
2200 // Perform access control. It is vital that we return here if the permission is denied.
2201 // So do not touch that '?' at the end.
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002202 check_permission(&access_key_descriptor, access_vector).context(ks_err!())?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002203
Janis Danisevskisaec14592020-11-12 09:41:49 -08002204 // KEY ID LOCK 2/2
2205 // If we did not get a key id lock by now, it was because we got a key descriptor
2206 // without a key id. At this point we got the key id, so we can try and get a lock.
2207 // However, we cannot block here, because we are in the middle of the transaction.
2208 // So first we try to get the lock non blocking. If that fails, we roll back the
2209 // transaction and block until we get the lock. After we successfully got the lock,
2210 // we start a new transaction and load the access tuple again.
2211 //
2212 // We don't need to perform access control again, because we already established
2213 // that the caller had access to the given key. But we need to make sure that the
2214 // key id still exists. So we have to load the key entry by key id this time.
2215 let (key_id_guard, tx) = match key_id_guard {
2216 None => match KEY_ID_LOCK.try_get(key_id) {
2217 None => {
2218 // Roll back the transaction.
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002219 tx.rollback().context(ks_err!("Failed to roll back transaction."))?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002220
Janis Danisevskisaec14592020-11-12 09:41:49 -08002221 // Block until we have a key id lock.
2222 let key_id_guard = KEY_ID_LOCK.get(key_id);
2223
2224 // Create a new transaction.
Janis Danisevskis66784c42021-01-27 08:40:25 -08002225 let tx = self
2226 .conn
2227 .unchecked_transaction()
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002228 .context(ks_err!("Failed to initialize transaction."))?;
Janis Danisevskisaec14592020-11-12 09:41:49 -08002229
2230 Self::load_access_tuple(
2231 &tx,
2232 // This time we have to load the key by the retrieved key id, because the
2233 // alias may have been rebound after we rolled back the transaction.
Janis Danisevskis66784c42021-01-27 08:40:25 -08002234 &KeyDescriptor {
Janis Danisevskisaec14592020-11-12 09:41:49 -08002235 domain: Domain::KEY_ID,
2236 nspace: key_id,
2237 ..Default::default()
2238 },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002239 key_type,
Janis Danisevskisaec14592020-11-12 09:41:49 -08002240 caller_uid,
2241 )
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002242 .context(ks_err!("(deferred key lock)"))?;
Janis Danisevskisaec14592020-11-12 09:41:49 -08002243 (key_id_guard, tx)
2244 }
2245 Some(l) => (l, tx),
2246 },
2247 Some(key_id_guard) => (key_id_guard, tx),
2248 };
2249
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002250 let key_entry =
2251 Self::load_key_components(&tx, load_bits, key_id_guard.id()).context(ks_err!())?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002252
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002253 tx.commit().context(ks_err!("Failed to commit transaction."))?;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002254
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002255 Ok((key_id_guard, key_entry))
2256 }
2257
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002258 fn mark_unreferenced(tx: &Transaction, key_id: i64) -> Result<bool> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002259 let updated = tx
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002260 .execute("DELETE FROM persistent.keyentry WHERE id = ?;", params![key_id])
2261 .context("Trying to delete keyentry.")?;
2262 tx.execute("DELETE FROM persistent.keymetadata WHERE keyentryid = ?;", params![key_id])
2263 .context("Trying to delete keymetadata.")?;
2264 tx.execute("DELETE FROM persistent.keyparameter WHERE keyentryid = ?;", params![key_id])
2265 .context("Trying to delete keyparameters.")?;
2266 tx.execute("DELETE FROM persistent.grant WHERE keyentryid = ?;", params![key_id])
2267 .context("Trying to delete grants.")?;
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002268 Ok(updated != 0)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002269 }
2270
2271 /// Marks the given key as unreferenced and removes all of the grants to this key.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002272 /// Returns Ok(true) if a key was marked unreferenced as a hint for the garbage collector.
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002273 pub fn unbind_key(
2274 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002275 key: &KeyDescriptor,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002276 key_type: KeyType,
2277 caller_uid: u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002278 check_permission: impl Fn(&KeyDescriptor, Option<KeyPermSet>) -> Result<()>,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002279 ) -> Result<()> {
David Drysdale541846b2024-05-23 13:16:07 +01002280 let _wp = wd::watch("KeystoreDB::unbind_key");
Janis Danisevskis850d4862021-05-05 08:41:14 -07002281
David Drysdale7b9ca232024-05-23 18:19:46 +01002282 self.with_transaction(Immediate("TX_unbind_key"), |tx| {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002283 let (key_id, access_key_descriptor, access_vector) =
2284 Self::load_access_tuple(tx, key, key_type, caller_uid)
2285 .context("Trying to get access tuple.")?;
2286
2287 // Perform access control. It is vital that we return here if the permission is denied.
2288 // So do not touch that '?' at the end.
2289 check_permission(&access_key_descriptor, access_vector)
2290 .context("While checking permission.")?;
2291
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002292 Self::mark_unreferenced(tx, key_id)
2293 .map(|need_gc| (need_gc, ()))
2294 .context("Trying to mark the key unreferenced.")
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002295 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002296 .context(ks_err!())
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002297 }
2298
Max Bires8e93d2b2021-01-14 13:17:59 -08002299 fn get_key_km_uuid(tx: &Transaction, key_id: i64) -> Result<Uuid> {
2300 tx.query_row(
2301 "SELECT km_uuid FROM persistent.keyentry WHERE id = ?",
2302 params![key_id],
2303 |row| row.get(0),
2304 )
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002305 .context(ks_err!())
Max Bires8e93d2b2021-01-14 13:17:59 -08002306 }
2307
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002308 /// Delete all artifacts belonging to the namespace given by the domain-namespace tuple.
2309 /// This leaves all of the blob entries orphaned for subsequent garbage collection.
2310 pub fn unbind_keys_for_namespace(&mut self, domain: Domain, namespace: i64) -> Result<()> {
David Drysdale541846b2024-05-23 13:16:07 +01002311 let _wp = wd::watch("KeystoreDB::unbind_keys_for_namespace");
Janis Danisevskis850d4862021-05-05 08:41:14 -07002312
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002313 if !(domain == Domain::APP || domain == Domain::SELINUX) {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002314 return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT)).context(ks_err!());
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002315 }
David Drysdale7b9ca232024-05-23 18:19:46 +01002316 self.with_transaction(Immediate("TX_unbind_keys_for_namespace"), |tx| {
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002317 tx.execute(
2318 "DELETE FROM persistent.keymetadata
2319 WHERE keyentryid IN (
2320 SELECT id FROM persistent.keyentry
Tri Vo0346bbe2023-05-12 14:16:31 -04002321 WHERE domain = ? AND namespace = ? AND key_type = ?
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002322 );",
Tri Vo0346bbe2023-05-12 14:16:31 -04002323 params![domain.0, namespace, KeyType::Client],
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002324 )
2325 .context("Trying to delete keymetadata.")?;
2326 tx.execute(
2327 "DELETE FROM persistent.keyparameter
2328 WHERE keyentryid IN (
2329 SELECT id FROM persistent.keyentry
Tri Vo0346bbe2023-05-12 14:16:31 -04002330 WHERE domain = ? AND namespace = ? AND key_type = ?
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002331 );",
Tri Vo0346bbe2023-05-12 14:16:31 -04002332 params![domain.0, namespace, KeyType::Client],
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002333 )
2334 .context("Trying to delete keyparameters.")?;
2335 tx.execute(
2336 "DELETE FROM persistent.grant
2337 WHERE keyentryid IN (
2338 SELECT id FROM persistent.keyentry
Tri Vo0346bbe2023-05-12 14:16:31 -04002339 WHERE domain = ? AND namespace = ? AND key_type = ?
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002340 );",
Tri Vo0346bbe2023-05-12 14:16:31 -04002341 params![domain.0, namespace, KeyType::Client],
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002342 )
2343 .context("Trying to delete grants.")?;
2344 tx.execute(
Janis Danisevskisb146f312021-05-06 15:05:45 -07002345 "DELETE FROM persistent.keyentry
Tri Vo0346bbe2023-05-12 14:16:31 -04002346 WHERE domain = ? AND namespace = ? AND key_type = ?;",
2347 params![domain.0, namespace, KeyType::Client],
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002348 )
2349 .context("Trying to delete keyentry.")?;
2350 Ok(()).need_gc()
2351 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002352 .context(ks_err!())
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002353 }
2354
Janis Danisevskis3cba10d2021-05-06 17:02:19 -07002355 fn cleanup_unreferenced(tx: &Transaction) -> Result<()> {
David Drysdale541846b2024-05-23 13:16:07 +01002356 let _wp = wd::watch("KeystoreDB::cleanup_unreferenced");
Janis Danisevskis3cba10d2021-05-06 17:02:19 -07002357 {
2358 tx.execute(
2359 "DELETE FROM persistent.keymetadata
2360 WHERE keyentryid IN (
2361 SELECT id FROM persistent.keyentry
2362 WHERE state = ?
2363 );",
2364 params![KeyLifeCycle::Unreferenced],
2365 )
2366 .context("Trying to delete keymetadata.")?;
2367 tx.execute(
2368 "DELETE FROM persistent.keyparameter
2369 WHERE keyentryid IN (
2370 SELECT id FROM persistent.keyentry
2371 WHERE state = ?
2372 );",
2373 params![KeyLifeCycle::Unreferenced],
2374 )
2375 .context("Trying to delete keyparameters.")?;
2376 tx.execute(
2377 "DELETE FROM persistent.grant
2378 WHERE keyentryid IN (
2379 SELECT id FROM persistent.keyentry
2380 WHERE state = ?
2381 );",
2382 params![KeyLifeCycle::Unreferenced],
2383 )
2384 .context("Trying to delete grants.")?;
2385 tx.execute(
2386 "DELETE FROM persistent.keyentry
2387 WHERE state = ?;",
2388 params![KeyLifeCycle::Unreferenced],
2389 )
2390 .context("Trying to delete keyentry.")?;
2391 Result::<()>::Ok(())
2392 }
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002393 .context(ks_err!())
Janis Danisevskis3cba10d2021-05-06 17:02:19 -07002394 }
2395
Eric Biggers9f7ebeb2024-06-20 14:59:32 +00002396 /// Deletes all keys for the given user, including both client keys and super keys.
2397 pub fn unbind_keys_for_user(&mut self, user_id: u32) -> Result<()> {
David Drysdale541846b2024-05-23 13:16:07 +01002398 let _wp = wd::watch("KeystoreDB::unbind_keys_for_user");
Janis Danisevskis850d4862021-05-05 08:41:14 -07002399
David Drysdale7b9ca232024-05-23 18:19:46 +01002400 self.with_transaction(Immediate("TX_unbind_keys_for_user"), |tx| {
Hasini Gunasingheda895552021-01-27 19:34:37 +00002401 let mut stmt = tx
2402 .prepare(&format!(
2403 "SELECT id from persistent.keyentry
2404 WHERE (
2405 key_type = ?
2406 AND domain = ?
2407 AND cast ( (namespace/{aid_user_offset}) as int) = ?
2408 AND state = ?
2409 ) OR (
2410 key_type = ?
2411 AND namespace = ?
Hasini Gunasingheda895552021-01-27 19:34:37 +00002412 AND state = ?
2413 );",
2414 aid_user_offset = AID_USER_OFFSET
2415 ))
2416 .context(concat!(
2417 "In unbind_keys_for_user. ",
2418 "Failed to prepare the query to find the keys created by apps."
2419 ))?;
2420
2421 let mut rows = stmt
2422 .query(params![
2423 // WHERE client key:
2424 KeyType::Client,
2425 Domain::APP.0 as u32,
2426 user_id,
2427 KeyLifeCycle::Live,
2428 // OR super key:
2429 KeyType::Super,
2430 user_id,
Hasini Gunasingheda895552021-01-27 19:34:37 +00002431 KeyLifeCycle::Live
2432 ])
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002433 .context(ks_err!("Failed to query the keys created by apps."))?;
Hasini Gunasingheda895552021-01-27 19:34:37 +00002434
2435 let mut key_ids: Vec<i64> = Vec::new();
2436 db_utils::with_rows_extract_all(&mut rows, |row| {
2437 key_ids
2438 .push(row.get(0).context("Failed to read key id of a key created by an app.")?);
2439 Ok(())
2440 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002441 .context(ks_err!())?;
Hasini Gunasingheda895552021-01-27 19:34:37 +00002442
2443 let mut notify_gc = false;
2444 for key_id in key_ids {
Chris Wailesd5aaaef2021-07-27 16:04:33 -07002445 notify_gc = Self::mark_unreferenced(tx, key_id)
Hasini Gunasingheda895552021-01-27 19:34:37 +00002446 .context("In unbind_keys_for_user.")?
2447 || notify_gc;
2448 }
2449 Ok(()).do_gc(notify_gc)
2450 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002451 .context(ks_err!())
Hasini Gunasingheda895552021-01-27 19:34:37 +00002452 }
2453
Eric Biggersb0478cf2023-10-27 03:55:29 +00002454 /// Deletes all auth-bound keys, i.e. keys that require user authentication, for the given user.
2455 /// This runs when the user's lock screen is being changed to Swipe or None.
2456 ///
2457 /// This intentionally does *not* delete keys that require that the device be unlocked, unless
2458 /// such keys also require user authentication. Keystore's concept of user authentication is
2459 /// fairly strong, and it requires that keys that require authentication be deleted as soon as
2460 /// authentication is no longer possible. In contrast, keys that just require that the device
2461 /// be unlocked should remain usable when the lock screen is set to Swipe or None, as the device
2462 /// is always considered "unlocked" in that case.
2463 pub fn unbind_auth_bound_keys_for_user(&mut self, user_id: u32) -> Result<()> {
David Drysdale541846b2024-05-23 13:16:07 +01002464 let _wp = wd::watch("KeystoreDB::unbind_auth_bound_keys_for_user");
Eric Biggersb0478cf2023-10-27 03:55:29 +00002465
David Drysdale7b9ca232024-05-23 18:19:46 +01002466 self.with_transaction(Immediate("TX_unbind_auth_bound_keys_for_user"), |tx| {
Eric Biggersb0478cf2023-10-27 03:55:29 +00002467 let mut stmt = tx
2468 .prepare(&format!(
2469 "SELECT id from persistent.keyentry
2470 WHERE key_type = ?
2471 AND domain = ?
2472 AND cast ( (namespace/{aid_user_offset}) as int) = ?
2473 AND state = ?;",
2474 aid_user_offset = AID_USER_OFFSET
2475 ))
2476 .context(concat!(
2477 "In unbind_auth_bound_keys_for_user. ",
2478 "Failed to prepare the query to find the keys created by apps."
2479 ))?;
2480
2481 let mut rows = stmt
2482 .query(params![KeyType::Client, Domain::APP.0 as u32, user_id, KeyLifeCycle::Live,])
2483 .context(ks_err!("Failed to query the keys created by apps."))?;
2484
2485 let mut key_ids: Vec<i64> = Vec::new();
2486 db_utils::with_rows_extract_all(&mut rows, |row| {
2487 key_ids
2488 .push(row.get(0).context("Failed to read key id of a key created by an app.")?);
2489 Ok(())
2490 })
2491 .context(ks_err!())?;
2492
2493 let mut notify_gc = false;
2494 let mut num_unbound = 0;
2495 for key_id in key_ids {
2496 // Load the key parameters and filter out non-auth-bound keys. To identify
2497 // auth-bound keys, use the presence of UserSecureID. The absence of NoAuthRequired
2498 // could also be used, but UserSecureID is what Keystore treats as authoritative
2499 // when actually enforcing the key parameters (it might not matter, though).
2500 let params = Self::load_key_parameters(key_id, tx)
2501 .context("Failed to load key parameters.")?;
2502 let is_auth_bound_key = params.iter().any(|kp| {
2503 matches!(kp.key_parameter_value(), KeyParameterValue::UserSecureID(_))
2504 });
2505 if is_auth_bound_key {
2506 notify_gc = Self::mark_unreferenced(tx, key_id)
2507 .context("In unbind_auth_bound_keys_for_user.")?
2508 || notify_gc;
2509 num_unbound += 1;
2510 }
2511 }
2512 log::info!("Deleting {num_unbound} auth-bound keys for user {user_id}");
2513 Ok(()).do_gc(notify_gc)
2514 })
2515 .context(ks_err!())
2516 }
2517
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002518 fn load_key_components(
2519 tx: &Transaction,
2520 load_bits: KeyEntryLoadBits,
2521 key_id: i64,
2522 ) -> Result<KeyEntry> {
Chris Wailesd5aaaef2021-07-27 16:04:33 -07002523 let metadata = KeyMetaData::load_from_db(key_id, tx).context("In load_key_components.")?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002524
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002525 let (has_km_blob, key_blob_info, cert_blob, cert_chain_blob) =
Chris Wailesd5aaaef2021-07-27 16:04:33 -07002526 Self::load_blob_components(key_id, load_bits, tx).context("In load_key_components.")?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002527
Chris Wailesd5aaaef2021-07-27 16:04:33 -07002528 let parameters = Self::load_key_parameters(key_id, tx)
Max Bires8e93d2b2021-01-14 13:17:59 -08002529 .context("In load_key_components: Trying to load key parameters.")?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002530
Chris Wailesd5aaaef2021-07-27 16:04:33 -07002531 let km_uuid = Self::get_key_km_uuid(tx, key_id)
Max Bires8e93d2b2021-01-14 13:17:59 -08002532 .context("In load_key_components: Trying to get KM uuid.")?;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002533
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002534 Ok(KeyEntry {
2535 id: key_id,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002536 key_blob_info,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002537 cert: cert_blob,
2538 cert_chain: cert_chain_blob,
Max Bires8e93d2b2021-01-14 13:17:59 -08002539 km_uuid,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002540 parameters,
2541 metadata,
Janis Danisevskis377d1002021-01-27 19:07:48 -08002542 pure_cert: !has_km_blob,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002543 })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002544 }
2545
Eran Messeri24f31972023-01-25 17:00:33 +00002546 /// Returns a list of KeyDescriptors in the selected domain/namespace whose
2547 /// aliases are greater than the specified 'start_past_alias'. If no value
2548 /// is provided, returns all KeyDescriptors.
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002549 /// The key descriptors will have the domain, nspace, and alias field set.
Eran Messeri24f31972023-01-25 17:00:33 +00002550 /// The returned list will be sorted by alias.
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002551 /// Domain must be APP or SELINUX, the caller must make sure of that.
Eran Messeri24f31972023-01-25 17:00:33 +00002552 pub fn list_past_alias(
Janis Danisevskis18313832021-05-17 13:30:32 -07002553 &mut self,
2554 domain: Domain,
2555 namespace: i64,
2556 key_type: KeyType,
Eran Messeri24f31972023-01-25 17:00:33 +00002557 start_past_alias: Option<&str>,
Janis Danisevskis18313832021-05-17 13:30:32 -07002558 ) -> Result<Vec<KeyDescriptor>> {
David Drysdale541846b2024-05-23 13:16:07 +01002559 let _wp = wd::watch("KeystoreDB::list_past_alias");
Janis Danisevskis850d4862021-05-05 08:41:14 -07002560
Eran Messeri24f31972023-01-25 17:00:33 +00002561 let query = format!(
2562 "SELECT DISTINCT alias FROM persistent.keyentry
Janis Danisevskis18313832021-05-17 13:30:32 -07002563 WHERE domain = ?
2564 AND namespace = ?
2565 AND alias IS NOT NULL
2566 AND state = ?
Eran Messeri24f31972023-01-25 17:00:33 +00002567 AND key_type = ?
2568 {}
2569 ORDER BY alias ASC;",
2570 if start_past_alias.is_some() { " AND alias > ?" } else { "" }
2571 );
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002572
Eran Messeri24f31972023-01-25 17:00:33 +00002573 self.with_transaction(TransactionBehavior::Deferred, |tx| {
2574 let mut stmt = tx.prepare(&query).context(ks_err!("Failed to prepare."))?;
2575
2576 let mut rows = match start_past_alias {
2577 Some(past_alias) => stmt
2578 .query(params![
2579 domain.0 as u32,
2580 namespace,
2581 KeyLifeCycle::Live,
2582 key_type,
2583 past_alias
2584 ])
2585 .context(ks_err!("Failed to query."))?,
2586 None => stmt
2587 .query(params![domain.0 as u32, namespace, KeyLifeCycle::Live, key_type,])
2588 .context(ks_err!("Failed to query."))?,
2589 };
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002590
Janis Danisevskis66784c42021-01-27 08:40:25 -08002591 let mut descriptors: Vec<KeyDescriptor> = Vec::new();
2592 db_utils::with_rows_extract_all(&mut rows, |row| {
2593 descriptors.push(KeyDescriptor {
2594 domain,
2595 nspace: namespace,
2596 alias: Some(row.get(0).context("Trying to extract alias.")?),
2597 blob: None,
2598 });
2599 Ok(())
2600 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002601 .context(ks_err!("Failed to extract rows."))?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002602 Ok(descriptors).no_gc()
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002603 })
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002604 }
2605
Eran Messeri24f31972023-01-25 17:00:33 +00002606 /// Returns a number of KeyDescriptors in the selected domain/namespace.
2607 /// Domain must be APP or SELINUX, the caller must make sure of that.
2608 pub fn count_keys(
2609 &mut self,
2610 domain: Domain,
2611 namespace: i64,
2612 key_type: KeyType,
2613 ) -> Result<usize> {
David Drysdale541846b2024-05-23 13:16:07 +01002614 let _wp = wd::watch("KeystoreDB::countKeys");
Eran Messeri24f31972023-01-25 17:00:33 +00002615
2616 let num_keys = self.with_transaction(TransactionBehavior::Deferred, |tx| {
2617 tx.query_row(
2618 "SELECT COUNT(alias) FROM persistent.keyentry
2619 WHERE domain = ?
2620 AND namespace = ?
2621 AND alias IS NOT NULL
2622 AND state = ?
2623 AND key_type = ?;",
2624 params![domain.0 as u32, namespace, KeyLifeCycle::Live, key_type],
2625 |row| row.get(0),
2626 )
2627 .context(ks_err!("Failed to count number of keys."))
2628 .no_gc()
2629 })?;
2630 Ok(num_keys)
2631 }
2632
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002633 /// Adds a grant to the grant table.
2634 /// Like `load_key_entry` this function loads the access tuple before
2635 /// it uses the callback for a permission check. Upon success,
2636 /// it inserts the `grantee_uid`, `key_id`, and `access_vector` into the
2637 /// grant table. The new row will have a randomized id, which is used as
2638 /// grant id in the namespace field of the resulting KeyDescriptor.
2639 pub fn grant(
2640 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002641 key: &KeyDescriptor,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002642 caller_uid: u32,
2643 grantee_uid: u32,
2644 access_vector: KeyPermSet,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002645 check_permission: impl Fn(&KeyDescriptor, &KeyPermSet) -> Result<()>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002646 ) -> Result<KeyDescriptor> {
David Drysdale541846b2024-05-23 13:16:07 +01002647 let _wp = wd::watch("KeystoreDB::grant");
Janis Danisevskis850d4862021-05-05 08:41:14 -07002648
David Drysdale7b9ca232024-05-23 18:19:46 +01002649 self.with_transaction(Immediate("TX_grant"), |tx| {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002650 // Load the key_id and complete the access control tuple.
2651 // We ignore the access vector here because grants cannot be granted.
2652 // The access vector returned here expresses the permissions the
2653 // grantee has if key.domain == Domain::GRANT. But this vector
2654 // cannot include the grant permission by design, so there is no way the
2655 // subsequent permission check can pass.
2656 // We could check key.domain == Domain::GRANT and fail early.
2657 // But even if we load the access tuple by grant here, the permission
2658 // check denies the attempt to create a grant by grant descriptor.
2659 let (key_id, access_key_descriptor, _) =
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002660 Self::load_access_tuple(tx, key, KeyType::Client, caller_uid).context(ks_err!())?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002661
Janis Danisevskis66784c42021-01-27 08:40:25 -08002662 // Perform access control. It is vital that we return here if the permission
2663 // was denied. So do not touch that '?' at the end of the line.
2664 // This permission check checks if the caller has the grant permission
2665 // for the given key and in addition to all of the permissions
2666 // expressed in `access_vector`.
2667 check_permission(&access_key_descriptor, &access_vector)
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002668 .context(ks_err!("check_permission failed"))?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002669
Janis Danisevskis66784c42021-01-27 08:40:25 -08002670 let grant_id = if let Some(grant_id) = tx
2671 .query_row(
2672 "SELECT id FROM persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002673 WHERE keyentryid = ? AND grantee = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08002674 params![key_id, grantee_uid],
2675 |row| row.get(0),
2676 )
2677 .optional()
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002678 .context(ks_err!("Failed get optional existing grant id."))?
Janis Danisevskis66784c42021-01-27 08:40:25 -08002679 {
2680 tx.execute(
2681 "UPDATE persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002682 SET access_vector = ?
2683 WHERE id = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08002684 params![i32::from(access_vector), grant_id],
Joel Galenson845f74b2020-09-09 14:11:55 -07002685 )
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002686 .context(ks_err!("Failed to update existing grant."))?;
Janis Danisevskis66784c42021-01-27 08:40:25 -08002687 grant_id
2688 } else {
2689 Self::insert_with_retry(|id| {
2690 tx.execute(
2691 "INSERT INTO persistent.grant (id, grantee, keyentryid, access_vector)
2692 VALUES (?, ?, ?, ?);",
2693 params![id, grantee_uid, key_id, i32::from(access_vector)],
2694 )
2695 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002696 .context(ks_err!())?
Janis Danisevskis66784c42021-01-27 08:40:25 -08002697 };
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002698
Janis Danisevskis66784c42021-01-27 08:40:25 -08002699 Ok(KeyDescriptor { domain: Domain::GRANT, nspace: grant_id, alias: None, blob: None })
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002700 .no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08002701 })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002702 }
2703
2704 /// This function checks permissions like `grant` and `load_key_entry`
2705 /// before removing a grant from the grant table.
2706 pub fn ungrant(
2707 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002708 key: &KeyDescriptor,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002709 caller_uid: u32,
2710 grantee_uid: u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002711 check_permission: impl Fn(&KeyDescriptor) -> Result<()>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002712 ) -> Result<()> {
David Drysdale541846b2024-05-23 13:16:07 +01002713 let _wp = wd::watch("KeystoreDB::ungrant");
Janis Danisevskis850d4862021-05-05 08:41:14 -07002714
David Drysdale7b9ca232024-05-23 18:19:46 +01002715 self.with_transaction(Immediate("TX_ungrant"), |tx| {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002716 // Load the key_id and complete the access control tuple.
2717 // We ignore the access vector here because grants cannot be granted.
2718 let (key_id, access_key_descriptor, _) =
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002719 Self::load_access_tuple(tx, key, KeyType::Client, caller_uid).context(ks_err!())?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002720
Janis Danisevskis66784c42021-01-27 08:40:25 -08002721 // Perform access control. We must return here if the permission
2722 // was denied. So do not touch the '?' at the end of this line.
2723 check_permission(&access_key_descriptor)
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002724 .context(ks_err!("check_permission failed."))?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002725
Janis Danisevskis66784c42021-01-27 08:40:25 -08002726 tx.execute(
2727 "DELETE FROM persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002728 WHERE keyentryid = ? AND grantee = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08002729 params![key_id, grantee_uid],
2730 )
2731 .context("Failed to delete grant.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002732
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002733 Ok(()).no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08002734 })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002735 }
2736
Joel Galenson845f74b2020-09-09 14:11:55 -07002737 // Generates a random id and passes it to the given function, which will
2738 // try to insert it into a database. If that insertion fails, retry;
2739 // otherwise return the id.
2740 fn insert_with_retry(inserter: impl Fn(i64) -> rusqlite::Result<usize>) -> Result<i64> {
2741 loop {
Janis Danisevskiseed69842021-02-18 20:04:10 -08002742 let newid: i64 = match random() {
2743 Self::UNASSIGNED_KEY_ID => continue, // UNASSIGNED_KEY_ID cannot be assigned.
2744 i => i,
2745 };
Joel Galenson845f74b2020-09-09 14:11:55 -07002746 match inserter(newid) {
2747 // If the id already existed, try again.
2748 Err(rusqlite::Error::SqliteFailure(
2749 libsqlite3_sys::Error {
2750 code: libsqlite3_sys::ErrorCode::ConstraintViolation,
2751 extended_code: libsqlite3_sys::SQLITE_CONSTRAINT_UNIQUE,
2752 },
2753 _,
2754 )) => (),
2755 Err(e) => {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002756 return Err(e).context(ks_err!("failed to insert into database."));
Joel Galenson845f74b2020-09-09 14:11:55 -07002757 }
2758 _ => return Ok(newid),
2759 }
2760 }
2761 }
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002762
Matthew Maurerd7815ca2021-05-06 21:58:45 -07002763 /// Insert or replace the auth token based on (user_id, auth_id, auth_type)
2764 pub fn insert_auth_token(&mut self, auth_token: &HardwareAuthToken) {
Eric Biggers19b3b0d2024-01-31 22:46:47 +00002765 self.perboot
2766 .insert_auth_token_entry(AuthTokenEntry::new(auth_token.clone(), BootTime::now()))
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002767 }
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002768
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002769 /// Find the newest auth token matching the given predicate.
Eric Biggersb5613da2024-03-13 19:31:42 +00002770 pub fn find_auth_token_entry<F>(&self, p: F) -> Option<AuthTokenEntry>
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002771 where
2772 F: Fn(&AuthTokenEntry) -> bool,
2773 {
Eric Biggersb5613da2024-03-13 19:31:42 +00002774 self.perboot.find_auth_token_entry(p)
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002775 }
Pavel Grafovf45034a2021-05-12 22:35:45 +01002776
2777 /// Load descriptor of a key by key id
2778 pub fn load_key_descriptor(&mut self, key_id: i64) -> Result<Option<KeyDescriptor>> {
David Drysdale541846b2024-05-23 13:16:07 +01002779 let _wp = wd::watch("KeystoreDB::load_key_descriptor");
Pavel Grafovf45034a2021-05-12 22:35:45 +01002780
2781 self.with_transaction(TransactionBehavior::Deferred, |tx| {
2782 tx.query_row(
2783 "SELECT domain, namespace, alias FROM persistent.keyentry WHERE id = ?;",
2784 params![key_id],
2785 |row| {
2786 Ok(KeyDescriptor {
2787 domain: Domain(row.get(0)?),
2788 nspace: row.get(1)?,
2789 alias: row.get(2)?,
2790 blob: None,
2791 })
2792 },
2793 )
2794 .optional()
2795 .context("Trying to load key descriptor")
2796 .no_gc()
2797 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +00002798 .context(ks_err!())
Pavel Grafovf45034a2021-05-12 22:35:45 +01002799 }
Eran Messeri4dc27b52024-01-09 12:43:31 +00002800
2801 /// Returns a list of app UIDs that have keys authenticated by the given secure_user_id
2802 /// (for the given user_id).
2803 /// This is helpful for finding out which apps will have their keys invalidated when
2804 /// the user changes biometrics enrollment or removes their LSKF.
2805 pub fn get_app_uids_affected_by_sid(
2806 &mut self,
2807 user_id: i32,
2808 secure_user_id: i64,
2809 ) -> Result<Vec<i64>> {
David Drysdale541846b2024-05-23 13:16:07 +01002810 let _wp = wd::watch("KeystoreDB::get_app_uids_affected_by_sid");
Eran Messeri4dc27b52024-01-09 12:43:31 +00002811
David Drysdale7b9ca232024-05-23 18:19:46 +01002812 let ids = self.with_transaction(Immediate("TX_get_app_uids_affected_by_sid"), |tx| {
Eran Messeri4dc27b52024-01-09 12:43:31 +00002813 let mut stmt = tx
2814 .prepare(&format!(
2815 "SELECT id, namespace from persistent.keyentry
2816 WHERE key_type = ?
2817 AND domain = ?
2818 AND cast ( (namespace/{AID_USER_OFFSET}) as int) = ?
2819 AND state = ?;",
2820 ))
2821 .context(concat!(
2822 "In get_app_uids_affected_by_sid, ",
2823 "failed to prepare the query to find the keys created by apps."
2824 ))?;
2825
2826 let mut rows = stmt
2827 .query(params![KeyType::Client, Domain::APP.0 as u32, user_id, KeyLifeCycle::Live,])
2828 .context(ks_err!("Failed to query the keys created by apps."))?;
2829
2830 let mut key_ids_and_app_uids: HashMap<i64, i64> = Default::default();
2831 db_utils::with_rows_extract_all(&mut rows, |row| {
2832 key_ids_and_app_uids.insert(
2833 row.get(0).context("Failed to read key id of a key created by an app.")?,
2834 row.get(1).context("Failed to read the app uid")?,
2835 );
2836 Ok(())
2837 })?;
2838 Ok(key_ids_and_app_uids).no_gc()
2839 })?;
2840 let mut app_uids_affected_by_sid: HashSet<i64> = Default::default();
David Drysdale7b9ca232024-05-23 18:19:46 +01002841 for (key_id, app_uid) in ids {
Eran Messeri4dc27b52024-01-09 12:43:31 +00002842 // Read the key parameters for each key in its own transaction. It is OK to ignore
2843 // an error to get the properties of a particular key since it might have been deleted
2844 // under our feet after the previous transaction concluded. If the key was deleted
2845 // then it is no longer applicable if it was auth-bound or not.
2846 if let Ok(is_key_bound_to_sid) =
David Drysdale7b9ca232024-05-23 18:19:46 +01002847 self.with_transaction(Immediate("TX_get_app_uids_affects_by_sid 2"), |tx| {
Eran Messeri4dc27b52024-01-09 12:43:31 +00002848 let params = Self::load_key_parameters(key_id, tx)
2849 .context("Failed to load key parameters.")?;
2850 // Check if the key is bound to this secure user ID.
2851 let is_key_bound_to_sid = params.iter().any(|kp| {
2852 matches!(
2853 kp.key_parameter_value(),
2854 KeyParameterValue::UserSecureID(sid) if *sid == secure_user_id
2855 )
2856 });
2857 Ok(is_key_bound_to_sid).no_gc()
2858 })
2859 {
2860 if is_key_bound_to_sid {
2861 app_uids_affected_by_sid.insert(app_uid);
2862 }
2863 }
2864 }
2865
2866 let app_uids_vec: Vec<i64> = app_uids_affected_by_sid.into_iter().collect();
2867 Ok(app_uids_vec)
2868 }
Joel Galenson26f4d012020-07-17 14:57:21 -07002869}