blob: 174a928d53c0b2e44c8e7ed3f4105df30bfb84da [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,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800189 // --- ADD NEW META DATA FIELDS HERE ---
190 // For backwards compatibility add new entries only to
191 // end of this list and above this comment.
192 };
193);
194
195impl BlobMetaData {
196 fn load_from_db(blob_id: i64, tx: &Transaction) -> Result<Self> {
197 let mut stmt = tx
198 .prepare(
199 "SELECT tag, data from persistent.blobmetadata
200 WHERE blobentryid = ?;",
201 )
202 .context("In BlobMetaData::load_from_db: prepare statement failed.")?;
203
204 let mut metadata: HashMap<i64, BlobMetaEntry> = Default::default();
205
206 let mut rows =
207 stmt.query(params![blob_id]).context("In BlobMetaData::load_from_db: query failed.")?;
208 db_utils::with_rows_extract_all(&mut rows, |row| {
209 let db_tag: i64 = row.get(0).context("Failed to read tag.")?;
210 metadata.insert(
211 db_tag,
212 BlobMetaEntry::new_from_sql(db_tag, &SqlField::new(1, &row))
213 .context("Failed to read BlobMetaEntry.")?,
214 );
215 Ok(())
216 })
217 .context("In BlobMetaData::load_from_db.")?;
218
219 Ok(Self { data: metadata })
220 }
221
222 fn store_in_db(&self, blob_id: i64, tx: &Transaction) -> Result<()> {
223 let mut stmt = tx
224 .prepare(
225 "INSERT or REPLACE INTO persistent.blobmetadata (blobentryid, tag, data)
226 VALUES (?, ?, ?);",
227 )
228 .context("In BlobMetaData::store_in_db: Failed to prepare statement.")?;
229
230 let iter = self.data.iter();
231 for (tag, entry) in iter {
232 stmt.insert(params![blob_id, tag, entry,]).with_context(|| {
233 format!("In BlobMetaData::store_in_db: Failed to insert {:?}", entry)
234 })?;
235 }
236 Ok(())
237 }
238}
239
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800240/// Indicates the type of the keyentry.
241#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
242pub enum KeyType {
243 /// This is a client key type. These keys are created or imported through the Keystore 2.0
244 /// AIDL interface android.system.keystore2.
245 Client,
246 /// This is a super key type. These keys are created by keystore itself and used to encrypt
247 /// other key blobs to provide LSKF binding.
248 Super,
249 /// This is an attestation key. These keys are created by the remote provisioning mechanism.
250 Attestation,
251}
252
253impl ToSql for KeyType {
254 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
255 Ok(ToSqlOutput::Owned(Value::Integer(match self {
256 KeyType::Client => 0,
257 KeyType::Super => 1,
258 KeyType::Attestation => 2,
259 })))
260 }
261}
262
263impl FromSql for KeyType {
264 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
265 match i64::column_result(value)? {
266 0 => Ok(KeyType::Client),
267 1 => Ok(KeyType::Super),
268 2 => Ok(KeyType::Attestation),
269 v => Err(FromSqlError::OutOfRange(v)),
270 }
271 }
272}
273
Max Bires8e93d2b2021-01-14 13:17:59 -0800274/// Uuid representation that can be stored in the database.
275/// Right now it can only be initialized from SecurityLevel.
276/// Once KeyMint provides a UUID type a corresponding From impl shall be added.
277#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
278pub struct Uuid([u8; 16]);
279
280impl Deref for Uuid {
281 type Target = [u8; 16];
282
283 fn deref(&self) -> &Self::Target {
284 &self.0
285 }
286}
287
288impl From<SecurityLevel> for Uuid {
289 fn from(sec_level: SecurityLevel) -> Self {
290 Self((sec_level.0 as u128).to_be_bytes())
291 }
292}
293
294impl ToSql for Uuid {
295 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
296 self.0.to_sql()
297 }
298}
299
300impl FromSql for Uuid {
301 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
302 let blob = Vec::<u8>::column_result(value)?;
303 if blob.len() != 16 {
304 return Err(FromSqlError::OutOfRange(blob.len() as i64));
305 }
306 let mut arr = [0u8; 16];
307 arr.copy_from_slice(&blob);
308 Ok(Self(arr))
309 }
310}
311
312/// Key entries that are not associated with any KeyMint instance, such as pure certificate
313/// entries are associated with this UUID.
314pub static KEYSTORE_UUID: Uuid = Uuid([
315 0x41, 0xe3, 0xb9, 0xce, 0x27, 0x58, 0x4e, 0x91, 0xbc, 0xfd, 0xa5, 0x5d, 0x91, 0x85, 0xab, 0x11,
316]);
317
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800318/// Indicates how the sensitive part of this key blob is encrypted.
319#[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
320pub enum EncryptedBy {
321 /// The keyblob is encrypted by a user password.
322 /// In the database this variant is represented as NULL.
323 Password,
324 /// The keyblob is encrypted by another key with wrapped key id.
325 /// In the database this variant is represented as non NULL value
326 /// that is convertible to i64, typically NUMERIC.
327 KeyId(i64),
328}
329
330impl ToSql for EncryptedBy {
331 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
332 match self {
333 Self::Password => Ok(ToSqlOutput::Owned(Value::Null)),
334 Self::KeyId(id) => id.to_sql(),
335 }
336 }
337}
338
339impl FromSql for EncryptedBy {
340 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
341 match value {
342 ValueRef::Null => Ok(Self::Password),
343 _ => Ok(Self::KeyId(i64::column_result(value)?)),
344 }
345 }
346}
347
348/// A database representation of wall clock time. DateTime stores unix epoch time as
349/// i64 in milliseconds.
350#[derive(Debug, Copy, Clone, Default, Eq, PartialEq, Ord, PartialOrd)]
351pub struct DateTime(i64);
352
353/// Error type returned when creating DateTime or converting it from and to
354/// SystemTime.
355#[derive(thiserror::Error, Debug)]
356pub enum DateTimeError {
357 /// This is returned when SystemTime and Duration computations fail.
358 #[error(transparent)]
359 SystemTimeError(#[from] SystemTimeError),
360
361 /// This is returned when type conversions fail.
362 #[error(transparent)]
363 TypeConversion(#[from] std::num::TryFromIntError),
364
365 /// This is returned when checked time arithmetic failed.
366 #[error("Time arithmetic failed.")]
367 TimeArithmetic,
368}
369
370impl DateTime {
371 /// Constructs a new DateTime object denoting the current time. This may fail during
372 /// conversion to unix epoch time and during conversion to the internal i64 representation.
373 pub fn now() -> Result<Self, DateTimeError> {
374 Ok(Self(SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_millis().try_into()?))
375 }
376
377 /// Constructs a new DateTime object from milliseconds.
378 pub fn from_millis_epoch(millis: i64) -> Self {
379 Self(millis)
380 }
381
382 /// Returns unix epoch time in milliseconds.
383 pub fn to_millis_epoch(&self) -> i64 {
384 self.0
385 }
386
387 /// Returns unix epoch time in seconds.
388 pub fn to_secs_epoch(&self) -> i64 {
389 self.0 / 1000
390 }
391}
392
393impl ToSql for DateTime {
394 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
395 Ok(ToSqlOutput::Owned(Value::Integer(self.0)))
396 }
397}
398
399impl FromSql for DateTime {
400 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
401 Ok(Self(i64::column_result(value)?))
402 }
403}
404
405impl TryInto<SystemTime> for DateTime {
406 type Error = DateTimeError;
407
408 fn try_into(self) -> Result<SystemTime, Self::Error> {
409 // We want to construct a SystemTime representation equivalent to self, denoting
410 // a point in time THEN, but we cannot set the time directly. We can only construct
411 // a SystemTime denoting NOW, and we can get the duration between EPOCH and NOW,
412 // and between EPOCH and THEN. With this common reference we can construct the
413 // duration between NOW and THEN which we can add to our SystemTime representation
414 // of NOW to get a SystemTime representation of THEN.
415 // Durations can only be positive, thus the if statement below.
416 let now = SystemTime::now();
417 let now_epoch = now.duration_since(SystemTime::UNIX_EPOCH)?;
418 let then_epoch = Duration::from_millis(self.0.try_into()?);
419 Ok(if now_epoch > then_epoch {
420 // then = now - (now_epoch - then_epoch)
421 now_epoch
422 .checked_sub(then_epoch)
423 .and_then(|d| now.checked_sub(d))
424 .ok_or(DateTimeError::TimeArithmetic)?
425 } else {
426 // then = now + (then_epoch - now_epoch)
427 then_epoch
428 .checked_sub(now_epoch)
429 .and_then(|d| now.checked_add(d))
430 .ok_or(DateTimeError::TimeArithmetic)?
431 })
432 }
433}
434
435impl TryFrom<SystemTime> for DateTime {
436 type Error = DateTimeError;
437
438 fn try_from(t: SystemTime) -> Result<Self, Self::Error> {
439 Ok(Self(t.duration_since(SystemTime::UNIX_EPOCH)?.as_millis().try_into()?))
440 }
441}
442
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800443#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone)]
444enum KeyLifeCycle {
445 /// Existing keys have a key ID but are not fully populated yet.
446 /// This is a transient state. If Keystore finds any such keys when it starts up, it must move
447 /// them to Unreferenced for garbage collection.
448 Existing,
449 /// A live key is fully populated and usable by clients.
450 Live,
451 /// An unreferenced key is scheduled for garbage collection.
452 Unreferenced,
453}
454
455impl ToSql for KeyLifeCycle {
456 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
457 match self {
458 Self::Existing => Ok(ToSqlOutput::Owned(Value::Integer(0))),
459 Self::Live => Ok(ToSqlOutput::Owned(Value::Integer(1))),
460 Self::Unreferenced => Ok(ToSqlOutput::Owned(Value::Integer(2))),
461 }
462 }
463}
464
465impl FromSql for KeyLifeCycle {
466 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
467 match i64::column_result(value)? {
468 0 => Ok(KeyLifeCycle::Existing),
469 1 => Ok(KeyLifeCycle::Live),
470 2 => Ok(KeyLifeCycle::Unreferenced),
471 v => Err(FromSqlError::OutOfRange(v)),
472 }
473 }
474}
475
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700476/// Keys have a KeyMint blob component and optional public certificate and
477/// certificate chain components.
478/// KeyEntryLoadBits is a bitmap that indicates to `KeystoreDB::load_key_entry`
479/// which components shall be loaded from the database if present.
Janis Danisevskis66784c42021-01-27 08:40:25 -0800480#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700481pub struct KeyEntryLoadBits(u32);
482
483impl KeyEntryLoadBits {
484 /// Indicate to `KeystoreDB::load_key_entry` that no component shall be loaded.
485 pub const NONE: KeyEntryLoadBits = Self(0);
486 /// Indicate to `KeystoreDB::load_key_entry` that the KeyMint component shall be loaded.
487 pub const KM: KeyEntryLoadBits = Self(1);
488 /// Indicate to `KeystoreDB::load_key_entry` that the Public components shall be loaded.
489 pub const PUBLIC: KeyEntryLoadBits = Self(2);
490 /// Indicate to `KeystoreDB::load_key_entry` that both components shall be loaded.
491 pub const BOTH: KeyEntryLoadBits = Self(3);
492
493 /// Returns true if this object indicates that the public components shall be loaded.
494 pub const fn load_public(&self) -> bool {
495 self.0 & Self::PUBLIC.0 != 0
496 }
497
498 /// Returns true if the object indicates that the KeyMint component shall be loaded.
499 pub const fn load_km(&self) -> bool {
500 self.0 & Self::KM.0 != 0
501 }
502}
503
Janis Danisevskisaec14592020-11-12 09:41:49 -0800504lazy_static! {
505 static ref KEY_ID_LOCK: KeyIdLockDb = KeyIdLockDb::new();
506}
507
508struct KeyIdLockDb {
509 locked_keys: Mutex<HashSet<i64>>,
510 cond_var: Condvar,
511}
512
513/// A locked key. While a guard exists for a given key id, the same key cannot be loaded
514/// from the database a second time. Most functions manipulating the key blob database
515/// require a KeyIdGuard.
516#[derive(Debug)]
517pub struct KeyIdGuard(i64);
518
519impl KeyIdLockDb {
520 fn new() -> Self {
521 Self { locked_keys: Mutex::new(HashSet::new()), cond_var: Condvar::new() }
522 }
523
524 /// This function blocks until an exclusive lock for the given key entry id can
525 /// be acquired. It returns a guard object, that represents the lifecycle of the
526 /// acquired lock.
527 pub fn get(&self, key_id: i64) -> KeyIdGuard {
528 let mut locked_keys = self.locked_keys.lock().unwrap();
529 while locked_keys.contains(&key_id) {
530 locked_keys = self.cond_var.wait(locked_keys).unwrap();
531 }
532 locked_keys.insert(key_id);
533 KeyIdGuard(key_id)
534 }
535
536 /// This function attempts to acquire an exclusive lock on a given key id. If the
537 /// given key id is already taken the function returns None immediately. If a lock
538 /// can be acquired this function returns a guard object, that represents the
539 /// lifecycle of the acquired lock.
540 pub fn try_get(&self, key_id: i64) -> Option<KeyIdGuard> {
541 let mut locked_keys = self.locked_keys.lock().unwrap();
542 if locked_keys.insert(key_id) {
543 Some(KeyIdGuard(key_id))
544 } else {
545 None
546 }
547 }
548}
549
550impl KeyIdGuard {
551 /// Get the numeric key id of the locked key.
552 pub fn id(&self) -> i64 {
553 self.0
554 }
555}
556
557impl Drop for KeyIdGuard {
558 fn drop(&mut self) {
559 let mut locked_keys = KEY_ID_LOCK.locked_keys.lock().unwrap();
560 locked_keys.remove(&self.0);
Janis Danisevskis7fd53582020-11-23 13:40:34 -0800561 drop(locked_keys);
Janis Danisevskisaec14592020-11-12 09:41:49 -0800562 KEY_ID_LOCK.cond_var.notify_all();
563 }
564}
565
Max Bires8e93d2b2021-01-14 13:17:59 -0800566/// This type represents a certificate and certificate chain entry for a key.
Max Bires2b2e6562020-09-22 11:22:36 -0700567#[derive(Debug, Default)]
Max Bires8e93d2b2021-01-14 13:17:59 -0800568pub struct CertificateInfo {
569 cert: Option<Vec<u8>>,
570 cert_chain: Option<Vec<u8>>,
571}
572
573impl CertificateInfo {
574 /// Constructs a new CertificateInfo object from `cert` and `cert_chain`
575 pub fn new(cert: Option<Vec<u8>>, cert_chain: Option<Vec<u8>>) -> Self {
576 Self { cert, cert_chain }
577 }
578
579 /// Take the cert
580 pub fn take_cert(&mut self) -> Option<Vec<u8>> {
581 self.cert.take()
582 }
583
584 /// Take the cert chain
585 pub fn take_cert_chain(&mut self) -> Option<Vec<u8>> {
586 self.cert_chain.take()
587 }
588}
589
Max Bires2b2e6562020-09-22 11:22:36 -0700590/// This type represents a certificate chain with a private key corresponding to the leaf
591/// 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 -0700592pub struct CertificateChain {
Max Bires97f96812021-02-23 23:44:57 -0800593 /// A KM key blob
594 pub private_key: ZVec,
595 /// A batch cert for private_key
596 pub batch_cert: Vec<u8>,
597 /// A full certificate chain from root signing authority to private_key, including batch_cert
598 /// for convenience.
599 pub cert_chain: Vec<u8>,
Max Bires2b2e6562020-09-22 11:22:36 -0700600}
601
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700602/// This type represents a Keystore 2.0 key entry.
603/// An entry has a unique `id` by which it can be found in the database.
604/// It has a security level field, key parameters, and three optional fields
605/// for the KeyMint blob, public certificate and a public certificate chain.
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800606#[derive(Debug, Default, Eq, PartialEq)]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700607pub struct KeyEntry {
608 id: i64,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800609 key_blob_info: Option<(Vec<u8>, BlobMetaData)>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700610 cert: Option<Vec<u8>>,
611 cert_chain: Option<Vec<u8>>,
Max Bires8e93d2b2021-01-14 13:17:59 -0800612 km_uuid: Uuid,
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700613 parameters: Vec<KeyParameter>,
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800614 metadata: KeyMetaData,
Janis Danisevskis377d1002021-01-27 19:07:48 -0800615 pure_cert: bool,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700616}
617
618impl KeyEntry {
619 /// Returns the unique id of the Key entry.
620 pub fn id(&self) -> i64 {
621 self.id
622 }
623 /// Exposes the optional KeyMint blob.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800624 pub fn key_blob_info(&self) -> &Option<(Vec<u8>, BlobMetaData)> {
625 &self.key_blob_info
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700626 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800627 /// Extracts the Optional KeyMint blob including its metadata.
628 pub fn take_key_blob_info(&mut self) -> Option<(Vec<u8>, BlobMetaData)> {
629 self.key_blob_info.take()
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700630 }
631 /// Exposes the optional public certificate.
632 pub fn cert(&self) -> &Option<Vec<u8>> {
633 &self.cert
634 }
635 /// Extracts the optional public certificate.
636 pub fn take_cert(&mut self) -> Option<Vec<u8>> {
637 self.cert.take()
638 }
639 /// Exposes the optional public certificate chain.
640 pub fn cert_chain(&self) -> &Option<Vec<u8>> {
641 &self.cert_chain
642 }
643 /// Extracts the optional public certificate_chain.
644 pub fn take_cert_chain(&mut self) -> Option<Vec<u8>> {
645 self.cert_chain.take()
646 }
Max Bires8e93d2b2021-01-14 13:17:59 -0800647 /// Returns the uuid of the owning KeyMint instance.
648 pub fn km_uuid(&self) -> &Uuid {
649 &self.km_uuid
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700650 }
Janis Danisevskis04b02832020-10-26 09:21:40 -0700651 /// Exposes the key parameters of this key entry.
652 pub fn key_parameters(&self) -> &Vec<KeyParameter> {
653 &self.parameters
654 }
655 /// Consumes this key entry and extracts the keyparameters from it.
656 pub fn into_key_parameters(self) -> Vec<KeyParameter> {
657 self.parameters
658 }
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800659 /// Exposes the key metadata of this key entry.
660 pub fn metadata(&self) -> &KeyMetaData {
661 &self.metadata
662 }
Janis Danisevskis377d1002021-01-27 19:07:48 -0800663 /// This returns true if the entry is a pure certificate entry with no
664 /// private key component.
665 pub fn pure_cert(&self) -> bool {
666 self.pure_cert
667 }
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000668 /// Consumes this key entry and extracts the keyparameters and metadata from it.
669 pub fn into_key_parameters_and_metadata(self) -> (Vec<KeyParameter>, KeyMetaData) {
670 (self.parameters, self.metadata)
671 }
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700672}
673
674/// Indicates the sub component of a key entry for persistent storage.
Janis Danisevskis377d1002021-01-27 19:07:48 -0800675#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700676pub struct SubComponentType(u32);
677impl SubComponentType {
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800678 /// Persistent identifier for a key blob.
679 pub const KEY_BLOB: SubComponentType = Self(0);
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700680 /// Persistent identifier for a certificate blob.
681 pub const CERT: SubComponentType = Self(1);
682 /// Persistent identifier for a certificate chain blob.
683 pub const CERT_CHAIN: SubComponentType = Self(2);
684}
685
686impl ToSql for SubComponentType {
687 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
688 self.0.to_sql()
689 }
690}
691
692impl FromSql for SubComponentType {
693 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
694 Ok(Self(u32::column_result(value)?))
695 }
696}
697
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800698/// This trait is private to the database module. It is used to convey whether or not the garbage
699/// collector shall be invoked after a database access. All closures passed to
700/// `KeystoreDB::with_transaction` return a tuple (bool, T) where the bool indicates if the
701/// gc needs to be triggered. This convenience function allows to turn any anyhow::Result<T>
702/// into anyhow::Result<(bool, T)> by simply appending one of `.do_gc(bool)`, `.no_gc()`, or
703/// `.need_gc()`.
704trait DoGc<T> {
705 fn do_gc(self, need_gc: bool) -> Result<(bool, T)>;
706
707 fn no_gc(self) -> Result<(bool, T)>;
708
709 fn need_gc(self) -> Result<(bool, T)>;
710}
711
712impl<T> DoGc<T> for Result<T> {
713 fn do_gc(self, need_gc: bool) -> Result<(bool, T)> {
714 self.map(|r| (need_gc, r))
715 }
716
717 fn no_gc(self) -> Result<(bool, T)> {
718 self.do_gc(false)
719 }
720
721 fn need_gc(self) -> Result<(bool, T)> {
722 self.do_gc(true)
723 }
724}
725
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700726/// KeystoreDB wraps a connection to an SQLite database and tracks its
727/// ownership. It also implements all of Keystore 2.0's database functionality.
Joel Galenson26f4d012020-07-17 14:57:21 -0700728pub struct KeystoreDB {
Joel Galenson26f4d012020-07-17 14:57:21 -0700729 conn: Connection,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800730 gc: Option<Gc>,
Joel Galenson26f4d012020-07-17 14:57:21 -0700731}
732
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000733/// Database representation of the monotonic time retrieved from the system call clock_gettime with
734/// CLOCK_MONOTONIC_RAW. Stores monotonic time as i64 in seconds.
735#[derive(Debug, Copy, Clone, Default, Eq, PartialEq, Ord, PartialOrd)]
736pub struct MonotonicRawTime(i64);
737
738impl MonotonicRawTime {
739 /// Constructs a new MonotonicRawTime
740 pub fn now() -> Self {
741 Self(get_current_time_in_seconds())
742 }
743
David Drysdale0e45a612021-02-25 17:24:36 +0000744 /// Constructs a new MonotonicRawTime from a given number of seconds.
745 pub fn from_secs(val: i64) -> Self {
746 Self(val)
747 }
748
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000749 /// Returns the integer value of MonotonicRawTime as i64
750 pub fn seconds(&self) -> i64 {
751 self.0
752 }
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800753
Hasini Gunasingheb3715fb2021-02-26 20:34:45 +0000754 /// Returns the value of MonotonicRawTime in milli seconds as i64
755 pub fn milli_seconds(&self) -> i64 {
756 self.0 * 1000
757 }
758
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800759 /// Like i64::checked_sub.
760 pub fn checked_sub(&self, other: &Self) -> Option<Self> {
761 self.0.checked_sub(other.0).map(Self)
762 }
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000763}
764
765impl ToSql for MonotonicRawTime {
766 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
767 Ok(ToSqlOutput::Owned(Value::Integer(self.0)))
768 }
769}
770
771impl FromSql for MonotonicRawTime {
772 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
773 Ok(Self(i64::column_result(value)?))
774 }
775}
776
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000777/// This struct encapsulates the information to be stored in the database about the auth tokens
778/// received by keystore.
779pub struct AuthTokenEntry {
780 auth_token: HardwareAuthToken,
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000781 time_received: MonotonicRawTime,
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000782}
783
784impl AuthTokenEntry {
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000785 fn new(auth_token: HardwareAuthToken, time_received: MonotonicRawTime) -> Self {
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000786 AuthTokenEntry { auth_token, time_received }
787 }
788
789 /// Checks if this auth token satisfies the given authentication information.
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800790 pub fn satisfies(&self, user_secure_ids: &[i64], auth_type: HardwareAuthenticatorType) -> bool {
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000791 user_secure_ids.iter().any(|&sid| {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800792 (sid == self.auth_token.userId || sid == self.auth_token.authenticatorId)
793 && (((auth_type.0 as i32) & (self.auth_token.authenticatorType.0 as i32)) != 0)
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000794 })
795 }
796
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000797 /// Returns the auth token wrapped by the AuthTokenEntry
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800798 pub fn auth_token(&self) -> &HardwareAuthToken {
799 &self.auth_token
800 }
801
802 /// Returns the auth token wrapped by the AuthTokenEntry
803 pub fn take_auth_token(self) -> HardwareAuthToken {
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000804 self.auth_token
805 }
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800806
807 /// Returns the time that this auth token was received.
808 pub fn time_received(&self) -> MonotonicRawTime {
809 self.time_received
810 }
Hasini Gunasingheb3715fb2021-02-26 20:34:45 +0000811
812 /// Returns the challenge value of the auth token.
813 pub fn challenge(&self) -> i64 {
814 self.auth_token.challenge
815 }
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000816}
817
Janis Danisevskisb00ebd02021-02-02 21:52:24 -0800818/// Shared in-memory databases get destroyed as soon as the last connection to them gets closed.
819/// This object does not allow access to the database connection. But it keeps a database
820/// connection alive in order to keep the in memory per boot database alive.
821pub struct PerBootDbKeepAlive(Connection);
822
Joel Galenson26f4d012020-07-17 14:57:21 -0700823impl KeystoreDB {
Janis Danisevskiseed69842021-02-18 20:04:10 -0800824 const UNASSIGNED_KEY_ID: i64 = -1i64;
Janis Danisevskisb00ebd02021-02-02 21:52:24 -0800825 const PERBOOT_DB_FILE_NAME: &'static str = &"file:perboot.sqlite?mode=memory&cache=shared";
826
827 /// This creates a PerBootDbKeepAlive object to keep the per boot database alive.
828 pub fn keep_perboot_db_alive() -> Result<PerBootDbKeepAlive> {
829 let conn = Connection::open_in_memory()
830 .context("In keep_perboot_db_alive: Failed to initialize SQLite connection.")?;
831
832 conn.execute("ATTACH DATABASE ? as perboot;", params![Self::PERBOOT_DB_FILE_NAME])
833 .context("In keep_perboot_db_alive: Failed to attach database perboot.")?;
834 Ok(PerBootDbKeepAlive(conn))
835 }
836
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700837 /// This will create a new database connection connecting the two
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800838 /// files persistent.sqlite and perboot.sqlite in the given directory.
839 /// It also attempts to initialize all of the tables.
840 /// KeystoreDB cannot be used by multiple threads.
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700841 /// Each thread should open their own connection using `thread_local!`.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800842 pub fn new(db_root: &Path, gc: Option<Gc>) -> Result<Self> {
Janis Danisevskisb00ebd02021-02-02 21:52:24 -0800843 // Build the path to the sqlite file.
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800844 let mut persistent_path = db_root.to_path_buf();
845 persistent_path.push("persistent.sqlite");
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700846
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800847 // Now convert them to strings prefixed with "file:"
848 let mut persistent_path_str = "file:".to_owned();
849 persistent_path_str.push_str(&persistent_path.to_string_lossy());
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800850
Janis Danisevskisb00ebd02021-02-02 21:52:24 -0800851 let conn = Self::make_connection(&persistent_path_str, &Self::PERBOOT_DB_FILE_NAME)?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800852
Janis Danisevskis66784c42021-01-27 08:40:25 -0800853 // On busy fail Immediately. It is unlikely to succeed given a bug in sqlite.
854 conn.busy_handler(None).context("In KeystoreDB::new: Failed to set busy handler.")?;
855
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800856 let mut db = Self { conn, gc };
Janis Danisevskis66784c42021-01-27 08:40:25 -0800857 db.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800858 Self::init_tables(tx).context("Trying to initialize tables.").no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -0800859 })?;
860 Ok(db)
Joel Galenson2aab4432020-07-22 15:27:57 -0700861 }
862
Janis Danisevskis66784c42021-01-27 08:40:25 -0800863 fn init_tables(tx: &Transaction) -> Result<()> {
864 tx.execute(
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700865 "CREATE TABLE IF NOT EXISTS persistent.keyentry (
Joel Galenson0891bc12020-07-20 10:37:03 -0700866 id INTEGER UNIQUE,
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800867 key_type INTEGER,
Joel Galenson0891bc12020-07-20 10:37:03 -0700868 domain INTEGER,
869 namespace INTEGER,
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800870 alias BLOB,
Max Bires8e93d2b2021-01-14 13:17:59 -0800871 state INTEGER,
872 km_uuid BLOB);",
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700873 NO_PARAMS,
874 )
875 .context("Failed to initialize \"keyentry\" table.")?;
876
Janis Danisevskis66784c42021-01-27 08:40:25 -0800877 tx.execute(
Janis Danisevskisa5438182021-02-02 14:22:59 -0800878 "CREATE INDEX IF NOT EXISTS persistent.keyentry_id_index
879 ON keyentry(id);",
880 NO_PARAMS,
881 )
882 .context("Failed to create index keyentry_id_index.")?;
883
884 tx.execute(
885 "CREATE INDEX IF NOT EXISTS persistent.keyentry_domain_namespace_index
886 ON keyentry(domain, namespace, alias);",
887 NO_PARAMS,
888 )
889 .context("Failed to create index keyentry_domain_namespace_index.")?;
890
891 tx.execute(
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700892 "CREATE TABLE IF NOT EXISTS persistent.blobentry (
893 id INTEGER PRIMARY KEY,
894 subcomponent_type INTEGER,
895 keyentryid INTEGER,
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800896 blob BLOB);",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700897 NO_PARAMS,
898 )
899 .context("Failed to initialize \"blobentry\" table.")?;
900
Janis Danisevskis66784c42021-01-27 08:40:25 -0800901 tx.execute(
Janis Danisevskisa5438182021-02-02 14:22:59 -0800902 "CREATE INDEX IF NOT EXISTS persistent.blobentry_keyentryid_index
903 ON blobentry(keyentryid);",
904 NO_PARAMS,
905 )
906 .context("Failed to create index blobentry_keyentryid_index.")?;
907
908 tx.execute(
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800909 "CREATE TABLE IF NOT EXISTS persistent.blobmetadata (
910 id INTEGER PRIMARY KEY,
911 blobentryid INTEGER,
912 tag INTEGER,
913 data ANY,
914 UNIQUE (blobentryid, tag));",
915 NO_PARAMS,
916 )
917 .context("Failed to initialize \"blobmetadata\" table.")?;
918
919 tx.execute(
920 "CREATE INDEX IF NOT EXISTS persistent.blobmetadata_blobentryid_index
921 ON blobmetadata(blobentryid);",
922 NO_PARAMS,
923 )
924 .context("Failed to create index blobmetadata_blobentryid_index.")?;
925
926 tx.execute(
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700927 "CREATE TABLE IF NOT EXISTS persistent.keyparameter (
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000928 keyentryid INTEGER,
929 tag INTEGER,
930 data ANY,
931 security_level INTEGER);",
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700932 NO_PARAMS,
933 )
934 .context("Failed to initialize \"keyparameter\" table.")?;
935
Janis Danisevskis66784c42021-01-27 08:40:25 -0800936 tx.execute(
Janis Danisevskisa5438182021-02-02 14:22:59 -0800937 "CREATE INDEX IF NOT EXISTS persistent.keyparameter_keyentryid_index
938 ON keyparameter(keyentryid);",
939 NO_PARAMS,
940 )
941 .context("Failed to create index keyparameter_keyentryid_index.")?;
942
943 tx.execute(
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800944 "CREATE TABLE IF NOT EXISTS persistent.keymetadata (
945 keyentryid INTEGER,
946 tag INTEGER,
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000947 data ANY,
948 UNIQUE (keyentryid, tag));",
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800949 NO_PARAMS,
950 )
951 .context("Failed to initialize \"keymetadata\" table.")?;
952
Janis Danisevskis66784c42021-01-27 08:40:25 -0800953 tx.execute(
Janis Danisevskisa5438182021-02-02 14:22:59 -0800954 "CREATE INDEX IF NOT EXISTS persistent.keymetadata_keyentryid_index
955 ON keymetadata(keyentryid);",
956 NO_PARAMS,
957 )
958 .context("Failed to create index keymetadata_keyentryid_index.")?;
959
960 tx.execute(
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800961 "CREATE TABLE IF NOT EXISTS persistent.grant (
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700962 id INTEGER UNIQUE,
963 grantee INTEGER,
964 keyentryid INTEGER,
965 access_vector INTEGER);",
966 NO_PARAMS,
967 )
968 .context("Failed to initialize \"grant\" table.")?;
969
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000970 //TODO: only drop the following two perboot tables if this is the first start up
971 //during the boot (b/175716626).
Janis Danisevskis66784c42021-01-27 08:40:25 -0800972 // tx.execute("DROP TABLE IF EXISTS perboot.authtoken;", NO_PARAMS)
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000973 // .context("Failed to drop perboot.authtoken table")?;
Janis Danisevskis66784c42021-01-27 08:40:25 -0800974 tx.execute(
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000975 "CREATE TABLE IF NOT EXISTS perboot.authtoken (
976 id INTEGER PRIMARY KEY,
977 challenge INTEGER,
978 user_id INTEGER,
979 auth_id INTEGER,
980 authenticator_type INTEGER,
981 timestamp INTEGER,
982 mac BLOB,
983 time_received INTEGER,
984 UNIQUE(user_id, auth_id, authenticator_type));",
985 NO_PARAMS,
986 )
987 .context("Failed to initialize \"authtoken\" table.")?;
988
Janis Danisevskis66784c42021-01-27 08:40:25 -0800989 // tx.execute("DROP TABLE IF EXISTS perboot.metadata;", NO_PARAMS)
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000990 // .context("Failed to drop perboot.metadata table")?;
991 // metadata table stores certain miscellaneous information required for keystore functioning
992 // during a boot cycle, as key-value pairs.
Janis Danisevskis66784c42021-01-27 08:40:25 -0800993 tx.execute(
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000994 "CREATE TABLE IF NOT EXISTS perboot.metadata (
995 key TEXT,
996 value BLOB,
997 UNIQUE(key));",
998 NO_PARAMS,
999 )
1000 .context("Failed to initialize \"metadata\" table.")?;
Joel Galenson0891bc12020-07-20 10:37:03 -07001001 Ok(())
1002 }
1003
Janis Danisevskis4df44f42020-08-26 14:40:03 -07001004 fn make_connection(persistent_file: &str, perboot_file: &str) -> Result<Connection> {
1005 let conn =
1006 Connection::open_in_memory().context("Failed to initialize SQLite connection.")?;
1007
Janis Danisevskis66784c42021-01-27 08:40:25 -08001008 loop {
1009 if let Err(e) = conn
1010 .execute("ATTACH DATABASE ? as persistent;", params![persistent_file])
1011 .context("Failed to attach database persistent.")
1012 {
1013 if Self::is_locked_error(&e) {
1014 std::thread::sleep(std::time::Duration::from_micros(500));
1015 continue;
1016 } else {
1017 return Err(e);
1018 }
1019 }
1020 break;
1021 }
1022 loop {
1023 if let Err(e) = conn
1024 .execute("ATTACH DATABASE ? as perboot;", params![perboot_file])
1025 .context("Failed to attach database perboot.")
1026 {
1027 if Self::is_locked_error(&e) {
1028 std::thread::sleep(std::time::Duration::from_micros(500));
1029 continue;
1030 } else {
1031 return Err(e);
1032 }
1033 }
1034 break;
1035 }
Janis Danisevskis4df44f42020-08-26 14:40:03 -07001036
1037 Ok(conn)
1038 }
1039
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001040 /// This function is intended to be used by the garbage collector.
1041 /// It deletes the blob given by `blob_id_to_delete`. It then tries to find a superseded
1042 /// key blob that might need special handling by the garbage collector.
1043 /// If no further superseded blobs can be found it deletes all other superseded blobs that don't
1044 /// need special handling and returns None.
1045 pub fn handle_next_superseded_blob(
1046 &mut self,
1047 blob_id_to_delete: Option<i64>,
1048 ) -> Result<Option<(i64, Vec<u8>, BlobMetaData)>> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001049 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001050 // Delete the given blob if one was given.
1051 if let Some(blob_id_to_delete) = blob_id_to_delete {
1052 tx.execute(
1053 "DELETE FROM persistent.blobmetadata WHERE blobentryid = ?;",
1054 params![blob_id_to_delete],
1055 )
1056 .context("Trying to delete blob metadata.")?;
1057 tx.execute(
1058 "DELETE FROM persistent.blobentry WHERE id = ?;",
1059 params![blob_id_to_delete],
1060 )
1061 .context("Trying to blob.")?;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001062 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001063
1064 // Find another superseded keyblob load its metadata and return it.
1065 if let Some((blob_id, blob)) = tx
1066 .query_row(
1067 "SELECT id, blob FROM persistent.blobentry
1068 WHERE subcomponent_type = ?
1069 AND (
1070 id NOT IN (
1071 SELECT MAX(id) FROM persistent.blobentry
1072 WHERE subcomponent_type = ?
1073 GROUP BY keyentryid, subcomponent_type
1074 )
1075 OR keyentryid NOT IN (SELECT id FROM persistent.keyentry)
1076 );",
1077 params![SubComponentType::KEY_BLOB, SubComponentType::KEY_BLOB],
1078 |row| Ok((row.get(0)?, row.get(1)?)),
1079 )
1080 .optional()
1081 .context("Trying to query superseded blob.")?
1082 {
1083 let blob_metadata = BlobMetaData::load_from_db(blob_id, tx)
1084 .context("Trying to load blob metadata.")?;
1085 return Ok(Some((blob_id, blob, blob_metadata))).no_gc();
1086 }
1087
1088 // We did not find any superseded key blob, so let's remove other superseded blob in
1089 // one transaction.
1090 tx.execute(
1091 "DELETE FROM persistent.blobentry
1092 WHERE NOT subcomponent_type = ?
1093 AND (
1094 id NOT IN (
1095 SELECT MAX(id) FROM persistent.blobentry
1096 WHERE NOT subcomponent_type = ?
1097 GROUP BY keyentryid, subcomponent_type
1098 ) OR keyentryid NOT IN (SELECT id FROM persistent.keyentry)
1099 );",
1100 params![SubComponentType::KEY_BLOB, SubComponentType::KEY_BLOB],
1101 )
1102 .context("Trying to purge superseded blobs.")?;
1103
1104 Ok(None).no_gc()
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001105 })
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001106 .context("In handle_next_superseded_blob.")
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001107 }
1108
1109 /// This maintenance function should be called only once before the database is used for the
1110 /// first time. It restores the invariant that `KeyLifeCycle::Existing` is a transient state.
1111 /// The function transitions all key entries from Existing to Unreferenced unconditionally and
1112 /// returns the number of rows affected. If this returns a value greater than 0, it means that
1113 /// Keystore crashed at some point during key generation. Callers may want to log such
1114 /// occurrences.
1115 /// Unlike with `mark_unreferenced`, we don't need to purge grants, because only keys that made
1116 /// it to `KeyLifeCycle::Live` may have grants.
1117 pub fn cleanup_leftovers(&mut self) -> Result<usize> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001118 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1119 tx.execute(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001120 "UPDATE persistent.keyentry SET state = ? WHERE state = ?;",
1121 params![KeyLifeCycle::Unreferenced, KeyLifeCycle::Existing],
1122 )
Janis Danisevskis66784c42021-01-27 08:40:25 -08001123 .context("Failed to execute query.")
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001124 .need_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08001125 })
1126 .context("In cleanup_leftovers.")
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001127 }
1128
Hasini Gunasinghe0e161452021-01-27 19:34:37 +00001129 /// Checks if a key exists with given key type and key descriptor properties.
1130 pub fn key_exists(
1131 &mut self,
1132 domain: Domain,
1133 nspace: i64,
1134 alias: &str,
1135 key_type: KeyType,
1136 ) -> Result<bool> {
1137 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1138 let key_descriptor =
1139 KeyDescriptor { domain, nspace, alias: Some(alias.to_string()), blob: None };
1140 let result = Self::load_key_entry_id(&tx, &key_descriptor, key_type);
1141 match result {
1142 Ok(_) => Ok(true),
1143 Err(error) => match error.root_cause().downcast_ref::<KsError>() {
1144 Some(KsError::Rc(ResponseCode::KEY_NOT_FOUND)) => Ok(false),
1145 _ => Err(error).context("In key_exists: Failed to find if the key exists."),
1146 },
1147 }
1148 .no_gc()
1149 })
1150 .context("In key_exists.")
1151 }
1152
Hasini Gunasingheda895552021-01-27 19:34:37 +00001153 /// Stores a super key in the database.
1154 pub fn store_super_key(
1155 &mut self,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +00001156 user_id: u32,
Paul Crowley7a658392021-03-18 17:08:20 -07001157 key_type: &SuperKeyType,
1158 blob: &[u8],
1159 blob_metadata: &BlobMetaData,
Paul Crowley8d5b2532021-03-19 10:53:07 -07001160 key_metadata: &KeyMetaData,
Hasini Gunasingheda895552021-01-27 19:34:37 +00001161 ) -> Result<KeyEntry> {
1162 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1163 let key_id = Self::insert_with_retry(|id| {
1164 tx.execute(
1165 "INSERT into persistent.keyentry
1166 (id, key_type, domain, namespace, alias, state, km_uuid)
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00001167 VALUES(?, ?, ?, ?, ?, ?, ?);",
Hasini Gunasingheda895552021-01-27 19:34:37 +00001168 params![
1169 id,
1170 KeyType::Super,
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00001171 Domain::APP.0,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +00001172 user_id as i64,
Paul Crowley7a658392021-03-18 17:08:20 -07001173 key_type.alias,
Hasini Gunasingheda895552021-01-27 19:34:37 +00001174 KeyLifeCycle::Live,
1175 &KEYSTORE_UUID,
1176 ],
1177 )
1178 })
1179 .context("Failed to insert into keyentry table.")?;
1180
Paul Crowley8d5b2532021-03-19 10:53:07 -07001181 key_metadata.store_in_db(key_id, tx).context("KeyMetaData::store_in_db failed")?;
1182
Hasini Gunasingheda895552021-01-27 19:34:37 +00001183 Self::set_blob_internal(
1184 &tx,
1185 key_id,
1186 SubComponentType::KEY_BLOB,
1187 Some(blob),
1188 Some(blob_metadata),
1189 )
1190 .context("Failed to store key blob.")?;
1191
1192 Self::load_key_components(tx, KeyEntryLoadBits::KM, key_id)
1193 .context("Trying to load key components.")
1194 .no_gc()
1195 })
1196 .context("In store_super_key.")
1197 }
1198
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +00001199 /// Loads super key of a given user, if exists
Paul Crowley7a658392021-03-18 17:08:20 -07001200 pub fn load_super_key(
1201 &mut self,
1202 key_type: &SuperKeyType,
1203 user_id: u32,
1204 ) -> Result<Option<(KeyIdGuard, KeyEntry)>> {
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +00001205 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1206 let key_descriptor = KeyDescriptor {
1207 domain: Domain::APP,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +00001208 nspace: user_id as i64,
Paul Crowley7a658392021-03-18 17:08:20 -07001209 alias: Some(key_type.alias.into()),
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +00001210 blob: None,
1211 };
1212 let id = Self::load_key_entry_id(&tx, &key_descriptor, KeyType::Super);
1213 match id {
1214 Ok(id) => {
1215 let key_entry = Self::load_key_components(&tx, KeyEntryLoadBits::KM, id)
1216 .context("In load_super_key. Failed to load key entry.")?;
1217 Ok(Some((KEY_ID_LOCK.get(id), key_entry)))
1218 }
1219 Err(error) => match error.root_cause().downcast_ref::<KsError>() {
1220 Some(KsError::Rc(ResponseCode::KEY_NOT_FOUND)) => Ok(None),
1221 _ => Err(error).context("In load_super_key."),
1222 },
1223 }
1224 .no_gc()
1225 })
1226 .context("In load_super_key.")
1227 }
1228
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001229 /// Atomically loads a key entry and associated metadata or creates it using the
1230 /// callback create_new_key callback. The callback is called during a database
1231 /// transaction. This means that implementers should be mindful about using
1232 /// blocking operations such as IPC or grabbing mutexes.
1233 pub fn get_or_create_key_with<F>(
1234 &mut self,
1235 domain: Domain,
1236 namespace: i64,
1237 alias: &str,
Max Bires8e93d2b2021-01-14 13:17:59 -08001238 km_uuid: Uuid,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001239 create_new_key: F,
1240 ) -> Result<(KeyIdGuard, KeyEntry)>
1241 where
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001242 F: Fn() -> Result<(Vec<u8>, BlobMetaData)>,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001243 {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001244 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1245 let id = {
1246 let mut stmt = tx
1247 .prepare(
1248 "SELECT id FROM persistent.keyentry
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001249 WHERE
1250 key_type = ?
1251 AND domain = ?
1252 AND namespace = ?
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001253 AND alias = ?
1254 AND state = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08001255 )
1256 .context("In get_or_create_key_with: Failed to select from keyentry table.")?;
1257 let mut rows = stmt
1258 .query(params![KeyType::Super, domain.0, namespace, alias, KeyLifeCycle::Live])
1259 .context("In get_or_create_key_with: Failed to query from keyentry table.")?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001260
Janis Danisevskis66784c42021-01-27 08:40:25 -08001261 db_utils::with_rows_extract_one(&mut rows, |row| {
1262 Ok(match row {
1263 Some(r) => r.get(0).context("Failed to unpack id.")?,
1264 None => None,
1265 })
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001266 })
Janis Danisevskis66784c42021-01-27 08:40:25 -08001267 .context("In get_or_create_key_with.")?
1268 };
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001269
Janis Danisevskis66784c42021-01-27 08:40:25 -08001270 let (id, entry) = match id {
1271 Some(id) => (
1272 id,
1273 Self::load_key_components(&tx, KeyEntryLoadBits::KM, id)
1274 .context("In get_or_create_key_with.")?,
1275 ),
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001276
Janis Danisevskis66784c42021-01-27 08:40:25 -08001277 None => {
1278 let id = Self::insert_with_retry(|id| {
1279 tx.execute(
1280 "INSERT into persistent.keyentry
Max Bires8e93d2b2021-01-14 13:17:59 -08001281 (id, key_type, domain, namespace, alias, state, km_uuid)
1282 VALUES(?, ?, ?, ?, ?, ?, ?);",
Janis Danisevskis66784c42021-01-27 08:40:25 -08001283 params![
1284 id,
1285 KeyType::Super,
1286 domain.0,
1287 namespace,
1288 alias,
1289 KeyLifeCycle::Live,
1290 km_uuid,
1291 ],
1292 )
1293 })
1294 .context("In get_or_create_key_with.")?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001295
Janis Danisevskis66784c42021-01-27 08:40:25 -08001296 let (blob, metadata) =
1297 create_new_key().context("In get_or_create_key_with.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001298 Self::set_blob_internal(
1299 &tx,
1300 id,
1301 SubComponentType::KEY_BLOB,
1302 Some(&blob),
1303 Some(&metadata),
1304 )
Paul Crowley7a658392021-03-18 17:08:20 -07001305 .context("In get_or_create_key_with.")?;
Janis Danisevskis66784c42021-01-27 08:40:25 -08001306 (
Janis Danisevskis377d1002021-01-27 19:07:48 -08001307 id,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001308 KeyEntry {
1309 id,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001310 key_blob_info: Some((blob, metadata)),
Janis Danisevskis66784c42021-01-27 08:40:25 -08001311 pure_cert: false,
1312 ..Default::default()
1313 },
1314 )
1315 }
1316 };
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001317 Ok((KEY_ID_LOCK.get(id), entry)).no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08001318 })
1319 .context("In get_or_create_key_with.")
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001320 }
1321
Janis Danisevskis66784c42021-01-27 08:40:25 -08001322 /// SQLite3 seems to hold a shared mutex while running the busy handler when
1323 /// waiting for the database file to become available. This makes it
1324 /// impossible to successfully recover from a locked database when the
1325 /// transaction holding the device busy is in the same process on a
1326 /// different connection. As a result the busy handler has to time out and
1327 /// fail in order to make progress.
1328 ///
1329 /// Instead, we set the busy handler to None (return immediately). And catch
1330 /// Busy and Locked errors (the latter occur on in memory databases with
1331 /// shared cache, e.g., the per-boot database.) and restart the transaction
1332 /// after a grace period of half a millisecond.
1333 ///
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001334 /// Creates a transaction with the given behavior and executes f with the new transaction.
Janis Danisevskis66784c42021-01-27 08:40:25 -08001335 /// The transaction is committed only if f returns Ok and retried if DatabaseBusy
1336 /// or DatabaseLocked is encountered.
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001337 fn with_transaction<T, F>(&mut self, behavior: TransactionBehavior, f: F) -> Result<T>
1338 where
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001339 F: Fn(&Transaction) -> Result<(bool, T)>,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001340 {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001341 loop {
1342 match self
1343 .conn
1344 .transaction_with_behavior(behavior)
1345 .context("In with_transaction.")
1346 .and_then(|tx| f(&tx).map(|result| (result, tx)))
1347 .and_then(|(result, tx)| {
1348 tx.commit().context("In with_transaction: Failed to commit transaction.")?;
1349 Ok(result)
1350 }) {
1351 Ok(result) => break Ok(result),
1352 Err(e) => {
1353 if Self::is_locked_error(&e) {
1354 std::thread::sleep(std::time::Duration::from_micros(500));
1355 continue;
1356 } else {
1357 return Err(e).context("In with_transaction.");
1358 }
1359 }
1360 }
1361 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001362 .map(|(need_gc, result)| {
1363 if need_gc {
1364 if let Some(ref gc) = self.gc {
1365 gc.notify_gc();
1366 }
1367 }
1368 result
1369 })
Janis Danisevskis66784c42021-01-27 08:40:25 -08001370 }
1371
1372 fn is_locked_error(e: &anyhow::Error) -> bool {
Paul Crowleyf61fee72021-03-17 14:38:44 -07001373 matches!(
1374 e.root_cause().downcast_ref::<rusqlite::ffi::Error>(),
1375 Some(rusqlite::ffi::Error { code: rusqlite::ErrorCode::DatabaseBusy, .. })
1376 | Some(rusqlite::ffi::Error { code: rusqlite::ErrorCode::DatabaseLocked, .. })
1377 )
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001378 }
1379
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001380 /// Creates a new key entry and allocates a new randomized id for the new key.
1381 /// The key id gets associated with a domain and namespace but not with an alias.
1382 /// To complete key generation `rebind_alias` should be called after all of the
1383 /// key artifacts, i.e., blobs and parameters have been associated with the new
1384 /// key id. Finalizing with `rebind_alias` makes the creation of a new key entry
1385 /// atomic even if key generation is not.
Max Bires8e93d2b2021-01-14 13:17:59 -08001386 pub fn create_key_entry(
1387 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001388 domain: &Domain,
1389 namespace: &i64,
Max Bires8e93d2b2021-01-14 13:17:59 -08001390 km_uuid: &Uuid,
1391 ) -> Result<KeyIdGuard> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001392 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001393 Self::create_key_entry_internal(tx, domain, namespace, km_uuid).no_gc()
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001394 })
1395 .context("In create_key_entry.")
1396 }
1397
1398 fn create_key_entry_internal(
1399 tx: &Transaction,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001400 domain: &Domain,
1401 namespace: &i64,
Max Bires8e93d2b2021-01-14 13:17:59 -08001402 km_uuid: &Uuid,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001403 ) -> Result<KeyIdGuard> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001404 match *domain {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001405 Domain::APP | Domain::SELINUX => {}
Joel Galenson0891bc12020-07-20 10:37:03 -07001406 _ => {
1407 return Err(KsError::sys())
1408 .context(format!("Domain {:?} must be either App or SELinux.", domain));
1409 }
1410 }
Janis Danisevskisaec14592020-11-12 09:41:49 -08001411 Ok(KEY_ID_LOCK.get(
1412 Self::insert_with_retry(|id| {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001413 tx.execute(
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001414 "INSERT into persistent.keyentry
Max Bires8e93d2b2021-01-14 13:17:59 -08001415 (id, key_type, domain, namespace, alias, state, km_uuid)
1416 VALUES(?, ?, ?, ?, NULL, ?, ?);",
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001417 params![
1418 id,
1419 KeyType::Client,
1420 domain.0 as u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001421 *namespace,
Max Bires8e93d2b2021-01-14 13:17:59 -08001422 KeyLifeCycle::Existing,
1423 km_uuid,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001424 ],
Janis Danisevskisaec14592020-11-12 09:41:49 -08001425 )
1426 })
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001427 .context("In create_key_entry_internal")?,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001428 ))
Joel Galenson26f4d012020-07-17 14:57:21 -07001429 }
Joel Galenson33c04ad2020-08-03 11:04:38 -07001430
Max Bires2b2e6562020-09-22 11:22:36 -07001431 /// Creates a new attestation key entry and allocates a new randomized id for the new key.
1432 /// The key id gets associated with a domain and namespace later but not with an alias. The
1433 /// alias will be used to denote if a key has been signed as each key can only be bound to one
1434 /// domain and namespace pairing so there is no need to use them as a value for indexing into
1435 /// a key.
1436 pub fn create_attestation_key_entry(
1437 &mut self,
1438 maced_public_key: &[u8],
1439 raw_public_key: &[u8],
1440 private_key: &[u8],
1441 km_uuid: &Uuid,
1442 ) -> Result<()> {
1443 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1444 let key_id = KEY_ID_LOCK.get(
1445 Self::insert_with_retry(|id| {
1446 tx.execute(
1447 "INSERT into persistent.keyentry
1448 (id, key_type, domain, namespace, alias, state, km_uuid)
1449 VALUES(?, ?, NULL, NULL, NULL, ?, ?);",
1450 params![id, KeyType::Attestation, KeyLifeCycle::Live, km_uuid],
1451 )
1452 })
1453 .context("In create_key_entry")?,
1454 );
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001455 Self::set_blob_internal(
1456 &tx,
1457 key_id.0,
1458 SubComponentType::KEY_BLOB,
1459 Some(private_key),
1460 None,
1461 )?;
Max Bires2b2e6562020-09-22 11:22:36 -07001462 let mut metadata = KeyMetaData::new();
1463 metadata.add(KeyMetaEntry::AttestationMacedPublicKey(maced_public_key.to_vec()));
1464 metadata.add(KeyMetaEntry::AttestationRawPubKey(raw_public_key.to_vec()));
1465 metadata.store_in_db(key_id.0, &tx)?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001466 Ok(()).no_gc()
Max Bires2b2e6562020-09-22 11:22:36 -07001467 })
1468 .context("In create_attestation_key_entry")
1469 }
1470
Janis Danisevskis377d1002021-01-27 19:07:48 -08001471 /// Set a new blob and associates it with the given key id. Each blob
1472 /// has a sub component type.
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001473 /// Each key can have one of each sub component type associated. If more
1474 /// are added only the most recent can be retrieved, and superseded blobs
Janis Danisevskis377d1002021-01-27 19:07:48 -08001475 /// will get garbage collected.
1476 /// Components SubComponentType::CERT and SubComponentType::CERT_CHAIN can be
1477 /// removed by setting blob to None.
1478 pub fn set_blob(
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001479 &mut self,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001480 key_id: &KeyIdGuard,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001481 sc_type: SubComponentType,
Janis Danisevskis377d1002021-01-27 19:07:48 -08001482 blob: Option<&[u8]>,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001483 blob_metadata: Option<&BlobMetaData>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001484 ) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001485 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001486 Self::set_blob_internal(&tx, key_id.0, sc_type, blob, blob_metadata).need_gc()
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001487 })
Janis Danisevskis377d1002021-01-27 19:07:48 -08001488 .context("In set_blob.")
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001489 }
1490
Janis Danisevskiseed69842021-02-18 20:04:10 -08001491 /// Why would we insert a deleted blob? This weird function is for the purpose of legacy
1492 /// key migration in the case where we bulk delete all the keys of an app or even a user.
1493 /// We use this to insert key blobs into the database which can then be garbage collected
1494 /// lazily by the key garbage collector.
1495 pub fn set_deleted_blob(&mut self, blob: &[u8], blob_metadata: &BlobMetaData) -> Result<()> {
1496 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1497 Self::set_blob_internal(
1498 &tx,
1499 Self::UNASSIGNED_KEY_ID,
1500 SubComponentType::KEY_BLOB,
1501 Some(blob),
1502 Some(blob_metadata),
1503 )
1504 .need_gc()
1505 })
1506 .context("In set_deleted_blob.")
1507 }
1508
Janis Danisevskis377d1002021-01-27 19:07:48 -08001509 fn set_blob_internal(
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001510 tx: &Transaction,
1511 key_id: i64,
1512 sc_type: SubComponentType,
Janis Danisevskis377d1002021-01-27 19:07:48 -08001513 blob: Option<&[u8]>,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001514 blob_metadata: Option<&BlobMetaData>,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001515 ) -> Result<()> {
Janis Danisevskis377d1002021-01-27 19:07:48 -08001516 match (blob, sc_type) {
1517 (Some(blob), _) => {
1518 tx.execute(
1519 "INSERT INTO persistent.blobentry
1520 (subcomponent_type, keyentryid, blob) VALUES (?, ?, ?);",
1521 params![sc_type, key_id, blob],
1522 )
1523 .context("In set_blob_internal: Failed to insert blob.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001524 if let Some(blob_metadata) = blob_metadata {
1525 let blob_id = tx
1526 .query_row("SELECT MAX(id) FROM persistent.blobentry;", NO_PARAMS, |row| {
1527 row.get(0)
1528 })
1529 .context("In set_blob_internal: Failed to get new blob id.")?;
1530 blob_metadata
1531 .store_in_db(blob_id, tx)
1532 .context("In set_blob_internal: Trying to store blob metadata.")?;
1533 }
Janis Danisevskis377d1002021-01-27 19:07:48 -08001534 }
1535 (None, SubComponentType::CERT) | (None, SubComponentType::CERT_CHAIN) => {
1536 tx.execute(
1537 "DELETE FROM persistent.blobentry
1538 WHERE subcomponent_type = ? AND keyentryid = ?;",
1539 params![sc_type, key_id],
1540 )
1541 .context("In set_blob_internal: Failed to delete blob.")?;
1542 }
1543 (None, _) => {
1544 return Err(KsError::sys())
1545 .context("In set_blob_internal: Other blobs cannot be deleted in this way.");
1546 }
1547 }
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001548 Ok(())
1549 }
1550
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001551 /// Inserts a collection of key parameters into the `persistent.keyparameter` table
1552 /// and associates them with the given `key_id`.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001553 #[cfg(test)]
1554 fn insert_keyparameter(&mut self, key_id: &KeyIdGuard, params: &[KeyParameter]) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001555 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001556 Self::insert_keyparameter_internal(tx, key_id, params).no_gc()
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001557 })
1558 .context("In insert_keyparameter.")
1559 }
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001560
Janis Danisevskis66784c42021-01-27 08:40:25 -08001561 fn insert_keyparameter_internal(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001562 tx: &Transaction,
1563 key_id: &KeyIdGuard,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001564 params: &[KeyParameter],
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001565 ) -> Result<()> {
1566 let mut stmt = tx
1567 .prepare(
1568 "INSERT into persistent.keyparameter (keyentryid, tag, data, security_level)
1569 VALUES (?, ?, ?, ?);",
1570 )
1571 .context("In insert_keyparameter_internal: Failed to prepare statement.")?;
1572
Janis Danisevskis66784c42021-01-27 08:40:25 -08001573 for p in params.iter() {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001574 stmt.insert(params![
1575 key_id.0,
1576 p.get_tag().0,
1577 p.key_parameter_value(),
1578 p.security_level().0
1579 ])
1580 .with_context(|| {
1581 format!("In insert_keyparameter_internal: Failed to insert {:?}", p)
1582 })?;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001583 }
1584 Ok(())
1585 }
1586
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001587 /// Insert a set of key entry specific metadata into the database.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001588 #[cfg(test)]
1589 fn insert_key_metadata(&mut self, key_id: &KeyIdGuard, metadata: &KeyMetaData) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001590 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001591 metadata.store_in_db(key_id.0, &tx).no_gc()
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001592 })
1593 .context("In insert_key_metadata.")
1594 }
1595
Max Bires2b2e6562020-09-22 11:22:36 -07001596 /// Stores a signed certificate chain signed by a remote provisioning server, keyed
1597 /// on the public key.
1598 pub fn store_signed_attestation_certificate_chain(
1599 &mut self,
1600 raw_public_key: &[u8],
Max Biresb2e1d032021-02-08 21:35:05 -08001601 batch_cert: &[u8],
Max Bires2b2e6562020-09-22 11:22:36 -07001602 cert_chain: &[u8],
1603 expiration_date: i64,
1604 km_uuid: &Uuid,
1605 ) -> Result<()> {
1606 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1607 let mut stmt = tx
1608 .prepare(
1609 "SELECT keyentryid
1610 FROM persistent.keymetadata
1611 WHERE tag = ? AND data = ? AND keyentryid IN
1612 (SELECT id
1613 FROM persistent.keyentry
1614 WHERE
1615 alias IS NULL AND
1616 domain IS NULL AND
1617 namespace IS NULL AND
1618 key_type = ? AND
1619 km_uuid = ?);",
1620 )
1621 .context("Failed to store attestation certificate chain.")?;
1622 let mut rows = stmt
1623 .query(params![
1624 KeyMetaData::AttestationRawPubKey,
1625 raw_public_key,
1626 KeyType::Attestation,
1627 km_uuid
1628 ])
1629 .context("Failed to fetch keyid")?;
1630 let key_id = db_utils::with_rows_extract_one(&mut rows, |row| {
1631 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?
1632 .get(0)
1633 .context("Failed to unpack id.")
1634 })
1635 .context("Failed to get key_id.")?;
1636 let num_updated = tx
1637 .execute(
1638 "UPDATE persistent.keyentry
1639 SET alias = ?
1640 WHERE id = ?;",
1641 params!["signed", key_id],
1642 )
1643 .context("Failed to update alias.")?;
1644 if num_updated != 1 {
1645 return Err(KsError::sys()).context("Alias not updated for the key.");
1646 }
1647 let mut metadata = KeyMetaData::new();
1648 metadata.add(KeyMetaEntry::AttestationExpirationDate(DateTime::from_millis_epoch(
1649 expiration_date,
1650 )));
1651 metadata.store_in_db(key_id, &tx).context("Failed to insert key metadata.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001652 Self::set_blob_internal(
1653 &tx,
1654 key_id,
1655 SubComponentType::CERT_CHAIN,
1656 Some(cert_chain),
1657 None,
1658 )
1659 .context("Failed to insert cert chain")?;
Max Biresb2e1d032021-02-08 21:35:05 -08001660 Self::set_blob_internal(&tx, key_id, SubComponentType::CERT, Some(batch_cert), None)
1661 .context("Failed to insert cert")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001662 Ok(()).no_gc()
Max Bires2b2e6562020-09-22 11:22:36 -07001663 })
1664 .context("In store_signed_attestation_certificate_chain: ")
1665 }
1666
1667 /// Assigns the next unassigned attestation key to a domain/namespace combo that does not
1668 /// currently have a key assigned to it.
1669 pub fn assign_attestation_key(
1670 &mut self,
1671 domain: Domain,
1672 namespace: i64,
1673 km_uuid: &Uuid,
1674 ) -> Result<()> {
1675 match domain {
1676 Domain::APP | Domain::SELINUX => {}
1677 _ => {
1678 return Err(KsError::sys()).context(format!(
1679 concat!(
1680 "In assign_attestation_key: Domain {:?} ",
1681 "must be either App or SELinux.",
1682 ),
1683 domain
1684 ));
1685 }
1686 }
1687 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1688 let result = tx
1689 .execute(
1690 "UPDATE persistent.keyentry
1691 SET domain=?1, namespace=?2
1692 WHERE
1693 id =
1694 (SELECT MIN(id)
1695 FROM persistent.keyentry
1696 WHERE ALIAS IS NOT NULL
1697 AND domain IS NULL
1698 AND key_type IS ?3
1699 AND state IS ?4
1700 AND km_uuid IS ?5)
1701 AND
1702 (SELECT COUNT(*)
1703 FROM persistent.keyentry
1704 WHERE domain=?1
1705 AND namespace=?2
1706 AND key_type IS ?3
1707 AND state IS ?4
1708 AND km_uuid IS ?5) = 0;",
1709 params![
1710 domain.0 as u32,
1711 namespace,
1712 KeyType::Attestation,
1713 KeyLifeCycle::Live,
1714 km_uuid,
1715 ],
1716 )
1717 .context("Failed to assign attestation key")?;
Max Bires01f8af22021-03-02 23:24:50 -08001718 if result == 0 {
1719 return Err(KsError::Rc(ResponseCode::OUT_OF_KEYS)).context("Out of keys.");
1720 } else if result > 1 {
1721 return Err(KsError::sys())
1722 .context(format!("Expected to update 1 entry, instead updated {}", result));
Max Bires2b2e6562020-09-22 11:22:36 -07001723 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001724 Ok(()).no_gc()
Max Bires2b2e6562020-09-22 11:22:36 -07001725 })
1726 .context("In assign_attestation_key: ")
1727 }
1728
1729 /// Retrieves num_keys number of attestation keys that have not yet been signed by a remote
1730 /// provisioning server, or the maximum number available if there are not num_keys number of
1731 /// entries in the table.
1732 pub fn fetch_unsigned_attestation_keys(
1733 &mut self,
1734 num_keys: i32,
1735 km_uuid: &Uuid,
1736 ) -> Result<Vec<Vec<u8>>> {
1737 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1738 let mut stmt = tx
1739 .prepare(
1740 "SELECT data
1741 FROM persistent.keymetadata
1742 WHERE tag = ? AND keyentryid IN
1743 (SELECT id
1744 FROM persistent.keyentry
1745 WHERE
1746 alias IS NULL AND
1747 domain IS NULL AND
1748 namespace IS NULL AND
1749 key_type = ? AND
1750 km_uuid = ?
1751 LIMIT ?);",
1752 )
1753 .context("Failed to prepare statement")?;
1754 let rows = stmt
1755 .query_map(
1756 params![
1757 KeyMetaData::AttestationMacedPublicKey,
1758 KeyType::Attestation,
1759 km_uuid,
1760 num_keys
1761 ],
1762 |row| Ok(row.get(0)?),
1763 )?
1764 .collect::<rusqlite::Result<Vec<Vec<u8>>>>()
1765 .context("Failed to execute statement")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001766 Ok(rows).no_gc()
Max Bires2b2e6562020-09-22 11:22:36 -07001767 })
1768 .context("In fetch_unsigned_attestation_keys")
1769 }
1770
1771 /// Removes any keys that have expired as of the current time. Returns the number of keys
1772 /// marked unreferenced that are bound to be garbage collected.
1773 pub fn delete_expired_attestation_keys(&mut self) -> Result<i32> {
1774 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1775 let mut stmt = tx
1776 .prepare(
1777 "SELECT keyentryid, data
1778 FROM persistent.keymetadata
1779 WHERE tag = ? AND keyentryid IN
1780 (SELECT id
1781 FROM persistent.keyentry
1782 WHERE key_type = ?);",
1783 )
1784 .context("Failed to prepare query")?;
1785 let key_ids_to_check = stmt
1786 .query_map(
1787 params![KeyMetaData::AttestationExpirationDate, KeyType::Attestation],
1788 |row| Ok((row.get(0)?, row.get(1)?)),
1789 )?
1790 .collect::<rusqlite::Result<Vec<(i64, DateTime)>>>()
1791 .context("Failed to get date metadata")?;
1792 let curr_time = DateTime::from_millis_epoch(
1793 SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_millis() as i64,
1794 );
1795 let mut num_deleted = 0;
1796 for id in key_ids_to_check.iter().filter(|kt| kt.1 < curr_time).map(|kt| kt.0) {
1797 if Self::mark_unreferenced(&tx, id)? {
1798 num_deleted += 1;
1799 }
1800 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001801 Ok(num_deleted).do_gc(num_deleted != 0)
Max Bires2b2e6562020-09-22 11:22:36 -07001802 })
1803 .context("In delete_expired_attestation_keys: ")
1804 }
1805
Max Bires60d7ed12021-03-05 15:59:22 -08001806 /// Deletes all remotely provisioned attestation keys in the system, regardless of the state
1807 /// they are in. This is useful primarily as a testing mechanism.
1808 pub fn delete_all_attestation_keys(&mut self) -> Result<i64> {
1809 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1810 let mut stmt = tx
1811 .prepare(
1812 "SELECT id FROM persistent.keyentry
1813 WHERE key_type IS ?;",
1814 )
1815 .context("Failed to prepare statement")?;
1816 let keys_to_delete = stmt
1817 .query_map(params![KeyType::Attestation], |row| Ok(row.get(0)?))?
1818 .collect::<rusqlite::Result<Vec<i64>>>()
1819 .context("Failed to execute statement")?;
1820 let num_deleted = keys_to_delete
1821 .iter()
1822 .map(|id| Self::mark_unreferenced(&tx, *id))
1823 .collect::<Result<Vec<bool>>>()
1824 .context("Failed to execute mark_unreferenced on a keyid")?
1825 .into_iter()
1826 .filter(|result| *result)
1827 .count() as i64;
1828 Ok(num_deleted).do_gc(num_deleted != 0)
1829 })
1830 .context("In delete_all_attestation_keys: ")
1831 }
1832
Max Bires2b2e6562020-09-22 11:22:36 -07001833 /// Counts the number of keys that will expire by the provided epoch date and the number of
1834 /// keys not currently assigned to a domain.
1835 pub fn get_attestation_pool_status(
1836 &mut self,
1837 date: i64,
1838 km_uuid: &Uuid,
1839 ) -> Result<AttestationPoolStatus> {
1840 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1841 let mut stmt = tx.prepare(
1842 "SELECT data
1843 FROM persistent.keymetadata
1844 WHERE tag = ? AND keyentryid IN
1845 (SELECT id
1846 FROM persistent.keyentry
1847 WHERE alias IS NOT NULL
1848 AND key_type = ?
1849 AND km_uuid = ?
1850 AND state = ?);",
1851 )?;
1852 let times = stmt
1853 .query_map(
1854 params![
1855 KeyMetaData::AttestationExpirationDate,
1856 KeyType::Attestation,
1857 km_uuid,
1858 KeyLifeCycle::Live
1859 ],
1860 |row| Ok(row.get(0)?),
1861 )?
1862 .collect::<rusqlite::Result<Vec<DateTime>>>()
1863 .context("Failed to execute metadata statement")?;
1864 let expiring =
1865 times.iter().filter(|time| time < &&DateTime::from_millis_epoch(date)).count()
1866 as i32;
1867 stmt = tx.prepare(
1868 "SELECT alias, domain
1869 FROM persistent.keyentry
1870 WHERE key_type = ? AND km_uuid = ? AND state = ?;",
1871 )?;
1872 let rows = stmt
1873 .query_map(params![KeyType::Attestation, km_uuid, KeyLifeCycle::Live], |row| {
1874 Ok((row.get(0)?, row.get(1)?))
1875 })?
1876 .collect::<rusqlite::Result<Vec<(Option<String>, Option<u32>)>>>()
1877 .context("Failed to execute keyentry statement")?;
1878 let mut unassigned = 0i32;
1879 let mut attested = 0i32;
1880 let total = rows.len() as i32;
1881 for (alias, domain) in rows {
1882 match (alias, domain) {
1883 (Some(_alias), None) => {
1884 attested += 1;
1885 unassigned += 1;
1886 }
1887 (Some(_alias), Some(_domain)) => {
1888 attested += 1;
1889 }
1890 _ => {}
1891 }
1892 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001893 Ok(AttestationPoolStatus { expiring, unassigned, attested, total }).no_gc()
Max Bires2b2e6562020-09-22 11:22:36 -07001894 })
1895 .context("In get_attestation_pool_status: ")
1896 }
1897
1898 /// Fetches the private key and corresponding certificate chain assigned to a
1899 /// domain/namespace pair. Will either return nothing if the domain/namespace is
1900 /// not assigned, or one CertificateChain.
1901 pub fn retrieve_attestation_key_and_cert_chain(
1902 &mut self,
1903 domain: Domain,
1904 namespace: i64,
1905 km_uuid: &Uuid,
1906 ) -> Result<Option<CertificateChain>> {
1907 match domain {
1908 Domain::APP | Domain::SELINUX => {}
1909 _ => {
1910 return Err(KsError::sys())
1911 .context(format!("Domain {:?} must be either App or SELinux.", domain));
1912 }
1913 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001914 self.with_transaction(TransactionBehavior::Deferred, |tx| {
1915 let mut stmt = tx.prepare(
1916 "SELECT subcomponent_type, blob
Max Bires2b2e6562020-09-22 11:22:36 -07001917 FROM persistent.blobentry
1918 WHERE keyentryid IN
1919 (SELECT id
1920 FROM persistent.keyentry
1921 WHERE key_type = ?
1922 AND domain = ?
1923 AND namespace = ?
1924 AND state = ?
1925 AND km_uuid = ?);",
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001926 )?;
1927 let rows = stmt
1928 .query_map(
1929 params![
1930 KeyType::Attestation,
1931 domain.0 as u32,
1932 namespace,
1933 KeyLifeCycle::Live,
1934 km_uuid
1935 ],
1936 |row| Ok((row.get(0)?, row.get(1)?)),
1937 )?
1938 .collect::<rusqlite::Result<Vec<(SubComponentType, Vec<u8>)>>>()
Max Biresb2e1d032021-02-08 21:35:05 -08001939 .context("query failed.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001940 if rows.is_empty() {
1941 return Ok(None).no_gc();
Max Biresb2e1d032021-02-08 21:35:05 -08001942 } else if rows.len() != 3 {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001943 return Err(KsError::sys()).context(format!(
1944 concat!(
Max Biresb2e1d032021-02-08 21:35:05 -08001945 "Expected to get a single attestation",
1946 "key, cert, and cert chain for a total of 3 entries, but instead got {}."
1947 ),
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001948 rows.len()
1949 ));
Max Bires2b2e6562020-09-22 11:22:36 -07001950 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001951 let mut km_blob: Vec<u8> = Vec::new();
1952 let mut cert_chain_blob: Vec<u8> = Vec::new();
Max Biresb2e1d032021-02-08 21:35:05 -08001953 let mut batch_cert_blob: Vec<u8> = Vec::new();
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001954 for row in rows {
1955 let sub_type: SubComponentType = row.0;
1956 match sub_type {
1957 SubComponentType::KEY_BLOB => {
1958 km_blob = row.1;
1959 }
1960 SubComponentType::CERT_CHAIN => {
1961 cert_chain_blob = row.1;
1962 }
Max Biresb2e1d032021-02-08 21:35:05 -08001963 SubComponentType::CERT => {
1964 batch_cert_blob = row.1;
1965 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001966 _ => Err(KsError::sys()).context("Unknown or incorrect subcomponent type.")?,
1967 }
1968 }
1969 Ok(Some(CertificateChain {
1970 private_key: ZVec::try_from(km_blob)?,
Max Bires97f96812021-02-23 23:44:57 -08001971 batch_cert: batch_cert_blob,
1972 cert_chain: cert_chain_blob,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08001973 }))
1974 .no_gc()
1975 })
Max Biresb2e1d032021-02-08 21:35:05 -08001976 .context("In retrieve_attestation_key_and_cert_chain:")
Max Bires2b2e6562020-09-22 11:22:36 -07001977 }
1978
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001979 /// Updates the alias column of the given key id `newid` with the given alias,
1980 /// and atomically, removes the alias, domain, and namespace from another row
1981 /// with the same alias-domain-namespace tuple if such row exits.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001982 /// Returns Ok(true) if an old key was marked unreferenced as a hint to the garbage
1983 /// collector.
1984 fn rebind_alias(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001985 tx: &Transaction,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001986 newid: &KeyIdGuard,
Joel Galenson33c04ad2020-08-03 11:04:38 -07001987 alias: &str,
Janis Danisevskis66784c42021-01-27 08:40:25 -08001988 domain: &Domain,
1989 namespace: &i64,
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001990 ) -> Result<bool> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08001991 match *domain {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001992 Domain::APP | Domain::SELINUX => {}
Joel Galenson33c04ad2020-08-03 11:04:38 -07001993 _ => {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001994 return Err(KsError::sys()).context(format!(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001995 "In rebind_alias: Domain {:?} must be either App or SELinux.",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001996 domain
1997 ));
Joel Galenson33c04ad2020-08-03 11:04:38 -07001998 }
1999 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002000 let updated = tx
2001 .execute(
2002 "UPDATE persistent.keyentry
2003 SET alias = NULL, domain = NULL, namespace = NULL, state = ?
Joel Galenson33c04ad2020-08-03 11:04:38 -07002004 WHERE alias = ? AND domain = ? AND namespace = ?;",
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002005 params![KeyLifeCycle::Unreferenced, alias, domain.0 as u32, namespace],
2006 )
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002007 .context("In rebind_alias: Failed to rebind existing entry.")?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07002008 let result = tx
2009 .execute(
2010 "UPDATE persistent.keyentry
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002011 SET alias = ?, state = ?
2012 WHERE id = ? AND domain = ? AND namespace = ? AND state = ?;",
2013 params![
2014 alias,
2015 KeyLifeCycle::Live,
2016 newid.0,
2017 domain.0 as u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002018 *namespace,
Max Bires8e93d2b2021-01-14 13:17:59 -08002019 KeyLifeCycle::Existing,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002020 ],
Joel Galenson33c04ad2020-08-03 11:04:38 -07002021 )
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002022 .context("In rebind_alias: Failed to set alias.")?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07002023 if result != 1 {
Joel Galenson33c04ad2020-08-03 11:04:38 -07002024 return Err(KsError::sys()).context(format!(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002025 "In rebind_alias: Expected to update a single entry but instead updated {}.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07002026 result
2027 ));
2028 }
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002029 Ok(updated != 0)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002030 }
2031
2032 /// Store a new key in a single transaction.
2033 /// The function creates a new key entry, populates the blob, key parameter, and metadata
2034 /// fields, and rebinds the given alias to the new key.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002035 /// The boolean returned is a hint for the garbage collector. If true, a key was replaced,
2036 /// is now unreferenced and needs to be collected.
Janis Danisevskis66784c42021-01-27 08:40:25 -08002037 pub fn store_new_key(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002038 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002039 key: &KeyDescriptor,
2040 params: &[KeyParameter],
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002041 blob_info: &(&[u8], &BlobMetaData),
Max Bires8e93d2b2021-01-14 13:17:59 -08002042 cert_info: &CertificateInfo,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002043 metadata: &KeyMetaData,
Max Bires8e93d2b2021-01-14 13:17:59 -08002044 km_uuid: &Uuid,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002045 ) -> Result<KeyIdGuard> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002046 let (alias, domain, namespace) = match key {
2047 KeyDescriptor { alias: Some(alias), domain: Domain::APP, nspace, blob: None }
2048 | KeyDescriptor { alias: Some(alias), domain: Domain::SELINUX, nspace, blob: None } => {
2049 (alias, key.domain, nspace)
2050 }
2051 _ => {
2052 return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT))
2053 .context("In store_new_key: Need alias and domain must be APP or SELINUX.")
2054 }
2055 };
2056 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002057 let key_id = Self::create_key_entry_internal(tx, &domain, namespace, km_uuid)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002058 .context("Trying to create new key entry.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002059 let (blob, blob_metadata) = *blob_info;
2060 Self::set_blob_internal(
2061 tx,
2062 key_id.id(),
2063 SubComponentType::KEY_BLOB,
2064 Some(blob),
2065 Some(&blob_metadata),
2066 )
2067 .context("Trying to insert the key blob.")?;
Max Bires8e93d2b2021-01-14 13:17:59 -08002068 if let Some(cert) = &cert_info.cert {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002069 Self::set_blob_internal(tx, key_id.id(), SubComponentType::CERT, Some(&cert), None)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002070 .context("Trying to insert the certificate.")?;
2071 }
Max Bires8e93d2b2021-01-14 13:17:59 -08002072 if let Some(cert_chain) = &cert_info.cert_chain {
Janis Danisevskis377d1002021-01-27 19:07:48 -08002073 Self::set_blob_internal(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002074 tx,
2075 key_id.id(),
2076 SubComponentType::CERT_CHAIN,
Janis Danisevskis377d1002021-01-27 19:07:48 -08002077 Some(&cert_chain),
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002078 None,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002079 )
2080 .context("Trying to insert the certificate chain.")?;
2081 }
2082 Self::insert_keyparameter_internal(tx, &key_id, params)
2083 .context("Trying to insert key parameters.")?;
Janis Danisevskis377d1002021-01-27 19:07:48 -08002084 metadata.store_in_db(key_id.id(), tx).context("Trying to insert key metadata.")?;
Janis Danisevskis66784c42021-01-27 08:40:25 -08002085 let need_gc = Self::rebind_alias(tx, &key_id, &alias, &domain, namespace)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002086 .context("Trying to rebind alias.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002087 Ok(key_id).do_gc(need_gc)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002088 })
2089 .context("In store_new_key.")
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002090 }
2091
Janis Danisevskis377d1002021-01-27 19:07:48 -08002092 /// Store a new certificate
2093 /// The function creates a new key entry, populates the blob field and metadata, and rebinds
2094 /// the given alias to the new cert.
Max Bires8e93d2b2021-01-14 13:17:59 -08002095 pub fn store_new_certificate(
2096 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002097 key: &KeyDescriptor,
Max Bires8e93d2b2021-01-14 13:17:59 -08002098 cert: &[u8],
2099 km_uuid: &Uuid,
2100 ) -> Result<KeyIdGuard> {
Janis Danisevskis377d1002021-01-27 19:07:48 -08002101 let (alias, domain, namespace) = match key {
2102 KeyDescriptor { alias: Some(alias), domain: Domain::APP, nspace, blob: None }
2103 | KeyDescriptor { alias: Some(alias), domain: Domain::SELINUX, nspace, blob: None } => {
2104 (alias, key.domain, nspace)
2105 }
2106 _ => {
2107 return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT)).context(
2108 "In store_new_certificate: Need alias and domain must be APP or SELINUX.",
2109 )
2110 }
2111 };
2112 self.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002113 let key_id = Self::create_key_entry_internal(tx, &domain, namespace, km_uuid)
Janis Danisevskis377d1002021-01-27 19:07:48 -08002114 .context("Trying to create new key entry.")?;
2115
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002116 Self::set_blob_internal(
2117 tx,
2118 key_id.id(),
2119 SubComponentType::CERT_CHAIN,
2120 Some(cert),
2121 None,
2122 )
2123 .context("Trying to insert certificate.")?;
Janis Danisevskis377d1002021-01-27 19:07:48 -08002124
2125 let mut metadata = KeyMetaData::new();
2126 metadata.add(KeyMetaEntry::CreationDate(
2127 DateTime::now().context("Trying to make creation time.")?,
2128 ));
2129
2130 metadata.store_in_db(key_id.id(), tx).context("Trying to insert key metadata.")?;
2131
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002132 let need_gc = Self::rebind_alias(tx, &key_id, &alias, &domain, namespace)
Janis Danisevskis377d1002021-01-27 19:07:48 -08002133 .context("Trying to rebind alias.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002134 Ok(key_id).do_gc(need_gc)
Janis Danisevskis377d1002021-01-27 19:07:48 -08002135 })
2136 .context("In store_new_certificate.")
2137 }
2138
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002139 // Helper function loading the key_id given the key descriptor
2140 // tuple comprising domain, namespace, and alias.
2141 // Requires a valid transaction.
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002142 fn load_key_entry_id(tx: &Transaction, key: &KeyDescriptor, key_type: KeyType) -> Result<i64> {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002143 let alias = key
2144 .alias
2145 .as_ref()
2146 .map_or_else(|| Err(KsError::sys()), Ok)
2147 .context("In load_key_entry_id: Alias must be specified.")?;
2148 let mut stmt = tx
2149 .prepare(
2150 "SELECT id FROM persistent.keyentry
2151 WHERE
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00002152 key_type = ?
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002153 AND domain = ?
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002154 AND namespace = ?
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002155 AND alias = ?
2156 AND state = ?;",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002157 )
2158 .context("In load_key_entry_id: Failed to select from keyentry table.")?;
2159 let mut rows = stmt
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002160 .query(params![key_type, key.domain.0 as u32, key.nspace, alias, KeyLifeCycle::Live])
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002161 .context("In load_key_entry_id: Failed to read from keyentry table.")?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002162 db_utils::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002163 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002164 .get(0)
2165 .context("Failed to unpack id.")
2166 })
2167 .context("In load_key_entry_id.")
2168 }
2169
2170 /// This helper function completes the access tuple of a key, which is required
2171 /// to perform access control. The strategy depends on the `domain` field in the
2172 /// key descriptor.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002173 /// * Domain::SELINUX: The access tuple is complete and this function only loads
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002174 /// the key_id for further processing.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002175 /// * Domain::APP: Like Domain::SELINUX, but the tuple is completed by `caller_uid`
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002176 /// which serves as the namespace.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002177 /// * Domain::GRANT: The grant table is queried for the `key_id` and the
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002178 /// `access_vector`.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002179 /// * Domain::KEY_ID: The keyentry table is queried for the owning `domain` and
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002180 /// `namespace`.
2181 /// In each case the information returned is sufficient to perform the access
2182 /// check and the key id can be used to load further key artifacts.
2183 fn load_access_tuple(
2184 tx: &Transaction,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002185 key: &KeyDescriptor,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002186 key_type: KeyType,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002187 caller_uid: u32,
2188 ) -> Result<(i64, KeyDescriptor, Option<KeyPermSet>)> {
2189 match key.domain {
2190 // Domain App or SELinux. In this case we load the key_id from
2191 // the keyentry database for further loading of key components.
2192 // We already have the full access tuple to perform access control.
2193 // The only distinction is that we use the caller_uid instead
2194 // of the caller supplied namespace if the domain field is
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002195 // Domain::APP.
2196 Domain::APP | Domain::SELINUX => {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002197 let mut access_key = key.clone();
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002198 if access_key.domain == Domain::APP {
2199 access_key.nspace = caller_uid as i64;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002200 }
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002201 let key_id = Self::load_key_entry_id(&tx, &access_key, key_type)
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002202 .with_context(|| format!("With key.domain = {:?}.", access_key.domain))?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002203
2204 Ok((key_id, access_key, None))
2205 }
2206
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002207 // Domain::GRANT. In this case we load the key_id and the access_vector
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002208 // from the grant table.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002209 Domain::GRANT => {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002210 let mut stmt = tx
2211 .prepare(
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002212 "SELECT keyentryid, access_vector FROM persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002213 WHERE grantee = ? AND id = ?;",
2214 )
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002215 .context("Domain::GRANT prepare statement failed")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002216 let mut rows = stmt
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002217 .query(params![caller_uid as i64, key.nspace])
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002218 .context("Domain:Grant: query failed.")?;
2219 let (key_id, access_vector): (i64, i32) =
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002220 db_utils::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002221 let r =
2222 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002223 Ok((
2224 r.get(0).context("Failed to unpack key_id.")?,
2225 r.get(1).context("Failed to unpack access_vector.")?,
2226 ))
2227 })
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002228 .context("Domain::GRANT.")?;
Janis Danisevskis66784c42021-01-27 08:40:25 -08002229 Ok((key_id, key.clone(), Some(access_vector.into())))
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002230 }
2231
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002232 // Domain::KEY_ID. In this case we load the domain and namespace from the
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002233 // keyentry database because we need them for access control.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002234 Domain::KEY_ID => {
Janis Danisevskis45760022021-01-19 16:34:10 -08002235 let (domain, namespace): (Domain, i64) = {
2236 let mut stmt = tx
2237 .prepare(
2238 "SELECT domain, namespace FROM persistent.keyentry
2239 WHERE
2240 id = ?
2241 AND state = ?;",
2242 )
2243 .context("Domain::KEY_ID: prepare statement failed")?;
2244 let mut rows = stmt
2245 .query(params![key.nspace, KeyLifeCycle::Live])
2246 .context("Domain::KEY_ID: query failed.")?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002247 db_utils::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002248 let r =
2249 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002250 Ok((
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002251 Domain(r.get(0).context("Failed to unpack domain.")?),
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002252 r.get(1).context("Failed to unpack namespace.")?,
2253 ))
2254 })
Janis Danisevskis45760022021-01-19 16:34:10 -08002255 .context("Domain::KEY_ID.")?
2256 };
2257
2258 // We may use a key by id after loading it by grant.
2259 // In this case we have to check if the caller has a grant for this particular
2260 // key. We can skip this if we already know that the caller is the owner.
2261 // But we cannot know this if domain is anything but App. E.g. in the case
2262 // of Domain::SELINUX we have to speculatively check for grants because we have to
2263 // consult the SEPolicy before we know if the caller is the owner.
2264 let access_vector: Option<KeyPermSet> =
2265 if domain != Domain::APP || namespace != caller_uid as i64 {
2266 let access_vector: Option<i32> = tx
2267 .query_row(
2268 "SELECT access_vector FROM persistent.grant
2269 WHERE grantee = ? AND keyentryid = ?;",
2270 params![caller_uid as i64, key.nspace],
2271 |row| row.get(0),
2272 )
2273 .optional()
2274 .context("Domain::KEY_ID: query grant failed.")?;
2275 access_vector.map(|p| p.into())
2276 } else {
2277 None
2278 };
2279
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002280 let key_id = key.nspace;
Janis Danisevskis66784c42021-01-27 08:40:25 -08002281 let mut access_key: KeyDescriptor = key.clone();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002282 access_key.domain = domain;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002283 access_key.nspace = namespace;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002284
Janis Danisevskis45760022021-01-19 16:34:10 -08002285 Ok((key_id, access_key, access_vector))
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002286 }
2287 _ => Err(anyhow!(KsError::sys())),
2288 }
2289 }
2290
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002291 fn load_blob_components(
2292 key_id: i64,
2293 load_bits: KeyEntryLoadBits,
2294 tx: &Transaction,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002295 ) -> Result<(bool, Option<(Vec<u8>, BlobMetaData)>, Option<Vec<u8>>, Option<Vec<u8>>)> {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002296 let mut stmt = tx
2297 .prepare(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002298 "SELECT MAX(id), subcomponent_type, blob FROM persistent.blobentry
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002299 WHERE keyentryid = ? GROUP BY subcomponent_type;",
2300 )
2301 .context("In load_blob_components: prepare statement failed.")?;
2302
2303 let mut rows =
2304 stmt.query(params![key_id]).context("In load_blob_components: query failed.")?;
2305
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002306 let mut key_blob: Option<(i64, Vec<u8>)> = None;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002307 let mut cert_blob: Option<Vec<u8>> = None;
2308 let mut cert_chain_blob: Option<Vec<u8>> = None;
Janis Danisevskis377d1002021-01-27 19:07:48 -08002309 let mut has_km_blob: bool = false;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002310 db_utils::with_rows_extract_all(&mut rows, |row| {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002311 let sub_type: SubComponentType =
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002312 row.get(1).context("Failed to extract subcomponent_type.")?;
Janis Danisevskis377d1002021-01-27 19:07:48 -08002313 has_km_blob = has_km_blob || sub_type == SubComponentType::KEY_BLOB;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002314 match (sub_type, load_bits.load_public(), load_bits.load_km()) {
2315 (SubComponentType::KEY_BLOB, _, true) => {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002316 key_blob = Some((
2317 row.get(0).context("Failed to extract key blob id.")?,
2318 row.get(2).context("Failed to extract key blob.")?,
2319 ));
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002320 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002321 (SubComponentType::CERT, true, _) => {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002322 cert_blob =
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002323 Some(row.get(2).context("Failed to extract public certificate blob.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002324 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002325 (SubComponentType::CERT_CHAIN, true, _) => {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002326 cert_chain_blob =
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002327 Some(row.get(2).context("Failed to extract certificate chain blob.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002328 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002329 (SubComponentType::CERT, _, _)
2330 | (SubComponentType::CERT_CHAIN, _, _)
2331 | (SubComponentType::KEY_BLOB, _, _) => {}
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002332 _ => Err(KsError::sys()).context("Unknown subcomponent type.")?,
2333 }
2334 Ok(())
2335 })
2336 .context("In load_blob_components.")?;
2337
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002338 let blob_info = key_blob.map_or::<Result<_>, _>(Ok(None), |(blob_id, blob)| {
2339 Ok(Some((
2340 blob,
2341 BlobMetaData::load_from_db(blob_id, tx)
2342 .context("In load_blob_components: Trying to load blob_metadata.")?,
2343 )))
2344 })?;
2345
2346 Ok((has_km_blob, blob_info, cert_blob, cert_chain_blob))
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002347 }
2348
2349 fn load_key_parameters(key_id: i64, tx: &Transaction) -> Result<Vec<KeyParameter>> {
2350 let mut stmt = tx
2351 .prepare(
2352 "SELECT tag, data, security_level from persistent.keyparameter
2353 WHERE keyentryid = ?;",
2354 )
2355 .context("In load_key_parameters: prepare statement failed.")?;
2356
2357 let mut parameters: Vec<KeyParameter> = Vec::new();
2358
2359 let mut rows =
2360 stmt.query(params![key_id]).context("In load_key_parameters: query failed.")?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002361 db_utils::with_rows_extract_all(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002362 let tag = Tag(row.get(0).context("Failed to read tag.")?);
2363 let sec_level = SecurityLevel(row.get(2).context("Failed to read sec_level.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002364 parameters.push(
2365 KeyParameter::new_from_sql(tag, &SqlField::new(1, &row), sec_level)
2366 .context("Failed to read KeyParameter.")?,
2367 );
2368 Ok(())
2369 })
2370 .context("In load_key_parameters.")?;
2371
2372 Ok(parameters)
2373 }
2374
Qi Wub9433b52020-12-01 14:52:46 +08002375 /// Decrements the usage count of a limited use key. This function first checks whether the
2376 /// usage has been exhausted, if not, decreases the usage count. If the usage count reaches
2377 /// zero, the key also gets marked unreferenced and scheduled for deletion.
2378 /// Returns Ok(true) if the key was marked unreferenced as a hint to the garbage collector.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002379 pub fn check_and_update_key_usage_count(&mut self, key_id: i64) -> Result<()> {
Qi Wub9433b52020-12-01 14:52:46 +08002380 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2381 let limit: Option<i32> = tx
2382 .query_row(
2383 "SELECT data FROM persistent.keyparameter WHERE keyentryid = ? AND tag = ?;",
2384 params![key_id, Tag::USAGE_COUNT_LIMIT.0],
2385 |row| row.get(0),
2386 )
2387 .optional()
2388 .context("Trying to load usage count")?;
2389
2390 let limit = limit
2391 .ok_or(KsError::Km(ErrorCode::INVALID_KEY_BLOB))
2392 .context("The Key no longer exists. Key is exhausted.")?;
2393
2394 tx.execute(
2395 "UPDATE persistent.keyparameter
2396 SET data = data - 1
2397 WHERE keyentryid = ? AND tag = ? AND data > 0;",
2398 params![key_id, Tag::USAGE_COUNT_LIMIT.0],
2399 )
2400 .context("Failed to update key usage count.")?;
2401
2402 match limit {
2403 1 => Self::mark_unreferenced(tx, key_id)
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002404 .map(|need_gc| (need_gc, ()))
Qi Wub9433b52020-12-01 14:52:46 +08002405 .context("Trying to mark limited use key for deletion."),
2406 0 => Err(KsError::Km(ErrorCode::INVALID_KEY_BLOB)).context("Key is exhausted."),
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002407 _ => Ok(()).no_gc(),
Qi Wub9433b52020-12-01 14:52:46 +08002408 }
2409 })
2410 .context("In check_and_update_key_usage_count.")
2411 }
2412
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002413 /// Load a key entry by the given key descriptor.
2414 /// It uses the `check_permission` callback to verify if the access is allowed
2415 /// given the key access tuple read from the database using `load_access_tuple`.
2416 /// With `load_bits` the caller may specify which blobs shall be loaded from
2417 /// the blob database.
2418 pub fn load_key_entry(
2419 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002420 key: &KeyDescriptor,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002421 key_type: KeyType,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002422 load_bits: KeyEntryLoadBits,
2423 caller_uid: u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002424 check_permission: impl Fn(&KeyDescriptor, Option<KeyPermSet>) -> Result<()>,
2425 ) -> Result<(KeyIdGuard, KeyEntry)> {
2426 loop {
2427 match self.load_key_entry_internal(
2428 key,
2429 key_type,
2430 load_bits,
2431 caller_uid,
2432 &check_permission,
2433 ) {
2434 Ok(result) => break Ok(result),
2435 Err(e) => {
2436 if Self::is_locked_error(&e) {
2437 std::thread::sleep(std::time::Duration::from_micros(500));
2438 continue;
2439 } else {
2440 return Err(e).context("In load_key_entry.");
2441 }
2442 }
2443 }
2444 }
2445 }
2446
2447 fn load_key_entry_internal(
2448 &mut self,
2449 key: &KeyDescriptor,
2450 key_type: KeyType,
2451 load_bits: KeyEntryLoadBits,
2452 caller_uid: u32,
2453 check_permission: &impl Fn(&KeyDescriptor, Option<KeyPermSet>) -> Result<()>,
Janis Danisevskisaec14592020-11-12 09:41:49 -08002454 ) -> Result<(KeyIdGuard, KeyEntry)> {
2455 // KEY ID LOCK 1/2
2456 // If we got a key descriptor with a key id we can get the lock right away.
2457 // Otherwise we have to defer it until we know the key id.
2458 let key_id_guard = match key.domain {
2459 Domain::KEY_ID => Some(KEY_ID_LOCK.get(key.nspace)),
2460 _ => None,
2461 };
2462
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002463 let tx = self
2464 .conn
Janis Danisevskisaec14592020-11-12 09:41:49 -08002465 .unchecked_transaction()
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002466 .context("In load_key_entry: Failed to initialize transaction.")?;
2467
2468 // Load the key_id and complete the access control tuple.
2469 let (key_id, access_key_descriptor, access_vector) =
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002470 Self::load_access_tuple(&tx, key, key_type, caller_uid)
2471 .context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002472
2473 // Perform access control. It is vital that we return here if the permission is denied.
2474 // So do not touch that '?' at the end.
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002475 check_permission(&access_key_descriptor, access_vector).context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002476
Janis Danisevskisaec14592020-11-12 09:41:49 -08002477 // KEY ID LOCK 2/2
2478 // If we did not get a key id lock by now, it was because we got a key descriptor
2479 // without a key id. At this point we got the key id, so we can try and get a lock.
2480 // However, we cannot block here, because we are in the middle of the transaction.
2481 // So first we try to get the lock non blocking. If that fails, we roll back the
2482 // transaction and block until we get the lock. After we successfully got the lock,
2483 // we start a new transaction and load the access tuple again.
2484 //
2485 // We don't need to perform access control again, because we already established
2486 // that the caller had access to the given key. But we need to make sure that the
2487 // key id still exists. So we have to load the key entry by key id this time.
2488 let (key_id_guard, tx) = match key_id_guard {
2489 None => match KEY_ID_LOCK.try_get(key_id) {
2490 None => {
2491 // Roll back the transaction.
2492 tx.rollback().context("In load_key_entry: Failed to roll back transaction.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002493
Janis Danisevskisaec14592020-11-12 09:41:49 -08002494 // Block until we have a key id lock.
2495 let key_id_guard = KEY_ID_LOCK.get(key_id);
2496
2497 // Create a new transaction.
Janis Danisevskis66784c42021-01-27 08:40:25 -08002498 let tx = self
2499 .conn
2500 .unchecked_transaction()
2501 .context("In load_key_entry: Failed to initialize transaction.")?;
Janis Danisevskisaec14592020-11-12 09:41:49 -08002502
2503 Self::load_access_tuple(
2504 &tx,
2505 // This time we have to load the key by the retrieved key id, because the
2506 // alias may have been rebound after we rolled back the transaction.
Janis Danisevskis66784c42021-01-27 08:40:25 -08002507 &KeyDescriptor {
Janis Danisevskisaec14592020-11-12 09:41:49 -08002508 domain: Domain::KEY_ID,
2509 nspace: key_id,
2510 ..Default::default()
2511 },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002512 key_type,
Janis Danisevskisaec14592020-11-12 09:41:49 -08002513 caller_uid,
2514 )
2515 .context("In load_key_entry. (deferred key lock)")?;
2516 (key_id_guard, tx)
2517 }
2518 Some(l) => (l, tx),
2519 },
2520 Some(key_id_guard) => (key_id_guard, tx),
2521 };
2522
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002523 let key_entry = Self::load_key_components(&tx, load_bits, key_id_guard.id())
2524 .context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002525
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002526 tx.commit().context("In load_key_entry: Failed to commit transaction.")?;
2527
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002528 Ok((key_id_guard, key_entry))
2529 }
2530
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002531 fn mark_unreferenced(tx: &Transaction, key_id: i64) -> Result<bool> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002532 let updated = tx
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002533 .execute("DELETE FROM persistent.keyentry WHERE id = ?;", params![key_id])
2534 .context("Trying to delete keyentry.")?;
2535 tx.execute("DELETE FROM persistent.keymetadata WHERE keyentryid = ?;", params![key_id])
2536 .context("Trying to delete keymetadata.")?;
2537 tx.execute("DELETE FROM persistent.keyparameter WHERE keyentryid = ?;", params![key_id])
2538 .context("Trying to delete keyparameters.")?;
2539 tx.execute("DELETE FROM persistent.grant WHERE keyentryid = ?;", params![key_id])
2540 .context("Trying to delete grants.")?;
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002541 Ok(updated != 0)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002542 }
2543
2544 /// Marks the given key as unreferenced and removes all of the grants to this key.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002545 /// Returns Ok(true) if a key was marked unreferenced as a hint for the garbage collector.
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002546 pub fn unbind_key(
2547 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002548 key: &KeyDescriptor,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002549 key_type: KeyType,
2550 caller_uid: u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002551 check_permission: impl Fn(&KeyDescriptor, Option<KeyPermSet>) -> Result<()>,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002552 ) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002553 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2554 let (key_id, access_key_descriptor, access_vector) =
2555 Self::load_access_tuple(tx, key, key_type, caller_uid)
2556 .context("Trying to get access tuple.")?;
2557
2558 // Perform access control. It is vital that we return here if the permission is denied.
2559 // So do not touch that '?' at the end.
2560 check_permission(&access_key_descriptor, access_vector)
2561 .context("While checking permission.")?;
2562
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002563 Self::mark_unreferenced(tx, key_id)
2564 .map(|need_gc| (need_gc, ()))
2565 .context("Trying to mark the key unreferenced.")
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002566 })
2567 .context("In unbind_key.")
2568 }
2569
Max Bires8e93d2b2021-01-14 13:17:59 -08002570 fn get_key_km_uuid(tx: &Transaction, key_id: i64) -> Result<Uuid> {
2571 tx.query_row(
2572 "SELECT km_uuid FROM persistent.keyentry WHERE id = ?",
2573 params![key_id],
2574 |row| row.get(0),
2575 )
2576 .context("In get_key_km_uuid.")
2577 }
2578
Janis Danisevskisddd6e752021-02-22 18:46:55 -08002579 /// Delete all artifacts belonging to the namespace given by the domain-namespace tuple.
2580 /// This leaves all of the blob entries orphaned for subsequent garbage collection.
2581 pub fn unbind_keys_for_namespace(&mut self, domain: Domain, namespace: i64) -> Result<()> {
2582 if !(domain == Domain::APP || domain == Domain::SELINUX) {
2583 return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT))
2584 .context("In unbind_keys_for_namespace.");
2585 }
2586 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2587 tx.execute(
2588 "DELETE FROM persistent.keymetadata
2589 WHERE keyentryid IN (
2590 SELECT id FROM persistent.keyentry
2591 WHERE domain = ? AND namespace = ?
2592 );",
2593 params![domain.0, namespace],
2594 )
2595 .context("Trying to delete keymetadata.")?;
2596 tx.execute(
2597 "DELETE FROM persistent.keyparameter
2598 WHERE keyentryid IN (
2599 SELECT id FROM persistent.keyentry
2600 WHERE domain = ? AND namespace = ?
2601 );",
2602 params![domain.0, namespace],
2603 )
2604 .context("Trying to delete keyparameters.")?;
2605 tx.execute(
2606 "DELETE FROM persistent.grant
2607 WHERE keyentryid IN (
2608 SELECT id FROM persistent.keyentry
2609 WHERE domain = ? AND namespace = ?
2610 );",
2611 params![domain.0, namespace],
2612 )
2613 .context("Trying to delete grants.")?;
2614 tx.execute(
2615 "DELETE FROM persistent.keyentry WHERE domain = ? AND namespace = ?;",
2616 params![domain.0, namespace],
2617 )
2618 .context("Trying to delete keyentry.")?;
2619 Ok(()).need_gc()
2620 })
2621 .context("In unbind_keys_for_namespace")
2622 }
2623
Hasini Gunasingheda895552021-01-27 19:34:37 +00002624 /// Delete the keys created on behalf of the user, denoted by the user id.
2625 /// Delete all the keys unless 'keep_non_super_encrypted_keys' set to true.
2626 /// Returned boolean is to hint the garbage collector to delete the unbound keys.
2627 /// The caller of this function should notify the gc if the returned value is true.
2628 pub fn unbind_keys_for_user(
2629 &mut self,
2630 user_id: u32,
2631 keep_non_super_encrypted_keys: bool,
2632 ) -> Result<()> {
2633 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2634 let mut stmt = tx
2635 .prepare(&format!(
2636 "SELECT id from persistent.keyentry
2637 WHERE (
2638 key_type = ?
2639 AND domain = ?
2640 AND cast ( (namespace/{aid_user_offset}) as int) = ?
2641 AND state = ?
2642 ) OR (
2643 key_type = ?
2644 AND namespace = ?
2645 AND alias = ?
2646 AND state = ?
2647 );",
2648 aid_user_offset = AID_USER_OFFSET
2649 ))
2650 .context(concat!(
2651 "In unbind_keys_for_user. ",
2652 "Failed to prepare the query to find the keys created by apps."
2653 ))?;
2654
2655 let mut rows = stmt
2656 .query(params![
2657 // WHERE client key:
2658 KeyType::Client,
2659 Domain::APP.0 as u32,
2660 user_id,
2661 KeyLifeCycle::Live,
2662 // OR super key:
2663 KeyType::Super,
2664 user_id,
Paul Crowley7a658392021-03-18 17:08:20 -07002665 USER_SUPER_KEY.alias,
Hasini Gunasingheda895552021-01-27 19:34:37 +00002666 KeyLifeCycle::Live
2667 ])
2668 .context("In unbind_keys_for_user. Failed to query the keys created by apps.")?;
2669
2670 let mut key_ids: Vec<i64> = Vec::new();
2671 db_utils::with_rows_extract_all(&mut rows, |row| {
2672 key_ids
2673 .push(row.get(0).context("Failed to read key id of a key created by an app.")?);
2674 Ok(())
2675 })
2676 .context("In unbind_keys_for_user.")?;
2677
2678 let mut notify_gc = false;
2679 for key_id in key_ids {
2680 if keep_non_super_encrypted_keys {
2681 // Load metadata and filter out non-super-encrypted keys.
2682 if let (_, Some((_, blob_metadata)), _, _) =
2683 Self::load_blob_components(key_id, KeyEntryLoadBits::KM, tx)
2684 .context("In unbind_keys_for_user: Trying to load blob info.")?
2685 {
2686 if blob_metadata.encrypted_by().is_none() {
2687 continue;
2688 }
2689 }
2690 }
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +00002691 notify_gc = Self::mark_unreferenced(&tx, key_id)
Hasini Gunasingheda895552021-01-27 19:34:37 +00002692 .context("In unbind_keys_for_user.")?
2693 || notify_gc;
2694 }
2695 Ok(()).do_gc(notify_gc)
2696 })
2697 .context("In unbind_keys_for_user.")
2698 }
2699
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002700 fn load_key_components(
2701 tx: &Transaction,
2702 load_bits: KeyEntryLoadBits,
2703 key_id: i64,
2704 ) -> Result<KeyEntry> {
2705 let metadata = KeyMetaData::load_from_db(key_id, &tx).context("In load_key_components.")?;
2706
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002707 let (has_km_blob, key_blob_info, cert_blob, cert_chain_blob) =
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002708 Self::load_blob_components(key_id, load_bits, &tx)
2709 .context("In load_key_components.")?;
2710
Max Bires8e93d2b2021-01-14 13:17:59 -08002711 let parameters = Self::load_key_parameters(key_id, &tx)
2712 .context("In load_key_components: Trying to load key parameters.")?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002713
Max Bires8e93d2b2021-01-14 13:17:59 -08002714 let km_uuid = Self::get_key_km_uuid(&tx, key_id)
2715 .context("In load_key_components: Trying to get KM uuid.")?;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002716
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002717 Ok(KeyEntry {
2718 id: key_id,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002719 key_blob_info,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002720 cert: cert_blob,
2721 cert_chain: cert_chain_blob,
Max Bires8e93d2b2021-01-14 13:17:59 -08002722 km_uuid,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002723 parameters,
2724 metadata,
Janis Danisevskis377d1002021-01-27 19:07:48 -08002725 pure_cert: !has_km_blob,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002726 })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002727 }
2728
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002729 /// Returns a list of KeyDescriptors in the selected domain/namespace.
2730 /// The key descriptors will have the domain, nspace, and alias field set.
2731 /// Domain must be APP or SELINUX, the caller must make sure of that.
2732 pub fn list(&mut self, domain: Domain, namespace: i64) -> Result<Vec<KeyDescriptor>> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002733 self.with_transaction(TransactionBehavior::Deferred, |tx| {
2734 let mut stmt = tx
2735 .prepare(
2736 "SELECT alias FROM persistent.keyentry
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002737 WHERE domain = ? AND namespace = ? AND alias IS NOT NULL AND state = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08002738 )
2739 .context("In list: Failed to prepare.")?;
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002740
Janis Danisevskis66784c42021-01-27 08:40:25 -08002741 let mut rows = stmt
2742 .query(params![domain.0 as u32, namespace, KeyLifeCycle::Live])
2743 .context("In list: Failed to query.")?;
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002744
Janis Danisevskis66784c42021-01-27 08:40:25 -08002745 let mut descriptors: Vec<KeyDescriptor> = Vec::new();
2746 db_utils::with_rows_extract_all(&mut rows, |row| {
2747 descriptors.push(KeyDescriptor {
2748 domain,
2749 nspace: namespace,
2750 alias: Some(row.get(0).context("Trying to extract alias.")?),
2751 blob: None,
2752 });
2753 Ok(())
2754 })
2755 .context("In list: Failed to extract rows.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002756 Ok(descriptors).no_gc()
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002757 })
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002758 }
2759
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002760 /// Adds a grant to the grant table.
2761 /// Like `load_key_entry` this function loads the access tuple before
2762 /// it uses the callback for a permission check. Upon success,
2763 /// it inserts the `grantee_uid`, `key_id`, and `access_vector` into the
2764 /// grant table. The new row will have a randomized id, which is used as
2765 /// grant id in the namespace field of the resulting KeyDescriptor.
2766 pub fn grant(
2767 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002768 key: &KeyDescriptor,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002769 caller_uid: u32,
2770 grantee_uid: u32,
2771 access_vector: KeyPermSet,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002772 check_permission: impl Fn(&KeyDescriptor, &KeyPermSet) -> Result<()>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002773 ) -> Result<KeyDescriptor> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002774 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2775 // Load the key_id and complete the access control tuple.
2776 // We ignore the access vector here because grants cannot be granted.
2777 // The access vector returned here expresses the permissions the
2778 // grantee has if key.domain == Domain::GRANT. But this vector
2779 // cannot include the grant permission by design, so there is no way the
2780 // subsequent permission check can pass.
2781 // We could check key.domain == Domain::GRANT and fail early.
2782 // But even if we load the access tuple by grant here, the permission
2783 // check denies the attempt to create a grant by grant descriptor.
2784 let (key_id, access_key_descriptor, _) =
2785 Self::load_access_tuple(&tx, key, KeyType::Client, caller_uid)
2786 .context("In grant")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002787
Janis Danisevskis66784c42021-01-27 08:40:25 -08002788 // Perform access control. It is vital that we return here if the permission
2789 // was denied. So do not touch that '?' at the end of the line.
2790 // This permission check checks if the caller has the grant permission
2791 // for the given key and in addition to all of the permissions
2792 // expressed in `access_vector`.
2793 check_permission(&access_key_descriptor, &access_vector)
2794 .context("In grant: check_permission failed.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002795
Janis Danisevskis66784c42021-01-27 08:40:25 -08002796 let grant_id = if let Some(grant_id) = tx
2797 .query_row(
2798 "SELECT id FROM persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002799 WHERE keyentryid = ? AND grantee = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08002800 params![key_id, grantee_uid],
2801 |row| row.get(0),
2802 )
2803 .optional()
2804 .context("In grant: Failed get optional existing grant id.")?
2805 {
2806 tx.execute(
2807 "UPDATE persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002808 SET access_vector = ?
2809 WHERE id = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08002810 params![i32::from(access_vector), grant_id],
Joel Galenson845f74b2020-09-09 14:11:55 -07002811 )
Janis Danisevskis66784c42021-01-27 08:40:25 -08002812 .context("In grant: Failed to update existing grant.")?;
2813 grant_id
2814 } else {
2815 Self::insert_with_retry(|id| {
2816 tx.execute(
2817 "INSERT INTO persistent.grant (id, grantee, keyentryid, access_vector)
2818 VALUES (?, ?, ?, ?);",
2819 params![id, grantee_uid, key_id, i32::from(access_vector)],
2820 )
2821 })
2822 .context("In grant")?
2823 };
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002824
Janis Danisevskis66784c42021-01-27 08:40:25 -08002825 Ok(KeyDescriptor { domain: Domain::GRANT, nspace: grant_id, alias: None, blob: None })
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002826 .no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08002827 })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002828 }
2829
2830 /// This function checks permissions like `grant` and `load_key_entry`
2831 /// before removing a grant from the grant table.
2832 pub fn ungrant(
2833 &mut self,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002834 key: &KeyDescriptor,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002835 caller_uid: u32,
2836 grantee_uid: u32,
Janis Danisevskis66784c42021-01-27 08:40:25 -08002837 check_permission: impl Fn(&KeyDescriptor) -> Result<()>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002838 ) -> Result<()> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002839 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2840 // Load the key_id and complete the access control tuple.
2841 // We ignore the access vector here because grants cannot be granted.
2842 let (key_id, access_key_descriptor, _) =
2843 Self::load_access_tuple(&tx, key, KeyType::Client, caller_uid)
2844 .context("In ungrant.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002845
Janis Danisevskis66784c42021-01-27 08:40:25 -08002846 // Perform access control. We must return here if the permission
2847 // was denied. So do not touch the '?' at the end of this line.
2848 check_permission(&access_key_descriptor)
2849 .context("In grant: check_permission failed.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002850
Janis Danisevskis66784c42021-01-27 08:40:25 -08002851 tx.execute(
2852 "DELETE FROM persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002853 WHERE keyentryid = ? AND grantee = ?;",
Janis Danisevskis66784c42021-01-27 08:40:25 -08002854 params![key_id, grantee_uid],
2855 )
2856 .context("Failed to delete grant.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002857
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002858 Ok(()).no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08002859 })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002860 }
2861
Joel Galenson845f74b2020-09-09 14:11:55 -07002862 // Generates a random id and passes it to the given function, which will
2863 // try to insert it into a database. If that insertion fails, retry;
2864 // otherwise return the id.
2865 fn insert_with_retry(inserter: impl Fn(i64) -> rusqlite::Result<usize>) -> Result<i64> {
2866 loop {
Janis Danisevskiseed69842021-02-18 20:04:10 -08002867 let newid: i64 = match random() {
2868 Self::UNASSIGNED_KEY_ID => continue, // UNASSIGNED_KEY_ID cannot be assigned.
2869 i => i,
2870 };
Joel Galenson845f74b2020-09-09 14:11:55 -07002871 match inserter(newid) {
2872 // If the id already existed, try again.
2873 Err(rusqlite::Error::SqliteFailure(
2874 libsqlite3_sys::Error {
2875 code: libsqlite3_sys::ErrorCode::ConstraintViolation,
2876 extended_code: libsqlite3_sys::SQLITE_CONSTRAINT_UNIQUE,
2877 },
2878 _,
2879 )) => (),
2880 Err(e) => {
2881 return Err(e).context("In insert_with_retry: failed to insert into database.")
2882 }
2883 _ => return Ok(newid),
2884 }
2885 }
2886 }
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002887
2888 /// Insert or replace the auth token based on the UNIQUE constraint of the auth token table
2889 pub fn insert_auth_token(&mut self, auth_token: &HardwareAuthToken) -> Result<()> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08002890 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2891 tx.execute(
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002892 "INSERT OR REPLACE INTO perboot.authtoken (challenge, user_id, auth_id,
2893 authenticator_type, timestamp, mac, time_received) VALUES(?, ?, ?, ?, ?, ?, ?);",
2894 params![
2895 auth_token.challenge,
2896 auth_token.userId,
2897 auth_token.authenticatorId,
2898 auth_token.authenticatorType.0 as i32,
2899 auth_token.timestamp.milliSeconds as i64,
2900 auth_token.mac,
2901 MonotonicRawTime::now(),
2902 ],
2903 )
2904 .context("In insert_auth_token: failed to insert auth token into the database")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002905 Ok(()).no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08002906 })
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002907 }
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002908
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002909 /// Find the newest auth token matching the given predicate.
2910 pub fn find_auth_token_entry<F>(
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002911 &mut self,
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002912 p: F,
2913 ) -> Result<Option<(AuthTokenEntry, MonotonicRawTime)>>
2914 where
2915 F: Fn(&AuthTokenEntry) -> bool,
2916 {
2917 self.with_transaction(TransactionBehavior::Deferred, |tx| {
2918 let mut stmt = tx
2919 .prepare("SELECT * from perboot.authtoken ORDER BY time_received DESC;")
2920 .context("Prepare statement failed.")?;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002921
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002922 let mut rows = stmt.query(NO_PARAMS).context("Failed to query.")?;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002923
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002924 while let Some(row) = rows.next().context("Failed to get next row.")? {
2925 let entry = AuthTokenEntry::new(
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002926 HardwareAuthToken {
2927 challenge: row.get(1)?,
2928 userId: row.get(2)?,
2929 authenticatorId: row.get(3)?,
2930 authenticatorType: HardwareAuthenticatorType(row.get(4)?),
2931 timestamp: Timestamp { milliSeconds: row.get(5)? },
2932 mac: row.get(6)?,
2933 },
2934 row.get(7)?,
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002935 );
2936 if p(&entry) {
2937 return Ok(Some((
2938 entry,
2939 Self::get_last_off_body(tx)
2940 .context("In find_auth_token_entry: Trying to get last off body")?,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002941 )))
2942 .no_gc();
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002943 }
2944 }
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002945 Ok(None).no_gc()
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002946 })
2947 .context("In find_auth_token_entry.")
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002948 }
2949
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002950 /// Insert last_off_body into the metadata table at the initialization of auth token table
Janis Danisevskis66784c42021-01-27 08:40:25 -08002951 pub fn insert_last_off_body(&mut self, last_off_body: MonotonicRawTime) -> Result<()> {
2952 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2953 tx.execute(
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002954 "INSERT OR REPLACE INTO perboot.metadata (key, value) VALUES (?, ?);",
2955 params!["last_off_body", last_off_body],
2956 )
2957 .context("In insert_last_off_body: failed to insert.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002958 Ok(()).no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08002959 })
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002960 }
2961
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002962 /// Update last_off_body when on_device_off_body is called
Janis Danisevskis66784c42021-01-27 08:40:25 -08002963 pub fn update_last_off_body(&mut self, last_off_body: MonotonicRawTime) -> Result<()> {
2964 self.with_transaction(TransactionBehavior::Immediate, |tx| {
2965 tx.execute(
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002966 "UPDATE perboot.metadata SET value = ? WHERE key = ?;",
2967 params![last_off_body, "last_off_body"],
2968 )
2969 .context("In update_last_off_body: failed to update.")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08002970 Ok(()).no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08002971 })
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002972 }
2973
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002974 /// Get last_off_body time when finding auth tokens
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002975 fn get_last_off_body(tx: &Transaction) -> Result<MonotonicRawTime> {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08002976 tx.query_row(
2977 "SELECT value from perboot.metadata WHERE key = ?;",
2978 params!["last_off_body"],
2979 |row| Ok(row.get(0)?),
2980 )
2981 .context("In get_last_off_body: query_row failed.")
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00002982 }
Joel Galenson26f4d012020-07-17 14:57:21 -07002983}
2984
2985#[cfg(test)]
2986mod tests {
2987
2988 use super::*;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002989 use crate::key_parameter::{
2990 Algorithm, BlockMode, Digest, EcCurve, HardwareAuthenticatorType, KeyOrigin, KeyParameter,
2991 KeyParameterValue, KeyPurpose, PaddingMode, SecurityLevel,
2992 };
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002993 use crate::key_perm_set;
2994 use crate::permission::{KeyPerm, KeyPermSet};
Hasini Gunasingheda895552021-01-27 19:34:37 +00002995 use crate::super_key::SuperKeyManager;
Janis Danisevskis2a8330a2021-01-20 15:34:26 -08002996 use keystore2_test_utils::TempDir;
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00002997 use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
2998 HardwareAuthToken::HardwareAuthToken,
2999 HardwareAuthenticatorType::HardwareAuthenticatorType as kmhw_authenticator_type,
Janis Danisevskisc3a496b2021-01-05 10:37:22 -08003000 };
3001 use android_hardware_security_secureclock::aidl::android::hardware::security::secureclock::{
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00003002 Timestamp::Timestamp,
3003 };
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003004 use rusqlite::NO_PARAMS;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00003005 use rusqlite::{Error, TransactionBehavior};
Joel Galenson0891bc12020-07-20 10:37:03 -07003006 use std::cell::RefCell;
Janis Danisevskisaec14592020-11-12 09:41:49 -08003007 use std::sync::atomic::{AtomicU8, Ordering};
3008 use std::sync::Arc;
3009 use std::thread;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00003010 use std::time::{Duration, SystemTime};
Janis Danisevskis66784c42021-01-27 08:40:25 -08003011 #[cfg(disabled)]
3012 use std::time::Instant;
Joel Galenson0891bc12020-07-20 10:37:03 -07003013
Janis Danisevskis4df44f42020-08-26 14:40:03 -07003014 fn new_test_db() -> Result<KeystoreDB> {
3015 let conn = KeystoreDB::make_connection("file::memory:", "file::memory:")?;
3016
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003017 let mut db = KeystoreDB { conn, gc: None };
Janis Danisevskis66784c42021-01-27 08:40:25 -08003018 db.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003019 KeystoreDB::init_tables(tx).context("Failed to initialize tables.").no_gc()
Janis Danisevskis66784c42021-01-27 08:40:25 -08003020 })?;
3021 Ok(db)
Janis Danisevskis4df44f42020-08-26 14:40:03 -07003022 }
3023
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003024 fn new_test_db_with_gc<F>(path: &Path, cb: F) -> Result<KeystoreDB>
3025 where
3026 F: Fn(&Uuid, &[u8]) -> Result<()> + Send + 'static,
3027 {
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00003028 let super_key = Arc::new(SuperKeyManager::new());
3029
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003030 let gc_db = KeystoreDB::new(path, None).expect("Failed to open test gc db_connection.");
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00003031 let gc = Gc::new_init_with(Default::default(), move || (Box::new(cb), gc_db, super_key));
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003032
3033 KeystoreDB::new(path, Some(gc))
3034 }
3035
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003036 fn rebind_alias(
3037 db: &mut KeystoreDB,
3038 newid: &KeyIdGuard,
3039 alias: &str,
3040 domain: Domain,
3041 namespace: i64,
3042 ) -> Result<bool> {
3043 db.with_transaction(TransactionBehavior::Immediate, |tx| {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003044 KeystoreDB::rebind_alias(tx, newid, alias, &domain, &namespace).no_gc()
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003045 })
3046 .context("In rebind_alias.")
3047 }
3048
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003049 #[test]
3050 fn datetime() -> Result<()> {
3051 let conn = Connection::open_in_memory()?;
3052 conn.execute("CREATE TABLE test (ts DATETIME);", NO_PARAMS)?;
3053 let now = SystemTime::now();
3054 let duration = Duration::from_secs(1000);
3055 let then = now.checked_sub(duration).unwrap();
3056 let soon = now.checked_add(duration).unwrap();
3057 conn.execute(
3058 "INSERT INTO test (ts) VALUES (?), (?), (?);",
3059 params![DateTime::try_from(now)?, DateTime::try_from(then)?, DateTime::try_from(soon)?],
3060 )?;
3061 let mut stmt = conn.prepare("SELECT ts FROM test ORDER BY ts ASC;")?;
3062 let mut rows = stmt.query(NO_PARAMS)?;
3063 assert_eq!(DateTime::try_from(then)?, rows.next()?.unwrap().get(0)?);
3064 assert_eq!(DateTime::try_from(now)?, rows.next()?.unwrap().get(0)?);
3065 assert_eq!(DateTime::try_from(soon)?, rows.next()?.unwrap().get(0)?);
3066 assert!(rows.next()?.is_none());
3067 assert!(DateTime::try_from(then)? < DateTime::try_from(now)?);
3068 assert!(DateTime::try_from(then)? < DateTime::try_from(soon)?);
3069 assert!(DateTime::try_from(now)? < DateTime::try_from(soon)?);
3070 Ok(())
3071 }
3072
Joel Galenson0891bc12020-07-20 10:37:03 -07003073 // Ensure that we're using the "injected" random function, not the real one.
3074 #[test]
3075 fn test_mocked_random() {
3076 let rand1 = random();
3077 let rand2 = random();
3078 let rand3 = random();
3079 if rand1 == rand2 {
3080 assert_eq!(rand2 + 1, rand3);
3081 } else {
3082 assert_eq!(rand1 + 1, rand2);
3083 assert_eq!(rand2, rand3);
3084 }
3085 }
Joel Galenson26f4d012020-07-17 14:57:21 -07003086
Joel Galenson26f4d012020-07-17 14:57:21 -07003087 // Test that we have the correct tables.
3088 #[test]
3089 fn test_tables() -> Result<()> {
Janis Danisevskis4df44f42020-08-26 14:40:03 -07003090 let db = new_test_db()?;
Joel Galenson26f4d012020-07-17 14:57:21 -07003091 let tables = db
3092 .conn
Joel Galenson2aab4432020-07-22 15:27:57 -07003093 .prepare("SELECT name from persistent.sqlite_master WHERE type='table' ORDER BY name;")?
Joel Galenson26f4d012020-07-17 14:57:21 -07003094 .query_map(params![], |row| row.get(0))?
3095 .collect::<rusqlite::Result<Vec<String>>>()?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003096 assert_eq!(tables.len(), 6);
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003097 assert_eq!(tables[0], "blobentry");
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003098 assert_eq!(tables[1], "blobmetadata");
3099 assert_eq!(tables[2], "grant");
3100 assert_eq!(tables[3], "keyentry");
3101 assert_eq!(tables[4], "keymetadata");
3102 assert_eq!(tables[5], "keyparameter");
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003103 let tables = db
3104 .conn
3105 .prepare("SELECT name from perboot.sqlite_master WHERE type='table' ORDER BY name;")?
3106 .query_map(params![], |row| row.get(0))?
3107 .collect::<rusqlite::Result<Vec<String>>>()?;
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00003108
3109 assert_eq!(tables.len(), 2);
3110 assert_eq!(tables[0], "authtoken");
3111 assert_eq!(tables[1], "metadata");
Joel Galenson2aab4432020-07-22 15:27:57 -07003112 Ok(())
3113 }
3114
3115 #[test]
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00003116 fn test_auth_token_table_invariant() -> Result<()> {
3117 let mut db = new_test_db()?;
3118 let auth_token1 = HardwareAuthToken {
3119 challenge: i64::MAX,
3120 userId: 200,
3121 authenticatorId: 200,
3122 authenticatorType: kmhw_authenticator_type(kmhw_authenticator_type::PASSWORD.0),
3123 timestamp: Timestamp { milliSeconds: 500 },
3124 mac: String::from("mac").into_bytes(),
3125 };
3126 db.insert_auth_token(&auth_token1)?;
3127 let auth_tokens_returned = get_auth_tokens(&mut db)?;
3128 assert_eq!(auth_tokens_returned.len(), 1);
3129
3130 // insert another auth token with the same values for the columns in the UNIQUE constraint
3131 // of the auth token table and different value for timestamp
3132 let auth_token2 = HardwareAuthToken {
3133 challenge: i64::MAX,
3134 userId: 200,
3135 authenticatorId: 200,
3136 authenticatorType: kmhw_authenticator_type(kmhw_authenticator_type::PASSWORD.0),
3137 timestamp: Timestamp { milliSeconds: 600 },
3138 mac: String::from("mac").into_bytes(),
3139 };
3140
3141 db.insert_auth_token(&auth_token2)?;
3142 let mut auth_tokens_returned = get_auth_tokens(&mut db)?;
3143 assert_eq!(auth_tokens_returned.len(), 1);
3144
3145 if let Some(auth_token) = auth_tokens_returned.pop() {
3146 assert_eq!(auth_token.auth_token.timestamp.milliSeconds, 600);
3147 }
3148
3149 // insert another auth token with the different values for the columns in the UNIQUE
3150 // constraint of the auth token table
3151 let auth_token3 = HardwareAuthToken {
3152 challenge: i64::MAX,
3153 userId: 201,
3154 authenticatorId: 200,
3155 authenticatorType: kmhw_authenticator_type(kmhw_authenticator_type::PASSWORD.0),
3156 timestamp: Timestamp { milliSeconds: 600 },
3157 mac: String::from("mac").into_bytes(),
3158 };
3159
3160 db.insert_auth_token(&auth_token3)?;
3161 let auth_tokens_returned = get_auth_tokens(&mut db)?;
3162 assert_eq!(auth_tokens_returned.len(), 2);
3163
3164 Ok(())
3165 }
3166
3167 // utility function for test_auth_token_table_invariant()
3168 fn get_auth_tokens(db: &mut KeystoreDB) -> Result<Vec<AuthTokenEntry>> {
3169 let mut stmt = db.conn.prepare("SELECT * from perboot.authtoken;")?;
3170
3171 let auth_token_entries: Vec<AuthTokenEntry> = stmt
3172 .query_map(NO_PARAMS, |row| {
3173 Ok(AuthTokenEntry::new(
3174 HardwareAuthToken {
3175 challenge: row.get(1)?,
3176 userId: row.get(2)?,
3177 authenticatorId: row.get(3)?,
3178 authenticatorType: HardwareAuthenticatorType(row.get(4)?),
3179 timestamp: Timestamp { milliSeconds: row.get(5)? },
3180 mac: row.get(6)?,
3181 },
3182 row.get(7)?,
3183 ))
3184 })?
3185 .collect::<Result<Vec<AuthTokenEntry>, Error>>()?;
3186 Ok(auth_token_entries)
3187 }
3188
3189 #[test]
Joel Galenson2aab4432020-07-22 15:27:57 -07003190 fn test_persistence_for_files() -> Result<()> {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08003191 let temp_dir = TempDir::new("persistent_db_test")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003192 let mut db = KeystoreDB::new(temp_dir.path(), None)?;
Joel Galenson2aab4432020-07-22 15:27:57 -07003193
Janis Danisevskis66784c42021-01-27 08:40:25 -08003194 db.create_key_entry(&Domain::APP, &100, &KEYSTORE_UUID)?;
Joel Galenson2aab4432020-07-22 15:27:57 -07003195 let entries = get_keyentry(&db)?;
3196 assert_eq!(entries.len(), 1);
Janis Danisevskisbf15d732020-12-08 10:35:26 -08003197
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003198 let db = KeystoreDB::new(temp_dir.path(), None)?;
Joel Galenson2aab4432020-07-22 15:27:57 -07003199
3200 let entries_new = get_keyentry(&db)?;
3201 assert_eq!(entries, entries_new);
3202 Ok(())
3203 }
3204
3205 #[test]
Joel Galenson0891bc12020-07-20 10:37:03 -07003206 fn test_create_key_entry() -> Result<()> {
Max Bires8e93d2b2021-01-14 13:17:59 -08003207 fn extractor(ke: &KeyEntryRow) -> (Domain, i64, Option<&str>, Uuid) {
3208 (ke.domain.unwrap(), ke.namespace.unwrap(), ke.alias.as_deref(), ke.km_uuid.unwrap())
Joel Galenson0891bc12020-07-20 10:37:03 -07003209 }
3210
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003211 let mut db = new_test_db()?;
Joel Galenson0891bc12020-07-20 10:37:03 -07003212
Janis Danisevskis66784c42021-01-27 08:40:25 -08003213 db.create_key_entry(&Domain::APP, &100, &KEYSTORE_UUID)?;
3214 db.create_key_entry(&Domain::SELINUX, &101, &KEYSTORE_UUID)?;
Joel Galenson0891bc12020-07-20 10:37:03 -07003215
3216 let entries = get_keyentry(&db)?;
3217 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08003218 assert_eq!(extractor(&entries[0]), (Domain::APP, 100, None, KEYSTORE_UUID));
3219 assert_eq!(extractor(&entries[1]), (Domain::SELINUX, 101, None, KEYSTORE_UUID));
Joel Galenson0891bc12020-07-20 10:37:03 -07003220
3221 // Test that we must pass in a valid Domain.
3222 check_result_is_error_containing_string(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003223 db.create_key_entry(&Domain::GRANT, &102, &KEYSTORE_UUID),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003224 "Domain Domain(1) must be either App or SELinux.",
Joel Galenson0891bc12020-07-20 10:37:03 -07003225 );
3226 check_result_is_error_containing_string(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003227 db.create_key_entry(&Domain::BLOB, &103, &KEYSTORE_UUID),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003228 "Domain Domain(3) must be either App or SELinux.",
Joel Galenson0891bc12020-07-20 10:37:03 -07003229 );
3230 check_result_is_error_containing_string(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003231 db.create_key_entry(&Domain::KEY_ID, &104, &KEYSTORE_UUID),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003232 "Domain Domain(4) must be either App or SELinux.",
Joel Galenson0891bc12020-07-20 10:37:03 -07003233 );
3234
3235 Ok(())
3236 }
3237
Joel Galenson33c04ad2020-08-03 11:04:38 -07003238 #[test]
Max Bires2b2e6562020-09-22 11:22:36 -07003239 fn test_add_unsigned_key() -> Result<()> {
3240 let mut db = new_test_db()?;
3241 let public_key: Vec<u8> = vec![0x01, 0x02, 0x03];
3242 let private_key: Vec<u8> = vec![0x04, 0x05, 0x06];
3243 let raw_public_key: Vec<u8> = vec![0x07, 0x08, 0x09];
3244 db.create_attestation_key_entry(
3245 &public_key,
3246 &raw_public_key,
3247 &private_key,
3248 &KEYSTORE_UUID,
3249 )?;
3250 let keys = db.fetch_unsigned_attestation_keys(5, &KEYSTORE_UUID)?;
3251 assert_eq!(keys.len(), 1);
3252 assert_eq!(keys[0], public_key);
3253 Ok(())
3254 }
3255
3256 #[test]
3257 fn test_store_signed_attestation_certificate_chain() -> Result<()> {
3258 let mut db = new_test_db()?;
3259 let expiration_date: i64 = 20;
3260 let namespace: i64 = 30;
3261 let base_byte: u8 = 1;
3262 let loaded_values =
3263 load_attestation_key_pool(&mut db, expiration_date, namespace, base_byte)?;
3264 let chain =
3265 db.retrieve_attestation_key_and_cert_chain(Domain::APP, namespace, &KEYSTORE_UUID)?;
3266 assert_eq!(true, chain.is_some());
3267 let cert_chain = chain.unwrap();
Max Biresb2e1d032021-02-08 21:35:05 -08003268 assert_eq!(cert_chain.private_key.to_vec(), loaded_values.priv_key);
Max Bires97f96812021-02-23 23:44:57 -08003269 assert_eq!(cert_chain.batch_cert, loaded_values.batch_cert);
3270 assert_eq!(cert_chain.cert_chain, loaded_values.cert_chain);
Max Bires2b2e6562020-09-22 11:22:36 -07003271 Ok(())
3272 }
3273
3274 #[test]
3275 fn test_get_attestation_pool_status() -> Result<()> {
3276 let mut db = new_test_db()?;
3277 let namespace: i64 = 30;
3278 load_attestation_key_pool(
3279 &mut db, 10, /* expiration */
3280 namespace, 0x01, /* base_byte */
3281 )?;
3282 load_attestation_key_pool(&mut db, 20 /* expiration */, namespace + 1, 0x02)?;
3283 load_attestation_key_pool(&mut db, 40 /* expiration */, namespace + 2, 0x03)?;
3284 let mut status = db.get_attestation_pool_status(9 /* expiration */, &KEYSTORE_UUID)?;
3285 assert_eq!(status.expiring, 0);
3286 assert_eq!(status.attested, 3);
3287 assert_eq!(status.unassigned, 0);
3288 assert_eq!(status.total, 3);
3289 assert_eq!(
3290 db.get_attestation_pool_status(15 /* expiration */, &KEYSTORE_UUID)?.expiring,
3291 1
3292 );
3293 assert_eq!(
3294 db.get_attestation_pool_status(25 /* expiration */, &KEYSTORE_UUID)?.expiring,
3295 2
3296 );
3297 assert_eq!(
3298 db.get_attestation_pool_status(60 /* expiration */, &KEYSTORE_UUID)?.expiring,
3299 3
3300 );
3301 let public_key: Vec<u8> = vec![0x01, 0x02, 0x03];
3302 let private_key: Vec<u8> = vec![0x04, 0x05, 0x06];
3303 let raw_public_key: Vec<u8> = vec![0x07, 0x08, 0x09];
3304 let cert_chain: Vec<u8> = vec![0x0a, 0x0b, 0x0c];
Max Biresb2e1d032021-02-08 21:35:05 -08003305 let batch_cert: Vec<u8> = vec![0x0d, 0x0e, 0x0f];
Max Bires2b2e6562020-09-22 11:22:36 -07003306 db.create_attestation_key_entry(
3307 &public_key,
3308 &raw_public_key,
3309 &private_key,
3310 &KEYSTORE_UUID,
3311 )?;
3312 status = db.get_attestation_pool_status(0 /* expiration */, &KEYSTORE_UUID)?;
3313 assert_eq!(status.attested, 3);
3314 assert_eq!(status.unassigned, 0);
3315 assert_eq!(status.total, 4);
3316 db.store_signed_attestation_certificate_chain(
3317 &raw_public_key,
Max Biresb2e1d032021-02-08 21:35:05 -08003318 &batch_cert,
Max Bires2b2e6562020-09-22 11:22:36 -07003319 &cert_chain,
3320 20,
3321 &KEYSTORE_UUID,
3322 )?;
3323 status = db.get_attestation_pool_status(0 /* expiration */, &KEYSTORE_UUID)?;
3324 assert_eq!(status.attested, 4);
3325 assert_eq!(status.unassigned, 1);
3326 assert_eq!(status.total, 4);
3327 Ok(())
3328 }
3329
3330 #[test]
3331 fn test_remove_expired_certs() -> Result<()> {
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003332 let temp_dir =
3333 TempDir::new("test_remove_expired_certs_").expect("Failed to create temp dir.");
3334 let mut db = new_test_db_with_gc(temp_dir.path(), |_, _| Ok(()))?;
Max Bires2b2e6562020-09-22 11:22:36 -07003335 let expiration_date: i64 =
3336 SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_millis() as i64 + 10000;
3337 let namespace: i64 = 30;
3338 let namespace_del1: i64 = 45;
3339 let namespace_del2: i64 = 60;
3340 let entry_values = load_attestation_key_pool(
3341 &mut db,
3342 expiration_date,
3343 namespace,
3344 0x01, /* base_byte */
3345 )?;
3346 load_attestation_key_pool(&mut db, 45, namespace_del1, 0x02)?;
3347 load_attestation_key_pool(&mut db, 60, namespace_del2, 0x03)?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003348
3349 let blob_entry_row_count: u32 = db
3350 .conn
3351 .query_row("SELECT COUNT(id) FROM persistent.blobentry;", NO_PARAMS, |row| row.get(0))
3352 .expect("Failed to get blob entry row count.");
Max Biresb2e1d032021-02-08 21:35:05 -08003353 // We expect 9 rows here because there are three blobs per attestation key, i.e.,
3354 // one key, one certificate chain, and one certificate.
3355 assert_eq!(blob_entry_row_count, 9);
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003356
Max Bires2b2e6562020-09-22 11:22:36 -07003357 assert_eq!(db.delete_expired_attestation_keys()?, 2);
3358
3359 let mut cert_chain =
3360 db.retrieve_attestation_key_and_cert_chain(Domain::APP, namespace, &KEYSTORE_UUID)?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003361 assert!(cert_chain.is_some());
Max Bires2b2e6562020-09-22 11:22:36 -07003362 let value = cert_chain.unwrap();
Max Bires97f96812021-02-23 23:44:57 -08003363 assert_eq!(entry_values.batch_cert, value.batch_cert);
3364 assert_eq!(entry_values.cert_chain, value.cert_chain);
Max Biresb2e1d032021-02-08 21:35:05 -08003365 assert_eq!(entry_values.priv_key, value.private_key.to_vec());
Max Bires2b2e6562020-09-22 11:22:36 -07003366
3367 cert_chain = db.retrieve_attestation_key_and_cert_chain(
3368 Domain::APP,
3369 namespace_del1,
3370 &KEYSTORE_UUID,
3371 )?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003372 assert!(!cert_chain.is_some());
Max Bires2b2e6562020-09-22 11:22:36 -07003373 cert_chain = db.retrieve_attestation_key_and_cert_chain(
3374 Domain::APP,
3375 namespace_del2,
3376 &KEYSTORE_UUID,
3377 )?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003378 assert!(!cert_chain.is_some());
Max Bires2b2e6562020-09-22 11:22:36 -07003379
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003380 // Give the garbage collector half a second to catch up.
3381 std::thread::sleep(Duration::from_millis(500));
Max Bires2b2e6562020-09-22 11:22:36 -07003382
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003383 let blob_entry_row_count: u32 = db
3384 .conn
3385 .query_row("SELECT COUNT(id) FROM persistent.blobentry;", NO_PARAMS, |row| row.get(0))
3386 .expect("Failed to get blob entry row count.");
Max Biresb2e1d032021-02-08 21:35:05 -08003387 // There shound be 3 blob entries left, because we deleted two of the attestation
3388 // key entries with three blobs each.
3389 assert_eq!(blob_entry_row_count, 3);
Max Bires2b2e6562020-09-22 11:22:36 -07003390
Max Bires2b2e6562020-09-22 11:22:36 -07003391 Ok(())
3392 }
3393
3394 #[test]
Max Bires60d7ed12021-03-05 15:59:22 -08003395 fn test_delete_all_attestation_keys() -> Result<()> {
3396 let mut db = new_test_db()?;
3397 load_attestation_key_pool(&mut db, 45 /* expiration */, 1 /* namespace */, 0x02)?;
3398 load_attestation_key_pool(&mut db, 80 /* expiration */, 2 /* namespace */, 0x03)?;
3399 db.create_key_entry(&Domain::APP, &42, &KEYSTORE_UUID)?;
3400 let result = db.delete_all_attestation_keys()?;
3401
3402 // Give the garbage collector half a second to catch up.
3403 std::thread::sleep(Duration::from_millis(500));
3404
3405 // Attestation keys should be deleted, and the regular key should remain.
3406 assert_eq!(result, 2);
3407
3408 Ok(())
3409 }
3410
3411 #[test]
Joel Galenson33c04ad2020-08-03 11:04:38 -07003412 fn test_rebind_alias() -> Result<()> {
Max Bires8e93d2b2021-01-14 13:17:59 -08003413 fn extractor(
3414 ke: &KeyEntryRow,
3415 ) -> (Option<Domain>, Option<i64>, Option<&str>, Option<Uuid>) {
3416 (ke.domain, ke.namespace, ke.alias.as_deref(), ke.km_uuid)
Joel Galenson33c04ad2020-08-03 11:04:38 -07003417 }
3418
Janis Danisevskis4df44f42020-08-26 14:40:03 -07003419 let mut db = new_test_db()?;
Janis Danisevskis66784c42021-01-27 08:40:25 -08003420 db.create_key_entry(&Domain::APP, &42, &KEYSTORE_UUID)?;
3421 db.create_key_entry(&Domain::APP, &42, &KEYSTORE_UUID)?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07003422 let entries = get_keyentry(&db)?;
3423 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08003424 assert_eq!(
3425 extractor(&entries[0]),
3426 (Some(Domain::APP), Some(42), None, Some(KEYSTORE_UUID))
3427 );
3428 assert_eq!(
3429 extractor(&entries[1]),
3430 (Some(Domain::APP), Some(42), None, Some(KEYSTORE_UUID))
3431 );
Joel Galenson33c04ad2020-08-03 11:04:38 -07003432
3433 // Test that the first call to rebind_alias sets the alias.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003434 rebind_alias(&mut db, &KEY_ID_LOCK.get(entries[0].id), "foo", Domain::APP, 42)?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07003435 let entries = get_keyentry(&db)?;
3436 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08003437 assert_eq!(
3438 extractor(&entries[0]),
3439 (Some(Domain::APP), Some(42), Some("foo"), Some(KEYSTORE_UUID))
3440 );
3441 assert_eq!(
3442 extractor(&entries[1]),
3443 (Some(Domain::APP), Some(42), None, Some(KEYSTORE_UUID))
3444 );
Joel Galenson33c04ad2020-08-03 11:04:38 -07003445
3446 // Test that the second call to rebind_alias also empties the old one.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003447 rebind_alias(&mut db, &KEY_ID_LOCK.get(entries[1].id), "foo", Domain::APP, 42)?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07003448 let entries = get_keyentry(&db)?;
3449 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08003450 assert_eq!(extractor(&entries[0]), (None, None, None, Some(KEYSTORE_UUID)));
3451 assert_eq!(
3452 extractor(&entries[1]),
3453 (Some(Domain::APP), Some(42), Some("foo"), Some(KEYSTORE_UUID))
3454 );
Joel Galenson33c04ad2020-08-03 11:04:38 -07003455
3456 // Test that we must pass in a valid Domain.
3457 check_result_is_error_containing_string(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003458 rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::GRANT, 42),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003459 "Domain Domain(1) must be either App or SELinux.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07003460 );
3461 check_result_is_error_containing_string(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003462 rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::BLOB, 42),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003463 "Domain Domain(3) must be either App or SELinux.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07003464 );
3465 check_result_is_error_containing_string(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003466 rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::KEY_ID, 42),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003467 "Domain Domain(4) must be either App or SELinux.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07003468 );
3469
3470 // Test that we correctly handle setting an alias for something that does not exist.
3471 check_result_is_error_containing_string(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003472 rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::SELINUX, 42),
Joel Galenson33c04ad2020-08-03 11:04:38 -07003473 "Expected to update a single entry but instead updated 0",
3474 );
3475 // Test that we correctly abort the transaction in this case.
3476 let entries = get_keyentry(&db)?;
3477 assert_eq!(entries.len(), 2);
Max Bires8e93d2b2021-01-14 13:17:59 -08003478 assert_eq!(extractor(&entries[0]), (None, None, None, Some(KEYSTORE_UUID)));
3479 assert_eq!(
3480 extractor(&entries[1]),
3481 (Some(Domain::APP), Some(42), Some("foo"), Some(KEYSTORE_UUID))
3482 );
Joel Galenson33c04ad2020-08-03 11:04:38 -07003483
3484 Ok(())
3485 }
3486
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003487 #[test]
3488 fn test_grant_ungrant() -> Result<()> {
3489 const CALLER_UID: u32 = 15;
3490 const GRANTEE_UID: u32 = 12;
3491 const SELINUX_NAMESPACE: i64 = 7;
3492
3493 let mut db = new_test_db()?;
3494 db.conn.execute(
Max Bires8e93d2b2021-01-14 13:17:59 -08003495 "INSERT INTO persistent.keyentry (id, key_type, domain, namespace, alias, state, km_uuid)
3496 VALUES (1, 0, 0, 15, 'key', 1, ?), (2, 0, 2, 7, 'yek', 1, ?);",
3497 params![KEYSTORE_UUID, KEYSTORE_UUID],
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003498 )?;
3499 let app_key = KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003500 domain: super::Domain::APP,
3501 nspace: 0,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003502 alias: Some("key".to_string()),
3503 blob: None,
3504 };
3505 const PVEC1: KeyPermSet = key_perm_set![KeyPerm::use_(), KeyPerm::get_info()];
3506 const PVEC2: KeyPermSet = key_perm_set![KeyPerm::use_()];
3507
3508 // Reset totally predictable random number generator in case we
3509 // are not the first test running on this thread.
3510 reset_random();
3511 let next_random = 0i64;
3512
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003513 let app_granted_key = db
Janis Danisevskis66784c42021-01-27 08:40:25 -08003514 .grant(&app_key, CALLER_UID, GRANTEE_UID, PVEC1, |k, a| {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003515 assert_eq!(*a, PVEC1);
3516 assert_eq!(
3517 *k,
3518 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003519 domain: super::Domain::APP,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003520 // namespace must be set to the caller_uid.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003521 nspace: CALLER_UID as i64,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003522 alias: Some("key".to_string()),
3523 blob: None,
3524 }
3525 );
3526 Ok(())
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003527 })
3528 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003529
3530 assert_eq!(
3531 app_granted_key,
3532 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003533 domain: super::Domain::GRANT,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003534 // The grantid is next_random due to the mock random number generator.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003535 nspace: next_random,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003536 alias: None,
3537 blob: None,
3538 }
3539 );
3540
3541 let selinux_key = KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003542 domain: super::Domain::SELINUX,
3543 nspace: SELINUX_NAMESPACE,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003544 alias: Some("yek".to_string()),
3545 blob: None,
3546 };
3547
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003548 let selinux_granted_key = db
Janis Danisevskis66784c42021-01-27 08:40:25 -08003549 .grant(&selinux_key, CALLER_UID, 12, PVEC1, |k, a| {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003550 assert_eq!(*a, PVEC1);
3551 assert_eq!(
3552 *k,
3553 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003554 domain: super::Domain::SELINUX,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003555 // namespace must be the supplied SELinux
3556 // namespace.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003557 nspace: SELINUX_NAMESPACE,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003558 alias: Some("yek".to_string()),
3559 blob: None,
3560 }
3561 );
3562 Ok(())
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003563 })
3564 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003565
3566 assert_eq!(
3567 selinux_granted_key,
3568 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003569 domain: super::Domain::GRANT,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003570 // The grantid is next_random + 1 due to the mock random number generator.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003571 nspace: next_random + 1,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003572 alias: None,
3573 blob: None,
3574 }
3575 );
3576
3577 // This should update the existing grant with PVEC2.
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003578 let selinux_granted_key = db
Janis Danisevskis66784c42021-01-27 08:40:25 -08003579 .grant(&selinux_key, CALLER_UID, 12, PVEC2, |k, a| {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003580 assert_eq!(*a, PVEC2);
3581 assert_eq!(
3582 *k,
3583 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003584 domain: super::Domain::SELINUX,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003585 // namespace must be the supplied SELinux
3586 // namespace.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003587 nspace: SELINUX_NAMESPACE,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003588 alias: Some("yek".to_string()),
3589 blob: None,
3590 }
3591 );
3592 Ok(())
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003593 })
3594 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003595
3596 assert_eq!(
3597 selinux_granted_key,
3598 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003599 domain: super::Domain::GRANT,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003600 // Same grant id as before. The entry was only updated.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003601 nspace: next_random + 1,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003602 alias: None,
3603 blob: None,
3604 }
3605 );
3606
3607 {
3608 // Limiting scope of stmt, because it borrows db.
3609 let mut stmt = db
3610 .conn
Janis Danisevskisbf15d732020-12-08 10:35:26 -08003611 .prepare("SELECT id, grantee, keyentryid, access_vector FROM persistent.grant;")?;
Janis Danisevskisee10b5f2020-09-22 16:42:35 -07003612 let mut rows =
3613 stmt.query_map::<(i64, u32, i64, KeyPermSet), _, _>(NO_PARAMS, |row| {
3614 Ok((
3615 row.get(0)?,
3616 row.get(1)?,
3617 row.get(2)?,
3618 KeyPermSet::from(row.get::<_, i32>(3)?),
3619 ))
3620 })?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003621
3622 let r = rows.next().unwrap().unwrap();
Janis Danisevskisee10b5f2020-09-22 16:42:35 -07003623 assert_eq!(r, (next_random, GRANTEE_UID, 1, PVEC1));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003624 let r = rows.next().unwrap().unwrap();
Janis Danisevskisee10b5f2020-09-22 16:42:35 -07003625 assert_eq!(r, (next_random + 1, GRANTEE_UID, 2, PVEC2));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003626 assert!(rows.next().is_none());
3627 }
3628
3629 debug_dump_keyentry_table(&mut db)?;
3630 println!("app_key {:?}", app_key);
3631 println!("selinux_key {:?}", selinux_key);
3632
Janis Danisevskis66784c42021-01-27 08:40:25 -08003633 db.ungrant(&app_key, CALLER_UID, GRANTEE_UID, |_| Ok(()))?;
3634 db.ungrant(&selinux_key, CALLER_UID, GRANTEE_UID, |_| Ok(()))?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003635
3636 Ok(())
3637 }
3638
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003639 static TEST_KEY_BLOB: &[u8] = b"my test blob";
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003640 static TEST_CERT_BLOB: &[u8] = b"my test cert";
3641 static TEST_CERT_CHAIN_BLOB: &[u8] = b"my test cert_chain";
3642
3643 #[test]
Janis Danisevskis377d1002021-01-27 19:07:48 -08003644 fn test_set_blob() -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003645 let key_id = KEY_ID_LOCK.get(3000);
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003646 let mut db = new_test_db()?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003647 let mut blob_metadata = BlobMetaData::new();
3648 blob_metadata.add(BlobMetaEntry::KmUuid(KEYSTORE_UUID));
3649 db.set_blob(
3650 &key_id,
3651 SubComponentType::KEY_BLOB,
3652 Some(TEST_KEY_BLOB),
3653 Some(&blob_metadata),
3654 )?;
3655 db.set_blob(&key_id, SubComponentType::CERT, Some(TEST_CERT_BLOB), None)?;
3656 db.set_blob(&key_id, SubComponentType::CERT_CHAIN, Some(TEST_CERT_CHAIN_BLOB), None)?;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003657 drop(key_id);
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003658
3659 let mut stmt = db.conn.prepare(
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003660 "SELECT subcomponent_type, keyentryid, blob, id FROM persistent.blobentry
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003661 ORDER BY subcomponent_type ASC;",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003662 )?;
3663 let mut rows = stmt
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003664 .query_map::<((SubComponentType, i64, Vec<u8>), i64), _, _>(NO_PARAMS, |row| {
3665 Ok(((row.get(0)?, row.get(1)?, row.get(2)?), row.get(3)?))
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003666 })?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003667 let (r, id) = rows.next().unwrap().unwrap();
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003668 assert_eq!(r, (SubComponentType::KEY_BLOB, 3000, TEST_KEY_BLOB.to_vec()));
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003669 let (r, _) = rows.next().unwrap().unwrap();
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003670 assert_eq!(r, (SubComponentType::CERT, 3000, TEST_CERT_BLOB.to_vec()));
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003671 let (r, _) = rows.next().unwrap().unwrap();
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003672 assert_eq!(r, (SubComponentType::CERT_CHAIN, 3000, TEST_CERT_CHAIN_BLOB.to_vec()));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003673
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08003674 drop(rows);
3675 drop(stmt);
3676
3677 assert_eq!(
3678 db.with_transaction(TransactionBehavior::Immediate, |tx| {
3679 BlobMetaData::load_from_db(id, tx).no_gc()
3680 })
3681 .expect("Should find blob metadata."),
3682 blob_metadata
3683 );
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003684 Ok(())
3685 }
3686
3687 static TEST_ALIAS: &str = "my super duper key";
3688
3689 #[test]
3690 fn test_insert_and_load_full_keyentry_domain_app() -> Result<()> {
3691 let mut db = new_test_db()?;
Qi Wub9433b52020-12-01 14:52:46 +08003692 let key_id = make_test_key_entry(&mut db, Domain::APP, 1, TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08003693 .context("test_insert_and_load_full_keyentry_domain_app")?
3694 .0;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003695 let (_key_guard, key_entry) = db
3696 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003697 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003698 domain: Domain::APP,
3699 nspace: 0,
3700 alias: Some(TEST_ALIAS.to_string()),
3701 blob: None,
3702 },
3703 KeyType::Client,
3704 KeyEntryLoadBits::BOTH,
3705 1,
3706 |_k, _av| Ok(()),
3707 )
3708 .unwrap();
Qi Wub9433b52020-12-01 14:52:46 +08003709 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003710
3711 db.unbind_key(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003712 &KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003713 domain: Domain::APP,
3714 nspace: 0,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003715 alias: Some(TEST_ALIAS.to_string()),
3716 blob: None,
3717 },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003718 KeyType::Client,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003719 1,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003720 |_, _| Ok(()),
3721 )
3722 .unwrap();
3723
3724 assert_eq!(
3725 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
3726 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003727 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003728 domain: Domain::APP,
3729 nspace: 0,
3730 alias: Some(TEST_ALIAS.to_string()),
3731 blob: None,
3732 },
3733 KeyType::Client,
3734 KeyEntryLoadBits::NONE,
3735 1,
3736 |_k, _av| Ok(()),
3737 )
3738 .unwrap_err()
3739 .root_cause()
3740 .downcast_ref::<KsError>()
3741 );
3742
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003743 Ok(())
3744 }
3745
3746 #[test]
Janis Danisevskis377d1002021-01-27 19:07:48 -08003747 fn test_insert_and_load_certificate_entry_domain_app() -> Result<()> {
3748 let mut db = new_test_db()?;
3749
3750 db.store_new_certificate(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003751 &KeyDescriptor {
Janis Danisevskis377d1002021-01-27 19:07:48 -08003752 domain: Domain::APP,
3753 nspace: 1,
3754 alias: Some(TEST_ALIAS.to_string()),
3755 blob: None,
3756 },
3757 TEST_CERT_BLOB,
Max Bires8e93d2b2021-01-14 13:17:59 -08003758 &KEYSTORE_UUID,
Janis Danisevskis377d1002021-01-27 19:07:48 -08003759 )
3760 .expect("Trying to insert cert.");
3761
3762 let (_key_guard, mut key_entry) = db
3763 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003764 &KeyDescriptor {
Janis Danisevskis377d1002021-01-27 19:07:48 -08003765 domain: Domain::APP,
3766 nspace: 1,
3767 alias: Some(TEST_ALIAS.to_string()),
3768 blob: None,
3769 },
3770 KeyType::Client,
3771 KeyEntryLoadBits::PUBLIC,
3772 1,
3773 |_k, _av| Ok(()),
3774 )
3775 .expect("Trying to read certificate entry.");
3776
3777 assert!(key_entry.pure_cert());
3778 assert!(key_entry.cert().is_none());
3779 assert_eq!(key_entry.take_cert_chain(), Some(TEST_CERT_BLOB.to_vec()));
3780
3781 db.unbind_key(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003782 &KeyDescriptor {
Janis Danisevskis377d1002021-01-27 19:07:48 -08003783 domain: Domain::APP,
3784 nspace: 1,
3785 alias: Some(TEST_ALIAS.to_string()),
3786 blob: None,
3787 },
3788 KeyType::Client,
3789 1,
3790 |_, _| Ok(()),
3791 )
3792 .unwrap();
3793
3794 assert_eq!(
3795 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
3796 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003797 &KeyDescriptor {
Janis Danisevskis377d1002021-01-27 19:07:48 -08003798 domain: Domain::APP,
3799 nspace: 1,
3800 alias: Some(TEST_ALIAS.to_string()),
3801 blob: None,
3802 },
3803 KeyType::Client,
3804 KeyEntryLoadBits::NONE,
3805 1,
3806 |_k, _av| Ok(()),
3807 )
3808 .unwrap_err()
3809 .root_cause()
3810 .downcast_ref::<KsError>()
3811 );
3812
3813 Ok(())
3814 }
3815
3816 #[test]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003817 fn test_insert_and_load_full_keyentry_domain_selinux() -> Result<()> {
3818 let mut db = new_test_db()?;
Qi Wub9433b52020-12-01 14:52:46 +08003819 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08003820 .context("test_insert_and_load_full_keyentry_domain_selinux")?
3821 .0;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003822 let (_key_guard, key_entry) = db
3823 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003824 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003825 domain: Domain::SELINUX,
3826 nspace: 1,
3827 alias: Some(TEST_ALIAS.to_string()),
3828 blob: None,
3829 },
3830 KeyType::Client,
3831 KeyEntryLoadBits::BOTH,
3832 1,
3833 |_k, _av| Ok(()),
3834 )
3835 .unwrap();
Qi Wub9433b52020-12-01 14:52:46 +08003836 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003837
3838 db.unbind_key(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003839 &KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003840 domain: Domain::SELINUX,
3841 nspace: 1,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003842 alias: Some(TEST_ALIAS.to_string()),
3843 blob: None,
3844 },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003845 KeyType::Client,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003846 1,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003847 |_, _| Ok(()),
3848 )
3849 .unwrap();
3850
3851 assert_eq!(
3852 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
3853 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003854 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003855 domain: Domain::SELINUX,
3856 nspace: 1,
3857 alias: Some(TEST_ALIAS.to_string()),
3858 blob: None,
3859 },
3860 KeyType::Client,
3861 KeyEntryLoadBits::NONE,
3862 1,
3863 |_k, _av| Ok(()),
3864 )
3865 .unwrap_err()
3866 .root_cause()
3867 .downcast_ref::<KsError>()
3868 );
3869
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003870 Ok(())
3871 }
3872
3873 #[test]
3874 fn test_insert_and_load_full_keyentry_domain_key_id() -> Result<()> {
3875 let mut db = new_test_db()?;
Qi Wub9433b52020-12-01 14:52:46 +08003876 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08003877 .context("test_insert_and_load_full_keyentry_domain_key_id")?
3878 .0;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003879 let (_, key_entry) = db
3880 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003881 &KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003882 KeyType::Client,
3883 KeyEntryLoadBits::BOTH,
3884 1,
3885 |_k, _av| Ok(()),
3886 )
3887 .unwrap();
3888
Qi Wub9433b52020-12-01 14:52:46 +08003889 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003890
3891 db.unbind_key(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003892 &KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003893 KeyType::Client,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003894 1,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003895 |_, _| Ok(()),
3896 )
3897 .unwrap();
3898
3899 assert_eq!(
3900 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
3901 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003902 &KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003903 KeyType::Client,
3904 KeyEntryLoadBits::NONE,
3905 1,
3906 |_k, _av| Ok(()),
3907 )
3908 .unwrap_err()
3909 .root_cause()
3910 .downcast_ref::<KsError>()
3911 );
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003912
3913 Ok(())
3914 }
3915
3916 #[test]
Qi Wub9433b52020-12-01 14:52:46 +08003917 fn test_check_and_update_key_usage_count_with_limited_use_key() -> Result<()> {
3918 let mut db = new_test_db()?;
3919 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, Some(123))
3920 .context("test_check_and_update_key_usage_count_with_limited_use_key")?
3921 .0;
3922 // Update the usage count of the limited use key.
3923 db.check_and_update_key_usage_count(key_id)?;
3924
3925 let (_key_guard, key_entry) = db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003926 &KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
Qi Wub9433b52020-12-01 14:52:46 +08003927 KeyType::Client,
3928 KeyEntryLoadBits::BOTH,
3929 1,
3930 |_k, _av| Ok(()),
3931 )?;
3932
3933 // The usage count is decremented now.
3934 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, Some(122)));
3935
3936 Ok(())
3937 }
3938
3939 #[test]
3940 fn test_check_and_update_key_usage_count_with_exhausted_limited_use_key() -> Result<()> {
3941 let mut db = new_test_db()?;
3942 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, Some(1))
3943 .context("test_check_and_update_key_usage_count_with_exhausted_limited_use_key")?
3944 .0;
3945 // Update the usage count of the limited use key.
3946 db.check_and_update_key_usage_count(key_id).expect(concat!(
3947 "In test_check_and_update_key_usage_count_with_exhausted_limited_use_key: ",
3948 "This should succeed."
3949 ));
3950
3951 // Try to update the exhausted limited use key.
3952 let e = db.check_and_update_key_usage_count(key_id).expect_err(concat!(
3953 "In test_check_and_update_key_usage_count_with_exhausted_limited_use_key: ",
3954 "This should fail."
3955 ));
3956 assert_eq!(
3957 &KsError::Km(ErrorCode::INVALID_KEY_BLOB),
3958 e.root_cause().downcast_ref::<KsError>().unwrap()
3959 );
3960
3961 Ok(())
3962 }
3963
3964 #[test]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003965 fn test_insert_and_load_full_keyentry_from_grant() -> Result<()> {
3966 let mut db = new_test_db()?;
Qi Wub9433b52020-12-01 14:52:46 +08003967 let key_id = make_test_key_entry(&mut db, Domain::APP, 1, TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08003968 .context("test_insert_and_load_full_keyentry_from_grant")?
3969 .0;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003970
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003971 let granted_key = db
3972 .grant(
Janis Danisevskis66784c42021-01-27 08:40:25 -08003973 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003974 domain: Domain::APP,
3975 nspace: 0,
3976 alias: Some(TEST_ALIAS.to_string()),
3977 blob: None,
3978 },
3979 1,
3980 2,
3981 key_perm_set![KeyPerm::use_()],
3982 |_k, _av| Ok(()),
3983 )
3984 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003985
3986 debug_dump_grant_table(&mut db)?;
3987
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003988 let (_key_guard, key_entry) = db
Janis Danisevskis66784c42021-01-27 08:40:25 -08003989 .load_key_entry(&granted_key, KeyType::Client, KeyEntryLoadBits::BOTH, 2, |k, av| {
3990 assert_eq!(Domain::GRANT, k.domain);
3991 assert!(av.unwrap().includes(KeyPerm::use_()));
3992 Ok(())
3993 })
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003994 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003995
Qi Wub9433b52020-12-01 14:52:46 +08003996 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003997
Janis Danisevskis66784c42021-01-27 08:40:25 -08003998 db.unbind_key(&granted_key, KeyType::Client, 2, |_, _| Ok(())).unwrap();
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003999
4000 assert_eq!(
4001 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
4002 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004003 &granted_key,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004004 KeyType::Client,
4005 KeyEntryLoadBits::NONE,
4006 2,
4007 |_k, _av| Ok(()),
4008 )
4009 .unwrap_err()
4010 .root_cause()
4011 .downcast_ref::<KsError>()
4012 );
4013
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004014 Ok(())
4015 }
4016
Janis Danisevskis45760022021-01-19 16:34:10 -08004017 // This test attempts to load a key by key id while the caller is not the owner
4018 // but a grant exists for the given key and the caller.
4019 #[test]
4020 fn test_insert_and_load_full_keyentry_from_grant_by_key_id() -> Result<()> {
4021 let mut db = new_test_db()?;
4022 const OWNER_UID: u32 = 1u32;
4023 const GRANTEE_UID: u32 = 2u32;
4024 const SOMEONE_ELSE_UID: u32 = 3u32;
4025 let key_id = make_test_key_entry(&mut db, Domain::APP, OWNER_UID as i64, TEST_ALIAS, None)
4026 .context("test_insert_and_load_full_keyentry_from_grant_by_key_id")?
4027 .0;
4028
4029 db.grant(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004030 &KeyDescriptor {
Janis Danisevskis45760022021-01-19 16:34:10 -08004031 domain: Domain::APP,
4032 nspace: 0,
4033 alias: Some(TEST_ALIAS.to_string()),
4034 blob: None,
4035 },
4036 OWNER_UID,
4037 GRANTEE_UID,
4038 key_perm_set![KeyPerm::use_()],
4039 |_k, _av| Ok(()),
4040 )
4041 .unwrap();
4042
4043 debug_dump_grant_table(&mut db)?;
4044
4045 let id_descriptor =
4046 KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, ..Default::default() };
4047
4048 let (_, key_entry) = db
4049 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004050 &id_descriptor,
Janis Danisevskis45760022021-01-19 16:34:10 -08004051 KeyType::Client,
4052 KeyEntryLoadBits::BOTH,
4053 GRANTEE_UID,
4054 |k, av| {
4055 assert_eq!(Domain::APP, k.domain);
4056 assert_eq!(OWNER_UID as i64, k.nspace);
4057 assert!(av.unwrap().includes(KeyPerm::use_()));
4058 Ok(())
4059 },
4060 )
4061 .unwrap();
4062
4063 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
4064
4065 let (_, key_entry) = db
4066 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004067 &id_descriptor,
Janis Danisevskis45760022021-01-19 16:34:10 -08004068 KeyType::Client,
4069 KeyEntryLoadBits::BOTH,
4070 SOMEONE_ELSE_UID,
4071 |k, av| {
4072 assert_eq!(Domain::APP, k.domain);
4073 assert_eq!(OWNER_UID as i64, k.nspace);
4074 assert!(av.is_none());
4075 Ok(())
4076 },
4077 )
4078 .unwrap();
4079
4080 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
4081
Janis Danisevskis66784c42021-01-27 08:40:25 -08004082 db.unbind_key(&id_descriptor, KeyType::Client, OWNER_UID, |_, _| Ok(())).unwrap();
Janis Danisevskis45760022021-01-19 16:34:10 -08004083
4084 assert_eq!(
4085 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
4086 db.load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004087 &id_descriptor,
Janis Danisevskis45760022021-01-19 16:34:10 -08004088 KeyType::Client,
4089 KeyEntryLoadBits::NONE,
4090 GRANTEE_UID,
4091 |_k, _av| Ok(()),
4092 )
4093 .unwrap_err()
4094 .root_cause()
4095 .downcast_ref::<KsError>()
4096 );
4097
4098 Ok(())
4099 }
4100
Janis Danisevskisaec14592020-11-12 09:41:49 -08004101 static KEY_LOCK_TEST_ALIAS: &str = "my super duper locked key";
4102
Janis Danisevskisaec14592020-11-12 09:41:49 -08004103 #[test]
4104 fn test_insert_and_load_full_keyentry_domain_app_concurrently() -> Result<()> {
4105 let handle = {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08004106 let temp_dir = Arc::new(TempDir::new("id_lock_test")?);
4107 let temp_dir_clone = temp_dir.clone();
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004108 let mut db = KeystoreDB::new(temp_dir.path(), None)?;
Qi Wub9433b52020-12-01 14:52:46 +08004109 let key_id = make_test_key_entry(&mut db, Domain::APP, 33, KEY_LOCK_TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08004110 .context("test_insert_and_load_full_keyentry_domain_app")?
4111 .0;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004112 let (_key_guard, key_entry) = db
4113 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004114 &KeyDescriptor {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004115 domain: Domain::APP,
4116 nspace: 0,
4117 alias: Some(KEY_LOCK_TEST_ALIAS.to_string()),
4118 blob: None,
4119 },
4120 KeyType::Client,
4121 KeyEntryLoadBits::BOTH,
4122 33,
4123 |_k, _av| Ok(()),
4124 )
4125 .unwrap();
Qi Wub9433b52020-12-01 14:52:46 +08004126 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskisaec14592020-11-12 09:41:49 -08004127 let state = Arc::new(AtomicU8::new(1));
4128 let state2 = state.clone();
4129
4130 // Spawning a second thread that attempts to acquire the key id lock
4131 // for the same key as the primary thread. The primary thread then
4132 // waits, thereby forcing the secondary thread into the second stage
4133 // of acquiring the lock (see KEY ID LOCK 2/2 above).
4134 // The test succeeds if the secondary thread observes the transition
4135 // of `state` from 1 to 2, despite having a whole second to overtake
4136 // the primary thread.
4137 let handle = thread::spawn(move || {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08004138 let temp_dir = temp_dir_clone;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004139 let mut db = KeystoreDB::new(temp_dir.path(), None).unwrap();
Janis Danisevskisaec14592020-11-12 09:41:49 -08004140 assert!(db
4141 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004142 &KeyDescriptor {
Janis Danisevskisaec14592020-11-12 09:41:49 -08004143 domain: Domain::APP,
4144 nspace: 0,
4145 alias: Some(KEY_LOCK_TEST_ALIAS.to_string()),
4146 blob: None,
4147 },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004148 KeyType::Client,
Janis Danisevskisaec14592020-11-12 09:41:49 -08004149 KeyEntryLoadBits::BOTH,
4150 33,
4151 |_k, _av| Ok(()),
4152 )
4153 .is_ok());
4154 // We should only see a 2 here because we can only return
4155 // from load_key_entry when the `_key_guard` expires,
4156 // which happens at the end of the scope.
4157 assert_eq!(2, state2.load(Ordering::Relaxed));
4158 });
4159
4160 thread::sleep(std::time::Duration::from_millis(1000));
4161
4162 assert_eq!(Ok(1), state.compare_exchange(1, 2, Ordering::Relaxed, Ordering::Relaxed));
4163
4164 // Return the handle from this scope so we can join with the
4165 // secondary thread after the key id lock has expired.
4166 handle
4167 // This is where the `_key_guard` goes out of scope,
4168 // which is the reason for concurrent load_key_entry on the same key
4169 // to unblock.
4170 };
4171 // Join with the secondary thread and unwrap, to propagate failing asserts to the
4172 // main test thread. We will not see failing asserts in secondary threads otherwise.
4173 handle.join().unwrap();
4174 Ok(())
4175 }
4176
Janis Danisevskise92a5e62020-12-02 12:57:41 -08004177 #[test]
Janis Danisevskis66784c42021-01-27 08:40:25 -08004178 fn teset_database_busy_error_code() {
4179 let temp_dir =
4180 TempDir::new("test_database_busy_error_code_").expect("Failed to create temp dir.");
4181
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004182 let mut db1 = KeystoreDB::new(temp_dir.path(), None).expect("Failed to open database1.");
4183 let mut db2 = KeystoreDB::new(temp_dir.path(), None).expect("Failed to open database2.");
Janis Danisevskis66784c42021-01-27 08:40:25 -08004184
4185 let _tx1 = db1
4186 .conn
4187 .transaction_with_behavior(TransactionBehavior::Immediate)
4188 .expect("Failed to create first transaction.");
4189
4190 let error = db2
4191 .conn
4192 .transaction_with_behavior(TransactionBehavior::Immediate)
4193 .context("Transaction begin failed.")
4194 .expect_err("This should fail.");
4195 let root_cause = error.root_cause();
4196 if let Some(rusqlite::ffi::Error { code: rusqlite::ErrorCode::DatabaseBusy, .. }) =
4197 root_cause.downcast_ref::<rusqlite::ffi::Error>()
4198 {
4199 return;
4200 }
4201 panic!(
4202 "Unexpected error {:?} \n{:?} \n{:?}",
4203 error,
4204 root_cause,
4205 root_cause.downcast_ref::<rusqlite::ffi::Error>()
4206 )
4207 }
4208
4209 #[cfg(disabled)]
4210 #[test]
4211 fn test_large_number_of_concurrent_db_manipulations() -> Result<()> {
4212 let temp_dir = Arc::new(
4213 TempDir::new("test_large_number_of_concurrent_db_manipulations_")
4214 .expect("Failed to create temp dir."),
4215 );
4216
4217 let test_begin = Instant::now();
4218
4219 let mut db = KeystoreDB::new(temp_dir.path()).expect("Failed to open database.");
4220 const KEY_COUNT: u32 = 500u32;
4221 const OPEN_DB_COUNT: u32 = 50u32;
4222
4223 let mut actual_key_count = KEY_COUNT;
4224 // First insert KEY_COUNT keys.
4225 for count in 0..KEY_COUNT {
4226 if Instant::now().duration_since(test_begin) >= Duration::from_secs(15) {
4227 actual_key_count = count;
4228 break;
4229 }
4230 let alias = format!("test_alias_{}", count);
4231 make_test_key_entry(&mut db, Domain::APP, 1, &alias, None)
4232 .expect("Failed to make key entry.");
4233 }
4234
4235 // Insert more keys from a different thread and into a different namespace.
4236 let temp_dir1 = temp_dir.clone();
4237 let handle1 = thread::spawn(move || {
4238 let mut db = KeystoreDB::new(temp_dir1.path()).expect("Failed to open database.");
4239
4240 for count in 0..actual_key_count {
4241 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
4242 return;
4243 }
4244 let alias = format!("test_alias_{}", count);
4245 make_test_key_entry(&mut db, Domain::APP, 2, &alias, None)
4246 .expect("Failed to make key entry.");
4247 }
4248
4249 // then unbind them again.
4250 for count in 0..actual_key_count {
4251 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
4252 return;
4253 }
4254 let key = KeyDescriptor {
4255 domain: Domain::APP,
4256 nspace: -1,
4257 alias: Some(format!("test_alias_{}", count)),
4258 blob: None,
4259 };
4260 db.unbind_key(&key, KeyType::Client, 2, |_, _| Ok(())).expect("Unbind Failed.");
4261 }
4262 });
4263
4264 // And start unbinding the first set of keys.
4265 let temp_dir2 = temp_dir.clone();
4266 let handle2 = thread::spawn(move || {
4267 let mut db = KeystoreDB::new(temp_dir2.path()).expect("Failed to open database.");
4268
4269 for count in 0..actual_key_count {
4270 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
4271 return;
4272 }
4273 let key = KeyDescriptor {
4274 domain: Domain::APP,
4275 nspace: -1,
4276 alias: Some(format!("test_alias_{}", count)),
4277 blob: None,
4278 };
4279 db.unbind_key(&key, KeyType::Client, 1, |_, _| Ok(())).expect("Unbind Failed.");
4280 }
4281 });
4282
4283 let stop_deleting = Arc::new(AtomicU8::new(0));
4284 let stop_deleting2 = stop_deleting.clone();
4285
4286 // And delete anything that is unreferenced keys.
4287 let temp_dir3 = temp_dir.clone();
4288 let handle3 = thread::spawn(move || {
4289 let mut db = KeystoreDB::new(temp_dir3.path()).expect("Failed to open database.");
4290
4291 while stop_deleting2.load(Ordering::Relaxed) != 1 {
4292 while let Some((key_guard, _key)) =
4293 db.get_unreferenced_key().expect("Failed to get unreferenced Key.")
4294 {
4295 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
4296 return;
4297 }
4298 db.purge_key_entry(key_guard).expect("Failed to purge key.");
4299 }
4300 std::thread::sleep(std::time::Duration::from_millis(100));
4301 }
4302 });
4303
4304 // While a lot of inserting and deleting is going on we have to open database connections
4305 // successfully and use them.
4306 // This clone is not redundant, because temp_dir needs to be kept alive until db goes
4307 // out of scope.
4308 #[allow(clippy::redundant_clone)]
4309 let temp_dir4 = temp_dir.clone();
4310 let handle4 = thread::spawn(move || {
4311 for count in 0..OPEN_DB_COUNT {
4312 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
4313 return;
4314 }
4315 let mut db = KeystoreDB::new(temp_dir4.path()).expect("Failed to open database.");
4316
4317 let alias = format!("test_alias_{}", count);
4318 make_test_key_entry(&mut db, Domain::APP, 3, &alias, None)
4319 .expect("Failed to make key entry.");
4320 let key = KeyDescriptor {
4321 domain: Domain::APP,
4322 nspace: -1,
4323 alias: Some(alias),
4324 blob: None,
4325 };
4326 db.unbind_key(&key, KeyType::Client, 3, |_, _| Ok(())).expect("Unbind Failed.");
4327 }
4328 });
4329
4330 handle1.join().expect("Thread 1 panicked.");
4331 handle2.join().expect("Thread 2 panicked.");
4332 handle4.join().expect("Thread 4 panicked.");
4333
4334 stop_deleting.store(1, Ordering::Relaxed);
4335 handle3.join().expect("Thread 3 panicked.");
4336
4337 Ok(())
4338 }
4339
4340 #[test]
Janis Danisevskise92a5e62020-12-02 12:57:41 -08004341 fn list() -> Result<()> {
4342 let temp_dir = TempDir::new("list_test")?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004343 let mut db = KeystoreDB::new(temp_dir.path(), None)?;
Janis Danisevskise92a5e62020-12-02 12:57:41 -08004344 static LIST_O_ENTRIES: &[(Domain, i64, &str)] = &[
4345 (Domain::APP, 1, "test1"),
4346 (Domain::APP, 1, "test2"),
4347 (Domain::APP, 1, "test3"),
4348 (Domain::APP, 1, "test4"),
4349 (Domain::APP, 1, "test5"),
4350 (Domain::APP, 1, "test6"),
4351 (Domain::APP, 1, "test7"),
4352 (Domain::APP, 2, "test1"),
4353 (Domain::APP, 2, "test2"),
4354 (Domain::APP, 2, "test3"),
4355 (Domain::APP, 2, "test4"),
4356 (Domain::APP, 2, "test5"),
4357 (Domain::APP, 2, "test6"),
4358 (Domain::APP, 2, "test8"),
4359 (Domain::SELINUX, 100, "test1"),
4360 (Domain::SELINUX, 100, "test2"),
4361 (Domain::SELINUX, 100, "test3"),
4362 (Domain::SELINUX, 100, "test4"),
4363 (Domain::SELINUX, 100, "test5"),
4364 (Domain::SELINUX, 100, "test6"),
4365 (Domain::SELINUX, 100, "test9"),
4366 ];
4367
4368 let list_o_keys: Vec<(i64, i64)> = LIST_O_ENTRIES
4369 .iter()
4370 .map(|(domain, ns, alias)| {
Qi Wub9433b52020-12-01 14:52:46 +08004371 let entry = make_test_key_entry(&mut db, *domain, *ns, *alias, None)
4372 .unwrap_or_else(|e| {
Janis Danisevskise92a5e62020-12-02 12:57:41 -08004373 panic!("Failed to insert {:?} {} {}. Error {:?}", domain, ns, alias, e)
4374 });
4375 (entry.id(), *ns)
4376 })
4377 .collect();
4378
4379 for (domain, namespace) in
4380 &[(Domain::APP, 1i64), (Domain::APP, 2i64), (Domain::SELINUX, 100i64)]
4381 {
4382 let mut list_o_descriptors: Vec<KeyDescriptor> = LIST_O_ENTRIES
4383 .iter()
4384 .filter_map(|(domain, ns, alias)| match ns {
4385 ns if *ns == *namespace => Some(KeyDescriptor {
4386 domain: *domain,
4387 nspace: *ns,
4388 alias: Some(alias.to_string()),
4389 blob: None,
4390 }),
4391 _ => None,
4392 })
4393 .collect();
4394 list_o_descriptors.sort();
4395 let mut list_result = db.list(*domain, *namespace)?;
4396 list_result.sort();
4397 assert_eq!(list_o_descriptors, list_result);
4398
4399 let mut list_o_ids: Vec<i64> = list_o_descriptors
4400 .into_iter()
4401 .map(|d| {
4402 let (_, entry) = db
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004403 .load_key_entry(
Janis Danisevskis66784c42021-01-27 08:40:25 -08004404 &d,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004405 KeyType::Client,
4406 KeyEntryLoadBits::NONE,
4407 *namespace as u32,
4408 |_, _| Ok(()),
4409 )
Janis Danisevskise92a5e62020-12-02 12:57:41 -08004410 .unwrap();
4411 entry.id()
4412 })
4413 .collect();
4414 list_o_ids.sort_unstable();
4415 let mut loaded_entries: Vec<i64> = list_o_keys
4416 .iter()
4417 .filter_map(|(id, ns)| match ns {
4418 ns if *ns == *namespace => Some(*id),
4419 _ => None,
4420 })
4421 .collect();
4422 loaded_entries.sort_unstable();
4423 assert_eq!(list_o_ids, loaded_entries);
4424 }
4425 assert_eq!(Vec::<KeyDescriptor>::new(), db.list(Domain::SELINUX, 101)?);
4426
4427 Ok(())
4428 }
4429
Joel Galenson0891bc12020-07-20 10:37:03 -07004430 // Helpers
4431
4432 // Checks that the given result is an error containing the given string.
4433 fn check_result_is_error_containing_string<T>(result: Result<T>, target: &str) {
4434 let error_str = format!(
4435 "{:#?}",
4436 result.err().unwrap_or_else(|| panic!("Expected the error: {}", target))
4437 );
4438 assert!(
4439 error_str.contains(target),
4440 "The string \"{}\" should contain \"{}\"",
4441 error_str,
4442 target
4443 );
4444 }
4445
Joel Galenson2aab4432020-07-22 15:27:57 -07004446 #[derive(Debug, PartialEq)]
Joel Galenson0891bc12020-07-20 10:37:03 -07004447 struct KeyEntryRow {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004448 id: i64,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004449 key_type: KeyType,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07004450 domain: Option<Domain>,
Joel Galenson0891bc12020-07-20 10:37:03 -07004451 namespace: Option<i64>,
4452 alias: Option<String>,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004453 state: KeyLifeCycle,
Max Bires8e93d2b2021-01-14 13:17:59 -08004454 km_uuid: Option<Uuid>,
Joel Galenson0891bc12020-07-20 10:37:03 -07004455 }
4456
4457 fn get_keyentry(db: &KeystoreDB) -> Result<Vec<KeyEntryRow>> {
4458 db.conn
Joel Galenson2aab4432020-07-22 15:27:57 -07004459 .prepare("SELECT * FROM persistent.keyentry;")?
Joel Galenson0891bc12020-07-20 10:37:03 -07004460 .query_map(NO_PARAMS, |row| {
Joel Galenson0891bc12020-07-20 10:37:03 -07004461 Ok(KeyEntryRow {
4462 id: row.get(0)?,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004463 key_type: row.get(1)?,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07004464 domain: match row.get(2)? {
4465 Some(i) => Some(Domain(i)),
4466 None => None,
4467 },
Joel Galenson0891bc12020-07-20 10:37:03 -07004468 namespace: row.get(3)?,
4469 alias: row.get(4)?,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004470 state: row.get(5)?,
Max Bires8e93d2b2021-01-14 13:17:59 -08004471 km_uuid: row.get(6)?,
Joel Galenson0891bc12020-07-20 10:37:03 -07004472 })
4473 })?
4474 .map(|r| r.context("Could not read keyentry row."))
4475 .collect::<Result<Vec<_>>>()
4476 }
4477
Max Biresb2e1d032021-02-08 21:35:05 -08004478 struct RemoteProvValues {
4479 cert_chain: Vec<u8>,
4480 priv_key: Vec<u8>,
4481 batch_cert: Vec<u8>,
4482 }
4483
Max Bires2b2e6562020-09-22 11:22:36 -07004484 fn load_attestation_key_pool(
4485 db: &mut KeystoreDB,
4486 expiration_date: i64,
4487 namespace: i64,
4488 base_byte: u8,
Max Biresb2e1d032021-02-08 21:35:05 -08004489 ) -> Result<RemoteProvValues> {
Max Bires2b2e6562020-09-22 11:22:36 -07004490 let public_key: Vec<u8> = vec![base_byte, 0x02 * base_byte];
4491 let cert_chain: Vec<u8> = vec![0x03 * base_byte, 0x04 * base_byte];
4492 let priv_key: Vec<u8> = vec![0x05 * base_byte, 0x06 * base_byte];
4493 let raw_public_key: Vec<u8> = vec![0x0b * base_byte, 0x0c * base_byte];
Max Biresb2e1d032021-02-08 21:35:05 -08004494 let batch_cert: Vec<u8> = vec![base_byte * 0x0d, base_byte * 0x0e];
Max Bires2b2e6562020-09-22 11:22:36 -07004495 db.create_attestation_key_entry(&public_key, &raw_public_key, &priv_key, &KEYSTORE_UUID)?;
4496 db.store_signed_attestation_certificate_chain(
4497 &raw_public_key,
Max Biresb2e1d032021-02-08 21:35:05 -08004498 &batch_cert,
Max Bires2b2e6562020-09-22 11:22:36 -07004499 &cert_chain,
4500 expiration_date,
4501 &KEYSTORE_UUID,
4502 )?;
4503 db.assign_attestation_key(Domain::APP, namespace, &KEYSTORE_UUID)?;
Max Biresb2e1d032021-02-08 21:35:05 -08004504 Ok(RemoteProvValues { cert_chain, priv_key, batch_cert })
Max Bires2b2e6562020-09-22 11:22:36 -07004505 }
4506
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07004507 // Note: The parameters and SecurityLevel associations are nonsensical. This
4508 // collection is only used to check if the parameters are preserved as expected by the
4509 // database.
Qi Wub9433b52020-12-01 14:52:46 +08004510 fn make_test_params(max_usage_count: Option<i32>) -> Vec<KeyParameter> {
4511 let mut params = vec![
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07004512 KeyParameter::new(KeyParameterValue::Invalid, SecurityLevel::TRUSTED_ENVIRONMENT),
4513 KeyParameter::new(
4514 KeyParameterValue::KeyPurpose(KeyPurpose::SIGN),
4515 SecurityLevel::TRUSTED_ENVIRONMENT,
4516 ),
4517 KeyParameter::new(
4518 KeyParameterValue::KeyPurpose(KeyPurpose::DECRYPT),
4519 SecurityLevel::TRUSTED_ENVIRONMENT,
4520 ),
4521 KeyParameter::new(
4522 KeyParameterValue::Algorithm(Algorithm::RSA),
4523 SecurityLevel::TRUSTED_ENVIRONMENT,
4524 ),
4525 KeyParameter::new(KeyParameterValue::KeySize(1024), SecurityLevel::TRUSTED_ENVIRONMENT),
4526 KeyParameter::new(
4527 KeyParameterValue::BlockMode(BlockMode::ECB),
4528 SecurityLevel::TRUSTED_ENVIRONMENT,
4529 ),
4530 KeyParameter::new(
4531 KeyParameterValue::BlockMode(BlockMode::GCM),
4532 SecurityLevel::TRUSTED_ENVIRONMENT,
4533 ),
4534 KeyParameter::new(KeyParameterValue::Digest(Digest::NONE), SecurityLevel::STRONGBOX),
4535 KeyParameter::new(
4536 KeyParameterValue::Digest(Digest::MD5),
4537 SecurityLevel::TRUSTED_ENVIRONMENT,
4538 ),
4539 KeyParameter::new(
4540 KeyParameterValue::Digest(Digest::SHA_2_224),
4541 SecurityLevel::TRUSTED_ENVIRONMENT,
4542 ),
4543 KeyParameter::new(
4544 KeyParameterValue::Digest(Digest::SHA_2_256),
4545 SecurityLevel::STRONGBOX,
4546 ),
4547 KeyParameter::new(
4548 KeyParameterValue::PaddingMode(PaddingMode::NONE),
4549 SecurityLevel::TRUSTED_ENVIRONMENT,
4550 ),
4551 KeyParameter::new(
4552 KeyParameterValue::PaddingMode(PaddingMode::RSA_OAEP),
4553 SecurityLevel::TRUSTED_ENVIRONMENT,
4554 ),
4555 KeyParameter::new(
4556 KeyParameterValue::PaddingMode(PaddingMode::RSA_PSS),
4557 SecurityLevel::STRONGBOX,
4558 ),
4559 KeyParameter::new(
4560 KeyParameterValue::PaddingMode(PaddingMode::RSA_PKCS1_1_5_SIGN),
4561 SecurityLevel::TRUSTED_ENVIRONMENT,
4562 ),
4563 KeyParameter::new(KeyParameterValue::CallerNonce, SecurityLevel::TRUSTED_ENVIRONMENT),
4564 KeyParameter::new(KeyParameterValue::MinMacLength(256), SecurityLevel::STRONGBOX),
4565 KeyParameter::new(
4566 KeyParameterValue::EcCurve(EcCurve::P_224),
4567 SecurityLevel::TRUSTED_ENVIRONMENT,
4568 ),
4569 KeyParameter::new(KeyParameterValue::EcCurve(EcCurve::P_256), SecurityLevel::STRONGBOX),
4570 KeyParameter::new(
4571 KeyParameterValue::EcCurve(EcCurve::P_384),
4572 SecurityLevel::TRUSTED_ENVIRONMENT,
4573 ),
4574 KeyParameter::new(
4575 KeyParameterValue::EcCurve(EcCurve::P_521),
4576 SecurityLevel::TRUSTED_ENVIRONMENT,
4577 ),
4578 KeyParameter::new(
4579 KeyParameterValue::RSAPublicExponent(3),
4580 SecurityLevel::TRUSTED_ENVIRONMENT,
4581 ),
4582 KeyParameter::new(
4583 KeyParameterValue::IncludeUniqueID,
4584 SecurityLevel::TRUSTED_ENVIRONMENT,
4585 ),
4586 KeyParameter::new(KeyParameterValue::BootLoaderOnly, SecurityLevel::STRONGBOX),
4587 KeyParameter::new(KeyParameterValue::RollbackResistance, SecurityLevel::STRONGBOX),
4588 KeyParameter::new(
4589 KeyParameterValue::ActiveDateTime(1234567890),
4590 SecurityLevel::STRONGBOX,
4591 ),
4592 KeyParameter::new(
4593 KeyParameterValue::OriginationExpireDateTime(1234567890),
4594 SecurityLevel::TRUSTED_ENVIRONMENT,
4595 ),
4596 KeyParameter::new(
4597 KeyParameterValue::UsageExpireDateTime(1234567890),
4598 SecurityLevel::TRUSTED_ENVIRONMENT,
4599 ),
4600 KeyParameter::new(
4601 KeyParameterValue::MinSecondsBetweenOps(1234567890),
4602 SecurityLevel::TRUSTED_ENVIRONMENT,
4603 ),
4604 KeyParameter::new(
4605 KeyParameterValue::MaxUsesPerBoot(1234567890),
4606 SecurityLevel::TRUSTED_ENVIRONMENT,
4607 ),
4608 KeyParameter::new(KeyParameterValue::UserID(1), SecurityLevel::STRONGBOX),
4609 KeyParameter::new(KeyParameterValue::UserSecureID(42), SecurityLevel::STRONGBOX),
4610 KeyParameter::new(
4611 KeyParameterValue::NoAuthRequired,
4612 SecurityLevel::TRUSTED_ENVIRONMENT,
4613 ),
4614 KeyParameter::new(
4615 KeyParameterValue::HardwareAuthenticatorType(HardwareAuthenticatorType::PASSWORD),
4616 SecurityLevel::TRUSTED_ENVIRONMENT,
4617 ),
4618 KeyParameter::new(KeyParameterValue::AuthTimeout(1234567890), SecurityLevel::SOFTWARE),
4619 KeyParameter::new(KeyParameterValue::AllowWhileOnBody, SecurityLevel::SOFTWARE),
4620 KeyParameter::new(
4621 KeyParameterValue::TrustedUserPresenceRequired,
4622 SecurityLevel::TRUSTED_ENVIRONMENT,
4623 ),
4624 KeyParameter::new(
4625 KeyParameterValue::TrustedConfirmationRequired,
4626 SecurityLevel::TRUSTED_ENVIRONMENT,
4627 ),
4628 KeyParameter::new(
4629 KeyParameterValue::UnlockedDeviceRequired,
4630 SecurityLevel::TRUSTED_ENVIRONMENT,
4631 ),
4632 KeyParameter::new(
4633 KeyParameterValue::ApplicationID(vec![1u8, 2u8, 3u8, 4u8]),
4634 SecurityLevel::SOFTWARE,
4635 ),
4636 KeyParameter::new(
4637 KeyParameterValue::ApplicationData(vec![4u8, 3u8, 2u8, 1u8]),
4638 SecurityLevel::SOFTWARE,
4639 ),
4640 KeyParameter::new(
4641 KeyParameterValue::CreationDateTime(12345677890),
4642 SecurityLevel::SOFTWARE,
4643 ),
4644 KeyParameter::new(
4645 KeyParameterValue::KeyOrigin(KeyOrigin::GENERATED),
4646 SecurityLevel::TRUSTED_ENVIRONMENT,
4647 ),
4648 KeyParameter::new(
4649 KeyParameterValue::RootOfTrust(vec![3u8, 2u8, 1u8, 4u8]),
4650 SecurityLevel::TRUSTED_ENVIRONMENT,
4651 ),
4652 KeyParameter::new(KeyParameterValue::OSVersion(1), SecurityLevel::TRUSTED_ENVIRONMENT),
4653 KeyParameter::new(KeyParameterValue::OSPatchLevel(2), SecurityLevel::SOFTWARE),
4654 KeyParameter::new(
4655 KeyParameterValue::UniqueID(vec![4u8, 3u8, 1u8, 2u8]),
4656 SecurityLevel::SOFTWARE,
4657 ),
4658 KeyParameter::new(
4659 KeyParameterValue::AttestationChallenge(vec![4u8, 3u8, 1u8, 2u8]),
4660 SecurityLevel::TRUSTED_ENVIRONMENT,
4661 ),
4662 KeyParameter::new(
4663 KeyParameterValue::AttestationApplicationID(vec![4u8, 3u8, 1u8, 2u8]),
4664 SecurityLevel::TRUSTED_ENVIRONMENT,
4665 ),
4666 KeyParameter::new(
4667 KeyParameterValue::AttestationIdBrand(vec![4u8, 3u8, 1u8, 2u8]),
4668 SecurityLevel::TRUSTED_ENVIRONMENT,
4669 ),
4670 KeyParameter::new(
4671 KeyParameterValue::AttestationIdDevice(vec![4u8, 3u8, 1u8, 2u8]),
4672 SecurityLevel::TRUSTED_ENVIRONMENT,
4673 ),
4674 KeyParameter::new(
4675 KeyParameterValue::AttestationIdProduct(vec![4u8, 3u8, 1u8, 2u8]),
4676 SecurityLevel::TRUSTED_ENVIRONMENT,
4677 ),
4678 KeyParameter::new(
4679 KeyParameterValue::AttestationIdSerial(vec![4u8, 3u8, 1u8, 2u8]),
4680 SecurityLevel::TRUSTED_ENVIRONMENT,
4681 ),
4682 KeyParameter::new(
4683 KeyParameterValue::AttestationIdIMEI(vec![4u8, 3u8, 1u8, 2u8]),
4684 SecurityLevel::TRUSTED_ENVIRONMENT,
4685 ),
4686 KeyParameter::new(
4687 KeyParameterValue::AttestationIdMEID(vec![4u8, 3u8, 1u8, 2u8]),
4688 SecurityLevel::TRUSTED_ENVIRONMENT,
4689 ),
4690 KeyParameter::new(
4691 KeyParameterValue::AttestationIdManufacturer(vec![4u8, 3u8, 1u8, 2u8]),
4692 SecurityLevel::TRUSTED_ENVIRONMENT,
4693 ),
4694 KeyParameter::new(
4695 KeyParameterValue::AttestationIdModel(vec![4u8, 3u8, 1u8, 2u8]),
4696 SecurityLevel::TRUSTED_ENVIRONMENT,
4697 ),
4698 KeyParameter::new(
4699 KeyParameterValue::VendorPatchLevel(3),
4700 SecurityLevel::TRUSTED_ENVIRONMENT,
4701 ),
4702 KeyParameter::new(
4703 KeyParameterValue::BootPatchLevel(4),
4704 SecurityLevel::TRUSTED_ENVIRONMENT,
4705 ),
4706 KeyParameter::new(
4707 KeyParameterValue::AssociatedData(vec![4u8, 3u8, 1u8, 2u8]),
4708 SecurityLevel::TRUSTED_ENVIRONMENT,
4709 ),
4710 KeyParameter::new(
4711 KeyParameterValue::Nonce(vec![4u8, 3u8, 1u8, 2u8]),
4712 SecurityLevel::TRUSTED_ENVIRONMENT,
4713 ),
4714 KeyParameter::new(
4715 KeyParameterValue::MacLength(256),
4716 SecurityLevel::TRUSTED_ENVIRONMENT,
4717 ),
4718 KeyParameter::new(
4719 KeyParameterValue::ResetSinceIdRotation,
4720 SecurityLevel::TRUSTED_ENVIRONMENT,
4721 ),
4722 KeyParameter::new(
4723 KeyParameterValue::ConfirmationToken(vec![5u8, 5u8, 5u8, 5u8]),
4724 SecurityLevel::TRUSTED_ENVIRONMENT,
4725 ),
Qi Wub9433b52020-12-01 14:52:46 +08004726 ];
4727 if let Some(value) = max_usage_count {
4728 params.push(KeyParameter::new(
4729 KeyParameterValue::UsageCountLimit(value),
4730 SecurityLevel::SOFTWARE,
4731 ));
4732 }
4733 params
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07004734 }
4735
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004736 fn make_test_key_entry(
4737 db: &mut KeystoreDB,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07004738 domain: Domain,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004739 namespace: i64,
4740 alias: &str,
Qi Wub9433b52020-12-01 14:52:46 +08004741 max_usage_count: Option<i32>,
Janis Danisevskisaec14592020-11-12 09:41:49 -08004742 ) -> Result<KeyIdGuard> {
Janis Danisevskis66784c42021-01-27 08:40:25 -08004743 let key_id = db.create_key_entry(&domain, &namespace, &KEYSTORE_UUID)?;
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004744 let mut blob_metadata = BlobMetaData::new();
4745 blob_metadata.add(BlobMetaEntry::EncryptedBy(EncryptedBy::Password));
4746 blob_metadata.add(BlobMetaEntry::Salt(vec![1, 2, 3]));
4747 blob_metadata.add(BlobMetaEntry::Iv(vec![2, 3, 1]));
4748 blob_metadata.add(BlobMetaEntry::AeadTag(vec![3, 1, 2]));
4749 blob_metadata.add(BlobMetaEntry::KmUuid(KEYSTORE_UUID));
4750
4751 db.set_blob(
4752 &key_id,
4753 SubComponentType::KEY_BLOB,
4754 Some(TEST_KEY_BLOB),
4755 Some(&blob_metadata),
4756 )?;
4757 db.set_blob(&key_id, SubComponentType::CERT, Some(TEST_CERT_BLOB), None)?;
4758 db.set_blob(&key_id, SubComponentType::CERT_CHAIN, Some(TEST_CERT_CHAIN_BLOB), None)?;
Qi Wub9433b52020-12-01 14:52:46 +08004759
4760 let params = make_test_params(max_usage_count);
4761 db.insert_keyparameter(&key_id, &params)?;
4762
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004763 let mut metadata = KeyMetaData::new();
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004764 metadata.add(KeyMetaEntry::CreationDate(DateTime::from_millis_epoch(123456789)));
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004765 db.insert_key_metadata(&key_id, &metadata)?;
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08004766 rebind_alias(db, &key_id, alias, domain, namespace)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004767 Ok(key_id)
4768 }
4769
Qi Wub9433b52020-12-01 14:52:46 +08004770 fn make_test_key_entry_test_vector(key_id: i64, max_usage_count: Option<i32>) -> KeyEntry {
4771 let params = make_test_params(max_usage_count);
4772
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004773 let mut blob_metadata = BlobMetaData::new();
4774 blob_metadata.add(BlobMetaEntry::EncryptedBy(EncryptedBy::Password));
4775 blob_metadata.add(BlobMetaEntry::Salt(vec![1, 2, 3]));
4776 blob_metadata.add(BlobMetaEntry::Iv(vec![2, 3, 1]));
4777 blob_metadata.add(BlobMetaEntry::AeadTag(vec![3, 1, 2]));
4778 blob_metadata.add(BlobMetaEntry::KmUuid(KEYSTORE_UUID));
4779
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004780 let mut metadata = KeyMetaData::new();
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004781 metadata.add(KeyMetaEntry::CreationDate(DateTime::from_millis_epoch(123456789)));
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004782
4783 KeyEntry {
4784 id: key_id,
Janis Danisevskis7e8b4622021-02-13 10:01:59 -08004785 key_blob_info: Some((TEST_KEY_BLOB.to_vec(), blob_metadata)),
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004786 cert: Some(TEST_CERT_BLOB.to_vec()),
4787 cert_chain: Some(TEST_CERT_CHAIN_BLOB.to_vec()),
Max Bires8e93d2b2021-01-14 13:17:59 -08004788 km_uuid: KEYSTORE_UUID,
Qi Wub9433b52020-12-01 14:52:46 +08004789 parameters: params,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004790 metadata,
Janis Danisevskis377d1002021-01-27 19:07:48 -08004791 pure_cert: false,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08004792 }
4793 }
4794
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004795 fn debug_dump_keyentry_table(db: &mut KeystoreDB) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004796 let mut stmt = db.conn.prepare(
Max Bires8e93d2b2021-01-14 13:17:59 -08004797 "SELECT id, key_type, domain, namespace, alias, state, km_uuid FROM persistent.keyentry;",
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004798 )?;
Max Bires8e93d2b2021-01-14 13:17:59 -08004799 let rows = stmt.query_map::<(i64, KeyType, i32, i64, String, KeyLifeCycle, Uuid), _, _>(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004800 NO_PARAMS,
4801 |row| {
Max Bires8e93d2b2021-01-14 13:17:59 -08004802 Ok((
4803 row.get(0)?,
4804 row.get(1)?,
4805 row.get(2)?,
4806 row.get(3)?,
4807 row.get(4)?,
4808 row.get(5)?,
4809 row.get(6)?,
4810 ))
Janis Danisevskis93927dd2020-12-23 12:23:08 -08004811 },
4812 )?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004813
4814 println!("Key entry table rows:");
4815 for r in rows {
Max Bires8e93d2b2021-01-14 13:17:59 -08004816 let (id, key_type, domain, namespace, alias, state, km_uuid) = r.unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004817 println!(
Max Bires8e93d2b2021-01-14 13:17:59 -08004818 " id: {} KeyType: {:?} Domain: {} Namespace: {} Alias: {} State: {:?} KmUuid: {:?}",
4819 id, key_type, domain, namespace, alias, state, km_uuid
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004820 );
4821 }
4822 Ok(())
4823 }
4824
4825 fn debug_dump_grant_table(db: &mut KeystoreDB) -> Result<()> {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08004826 let mut stmt = db
4827 .conn
4828 .prepare("SELECT id, grantee, keyentryid, access_vector FROM persistent.grant;")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004829 let rows = stmt.query_map::<(i64, i64, i64, i64), _, _>(NO_PARAMS, |row| {
4830 Ok((row.get(0)?, row.get(1)?, row.get(2)?, row.get(3)?))
4831 })?;
4832
4833 println!("Grant table rows:");
4834 for r in rows {
4835 let (id, gt, ki, av) = r.unwrap();
4836 println!(" id: {} grantee: {} key_id: {} access_vector: {}", id, gt, ki, av);
4837 }
4838 Ok(())
4839 }
4840
Joel Galenson0891bc12020-07-20 10:37:03 -07004841 // Use a custom random number generator that repeats each number once.
4842 // This allows us to test repeated elements.
4843
4844 thread_local! {
4845 static RANDOM_COUNTER: RefCell<i64> = RefCell::new(0);
4846 }
4847
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07004848 fn reset_random() {
4849 RANDOM_COUNTER.with(|counter| {
4850 *counter.borrow_mut() = 0;
4851 })
4852 }
4853
Joel Galenson0891bc12020-07-20 10:37:03 -07004854 pub fn random() -> i64 {
4855 RANDOM_COUNTER.with(|counter| {
4856 let result = *counter.borrow() / 2;
4857 *counter.borrow_mut() += 1;
4858 result
4859 })
4860 }
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00004861
4862 #[test]
4863 fn test_last_off_body() -> Result<()> {
4864 let mut db = new_test_db()?;
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08004865 db.insert_last_off_body(MonotonicRawTime::now())?;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00004866 let tx = db.conn.transaction_with_behavior(TransactionBehavior::Immediate)?;
4867 let last_off_body_1 = KeystoreDB::get_last_off_body(&tx)?;
4868 tx.commit()?;
4869 let one_second = Duration::from_secs(1);
4870 thread::sleep(one_second);
4871 db.update_last_off_body(MonotonicRawTime::now())?;
4872 let tx2 = db.conn.transaction_with_behavior(TransactionBehavior::Immediate)?;
4873 let last_off_body_2 = KeystoreDB::get_last_off_body(&tx2)?;
4874 tx2.commit()?;
4875 assert!(last_off_body_1.seconds() < last_off_body_2.seconds());
4876 Ok(())
4877 }
Hasini Gunasingheda895552021-01-27 19:34:37 +00004878
4879 #[test]
4880 fn test_unbind_keys_for_user() -> Result<()> {
4881 let mut db = new_test_db()?;
4882 db.unbind_keys_for_user(1, false)?;
4883
4884 make_test_key_entry(&mut db, Domain::APP, 210000, TEST_ALIAS, None)?;
4885 make_test_key_entry(&mut db, Domain::APP, 110000, TEST_ALIAS, None)?;
4886 db.unbind_keys_for_user(2, false)?;
4887
4888 assert_eq!(1, db.list(Domain::APP, 110000)?.len());
4889 assert_eq!(0, db.list(Domain::APP, 210000)?.len());
4890
4891 db.unbind_keys_for_user(1, true)?;
4892 assert_eq!(0, db.list(Domain::APP, 110000)?.len());
4893
4894 Ok(())
4895 }
4896
4897 #[test]
4898 fn test_store_super_key() -> Result<()> {
4899 let mut db = new_test_db()?;
Paul Crowleyf61fee72021-03-17 14:38:44 -07004900 let pw: keystore2_crypto::Password = (&b"xyzabc"[..]).into();
Hasini Gunasingheda895552021-01-27 19:34:37 +00004901 let super_key = keystore2_crypto::generate_aes256_key()?;
Paul Crowley7a658392021-03-18 17:08:20 -07004902 let secret_bytes = b"keystore2 is great.";
Hasini Gunasingheda895552021-01-27 19:34:37 +00004903 let (encrypted_secret, iv, tag) =
Paul Crowley7a658392021-03-18 17:08:20 -07004904 keystore2_crypto::aes_gcm_encrypt(secret_bytes, &super_key)?;
Hasini Gunasingheda895552021-01-27 19:34:37 +00004905
4906 let (encrypted_super_key, metadata) =
4907 SuperKeyManager::encrypt_with_password(&super_key, &pw)?;
Paul Crowley8d5b2532021-03-19 10:53:07 -07004908 db.store_super_key(
4909 1,
4910 &USER_SUPER_KEY,
4911 &encrypted_super_key,
4912 &metadata,
4913 &KeyMetaData::new(),
4914 )?;
Hasini Gunasingheda895552021-01-27 19:34:37 +00004915
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00004916 //check if super key exists
Paul Crowley7a658392021-03-18 17:08:20 -07004917 assert!(db.key_exists(Domain::APP, 1, &USER_SUPER_KEY.alias, KeyType::Super)?);
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00004918
Paul Crowley7a658392021-03-18 17:08:20 -07004919 let (_, key_entry) = db.load_super_key(&USER_SUPER_KEY, 1)?.unwrap();
Paul Crowley8d5b2532021-03-19 10:53:07 -07004920 let loaded_super_key = SuperKeyManager::extract_super_key_from_key_entry(
4921 USER_SUPER_KEY.algorithm,
4922 key_entry,
4923 &pw,
4924 None,
4925 )?;
Hasini Gunasingheda895552021-01-27 19:34:37 +00004926
Paul Crowley7a658392021-03-18 17:08:20 -07004927 let decrypted_secret_bytes =
4928 loaded_super_key.aes_gcm_decrypt(&encrypted_secret, &iv, &tag)?;
4929 assert_eq!(secret_bytes, &*decrypted_secret_bytes);
Hasini Gunasingheda895552021-01-27 19:34:37 +00004930 Ok(())
4931 }
Joel Galenson26f4d012020-07-17 14:57:21 -07004932}