blob: f673d17c5db8d7da425b7c29853344b210899d19 [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
Janis Danisevskisb42fc182020-12-15 08:41:27 -080044use crate::impl_metadata; // This is in db_utils.rs
Janis Danisevskis4522c2b2020-11-27 18:04:58 -080045use crate::key_parameter::{KeyParameter, Tag};
Janis Danisevskisc5b210b2020-09-11 13:27:37 -070046use crate::permission::KeyPermSet;
Hasini Gunasingheda895552021-01-27 19:34:37 +000047use crate::utils::{get_current_time_in_seconds, AID_USER_OFFSET};
Janis Danisevskis7e8b4622021-02-13 10:01:59 -080048use crate::{
49 db_utils::{self, SqlField},
50 gc::Gc,
Paul Crowley7a658392021-03-18 17:08:20 -070051 super_key::USER_SUPER_KEY,
52};
53use crate::{
54 error::{Error as KsError, ErrorCode, ResponseCode},
55 super_key::SuperKeyType,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -080056};
Janis Danisevskisb42fc182020-12-15 08:41:27 -080057use anyhow::{anyhow, Context, Result};
Max Bires8e93d2b2021-01-14 13:17:59 -080058use std::{convert::TryFrom, convert::TryInto, ops::Deref, time::SystemTimeError};
Janis Danisevskis60400fe2020-08-26 15:24:42 -070059
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +000060use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
Janis Danisevskis5ed8c532021-01-11 14:19:42 -080061 HardwareAuthToken::HardwareAuthToken,
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +000062 HardwareAuthenticatorType::HardwareAuthenticatorType, SecurityLevel::SecurityLevel,
Janis Danisevskisc3a496b2021-01-05 10:37:22 -080063};
64use android_hardware_security_secureclock::aidl::android::hardware::security::secureclock::{
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +000065 Timestamp::Timestamp,
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +000066};
Janis Danisevskisc5b210b2020-09-11 13:27:37 -070067use android_system_keystore2::aidl::android::system::keystore2::{
Janis Danisevskis04b02832020-10-26 09:21:40 -070068 Domain::Domain, KeyDescriptor::KeyDescriptor,
Janis Danisevskis60400fe2020-08-26 15:24:42 -070069};
Max Bires2b2e6562020-09-22 11:22:36 -070070use android_security_remoteprovisioning::aidl::android::security::remoteprovisioning::{
71 AttestationPoolStatus::AttestationPoolStatus,
72};
73
74use keystore2_crypto::ZVec;
Janis Danisevskisaec14592020-11-12 09:41:49 -080075use lazy_static::lazy_static;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +000076use log::error;
Joel Galenson0891bc12020-07-20 10:37:03 -070077#[cfg(not(test))]
78use rand::prelude::random;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -070079use rusqlite::{
Janis Danisevskisb42fc182020-12-15 08:41:27 -080080 params,
81 types::FromSql,
82 types::FromSqlResult,
83 types::ToSqlOutput,
84 types::{FromSqlError, Value, ValueRef},
Janis Danisevskis5ed8c532021-01-11 14:19:42 -080085 Connection, OptionalExtension, ToSql, Transaction, TransactionBehavior, NO_PARAMS,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -070086};
Max Bires2b2e6562020-09-22 11:22:36 -070087
Janis Danisevskisaec14592020-11-12 09:41:49 -080088use std::{
Janis Danisevskisb42fc182020-12-15 08:41:27 -080089 collections::{HashMap, HashSet},
Janis Danisevskisbf15d732020-12-08 10:35:26 -080090 path::Path,
91 sync::{Condvar, Mutex},
Janis Danisevskisb42fc182020-12-15 08:41:27 -080092 time::{Duration, SystemTime},
Janis Danisevskisaec14592020-11-12 09:41:49 -080093};
Max Bires2b2e6562020-09-22 11:22:36 -070094
Joel Galenson0891bc12020-07-20 10:37:03 -070095#[cfg(test)]
96use tests::random;
Joel Galenson26f4d012020-07-17 14:57:21 -070097
Janis Danisevskisb42fc182020-12-15 08:41:27 -080098impl_metadata!(
99 /// A set of metadata for key entries.
100 #[derive(Debug, Default, Eq, PartialEq)]
101 pub struct KeyMetaData;
102 /// A metadata entry for key entries.
103 #[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
104 pub enum KeyMetaEntry {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800105 /// Date of the creation of the key entry.
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800106 CreationDate(DateTime) with accessor creation_date,
107 /// Expiration date for attestation keys.
108 AttestationExpirationDate(DateTime) with accessor attestation_expiration_date,
Max Bires2b2e6562020-09-22 11:22:36 -0700109 /// CBOR Blob that represents a COSE_Key and associated metadata needed for remote
110 /// provisioning
111 AttestationMacedPublicKey(Vec<u8>) with accessor attestation_maced_public_key,
112 /// Vector representing the raw public key so results from the server can be matched
113 /// to the right entry
114 AttestationRawPubKey(Vec<u8>) with accessor attestation_raw_pub_key,
Paul Crowley8d5b2532021-03-19 10:53:07 -0700115 /// SEC1 public key for ECDH encryption
116 Sec1PublicKey(Vec<u8>) with accessor sec1_public_key,
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800117 // --- ADD NEW META DATA FIELDS HERE ---
118 // For backwards compatibility add new entries only to
119 // end of this list and above this comment.
120 };
121);
122
123impl KeyMetaData {
124 fn load_from_db(key_id: i64, tx: &Transaction) -> Result<Self> {
125 let mut stmt = tx
126 .prepare(
127 "SELECT tag, data from persistent.keymetadata
128 WHERE keyentryid = ?;",
129 )
130 .context("In KeyMetaData::load_from_db: prepare statement failed.")?;
131
132 let mut metadata: HashMap<i64, KeyMetaEntry> = Default::default();
133
134 let mut rows =
135 stmt.query(params![key_id]).context("In KeyMetaData::load_from_db: query failed.")?;
136 db_utils::with_rows_extract_all(&mut rows, |row| {
137 let db_tag: i64 = row.get(0).context("Failed to read tag.")?;
138 metadata.insert(
139 db_tag,
140 KeyMetaEntry::new_from_sql(db_tag, &SqlField::new(1, &row))
141 .context("Failed to read KeyMetaEntry.")?,
142 );
143 Ok(())
144 })
145 .context("In KeyMetaData::load_from_db.")?;
146
147 Ok(Self { data: metadata })
148 }
149
150 fn store_in_db(&self, key_id: i64, tx: &Transaction) -> Result<()> {
151 let mut stmt = tx
152 .prepare(
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000153 "INSERT or REPLACE INTO persistent.keymetadata (keyentryid, tag, data)
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800154 VALUES (?, ?, ?);",
155 )
156 .context("In KeyMetaData::store_in_db: Failed to prepare statement.")?;
157
158 let iter = self.data.iter();
159 for (tag, entry) in iter {
160 stmt.insert(params![key_id, tag, entry,]).with_context(|| {
161 format!("In KeyMetaData::store_in_db: Failed to insert {:?}", entry)
162 })?;
163 }
164 Ok(())
165 }
166}
167
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800168impl_metadata!(
169 /// A set of metadata for key blobs.
170 #[derive(Debug, Default, Eq, PartialEq)]
171 pub struct BlobMetaData;
172 /// A metadata entry for key blobs.
173 #[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
174 pub enum BlobMetaEntry {
175 /// If present, indicates that the blob is encrypted with another key or a key derived
176 /// from a password.
177 EncryptedBy(EncryptedBy) with accessor encrypted_by,
178 /// If the blob is password encrypted this field is set to the
179 /// salt used for the key derivation.
180 Salt(Vec<u8>) with accessor salt,
181 /// If the blob is encrypted, this field is set to the initialization vector.
182 Iv(Vec<u8>) with accessor iv,
183 /// If the blob is encrypted, this field holds the AEAD TAG.
184 AeadTag(Vec<u8>) with accessor aead_tag,
185 /// The uuid of the owning KeyMint instance.
186 KmUuid(Uuid) with accessor km_uuid,
Paul Crowley8d5b2532021-03-19 10:53:07 -0700187 /// If the key is ECDH encrypted, this is the ephemeral public key
188 PublicKey(Vec<u8>) with accessor public_key,
Paul Crowley44c02da2021-04-08 17:04:43 +0000189 /// If the key is encrypted with a MaxBootLevel key, this is the boot level
190 /// of that key
191 MaxBootLevel(i32) with accessor max_boot_level,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800192 // --- ADD NEW META DATA FIELDS HERE ---
193 // For backwards compatibility add new entries only to
194 // end of this list and above this comment.
195 };
196);
197
198impl BlobMetaData {
199 fn load_from_db(blob_id: i64, tx: &Transaction) -> Result<Self> {
200 let mut stmt = tx
201 .prepare(
202 "SELECT tag, data from persistent.blobmetadata
203 WHERE blobentryid = ?;",
204 )
205 .context("In BlobMetaData::load_from_db: prepare statement failed.")?;
206
207 let mut metadata: HashMap<i64, BlobMetaEntry> = Default::default();
208
209 let mut rows =
210 stmt.query(params![blob_id]).context("In BlobMetaData::load_from_db: query failed.")?;
211 db_utils::with_rows_extract_all(&mut rows, |row| {
212 let db_tag: i64 = row.get(0).context("Failed to read tag.")?;
213 metadata.insert(
214 db_tag,
215 BlobMetaEntry::new_from_sql(db_tag, &SqlField::new(1, &row))
216 .context("Failed to read BlobMetaEntry.")?,
217 );
218 Ok(())
219 })
220 .context("In BlobMetaData::load_from_db.")?;
221
222 Ok(Self { data: metadata })
223 }
224
225 fn store_in_db(&self, blob_id: i64, tx: &Transaction) -> Result<()> {
226 let mut stmt = tx
227 .prepare(
228 "INSERT or REPLACE INTO persistent.blobmetadata (blobentryid, tag, data)
229 VALUES (?, ?, ?);",
230 )
231 .context("In BlobMetaData::store_in_db: Failed to prepare statement.")?;
232
233 let iter = self.data.iter();
234 for (tag, entry) in iter {
235 stmt.insert(params![blob_id, tag, entry,]).with_context(|| {
236 format!("In BlobMetaData::store_in_db: Failed to insert {:?}", entry)
237 })?;
238 }
239 Ok(())
240 }
241}
242
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800243/// Indicates the type of the keyentry.
244#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
245pub enum KeyType {
246 /// This is a client key type. These keys are created or imported through the Keystore 2.0
247 /// AIDL interface android.system.keystore2.
248 Client,
249 /// This is a super key type. These keys are created by keystore itself and used to encrypt
250 /// other key blobs to provide LSKF binding.
251 Super,
252 /// This is an attestation key. These keys are created by the remote provisioning mechanism.
253 Attestation,
254}
255
256impl ToSql for KeyType {
257 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
258 Ok(ToSqlOutput::Owned(Value::Integer(match self {
259 KeyType::Client => 0,
260 KeyType::Super => 1,
261 KeyType::Attestation => 2,
262 })))
263 }
264}
265
266impl FromSql for KeyType {
267 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
268 match i64::column_result(value)? {
269 0 => Ok(KeyType::Client),
270 1 => Ok(KeyType::Super),
271 2 => Ok(KeyType::Attestation),
272 v => Err(FromSqlError::OutOfRange(v)),
273 }
274 }
275}
276
Max Bires8e93d2b2021-01-14 13:17:59 -0800277/// Uuid representation that can be stored in the database.
278/// Right now it can only be initialized from SecurityLevel.
279/// Once KeyMint provides a UUID type a corresponding From impl shall be added.
280#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
281pub struct Uuid([u8; 16]);
282
283impl Deref for Uuid {
284 type Target = [u8; 16];
285
286 fn deref(&self) -> &Self::Target {
287 &self.0
288 }
289}
290
291impl From<SecurityLevel> for Uuid {
292 fn from(sec_level: SecurityLevel) -> Self {
293 Self((sec_level.0 as u128).to_be_bytes())
294 }
295}
296
297impl ToSql for Uuid {
298 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
299 self.0.to_sql()
300 }
301}
302
303impl FromSql for Uuid {
304 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
305 let blob = Vec::<u8>::column_result(value)?;
306 if blob.len() != 16 {
307 return Err(FromSqlError::OutOfRange(blob.len() as i64));
308 }
309 let mut arr = [0u8; 16];
310 arr.copy_from_slice(&blob);
311 Ok(Self(arr))
312 }
313}
314
315/// Key entries that are not associated with any KeyMint instance, such as pure certificate
316/// entries are associated with this UUID.
317pub static KEYSTORE_UUID: Uuid = Uuid([
318 0x41, 0xe3, 0xb9, 0xce, 0x27, 0x58, 0x4e, 0x91, 0xbc, 0xfd, 0xa5, 0x5d, 0x91, 0x85, 0xab, 0x11,
319]);
320
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800321/// Indicates how the sensitive part of this key blob is encrypted.
322#[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
323pub enum EncryptedBy {
324 /// The keyblob is encrypted by a user password.
325 /// In the database this variant is represented as NULL.
326 Password,
327 /// The keyblob is encrypted by another key with wrapped key id.
328 /// In the database this variant is represented as non NULL value
329 /// that is convertible to i64, typically NUMERIC.
330 KeyId(i64),
331}
332
333impl ToSql for EncryptedBy {
334 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
335 match self {
336 Self::Password => Ok(ToSqlOutput::Owned(Value::Null)),
337 Self::KeyId(id) => id.to_sql(),
338 }
339 }
340}
341
342impl FromSql for EncryptedBy {
343 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
344 match value {
345 ValueRef::Null => Ok(Self::Password),
346 _ => Ok(Self::KeyId(i64::column_result(value)?)),
347 }
348 }
349}
350
351/// A database representation of wall clock time. DateTime stores unix epoch time as
352/// i64 in milliseconds.
353#[derive(Debug, Copy, Clone, Default, Eq, PartialEq, Ord, PartialOrd)]
354pub struct DateTime(i64);
355
356/// Error type returned when creating DateTime or converting it from and to
357/// SystemTime.
358#[derive(thiserror::Error, Debug)]
359pub enum DateTimeError {
360 /// This is returned when SystemTime and Duration computations fail.
361 #[error(transparent)]
362 SystemTimeError(#[from] SystemTimeError),
363
364 /// This is returned when type conversions fail.
365 #[error(transparent)]
366 TypeConversion(#[from] std::num::TryFromIntError),
367
368 /// This is returned when checked time arithmetic failed.
369 #[error("Time arithmetic failed.")]
370 TimeArithmetic,
371}
372
373impl DateTime {
374 /// Constructs a new DateTime object denoting the current time. This may fail during
375 /// conversion to unix epoch time and during conversion to the internal i64 representation.
376 pub fn now() -> Result<Self, DateTimeError> {
377 Ok(Self(SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_millis().try_into()?))
378 }
379
380 /// Constructs a new DateTime object from milliseconds.
381 pub fn from_millis_epoch(millis: i64) -> Self {
382 Self(millis)
383 }
384
385 /// Returns unix epoch time in milliseconds.
386 pub fn to_millis_epoch(&self) -> i64 {
387 self.0
388 }
389
390 /// Returns unix epoch time in seconds.
391 pub fn to_secs_epoch(&self) -> i64 {
392 self.0 / 1000
393 }
394}
395
396impl ToSql for DateTime {
397 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
398 Ok(ToSqlOutput::Owned(Value::Integer(self.0)))
399 }
400}
401
402impl FromSql for DateTime {
403 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
404 Ok(Self(i64::column_result(value)?))
405 }
406}
407
408impl TryInto<SystemTime> for DateTime {
409 type Error = DateTimeError;
410
411 fn try_into(self) -> Result<SystemTime, Self::Error> {
412 // We want to construct a SystemTime representation equivalent to self, denoting
413 // a point in time THEN, but we cannot set the time directly. We can only construct
414 // a SystemTime denoting NOW, and we can get the duration between EPOCH and NOW,
415 // and between EPOCH and THEN. With this common reference we can construct the
416 // duration between NOW and THEN which we can add to our SystemTime representation
417 // of NOW to get a SystemTime representation of THEN.
418 // Durations can only be positive, thus the if statement below.
419 let now = SystemTime::now();
420 let now_epoch = now.duration_since(SystemTime::UNIX_EPOCH)?;
421 let then_epoch = Duration::from_millis(self.0.try_into()?);
422 Ok(if now_epoch > then_epoch {
423 // then = now - (now_epoch - then_epoch)
424 now_epoch
425 .checked_sub(then_epoch)
426 .and_then(|d| now.checked_sub(d))
427 .ok_or(DateTimeError::TimeArithmetic)?
428 } else {
429 // then = now + (then_epoch - now_epoch)
430 then_epoch
431 .checked_sub(now_epoch)
432 .and_then(|d| now.checked_add(d))
433 .ok_or(DateTimeError::TimeArithmetic)?
434 })
435 }
436}
437
438impl TryFrom<SystemTime> for DateTime {
439 type Error = DateTimeError;
440
441 fn try_from(t: SystemTime) -> Result<Self, Self::Error> {
442 Ok(Self(t.duration_since(SystemTime::UNIX_EPOCH)?.as_millis().try_into()?))
443 }
444}
445
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800446#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone)]
447enum KeyLifeCycle {
448 /// Existing keys have a key ID but are not fully populated yet.
449 /// This is a transient state. If Keystore finds any such keys when it starts up, it must move
450 /// them to Unreferenced for garbage collection.
451 Existing,
452 /// A live key is fully populated and usable by clients.
453 Live,
454 /// An unreferenced key is scheduled for garbage collection.
455 Unreferenced,
456}
457
458impl ToSql for KeyLifeCycle {
459 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
460 match self {
461 Self::Existing => Ok(ToSqlOutput::Owned(Value::Integer(0))),
462 Self::Live => Ok(ToSqlOutput::Owned(Value::Integer(1))),
463 Self::Unreferenced => Ok(ToSqlOutput::Owned(Value::Integer(2))),
464 }
465 }
466}
467
468impl FromSql for KeyLifeCycle {
469 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
470 match i64::column_result(value)? {
471 0 => Ok(KeyLifeCycle::Existing),
472 1 => Ok(KeyLifeCycle::Live),
473 2 => Ok(KeyLifeCycle::Unreferenced),
474 v => Err(FromSqlError::OutOfRange(v)),
475 }
476 }
477}
478
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700479/// Keys have a KeyMint blob component and optional public certificate and
480/// certificate chain components.
481/// KeyEntryLoadBits is a bitmap that indicates to `KeystoreDB::load_key_entry`
482/// which components shall be loaded from the database if present.
Janis Danisevskis66784c42021-01-27 08:40:25 -0800483#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700484pub struct KeyEntryLoadBits(u32);
485
486impl KeyEntryLoadBits {
487 /// Indicate to `KeystoreDB::load_key_entry` that no component shall be loaded.
488 pub const NONE: KeyEntryLoadBits = Self(0);
489 /// Indicate to `KeystoreDB::load_key_entry` that the KeyMint component shall be loaded.
490 pub const KM: KeyEntryLoadBits = Self(1);
491 /// Indicate to `KeystoreDB::load_key_entry` that the Public components shall be loaded.
492 pub const PUBLIC: KeyEntryLoadBits = Self(2);
493 /// Indicate to `KeystoreDB::load_key_entry` that both components shall be loaded.
494 pub const BOTH: KeyEntryLoadBits = Self(3);
495
496 /// Returns true if this object indicates that the public components shall be loaded.
497 pub const fn load_public(&self) -> bool {
498 self.0 & Self::PUBLIC.0 != 0
499 }
500
501 /// Returns true if the object indicates that the KeyMint component shall be loaded.
502 pub const fn load_km(&self) -> bool {
503 self.0 & Self::KM.0 != 0
504 }
505}
506
Janis Danisevskisaec14592020-11-12 09:41:49 -0800507lazy_static! {
508 static ref KEY_ID_LOCK: KeyIdLockDb = KeyIdLockDb::new();
509}
510
511struct KeyIdLockDb {
512 locked_keys: Mutex<HashSet<i64>>,
513 cond_var: Condvar,
514}
515
516/// A locked key. While a guard exists for a given key id, the same key cannot be loaded
517/// from the database a second time. Most functions manipulating the key blob database
518/// require a KeyIdGuard.
519#[derive(Debug)]
520pub struct KeyIdGuard(i64);
521
522impl KeyIdLockDb {
523 fn new() -> Self {
524 Self { locked_keys: Mutex::new(HashSet::new()), cond_var: Condvar::new() }
525 }
526
527 /// This function blocks until an exclusive lock for the given key entry id can
528 /// be acquired. It returns a guard object, that represents the lifecycle of the
529 /// acquired lock.
530 pub fn get(&self, key_id: i64) -> KeyIdGuard {
531 let mut locked_keys = self.locked_keys.lock().unwrap();
532 while locked_keys.contains(&key_id) {
533 locked_keys = self.cond_var.wait(locked_keys).unwrap();
534 }
535 locked_keys.insert(key_id);
536 KeyIdGuard(key_id)
537 }
538
539 /// This function attempts to acquire an exclusive lock on a given key id. If the
540 /// given key id is already taken the function returns None immediately. If a lock
541 /// can be acquired this function returns a guard object, that represents the
542 /// lifecycle of the acquired lock.
543 pub fn try_get(&self, key_id: i64) -> Option<KeyIdGuard> {
544 let mut locked_keys = self.locked_keys.lock().unwrap();
545 if locked_keys.insert(key_id) {
546 Some(KeyIdGuard(key_id))
547 } else {
548 None
549 }
550 }
551}
552
553impl KeyIdGuard {
554 /// Get the numeric key id of the locked key.
555 pub fn id(&self) -> i64 {
556 self.0
557 }
558}
559
560impl Drop for KeyIdGuard {
561 fn drop(&mut self) {
562 let mut locked_keys = KEY_ID_LOCK.locked_keys.lock().unwrap();
563 locked_keys.remove(&self.0);
Janis Danisevskis7fd53582020-11-23 13:40:34 -0800564 drop(locked_keys);
Janis Danisevskisaec14592020-11-12 09:41:49 -0800565 KEY_ID_LOCK.cond_var.notify_all();
566 }
567}
568
Max Bires8e93d2b2021-01-14 13:17:59 -0800569/// This type represents a certificate and certificate chain entry for a key.
Max Bires2b2e6562020-09-22 11:22:36 -0700570#[derive(Debug, Default)]
Max Bires8e93d2b2021-01-14 13:17:59 -0800571pub struct CertificateInfo {
572 cert: Option<Vec<u8>>,
573 cert_chain: Option<Vec<u8>>,
574}
575
576impl CertificateInfo {
577 /// Constructs a new CertificateInfo object from `cert` and `cert_chain`
578 pub fn new(cert: Option<Vec<u8>>, cert_chain: Option<Vec<u8>>) -> Self {
579 Self { cert, cert_chain }
580 }
581
582 /// Take the cert
583 pub fn take_cert(&mut self) -> Option<Vec<u8>> {
584 self.cert.take()
585 }
586
587 /// Take the cert chain
588 pub fn take_cert_chain(&mut self) -> Option<Vec<u8>> {
589 self.cert_chain.take()
590 }
591}
592
Max Bires2b2e6562020-09-22 11:22:36 -0700593/// This type represents a certificate chain with a private key corresponding to the leaf
594/// 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 -0700595pub struct CertificateChain {
Max Bires97f96812021-02-23 23:44:57 -0800596 /// A KM key blob
597 pub private_key: ZVec,
598 /// A batch cert for private_key
599 pub batch_cert: Vec<u8>,
600 /// A full certificate chain from root signing authority to private_key, including batch_cert
601 /// for convenience.
602 pub cert_chain: Vec<u8>,
Max Bires2b2e6562020-09-22 11:22:36 -0700603}
604
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700605/// This type represents a Keystore 2.0 key entry.
606/// An entry has a unique `id` by which it can be found in the database.
607/// It has a security level field, key parameters, and three optional fields
608/// for the KeyMint blob, public certificate and a public certificate chain.
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800609#[derive(Debug, Default, Eq, PartialEq)]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700610pub struct KeyEntry {
611 id: i64,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800612 key_blob_info: Option<(Vec<u8>, BlobMetaData)>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700613 cert: Option<Vec<u8>>,
614 cert_chain: Option<Vec<u8>>,
Max Bires8e93d2b2021-01-14 13:17:59 -0800615 km_uuid: Uuid,
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700616 parameters: Vec<KeyParameter>,
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800617 metadata: KeyMetaData,
Janis Danisevskis377d1002021-01-27 19:07:48 -0800618 pure_cert: bool,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700619}
620
621impl KeyEntry {
622 /// Returns the unique id of the Key entry.
623 pub fn id(&self) -> i64 {
624 self.id
625 }
626 /// Exposes the optional KeyMint blob.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800627 pub fn key_blob_info(&self) -> &Option<(Vec<u8>, BlobMetaData)> {
628 &self.key_blob_info
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700629 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800630 /// Extracts the Optional KeyMint blob including its metadata.
631 pub fn take_key_blob_info(&mut self) -> Option<(Vec<u8>, BlobMetaData)> {
632 self.key_blob_info.take()
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700633 }
634 /// Exposes the optional public certificate.
635 pub fn cert(&self) -> &Option<Vec<u8>> {
636 &self.cert
637 }
638 /// Extracts the optional public certificate.
639 pub fn take_cert(&mut self) -> Option<Vec<u8>> {
640 self.cert.take()
641 }
642 /// Exposes the optional public certificate chain.
643 pub fn cert_chain(&self) -> &Option<Vec<u8>> {
644 &self.cert_chain
645 }
646 /// Extracts the optional public certificate_chain.
647 pub fn take_cert_chain(&mut self) -> Option<Vec<u8>> {
648 self.cert_chain.take()
649 }
Max Bires8e93d2b2021-01-14 13:17:59 -0800650 /// Returns the uuid of the owning KeyMint instance.
651 pub fn km_uuid(&self) -> &Uuid {
652 &self.km_uuid
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700653 }
Janis Danisevskis04b02832020-10-26 09:21:40 -0700654 /// Exposes the key parameters of this key entry.
655 pub fn key_parameters(&self) -> &Vec<KeyParameter> {
656 &self.parameters
657 }
658 /// Consumes this key entry and extracts the keyparameters from it.
659 pub fn into_key_parameters(self) -> Vec<KeyParameter> {
660 self.parameters
661 }
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800662 /// Exposes the key metadata of this key entry.
663 pub fn metadata(&self) -> &KeyMetaData {
664 &self.metadata
665 }
Janis Danisevskis377d1002021-01-27 19:07:48 -0800666 /// This returns true if the entry is a pure certificate entry with no
667 /// private key component.
668 pub fn pure_cert(&self) -> bool {
669 self.pure_cert
670 }
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000671 /// Consumes this key entry and extracts the keyparameters and metadata from it.
672 pub fn into_key_parameters_and_metadata(self) -> (Vec<KeyParameter>, KeyMetaData) {
673 (self.parameters, self.metadata)
674 }
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700675}
676
677/// Indicates the sub component of a key entry for persistent storage.
Janis Danisevskis377d1002021-01-27 19:07:48 -0800678#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700679pub struct SubComponentType(u32);
680impl SubComponentType {
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800681 /// Persistent identifier for a key blob.
682 pub const KEY_BLOB: SubComponentType = Self(0);
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700683 /// Persistent identifier for a certificate blob.
684 pub const CERT: SubComponentType = Self(1);
685 /// Persistent identifier for a certificate chain blob.
686 pub const CERT_CHAIN: SubComponentType = Self(2);
687}
688
689impl ToSql for SubComponentType {
690 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
691 self.0.to_sql()
692 }
693}
694
695impl FromSql for SubComponentType {
696 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
697 Ok(Self(u32::column_result(value)?))
698 }
699}
700
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800701/// This trait is private to the database module. It is used to convey whether or not the garbage
702/// collector shall be invoked after a database access. All closures passed to
703/// `KeystoreDB::with_transaction` return a tuple (bool, T) where the bool indicates if the
704/// gc needs to be triggered. This convenience function allows to turn any anyhow::Result<T>
705/// into anyhow::Result<(bool, T)> by simply appending one of `.do_gc(bool)`, `.no_gc()`, or
706/// `.need_gc()`.
707trait DoGc<T> {
708 fn do_gc(self, need_gc: bool) -> Result<(bool, T)>;
709
710 fn no_gc(self) -> Result<(bool, T)>;
711
712 fn need_gc(self) -> Result<(bool, T)>;
713}
714
715impl<T> DoGc<T> for Result<T> {
716 fn do_gc(self, need_gc: bool) -> Result<(bool, T)> {
717 self.map(|r| (need_gc, r))
718 }
719
720 fn no_gc(self) -> Result<(bool, T)> {
721 self.do_gc(false)
722 }
723
724 fn need_gc(self) -> Result<(bool, T)> {
725 self.do_gc(true)
726 }
727}
728
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700729/// KeystoreDB wraps a connection to an SQLite database and tracks its
730/// ownership. It also implements all of Keystore 2.0's database functionality.
Joel Galenson26f4d012020-07-17 14:57:21 -0700731pub struct KeystoreDB {
Joel Galenson26f4d012020-07-17 14:57:21 -0700732 conn: Connection,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800733 gc: Option<Gc>,
Joel Galenson26f4d012020-07-17 14:57:21 -0700734}
735
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000736/// Database representation of the monotonic time retrieved from the system call clock_gettime with
737/// CLOCK_MONOTONIC_RAW. Stores monotonic time as i64 in seconds.
738#[derive(Debug, Copy, Clone, Default, Eq, PartialEq, Ord, PartialOrd)]
739pub struct MonotonicRawTime(i64);
740
741impl MonotonicRawTime {
742 /// Constructs a new MonotonicRawTime
743 pub fn now() -> Self {
744 Self(get_current_time_in_seconds())
745 }
746
David Drysdale0e45a612021-02-25 17:24:36 +0000747 /// Constructs a new MonotonicRawTime from a given number of seconds.
748 pub fn from_secs(val: i64) -> Self {
749 Self(val)
750 }
751
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000752 /// Returns the integer value of MonotonicRawTime as i64
753 pub fn seconds(&self) -> i64 {
754 self.0
755 }
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800756
Hasini Gunasingheb3715fb2021-02-26 20:34:45 +0000757 /// Returns the value of MonotonicRawTime in milli seconds as i64
758 pub fn milli_seconds(&self) -> i64 {
759 self.0 * 1000
760 }
761
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800762 /// Like i64::checked_sub.
763 pub fn checked_sub(&self, other: &Self) -> Option<Self> {
764 self.0.checked_sub(other.0).map(Self)
765 }
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000766}
767
768impl ToSql for MonotonicRawTime {
769 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
770 Ok(ToSqlOutput::Owned(Value::Integer(self.0)))
771 }
772}
773
774impl FromSql for MonotonicRawTime {
775 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
776 Ok(Self(i64::column_result(value)?))
777 }
778}
779
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000780/// This struct encapsulates the information to be stored in the database about the auth tokens
781/// received by keystore.
782pub struct AuthTokenEntry {
783 auth_token: HardwareAuthToken,
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000784 time_received: MonotonicRawTime,
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000785}
786
787impl AuthTokenEntry {
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000788 fn new(auth_token: HardwareAuthToken, time_received: MonotonicRawTime) -> Self {
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000789 AuthTokenEntry { auth_token, time_received }
790 }
791
792 /// Checks if this auth token satisfies the given authentication information.
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800793 pub fn satisfies(&self, user_secure_ids: &[i64], auth_type: HardwareAuthenticatorType) -> bool {
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000794 user_secure_ids.iter().any(|&sid| {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800795 (sid == self.auth_token.userId || sid == self.auth_token.authenticatorId)
796 && (((auth_type.0 as i32) & (self.auth_token.authenticatorType.0 as i32)) != 0)
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000797 })
798 }
799
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000800 /// Returns the auth token wrapped by the AuthTokenEntry
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800801 pub fn auth_token(&self) -> &HardwareAuthToken {
802 &self.auth_token
803 }
804
805 /// Returns the auth token wrapped by the AuthTokenEntry
806 pub fn take_auth_token(self) -> HardwareAuthToken {
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000807 self.auth_token
808 }
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800809
810 /// Returns the time that this auth token was received.
811 pub fn time_received(&self) -> MonotonicRawTime {
812 self.time_received
813 }
Hasini Gunasingheb3715fb2021-02-26 20:34:45 +0000814
815 /// Returns the challenge value of the auth token.
816 pub fn challenge(&self) -> i64 {
817 self.auth_token.challenge
818 }
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000819}
820
Janis Danisevskisb00ebd02021-02-02 21:52:24 -0800821/// Shared in-memory databases get destroyed as soon as the last connection to them gets closed.
822/// This object does not allow access to the database connection. But it keeps a database
823/// connection alive in order to keep the in memory per boot database alive.
824pub struct PerBootDbKeepAlive(Connection);
825
Joel Galenson26f4d012020-07-17 14:57:21 -0700826impl KeystoreDB {
Janis Danisevskiseed69842021-02-18 20:04:10 -0800827 const UNASSIGNED_KEY_ID: i64 = -1i64;
Janis Danisevskisb00ebd02021-02-02 21:52:24 -0800828 const PERBOOT_DB_FILE_NAME: &'static str = &"file:perboot.sqlite?mode=memory&cache=shared";
829
830 /// This creates a PerBootDbKeepAlive object to keep the per boot database alive.
831 pub fn keep_perboot_db_alive() -> Result<PerBootDbKeepAlive> {
832 let conn = Connection::open_in_memory()
833 .context("In keep_perboot_db_alive: Failed to initialize SQLite connection.")?;
834
835 conn.execute("ATTACH DATABASE ? as perboot;", params![Self::PERBOOT_DB_FILE_NAME])
836 .context("In keep_perboot_db_alive: Failed to attach database perboot.")?;
837 Ok(PerBootDbKeepAlive(conn))
838 }
839
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700840 /// This will create a new database connection connecting the two
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800841 /// files persistent.sqlite and perboot.sqlite in the given directory.
842 /// It also attempts to initialize all of the tables.
843 /// KeystoreDB cannot be used by multiple threads.
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700844 /// Each thread should open their own connection using `thread_local!`.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800845 pub fn new(db_root: &Path, gc: Option<Gc>) -> Result<Self> {
Janis Danisevskisb00ebd02021-02-02 21:52:24 -0800846 // Build the path to the sqlite file.
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800847 let mut persistent_path = db_root.to_path_buf();
848 persistent_path.push("persistent.sqlite");
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700849
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800850 // Now convert them to strings prefixed with "file:"
851 let mut persistent_path_str = "file:".to_owned();
852 persistent_path_str.push_str(&persistent_path.to_string_lossy());
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800853
Janis Danisevskisb00ebd02021-02-02 21:52:24 -0800854 let conn = Self::make_connection(&persistent_path_str, &Self::PERBOOT_DB_FILE_NAME)?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800855
Janis Danisevskis66784c42021-01-27 08:40:25 -0800856 // On busy fail Immediately. It is unlikely to succeed given a bug in sqlite.
857 conn.busy_handler(None).context("In KeystoreDB::new: Failed to set busy handler.")?;
858
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800859 let mut db = Self { conn, gc };
Janis Danisevskis66784c42021-01-27 08:40:25 -0800860 db.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800861 Self::init_tables(tx).context("Trying to initialize tables.").no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -0800862 })?;
863 Ok(db)
Joel Galenson2aab4432020-07-22 15:27:57 -0700864 }
865
Janis Danisevskis66784c42021-01-27 08:40:25 -0800866 fn init_tables(tx: &Transaction) -> Result<()> {
867 tx.execute(
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700868 "CREATE TABLE IF NOT EXISTS persistent.keyentry (
Joel Galenson0891bc12020-07-20 10:37:03 -0700869 id INTEGER UNIQUE,
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800870 key_type INTEGER,
Joel Galenson0891bc12020-07-20 10:37:03 -0700871 domain INTEGER,
872 namespace INTEGER,
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800873 alias BLOB,
Max Bires8e93d2b2021-01-14 13:17:59 -0800874 state INTEGER,
875 km_uuid BLOB);",
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700876 NO_PARAMS,
877 )
878 .context("Failed to initialize \"keyentry\" table.")?;
879
Janis Danisevskis66784c42021-01-27 08:40:25 -0800880 tx.execute(
Janis Danisevskisa5438182021-02-02 14:22:59 -0800881 "CREATE INDEX IF NOT EXISTS persistent.keyentry_id_index
882 ON keyentry(id);",
883 NO_PARAMS,
884 )
885 .context("Failed to create index keyentry_id_index.")?;
886
887 tx.execute(
888 "CREATE INDEX IF NOT EXISTS persistent.keyentry_domain_namespace_index
889 ON keyentry(domain, namespace, alias);",
890 NO_PARAMS,
891 )
892 .context("Failed to create index keyentry_domain_namespace_index.")?;
893
894 tx.execute(
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700895 "CREATE TABLE IF NOT EXISTS persistent.blobentry (
896 id INTEGER PRIMARY KEY,
897 subcomponent_type INTEGER,
898 keyentryid INTEGER,
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800899 blob BLOB);",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700900 NO_PARAMS,
901 )
902 .context("Failed to initialize \"blobentry\" table.")?;
903
Janis Danisevskis66784c42021-01-27 08:40:25 -0800904 tx.execute(
Janis Danisevskisa5438182021-02-02 14:22:59 -0800905 "CREATE INDEX IF NOT EXISTS persistent.blobentry_keyentryid_index
906 ON blobentry(keyentryid);",
907 NO_PARAMS,
908 )
909 .context("Failed to create index blobentry_keyentryid_index.")?;
910
911 tx.execute(
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800912 "CREATE TABLE IF NOT EXISTS persistent.blobmetadata (
913 id INTEGER PRIMARY KEY,
914 blobentryid INTEGER,
915 tag INTEGER,
916 data ANY,
917 UNIQUE (blobentryid, tag));",
918 NO_PARAMS,
919 )
920 .context("Failed to initialize \"blobmetadata\" table.")?;
921
922 tx.execute(
923 "CREATE INDEX IF NOT EXISTS persistent.blobmetadata_blobentryid_index
924 ON blobmetadata(blobentryid);",
925 NO_PARAMS,
926 )
927 .context("Failed to create index blobmetadata_blobentryid_index.")?;
928
929 tx.execute(
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700930 "CREATE TABLE IF NOT EXISTS persistent.keyparameter (
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000931 keyentryid INTEGER,
932 tag INTEGER,
933 data ANY,
934 security_level INTEGER);",
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700935 NO_PARAMS,
936 )
937 .context("Failed to initialize \"keyparameter\" table.")?;
938
Janis Danisevskis66784c42021-01-27 08:40:25 -0800939 tx.execute(
Janis Danisevskisa5438182021-02-02 14:22:59 -0800940 "CREATE INDEX IF NOT EXISTS persistent.keyparameter_keyentryid_index
941 ON keyparameter(keyentryid);",
942 NO_PARAMS,
943 )
944 .context("Failed to create index keyparameter_keyentryid_index.")?;
945
946 tx.execute(
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800947 "CREATE TABLE IF NOT EXISTS persistent.keymetadata (
948 keyentryid INTEGER,
949 tag INTEGER,
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000950 data ANY,
951 UNIQUE (keyentryid, tag));",
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800952 NO_PARAMS,
953 )
954 .context("Failed to initialize \"keymetadata\" table.")?;
955
Janis Danisevskis66784c42021-01-27 08:40:25 -0800956 tx.execute(
Janis Danisevskisa5438182021-02-02 14:22:59 -0800957 "CREATE INDEX IF NOT EXISTS persistent.keymetadata_keyentryid_index
958 ON keymetadata(keyentryid);",
959 NO_PARAMS,
960 )
961 .context("Failed to create index keymetadata_keyentryid_index.")?;
962
963 tx.execute(
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800964 "CREATE TABLE IF NOT EXISTS persistent.grant (
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700965 id INTEGER UNIQUE,
966 grantee INTEGER,
967 keyentryid INTEGER,
968 access_vector INTEGER);",
969 NO_PARAMS,
970 )
971 .context("Failed to initialize \"grant\" table.")?;
972
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000973 //TODO: only drop the following two perboot tables if this is the first start up
974 //during the boot (b/175716626).
Janis Danisevskis66784c42021-01-27 08:40:25 -0800975 // tx.execute("DROP TABLE IF EXISTS perboot.authtoken;", NO_PARAMS)
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000976 // .context("Failed to drop perboot.authtoken table")?;
Janis Danisevskis66784c42021-01-27 08:40:25 -0800977 tx.execute(
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000978 "CREATE TABLE IF NOT EXISTS perboot.authtoken (
979 id INTEGER PRIMARY KEY,
980 challenge INTEGER,
981 user_id INTEGER,
982 auth_id INTEGER,
983 authenticator_type INTEGER,
984 timestamp INTEGER,
985 mac BLOB,
986 time_received INTEGER,
987 UNIQUE(user_id, auth_id, authenticator_type));",
988 NO_PARAMS,
989 )
990 .context("Failed to initialize \"authtoken\" table.")?;
991
Janis Danisevskis66784c42021-01-27 08:40:25 -0800992 // tx.execute("DROP TABLE IF EXISTS perboot.metadata;", NO_PARAMS)
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000993 // .context("Failed to drop perboot.metadata table")?;
994 // metadata table stores certain miscellaneous information required for keystore functioning
995 // during a boot cycle, as key-value pairs.
Janis Danisevskis66784c42021-01-27 08:40:25 -0800996 tx.execute(
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000997 "CREATE TABLE IF NOT EXISTS perboot.metadata (
998 key TEXT,
999 value BLOB,
1000 UNIQUE(key));",
1001 NO_PARAMS,
1002 )
1003 .context("Failed to initialize \"metadata\" table.")?;
Joel Galenson0891bc12020-07-20 10:37:03 -07001004 Ok(())
1005 }
1006
Janis Danisevskis4df44f42020-08-26 14:40:03 -07001007 fn make_connection(persistent_file: &str, perboot_file: &str) -> Result<Connection> {
1008 let conn =
1009 Connection::open_in_memory().context("Failed to initialize SQLite connection.")?;
1010
Janis Danisevskis66784c42021-01-27 08:40:25 -08001011 loop {
1012 if let Err(e) = conn
1013 .execute("ATTACH DATABASE ? as persistent;", params![persistent_file])
1014 .context("Failed to attach database persistent.")
1015 {
1016 if Self::is_locked_error(&e) {
1017 std::thread::sleep(std::time::Duration::from_micros(500));
1018 continue;
1019 } else {
1020 return Err(e);
1021 }
1022 }
1023 break;
1024 }
1025 loop {
1026 if let Err(e) = conn
1027 .execute("ATTACH DATABASE ? as perboot;", params![perboot_file])
1028 .context("Failed to attach database perboot.")
1029 {
1030 if Self::is_locked_error(&e) {
1031 std::thread::sleep(std::time::Duration::from_micros(500));
1032 continue;
1033 } else {
1034 return Err(e);
1035 }
1036 }
1037 break;
1038 }
Janis Danisevskis4df44f42020-08-26 14:40:03 -07001039
1040 Ok(conn)
1041 }
1042
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001043 /// This function is intended to be used by the garbage collector.
1044 /// It deletes the blob given by `blob_id_to_delete`. It then tries to find a superseded
1045 /// key blob that might need special handling by the garbage collector.
1046 /// If no further superseded blobs can be found it deletes all other superseded blobs that don't
1047 /// need special handling and returns None.
1048 pub fn handle_next_superseded_blob(
1049 &mut self,
1050 blob_id_to_delete: Option<i64>,
1051 ) -> Result<Option<(i64, Vec<u8>, BlobMetaData)>> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001052 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001053 // Delete the given blob if one was given.
1054 if let Some(blob_id_to_delete) = blob_id_to_delete {
1055 tx.execute(
1056 "DELETE FROM persistent.blobmetadata WHERE blobentryid = ?;",
1057 params![blob_id_to_delete],
1058 )
1059 .context("Trying to delete blob metadata.")?;
1060 tx.execute(
1061 "DELETE FROM persistent.blobentry WHERE id = ?;",
1062 params![blob_id_to_delete],
1063 )
1064 .context("Trying to blob.")?;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001065 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001066
1067 // Find another superseded keyblob load its metadata and return it.
1068 if let Some((blob_id, blob)) = tx
1069 .query_row(
1070 "SELECT id, blob FROM persistent.blobentry
1071 WHERE subcomponent_type = ?
1072 AND (
1073 id NOT IN (
1074 SELECT MAX(id) FROM persistent.blobentry
1075 WHERE subcomponent_type = ?
1076 GROUP BY keyentryid, subcomponent_type
1077 )
1078 OR keyentryid NOT IN (SELECT id FROM persistent.keyentry)
1079 );",
1080 params![SubComponentType::KEY_BLOB, SubComponentType::KEY_BLOB],
1081 |row| Ok((row.get(0)?, row.get(1)?)),
1082 )
1083 .optional()
1084 .context("Trying to query superseded blob.")?
1085 {
1086 let blob_metadata = BlobMetaData::load_from_db(blob_id, tx)
1087 .context("Trying to load blob metadata.")?;
1088 return Ok(Some((blob_id, blob, blob_metadata))).no_gc();
1089 }
1090
1091 // We did not find any superseded key blob, so let's remove other superseded blob in
1092 // one transaction.
1093 tx.execute(
1094 "DELETE FROM persistent.blobentry
1095 WHERE NOT subcomponent_type = ?
1096 AND (
1097 id NOT IN (
1098 SELECT MAX(id) FROM persistent.blobentry
1099 WHERE NOT subcomponent_type = ?
1100 GROUP BY keyentryid, subcomponent_type
1101 ) OR keyentryid NOT IN (SELECT id FROM persistent.keyentry)
1102 );",
1103 params![SubComponentType::KEY_BLOB, SubComponentType::KEY_BLOB],
1104 )
1105 .context("Trying to purge superseded blobs.")?;
1106
1107 Ok(None).no_gc()
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001108 })
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001109 .context("In handle_next_superseded_blob.")
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001110 }
1111
1112 /// This maintenance function should be called only once before the database is used for the
1113 /// first time. It restores the invariant that `KeyLifeCycle::Existing` is a transient state.
1114 /// The function transitions all key entries from Existing to Unreferenced unconditionally and
1115 /// returns the number of rows affected. If this returns a value greater than 0, it means that
1116 /// Keystore crashed at some point during key generation. Callers may want to log such
1117 /// occurrences.
1118 /// Unlike with `mark_unreferenced`, we don't need to purge grants, because only keys that made
1119 /// it to `KeyLifeCycle::Live` may have grants.
1120 pub fn cleanup_leftovers(&mut self) -> Result<usize> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001121 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1122 tx.execute(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001123 "UPDATE persistent.keyentry SET state = ? WHERE state = ?;",
1124 params![KeyLifeCycle::Unreferenced, KeyLifeCycle::Existing],
1125 )
Janis Danisevskis66784c42021-01-27 08:40:25 -08001126 .context("Failed to execute query.")
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001127 .need_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08001128 })
1129 .context("In cleanup_leftovers.")
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001130 }
1131
Hasini Gunasinghe0e161452021-01-27 19:34:37 +00001132 /// Checks if a key exists with given key type and key descriptor properties.
1133 pub fn key_exists(
1134 &mut self,
1135 domain: Domain,
1136 nspace: i64,
1137 alias: &str,
1138 key_type: KeyType,
1139 ) -> Result<bool> {
1140 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1141 let key_descriptor =
1142 KeyDescriptor { domain, nspace, alias: Some(alias.to_string()), blob: None };
1143 let result = Self::load_key_entry_id(&tx, &key_descriptor, key_type);
1144 match result {
1145 Ok(_) => Ok(true),
1146 Err(error) => match error.root_cause().downcast_ref::<KsError>() {
1147 Some(KsError::Rc(ResponseCode::KEY_NOT_FOUND)) => Ok(false),
1148 _ => Err(error).context("In key_exists: Failed to find if the key exists."),
1149 },
1150 }
1151 .no_gc()
1152 })
1153 .context("In key_exists.")
1154 }
1155
Hasini Gunasingheda895552021-01-27 19:34:37 +00001156 /// Stores a super key in the database.
1157 pub fn store_super_key(
1158 &mut self,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +00001159 user_id: u32,
Paul Crowley7a658392021-03-18 17:08:20 -07001160 key_type: &SuperKeyType,
1161 blob: &[u8],
1162 blob_metadata: &BlobMetaData,
Paul Crowley8d5b2532021-03-19 10:53:07 -07001163 key_metadata: &KeyMetaData,
Hasini Gunasingheda895552021-01-27 19:34:37 +00001164 ) -> Result<KeyEntry> {
1165 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1166 let key_id = Self::insert_with_retry(|id| {
1167 tx.execute(
1168 "INSERT into persistent.keyentry
1169 (id, key_type, domain, namespace, alias, state, km_uuid)
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00001170 VALUES(?, ?, ?, ?, ?, ?, ?);",
Hasini Gunasingheda895552021-01-27 19:34:37 +00001171 params![
1172 id,
1173 KeyType::Super,
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00001174 Domain::APP.0,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +00001175 user_id as i64,
Paul Crowley7a658392021-03-18 17:08:20 -07001176 key_type.alias,
Hasini Gunasingheda895552021-01-27 19:34:37 +00001177 KeyLifeCycle::Live,
1178 &KEYSTORE_UUID,
1179 ],
1180 )
1181 })
1182 .context("Failed to insert into keyentry table.")?;
1183
Paul Crowley8d5b2532021-03-19 10:53:07 -07001184 key_metadata.store_in_db(key_id, tx).context("KeyMetaData::store_in_db failed")?;
1185
Hasini Gunasingheda895552021-01-27 19:34:37 +00001186 Self::set_blob_internal(
1187 &tx,
1188 key_id,
1189 SubComponentType::KEY_BLOB,
1190 Some(blob),
1191 Some(blob_metadata),
1192 )
1193 .context("Failed to store key blob.")?;
1194
1195 Self::load_key_components(tx, KeyEntryLoadBits::KM, key_id)
1196 .context("Trying to load key components.")
1197 .no_gc()
1198 })
1199 .context("In store_super_key.")
1200 }
1201
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +00001202 /// Loads super key of a given user, if exists
Paul Crowley7a658392021-03-18 17:08:20 -07001203 pub fn load_super_key(
1204 &mut self,
1205 key_type: &SuperKeyType,
1206 user_id: u32,
1207 ) -> Result<Option<(KeyIdGuard, KeyEntry)>> {
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +00001208 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1209 let key_descriptor = KeyDescriptor {
1210 domain: Domain::APP,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +00001211 nspace: user_id as i64,
Paul Crowley7a658392021-03-18 17:08:20 -07001212 alias: Some(key_type.alias.into()),
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +00001213 blob: None,
1214 };
1215 let id = Self::load_key_entry_id(&tx, &key_descriptor, KeyType::Super);
1216 match id {
1217 Ok(id) => {
1218 let key_entry = Self::load_key_components(&tx, KeyEntryLoadBits::KM, id)
1219 .context("In load_super_key. Failed to load key entry.")?;
1220 Ok(Some((KEY_ID_LOCK.get(id), key_entry)))
1221 }
1222 Err(error) => match error.root_cause().downcast_ref::<KsError>() {
1223 Some(KsError::Rc(ResponseCode::KEY_NOT_FOUND)) => Ok(None),
1224 _ => Err(error).context("In load_super_key."),
1225 },
1226 }
1227 .no_gc()
1228 })
1229 .context("In load_super_key.")
1230 }
1231
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001232 /// Atomically loads a key entry and associated metadata or creates it using the
1233 /// callback create_new_key callback. The callback is called during a database
1234 /// transaction. This means that implementers should be mindful about using
1235 /// blocking operations such as IPC or grabbing mutexes.
1236 pub fn get_or_create_key_with<F>(
1237 &mut self,
1238 domain: Domain,
1239 namespace: i64,
1240 alias: &str,
Max Bires8e93d2b2021-01-14 13:17:59 -08001241 km_uuid: Uuid,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001242 create_new_key: F,
1243 ) -> Result<(KeyIdGuard, KeyEntry)>
1244 where
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001245 F: Fn() -> Result<(Vec<u8>, BlobMetaData)>,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001246 {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001247 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1248 let id = {
1249 let mut stmt = tx
1250 .prepare(
1251 "SELECT id FROM persistent.keyentry
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001252 WHERE
1253 key_type = ?
1254 AND domain = ?
1255 AND namespace = ?
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001256 AND alias = ?
1257 AND state = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08001258 )
1259 .context("In get_or_create_key_with: Failed to select from keyentry table.")?;
1260 let mut rows = stmt
1261 .query(params![KeyType::Super, domain.0, namespace, alias, KeyLifeCycle::Live])
1262 .context("In get_or_create_key_with: Failed to query from keyentry table.")?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001263
Janis Danisevskis66784c42021-01-27 08:40:25 -08001264 db_utils::with_rows_extract_one(&mut rows, |row| {
1265 Ok(match row {
1266 Some(r) => r.get(0).context("Failed to unpack id.")?,
1267 None => None,
1268 })
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001269 })
Janis Danisevskis66784c42021-01-27 08:40:25 -08001270 .context("In get_or_create_key_with.")?
1271 };
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001272
Janis Danisevskis66784c42021-01-27 08:40:25 -08001273 let (id, entry) = match id {
1274 Some(id) => (
1275 id,
1276 Self::load_key_components(&tx, KeyEntryLoadBits::KM, id)
1277 .context("In get_or_create_key_with.")?,
1278 ),
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001279
Janis Danisevskis66784c42021-01-27 08:40:25 -08001280 None => {
1281 let id = Self::insert_with_retry(|id| {
1282 tx.execute(
1283 "INSERT into persistent.keyentry
Max Bires8e93d2b2021-01-14 13:17:59 -08001284 (id, key_type, domain, namespace, alias, state, km_uuid)
1285 VALUES(?, ?, ?, ?, ?, ?, ?);",
Janis Danisevskis66784c42021-01-27 08:40:25 -08001286 params![
1287 id,
1288 KeyType::Super,
1289 domain.0,
1290 namespace,
1291 alias,
1292 KeyLifeCycle::Live,
1293 km_uuid,
1294 ],
1295 )
1296 })
1297 .context("In get_or_create_key_with.")?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001298
Janis Danisevskis66784c42021-01-27 08:40:25 -08001299 let (blob, metadata) =
1300 create_new_key().context("In get_or_create_key_with.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001301 Self::set_blob_internal(
1302 &tx,
1303 id,
1304 SubComponentType::KEY_BLOB,
1305 Some(&blob),
1306 Some(&metadata),
1307 )
Paul Crowley7a658392021-03-18 17:08:20 -07001308 .context("In get_or_create_key_with.")?;
Janis Danisevskis66784c42021-01-27 08:40:25 -08001309 (
Janis Danisevskis377d1002021-01-27 19:07:48 -08001310 id,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001311 KeyEntry {
1312 id,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001313 key_blob_info: Some((blob, metadata)),
Janis Danisevskis66784c42021-01-27 08:40:25 -08001314 pure_cert: false,
1315 ..Default::default()
1316 },
1317 )
1318 }
1319 };
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001320 Ok((KEY_ID_LOCK.get(id), entry)).no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08001321 })
1322 .context("In get_or_create_key_with.")
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001323 }
1324
Janis Danisevskis66784c42021-01-27 08:40:25 -08001325 /// SQLite3 seems to hold a shared mutex while running the busy handler when
1326 /// waiting for the database file to become available. This makes it
1327 /// impossible to successfully recover from a locked database when the
1328 /// transaction holding the device busy is in the same process on a
1329 /// different connection. As a result the busy handler has to time out and
1330 /// fail in order to make progress.
1331 ///
1332 /// Instead, we set the busy handler to None (return immediately). And catch
1333 /// Busy and Locked errors (the latter occur on in memory databases with
1334 /// shared cache, e.g., the per-boot database.) and restart the transaction
1335 /// after a grace period of half a millisecond.
1336 ///
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001337 /// Creates a transaction with the given behavior and executes f with the new transaction.
Janis Danisevskis66784c42021-01-27 08:40:25 -08001338 /// The transaction is committed only if f returns Ok and retried if DatabaseBusy
1339 /// or DatabaseLocked is encountered.
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001340 fn with_transaction<T, F>(&mut self, behavior: TransactionBehavior, f: F) -> Result<T>
1341 where
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001342 F: Fn(&Transaction) -> Result<(bool, T)>,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001343 {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001344 loop {
1345 match self
1346 .conn
1347 .transaction_with_behavior(behavior)
1348 .context("In with_transaction.")
1349 .and_then(|tx| f(&tx).map(|result| (result, tx)))
1350 .and_then(|(result, tx)| {
1351 tx.commit().context("In with_transaction: Failed to commit transaction.")?;
1352 Ok(result)
1353 }) {
1354 Ok(result) => break Ok(result),
1355 Err(e) => {
1356 if Self::is_locked_error(&e) {
1357 std::thread::sleep(std::time::Duration::from_micros(500));
1358 continue;
1359 } else {
1360 return Err(e).context("In with_transaction.");
1361 }
1362 }
1363 }
1364 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001365 .map(|(need_gc, result)| {
1366 if need_gc {
1367 if let Some(ref gc) = self.gc {
1368 gc.notify_gc();
1369 }
1370 }
1371 result
1372 })
Janis Danisevskis66784c42021-01-27 08:40:25 -08001373 }
1374
1375 fn is_locked_error(e: &anyhow::Error) -> bool {
Paul Crowleyf61fee72021-03-17 14:38:44 -07001376 matches!(
1377 e.root_cause().downcast_ref::<rusqlite::ffi::Error>(),
1378 Some(rusqlite::ffi::Error { code: rusqlite::ErrorCode::DatabaseBusy, .. })
1379 | Some(rusqlite::ffi::Error { code: rusqlite::ErrorCode::DatabaseLocked, .. })
1380 )
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001381 }
1382
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001383 /// Creates a new key entry and allocates a new randomized id for the new key.
1384 /// The key id gets associated with a domain and namespace but not with an alias.
1385 /// To complete key generation `rebind_alias` should be called after all of the
1386 /// key artifacts, i.e., blobs and parameters have been associated with the new
1387 /// key id. Finalizing with `rebind_alias` makes the creation of a new key entry
1388 /// atomic even if key generation is not.
Max Bires8e93d2b2021-01-14 13:17:59 -08001389 pub fn create_key_entry(
1390 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001391 domain: &Domain,
1392 namespace: &i64,
Max Bires8e93d2b2021-01-14 13:17:59 -08001393 km_uuid: &Uuid,
1394 ) -> Result<KeyIdGuard> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001395 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001396 Self::create_key_entry_internal(tx, domain, namespace, km_uuid).no_gc()
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001397 })
1398 .context("In create_key_entry.")
1399 }
1400
1401 fn create_key_entry_internal(
1402 tx: &Transaction,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001403 domain: &Domain,
1404 namespace: &i64,
Max Bires8e93d2b2021-01-14 13:17:59 -08001405 km_uuid: &Uuid,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001406 ) -> Result<KeyIdGuard> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001407 match *domain {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001408 Domain::APP | Domain::SELINUX => {}
Joel Galenson0891bc12020-07-20 10:37:03 -07001409 _ => {
1410 return Err(KsError::sys())
1411 .context(format!("Domain {:?} must be either App or SELinux.", domain));
1412 }
1413 }
Janis Danisevskisaec14592020-11-12 09:41:49 -08001414 Ok(KEY_ID_LOCK.get(
1415 Self::insert_with_retry(|id| {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001416 tx.execute(
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001417 "INSERT into persistent.keyentry
Max Bires8e93d2b2021-01-14 13:17:59 -08001418 (id, key_type, domain, namespace, alias, state, km_uuid)
1419 VALUES(?, ?, ?, ?, NULL, ?, ?);",
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001420 params![
1421 id,
1422 KeyType::Client,
1423 domain.0 as u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001424 *namespace,
Max Bires8e93d2b2021-01-14 13:17:59 -08001425 KeyLifeCycle::Existing,
1426 km_uuid,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001427 ],
Janis Danisevskisaec14592020-11-12 09:41:49 -08001428 )
1429 })
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001430 .context("In create_key_entry_internal")?,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001431 ))
Joel Galenson26f4d012020-07-17 14:57:21 -07001432 }
Joel Galenson33c04ad2020-08-03 11:04:38 -07001433
Max Bires2b2e6562020-09-22 11:22:36 -07001434 /// Creates a new attestation key entry and allocates a new randomized id for the new key.
1435 /// The key id gets associated with a domain and namespace later but not with an alias. The
1436 /// alias will be used to denote if a key has been signed as each key can only be bound to one
1437 /// domain and namespace pairing so there is no need to use them as a value for indexing into
1438 /// a key.
1439 pub fn create_attestation_key_entry(
1440 &mut self,
1441 maced_public_key: &[u8],
1442 raw_public_key: &[u8],
1443 private_key: &[u8],
1444 km_uuid: &Uuid,
1445 ) -> Result<()> {
1446 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1447 let key_id = KEY_ID_LOCK.get(
1448 Self::insert_with_retry(|id| {
1449 tx.execute(
1450 "INSERT into persistent.keyentry
1451 (id, key_type, domain, namespace, alias, state, km_uuid)
1452 VALUES(?, ?, NULL, NULL, NULL, ?, ?);",
1453 params![id, KeyType::Attestation, KeyLifeCycle::Live, km_uuid],
1454 )
1455 })
1456 .context("In create_key_entry")?,
1457 );
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001458 Self::set_blob_internal(
1459 &tx,
1460 key_id.0,
1461 SubComponentType::KEY_BLOB,
1462 Some(private_key),
1463 None,
1464 )?;
Max Bires2b2e6562020-09-22 11:22:36 -07001465 let mut metadata = KeyMetaData::new();
1466 metadata.add(KeyMetaEntry::AttestationMacedPublicKey(maced_public_key.to_vec()));
1467 metadata.add(KeyMetaEntry::AttestationRawPubKey(raw_public_key.to_vec()));
1468 metadata.store_in_db(key_id.0, &tx)?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001469 Ok(()).no_gc()
Max Bires2b2e6562020-09-22 11:22:36 -07001470 })
1471 .context("In create_attestation_key_entry")
1472 }
1473
Janis Danisevskis377d1002021-01-27 19:07:48 -08001474 /// Set a new blob and associates it with the given key id. Each blob
1475 /// has a sub component type.
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001476 /// Each key can have one of each sub component type associated. If more
1477 /// are added only the most recent can be retrieved, and superseded blobs
Janis Danisevskis377d1002021-01-27 19:07:48 -08001478 /// will get garbage collected.
1479 /// Components SubComponentType::CERT and SubComponentType::CERT_CHAIN can be
1480 /// removed by setting blob to None.
1481 pub fn set_blob(
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001482 &mut self,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001483 key_id: &KeyIdGuard,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001484 sc_type: SubComponentType,
Janis Danisevskis377d1002021-01-27 19:07:48 -08001485 blob: Option<&[u8]>,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001486 blob_metadata: Option<&BlobMetaData>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001487 ) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001488 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001489 Self::set_blob_internal(&tx, key_id.0, sc_type, blob, blob_metadata).need_gc()
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001490 })
Janis Danisevskis377d1002021-01-27 19:07:48 -08001491 .context("In set_blob.")
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001492 }
1493
Janis Danisevskiseed69842021-02-18 20:04:10 -08001494 /// Why would we insert a deleted blob? This weird function is for the purpose of legacy
1495 /// key migration in the case where we bulk delete all the keys of an app or even a user.
1496 /// We use this to insert key blobs into the database which can then be garbage collected
1497 /// lazily by the key garbage collector.
1498 pub fn set_deleted_blob(&mut self, blob: &[u8], blob_metadata: &BlobMetaData) -> Result<()> {
1499 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1500 Self::set_blob_internal(
1501 &tx,
1502 Self::UNASSIGNED_KEY_ID,
1503 SubComponentType::KEY_BLOB,
1504 Some(blob),
1505 Some(blob_metadata),
1506 )
1507 .need_gc()
1508 })
1509 .context("In set_deleted_blob.")
1510 }
1511
Janis Danisevskis377d1002021-01-27 19:07:48 -08001512 fn set_blob_internal(
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001513 tx: &Transaction,
1514 key_id: i64,
1515 sc_type: SubComponentType,
Janis Danisevskis377d1002021-01-27 19:07:48 -08001516 blob: Option<&[u8]>,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001517 blob_metadata: Option<&BlobMetaData>,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001518 ) -> Result<()> {
Janis Danisevskis377d1002021-01-27 19:07:48 -08001519 match (blob, sc_type) {
1520 (Some(blob), _) => {
1521 tx.execute(
1522 "INSERT INTO persistent.blobentry
1523 (subcomponent_type, keyentryid, blob) VALUES (?, ?, ?);",
1524 params![sc_type, key_id, blob],
1525 )
1526 .context("In set_blob_internal: Failed to insert blob.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001527 if let Some(blob_metadata) = blob_metadata {
1528 let blob_id = tx
1529 .query_row("SELECT MAX(id) FROM persistent.blobentry;", NO_PARAMS, |row| {
1530 row.get(0)
1531 })
1532 .context("In set_blob_internal: Failed to get new blob id.")?;
1533 blob_metadata
1534 .store_in_db(blob_id, tx)
1535 .context("In set_blob_internal: Trying to store blob metadata.")?;
1536 }
Janis Danisevskis377d1002021-01-27 19:07:48 -08001537 }
1538 (None, SubComponentType::CERT) | (None, SubComponentType::CERT_CHAIN) => {
1539 tx.execute(
1540 "DELETE FROM persistent.blobentry
1541 WHERE subcomponent_type = ? AND keyentryid = ?;",
1542 params![sc_type, key_id],
1543 )
1544 .context("In set_blob_internal: Failed to delete blob.")?;
1545 }
1546 (None, _) => {
1547 return Err(KsError::sys())
1548 .context("In set_blob_internal: Other blobs cannot be deleted in this way.");
1549 }
1550 }
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001551 Ok(())
1552 }
1553
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001554 /// Inserts a collection of key parameters into the `persistent.keyparameter` table
1555 /// and associates them with the given `key_id`.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001556 #[cfg(test)]
1557 fn insert_keyparameter(&mut self, key_id: &KeyIdGuard, params: &[KeyParameter]) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001558 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001559 Self::insert_keyparameter_internal(tx, key_id, params).no_gc()
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001560 })
1561 .context("In insert_keyparameter.")
1562 }
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001563
Janis Danisevskis66784c42021-01-27 08:40:25 -08001564 fn insert_keyparameter_internal(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001565 tx: &Transaction,
1566 key_id: &KeyIdGuard,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001567 params: &[KeyParameter],
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001568 ) -> Result<()> {
1569 let mut stmt = tx
1570 .prepare(
1571 "INSERT into persistent.keyparameter (keyentryid, tag, data, security_level)
1572 VALUES (?, ?, ?, ?);",
1573 )
1574 .context("In insert_keyparameter_internal: Failed to prepare statement.")?;
1575
Janis Danisevskis66784c42021-01-27 08:40:25 -08001576 for p in params.iter() {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001577 stmt.insert(params![
1578 key_id.0,
1579 p.get_tag().0,
1580 p.key_parameter_value(),
1581 p.security_level().0
1582 ])
1583 .with_context(|| {
1584 format!("In insert_keyparameter_internal: Failed to insert {:?}", p)
1585 })?;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001586 }
1587 Ok(())
1588 }
1589
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001590 /// Insert a set of key entry specific metadata into the database.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001591 #[cfg(test)]
1592 fn insert_key_metadata(&mut self, key_id: &KeyIdGuard, metadata: &KeyMetaData) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001593 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001594 metadata.store_in_db(key_id.0, &tx).no_gc()
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001595 })
1596 .context("In insert_key_metadata.")
1597 }
1598
Max Bires2b2e6562020-09-22 11:22:36 -07001599 /// Stores a signed certificate chain signed by a remote provisioning server, keyed
1600 /// on the public key.
1601 pub fn store_signed_attestation_certificate_chain(
1602 &mut self,
1603 raw_public_key: &[u8],
Max Biresb2e1d032021-02-08 21:35:05 -08001604 batch_cert: &[u8],
Max Bires2b2e6562020-09-22 11:22:36 -07001605 cert_chain: &[u8],
1606 expiration_date: i64,
1607 km_uuid: &Uuid,
1608 ) -> Result<()> {
1609 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1610 let mut stmt = tx
1611 .prepare(
1612 "SELECT keyentryid
1613 FROM persistent.keymetadata
1614 WHERE tag = ? AND data = ? AND keyentryid IN
1615 (SELECT id
1616 FROM persistent.keyentry
1617 WHERE
1618 alias IS NULL AND
1619 domain IS NULL AND
1620 namespace IS NULL AND
1621 key_type = ? AND
1622 km_uuid = ?);",
1623 )
1624 .context("Failed to store attestation certificate chain.")?;
1625 let mut rows = stmt
1626 .query(params![
1627 KeyMetaData::AttestationRawPubKey,
1628 raw_public_key,
1629 KeyType::Attestation,
1630 km_uuid
1631 ])
1632 .context("Failed to fetch keyid")?;
1633 let key_id = db_utils::with_rows_extract_one(&mut rows, |row| {
1634 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?
1635 .get(0)
1636 .context("Failed to unpack id.")
1637 })
1638 .context("Failed to get key_id.")?;
1639 let num_updated = tx
1640 .execute(
1641 "UPDATE persistent.keyentry
1642 SET alias = ?
1643 WHERE id = ?;",
1644 params!["signed", key_id],
1645 )
1646 .context("Failed to update alias.")?;
1647 if num_updated != 1 {
1648 return Err(KsError::sys()).context("Alias not updated for the key.");
1649 }
1650 let mut metadata = KeyMetaData::new();
1651 metadata.add(KeyMetaEntry::AttestationExpirationDate(DateTime::from_millis_epoch(
1652 expiration_date,
1653 )));
1654 metadata.store_in_db(key_id, &tx).context("Failed to insert key metadata.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001655 Self::set_blob_internal(
1656 &tx,
1657 key_id,
1658 SubComponentType::CERT_CHAIN,
1659 Some(cert_chain),
1660 None,
1661 )
1662 .context("Failed to insert cert chain")?;
Max Biresb2e1d032021-02-08 21:35:05 -08001663 Self::set_blob_internal(&tx, key_id, SubComponentType::CERT, Some(batch_cert), None)
1664 .context("Failed to insert cert")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001665 Ok(()).no_gc()
Max Bires2b2e6562020-09-22 11:22:36 -07001666 })
1667 .context("In store_signed_attestation_certificate_chain: ")
1668 }
1669
1670 /// Assigns the next unassigned attestation key to a domain/namespace combo that does not
1671 /// currently have a key assigned to it.
1672 pub fn assign_attestation_key(
1673 &mut self,
1674 domain: Domain,
1675 namespace: i64,
1676 km_uuid: &Uuid,
1677 ) -> Result<()> {
1678 match domain {
1679 Domain::APP | Domain::SELINUX => {}
1680 _ => {
1681 return Err(KsError::sys()).context(format!(
1682 concat!(
1683 "In assign_attestation_key: Domain {:?} ",
1684 "must be either App or SELinux.",
1685 ),
1686 domain
1687 ));
1688 }
1689 }
1690 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1691 let result = tx
1692 .execute(
1693 "UPDATE persistent.keyentry
1694 SET domain=?1, namespace=?2
1695 WHERE
1696 id =
1697 (SELECT MIN(id)
1698 FROM persistent.keyentry
1699 WHERE ALIAS IS NOT NULL
1700 AND domain IS NULL
1701 AND key_type IS ?3
1702 AND state IS ?4
1703 AND km_uuid IS ?5)
1704 AND
1705 (SELECT COUNT(*)
1706 FROM persistent.keyentry
1707 WHERE domain=?1
1708 AND namespace=?2
1709 AND key_type IS ?3
1710 AND state IS ?4
1711 AND km_uuid IS ?5) = 0;",
1712 params![
1713 domain.0 as u32,
1714 namespace,
1715 KeyType::Attestation,
1716 KeyLifeCycle::Live,
1717 km_uuid,
1718 ],
1719 )
1720 .context("Failed to assign attestation key")?;
Max Bires01f8af22021-03-02 23:24:50 -08001721 if result == 0 {
1722 return Err(KsError::Rc(ResponseCode::OUT_OF_KEYS)).context("Out of keys.");
1723 } else if result > 1 {
1724 return Err(KsError::sys())
1725 .context(format!("Expected to update 1 entry, instead updated {}", result));
Max Bires2b2e6562020-09-22 11:22:36 -07001726 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001727 Ok(()).no_gc()
Max Bires2b2e6562020-09-22 11:22:36 -07001728 })
1729 .context("In assign_attestation_key: ")
1730 }
1731
1732 /// Retrieves num_keys number of attestation keys that have not yet been signed by a remote
1733 /// provisioning server, or the maximum number available if there are not num_keys number of
1734 /// entries in the table.
1735 pub fn fetch_unsigned_attestation_keys(
1736 &mut self,
1737 num_keys: i32,
1738 km_uuid: &Uuid,
1739 ) -> Result<Vec<Vec<u8>>> {
1740 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1741 let mut stmt = tx
1742 .prepare(
1743 "SELECT data
1744 FROM persistent.keymetadata
1745 WHERE tag = ? AND keyentryid IN
1746 (SELECT id
1747 FROM persistent.keyentry
1748 WHERE
1749 alias IS NULL AND
1750 domain IS NULL AND
1751 namespace IS NULL AND
1752 key_type = ? AND
1753 km_uuid = ?
1754 LIMIT ?);",
1755 )
1756 .context("Failed to prepare statement")?;
1757 let rows = stmt
1758 .query_map(
1759 params![
1760 KeyMetaData::AttestationMacedPublicKey,
1761 KeyType::Attestation,
1762 km_uuid,
1763 num_keys
1764 ],
1765 |row| Ok(row.get(0)?),
1766 )?
1767 .collect::<rusqlite::Result<Vec<Vec<u8>>>>()
1768 .context("Failed to execute statement")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001769 Ok(rows).no_gc()
Max Bires2b2e6562020-09-22 11:22:36 -07001770 })
1771 .context("In fetch_unsigned_attestation_keys")
1772 }
1773
1774 /// Removes any keys that have expired as of the current time. Returns the number of keys
1775 /// marked unreferenced that are bound to be garbage collected.
1776 pub fn delete_expired_attestation_keys(&mut self) -> Result<i32> {
1777 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1778 let mut stmt = tx
1779 .prepare(
1780 "SELECT keyentryid, data
1781 FROM persistent.keymetadata
1782 WHERE tag = ? AND keyentryid IN
1783 (SELECT id
1784 FROM persistent.keyentry
1785 WHERE key_type = ?);",
1786 )
1787 .context("Failed to prepare query")?;
1788 let key_ids_to_check = stmt
1789 .query_map(
1790 params![KeyMetaData::AttestationExpirationDate, KeyType::Attestation],
1791 |row| Ok((row.get(0)?, row.get(1)?)),
1792 )?
1793 .collect::<rusqlite::Result<Vec<(i64, DateTime)>>>()
1794 .context("Failed to get date metadata")?;
1795 let curr_time = DateTime::from_millis_epoch(
1796 SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_millis() as i64,
1797 );
1798 let mut num_deleted = 0;
1799 for id in key_ids_to_check.iter().filter(|kt| kt.1 < curr_time).map(|kt| kt.0) {
1800 if Self::mark_unreferenced(&tx, id)? {
1801 num_deleted += 1;
1802 }
1803 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001804 Ok(num_deleted).do_gc(num_deleted != 0)
Max Bires2b2e6562020-09-22 11:22:36 -07001805 })
1806 .context("In delete_expired_attestation_keys: ")
1807 }
1808
Max Bires60d7ed12021-03-05 15:59:22 -08001809 /// Deletes all remotely provisioned attestation keys in the system, regardless of the state
1810 /// they are in. This is useful primarily as a testing mechanism.
1811 pub fn delete_all_attestation_keys(&mut self) -> Result<i64> {
1812 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1813 let mut stmt = tx
1814 .prepare(
1815 "SELECT id FROM persistent.keyentry
1816 WHERE key_type IS ?;",
1817 )
1818 .context("Failed to prepare statement")?;
1819 let keys_to_delete = stmt
1820 .query_map(params![KeyType::Attestation], |row| Ok(row.get(0)?))?
1821 .collect::<rusqlite::Result<Vec<i64>>>()
1822 .context("Failed to execute statement")?;
1823 let num_deleted = keys_to_delete
1824 .iter()
1825 .map(|id| Self::mark_unreferenced(&tx, *id))
1826 .collect::<Result<Vec<bool>>>()
1827 .context("Failed to execute mark_unreferenced on a keyid")?
1828 .into_iter()
1829 .filter(|result| *result)
1830 .count() as i64;
1831 Ok(num_deleted).do_gc(num_deleted != 0)
1832 })
1833 .context("In delete_all_attestation_keys: ")
1834 }
1835
Max Bires2b2e6562020-09-22 11:22:36 -07001836 /// Counts the number of keys that will expire by the provided epoch date and the number of
1837 /// keys not currently assigned to a domain.
1838 pub fn get_attestation_pool_status(
1839 &mut self,
1840 date: i64,
1841 km_uuid: &Uuid,
1842 ) -> Result<AttestationPoolStatus> {
1843 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1844 let mut stmt = tx.prepare(
1845 "SELECT data
1846 FROM persistent.keymetadata
1847 WHERE tag = ? AND keyentryid IN
1848 (SELECT id
1849 FROM persistent.keyentry
1850 WHERE alias IS NOT NULL
1851 AND key_type = ?
1852 AND km_uuid = ?
1853 AND state = ?);",
1854 )?;
1855 let times = stmt
1856 .query_map(
1857 params![
1858 KeyMetaData::AttestationExpirationDate,
1859 KeyType::Attestation,
1860 km_uuid,
1861 KeyLifeCycle::Live
1862 ],
1863 |row| Ok(row.get(0)?),
1864 )?
1865 .collect::<rusqlite::Result<Vec<DateTime>>>()
1866 .context("Failed to execute metadata statement")?;
1867 let expiring =
1868 times.iter().filter(|time| time < &&DateTime::from_millis_epoch(date)).count()
1869 as i32;
1870 stmt = tx.prepare(
1871 "SELECT alias, domain
1872 FROM persistent.keyentry
1873 WHERE key_type = ? AND km_uuid = ? AND state = ?;",
1874 )?;
1875 let rows = stmt
1876 .query_map(params![KeyType::Attestation, km_uuid, KeyLifeCycle::Live], |row| {
1877 Ok((row.get(0)?, row.get(1)?))
1878 })?
1879 .collect::<rusqlite::Result<Vec<(Option<String>, Option<u32>)>>>()
1880 .context("Failed to execute keyentry statement")?;
1881 let mut unassigned = 0i32;
1882 let mut attested = 0i32;
1883 let total = rows.len() as i32;
1884 for (alias, domain) in rows {
1885 match (alias, domain) {
1886 (Some(_alias), None) => {
1887 attested += 1;
1888 unassigned += 1;
1889 }
1890 (Some(_alias), Some(_domain)) => {
1891 attested += 1;
1892 }
1893 _ => {}
1894 }
1895 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001896 Ok(AttestationPoolStatus { expiring, unassigned, attested, total }).no_gc()
Max Bires2b2e6562020-09-22 11:22:36 -07001897 })
1898 .context("In get_attestation_pool_status: ")
1899 }
1900
1901 /// Fetches the private key and corresponding certificate chain assigned to a
1902 /// domain/namespace pair. Will either return nothing if the domain/namespace is
1903 /// not assigned, or one CertificateChain.
1904 pub fn retrieve_attestation_key_and_cert_chain(
1905 &mut self,
1906 domain: Domain,
1907 namespace: i64,
1908 km_uuid: &Uuid,
1909 ) -> Result<Option<CertificateChain>> {
1910 match domain {
1911 Domain::APP | Domain::SELINUX => {}
1912 _ => {
1913 return Err(KsError::sys())
1914 .context(format!("Domain {:?} must be either App or SELinux.", domain));
1915 }
1916 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001917 self.with_transaction(TransactionBehavior::Deferred, |tx| {
1918 let mut stmt = tx.prepare(
1919 "SELECT subcomponent_type, blob
Max Bires2b2e6562020-09-22 11:22:36 -07001920 FROM persistent.blobentry
1921 WHERE keyentryid IN
1922 (SELECT id
1923 FROM persistent.keyentry
1924 WHERE key_type = ?
1925 AND domain = ?
1926 AND namespace = ?
1927 AND state = ?
1928 AND km_uuid = ?);",
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001929 )?;
1930 let rows = stmt
1931 .query_map(
1932 params![
1933 KeyType::Attestation,
1934 domain.0 as u32,
1935 namespace,
1936 KeyLifeCycle::Live,
1937 km_uuid
1938 ],
1939 |row| Ok((row.get(0)?, row.get(1)?)),
1940 )?
1941 .collect::<rusqlite::Result<Vec<(SubComponentType, Vec<u8>)>>>()
Max Biresb2e1d032021-02-08 21:35:05 -08001942 .context("query failed.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001943 if rows.is_empty() {
1944 return Ok(None).no_gc();
Max Biresb2e1d032021-02-08 21:35:05 -08001945 } else if rows.len() != 3 {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001946 return Err(KsError::sys()).context(format!(
1947 concat!(
Max Biresb2e1d032021-02-08 21:35:05 -08001948 "Expected to get a single attestation",
1949 "key, cert, and cert chain for a total of 3 entries, but instead got {}."
1950 ),
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001951 rows.len()
1952 ));
Max Bires2b2e6562020-09-22 11:22:36 -07001953 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001954 let mut km_blob: Vec<u8> = Vec::new();
1955 let mut cert_chain_blob: Vec<u8> = Vec::new();
Max Biresb2e1d032021-02-08 21:35:05 -08001956 let mut batch_cert_blob: Vec<u8> = Vec::new();
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001957 for row in rows {
1958 let sub_type: SubComponentType = row.0;
1959 match sub_type {
1960 SubComponentType::KEY_BLOB => {
1961 km_blob = row.1;
1962 }
1963 SubComponentType::CERT_CHAIN => {
1964 cert_chain_blob = row.1;
1965 }
Max Biresb2e1d032021-02-08 21:35:05 -08001966 SubComponentType::CERT => {
1967 batch_cert_blob = row.1;
1968 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001969 _ => Err(KsError::sys()).context("Unknown or incorrect subcomponent type.")?,
1970 }
1971 }
1972 Ok(Some(CertificateChain {
1973 private_key: ZVec::try_from(km_blob)?,
Max Bires97f96812021-02-23 23:44:57 -08001974 batch_cert: batch_cert_blob,
1975 cert_chain: cert_chain_blob,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001976 }))
1977 .no_gc()
1978 })
Max Biresb2e1d032021-02-08 21:35:05 -08001979 .context("In retrieve_attestation_key_and_cert_chain:")
Max Bires2b2e6562020-09-22 11:22:36 -07001980 }
1981
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001982 /// Updates the alias column of the given key id `newid` with the given alias,
1983 /// and atomically, removes the alias, domain, and namespace from another row
1984 /// with the same alias-domain-namespace tuple if such row exits.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001985 /// Returns Ok(true) if an old key was marked unreferenced as a hint to the garbage
1986 /// collector.
1987 fn rebind_alias(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001988 tx: &Transaction,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001989 newid: &KeyIdGuard,
Joel Galenson33c04ad2020-08-03 11:04:38 -07001990 alias: &str,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001991 domain: &Domain,
1992 namespace: &i64,
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001993 ) -> Result<bool> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001994 match *domain {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001995 Domain::APP | Domain::SELINUX => {}
Joel Galenson33c04ad2020-08-03 11:04:38 -07001996 _ => {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001997 return Err(KsError::sys()).context(format!(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001998 "In rebind_alias: Domain {:?} must be either App or SELinux.",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001999 domain
2000 ));
Joel Galenson33c04ad2020-08-03 11:04:38 -07002001 }
2002 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002003 let updated = tx
2004 .execute(
2005 "UPDATE persistent.keyentry
2006 SET alias = NULL, domain = NULL, namespace = NULL, state = ?
Joel Galenson33c04ad2020-08-03 11:04:38 -07002007 WHERE alias = ? AND domain = ? AND namespace = ?;",
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002008 params![KeyLifeCycle::Unreferenced, alias, domain.0 as u32, namespace],
2009 )
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002010 .context("In rebind_alias: Failed to rebind existing entry.")?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07002011 let result = tx
2012 .execute(
2013 "UPDATE persistent.keyentry
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002014 SET alias = ?, state = ?
2015 WHERE id = ? AND domain = ? AND namespace = ? AND state = ?;",
2016 params![
2017 alias,
2018 KeyLifeCycle::Live,
2019 newid.0,
2020 domain.0 as u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002021 *namespace,
Max Bires8e93d2b2021-01-14 13:17:59 -08002022 KeyLifeCycle::Existing,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002023 ],
Joel Galenson33c04ad2020-08-03 11:04:38 -07002024 )
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002025 .context("In rebind_alias: Failed to set alias.")?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07002026 if result != 1 {
Joel Galenson33c04ad2020-08-03 11:04:38 -07002027 return Err(KsError::sys()).context(format!(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002028 "In rebind_alias: Expected to update a single entry but instead updated {}.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07002029 result
2030 ));
2031 }
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002032 Ok(updated != 0)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002033 }
2034
2035 /// Store a new key in a single transaction.
2036 /// The function creates a new key entry, populates the blob, key parameter, and metadata
2037 /// fields, and rebinds the given alias to the new key.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002038 /// The boolean returned is a hint for the garbage collector. If true, a key was replaced,
2039 /// is now unreferenced and needs to be collected.
Janis Danisevskis66784c42021-01-27 08:40:25 -08002040 pub fn store_new_key(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002041 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002042 key: &KeyDescriptor,
2043 params: &[KeyParameter],
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002044 blob_info: &(&[u8], &BlobMetaData),
Max Bires8e93d2b2021-01-14 13:17:59 -08002045 cert_info: &CertificateInfo,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002046 metadata: &KeyMetaData,
Max Bires8e93d2b2021-01-14 13:17:59 -08002047 km_uuid: &Uuid,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002048 ) -> Result<KeyIdGuard> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002049 let (alias, domain, namespace) = match key {
2050 KeyDescriptor { alias: Some(alias), domain: Domain::APP, nspace, blob: None }
2051 | KeyDescriptor { alias: Some(alias), domain: Domain::SELINUX, nspace, blob: None } => {
2052 (alias, key.domain, nspace)
2053 }
2054 _ => {
2055 return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT))
2056 .context("In store_new_key: Need alias and domain must be APP or SELINUX.")
2057 }
2058 };
2059 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002060 let key_id = Self::create_key_entry_internal(tx, &domain, namespace, km_uuid)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002061 .context("Trying to create new key entry.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002062 let (blob, blob_metadata) = *blob_info;
2063 Self::set_blob_internal(
2064 tx,
2065 key_id.id(),
2066 SubComponentType::KEY_BLOB,
2067 Some(blob),
2068 Some(&blob_metadata),
2069 )
2070 .context("Trying to insert the key blob.")?;
Max Bires8e93d2b2021-01-14 13:17:59 -08002071 if let Some(cert) = &cert_info.cert {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002072 Self::set_blob_internal(tx, key_id.id(), SubComponentType::CERT, Some(&cert), None)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002073 .context("Trying to insert the certificate.")?;
2074 }
Max Bires8e93d2b2021-01-14 13:17:59 -08002075 if let Some(cert_chain) = &cert_info.cert_chain {
Janis Danisevskis377d1002021-01-27 19:07:48 -08002076 Self::set_blob_internal(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002077 tx,
2078 key_id.id(),
2079 SubComponentType::CERT_CHAIN,
Janis Danisevskis377d1002021-01-27 19:07:48 -08002080 Some(&cert_chain),
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002081 None,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002082 )
2083 .context("Trying to insert the certificate chain.")?;
2084 }
2085 Self::insert_keyparameter_internal(tx, &key_id, params)
2086 .context("Trying to insert key parameters.")?;
Janis Danisevskis377d1002021-01-27 19:07:48 -08002087 metadata.store_in_db(key_id.id(), tx).context("Trying to insert key metadata.")?;
Janis Danisevskis66784c42021-01-27 08:40:25 -08002088 let need_gc = Self::rebind_alias(tx, &key_id, &alias, &domain, namespace)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002089 .context("Trying to rebind alias.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002090 Ok(key_id).do_gc(need_gc)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002091 })
2092 .context("In store_new_key.")
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002093 }
2094
Janis Danisevskis377d1002021-01-27 19:07:48 -08002095 /// Store a new certificate
2096 /// The function creates a new key entry, populates the blob field and metadata, and rebinds
2097 /// the given alias to the new cert.
Max Bires8e93d2b2021-01-14 13:17:59 -08002098 pub fn store_new_certificate(
2099 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002100 key: &KeyDescriptor,
Max Bires8e93d2b2021-01-14 13:17:59 -08002101 cert: &[u8],
2102 km_uuid: &Uuid,
2103 ) -> Result<KeyIdGuard> {
Janis Danisevskis377d1002021-01-27 19:07:48 -08002104 let (alias, domain, namespace) = match key {
2105 KeyDescriptor { alias: Some(alias), domain: Domain::APP, nspace, blob: None }
2106 | KeyDescriptor { alias: Some(alias), domain: Domain::SELINUX, nspace, blob: None } => {
2107 (alias, key.domain, nspace)
2108 }
2109 _ => {
2110 return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT)).context(
2111 "In store_new_certificate: Need alias and domain must be APP or SELINUX.",
2112 )
2113 }
2114 };
2115 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002116 let key_id = Self::create_key_entry_internal(tx, &domain, namespace, km_uuid)
Janis Danisevskis377d1002021-01-27 19:07:48 -08002117 .context("Trying to create new key entry.")?;
2118
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002119 Self::set_blob_internal(
2120 tx,
2121 key_id.id(),
2122 SubComponentType::CERT_CHAIN,
2123 Some(cert),
2124 None,
2125 )
2126 .context("Trying to insert certificate.")?;
Janis Danisevskis377d1002021-01-27 19:07:48 -08002127
2128 let mut metadata = KeyMetaData::new();
2129 metadata.add(KeyMetaEntry::CreationDate(
2130 DateTime::now().context("Trying to make creation time.")?,
2131 ));
2132
2133 metadata.store_in_db(key_id.id(), tx).context("Trying to insert key metadata.")?;
2134
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002135 let need_gc = Self::rebind_alias(tx, &key_id, &alias, &domain, namespace)
Janis Danisevskis377d1002021-01-27 19:07:48 -08002136 .context("Trying to rebind alias.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002137 Ok(key_id).do_gc(need_gc)
Janis Danisevskis377d1002021-01-27 19:07:48 -08002138 })
2139 .context("In store_new_certificate.")
2140 }
2141
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002142 // Helper function loading the key_id given the key descriptor
2143 // tuple comprising domain, namespace, and alias.
2144 // Requires a valid transaction.
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002145 fn load_key_entry_id(tx: &Transaction, key: &KeyDescriptor, key_type: KeyType) -> Result<i64> {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002146 let alias = key
2147 .alias
2148 .as_ref()
2149 .map_or_else(|| Err(KsError::sys()), Ok)
2150 .context("In load_key_entry_id: Alias must be specified.")?;
2151 let mut stmt = tx
2152 .prepare(
2153 "SELECT id FROM persistent.keyentry
2154 WHERE
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00002155 key_type = ?
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002156 AND domain = ?
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002157 AND namespace = ?
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002158 AND alias = ?
2159 AND state = ?;",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002160 )
2161 .context("In load_key_entry_id: Failed to select from keyentry table.")?;
2162 let mut rows = stmt
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002163 .query(params![key_type, key.domain.0 as u32, key.nspace, alias, KeyLifeCycle::Live])
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002164 .context("In load_key_entry_id: Failed to read from keyentry table.")?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002165 db_utils::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002166 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002167 .get(0)
2168 .context("Failed to unpack id.")
2169 })
2170 .context("In load_key_entry_id.")
2171 }
2172
2173 /// This helper function completes the access tuple of a key, which is required
2174 /// to perform access control. The strategy depends on the `domain` field in the
2175 /// key descriptor.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002176 /// * Domain::SELINUX: The access tuple is complete and this function only loads
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002177 /// the key_id for further processing.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002178 /// * Domain::APP: Like Domain::SELINUX, but the tuple is completed by `caller_uid`
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002179 /// which serves as the namespace.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002180 /// * Domain::GRANT: The grant table is queried for the `key_id` and the
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002181 /// `access_vector`.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002182 /// * Domain::KEY_ID: The keyentry table is queried for the owning `domain` and
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002183 /// `namespace`.
2184 /// In each case the information returned is sufficient to perform the access
2185 /// check and the key id can be used to load further key artifacts.
2186 fn load_access_tuple(
2187 tx: &Transaction,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002188 key: &KeyDescriptor,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002189 key_type: KeyType,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002190 caller_uid: u32,
2191 ) -> Result<(i64, KeyDescriptor, Option<KeyPermSet>)> {
2192 match key.domain {
2193 // Domain App or SELinux. In this case we load the key_id from
2194 // the keyentry database for further loading of key components.
2195 // We already have the full access tuple to perform access control.
2196 // The only distinction is that we use the caller_uid instead
2197 // of the caller supplied namespace if the domain field is
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002198 // Domain::APP.
2199 Domain::APP | Domain::SELINUX => {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002200 let mut access_key = key.clone();
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002201 if access_key.domain == Domain::APP {
2202 access_key.nspace = caller_uid as i64;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002203 }
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002204 let key_id = Self::load_key_entry_id(&tx, &access_key, key_type)
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002205 .with_context(|| format!("With key.domain = {:?}.", access_key.domain))?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002206
2207 Ok((key_id, access_key, None))
2208 }
2209
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002210 // Domain::GRANT. In this case we load the key_id and the access_vector
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002211 // from the grant table.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002212 Domain::GRANT => {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002213 let mut stmt = tx
2214 .prepare(
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002215 "SELECT keyentryid, access_vector FROM persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002216 WHERE grantee = ? AND id = ?;",
2217 )
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002218 .context("Domain::GRANT prepare statement failed")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002219 let mut rows = stmt
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002220 .query(params![caller_uid as i64, key.nspace])
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002221 .context("Domain:Grant: query failed.")?;
2222 let (key_id, access_vector): (i64, i32) =
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002223 db_utils::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002224 let r =
2225 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002226 Ok((
2227 r.get(0).context("Failed to unpack key_id.")?,
2228 r.get(1).context("Failed to unpack access_vector.")?,
2229 ))
2230 })
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002231 .context("Domain::GRANT.")?;
Janis Danisevskis66784c42021-01-27 08:40:25 -08002232 Ok((key_id, key.clone(), Some(access_vector.into())))
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002233 }
2234
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002235 // Domain::KEY_ID. In this case we load the domain and namespace from the
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002236 // keyentry database because we need them for access control.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002237 Domain::KEY_ID => {
Janis Danisevskis45760022021-01-19 16:34:10 -08002238 let (domain, namespace): (Domain, i64) = {
2239 let mut stmt = tx
2240 .prepare(
2241 "SELECT domain, namespace FROM persistent.keyentry
2242 WHERE
2243 id = ?
2244 AND state = ?;",
2245 )
2246 .context("Domain::KEY_ID: prepare statement failed")?;
2247 let mut rows = stmt
2248 .query(params![key.nspace, KeyLifeCycle::Live])
2249 .context("Domain::KEY_ID: query failed.")?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002250 db_utils::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002251 let r =
2252 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002253 Ok((
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002254 Domain(r.get(0).context("Failed to unpack domain.")?),
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002255 r.get(1).context("Failed to unpack namespace.")?,
2256 ))
2257 })
Janis Danisevskis45760022021-01-19 16:34:10 -08002258 .context("Domain::KEY_ID.")?
2259 };
2260
2261 // We may use a key by id after loading it by grant.
2262 // In this case we have to check if the caller has a grant for this particular
2263 // key. We can skip this if we already know that the caller is the owner.
2264 // But we cannot know this if domain is anything but App. E.g. in the case
2265 // of Domain::SELINUX we have to speculatively check for grants because we have to
2266 // consult the SEPolicy before we know if the caller is the owner.
2267 let access_vector: Option<KeyPermSet> =
2268 if domain != Domain::APP || namespace != caller_uid as i64 {
2269 let access_vector: Option<i32> = tx
2270 .query_row(
2271 "SELECT access_vector FROM persistent.grant
2272 WHERE grantee = ? AND keyentryid = ?;",
2273 params![caller_uid as i64, key.nspace],
2274 |row| row.get(0),
2275 )
2276 .optional()
2277 .context("Domain::KEY_ID: query grant failed.")?;
2278 access_vector.map(|p| p.into())
2279 } else {
2280 None
2281 };
2282
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002283 let key_id = key.nspace;
Janis Danisevskis66784c42021-01-27 08:40:25 -08002284 let mut access_key: KeyDescriptor = key.clone();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002285 access_key.domain = domain;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002286 access_key.nspace = namespace;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002287
Janis Danisevskis45760022021-01-19 16:34:10 -08002288 Ok((key_id, access_key, access_vector))
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002289 }
2290 _ => Err(anyhow!(KsError::sys())),
2291 }
2292 }
2293
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002294 fn load_blob_components(
2295 key_id: i64,
2296 load_bits: KeyEntryLoadBits,
2297 tx: &Transaction,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002298 ) -> Result<(bool, Option<(Vec<u8>, BlobMetaData)>, Option<Vec<u8>>, Option<Vec<u8>>)> {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002299 let mut stmt = tx
2300 .prepare(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002301 "SELECT MAX(id), subcomponent_type, blob FROM persistent.blobentry
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002302 WHERE keyentryid = ? GROUP BY subcomponent_type;",
2303 )
2304 .context("In load_blob_components: prepare statement failed.")?;
2305
2306 let mut rows =
2307 stmt.query(params![key_id]).context("In load_blob_components: query failed.")?;
2308
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002309 let mut key_blob: Option<(i64, Vec<u8>)> = None;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002310 let mut cert_blob: Option<Vec<u8>> = None;
2311 let mut cert_chain_blob: Option<Vec<u8>> = None;
Janis Danisevskis377d1002021-01-27 19:07:48 -08002312 let mut has_km_blob: bool = false;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002313 db_utils::with_rows_extract_all(&mut rows, |row| {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002314 let sub_type: SubComponentType =
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002315 row.get(1).context("Failed to extract subcomponent_type.")?;
Janis Danisevskis377d1002021-01-27 19:07:48 -08002316 has_km_blob = has_km_blob || sub_type == SubComponentType::KEY_BLOB;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002317 match (sub_type, load_bits.load_public(), load_bits.load_km()) {
2318 (SubComponentType::KEY_BLOB, _, true) => {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002319 key_blob = Some((
2320 row.get(0).context("Failed to extract key blob id.")?,
2321 row.get(2).context("Failed to extract key blob.")?,
2322 ));
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002323 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002324 (SubComponentType::CERT, true, _) => {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002325 cert_blob =
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002326 Some(row.get(2).context("Failed to extract public certificate blob.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002327 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002328 (SubComponentType::CERT_CHAIN, true, _) => {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002329 cert_chain_blob =
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002330 Some(row.get(2).context("Failed to extract certificate chain blob.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002331 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002332 (SubComponentType::CERT, _, _)
2333 | (SubComponentType::CERT_CHAIN, _, _)
2334 | (SubComponentType::KEY_BLOB, _, _) => {}
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002335 _ => Err(KsError::sys()).context("Unknown subcomponent type.")?,
2336 }
2337 Ok(())
2338 })
2339 .context("In load_blob_components.")?;
2340
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002341 let blob_info = key_blob.map_or::<Result<_>, _>(Ok(None), |(blob_id, blob)| {
2342 Ok(Some((
2343 blob,
2344 BlobMetaData::load_from_db(blob_id, tx)
2345 .context("In load_blob_components: Trying to load blob_metadata.")?,
2346 )))
2347 })?;
2348
2349 Ok((has_km_blob, blob_info, cert_blob, cert_chain_blob))
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002350 }
2351
2352 fn load_key_parameters(key_id: i64, tx: &Transaction) -> Result<Vec<KeyParameter>> {
2353 let mut stmt = tx
2354 .prepare(
2355 "SELECT tag, data, security_level from persistent.keyparameter
2356 WHERE keyentryid = ?;",
2357 )
2358 .context("In load_key_parameters: prepare statement failed.")?;
2359
2360 let mut parameters: Vec<KeyParameter> = Vec::new();
2361
2362 let mut rows =
2363 stmt.query(params![key_id]).context("In load_key_parameters: query failed.")?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002364 db_utils::with_rows_extract_all(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002365 let tag = Tag(row.get(0).context("Failed to read tag.")?);
2366 let sec_level = SecurityLevel(row.get(2).context("Failed to read sec_level.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002367 parameters.push(
2368 KeyParameter::new_from_sql(tag, &SqlField::new(1, &row), sec_level)
2369 .context("Failed to read KeyParameter.")?,
2370 );
2371 Ok(())
2372 })
2373 .context("In load_key_parameters.")?;
2374
2375 Ok(parameters)
2376 }
2377
Qi Wub9433b52020-12-01 14:52:46 +08002378 /// Decrements the usage count of a limited use key. This function first checks whether the
2379 /// usage has been exhausted, if not, decreases the usage count. If the usage count reaches
2380 /// zero, the key also gets marked unreferenced and scheduled for deletion.
2381 /// Returns Ok(true) if the key was marked unreferenced as a hint to the garbage collector.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002382 pub fn check_and_update_key_usage_count(&mut self, key_id: i64) -> Result<()> {
Qi Wub9433b52020-12-01 14:52:46 +08002383 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2384 let limit: Option<i32> = tx
2385 .query_row(
2386 "SELECT data FROM persistent.keyparameter WHERE keyentryid = ? AND tag = ?;",
2387 params![key_id, Tag::USAGE_COUNT_LIMIT.0],
2388 |row| row.get(0),
2389 )
2390 .optional()
2391 .context("Trying to load usage count")?;
2392
2393 let limit = limit
2394 .ok_or(KsError::Km(ErrorCode::INVALID_KEY_BLOB))
2395 .context("The Key no longer exists. Key is exhausted.")?;
2396
2397 tx.execute(
2398 "UPDATE persistent.keyparameter
2399 SET data = data - 1
2400 WHERE keyentryid = ? AND tag = ? AND data > 0;",
2401 params![key_id, Tag::USAGE_COUNT_LIMIT.0],
2402 )
2403 .context("Failed to update key usage count.")?;
2404
2405 match limit {
2406 1 => Self::mark_unreferenced(tx, key_id)
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002407 .map(|need_gc| (need_gc, ()))
Qi Wub9433b52020-12-01 14:52:46 +08002408 .context("Trying to mark limited use key for deletion."),
2409 0 => Err(KsError::Km(ErrorCode::INVALID_KEY_BLOB)).context("Key is exhausted."),
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002410 _ => Ok(()).no_gc(),
Qi Wub9433b52020-12-01 14:52:46 +08002411 }
2412 })
2413 .context("In check_and_update_key_usage_count.")
2414 }
2415
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002416 /// Load a key entry by the given key descriptor.
2417 /// It uses the `check_permission` callback to verify if the access is allowed
2418 /// given the key access tuple read from the database using `load_access_tuple`.
2419 /// With `load_bits` the caller may specify which blobs shall be loaded from
2420 /// the blob database.
2421 pub fn load_key_entry(
2422 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002423 key: &KeyDescriptor,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002424 key_type: KeyType,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002425 load_bits: KeyEntryLoadBits,
2426 caller_uid: u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002427 check_permission: impl Fn(&KeyDescriptor, Option<KeyPermSet>) -> Result<()>,
2428 ) -> Result<(KeyIdGuard, KeyEntry)> {
2429 loop {
2430 match self.load_key_entry_internal(
2431 key,
2432 key_type,
2433 load_bits,
2434 caller_uid,
2435 &check_permission,
2436 ) {
2437 Ok(result) => break Ok(result),
2438 Err(e) => {
2439 if Self::is_locked_error(&e) {
2440 std::thread::sleep(std::time::Duration::from_micros(500));
2441 continue;
2442 } else {
2443 return Err(e).context("In load_key_entry.");
2444 }
2445 }
2446 }
2447 }
2448 }
2449
2450 fn load_key_entry_internal(
2451 &mut self,
2452 key: &KeyDescriptor,
2453 key_type: KeyType,
2454 load_bits: KeyEntryLoadBits,
2455 caller_uid: u32,
2456 check_permission: &impl Fn(&KeyDescriptor, Option<KeyPermSet>) -> Result<()>,
Janis Danisevskisaec14592020-11-12 09:41:49 -08002457 ) -> Result<(KeyIdGuard, KeyEntry)> {
2458 // KEY ID LOCK 1/2
2459 // If we got a key descriptor with a key id we can get the lock right away.
2460 // Otherwise we have to defer it until we know the key id.
2461 let key_id_guard = match key.domain {
2462 Domain::KEY_ID => Some(KEY_ID_LOCK.get(key.nspace)),
2463 _ => None,
2464 };
2465
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002466 let tx = self
2467 .conn
Janis Danisevskisaec14592020-11-12 09:41:49 -08002468 .unchecked_transaction()
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002469 .context("In load_key_entry: Failed to initialize transaction.")?;
2470
2471 // Load the key_id and complete the access control tuple.
2472 let (key_id, access_key_descriptor, access_vector) =
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002473 Self::load_access_tuple(&tx, key, key_type, caller_uid)
2474 .context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002475
2476 // Perform access control. It is vital that we return here if the permission is denied.
2477 // So do not touch that '?' at the end.
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002478 check_permission(&access_key_descriptor, access_vector).context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002479
Janis Danisevskisaec14592020-11-12 09:41:49 -08002480 // KEY ID LOCK 2/2
2481 // If we did not get a key id lock by now, it was because we got a key descriptor
2482 // without a key id. At this point we got the key id, so we can try and get a lock.
2483 // However, we cannot block here, because we are in the middle of the transaction.
2484 // So first we try to get the lock non blocking. If that fails, we roll back the
2485 // transaction and block until we get the lock. After we successfully got the lock,
2486 // we start a new transaction and load the access tuple again.
2487 //
2488 // We don't need to perform access control again, because we already established
2489 // that the caller had access to the given key. But we need to make sure that the
2490 // key id still exists. So we have to load the key entry by key id this time.
2491 let (key_id_guard, tx) = match key_id_guard {
2492 None => match KEY_ID_LOCK.try_get(key_id) {
2493 None => {
2494 // Roll back the transaction.
2495 tx.rollback().context("In load_key_entry: Failed to roll back transaction.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002496
Janis Danisevskisaec14592020-11-12 09:41:49 -08002497 // Block until we have a key id lock.
2498 let key_id_guard = KEY_ID_LOCK.get(key_id);
2499
2500 // Create a new transaction.
Janis Danisevskis66784c42021-01-27 08:40:25 -08002501 let tx = self
2502 .conn
2503 .unchecked_transaction()
2504 .context("In load_key_entry: Failed to initialize transaction.")?;
Janis Danisevskisaec14592020-11-12 09:41:49 -08002505
2506 Self::load_access_tuple(
2507 &tx,
2508 // This time we have to load the key by the retrieved key id, because the
2509 // alias may have been rebound after we rolled back the transaction.
Janis Danisevskis66784c42021-01-27 08:40:25 -08002510 &KeyDescriptor {
Janis Danisevskisaec14592020-11-12 09:41:49 -08002511 domain: Domain::KEY_ID,
2512 nspace: key_id,
2513 ..Default::default()
2514 },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002515 key_type,
Janis Danisevskisaec14592020-11-12 09:41:49 -08002516 caller_uid,
2517 )
2518 .context("In load_key_entry. (deferred key lock)")?;
2519 (key_id_guard, tx)
2520 }
2521 Some(l) => (l, tx),
2522 },
2523 Some(key_id_guard) => (key_id_guard, tx),
2524 };
2525
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002526 let key_entry = Self::load_key_components(&tx, load_bits, key_id_guard.id())
2527 .context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002528
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002529 tx.commit().context("In load_key_entry: Failed to commit transaction.")?;
2530
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002531 Ok((key_id_guard, key_entry))
2532 }
2533
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002534 fn mark_unreferenced(tx: &Transaction, key_id: i64) -> Result<bool> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002535 let updated = tx
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002536 .execute("DELETE FROM persistent.keyentry WHERE id = ?;", params![key_id])
2537 .context("Trying to delete keyentry.")?;
2538 tx.execute("DELETE FROM persistent.keymetadata WHERE keyentryid = ?;", params![key_id])
2539 .context("Trying to delete keymetadata.")?;
2540 tx.execute("DELETE FROM persistent.keyparameter WHERE keyentryid = ?;", params![key_id])
2541 .context("Trying to delete keyparameters.")?;
2542 tx.execute("DELETE FROM persistent.grant WHERE keyentryid = ?;", params![key_id])
2543 .context("Trying to delete grants.")?;
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002544 Ok(updated != 0)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002545 }
2546
2547 /// Marks the given key as unreferenced and removes all of the grants to this key.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002548 /// Returns Ok(true) if a key was marked unreferenced as a hint for the garbage collector.
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002549 pub fn unbind_key(
2550 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002551 key: &KeyDescriptor,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002552 key_type: KeyType,
2553 caller_uid: u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002554 check_permission: impl Fn(&KeyDescriptor, Option<KeyPermSet>) -> Result<()>,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002555 ) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002556 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2557 let (key_id, access_key_descriptor, access_vector) =
2558 Self::load_access_tuple(tx, key, key_type, caller_uid)
2559 .context("Trying to get access tuple.")?;
2560
2561 // Perform access control. It is vital that we return here if the permission is denied.
2562 // So do not touch that '?' at the end.
2563 check_permission(&access_key_descriptor, access_vector)
2564 .context("While checking permission.")?;
2565
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002566 Self::mark_unreferenced(tx, key_id)
2567 .map(|need_gc| (need_gc, ()))
2568 .context("Trying to mark the key unreferenced.")
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002569 })
2570 .context("In unbind_key.")
2571 }
2572
Max Bires8e93d2b2021-01-14 13:17:59 -08002573 fn get_key_km_uuid(tx: &Transaction, key_id: i64) -> Result<Uuid> {
2574 tx.query_row(
2575 "SELECT km_uuid FROM persistent.keyentry WHERE id = ?",
2576 params![key_id],
2577 |row| row.get(0),
2578 )
2579 .context("In get_key_km_uuid.")
2580 }
2581
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002582 /// Delete all artifacts belonging to the namespace given by the domain-namespace tuple.
2583 /// This leaves all of the blob entries orphaned for subsequent garbage collection.
2584 pub fn unbind_keys_for_namespace(&mut self, domain: Domain, namespace: i64) -> Result<()> {
2585 if !(domain == Domain::APP || domain == Domain::SELINUX) {
2586 return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT))
2587 .context("In unbind_keys_for_namespace.");
2588 }
2589 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2590 tx.execute(
2591 "DELETE FROM persistent.keymetadata
2592 WHERE keyentryid IN (
2593 SELECT id FROM persistent.keyentry
2594 WHERE domain = ? AND namespace = ?
2595 );",
2596 params![domain.0, namespace],
2597 )
2598 .context("Trying to delete keymetadata.")?;
2599 tx.execute(
2600 "DELETE FROM persistent.keyparameter
2601 WHERE keyentryid IN (
2602 SELECT id FROM persistent.keyentry
2603 WHERE domain = ? AND namespace = ?
2604 );",
2605 params![domain.0, namespace],
2606 )
2607 .context("Trying to delete keyparameters.")?;
2608 tx.execute(
2609 "DELETE FROM persistent.grant
2610 WHERE keyentryid IN (
2611 SELECT id FROM persistent.keyentry
2612 WHERE domain = ? AND namespace = ?
2613 );",
2614 params![domain.0, namespace],
2615 )
2616 .context("Trying to delete grants.")?;
2617 tx.execute(
2618 "DELETE FROM persistent.keyentry WHERE domain = ? AND namespace = ?;",
2619 params![domain.0, namespace],
2620 )
2621 .context("Trying to delete keyentry.")?;
2622 Ok(()).need_gc()
2623 })
2624 .context("In unbind_keys_for_namespace")
2625 }
2626
Hasini Gunasingheda895552021-01-27 19:34:37 +00002627 /// Delete the keys created on behalf of the user, denoted by the user id.
2628 /// Delete all the keys unless 'keep_non_super_encrypted_keys' set to true.
2629 /// Returned boolean is to hint the garbage collector to delete the unbound keys.
2630 /// The caller of this function should notify the gc if the returned value is true.
2631 pub fn unbind_keys_for_user(
2632 &mut self,
2633 user_id: u32,
2634 keep_non_super_encrypted_keys: bool,
2635 ) -> Result<()> {
2636 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2637 let mut stmt = tx
2638 .prepare(&format!(
2639 "SELECT id from persistent.keyentry
2640 WHERE (
2641 key_type = ?
2642 AND domain = ?
2643 AND cast ( (namespace/{aid_user_offset}) as int) = ?
2644 AND state = ?
2645 ) OR (
2646 key_type = ?
2647 AND namespace = ?
2648 AND alias = ?
2649 AND state = ?
2650 );",
2651 aid_user_offset = AID_USER_OFFSET
2652 ))
2653 .context(concat!(
2654 "In unbind_keys_for_user. ",
2655 "Failed to prepare the query to find the keys created by apps."
2656 ))?;
2657
2658 let mut rows = stmt
2659 .query(params![
2660 // WHERE client key:
2661 KeyType::Client,
2662 Domain::APP.0 as u32,
2663 user_id,
2664 KeyLifeCycle::Live,
2665 // OR super key:
2666 KeyType::Super,
2667 user_id,
Paul Crowley7a658392021-03-18 17:08:20 -07002668 USER_SUPER_KEY.alias,
Hasini Gunasingheda895552021-01-27 19:34:37 +00002669 KeyLifeCycle::Live
2670 ])
2671 .context("In unbind_keys_for_user. Failed to query the keys created by apps.")?;
2672
2673 let mut key_ids: Vec<i64> = Vec::new();
2674 db_utils::with_rows_extract_all(&mut rows, |row| {
2675 key_ids
2676 .push(row.get(0).context("Failed to read key id of a key created by an app.")?);
2677 Ok(())
2678 })
2679 .context("In unbind_keys_for_user.")?;
2680
2681 let mut notify_gc = false;
2682 for key_id in key_ids {
2683 if keep_non_super_encrypted_keys {
2684 // Load metadata and filter out non-super-encrypted keys.
2685 if let (_, Some((_, blob_metadata)), _, _) =
2686 Self::load_blob_components(key_id, KeyEntryLoadBits::KM, tx)
2687 .context("In unbind_keys_for_user: Trying to load blob info.")?
2688 {
2689 if blob_metadata.encrypted_by().is_none() {
2690 continue;
2691 }
2692 }
2693 }
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +00002694 notify_gc = Self::mark_unreferenced(&tx, key_id)
Hasini Gunasingheda895552021-01-27 19:34:37 +00002695 .context("In unbind_keys_for_user.")?
2696 || notify_gc;
2697 }
2698 Ok(()).do_gc(notify_gc)
2699 })
2700 .context("In unbind_keys_for_user.")
2701 }
2702
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002703 fn load_key_components(
2704 tx: &Transaction,
2705 load_bits: KeyEntryLoadBits,
2706 key_id: i64,
2707 ) -> Result<KeyEntry> {
2708 let metadata = KeyMetaData::load_from_db(key_id, &tx).context("In load_key_components.")?;
2709
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002710 let (has_km_blob, key_blob_info, cert_blob, cert_chain_blob) =
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002711 Self::load_blob_components(key_id, load_bits, &tx)
2712 .context("In load_key_components.")?;
2713
Max Bires8e93d2b2021-01-14 13:17:59 -08002714 let parameters = Self::load_key_parameters(key_id, &tx)
2715 .context("In load_key_components: Trying to load key parameters.")?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002716
Max Bires8e93d2b2021-01-14 13:17:59 -08002717 let km_uuid = Self::get_key_km_uuid(&tx, key_id)
2718 .context("In load_key_components: Trying to get KM uuid.")?;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002719
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002720 Ok(KeyEntry {
2721 id: key_id,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002722 key_blob_info,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002723 cert: cert_blob,
2724 cert_chain: cert_chain_blob,
Max Bires8e93d2b2021-01-14 13:17:59 -08002725 km_uuid,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002726 parameters,
2727 metadata,
Janis Danisevskis377d1002021-01-27 19:07:48 -08002728 pure_cert: !has_km_blob,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002729 })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002730 }
2731
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002732 /// Returns a list of KeyDescriptors in the selected domain/namespace.
2733 /// The key descriptors will have the domain, nspace, and alias field set.
2734 /// Domain must be APP or SELINUX, the caller must make sure of that.
2735 pub fn list(&mut self, domain: Domain, namespace: i64) -> Result<Vec<KeyDescriptor>> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002736 self.with_transaction(TransactionBehavior::Deferred, |tx| {
2737 let mut stmt = tx
2738 .prepare(
2739 "SELECT alias FROM persistent.keyentry
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002740 WHERE domain = ? AND namespace = ? AND alias IS NOT NULL AND state = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08002741 )
2742 .context("In list: Failed to prepare.")?;
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002743
Janis Danisevskis66784c42021-01-27 08:40:25 -08002744 let mut rows = stmt
2745 .query(params![domain.0 as u32, namespace, KeyLifeCycle::Live])
2746 .context("In list: Failed to query.")?;
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002747
Janis Danisevskis66784c42021-01-27 08:40:25 -08002748 let mut descriptors: Vec<KeyDescriptor> = Vec::new();
2749 db_utils::with_rows_extract_all(&mut rows, |row| {
2750 descriptors.push(KeyDescriptor {
2751 domain,
2752 nspace: namespace,
2753 alias: Some(row.get(0).context("Trying to extract alias.")?),
2754 blob: None,
2755 });
2756 Ok(())
2757 })
2758 .context("In list: Failed to extract rows.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002759 Ok(descriptors).no_gc()
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002760 })
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002761 }
2762
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002763 /// Adds a grant to the grant table.
2764 /// Like `load_key_entry` this function loads the access tuple before
2765 /// it uses the callback for a permission check. Upon success,
2766 /// it inserts the `grantee_uid`, `key_id`, and `access_vector` into the
2767 /// grant table. The new row will have a randomized id, which is used as
2768 /// grant id in the namespace field of the resulting KeyDescriptor.
2769 pub fn grant(
2770 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002771 key: &KeyDescriptor,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002772 caller_uid: u32,
2773 grantee_uid: u32,
2774 access_vector: KeyPermSet,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002775 check_permission: impl Fn(&KeyDescriptor, &KeyPermSet) -> Result<()>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002776 ) -> Result<KeyDescriptor> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002777 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2778 // Load the key_id and complete the access control tuple.
2779 // We ignore the access vector here because grants cannot be granted.
2780 // The access vector returned here expresses the permissions the
2781 // grantee has if key.domain == Domain::GRANT. But this vector
2782 // cannot include the grant permission by design, so there is no way the
2783 // subsequent permission check can pass.
2784 // We could check key.domain == Domain::GRANT and fail early.
2785 // But even if we load the access tuple by grant here, the permission
2786 // check denies the attempt to create a grant by grant descriptor.
2787 let (key_id, access_key_descriptor, _) =
2788 Self::load_access_tuple(&tx, key, KeyType::Client, caller_uid)
2789 .context("In grant")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002790
Janis Danisevskis66784c42021-01-27 08:40:25 -08002791 // Perform access control. It is vital that we return here if the permission
2792 // was denied. So do not touch that '?' at the end of the line.
2793 // This permission check checks if the caller has the grant permission
2794 // for the given key and in addition to all of the permissions
2795 // expressed in `access_vector`.
2796 check_permission(&access_key_descriptor, &access_vector)
2797 .context("In grant: check_permission failed.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002798
Janis Danisevskis66784c42021-01-27 08:40:25 -08002799 let grant_id = if let Some(grant_id) = tx
2800 .query_row(
2801 "SELECT id FROM persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002802 WHERE keyentryid = ? AND grantee = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08002803 params![key_id, grantee_uid],
2804 |row| row.get(0),
2805 )
2806 .optional()
2807 .context("In grant: Failed get optional existing grant id.")?
2808 {
2809 tx.execute(
2810 "UPDATE persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002811 SET access_vector = ?
2812 WHERE id = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08002813 params![i32::from(access_vector), grant_id],
Joel Galenson845f74b2020-09-09 14:11:55 -07002814 )
Janis Danisevskis66784c42021-01-27 08:40:25 -08002815 .context("In grant: Failed to update existing grant.")?;
2816 grant_id
2817 } else {
2818 Self::insert_with_retry(|id| {
2819 tx.execute(
2820 "INSERT INTO persistent.grant (id, grantee, keyentryid, access_vector)
2821 VALUES (?, ?, ?, ?);",
2822 params![id, grantee_uid, key_id, i32::from(access_vector)],
2823 )
2824 })
2825 .context("In grant")?
2826 };
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002827
Janis Danisevskis66784c42021-01-27 08:40:25 -08002828 Ok(KeyDescriptor { domain: Domain::GRANT, nspace: grant_id, alias: None, blob: None })
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002829 .no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08002830 })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002831 }
2832
2833 /// This function checks permissions like `grant` and `load_key_entry`
2834 /// before removing a grant from the grant table.
2835 pub fn ungrant(
2836 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002837 key: &KeyDescriptor,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002838 caller_uid: u32,
2839 grantee_uid: u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002840 check_permission: impl Fn(&KeyDescriptor) -> Result<()>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002841 ) -> Result<()> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002842 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2843 // Load the key_id and complete the access control tuple.
2844 // We ignore the access vector here because grants cannot be granted.
2845 let (key_id, access_key_descriptor, _) =
2846 Self::load_access_tuple(&tx, key, KeyType::Client, caller_uid)
2847 .context("In ungrant.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002848
Janis Danisevskis66784c42021-01-27 08:40:25 -08002849 // Perform access control. We must return here if the permission
2850 // was denied. So do not touch the '?' at the end of this line.
2851 check_permission(&access_key_descriptor)
2852 .context("In grant: check_permission failed.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002853
Janis Danisevskis66784c42021-01-27 08:40:25 -08002854 tx.execute(
2855 "DELETE FROM persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002856 WHERE keyentryid = ? AND grantee = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08002857 params![key_id, grantee_uid],
2858 )
2859 .context("Failed to delete grant.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002860
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002861 Ok(()).no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08002862 })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002863 }
2864
Joel Galenson845f74b2020-09-09 14:11:55 -07002865 // Generates a random id and passes it to the given function, which will
2866 // try to insert it into a database. If that insertion fails, retry;
2867 // otherwise return the id.
2868 fn insert_with_retry(inserter: impl Fn(i64) -> rusqlite::Result<usize>) -> Result<i64> {
2869 loop {
Janis Danisevskiseed69842021-02-18 20:04:10 -08002870 let newid: i64 = match random() {
2871 Self::UNASSIGNED_KEY_ID => continue, // UNASSIGNED_KEY_ID cannot be assigned.
2872 i => i,
2873 };
Joel Galenson845f74b2020-09-09 14:11:55 -07002874 match inserter(newid) {
2875 // If the id already existed, try again.
2876 Err(rusqlite::Error::SqliteFailure(
2877 libsqlite3_sys::Error {
2878 code: libsqlite3_sys::ErrorCode::ConstraintViolation,
2879 extended_code: libsqlite3_sys::SQLITE_CONSTRAINT_UNIQUE,
2880 },
2881 _,
2882 )) => (),
2883 Err(e) => {
2884 return Err(e).context("In insert_with_retry: failed to insert into database.")
2885 }
2886 _ => return Ok(newid),
2887 }
2888 }
2889 }
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002890
2891 /// Insert or replace the auth token based on the UNIQUE constraint of the auth token table
2892 pub fn insert_auth_token(&mut self, auth_token: &HardwareAuthToken) -> Result<()> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002893 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2894 tx.execute(
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002895 "INSERT OR REPLACE INTO perboot.authtoken (challenge, user_id, auth_id,
2896 authenticator_type, timestamp, mac, time_received) VALUES(?, ?, ?, ?, ?, ?, ?);",
2897 params![
2898 auth_token.challenge,
2899 auth_token.userId,
2900 auth_token.authenticatorId,
2901 auth_token.authenticatorType.0 as i32,
2902 auth_token.timestamp.milliSeconds as i64,
2903 auth_token.mac,
2904 MonotonicRawTime::now(),
2905 ],
2906 )
2907 .context("In insert_auth_token: failed to insert auth token into the database")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002908 Ok(()).no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08002909 })
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002910 }
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002911
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002912 /// Find the newest auth token matching the given predicate.
2913 pub fn find_auth_token_entry<F>(
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002914 &mut self,
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002915 p: F,
2916 ) -> Result<Option<(AuthTokenEntry, MonotonicRawTime)>>
2917 where
2918 F: Fn(&AuthTokenEntry) -> bool,
2919 {
2920 self.with_transaction(TransactionBehavior::Deferred, |tx| {
2921 let mut stmt = tx
2922 .prepare("SELECT * from perboot.authtoken ORDER BY time_received DESC;")
2923 .context("Prepare statement failed.")?;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002924
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002925 let mut rows = stmt.query(NO_PARAMS).context("Failed to query.")?;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002926
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002927 while let Some(row) = rows.next().context("Failed to get next row.")? {
2928 let entry = AuthTokenEntry::new(
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002929 HardwareAuthToken {
2930 challenge: row.get(1)?,
2931 userId: row.get(2)?,
2932 authenticatorId: row.get(3)?,
2933 authenticatorType: HardwareAuthenticatorType(row.get(4)?),
2934 timestamp: Timestamp { milliSeconds: row.get(5)? },
2935 mac: row.get(6)?,
2936 },
2937 row.get(7)?,
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002938 );
2939 if p(&entry) {
2940 return Ok(Some((
2941 entry,
2942 Self::get_last_off_body(tx)
2943 .context("In find_auth_token_entry: Trying to get last off body")?,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002944 )))
2945 .no_gc();
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002946 }
2947 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002948 Ok(None).no_gc()
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002949 })
2950 .context("In find_auth_token_entry.")
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002951 }
2952
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002953 /// Insert last_off_body into the metadata table at the initialization of auth token table
Janis Danisevskis66784c42021-01-27 08:40:25 -08002954 pub fn insert_last_off_body(&mut self, last_off_body: MonotonicRawTime) -> Result<()> {
2955 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2956 tx.execute(
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002957 "INSERT OR REPLACE INTO perboot.metadata (key, value) VALUES (?, ?);",
2958 params!["last_off_body", last_off_body],
2959 )
2960 .context("In insert_last_off_body: failed to insert.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002961 Ok(()).no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08002962 })
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002963 }
2964
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002965 /// Update last_off_body when on_device_off_body is called
Janis Danisevskis66784c42021-01-27 08:40:25 -08002966 pub fn update_last_off_body(&mut self, last_off_body: MonotonicRawTime) -> Result<()> {
2967 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2968 tx.execute(
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002969 "UPDATE perboot.metadata SET value = ? WHERE key = ?;",
2970 params![last_off_body, "last_off_body"],
2971 )
2972 .context("In update_last_off_body: failed to update.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002973 Ok(()).no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08002974 })
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002975 }
2976
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002977 /// Get last_off_body time when finding auth tokens
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002978 fn get_last_off_body(tx: &Transaction) -> Result<MonotonicRawTime> {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002979 tx.query_row(
2980 "SELECT value from perboot.metadata WHERE key = ?;",
2981 params!["last_off_body"],
2982 |row| Ok(row.get(0)?),
2983 )
2984 .context("In get_last_off_body: query_row failed.")
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002985 }
Joel Galenson26f4d012020-07-17 14:57:21 -07002986}
2987
2988#[cfg(test)]
2989mod tests {
2990
2991 use super::*;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002992 use crate::key_parameter::{
2993 Algorithm, BlockMode, Digest, EcCurve, HardwareAuthenticatorType, KeyOrigin, KeyParameter,
2994 KeyParameterValue, KeyPurpose, PaddingMode, SecurityLevel,
2995 };
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002996 use crate::key_perm_set;
2997 use crate::permission::{KeyPerm, KeyPermSet};
Hasini Gunasingheda895552021-01-27 19:34:37 +00002998 use crate::super_key::SuperKeyManager;
Janis Danisevskis2a8330a2021-01-20 15:34:26 -08002999 use keystore2_test_utils::TempDir;
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00003000 use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
3001 HardwareAuthToken::HardwareAuthToken,
3002 HardwareAuthenticatorType::HardwareAuthenticatorType as kmhw_authenticator_type,
Janis Danisevskisc3a496b2021-01-05 10:37:22 -08003003 };
3004 use android_hardware_security_secureclock::aidl::android::hardware::security::secureclock::{
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00003005 Timestamp::Timestamp,
3006 };
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003007 use rusqlite::NO_PARAMS;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00003008 use rusqlite::{Error, TransactionBehavior};
Joel Galenson0891bc12020-07-20 10:37:03 -07003009 use std::cell::RefCell;
Janis Danisevskisaec14592020-11-12 09:41:49 -08003010 use std::sync::atomic::{AtomicU8, Ordering};
3011 use std::sync::Arc;
3012 use std::thread;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00003013 use std::time::{Duration, SystemTime};
Janis Danisevskis66784c42021-01-27 08:40:25 -08003014 #[cfg(disabled)]
3015 use std::time::Instant;
Joel Galenson0891bc12020-07-20 10:37:03 -07003016
Janis Danisevskis4df44f42020-08-26 14:40:03 -07003017 fn new_test_db() -> Result<KeystoreDB> {
3018 let conn = KeystoreDB::make_connection("file::memory:", "file::memory:")?;
3019
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003020 let mut db = KeystoreDB { conn, gc: None };
Janis Danisevskis66784c42021-01-27 08:40:25 -08003021 db.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003022 KeystoreDB::init_tables(tx).context("Failed to initialize tables.").no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08003023 })?;
3024 Ok(db)
Janis Danisevskis4df44f42020-08-26 14:40:03 -07003025 }
3026
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003027 fn new_test_db_with_gc<F>(path: &Path, cb: F) -> Result<KeystoreDB>
3028 where
3029 F: Fn(&Uuid, &[u8]) -> Result<()> + Send + 'static,
3030 {
Paul Crowleye8826e52021-03-31 08:33:53 -07003031 let super_key: Arc<SuperKeyManager> = Default::default();
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00003032
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003033 let gc_db = KeystoreDB::new(path, None).expect("Failed to open test gc db_connection.");
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00003034 let gc = Gc::new_init_with(Default::default(), move || (Box::new(cb), gc_db, super_key));
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003035
3036 KeystoreDB::new(path, Some(gc))
3037 }
3038
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003039 fn rebind_alias(
3040 db: &mut KeystoreDB,
3041 newid: &KeyIdGuard,
3042 alias: &str,
3043 domain: Domain,
3044 namespace: i64,
3045 ) -> Result<bool> {
3046 db.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003047 KeystoreDB::rebind_alias(tx, newid, alias, &domain, &namespace).no_gc()
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003048 })
3049 .context("In rebind_alias.")
3050 }
3051
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003052 #[test]
3053 fn datetime() -> Result<()> {
3054 let conn = Connection::open_in_memory()?;
3055 conn.execute("CREATE TABLE test (ts DATETIME);", NO_PARAMS)?;
3056 let now = SystemTime::now();
3057 let duration = Duration::from_secs(1000);
3058 let then = now.checked_sub(duration).unwrap();
3059 let soon = now.checked_add(duration).unwrap();
3060 conn.execute(
3061 "INSERT INTO test (ts) VALUES (?), (?), (?);",
3062 params![DateTime::try_from(now)?, DateTime::try_from(then)?, DateTime::try_from(soon)?],
3063 )?;
3064 let mut stmt = conn.prepare("SELECT ts FROM test ORDER BY ts ASC;")?;
3065 let mut rows = stmt.query(NO_PARAMS)?;
3066 assert_eq!(DateTime::try_from(then)?, rows.next()?.unwrap().get(0)?);
3067 assert_eq!(DateTime::try_from(now)?, rows.next()?.unwrap().get(0)?);
3068 assert_eq!(DateTime::try_from(soon)?, rows.next()?.unwrap().get(0)?);
3069 assert!(rows.next()?.is_none());
3070 assert!(DateTime::try_from(then)? < DateTime::try_from(now)?);
3071 assert!(DateTime::try_from(then)? < DateTime::try_from(soon)?);
3072 assert!(DateTime::try_from(now)? < DateTime::try_from(soon)?);
3073 Ok(())
3074 }
3075
Joel Galenson0891bc12020-07-20 10:37:03 -07003076 // Ensure that we're using the "injected" random function, not the real one.
3077 #[test]
3078 fn test_mocked_random() {
3079 let rand1 = random();
3080 let rand2 = random();
3081 let rand3 = random();
3082 if rand1 == rand2 {
3083 assert_eq!(rand2 + 1, rand3);
3084 } else {
3085 assert_eq!(rand1 + 1, rand2);
3086 assert_eq!(rand2, rand3);
3087 }
3088 }
Joel Galenson26f4d012020-07-17 14:57:21 -07003089
Joel Galenson26f4d012020-07-17 14:57:21 -07003090 // Test that we have the correct tables.
3091 #[test]
3092 fn test_tables() -> Result<()> {
Janis Danisevskis4df44f42020-08-26 14:40:03 -07003093 let db = new_test_db()?;
Joel Galenson26f4d012020-07-17 14:57:21 -07003094 let tables = db
3095 .conn
Joel Galenson2aab4432020-07-22 15:27:57 -07003096 .prepare("SELECT name from persistent.sqlite_master WHERE type='table' ORDER BY name;")?
Joel Galenson26f4d012020-07-17 14:57:21 -07003097 .query_map(params![], |row| row.get(0))?
3098 .collect::<rusqlite::Result<Vec<String>>>()?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003099 assert_eq!(tables.len(), 6);
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003100 assert_eq!(tables[0], "blobentry");
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003101 assert_eq!(tables[1], "blobmetadata");
3102 assert_eq!(tables[2], "grant");
3103 assert_eq!(tables[3], "keyentry");
3104 assert_eq!(tables[4], "keymetadata");
3105 assert_eq!(tables[5], "keyparameter");
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003106 let tables = db
3107 .conn
3108 .prepare("SELECT name from perboot.sqlite_master WHERE type='table' ORDER BY name;")?
3109 .query_map(params![], |row| row.get(0))?
3110 .collect::<rusqlite::Result<Vec<String>>>()?;
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00003111
3112 assert_eq!(tables.len(), 2);
3113 assert_eq!(tables[0], "authtoken");
3114 assert_eq!(tables[1], "metadata");
Joel Galenson2aab4432020-07-22 15:27:57 -07003115 Ok(())
3116 }
3117
3118 #[test]
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00003119 fn test_auth_token_table_invariant() -> Result<()> {
3120 let mut db = new_test_db()?;
3121 let auth_token1 = HardwareAuthToken {
3122 challenge: i64::MAX,
3123 userId: 200,
3124 authenticatorId: 200,
3125 authenticatorType: kmhw_authenticator_type(kmhw_authenticator_type::PASSWORD.0),
3126 timestamp: Timestamp { milliSeconds: 500 },
3127 mac: String::from("mac").into_bytes(),
3128 };
3129 db.insert_auth_token(&auth_token1)?;
3130 let auth_tokens_returned = get_auth_tokens(&mut db)?;
3131 assert_eq!(auth_tokens_returned.len(), 1);
3132
3133 // insert another auth token with the same values for the columns in the UNIQUE constraint
3134 // of the auth token table and different value for timestamp
3135 let auth_token2 = HardwareAuthToken {
3136 challenge: i64::MAX,
3137 userId: 200,
3138 authenticatorId: 200,
3139 authenticatorType: kmhw_authenticator_type(kmhw_authenticator_type::PASSWORD.0),
3140 timestamp: Timestamp { milliSeconds: 600 },
3141 mac: String::from("mac").into_bytes(),
3142 };
3143
3144 db.insert_auth_token(&auth_token2)?;
3145 let mut auth_tokens_returned = get_auth_tokens(&mut db)?;
3146 assert_eq!(auth_tokens_returned.len(), 1);
3147
3148 if let Some(auth_token) = auth_tokens_returned.pop() {
3149 assert_eq!(auth_token.auth_token.timestamp.milliSeconds, 600);
3150 }
3151
3152 // insert another auth token with the different values for the columns in the UNIQUE
3153 // constraint of the auth token table
3154 let auth_token3 = HardwareAuthToken {
3155 challenge: i64::MAX,
3156 userId: 201,
3157 authenticatorId: 200,
3158 authenticatorType: kmhw_authenticator_type(kmhw_authenticator_type::PASSWORD.0),
3159 timestamp: Timestamp { milliSeconds: 600 },
3160 mac: String::from("mac").into_bytes(),
3161 };
3162
3163 db.insert_auth_token(&auth_token3)?;
3164 let auth_tokens_returned = get_auth_tokens(&mut db)?;
3165 assert_eq!(auth_tokens_returned.len(), 2);
3166
3167 Ok(())
3168 }
3169
3170 // utility function for test_auth_token_table_invariant()
3171 fn get_auth_tokens(db: &mut KeystoreDB) -> Result<Vec<AuthTokenEntry>> {
3172 let mut stmt = db.conn.prepare("SELECT * from perboot.authtoken;")?;
3173
3174 let auth_token_entries: Vec<AuthTokenEntry> = stmt
3175 .query_map(NO_PARAMS, |row| {
3176 Ok(AuthTokenEntry::new(
3177 HardwareAuthToken {
3178 challenge: row.get(1)?,
3179 userId: row.get(2)?,
3180 authenticatorId: row.get(3)?,
3181 authenticatorType: HardwareAuthenticatorType(row.get(4)?),
3182 timestamp: Timestamp { milliSeconds: row.get(5)? },
3183 mac: row.get(6)?,
3184 },
3185 row.get(7)?,
3186 ))
3187 })?
3188 .collect::<Result<Vec<AuthTokenEntry>, Error>>()?;
3189 Ok(auth_token_entries)
3190 }
3191
3192 #[test]
Joel Galenson2aab4432020-07-22 15:27:57 -07003193 fn test_persistence_for_files() -> Result<()> {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08003194 let temp_dir = TempDir::new("persistent_db_test")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003195 let mut db = KeystoreDB::new(temp_dir.path(), None)?;
Joel Galenson2aab4432020-07-22 15:27:57 -07003196
Janis Danisevskis66784c42021-01-27 08:40:25 -08003197 db.create_key_entry(&Domain::APP, &100, &KEYSTORE_UUID)?;
Joel Galenson2aab4432020-07-22 15:27:57 -07003198 let entries = get_keyentry(&db)?;
3199 assert_eq!(entries.len(), 1);
Janis Danisevskisbf15d732020-12-08 10:35:26 -08003200
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003201 let db = KeystoreDB::new(temp_dir.path(), None)?;
Joel Galenson2aab4432020-07-22 15:27:57 -07003202
3203 let entries_new = get_keyentry(&db)?;
3204 assert_eq!(entries, entries_new);
3205 Ok(())
3206 }
3207
3208 #[test]
Joel Galenson0891bc12020-07-20 10:37:03 -07003209 fn test_create_key_entry() -> Result<()> {
Max Bires8e93d2b2021-01-14 13:17:59 -08003210 fn extractor(ke: &KeyEntryRow) -> (Domain, i64, Option<&str>, Uuid) {
3211 (ke.domain.unwrap(), ke.namespace.unwrap(), ke.alias.as_deref(), ke.km_uuid.unwrap())
Joel Galenson0891bc12020-07-20 10:37:03 -07003212 }
3213
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003214 let mut db = new_test_db()?;
Joel Galenson0891bc12020-07-20 10:37:03 -07003215
Janis Danisevskis66784c42021-01-27 08:40:25 -08003216 db.create_key_entry(&Domain::APP, &100, &KEYSTORE_UUID)?;
3217 db.create_key_entry(&Domain::SELINUX, &101, &KEYSTORE_UUID)?;
Joel Galenson0891bc12020-07-20 10:37:03 -07003218
3219 let entries = get_keyentry(&db)?;
3220 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08003221 assert_eq!(extractor(&entries[0]), (Domain::APP, 100, None, KEYSTORE_UUID));
3222 assert_eq!(extractor(&entries[1]), (Domain::SELINUX, 101, None, KEYSTORE_UUID));
Joel Galenson0891bc12020-07-20 10:37:03 -07003223
3224 // Test that we must pass in a valid Domain.
3225 check_result_is_error_containing_string(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003226 db.create_key_entry(&Domain::GRANT, &102, &KEYSTORE_UUID),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003227 "Domain Domain(1) must be either App or SELinux.",
Joel Galenson0891bc12020-07-20 10:37:03 -07003228 );
3229 check_result_is_error_containing_string(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003230 db.create_key_entry(&Domain::BLOB, &103, &KEYSTORE_UUID),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003231 "Domain Domain(3) must be either App or SELinux.",
Joel Galenson0891bc12020-07-20 10:37:03 -07003232 );
3233 check_result_is_error_containing_string(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003234 db.create_key_entry(&Domain::KEY_ID, &104, &KEYSTORE_UUID),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003235 "Domain Domain(4) must be either App or SELinux.",
Joel Galenson0891bc12020-07-20 10:37:03 -07003236 );
3237
3238 Ok(())
3239 }
3240
Joel Galenson33c04ad2020-08-03 11:04:38 -07003241 #[test]
Max Bires2b2e6562020-09-22 11:22:36 -07003242 fn test_add_unsigned_key() -> Result<()> {
3243 let mut db = new_test_db()?;
3244 let public_key: Vec<u8> = vec![0x01, 0x02, 0x03];
3245 let private_key: Vec<u8> = vec![0x04, 0x05, 0x06];
3246 let raw_public_key: Vec<u8> = vec![0x07, 0x08, 0x09];
3247 db.create_attestation_key_entry(
3248 &public_key,
3249 &raw_public_key,
3250 &private_key,
3251 &KEYSTORE_UUID,
3252 )?;
3253 let keys = db.fetch_unsigned_attestation_keys(5, &KEYSTORE_UUID)?;
3254 assert_eq!(keys.len(), 1);
3255 assert_eq!(keys[0], public_key);
3256 Ok(())
3257 }
3258
3259 #[test]
3260 fn test_store_signed_attestation_certificate_chain() -> Result<()> {
3261 let mut db = new_test_db()?;
3262 let expiration_date: i64 = 20;
3263 let namespace: i64 = 30;
3264 let base_byte: u8 = 1;
3265 let loaded_values =
3266 load_attestation_key_pool(&mut db, expiration_date, namespace, base_byte)?;
3267 let chain =
3268 db.retrieve_attestation_key_and_cert_chain(Domain::APP, namespace, &KEYSTORE_UUID)?;
3269 assert_eq!(true, chain.is_some());
3270 let cert_chain = chain.unwrap();
Max Biresb2e1d032021-02-08 21:35:05 -08003271 assert_eq!(cert_chain.private_key.to_vec(), loaded_values.priv_key);
Max Bires97f96812021-02-23 23:44:57 -08003272 assert_eq!(cert_chain.batch_cert, loaded_values.batch_cert);
3273 assert_eq!(cert_chain.cert_chain, loaded_values.cert_chain);
Max Bires2b2e6562020-09-22 11:22:36 -07003274 Ok(())
3275 }
3276
3277 #[test]
3278 fn test_get_attestation_pool_status() -> Result<()> {
3279 let mut db = new_test_db()?;
3280 let namespace: i64 = 30;
3281 load_attestation_key_pool(
3282 &mut db, 10, /* expiration */
3283 namespace, 0x01, /* base_byte */
3284 )?;
3285 load_attestation_key_pool(&mut db, 20 /* expiration */, namespace + 1, 0x02)?;
3286 load_attestation_key_pool(&mut db, 40 /* expiration */, namespace + 2, 0x03)?;
3287 let mut status = db.get_attestation_pool_status(9 /* expiration */, &KEYSTORE_UUID)?;
3288 assert_eq!(status.expiring, 0);
3289 assert_eq!(status.attested, 3);
3290 assert_eq!(status.unassigned, 0);
3291 assert_eq!(status.total, 3);
3292 assert_eq!(
3293 db.get_attestation_pool_status(15 /* expiration */, &KEYSTORE_UUID)?.expiring,
3294 1
3295 );
3296 assert_eq!(
3297 db.get_attestation_pool_status(25 /* expiration */, &KEYSTORE_UUID)?.expiring,
3298 2
3299 );
3300 assert_eq!(
3301 db.get_attestation_pool_status(60 /* expiration */, &KEYSTORE_UUID)?.expiring,
3302 3
3303 );
3304 let public_key: Vec<u8> = vec![0x01, 0x02, 0x03];
3305 let private_key: Vec<u8> = vec![0x04, 0x05, 0x06];
3306 let raw_public_key: Vec<u8> = vec![0x07, 0x08, 0x09];
3307 let cert_chain: Vec<u8> = vec![0x0a, 0x0b, 0x0c];
Max Biresb2e1d032021-02-08 21:35:05 -08003308 let batch_cert: Vec<u8> = vec![0x0d, 0x0e, 0x0f];
Max Bires2b2e6562020-09-22 11:22:36 -07003309 db.create_attestation_key_entry(
3310 &public_key,
3311 &raw_public_key,
3312 &private_key,
3313 &KEYSTORE_UUID,
3314 )?;
3315 status = db.get_attestation_pool_status(0 /* expiration */, &KEYSTORE_UUID)?;
3316 assert_eq!(status.attested, 3);
3317 assert_eq!(status.unassigned, 0);
3318 assert_eq!(status.total, 4);
3319 db.store_signed_attestation_certificate_chain(
3320 &raw_public_key,
Max Biresb2e1d032021-02-08 21:35:05 -08003321 &batch_cert,
Max Bires2b2e6562020-09-22 11:22:36 -07003322 &cert_chain,
3323 20,
3324 &KEYSTORE_UUID,
3325 )?;
3326 status = db.get_attestation_pool_status(0 /* expiration */, &KEYSTORE_UUID)?;
3327 assert_eq!(status.attested, 4);
3328 assert_eq!(status.unassigned, 1);
3329 assert_eq!(status.total, 4);
3330 Ok(())
3331 }
3332
3333 #[test]
3334 fn test_remove_expired_certs() -> Result<()> {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003335 let temp_dir =
3336 TempDir::new("test_remove_expired_certs_").expect("Failed to create temp dir.");
3337 let mut db = new_test_db_with_gc(temp_dir.path(), |_, _| Ok(()))?;
Max Bires2b2e6562020-09-22 11:22:36 -07003338 let expiration_date: i64 =
3339 SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_millis() as i64 + 10000;
3340 let namespace: i64 = 30;
3341 let namespace_del1: i64 = 45;
3342 let namespace_del2: i64 = 60;
3343 let entry_values = load_attestation_key_pool(
3344 &mut db,
3345 expiration_date,
3346 namespace,
3347 0x01, /* base_byte */
3348 )?;
3349 load_attestation_key_pool(&mut db, 45, namespace_del1, 0x02)?;
3350 load_attestation_key_pool(&mut db, 60, namespace_del2, 0x03)?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003351
3352 let blob_entry_row_count: u32 = db
3353 .conn
3354 .query_row("SELECT COUNT(id) FROM persistent.blobentry;", NO_PARAMS, |row| row.get(0))
3355 .expect("Failed to get blob entry row count.");
Max Biresb2e1d032021-02-08 21:35:05 -08003356 // We expect 9 rows here because there are three blobs per attestation key, i.e.,
3357 // one key, one certificate chain, and one certificate.
3358 assert_eq!(blob_entry_row_count, 9);
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003359
Max Bires2b2e6562020-09-22 11:22:36 -07003360 assert_eq!(db.delete_expired_attestation_keys()?, 2);
3361
3362 let mut cert_chain =
3363 db.retrieve_attestation_key_and_cert_chain(Domain::APP, namespace, &KEYSTORE_UUID)?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003364 assert!(cert_chain.is_some());
Max Bires2b2e6562020-09-22 11:22:36 -07003365 let value = cert_chain.unwrap();
Max Bires97f96812021-02-23 23:44:57 -08003366 assert_eq!(entry_values.batch_cert, value.batch_cert);
3367 assert_eq!(entry_values.cert_chain, value.cert_chain);
Max Biresb2e1d032021-02-08 21:35:05 -08003368 assert_eq!(entry_values.priv_key, value.private_key.to_vec());
Max Bires2b2e6562020-09-22 11:22:36 -07003369
3370 cert_chain = db.retrieve_attestation_key_and_cert_chain(
3371 Domain::APP,
3372 namespace_del1,
3373 &KEYSTORE_UUID,
3374 )?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003375 assert!(!cert_chain.is_some());
Max Bires2b2e6562020-09-22 11:22:36 -07003376 cert_chain = db.retrieve_attestation_key_and_cert_chain(
3377 Domain::APP,
3378 namespace_del2,
3379 &KEYSTORE_UUID,
3380 )?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003381 assert!(!cert_chain.is_some());
Max Bires2b2e6562020-09-22 11:22:36 -07003382
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003383 // Give the garbage collector half a second to catch up.
3384 std::thread::sleep(Duration::from_millis(500));
Max Bires2b2e6562020-09-22 11:22:36 -07003385
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003386 let blob_entry_row_count: u32 = db
3387 .conn
3388 .query_row("SELECT COUNT(id) FROM persistent.blobentry;", NO_PARAMS, |row| row.get(0))
3389 .expect("Failed to get blob entry row count.");
Max Biresb2e1d032021-02-08 21:35:05 -08003390 // There shound be 3 blob entries left, because we deleted two of the attestation
3391 // key entries with three blobs each.
3392 assert_eq!(blob_entry_row_count, 3);
Max Bires2b2e6562020-09-22 11:22:36 -07003393
Max Bires2b2e6562020-09-22 11:22:36 -07003394 Ok(())
3395 }
3396
3397 #[test]
Max Bires60d7ed12021-03-05 15:59:22 -08003398 fn test_delete_all_attestation_keys() -> Result<()> {
3399 let mut db = new_test_db()?;
3400 load_attestation_key_pool(&mut db, 45 /* expiration */, 1 /* namespace */, 0x02)?;
3401 load_attestation_key_pool(&mut db, 80 /* expiration */, 2 /* namespace */, 0x03)?;
3402 db.create_key_entry(&Domain::APP, &42, &KEYSTORE_UUID)?;
3403 let result = db.delete_all_attestation_keys()?;
3404
3405 // Give the garbage collector half a second to catch up.
3406 std::thread::sleep(Duration::from_millis(500));
3407
3408 // Attestation keys should be deleted, and the regular key should remain.
3409 assert_eq!(result, 2);
3410
3411 Ok(())
3412 }
3413
3414 #[test]
Joel Galenson33c04ad2020-08-03 11:04:38 -07003415 fn test_rebind_alias() -> Result<()> {
Max Bires8e93d2b2021-01-14 13:17:59 -08003416 fn extractor(
3417 ke: &KeyEntryRow,
3418 ) -> (Option<Domain>, Option<i64>, Option<&str>, Option<Uuid>) {
3419 (ke.domain, ke.namespace, ke.alias.as_deref(), ke.km_uuid)
Joel Galenson33c04ad2020-08-03 11:04:38 -07003420 }
3421
Janis Danisevskis4df44f42020-08-26 14:40:03 -07003422 let mut db = new_test_db()?;
Janis Danisevskis66784c42021-01-27 08:40:25 -08003423 db.create_key_entry(&Domain::APP, &42, &KEYSTORE_UUID)?;
3424 db.create_key_entry(&Domain::APP, &42, &KEYSTORE_UUID)?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07003425 let entries = get_keyentry(&db)?;
3426 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08003427 assert_eq!(
3428 extractor(&entries[0]),
3429 (Some(Domain::APP), Some(42), None, Some(KEYSTORE_UUID))
3430 );
3431 assert_eq!(
3432 extractor(&entries[1]),
3433 (Some(Domain::APP), Some(42), None, Some(KEYSTORE_UUID))
3434 );
Joel Galenson33c04ad2020-08-03 11:04:38 -07003435
3436 // Test that the first call to rebind_alias sets the alias.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003437 rebind_alias(&mut db, &KEY_ID_LOCK.get(entries[0].id), "foo", Domain::APP, 42)?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07003438 let entries = get_keyentry(&db)?;
3439 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08003440 assert_eq!(
3441 extractor(&entries[0]),
3442 (Some(Domain::APP), Some(42), Some("foo"), Some(KEYSTORE_UUID))
3443 );
3444 assert_eq!(
3445 extractor(&entries[1]),
3446 (Some(Domain::APP), Some(42), None, Some(KEYSTORE_UUID))
3447 );
Joel Galenson33c04ad2020-08-03 11:04:38 -07003448
3449 // Test that the second call to rebind_alias also empties the old one.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003450 rebind_alias(&mut db, &KEY_ID_LOCK.get(entries[1].id), "foo", Domain::APP, 42)?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07003451 let entries = get_keyentry(&db)?;
3452 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08003453 assert_eq!(extractor(&entries[0]), (None, None, None, Some(KEYSTORE_UUID)));
3454 assert_eq!(
3455 extractor(&entries[1]),
3456 (Some(Domain::APP), Some(42), Some("foo"), Some(KEYSTORE_UUID))
3457 );
Joel Galenson33c04ad2020-08-03 11:04:38 -07003458
3459 // Test that we must pass in a valid Domain.
3460 check_result_is_error_containing_string(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003461 rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::GRANT, 42),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003462 "Domain Domain(1) must be either App or SELinux.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07003463 );
3464 check_result_is_error_containing_string(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003465 rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::BLOB, 42),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003466 "Domain Domain(3) must be either App or SELinux.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07003467 );
3468 check_result_is_error_containing_string(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003469 rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::KEY_ID, 42),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003470 "Domain Domain(4) must be either App or SELinux.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07003471 );
3472
3473 // Test that we correctly handle setting an alias for something that does not exist.
3474 check_result_is_error_containing_string(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003475 rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::SELINUX, 42),
Joel Galenson33c04ad2020-08-03 11:04:38 -07003476 "Expected to update a single entry but instead updated 0",
3477 );
3478 // Test that we correctly abort the transaction in this case.
3479 let entries = get_keyentry(&db)?;
3480 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08003481 assert_eq!(extractor(&entries[0]), (None, None, None, Some(KEYSTORE_UUID)));
3482 assert_eq!(
3483 extractor(&entries[1]),
3484 (Some(Domain::APP), Some(42), Some("foo"), Some(KEYSTORE_UUID))
3485 );
Joel Galenson33c04ad2020-08-03 11:04:38 -07003486
3487 Ok(())
3488 }
3489
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003490 #[test]
3491 fn test_grant_ungrant() -> Result<()> {
3492 const CALLER_UID: u32 = 15;
3493 const GRANTEE_UID: u32 = 12;
3494 const SELINUX_NAMESPACE: i64 = 7;
3495
3496 let mut db = new_test_db()?;
3497 db.conn.execute(
Max Bires8e93d2b2021-01-14 13:17:59 -08003498 "INSERT INTO persistent.keyentry (id, key_type, domain, namespace, alias, state, km_uuid)
3499 VALUES (1, 0, 0, 15, 'key', 1, ?), (2, 0, 2, 7, 'yek', 1, ?);",
3500 params![KEYSTORE_UUID, KEYSTORE_UUID],
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003501 )?;
3502 let app_key = KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003503 domain: super::Domain::APP,
3504 nspace: 0,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003505 alias: Some("key".to_string()),
3506 blob: None,
3507 };
3508 const PVEC1: KeyPermSet = key_perm_set![KeyPerm::use_(), KeyPerm::get_info()];
3509 const PVEC2: KeyPermSet = key_perm_set![KeyPerm::use_()];
3510
3511 // Reset totally predictable random number generator in case we
3512 // are not the first test running on this thread.
3513 reset_random();
3514 let next_random = 0i64;
3515
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003516 let app_granted_key = db
Janis Danisevskis66784c42021-01-27 08:40:25 -08003517 .grant(&app_key, CALLER_UID, GRANTEE_UID, PVEC1, |k, a| {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003518 assert_eq!(*a, PVEC1);
3519 assert_eq!(
3520 *k,
3521 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003522 domain: super::Domain::APP,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003523 // namespace must be set to the caller_uid.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003524 nspace: CALLER_UID as i64,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003525 alias: Some("key".to_string()),
3526 blob: None,
3527 }
3528 );
3529 Ok(())
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003530 })
3531 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003532
3533 assert_eq!(
3534 app_granted_key,
3535 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003536 domain: super::Domain::GRANT,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003537 // The grantid is next_random due to the mock random number generator.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003538 nspace: next_random,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003539 alias: None,
3540 blob: None,
3541 }
3542 );
3543
3544 let selinux_key = KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003545 domain: super::Domain::SELINUX,
3546 nspace: SELINUX_NAMESPACE,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003547 alias: Some("yek".to_string()),
3548 blob: None,
3549 };
3550
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003551 let selinux_granted_key = db
Janis Danisevskis66784c42021-01-27 08:40:25 -08003552 .grant(&selinux_key, CALLER_UID, 12, PVEC1, |k, a| {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003553 assert_eq!(*a, PVEC1);
3554 assert_eq!(
3555 *k,
3556 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003557 domain: super::Domain::SELINUX,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003558 // namespace must be the supplied SELinux
3559 // namespace.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003560 nspace: SELINUX_NAMESPACE,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003561 alias: Some("yek".to_string()),
3562 blob: None,
3563 }
3564 );
3565 Ok(())
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003566 })
3567 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003568
3569 assert_eq!(
3570 selinux_granted_key,
3571 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003572 domain: super::Domain::GRANT,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003573 // The grantid is next_random + 1 due to the mock random number generator.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003574 nspace: next_random + 1,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003575 alias: None,
3576 blob: None,
3577 }
3578 );
3579
3580 // This should update the existing grant with PVEC2.
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003581 let selinux_granted_key = db
Janis Danisevskis66784c42021-01-27 08:40:25 -08003582 .grant(&selinux_key, CALLER_UID, 12, PVEC2, |k, a| {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003583 assert_eq!(*a, PVEC2);
3584 assert_eq!(
3585 *k,
3586 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003587 domain: super::Domain::SELINUX,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003588 // namespace must be the supplied SELinux
3589 // namespace.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003590 nspace: SELINUX_NAMESPACE,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003591 alias: Some("yek".to_string()),
3592 blob: None,
3593 }
3594 );
3595 Ok(())
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003596 })
3597 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003598
3599 assert_eq!(
3600 selinux_granted_key,
3601 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003602 domain: super::Domain::GRANT,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003603 // Same grant id as before. The entry was only updated.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003604 nspace: next_random + 1,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003605 alias: None,
3606 blob: None,
3607 }
3608 );
3609
3610 {
3611 // Limiting scope of stmt, because it borrows db.
3612 let mut stmt = db
3613 .conn
Janis Danisevskisbf15d732020-12-08 10:35:26 -08003614 .prepare("SELECT id, grantee, keyentryid, access_vector FROM persistent.grant;")?;
Janis Danisevskisee10b5f2020-09-22 16:42:35 -07003615 let mut rows =
3616 stmt.query_map::<(i64, u32, i64, KeyPermSet), _, _>(NO_PARAMS, |row| {
3617 Ok((
3618 row.get(0)?,
3619 row.get(1)?,
3620 row.get(2)?,
3621 KeyPermSet::from(row.get::<_, i32>(3)?),
3622 ))
3623 })?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003624
3625 let r = rows.next().unwrap().unwrap();
Janis Danisevskisee10b5f2020-09-22 16:42:35 -07003626 assert_eq!(r, (next_random, GRANTEE_UID, 1, PVEC1));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003627 let r = rows.next().unwrap().unwrap();
Janis Danisevskisee10b5f2020-09-22 16:42:35 -07003628 assert_eq!(r, (next_random + 1, GRANTEE_UID, 2, PVEC2));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003629 assert!(rows.next().is_none());
3630 }
3631
3632 debug_dump_keyentry_table(&mut db)?;
3633 println!("app_key {:?}", app_key);
3634 println!("selinux_key {:?}", selinux_key);
3635
Janis Danisevskis66784c42021-01-27 08:40:25 -08003636 db.ungrant(&app_key, CALLER_UID, GRANTEE_UID, |_| Ok(()))?;
3637 db.ungrant(&selinux_key, CALLER_UID, GRANTEE_UID, |_| Ok(()))?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003638
3639 Ok(())
3640 }
3641
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003642 static TEST_KEY_BLOB: &[u8] = b"my test blob";
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003643 static TEST_CERT_BLOB: &[u8] = b"my test cert";
3644 static TEST_CERT_CHAIN_BLOB: &[u8] = b"my test cert_chain";
3645
3646 #[test]
Janis Danisevskis377d1002021-01-27 19:07:48 -08003647 fn test_set_blob() -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003648 let key_id = KEY_ID_LOCK.get(3000);
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003649 let mut db = new_test_db()?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003650 let mut blob_metadata = BlobMetaData::new();
3651 blob_metadata.add(BlobMetaEntry::KmUuid(KEYSTORE_UUID));
3652 db.set_blob(
3653 &key_id,
3654 SubComponentType::KEY_BLOB,
3655 Some(TEST_KEY_BLOB),
3656 Some(&blob_metadata),
3657 )?;
3658 db.set_blob(&key_id, SubComponentType::CERT, Some(TEST_CERT_BLOB), None)?;
3659 db.set_blob(&key_id, SubComponentType::CERT_CHAIN, Some(TEST_CERT_CHAIN_BLOB), None)?;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003660 drop(key_id);
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003661
3662 let mut stmt = db.conn.prepare(
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003663 "SELECT subcomponent_type, keyentryid, blob, id FROM persistent.blobentry
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003664 ORDER BY subcomponent_type ASC;",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003665 )?;
3666 let mut rows = stmt
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003667 .query_map::<((SubComponentType, i64, Vec<u8>), i64), _, _>(NO_PARAMS, |row| {
3668 Ok(((row.get(0)?, row.get(1)?, row.get(2)?), row.get(3)?))
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003669 })?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003670 let (r, id) = rows.next().unwrap().unwrap();
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003671 assert_eq!(r, (SubComponentType::KEY_BLOB, 3000, TEST_KEY_BLOB.to_vec()));
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003672 let (r, _) = rows.next().unwrap().unwrap();
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003673 assert_eq!(r, (SubComponentType::CERT, 3000, TEST_CERT_BLOB.to_vec()));
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003674 let (r, _) = rows.next().unwrap().unwrap();
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003675 assert_eq!(r, (SubComponentType::CERT_CHAIN, 3000, TEST_CERT_CHAIN_BLOB.to_vec()));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003676
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003677 drop(rows);
3678 drop(stmt);
3679
3680 assert_eq!(
3681 db.with_transaction(TransactionBehavior::Immediate, |tx| {
3682 BlobMetaData::load_from_db(id, tx).no_gc()
3683 })
3684 .expect("Should find blob metadata."),
3685 blob_metadata
3686 );
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003687 Ok(())
3688 }
3689
3690 static TEST_ALIAS: &str = "my super duper key";
3691
3692 #[test]
3693 fn test_insert_and_load_full_keyentry_domain_app() -> Result<()> {
3694 let mut db = new_test_db()?;
Qi Wub9433b52020-12-01 14:52:46 +08003695 let key_id = make_test_key_entry(&mut db, Domain::APP, 1, TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08003696 .context("test_insert_and_load_full_keyentry_domain_app")?
3697 .0;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003698 let (_key_guard, key_entry) = db
3699 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003700 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003701 domain: Domain::APP,
3702 nspace: 0,
3703 alias: Some(TEST_ALIAS.to_string()),
3704 blob: None,
3705 },
3706 KeyType::Client,
3707 KeyEntryLoadBits::BOTH,
3708 1,
3709 |_k, _av| Ok(()),
3710 )
3711 .unwrap();
Qi Wub9433b52020-12-01 14:52:46 +08003712 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003713
3714 db.unbind_key(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003715 &KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003716 domain: Domain::APP,
3717 nspace: 0,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003718 alias: Some(TEST_ALIAS.to_string()),
3719 blob: None,
3720 },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003721 KeyType::Client,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003722 1,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003723 |_, _| Ok(()),
3724 )
3725 .unwrap();
3726
3727 assert_eq!(
3728 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
3729 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003730 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003731 domain: Domain::APP,
3732 nspace: 0,
3733 alias: Some(TEST_ALIAS.to_string()),
3734 blob: None,
3735 },
3736 KeyType::Client,
3737 KeyEntryLoadBits::NONE,
3738 1,
3739 |_k, _av| Ok(()),
3740 )
3741 .unwrap_err()
3742 .root_cause()
3743 .downcast_ref::<KsError>()
3744 );
3745
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003746 Ok(())
3747 }
3748
3749 #[test]
Janis Danisevskis377d1002021-01-27 19:07:48 -08003750 fn test_insert_and_load_certificate_entry_domain_app() -> Result<()> {
3751 let mut db = new_test_db()?;
3752
3753 db.store_new_certificate(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003754 &KeyDescriptor {
Janis Danisevskis377d1002021-01-27 19:07:48 -08003755 domain: Domain::APP,
3756 nspace: 1,
3757 alias: Some(TEST_ALIAS.to_string()),
3758 blob: None,
3759 },
3760 TEST_CERT_BLOB,
Max Bires8e93d2b2021-01-14 13:17:59 -08003761 &KEYSTORE_UUID,
Janis Danisevskis377d1002021-01-27 19:07:48 -08003762 )
3763 .expect("Trying to insert cert.");
3764
3765 let (_key_guard, mut key_entry) = db
3766 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003767 &KeyDescriptor {
Janis Danisevskis377d1002021-01-27 19:07:48 -08003768 domain: Domain::APP,
3769 nspace: 1,
3770 alias: Some(TEST_ALIAS.to_string()),
3771 blob: None,
3772 },
3773 KeyType::Client,
3774 KeyEntryLoadBits::PUBLIC,
3775 1,
3776 |_k, _av| Ok(()),
3777 )
3778 .expect("Trying to read certificate entry.");
3779
3780 assert!(key_entry.pure_cert());
3781 assert!(key_entry.cert().is_none());
3782 assert_eq!(key_entry.take_cert_chain(), Some(TEST_CERT_BLOB.to_vec()));
3783
3784 db.unbind_key(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003785 &KeyDescriptor {
Janis Danisevskis377d1002021-01-27 19:07:48 -08003786 domain: Domain::APP,
3787 nspace: 1,
3788 alias: Some(TEST_ALIAS.to_string()),
3789 blob: None,
3790 },
3791 KeyType::Client,
3792 1,
3793 |_, _| Ok(()),
3794 )
3795 .unwrap();
3796
3797 assert_eq!(
3798 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
3799 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003800 &KeyDescriptor {
Janis Danisevskis377d1002021-01-27 19:07:48 -08003801 domain: Domain::APP,
3802 nspace: 1,
3803 alias: Some(TEST_ALIAS.to_string()),
3804 blob: None,
3805 },
3806 KeyType::Client,
3807 KeyEntryLoadBits::NONE,
3808 1,
3809 |_k, _av| Ok(()),
3810 )
3811 .unwrap_err()
3812 .root_cause()
3813 .downcast_ref::<KsError>()
3814 );
3815
3816 Ok(())
3817 }
3818
3819 #[test]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003820 fn test_insert_and_load_full_keyentry_domain_selinux() -> Result<()> {
3821 let mut db = new_test_db()?;
Qi Wub9433b52020-12-01 14:52:46 +08003822 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08003823 .context("test_insert_and_load_full_keyentry_domain_selinux")?
3824 .0;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003825 let (_key_guard, key_entry) = db
3826 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003827 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003828 domain: Domain::SELINUX,
3829 nspace: 1,
3830 alias: Some(TEST_ALIAS.to_string()),
3831 blob: None,
3832 },
3833 KeyType::Client,
3834 KeyEntryLoadBits::BOTH,
3835 1,
3836 |_k, _av| Ok(()),
3837 )
3838 .unwrap();
Qi Wub9433b52020-12-01 14:52:46 +08003839 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003840
3841 db.unbind_key(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003842 &KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003843 domain: Domain::SELINUX,
3844 nspace: 1,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003845 alias: Some(TEST_ALIAS.to_string()),
3846 blob: None,
3847 },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003848 KeyType::Client,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003849 1,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003850 |_, _| Ok(()),
3851 )
3852 .unwrap();
3853
3854 assert_eq!(
3855 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
3856 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003857 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003858 domain: Domain::SELINUX,
3859 nspace: 1,
3860 alias: Some(TEST_ALIAS.to_string()),
3861 blob: None,
3862 },
3863 KeyType::Client,
3864 KeyEntryLoadBits::NONE,
3865 1,
3866 |_k, _av| Ok(()),
3867 )
3868 .unwrap_err()
3869 .root_cause()
3870 .downcast_ref::<KsError>()
3871 );
3872
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003873 Ok(())
3874 }
3875
3876 #[test]
3877 fn test_insert_and_load_full_keyentry_domain_key_id() -> Result<()> {
3878 let mut db = new_test_db()?;
Qi Wub9433b52020-12-01 14:52:46 +08003879 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08003880 .context("test_insert_and_load_full_keyentry_domain_key_id")?
3881 .0;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003882 let (_, key_entry) = db
3883 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003884 &KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003885 KeyType::Client,
3886 KeyEntryLoadBits::BOTH,
3887 1,
3888 |_k, _av| Ok(()),
3889 )
3890 .unwrap();
3891
Qi Wub9433b52020-12-01 14:52:46 +08003892 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003893
3894 db.unbind_key(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003895 &KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003896 KeyType::Client,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003897 1,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003898 |_, _| Ok(()),
3899 )
3900 .unwrap();
3901
3902 assert_eq!(
3903 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
3904 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003905 &KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003906 KeyType::Client,
3907 KeyEntryLoadBits::NONE,
3908 1,
3909 |_k, _av| Ok(()),
3910 )
3911 .unwrap_err()
3912 .root_cause()
3913 .downcast_ref::<KsError>()
3914 );
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003915
3916 Ok(())
3917 }
3918
3919 #[test]
Qi Wub9433b52020-12-01 14:52:46 +08003920 fn test_check_and_update_key_usage_count_with_limited_use_key() -> Result<()> {
3921 let mut db = new_test_db()?;
3922 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, Some(123))
3923 .context("test_check_and_update_key_usage_count_with_limited_use_key")?
3924 .0;
3925 // Update the usage count of the limited use key.
3926 db.check_and_update_key_usage_count(key_id)?;
3927
3928 let (_key_guard, key_entry) = db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003929 &KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
Qi Wub9433b52020-12-01 14:52:46 +08003930 KeyType::Client,
3931 KeyEntryLoadBits::BOTH,
3932 1,
3933 |_k, _av| Ok(()),
3934 )?;
3935
3936 // The usage count is decremented now.
3937 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, Some(122)));
3938
3939 Ok(())
3940 }
3941
3942 #[test]
3943 fn test_check_and_update_key_usage_count_with_exhausted_limited_use_key() -> Result<()> {
3944 let mut db = new_test_db()?;
3945 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, Some(1))
3946 .context("test_check_and_update_key_usage_count_with_exhausted_limited_use_key")?
3947 .0;
3948 // Update the usage count of the limited use key.
3949 db.check_and_update_key_usage_count(key_id).expect(concat!(
3950 "In test_check_and_update_key_usage_count_with_exhausted_limited_use_key: ",
3951 "This should succeed."
3952 ));
3953
3954 // Try to update the exhausted limited use key.
3955 let e = db.check_and_update_key_usage_count(key_id).expect_err(concat!(
3956 "In test_check_and_update_key_usage_count_with_exhausted_limited_use_key: ",
3957 "This should fail."
3958 ));
3959 assert_eq!(
3960 &KsError::Km(ErrorCode::INVALID_KEY_BLOB),
3961 e.root_cause().downcast_ref::<KsError>().unwrap()
3962 );
3963
3964 Ok(())
3965 }
3966
3967 #[test]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003968 fn test_insert_and_load_full_keyentry_from_grant() -> Result<()> {
3969 let mut db = new_test_db()?;
Qi Wub9433b52020-12-01 14:52:46 +08003970 let key_id = make_test_key_entry(&mut db, Domain::APP, 1, TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08003971 .context("test_insert_and_load_full_keyentry_from_grant")?
3972 .0;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003973
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003974 let granted_key = db
3975 .grant(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003976 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003977 domain: Domain::APP,
3978 nspace: 0,
3979 alias: Some(TEST_ALIAS.to_string()),
3980 blob: None,
3981 },
3982 1,
3983 2,
3984 key_perm_set![KeyPerm::use_()],
3985 |_k, _av| Ok(()),
3986 )
3987 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003988
3989 debug_dump_grant_table(&mut db)?;
3990
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003991 let (_key_guard, key_entry) = db
Janis Danisevskis66784c42021-01-27 08:40:25 -08003992 .load_key_entry(&granted_key, KeyType::Client, KeyEntryLoadBits::BOTH, 2, |k, av| {
3993 assert_eq!(Domain::GRANT, k.domain);
3994 assert!(av.unwrap().includes(KeyPerm::use_()));
3995 Ok(())
3996 })
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003997 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003998
Qi Wub9433b52020-12-01 14:52:46 +08003999 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004000
Janis Danisevskis66784c42021-01-27 08:40:25 -08004001 db.unbind_key(&granted_key, KeyType::Client, 2, |_, _| Ok(())).unwrap();
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004002
4003 assert_eq!(
4004 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
4005 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004006 &granted_key,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004007 KeyType::Client,
4008 KeyEntryLoadBits::NONE,
4009 2,
4010 |_k, _av| Ok(()),
4011 )
4012 .unwrap_err()
4013 .root_cause()
4014 .downcast_ref::<KsError>()
4015 );
4016
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004017 Ok(())
4018 }
4019
Janis Danisevskis45760022021-01-19 16:34:10 -08004020 // This test attempts to load a key by key id while the caller is not the owner
4021 // but a grant exists for the given key and the caller.
4022 #[test]
4023 fn test_insert_and_load_full_keyentry_from_grant_by_key_id() -> Result<()> {
4024 let mut db = new_test_db()?;
4025 const OWNER_UID: u32 = 1u32;
4026 const GRANTEE_UID: u32 = 2u32;
4027 const SOMEONE_ELSE_UID: u32 = 3u32;
4028 let key_id = make_test_key_entry(&mut db, Domain::APP, OWNER_UID as i64, TEST_ALIAS, None)
4029 .context("test_insert_and_load_full_keyentry_from_grant_by_key_id")?
4030 .0;
4031
4032 db.grant(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004033 &KeyDescriptor {
Janis Danisevskis45760022021-01-19 16:34:10 -08004034 domain: Domain::APP,
4035 nspace: 0,
4036 alias: Some(TEST_ALIAS.to_string()),
4037 blob: None,
4038 },
4039 OWNER_UID,
4040 GRANTEE_UID,
4041 key_perm_set![KeyPerm::use_()],
4042 |_k, _av| Ok(()),
4043 )
4044 .unwrap();
4045
4046 debug_dump_grant_table(&mut db)?;
4047
4048 let id_descriptor =
4049 KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, ..Default::default() };
4050
4051 let (_, key_entry) = db
4052 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004053 &id_descriptor,
Janis Danisevskis45760022021-01-19 16:34:10 -08004054 KeyType::Client,
4055 KeyEntryLoadBits::BOTH,
4056 GRANTEE_UID,
4057 |k, av| {
4058 assert_eq!(Domain::APP, k.domain);
4059 assert_eq!(OWNER_UID as i64, k.nspace);
4060 assert!(av.unwrap().includes(KeyPerm::use_()));
4061 Ok(())
4062 },
4063 )
4064 .unwrap();
4065
4066 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
4067
4068 let (_, key_entry) = db
4069 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004070 &id_descriptor,
Janis Danisevskis45760022021-01-19 16:34:10 -08004071 KeyType::Client,
4072 KeyEntryLoadBits::BOTH,
4073 SOMEONE_ELSE_UID,
4074 |k, av| {
4075 assert_eq!(Domain::APP, k.domain);
4076 assert_eq!(OWNER_UID as i64, k.nspace);
4077 assert!(av.is_none());
4078 Ok(())
4079 },
4080 )
4081 .unwrap();
4082
4083 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
4084
Janis Danisevskis66784c42021-01-27 08:40:25 -08004085 db.unbind_key(&id_descriptor, KeyType::Client, OWNER_UID, |_, _| Ok(())).unwrap();
Janis Danisevskis45760022021-01-19 16:34:10 -08004086
4087 assert_eq!(
4088 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
4089 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004090 &id_descriptor,
Janis Danisevskis45760022021-01-19 16:34:10 -08004091 KeyType::Client,
4092 KeyEntryLoadBits::NONE,
4093 GRANTEE_UID,
4094 |_k, _av| Ok(()),
4095 )
4096 .unwrap_err()
4097 .root_cause()
4098 .downcast_ref::<KsError>()
4099 );
4100
4101 Ok(())
4102 }
4103
Janis Danisevskisaec14592020-11-12 09:41:49 -08004104 static KEY_LOCK_TEST_ALIAS: &str = "my super duper locked key";
4105
Janis Danisevskisaec14592020-11-12 09:41:49 -08004106 #[test]
4107 fn test_insert_and_load_full_keyentry_domain_app_concurrently() -> Result<()> {
4108 let handle = {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08004109 let temp_dir = Arc::new(TempDir::new("id_lock_test")?);
4110 let temp_dir_clone = temp_dir.clone();
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004111 let mut db = KeystoreDB::new(temp_dir.path(), None)?;
Qi Wub9433b52020-12-01 14:52:46 +08004112 let key_id = make_test_key_entry(&mut db, Domain::APP, 33, KEY_LOCK_TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08004113 .context("test_insert_and_load_full_keyentry_domain_app")?
4114 .0;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004115 let (_key_guard, key_entry) = db
4116 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004117 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004118 domain: Domain::APP,
4119 nspace: 0,
4120 alias: Some(KEY_LOCK_TEST_ALIAS.to_string()),
4121 blob: None,
4122 },
4123 KeyType::Client,
4124 KeyEntryLoadBits::BOTH,
4125 33,
4126 |_k, _av| Ok(()),
4127 )
4128 .unwrap();
Qi Wub9433b52020-12-01 14:52:46 +08004129 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskisaec14592020-11-12 09:41:49 -08004130 let state = Arc::new(AtomicU8::new(1));
4131 let state2 = state.clone();
4132
4133 // Spawning a second thread that attempts to acquire the key id lock
4134 // for the same key as the primary thread. The primary thread then
4135 // waits, thereby forcing the secondary thread into the second stage
4136 // of acquiring the lock (see KEY ID LOCK 2/2 above).
4137 // The test succeeds if the secondary thread observes the transition
4138 // of `state` from 1 to 2, despite having a whole second to overtake
4139 // the primary thread.
4140 let handle = thread::spawn(move || {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08004141 let temp_dir = temp_dir_clone;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004142 let mut db = KeystoreDB::new(temp_dir.path(), None).unwrap();
Janis Danisevskisaec14592020-11-12 09:41:49 -08004143 assert!(db
4144 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004145 &KeyDescriptor {
Janis Danisevskisaec14592020-11-12 09:41:49 -08004146 domain: Domain::APP,
4147 nspace: 0,
4148 alias: Some(KEY_LOCK_TEST_ALIAS.to_string()),
4149 blob: None,
4150 },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004151 KeyType::Client,
Janis Danisevskisaec14592020-11-12 09:41:49 -08004152 KeyEntryLoadBits::BOTH,
4153 33,
4154 |_k, _av| Ok(()),
4155 )
4156 .is_ok());
4157 // We should only see a 2 here because we can only return
4158 // from load_key_entry when the `_key_guard` expires,
4159 // which happens at the end of the scope.
4160 assert_eq!(2, state2.load(Ordering::Relaxed));
4161 });
4162
4163 thread::sleep(std::time::Duration::from_millis(1000));
4164
4165 assert_eq!(Ok(1), state.compare_exchange(1, 2, Ordering::Relaxed, Ordering::Relaxed));
4166
4167 // Return the handle from this scope so we can join with the
4168 // secondary thread after the key id lock has expired.
4169 handle
4170 // This is where the `_key_guard` goes out of scope,
4171 // which is the reason for concurrent load_key_entry on the same key
4172 // to unblock.
4173 };
4174 // Join with the secondary thread and unwrap, to propagate failing asserts to the
4175 // main test thread. We will not see failing asserts in secondary threads otherwise.
4176 handle.join().unwrap();
4177 Ok(())
4178 }
4179
Janis Danisevskise92a5e62020-12-02 12:57:41 -08004180 #[test]
Janis Danisevskis66784c42021-01-27 08:40:25 -08004181 fn teset_database_busy_error_code() {
4182 let temp_dir =
4183 TempDir::new("test_database_busy_error_code_").expect("Failed to create temp dir.");
4184
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004185 let mut db1 = KeystoreDB::new(temp_dir.path(), None).expect("Failed to open database1.");
4186 let mut db2 = KeystoreDB::new(temp_dir.path(), None).expect("Failed to open database2.");
Janis Danisevskis66784c42021-01-27 08:40:25 -08004187
4188 let _tx1 = db1
4189 .conn
4190 .transaction_with_behavior(TransactionBehavior::Immediate)
4191 .expect("Failed to create first transaction.");
4192
4193 let error = db2
4194 .conn
4195 .transaction_with_behavior(TransactionBehavior::Immediate)
4196 .context("Transaction begin failed.")
4197 .expect_err("This should fail.");
4198 let root_cause = error.root_cause();
4199 if let Some(rusqlite::ffi::Error { code: rusqlite::ErrorCode::DatabaseBusy, .. }) =
4200 root_cause.downcast_ref::<rusqlite::ffi::Error>()
4201 {
4202 return;
4203 }
4204 panic!(
4205 "Unexpected error {:?} \n{:?} \n{:?}",
4206 error,
4207 root_cause,
4208 root_cause.downcast_ref::<rusqlite::ffi::Error>()
4209 )
4210 }
4211
4212 #[cfg(disabled)]
4213 #[test]
4214 fn test_large_number_of_concurrent_db_manipulations() -> Result<()> {
4215 let temp_dir = Arc::new(
4216 TempDir::new("test_large_number_of_concurrent_db_manipulations_")
4217 .expect("Failed to create temp dir."),
4218 );
4219
4220 let test_begin = Instant::now();
4221
4222 let mut db = KeystoreDB::new(temp_dir.path()).expect("Failed to open database.");
4223 const KEY_COUNT: u32 = 500u32;
4224 const OPEN_DB_COUNT: u32 = 50u32;
4225
4226 let mut actual_key_count = KEY_COUNT;
4227 // First insert KEY_COUNT keys.
4228 for count in 0..KEY_COUNT {
4229 if Instant::now().duration_since(test_begin) >= Duration::from_secs(15) {
4230 actual_key_count = count;
4231 break;
4232 }
4233 let alias = format!("test_alias_{}", count);
4234 make_test_key_entry(&mut db, Domain::APP, 1, &alias, None)
4235 .expect("Failed to make key entry.");
4236 }
4237
4238 // Insert more keys from a different thread and into a different namespace.
4239 let temp_dir1 = temp_dir.clone();
4240 let handle1 = thread::spawn(move || {
4241 let mut db = KeystoreDB::new(temp_dir1.path()).expect("Failed to open database.");
4242
4243 for count in 0..actual_key_count {
4244 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
4245 return;
4246 }
4247 let alias = format!("test_alias_{}", count);
4248 make_test_key_entry(&mut db, Domain::APP, 2, &alias, None)
4249 .expect("Failed to make key entry.");
4250 }
4251
4252 // then unbind them again.
4253 for count in 0..actual_key_count {
4254 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
4255 return;
4256 }
4257 let key = KeyDescriptor {
4258 domain: Domain::APP,
4259 nspace: -1,
4260 alias: Some(format!("test_alias_{}", count)),
4261 blob: None,
4262 };
4263 db.unbind_key(&key, KeyType::Client, 2, |_, _| Ok(())).expect("Unbind Failed.");
4264 }
4265 });
4266
4267 // And start unbinding the first set of keys.
4268 let temp_dir2 = temp_dir.clone();
4269 let handle2 = thread::spawn(move || {
4270 let mut db = KeystoreDB::new(temp_dir2.path()).expect("Failed to open database.");
4271
4272 for count in 0..actual_key_count {
4273 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
4274 return;
4275 }
4276 let key = KeyDescriptor {
4277 domain: Domain::APP,
4278 nspace: -1,
4279 alias: Some(format!("test_alias_{}", count)),
4280 blob: None,
4281 };
4282 db.unbind_key(&key, KeyType::Client, 1, |_, _| Ok(())).expect("Unbind Failed.");
4283 }
4284 });
4285
4286 let stop_deleting = Arc::new(AtomicU8::new(0));
4287 let stop_deleting2 = stop_deleting.clone();
4288
4289 // And delete anything that is unreferenced keys.
4290 let temp_dir3 = temp_dir.clone();
4291 let handle3 = thread::spawn(move || {
4292 let mut db = KeystoreDB::new(temp_dir3.path()).expect("Failed to open database.");
4293
4294 while stop_deleting2.load(Ordering::Relaxed) != 1 {
4295 while let Some((key_guard, _key)) =
4296 db.get_unreferenced_key().expect("Failed to get unreferenced Key.")
4297 {
4298 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
4299 return;
4300 }
4301 db.purge_key_entry(key_guard).expect("Failed to purge key.");
4302 }
4303 std::thread::sleep(std::time::Duration::from_millis(100));
4304 }
4305 });
4306
4307 // While a lot of inserting and deleting is going on we have to open database connections
4308 // successfully and use them.
4309 // This clone is not redundant, because temp_dir needs to be kept alive until db goes
4310 // out of scope.
4311 #[allow(clippy::redundant_clone)]
4312 let temp_dir4 = temp_dir.clone();
4313 let handle4 = thread::spawn(move || {
4314 for count in 0..OPEN_DB_COUNT {
4315 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
4316 return;
4317 }
4318 let mut db = KeystoreDB::new(temp_dir4.path()).expect("Failed to open database.");
4319
4320 let alias = format!("test_alias_{}", count);
4321 make_test_key_entry(&mut db, Domain::APP, 3, &alias, None)
4322 .expect("Failed to make key entry.");
4323 let key = KeyDescriptor {
4324 domain: Domain::APP,
4325 nspace: -1,
4326 alias: Some(alias),
4327 blob: None,
4328 };
4329 db.unbind_key(&key, KeyType::Client, 3, |_, _| Ok(())).expect("Unbind Failed.");
4330 }
4331 });
4332
4333 handle1.join().expect("Thread 1 panicked.");
4334 handle2.join().expect("Thread 2 panicked.");
4335 handle4.join().expect("Thread 4 panicked.");
4336
4337 stop_deleting.store(1, Ordering::Relaxed);
4338 handle3.join().expect("Thread 3 panicked.");
4339
4340 Ok(())
4341 }
4342
4343 #[test]
Janis Danisevskise92a5e62020-12-02 12:57:41 -08004344 fn list() -> Result<()> {
4345 let temp_dir = TempDir::new("list_test")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004346 let mut db = KeystoreDB::new(temp_dir.path(), None)?;
Janis Danisevskise92a5e62020-12-02 12:57:41 -08004347 static LIST_O_ENTRIES: &[(Domain, i64, &str)] = &[
4348 (Domain::APP, 1, "test1"),
4349 (Domain::APP, 1, "test2"),
4350 (Domain::APP, 1, "test3"),
4351 (Domain::APP, 1, "test4"),
4352 (Domain::APP, 1, "test5"),
4353 (Domain::APP, 1, "test6"),
4354 (Domain::APP, 1, "test7"),
4355 (Domain::APP, 2, "test1"),
4356 (Domain::APP, 2, "test2"),
4357 (Domain::APP, 2, "test3"),
4358 (Domain::APP, 2, "test4"),
4359 (Domain::APP, 2, "test5"),
4360 (Domain::APP, 2, "test6"),
4361 (Domain::APP, 2, "test8"),
4362 (Domain::SELINUX, 100, "test1"),
4363 (Domain::SELINUX, 100, "test2"),
4364 (Domain::SELINUX, 100, "test3"),
4365 (Domain::SELINUX, 100, "test4"),
4366 (Domain::SELINUX, 100, "test5"),
4367 (Domain::SELINUX, 100, "test6"),
4368 (Domain::SELINUX, 100, "test9"),
4369 ];
4370
4371 let list_o_keys: Vec<(i64, i64)> = LIST_O_ENTRIES
4372 .iter()
4373 .map(|(domain, ns, alias)| {
Qi Wub9433b52020-12-01 14:52:46 +08004374 let entry = make_test_key_entry(&mut db, *domain, *ns, *alias, None)
4375 .unwrap_or_else(|e| {
Janis Danisevskise92a5e62020-12-02 12:57:41 -08004376 panic!("Failed to insert {:?} {} {}. Error {:?}", domain, ns, alias, e)
4377 });
4378 (entry.id(), *ns)
4379 })
4380 .collect();
4381
4382 for (domain, namespace) in
4383 &[(Domain::APP, 1i64), (Domain::APP, 2i64), (Domain::SELINUX, 100i64)]
4384 {
4385 let mut list_o_descriptors: Vec<KeyDescriptor> = LIST_O_ENTRIES
4386 .iter()
4387 .filter_map(|(domain, ns, alias)| match ns {
4388 ns if *ns == *namespace => Some(KeyDescriptor {
4389 domain: *domain,
4390 nspace: *ns,
4391 alias: Some(alias.to_string()),
4392 blob: None,
4393 }),
4394 _ => None,
4395 })
4396 .collect();
4397 list_o_descriptors.sort();
4398 let mut list_result = db.list(*domain, *namespace)?;
4399 list_result.sort();
4400 assert_eq!(list_o_descriptors, list_result);
4401
4402 let mut list_o_ids: Vec<i64> = list_o_descriptors
4403 .into_iter()
4404 .map(|d| {
4405 let (_, entry) = db
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004406 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004407 &d,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004408 KeyType::Client,
4409 KeyEntryLoadBits::NONE,
4410 *namespace as u32,
4411 |_, _| Ok(()),
4412 )
Janis Danisevskise92a5e62020-12-02 12:57:41 -08004413 .unwrap();
4414 entry.id()
4415 })
4416 .collect();
4417 list_o_ids.sort_unstable();
4418 let mut loaded_entries: Vec<i64> = list_o_keys
4419 .iter()
4420 .filter_map(|(id, ns)| match ns {
4421 ns if *ns == *namespace => Some(*id),
4422 _ => None,
4423 })
4424 .collect();
4425 loaded_entries.sort_unstable();
4426 assert_eq!(list_o_ids, loaded_entries);
4427 }
4428 assert_eq!(Vec::<KeyDescriptor>::new(), db.list(Domain::SELINUX, 101)?);
4429
4430 Ok(())
4431 }
4432
Joel Galenson0891bc12020-07-20 10:37:03 -07004433 // Helpers
4434
4435 // Checks that the given result is an error containing the given string.
4436 fn check_result_is_error_containing_string<T>(result: Result<T>, target: &str) {
4437 let error_str = format!(
4438 "{:#?}",
4439 result.err().unwrap_or_else(|| panic!("Expected the error: {}", target))
4440 );
4441 assert!(
4442 error_str.contains(target),
4443 "The string \"{}\" should contain \"{}\"",
4444 error_str,
4445 target
4446 );
4447 }
4448
Joel Galenson2aab4432020-07-22 15:27:57 -07004449 #[derive(Debug, PartialEq)]
Joel Galenson0891bc12020-07-20 10:37:03 -07004450 struct KeyEntryRow {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004451 id: i64,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004452 key_type: KeyType,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07004453 domain: Option<Domain>,
Joel Galenson0891bc12020-07-20 10:37:03 -07004454 namespace: Option<i64>,
4455 alias: Option<String>,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004456 state: KeyLifeCycle,
Max Bires8e93d2b2021-01-14 13:17:59 -08004457 km_uuid: Option<Uuid>,
Joel Galenson0891bc12020-07-20 10:37:03 -07004458 }
4459
4460 fn get_keyentry(db: &KeystoreDB) -> Result<Vec<KeyEntryRow>> {
4461 db.conn
Joel Galenson2aab4432020-07-22 15:27:57 -07004462 .prepare("SELECT * FROM persistent.keyentry;")?
Joel Galenson0891bc12020-07-20 10:37:03 -07004463 .query_map(NO_PARAMS, |row| {
Joel Galenson0891bc12020-07-20 10:37:03 -07004464 Ok(KeyEntryRow {
4465 id: row.get(0)?,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004466 key_type: row.get(1)?,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07004467 domain: match row.get(2)? {
4468 Some(i) => Some(Domain(i)),
4469 None => None,
4470 },
Joel Galenson0891bc12020-07-20 10:37:03 -07004471 namespace: row.get(3)?,
4472 alias: row.get(4)?,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004473 state: row.get(5)?,
Max Bires8e93d2b2021-01-14 13:17:59 -08004474 km_uuid: row.get(6)?,
Joel Galenson0891bc12020-07-20 10:37:03 -07004475 })
4476 })?
4477 .map(|r| r.context("Could not read keyentry row."))
4478 .collect::<Result<Vec<_>>>()
4479 }
4480
Max Biresb2e1d032021-02-08 21:35:05 -08004481 struct RemoteProvValues {
4482 cert_chain: Vec<u8>,
4483 priv_key: Vec<u8>,
4484 batch_cert: Vec<u8>,
4485 }
4486
Max Bires2b2e6562020-09-22 11:22:36 -07004487 fn load_attestation_key_pool(
4488 db: &mut KeystoreDB,
4489 expiration_date: i64,
4490 namespace: i64,
4491 base_byte: u8,
Max Biresb2e1d032021-02-08 21:35:05 -08004492 ) -> Result<RemoteProvValues> {
Max Bires2b2e6562020-09-22 11:22:36 -07004493 let public_key: Vec<u8> = vec![base_byte, 0x02 * base_byte];
4494 let cert_chain: Vec<u8> = vec![0x03 * base_byte, 0x04 * base_byte];
4495 let priv_key: Vec<u8> = vec![0x05 * base_byte, 0x06 * base_byte];
4496 let raw_public_key: Vec<u8> = vec![0x0b * base_byte, 0x0c * base_byte];
Max Biresb2e1d032021-02-08 21:35:05 -08004497 let batch_cert: Vec<u8> = vec![base_byte * 0x0d, base_byte * 0x0e];
Max Bires2b2e6562020-09-22 11:22:36 -07004498 db.create_attestation_key_entry(&public_key, &raw_public_key, &priv_key, &KEYSTORE_UUID)?;
4499 db.store_signed_attestation_certificate_chain(
4500 &raw_public_key,
Max Biresb2e1d032021-02-08 21:35:05 -08004501 &batch_cert,
Max Bires2b2e6562020-09-22 11:22:36 -07004502 &cert_chain,
4503 expiration_date,
4504 &KEYSTORE_UUID,
4505 )?;
4506 db.assign_attestation_key(Domain::APP, namespace, &KEYSTORE_UUID)?;
Max Biresb2e1d032021-02-08 21:35:05 -08004507 Ok(RemoteProvValues { cert_chain, priv_key, batch_cert })
Max Bires2b2e6562020-09-22 11:22:36 -07004508 }
4509
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07004510 // Note: The parameters and SecurityLevel associations are nonsensical. This
4511 // collection is only used to check if the parameters are preserved as expected by the
4512 // database.
Qi Wub9433b52020-12-01 14:52:46 +08004513 fn make_test_params(max_usage_count: Option<i32>) -> Vec<KeyParameter> {
4514 let mut params = vec![
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07004515 KeyParameter::new(KeyParameterValue::Invalid, SecurityLevel::TRUSTED_ENVIRONMENT),
4516 KeyParameter::new(
4517 KeyParameterValue::KeyPurpose(KeyPurpose::SIGN),
4518 SecurityLevel::TRUSTED_ENVIRONMENT,
4519 ),
4520 KeyParameter::new(
4521 KeyParameterValue::KeyPurpose(KeyPurpose::DECRYPT),
4522 SecurityLevel::TRUSTED_ENVIRONMENT,
4523 ),
4524 KeyParameter::new(
4525 KeyParameterValue::Algorithm(Algorithm::RSA),
4526 SecurityLevel::TRUSTED_ENVIRONMENT,
4527 ),
4528 KeyParameter::new(KeyParameterValue::KeySize(1024), SecurityLevel::TRUSTED_ENVIRONMENT),
4529 KeyParameter::new(
4530 KeyParameterValue::BlockMode(BlockMode::ECB),
4531 SecurityLevel::TRUSTED_ENVIRONMENT,
4532 ),
4533 KeyParameter::new(
4534 KeyParameterValue::BlockMode(BlockMode::GCM),
4535 SecurityLevel::TRUSTED_ENVIRONMENT,
4536 ),
4537 KeyParameter::new(KeyParameterValue::Digest(Digest::NONE), SecurityLevel::STRONGBOX),
4538 KeyParameter::new(
4539 KeyParameterValue::Digest(Digest::MD5),
4540 SecurityLevel::TRUSTED_ENVIRONMENT,
4541 ),
4542 KeyParameter::new(
4543 KeyParameterValue::Digest(Digest::SHA_2_224),
4544 SecurityLevel::TRUSTED_ENVIRONMENT,
4545 ),
4546 KeyParameter::new(
4547 KeyParameterValue::Digest(Digest::SHA_2_256),
4548 SecurityLevel::STRONGBOX,
4549 ),
4550 KeyParameter::new(
4551 KeyParameterValue::PaddingMode(PaddingMode::NONE),
4552 SecurityLevel::TRUSTED_ENVIRONMENT,
4553 ),
4554 KeyParameter::new(
4555 KeyParameterValue::PaddingMode(PaddingMode::RSA_OAEP),
4556 SecurityLevel::TRUSTED_ENVIRONMENT,
4557 ),
4558 KeyParameter::new(
4559 KeyParameterValue::PaddingMode(PaddingMode::RSA_PSS),
4560 SecurityLevel::STRONGBOX,
4561 ),
4562 KeyParameter::new(
4563 KeyParameterValue::PaddingMode(PaddingMode::RSA_PKCS1_1_5_SIGN),
4564 SecurityLevel::TRUSTED_ENVIRONMENT,
4565 ),
4566 KeyParameter::new(KeyParameterValue::CallerNonce, SecurityLevel::TRUSTED_ENVIRONMENT),
4567 KeyParameter::new(KeyParameterValue::MinMacLength(256), SecurityLevel::STRONGBOX),
4568 KeyParameter::new(
4569 KeyParameterValue::EcCurve(EcCurve::P_224),
4570 SecurityLevel::TRUSTED_ENVIRONMENT,
4571 ),
4572 KeyParameter::new(KeyParameterValue::EcCurve(EcCurve::P_256), SecurityLevel::STRONGBOX),
4573 KeyParameter::new(
4574 KeyParameterValue::EcCurve(EcCurve::P_384),
4575 SecurityLevel::TRUSTED_ENVIRONMENT,
4576 ),
4577 KeyParameter::new(
4578 KeyParameterValue::EcCurve(EcCurve::P_521),
4579 SecurityLevel::TRUSTED_ENVIRONMENT,
4580 ),
4581 KeyParameter::new(
4582 KeyParameterValue::RSAPublicExponent(3),
4583 SecurityLevel::TRUSTED_ENVIRONMENT,
4584 ),
4585 KeyParameter::new(
4586 KeyParameterValue::IncludeUniqueID,
4587 SecurityLevel::TRUSTED_ENVIRONMENT,
4588 ),
4589 KeyParameter::new(KeyParameterValue::BootLoaderOnly, SecurityLevel::STRONGBOX),
4590 KeyParameter::new(KeyParameterValue::RollbackResistance, SecurityLevel::STRONGBOX),
4591 KeyParameter::new(
4592 KeyParameterValue::ActiveDateTime(1234567890),
4593 SecurityLevel::STRONGBOX,
4594 ),
4595 KeyParameter::new(
4596 KeyParameterValue::OriginationExpireDateTime(1234567890),
4597 SecurityLevel::TRUSTED_ENVIRONMENT,
4598 ),
4599 KeyParameter::new(
4600 KeyParameterValue::UsageExpireDateTime(1234567890),
4601 SecurityLevel::TRUSTED_ENVIRONMENT,
4602 ),
4603 KeyParameter::new(
4604 KeyParameterValue::MinSecondsBetweenOps(1234567890),
4605 SecurityLevel::TRUSTED_ENVIRONMENT,
4606 ),
4607 KeyParameter::new(
4608 KeyParameterValue::MaxUsesPerBoot(1234567890),
4609 SecurityLevel::TRUSTED_ENVIRONMENT,
4610 ),
4611 KeyParameter::new(KeyParameterValue::UserID(1), SecurityLevel::STRONGBOX),
4612 KeyParameter::new(KeyParameterValue::UserSecureID(42), SecurityLevel::STRONGBOX),
4613 KeyParameter::new(
4614 KeyParameterValue::NoAuthRequired,
4615 SecurityLevel::TRUSTED_ENVIRONMENT,
4616 ),
4617 KeyParameter::new(
4618 KeyParameterValue::HardwareAuthenticatorType(HardwareAuthenticatorType::PASSWORD),
4619 SecurityLevel::TRUSTED_ENVIRONMENT,
4620 ),
4621 KeyParameter::new(KeyParameterValue::AuthTimeout(1234567890), SecurityLevel::SOFTWARE),
4622 KeyParameter::new(KeyParameterValue::AllowWhileOnBody, SecurityLevel::SOFTWARE),
4623 KeyParameter::new(
4624 KeyParameterValue::TrustedUserPresenceRequired,
4625 SecurityLevel::TRUSTED_ENVIRONMENT,
4626 ),
4627 KeyParameter::new(
4628 KeyParameterValue::TrustedConfirmationRequired,
4629 SecurityLevel::TRUSTED_ENVIRONMENT,
4630 ),
4631 KeyParameter::new(
4632 KeyParameterValue::UnlockedDeviceRequired,
4633 SecurityLevel::TRUSTED_ENVIRONMENT,
4634 ),
4635 KeyParameter::new(
4636 KeyParameterValue::ApplicationID(vec![1u8, 2u8, 3u8, 4u8]),
4637 SecurityLevel::SOFTWARE,
4638 ),
4639 KeyParameter::new(
4640 KeyParameterValue::ApplicationData(vec![4u8, 3u8, 2u8, 1u8]),
4641 SecurityLevel::SOFTWARE,
4642 ),
4643 KeyParameter::new(
4644 KeyParameterValue::CreationDateTime(12345677890),
4645 SecurityLevel::SOFTWARE,
4646 ),
4647 KeyParameter::new(
4648 KeyParameterValue::KeyOrigin(KeyOrigin::GENERATED),
4649 SecurityLevel::TRUSTED_ENVIRONMENT,
4650 ),
4651 KeyParameter::new(
4652 KeyParameterValue::RootOfTrust(vec![3u8, 2u8, 1u8, 4u8]),
4653 SecurityLevel::TRUSTED_ENVIRONMENT,
4654 ),
4655 KeyParameter::new(KeyParameterValue::OSVersion(1), SecurityLevel::TRUSTED_ENVIRONMENT),
4656 KeyParameter::new(KeyParameterValue::OSPatchLevel(2), SecurityLevel::SOFTWARE),
4657 KeyParameter::new(
4658 KeyParameterValue::UniqueID(vec![4u8, 3u8, 1u8, 2u8]),
4659 SecurityLevel::SOFTWARE,
4660 ),
4661 KeyParameter::new(
4662 KeyParameterValue::AttestationChallenge(vec![4u8, 3u8, 1u8, 2u8]),
4663 SecurityLevel::TRUSTED_ENVIRONMENT,
4664 ),
4665 KeyParameter::new(
4666 KeyParameterValue::AttestationApplicationID(vec![4u8, 3u8, 1u8, 2u8]),
4667 SecurityLevel::TRUSTED_ENVIRONMENT,
4668 ),
4669 KeyParameter::new(
4670 KeyParameterValue::AttestationIdBrand(vec![4u8, 3u8, 1u8, 2u8]),
4671 SecurityLevel::TRUSTED_ENVIRONMENT,
4672 ),
4673 KeyParameter::new(
4674 KeyParameterValue::AttestationIdDevice(vec![4u8, 3u8, 1u8, 2u8]),
4675 SecurityLevel::TRUSTED_ENVIRONMENT,
4676 ),
4677 KeyParameter::new(
4678 KeyParameterValue::AttestationIdProduct(vec![4u8, 3u8, 1u8, 2u8]),
4679 SecurityLevel::TRUSTED_ENVIRONMENT,
4680 ),
4681 KeyParameter::new(
4682 KeyParameterValue::AttestationIdSerial(vec![4u8, 3u8, 1u8, 2u8]),
4683 SecurityLevel::TRUSTED_ENVIRONMENT,
4684 ),
4685 KeyParameter::new(
4686 KeyParameterValue::AttestationIdIMEI(vec![4u8, 3u8, 1u8, 2u8]),
4687 SecurityLevel::TRUSTED_ENVIRONMENT,
4688 ),
4689 KeyParameter::new(
4690 KeyParameterValue::AttestationIdMEID(vec![4u8, 3u8, 1u8, 2u8]),
4691 SecurityLevel::TRUSTED_ENVIRONMENT,
4692 ),
4693 KeyParameter::new(
4694 KeyParameterValue::AttestationIdManufacturer(vec![4u8, 3u8, 1u8, 2u8]),
4695 SecurityLevel::TRUSTED_ENVIRONMENT,
4696 ),
4697 KeyParameter::new(
4698 KeyParameterValue::AttestationIdModel(vec![4u8, 3u8, 1u8, 2u8]),
4699 SecurityLevel::TRUSTED_ENVIRONMENT,
4700 ),
4701 KeyParameter::new(
4702 KeyParameterValue::VendorPatchLevel(3),
4703 SecurityLevel::TRUSTED_ENVIRONMENT,
4704 ),
4705 KeyParameter::new(
4706 KeyParameterValue::BootPatchLevel(4),
4707 SecurityLevel::TRUSTED_ENVIRONMENT,
4708 ),
4709 KeyParameter::new(
4710 KeyParameterValue::AssociatedData(vec![4u8, 3u8, 1u8, 2u8]),
4711 SecurityLevel::TRUSTED_ENVIRONMENT,
4712 ),
4713 KeyParameter::new(
4714 KeyParameterValue::Nonce(vec![4u8, 3u8, 1u8, 2u8]),
4715 SecurityLevel::TRUSTED_ENVIRONMENT,
4716 ),
4717 KeyParameter::new(
4718 KeyParameterValue::MacLength(256),
4719 SecurityLevel::TRUSTED_ENVIRONMENT,
4720 ),
4721 KeyParameter::new(
4722 KeyParameterValue::ResetSinceIdRotation,
4723 SecurityLevel::TRUSTED_ENVIRONMENT,
4724 ),
4725 KeyParameter::new(
4726 KeyParameterValue::ConfirmationToken(vec![5u8, 5u8, 5u8, 5u8]),
4727 SecurityLevel::TRUSTED_ENVIRONMENT,
4728 ),
Qi Wub9433b52020-12-01 14:52:46 +08004729 ];
4730 if let Some(value) = max_usage_count {
4731 params.push(KeyParameter::new(
4732 KeyParameterValue::UsageCountLimit(value),
4733 SecurityLevel::SOFTWARE,
4734 ));
4735 }
4736 params
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07004737 }
4738
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004739 fn make_test_key_entry(
4740 db: &mut KeystoreDB,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07004741 domain: Domain,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004742 namespace: i64,
4743 alias: &str,
Qi Wub9433b52020-12-01 14:52:46 +08004744 max_usage_count: Option<i32>,
Janis Danisevskisaec14592020-11-12 09:41:49 -08004745 ) -> Result<KeyIdGuard> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08004746 let key_id = db.create_key_entry(&domain, &namespace, &KEYSTORE_UUID)?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004747 let mut blob_metadata = BlobMetaData::new();
4748 blob_metadata.add(BlobMetaEntry::EncryptedBy(EncryptedBy::Password));
4749 blob_metadata.add(BlobMetaEntry::Salt(vec![1, 2, 3]));
4750 blob_metadata.add(BlobMetaEntry::Iv(vec![2, 3, 1]));
4751 blob_metadata.add(BlobMetaEntry::AeadTag(vec![3, 1, 2]));
4752 blob_metadata.add(BlobMetaEntry::KmUuid(KEYSTORE_UUID));
4753
4754 db.set_blob(
4755 &key_id,
4756 SubComponentType::KEY_BLOB,
4757 Some(TEST_KEY_BLOB),
4758 Some(&blob_metadata),
4759 )?;
4760 db.set_blob(&key_id, SubComponentType::CERT, Some(TEST_CERT_BLOB), None)?;
4761 db.set_blob(&key_id, SubComponentType::CERT_CHAIN, Some(TEST_CERT_CHAIN_BLOB), None)?;
Qi Wub9433b52020-12-01 14:52:46 +08004762
4763 let params = make_test_params(max_usage_count);
4764 db.insert_keyparameter(&key_id, &params)?;
4765
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004766 let mut metadata = KeyMetaData::new();
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004767 metadata.add(KeyMetaEntry::CreationDate(DateTime::from_millis_epoch(123456789)));
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004768 db.insert_key_metadata(&key_id, &metadata)?;
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08004769 rebind_alias(db, &key_id, alias, domain, namespace)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004770 Ok(key_id)
4771 }
4772
Qi Wub9433b52020-12-01 14:52:46 +08004773 fn make_test_key_entry_test_vector(key_id: i64, max_usage_count: Option<i32>) -> KeyEntry {
4774 let params = make_test_params(max_usage_count);
4775
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004776 let mut blob_metadata = BlobMetaData::new();
4777 blob_metadata.add(BlobMetaEntry::EncryptedBy(EncryptedBy::Password));
4778 blob_metadata.add(BlobMetaEntry::Salt(vec![1, 2, 3]));
4779 blob_metadata.add(BlobMetaEntry::Iv(vec![2, 3, 1]));
4780 blob_metadata.add(BlobMetaEntry::AeadTag(vec![3, 1, 2]));
4781 blob_metadata.add(BlobMetaEntry::KmUuid(KEYSTORE_UUID));
4782
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004783 let mut metadata = KeyMetaData::new();
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004784 metadata.add(KeyMetaEntry::CreationDate(DateTime::from_millis_epoch(123456789)));
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004785
4786 KeyEntry {
4787 id: key_id,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004788 key_blob_info: Some((TEST_KEY_BLOB.to_vec(), blob_metadata)),
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004789 cert: Some(TEST_CERT_BLOB.to_vec()),
4790 cert_chain: Some(TEST_CERT_CHAIN_BLOB.to_vec()),
Max Bires8e93d2b2021-01-14 13:17:59 -08004791 km_uuid: KEYSTORE_UUID,
Qi Wub9433b52020-12-01 14:52:46 +08004792 parameters: params,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004793 metadata,
Janis Danisevskis377d1002021-01-27 19:07:48 -08004794 pure_cert: false,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004795 }
4796 }
4797
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004798 fn debug_dump_keyentry_table(db: &mut KeystoreDB) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004799 let mut stmt = db.conn.prepare(
Max Bires8e93d2b2021-01-14 13:17:59 -08004800 "SELECT id, key_type, domain, namespace, alias, state, km_uuid FROM persistent.keyentry;",
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004801 )?;
Max Bires8e93d2b2021-01-14 13:17:59 -08004802 let rows = stmt.query_map::<(i64, KeyType, i32, i64, String, KeyLifeCycle, Uuid), _, _>(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004803 NO_PARAMS,
4804 |row| {
Max Bires8e93d2b2021-01-14 13:17:59 -08004805 Ok((
4806 row.get(0)?,
4807 row.get(1)?,
4808 row.get(2)?,
4809 row.get(3)?,
4810 row.get(4)?,
4811 row.get(5)?,
4812 row.get(6)?,
4813 ))
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004814 },
4815 )?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004816
4817 println!("Key entry table rows:");
4818 for r in rows {
Max Bires8e93d2b2021-01-14 13:17:59 -08004819 let (id, key_type, domain, namespace, alias, state, km_uuid) = r.unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004820 println!(
Max Bires8e93d2b2021-01-14 13:17:59 -08004821 " id: {} KeyType: {:?} Domain: {} Namespace: {} Alias: {} State: {:?} KmUuid: {:?}",
4822 id, key_type, domain, namespace, alias, state, km_uuid
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004823 );
4824 }
4825 Ok(())
4826 }
4827
4828 fn debug_dump_grant_table(db: &mut KeystoreDB) -> Result<()> {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08004829 let mut stmt = db
4830 .conn
4831 .prepare("SELECT id, grantee, keyentryid, access_vector FROM persistent.grant;")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004832 let rows = stmt.query_map::<(i64, i64, i64, i64), _, _>(NO_PARAMS, |row| {
4833 Ok((row.get(0)?, row.get(1)?, row.get(2)?, row.get(3)?))
4834 })?;
4835
4836 println!("Grant table rows:");
4837 for r in rows {
4838 let (id, gt, ki, av) = r.unwrap();
4839 println!(" id: {} grantee: {} key_id: {} access_vector: {}", id, gt, ki, av);
4840 }
4841 Ok(())
4842 }
4843
Joel Galenson0891bc12020-07-20 10:37:03 -07004844 // Use a custom random number generator that repeats each number once.
4845 // This allows us to test repeated elements.
4846
4847 thread_local! {
4848 static RANDOM_COUNTER: RefCell<i64> = RefCell::new(0);
4849 }
4850
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004851 fn reset_random() {
4852 RANDOM_COUNTER.with(|counter| {
4853 *counter.borrow_mut() = 0;
4854 })
4855 }
4856
Joel Galenson0891bc12020-07-20 10:37:03 -07004857 pub fn random() -> i64 {
4858 RANDOM_COUNTER.with(|counter| {
4859 let result = *counter.borrow() / 2;
4860 *counter.borrow_mut() += 1;
4861 result
4862 })
4863 }
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00004864
4865 #[test]
4866 fn test_last_off_body() -> Result<()> {
4867 let mut db = new_test_db()?;
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08004868 db.insert_last_off_body(MonotonicRawTime::now())?;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00004869 let tx = db.conn.transaction_with_behavior(TransactionBehavior::Immediate)?;
4870 let last_off_body_1 = KeystoreDB::get_last_off_body(&tx)?;
4871 tx.commit()?;
4872 let one_second = Duration::from_secs(1);
4873 thread::sleep(one_second);
4874 db.update_last_off_body(MonotonicRawTime::now())?;
4875 let tx2 = db.conn.transaction_with_behavior(TransactionBehavior::Immediate)?;
4876 let last_off_body_2 = KeystoreDB::get_last_off_body(&tx2)?;
4877 tx2.commit()?;
4878 assert!(last_off_body_1.seconds() < last_off_body_2.seconds());
4879 Ok(())
4880 }
Hasini Gunasingheda895552021-01-27 19:34:37 +00004881
4882 #[test]
4883 fn test_unbind_keys_for_user() -> Result<()> {
4884 let mut db = new_test_db()?;
4885 db.unbind_keys_for_user(1, false)?;
4886
4887 make_test_key_entry(&mut db, Domain::APP, 210000, TEST_ALIAS, None)?;
4888 make_test_key_entry(&mut db, Domain::APP, 110000, TEST_ALIAS, None)?;
4889 db.unbind_keys_for_user(2, false)?;
4890
4891 assert_eq!(1, db.list(Domain::APP, 110000)?.len());
4892 assert_eq!(0, db.list(Domain::APP, 210000)?.len());
4893
4894 db.unbind_keys_for_user(1, true)?;
4895 assert_eq!(0, db.list(Domain::APP, 110000)?.len());
4896
4897 Ok(())
4898 }
4899
4900 #[test]
4901 fn test_store_super_key() -> Result<()> {
4902 let mut db = new_test_db()?;
Paul Crowleyf61fee72021-03-17 14:38:44 -07004903 let pw: keystore2_crypto::Password = (&b"xyzabc"[..]).into();
Hasini Gunasingheda895552021-01-27 19:34:37 +00004904 let super_key = keystore2_crypto::generate_aes256_key()?;
Paul Crowley7a658392021-03-18 17:08:20 -07004905 let secret_bytes = b"keystore2 is great.";
Hasini Gunasingheda895552021-01-27 19:34:37 +00004906 let (encrypted_secret, iv, tag) =
Paul Crowley7a658392021-03-18 17:08:20 -07004907 keystore2_crypto::aes_gcm_encrypt(secret_bytes, &super_key)?;
Hasini Gunasingheda895552021-01-27 19:34:37 +00004908
4909 let (encrypted_super_key, metadata) =
4910 SuperKeyManager::encrypt_with_password(&super_key, &pw)?;
Paul Crowley8d5b2532021-03-19 10:53:07 -07004911 db.store_super_key(
4912 1,
4913 &USER_SUPER_KEY,
4914 &encrypted_super_key,
4915 &metadata,
4916 &KeyMetaData::new(),
4917 )?;
Hasini Gunasingheda895552021-01-27 19:34:37 +00004918
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00004919 //check if super key exists
Paul Crowley7a658392021-03-18 17:08:20 -07004920 assert!(db.key_exists(Domain::APP, 1, &USER_SUPER_KEY.alias, KeyType::Super)?);
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00004921
Paul Crowley7a658392021-03-18 17:08:20 -07004922 let (_, key_entry) = db.load_super_key(&USER_SUPER_KEY, 1)?.unwrap();
Paul Crowley8d5b2532021-03-19 10:53:07 -07004923 let loaded_super_key = SuperKeyManager::extract_super_key_from_key_entry(
4924 USER_SUPER_KEY.algorithm,
4925 key_entry,
4926 &pw,
4927 None,
4928 )?;
Hasini Gunasingheda895552021-01-27 19:34:37 +00004929
Paul Crowley7a658392021-03-18 17:08:20 -07004930 let decrypted_secret_bytes =
4931 loaded_super_key.aes_gcm_decrypt(&encrypted_secret, &iv, &tag)?;
4932 assert_eq!(secret_bytes, &*decrypted_secret_bytes);
Hasini Gunasingheda895552021-01-27 19:34:37 +00004933 Ok(())
4934 }
Joel Galenson26f4d012020-07-17 14:57:21 -07004935}