blob: 4e12c649d8bb410592096de3bca35a3d18f08c10 [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 Danisevskis4507f3b2021-01-13 16:34:39 -080044use crate::db_utils::{self, SqlField};
Qi Wub9433b52020-12-01 14:52:46 +080045use crate::error::{Error as KsError, ErrorCode, ResponseCode};
Janis Danisevskisb42fc182020-12-15 08:41:27 -080046use crate::impl_metadata; // This is in db_utils.rs
Janis Danisevskis4522c2b2020-11-27 18:04:58 -080047use crate::key_parameter::{KeyParameter, Tag};
Janis Danisevskisc5b210b2020-09-11 13:27:37 -070048use crate::permission::KeyPermSet;
Hasini Gunasinghe557b1032020-11-10 01:35:30 +000049use crate::utils::get_current_time_in_seconds;
Janis Danisevskisb42fc182020-12-15 08:41:27 -080050use anyhow::{anyhow, Context, Result};
51use std::{convert::TryFrom, convert::TryInto, time::SystemTimeError};
Janis Danisevskis60400fe2020-08-26 15:24:42 -070052
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +000053use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
Janis Danisevskis5ed8c532021-01-11 14:19:42 -080054 HardwareAuthToken::HardwareAuthToken,
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +000055 HardwareAuthenticatorType::HardwareAuthenticatorType, SecurityLevel::SecurityLevel,
Janis Danisevskisc3a496b2021-01-05 10:37:22 -080056};
57use android_hardware_security_secureclock::aidl::android::hardware::security::secureclock::{
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +000058 Timestamp::Timestamp,
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +000059};
Janis Danisevskisc5b210b2020-09-11 13:27:37 -070060use android_system_keystore2::aidl::android::system::keystore2::{
Janis Danisevskis04b02832020-10-26 09:21:40 -070061 Domain::Domain, KeyDescriptor::KeyDescriptor,
Janis Danisevskis60400fe2020-08-26 15:24:42 -070062};
Janis Danisevskisaec14592020-11-12 09:41:49 -080063use lazy_static::lazy_static;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +000064use log::error;
Joel Galenson0891bc12020-07-20 10:37:03 -070065#[cfg(not(test))]
66use rand::prelude::random;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -070067use rusqlite::{
Janis Danisevskisb42fc182020-12-15 08:41:27 -080068 params,
69 types::FromSql,
70 types::FromSqlResult,
71 types::ToSqlOutput,
72 types::{FromSqlError, Value, ValueRef},
Janis Danisevskis5ed8c532021-01-11 14:19:42 -080073 Connection, OptionalExtension, ToSql, Transaction, TransactionBehavior, NO_PARAMS,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -070074};
Janis Danisevskisaec14592020-11-12 09:41:49 -080075use std::{
Janis Danisevskisb42fc182020-12-15 08:41:27 -080076 collections::{HashMap, HashSet},
Janis Danisevskisbf15d732020-12-08 10:35:26 -080077 path::Path,
78 sync::{Condvar, Mutex},
Janis Danisevskisb42fc182020-12-15 08:41:27 -080079 time::{Duration, SystemTime},
Janis Danisevskisaec14592020-11-12 09:41:49 -080080};
Joel Galenson0891bc12020-07-20 10:37:03 -070081#[cfg(test)]
82use tests::random;
Joel Galenson26f4d012020-07-17 14:57:21 -070083
Janis Danisevskisb42fc182020-12-15 08:41:27 -080084impl_metadata!(
85 /// A set of metadata for key entries.
86 #[derive(Debug, Default, Eq, PartialEq)]
87 pub struct KeyMetaData;
88 /// A metadata entry for key entries.
89 #[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
90 pub enum KeyMetaEntry {
91 /// If present, indicates that the sensitive part of key
92 /// is encrypted with another key or a key derived from a password.
93 EncryptedBy(EncryptedBy) with accessor encrypted_by,
94 /// If the blob is password encrypted this field is set to the
95 /// salt used for the key derivation.
96 Salt(Vec<u8>) with accessor salt,
97 /// If the blob is encrypted, this field is set to the initialization vector.
98 Iv(Vec<u8>) with accessor iv,
99 /// If the blob is encrypted, this field holds the AEAD TAG.
100 AeadTag(Vec<u8>) with accessor aead_tag,
101 /// Creation date of a the key entry.
102 CreationDate(DateTime) with accessor creation_date,
103 /// Expiration date for attestation keys.
104 AttestationExpirationDate(DateTime) with accessor attestation_expiration_date,
105 // --- ADD NEW META DATA FIELDS HERE ---
106 // For backwards compatibility add new entries only to
107 // end of this list and above this comment.
108 };
109);
110
111impl KeyMetaData {
112 fn load_from_db(key_id: i64, tx: &Transaction) -> Result<Self> {
113 let mut stmt = tx
114 .prepare(
115 "SELECT tag, data from persistent.keymetadata
116 WHERE keyentryid = ?;",
117 )
118 .context("In KeyMetaData::load_from_db: prepare statement failed.")?;
119
120 let mut metadata: HashMap<i64, KeyMetaEntry> = Default::default();
121
122 let mut rows =
123 stmt.query(params![key_id]).context("In KeyMetaData::load_from_db: query failed.")?;
124 db_utils::with_rows_extract_all(&mut rows, |row| {
125 let db_tag: i64 = row.get(0).context("Failed to read tag.")?;
126 metadata.insert(
127 db_tag,
128 KeyMetaEntry::new_from_sql(db_tag, &SqlField::new(1, &row))
129 .context("Failed to read KeyMetaEntry.")?,
130 );
131 Ok(())
132 })
133 .context("In KeyMetaData::load_from_db.")?;
134
135 Ok(Self { data: metadata })
136 }
137
138 fn store_in_db(&self, key_id: i64, tx: &Transaction) -> Result<()> {
139 let mut stmt = tx
140 .prepare(
141 "INSERT into persistent.keymetadata (keyentryid, tag, data)
142 VALUES (?, ?, ?);",
143 )
144 .context("In KeyMetaData::store_in_db: Failed to prepare statement.")?;
145
146 let iter = self.data.iter();
147 for (tag, entry) in iter {
148 stmt.insert(params![key_id, tag, entry,]).with_context(|| {
149 format!("In KeyMetaData::store_in_db: Failed to insert {:?}", entry)
150 })?;
151 }
152 Ok(())
153 }
154}
155
156/// Indicates the type of the keyentry.
157#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
158pub enum KeyType {
159 /// This is a client key type. These keys are created or imported through the Keystore 2.0
160 /// AIDL interface android.system.keystore2.
161 Client,
162 /// This is a super key type. These keys are created by keystore itself and used to encrypt
163 /// other key blobs to provide LSKF binding.
164 Super,
165 /// This is an attestation key. These keys are created by the remote provisioning mechanism.
166 Attestation,
167}
168
169impl ToSql for KeyType {
170 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
171 Ok(ToSqlOutput::Owned(Value::Integer(match self {
172 KeyType::Client => 0,
173 KeyType::Super => 1,
174 KeyType::Attestation => 2,
175 })))
176 }
177}
178
179impl FromSql for KeyType {
180 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
181 match i64::column_result(value)? {
182 0 => Ok(KeyType::Client),
183 1 => Ok(KeyType::Super),
184 2 => Ok(KeyType::Attestation),
185 v => Err(FromSqlError::OutOfRange(v)),
186 }
187 }
188}
189
190/// Indicates how the sensitive part of this key blob is encrypted.
191#[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
192pub enum EncryptedBy {
193 /// The keyblob is encrypted by a user password.
194 /// In the database this variant is represented as NULL.
195 Password,
196 /// The keyblob is encrypted by another key with wrapped key id.
197 /// In the database this variant is represented as non NULL value
198 /// that is convertible to i64, typically NUMERIC.
199 KeyId(i64),
200}
201
202impl ToSql for EncryptedBy {
203 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
204 match self {
205 Self::Password => Ok(ToSqlOutput::Owned(Value::Null)),
206 Self::KeyId(id) => id.to_sql(),
207 }
208 }
209}
210
211impl FromSql for EncryptedBy {
212 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
213 match value {
214 ValueRef::Null => Ok(Self::Password),
215 _ => Ok(Self::KeyId(i64::column_result(value)?)),
216 }
217 }
218}
219
220/// A database representation of wall clock time. DateTime stores unix epoch time as
221/// i64 in milliseconds.
222#[derive(Debug, Copy, Clone, Default, Eq, PartialEq, Ord, PartialOrd)]
223pub struct DateTime(i64);
224
225/// Error type returned when creating DateTime or converting it from and to
226/// SystemTime.
227#[derive(thiserror::Error, Debug)]
228pub enum DateTimeError {
229 /// This is returned when SystemTime and Duration computations fail.
230 #[error(transparent)]
231 SystemTimeError(#[from] SystemTimeError),
232
233 /// This is returned when type conversions fail.
234 #[error(transparent)]
235 TypeConversion(#[from] std::num::TryFromIntError),
236
237 /// This is returned when checked time arithmetic failed.
238 #[error("Time arithmetic failed.")]
239 TimeArithmetic,
240}
241
242impl DateTime {
243 /// Constructs a new DateTime object denoting the current time. This may fail during
244 /// conversion to unix epoch time and during conversion to the internal i64 representation.
245 pub fn now() -> Result<Self, DateTimeError> {
246 Ok(Self(SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_millis().try_into()?))
247 }
248
249 /// Constructs a new DateTime object from milliseconds.
250 pub fn from_millis_epoch(millis: i64) -> Self {
251 Self(millis)
252 }
253
254 /// Returns unix epoch time in milliseconds.
255 pub fn to_millis_epoch(&self) -> i64 {
256 self.0
257 }
258
259 /// Returns unix epoch time in seconds.
260 pub fn to_secs_epoch(&self) -> i64 {
261 self.0 / 1000
262 }
263}
264
265impl ToSql for DateTime {
266 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
267 Ok(ToSqlOutput::Owned(Value::Integer(self.0)))
268 }
269}
270
271impl FromSql for DateTime {
272 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
273 Ok(Self(i64::column_result(value)?))
274 }
275}
276
277impl TryInto<SystemTime> for DateTime {
278 type Error = DateTimeError;
279
280 fn try_into(self) -> Result<SystemTime, Self::Error> {
281 // We want to construct a SystemTime representation equivalent to self, denoting
282 // a point in time THEN, but we cannot set the time directly. We can only construct
283 // a SystemTime denoting NOW, and we can get the duration between EPOCH and NOW,
284 // and between EPOCH and THEN. With this common reference we can construct the
285 // duration between NOW and THEN which we can add to our SystemTime representation
286 // of NOW to get a SystemTime representation of THEN.
287 // Durations can only be positive, thus the if statement below.
288 let now = SystemTime::now();
289 let now_epoch = now.duration_since(SystemTime::UNIX_EPOCH)?;
290 let then_epoch = Duration::from_millis(self.0.try_into()?);
291 Ok(if now_epoch > then_epoch {
292 // then = now - (now_epoch - then_epoch)
293 now_epoch
294 .checked_sub(then_epoch)
295 .and_then(|d| now.checked_sub(d))
296 .ok_or(DateTimeError::TimeArithmetic)?
297 } else {
298 // then = now + (then_epoch - now_epoch)
299 then_epoch
300 .checked_sub(now_epoch)
301 .and_then(|d| now.checked_add(d))
302 .ok_or(DateTimeError::TimeArithmetic)?
303 })
304 }
305}
306
307impl TryFrom<SystemTime> for DateTime {
308 type Error = DateTimeError;
309
310 fn try_from(t: SystemTime) -> Result<Self, Self::Error> {
311 Ok(Self(t.duration_since(SystemTime::UNIX_EPOCH)?.as_millis().try_into()?))
312 }
313}
314
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800315#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone)]
316enum KeyLifeCycle {
317 /// Existing keys have a key ID but are not fully populated yet.
318 /// This is a transient state. If Keystore finds any such keys when it starts up, it must move
319 /// them to Unreferenced for garbage collection.
320 Existing,
321 /// A live key is fully populated and usable by clients.
322 Live,
323 /// An unreferenced key is scheduled for garbage collection.
324 Unreferenced,
325}
326
327impl ToSql for KeyLifeCycle {
328 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
329 match self {
330 Self::Existing => Ok(ToSqlOutput::Owned(Value::Integer(0))),
331 Self::Live => Ok(ToSqlOutput::Owned(Value::Integer(1))),
332 Self::Unreferenced => Ok(ToSqlOutput::Owned(Value::Integer(2))),
333 }
334 }
335}
336
337impl FromSql for KeyLifeCycle {
338 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
339 match i64::column_result(value)? {
340 0 => Ok(KeyLifeCycle::Existing),
341 1 => Ok(KeyLifeCycle::Live),
342 2 => Ok(KeyLifeCycle::Unreferenced),
343 v => Err(FromSqlError::OutOfRange(v)),
344 }
345 }
346}
347
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700348/// Keys have a KeyMint blob component and optional public certificate and
349/// certificate chain components.
350/// KeyEntryLoadBits is a bitmap that indicates to `KeystoreDB::load_key_entry`
351/// which components shall be loaded from the database if present.
352#[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
353pub struct KeyEntryLoadBits(u32);
354
355impl KeyEntryLoadBits {
356 /// Indicate to `KeystoreDB::load_key_entry` that no component shall be loaded.
357 pub const NONE: KeyEntryLoadBits = Self(0);
358 /// Indicate to `KeystoreDB::load_key_entry` that the KeyMint component shall be loaded.
359 pub const KM: KeyEntryLoadBits = Self(1);
360 /// Indicate to `KeystoreDB::load_key_entry` that the Public components shall be loaded.
361 pub const PUBLIC: KeyEntryLoadBits = Self(2);
362 /// Indicate to `KeystoreDB::load_key_entry` that both components shall be loaded.
363 pub const BOTH: KeyEntryLoadBits = Self(3);
364
365 /// Returns true if this object indicates that the public components shall be loaded.
366 pub const fn load_public(&self) -> bool {
367 self.0 & Self::PUBLIC.0 != 0
368 }
369
370 /// Returns true if the object indicates that the KeyMint component shall be loaded.
371 pub const fn load_km(&self) -> bool {
372 self.0 & Self::KM.0 != 0
373 }
374}
375
Janis Danisevskisaec14592020-11-12 09:41:49 -0800376lazy_static! {
377 static ref KEY_ID_LOCK: KeyIdLockDb = KeyIdLockDb::new();
378}
379
380struct KeyIdLockDb {
381 locked_keys: Mutex<HashSet<i64>>,
382 cond_var: Condvar,
383}
384
385/// A locked key. While a guard exists for a given key id, the same key cannot be loaded
386/// from the database a second time. Most functions manipulating the key blob database
387/// require a KeyIdGuard.
388#[derive(Debug)]
389pub struct KeyIdGuard(i64);
390
391impl KeyIdLockDb {
392 fn new() -> Self {
393 Self { locked_keys: Mutex::new(HashSet::new()), cond_var: Condvar::new() }
394 }
395
396 /// This function blocks until an exclusive lock for the given key entry id can
397 /// be acquired. It returns a guard object, that represents the lifecycle of the
398 /// acquired lock.
399 pub fn get(&self, key_id: i64) -> KeyIdGuard {
400 let mut locked_keys = self.locked_keys.lock().unwrap();
401 while locked_keys.contains(&key_id) {
402 locked_keys = self.cond_var.wait(locked_keys).unwrap();
403 }
404 locked_keys.insert(key_id);
405 KeyIdGuard(key_id)
406 }
407
408 /// This function attempts to acquire an exclusive lock on a given key id. If the
409 /// given key id is already taken the function returns None immediately. If a lock
410 /// can be acquired this function returns a guard object, that represents the
411 /// lifecycle of the acquired lock.
412 pub fn try_get(&self, key_id: i64) -> Option<KeyIdGuard> {
413 let mut locked_keys = self.locked_keys.lock().unwrap();
414 if locked_keys.insert(key_id) {
415 Some(KeyIdGuard(key_id))
416 } else {
417 None
418 }
419 }
420}
421
422impl KeyIdGuard {
423 /// Get the numeric key id of the locked key.
424 pub fn id(&self) -> i64 {
425 self.0
426 }
427}
428
429impl Drop for KeyIdGuard {
430 fn drop(&mut self) {
431 let mut locked_keys = KEY_ID_LOCK.locked_keys.lock().unwrap();
432 locked_keys.remove(&self.0);
Janis Danisevskis7fd53582020-11-23 13:40:34 -0800433 drop(locked_keys);
Janis Danisevskisaec14592020-11-12 09:41:49 -0800434 KEY_ID_LOCK.cond_var.notify_all();
435 }
436}
437
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700438/// This type represents a Keystore 2.0 key entry.
439/// An entry has a unique `id` by which it can be found in the database.
440/// It has a security level field, key parameters, and three optional fields
441/// for the KeyMint blob, public certificate and a public certificate chain.
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800442#[derive(Debug, Default, Eq, PartialEq)]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700443pub struct KeyEntry {
444 id: i64,
445 km_blob: Option<Vec<u8>>,
446 cert: Option<Vec<u8>>,
447 cert_chain: Option<Vec<u8>>,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700448 sec_level: SecurityLevel,
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700449 parameters: Vec<KeyParameter>,
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800450 metadata: KeyMetaData,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700451}
452
453impl KeyEntry {
454 /// Returns the unique id of the Key entry.
455 pub fn id(&self) -> i64 {
456 self.id
457 }
458 /// Exposes the optional KeyMint blob.
459 pub fn km_blob(&self) -> &Option<Vec<u8>> {
460 &self.km_blob
461 }
462 /// Extracts the Optional KeyMint blob.
463 pub fn take_km_blob(&mut self) -> Option<Vec<u8>> {
464 self.km_blob.take()
465 }
466 /// Exposes the optional public certificate.
467 pub fn cert(&self) -> &Option<Vec<u8>> {
468 &self.cert
469 }
470 /// Extracts the optional public certificate.
471 pub fn take_cert(&mut self) -> Option<Vec<u8>> {
472 self.cert.take()
473 }
474 /// Exposes the optional public certificate chain.
475 pub fn cert_chain(&self) -> &Option<Vec<u8>> {
476 &self.cert_chain
477 }
478 /// Extracts the optional public certificate_chain.
479 pub fn take_cert_chain(&mut self) -> Option<Vec<u8>> {
480 self.cert_chain.take()
481 }
482 /// Returns the security level of the key entry.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700483 pub fn sec_level(&self) -> SecurityLevel {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700484 self.sec_level
485 }
Janis Danisevskis04b02832020-10-26 09:21:40 -0700486 /// Exposes the key parameters of this key entry.
487 pub fn key_parameters(&self) -> &Vec<KeyParameter> {
488 &self.parameters
489 }
490 /// Consumes this key entry and extracts the keyparameters from it.
491 pub fn into_key_parameters(self) -> Vec<KeyParameter> {
492 self.parameters
493 }
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800494 /// Exposes the key metadata of this key entry.
495 pub fn metadata(&self) -> &KeyMetaData {
496 &self.metadata
497 }
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700498}
499
500/// Indicates the sub component of a key entry for persistent storage.
501#[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
502pub struct SubComponentType(u32);
503impl SubComponentType {
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800504 /// Persistent identifier for a key blob.
505 pub const KEY_BLOB: SubComponentType = Self(0);
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700506 /// Persistent identifier for a certificate blob.
507 pub const CERT: SubComponentType = Self(1);
508 /// Persistent identifier for a certificate chain blob.
509 pub const CERT_CHAIN: SubComponentType = Self(2);
510}
511
512impl ToSql for SubComponentType {
513 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
514 self.0.to_sql()
515 }
516}
517
518impl FromSql for SubComponentType {
519 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
520 Ok(Self(u32::column_result(value)?))
521 }
522}
523
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700524/// KeystoreDB wraps a connection to an SQLite database and tracks its
525/// ownership. It also implements all of Keystore 2.0's database functionality.
Joel Galenson26f4d012020-07-17 14:57:21 -0700526pub struct KeystoreDB {
Joel Galenson26f4d012020-07-17 14:57:21 -0700527 conn: Connection,
528}
529
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000530/// Database representation of the monotonic time retrieved from the system call clock_gettime with
531/// CLOCK_MONOTONIC_RAW. Stores monotonic time as i64 in seconds.
532#[derive(Debug, Copy, Clone, Default, Eq, PartialEq, Ord, PartialOrd)]
533pub struct MonotonicRawTime(i64);
534
535impl MonotonicRawTime {
536 /// Constructs a new MonotonicRawTime
537 pub fn now() -> Self {
538 Self(get_current_time_in_seconds())
539 }
540
541 /// Returns the integer value of MonotonicRawTime as i64
542 pub fn seconds(&self) -> i64 {
543 self.0
544 }
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800545
546 /// Like i64::checked_sub.
547 pub fn checked_sub(&self, other: &Self) -> Option<Self> {
548 self.0.checked_sub(other.0).map(Self)
549 }
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000550}
551
552impl ToSql for MonotonicRawTime {
553 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
554 Ok(ToSqlOutput::Owned(Value::Integer(self.0)))
555 }
556}
557
558impl FromSql for MonotonicRawTime {
559 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
560 Ok(Self(i64::column_result(value)?))
561 }
562}
563
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000564/// This struct encapsulates the information to be stored in the database about the auth tokens
565/// received by keystore.
566pub struct AuthTokenEntry {
567 auth_token: HardwareAuthToken,
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000568 time_received: MonotonicRawTime,
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000569}
570
571impl AuthTokenEntry {
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000572 fn new(auth_token: HardwareAuthToken, time_received: MonotonicRawTime) -> Self {
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000573 AuthTokenEntry { auth_token, time_received }
574 }
575
576 /// Checks if this auth token satisfies the given authentication information.
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800577 pub fn satisfies(&self, user_secure_ids: &[i64], auth_type: HardwareAuthenticatorType) -> bool {
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000578 user_secure_ids.iter().any(|&sid| {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800579 (sid == self.auth_token.userId || sid == self.auth_token.authenticatorId)
580 && (((auth_type.0 as i32) & (self.auth_token.authenticatorType.0 as i32)) != 0)
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000581 })
582 }
583
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000584 /// Returns the auth token wrapped by the AuthTokenEntry
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800585 pub fn auth_token(&self) -> &HardwareAuthToken {
586 &self.auth_token
587 }
588
589 /// Returns the auth token wrapped by the AuthTokenEntry
590 pub fn take_auth_token(self) -> HardwareAuthToken {
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000591 self.auth_token
592 }
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800593
594 /// Returns the time that this auth token was received.
595 pub fn time_received(&self) -> MonotonicRawTime {
596 self.time_received
597 }
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000598}
599
Joel Galenson26f4d012020-07-17 14:57:21 -0700600impl KeystoreDB {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700601 /// This will create a new database connection connecting the two
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800602 /// files persistent.sqlite and perboot.sqlite in the given directory.
603 /// It also attempts to initialize all of the tables.
604 /// KeystoreDB cannot be used by multiple threads.
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700605 /// Each thread should open their own connection using `thread_local!`.
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800606 pub fn new(db_root: &Path) -> Result<Self> {
607 // Build the path to the sqlite files.
608 let mut persistent_path = db_root.to_path_buf();
609 persistent_path.push("persistent.sqlite");
610 let mut perboot_path = db_root.to_path_buf();
611 perboot_path.push("perboot.sqlite");
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700612
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800613 // Now convert them to strings prefixed with "file:"
614 let mut persistent_path_str = "file:".to_owned();
615 persistent_path_str.push_str(&persistent_path.to_string_lossy());
616 let mut perboot_path_str = "file:".to_owned();
617 perboot_path_str.push_str(&perboot_path.to_string_lossy());
618
619 let conn = Self::make_connection(&persistent_path_str, &perboot_path_str)?;
Janis Danisevskisaea27342021-01-29 08:38:11 -0800620 conn.busy_handler(Some(|_| {
621 std::thread::sleep(std::time::Duration::from_micros(50));
622 true
623 }))
624 .context("In KeystoreDB::new: Failed to set busy handler.")?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800625
626 Self::init_tables(&conn)?;
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700627 Ok(Self { conn })
Joel Galenson2aab4432020-07-22 15:27:57 -0700628 }
629
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700630 fn init_tables(conn: &Connection) -> Result<()> {
631 conn.execute(
632 "CREATE TABLE IF NOT EXISTS persistent.keyentry (
Joel Galenson0891bc12020-07-20 10:37:03 -0700633 id INTEGER UNIQUE,
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800634 key_type INTEGER,
Joel Galenson0891bc12020-07-20 10:37:03 -0700635 domain INTEGER,
636 namespace INTEGER,
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800637 alias BLOB,
638 state INTEGER);",
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700639 NO_PARAMS,
640 )
641 .context("Failed to initialize \"keyentry\" table.")?;
642
643 conn.execute(
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700644 "CREATE TABLE IF NOT EXISTS persistent.blobentry (
645 id INTEGER PRIMARY KEY,
646 subcomponent_type INTEGER,
647 keyentryid INTEGER,
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800648 blob BLOB);",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700649 NO_PARAMS,
650 )
651 .context("Failed to initialize \"blobentry\" table.")?;
652
653 conn.execute(
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700654 "CREATE TABLE IF NOT EXISTS persistent.keyparameter (
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000655 keyentryid INTEGER,
656 tag INTEGER,
657 data ANY,
658 security_level INTEGER);",
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700659 NO_PARAMS,
660 )
661 .context("Failed to initialize \"keyparameter\" table.")?;
662
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700663 conn.execute(
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800664 "CREATE TABLE IF NOT EXISTS persistent.keymetadata (
665 keyentryid INTEGER,
666 tag INTEGER,
667 data ANY);",
668 NO_PARAMS,
669 )
670 .context("Failed to initialize \"keymetadata\" table.")?;
671
672 conn.execute(
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800673 "CREATE TABLE IF NOT EXISTS persistent.grant (
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700674 id INTEGER UNIQUE,
675 grantee INTEGER,
676 keyentryid INTEGER,
677 access_vector INTEGER);",
678 NO_PARAMS,
679 )
680 .context("Failed to initialize \"grant\" table.")?;
681
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000682 //TODO: only drop the following two perboot tables if this is the first start up
683 //during the boot (b/175716626).
684 // conn.execute("DROP TABLE IF EXISTS perboot.authtoken;", NO_PARAMS)
685 // .context("Failed to drop perboot.authtoken table")?;
686 conn.execute(
687 "CREATE TABLE IF NOT EXISTS perboot.authtoken (
688 id INTEGER PRIMARY KEY,
689 challenge INTEGER,
690 user_id INTEGER,
691 auth_id INTEGER,
692 authenticator_type INTEGER,
693 timestamp INTEGER,
694 mac BLOB,
695 time_received INTEGER,
696 UNIQUE(user_id, auth_id, authenticator_type));",
697 NO_PARAMS,
698 )
699 .context("Failed to initialize \"authtoken\" table.")?;
700
701 // conn.execute("DROP TABLE IF EXISTS perboot.metadata;", NO_PARAMS)
702 // .context("Failed to drop perboot.metadata table")?;
703 // metadata table stores certain miscellaneous information required for keystore functioning
704 // during a boot cycle, as key-value pairs.
705 conn.execute(
706 "CREATE TABLE IF NOT EXISTS perboot.metadata (
707 key TEXT,
708 value BLOB,
709 UNIQUE(key));",
710 NO_PARAMS,
711 )
712 .context("Failed to initialize \"metadata\" table.")?;
Joel Galenson0891bc12020-07-20 10:37:03 -0700713 Ok(())
714 }
715
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700716 fn make_connection(persistent_file: &str, perboot_file: &str) -> Result<Connection> {
717 let conn =
718 Connection::open_in_memory().context("Failed to initialize SQLite connection.")?;
719
720 conn.execute("ATTACH DATABASE ? as persistent;", params![persistent_file])
721 .context("Failed to attach database persistent.")?;
722 conn.execute("ATTACH DATABASE ? as perboot;", params![perboot_file])
723 .context("Failed to attach database perboot.")?;
724
725 Ok(conn)
726 }
727
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800728 /// Get one unreferenced key. There is no particular order in which the keys are returned.
729 fn get_unreferenced_key_id(tx: &Transaction) -> Result<Option<i64>> {
730 tx.query_row(
731 "SELECT id FROM persistent.keyentry WHERE state = ?",
732 params![KeyLifeCycle::Unreferenced],
733 |row| row.get(0),
734 )
735 .optional()
736 .context("In get_unreferenced_key_id: Trying to get unreferenced key id.")
737 }
738
739 /// Returns a key id guard and key entry for one unreferenced key entry. Of the optional
740 /// fields of the key entry only the km_blob field will be populated. This is required
741 /// to subject the blob to its KeyMint instance for deletion.
742 pub fn get_unreferenced_key(&mut self) -> Result<Option<(KeyIdGuard, KeyEntry)>> {
743 self.with_transaction(TransactionBehavior::Deferred, |tx| {
744 let key_id = match Self::get_unreferenced_key_id(tx)
745 .context("Trying to get unreferenced key id")?
746 {
747 None => return Ok(None),
748 Some(id) => KEY_ID_LOCK.try_get(id).ok_or_else(KsError::sys).context(concat!(
749 "A key id lock was held for an unreferenced key. ",
750 "This should never happen."
751 ))?,
752 };
753 let key_entry = Self::load_key_components(tx, KeyEntryLoadBits::KM, key_id.id())
754 .context("Trying to get key components.")?;
755 Ok(Some((key_id, key_entry)))
756 })
757 .context("In get_unreferenced_key.")
758 }
759
760 /// This function purges all remnants of a key entry from the database.
761 /// Important: This does not check if the key was unreferenced, nor does it
762 /// subject the key to its KeyMint instance for permanent invalidation.
763 /// This function should only be called by the garbage collector.
764 /// To delete a key call `mark_unreferenced`, which transitions the key to the unreferenced
765 /// state, deletes all grants to the key, and notifies the garbage collector.
766 /// The garbage collector will:
767 /// 1. Call get_unreferenced_key.
768 /// 2. Determine the proper way to dispose of sensitive key material, e.g., call
769 /// `KeyMintDevice::delete()`.
770 /// 3. Call `purge_key_entry`.
771 pub fn purge_key_entry(&mut self, key_id: KeyIdGuard) -> Result<()> {
772 self.with_transaction(TransactionBehavior::Immediate, |tx| {
773 tx.execute("DELETE FROM persistent.keyentry WHERE id = ?;", params![key_id.id()])
774 .context("Trying to delete keyentry.")?;
775 tx.execute(
776 "DELETE FROM persistent.blobentry WHERE keyentryid = ?;",
777 params![key_id.id()],
778 )
779 .context("Trying to delete blobentries.")?;
780 tx.execute(
781 "DELETE FROM persistent.keymetadata WHERE keyentryid = ?;",
782 params![key_id.id()],
783 )
784 .context("Trying to delete keymetadata.")?;
785 tx.execute(
786 "DELETE FROM persistent.keyparameter WHERE keyentryid = ?;",
787 params![key_id.id()],
788 )
789 .context("Trying to delete keyparameters.")?;
790 let grants_deleted = tx
791 .execute("DELETE FROM persistent.grant WHERE keyentryid = ?;", params![key_id.id()])
792 .context("Trying to delete grants.")?;
793 if grants_deleted != 0 {
794 log::error!("Purged key that still had grants. This should not happen.");
795 }
796 Ok(())
797 })
798 .context("In purge_key_entry.")
799 }
800
801 /// This maintenance function should be called only once before the database is used for the
802 /// first time. It restores the invariant that `KeyLifeCycle::Existing` is a transient state.
803 /// The function transitions all key entries from Existing to Unreferenced unconditionally and
804 /// returns the number of rows affected. If this returns a value greater than 0, it means that
805 /// Keystore crashed at some point during key generation. Callers may want to log such
806 /// occurrences.
807 /// Unlike with `mark_unreferenced`, we don't need to purge grants, because only keys that made
808 /// it to `KeyLifeCycle::Live` may have grants.
809 pub fn cleanup_leftovers(&mut self) -> Result<usize> {
810 self.conn
811 .execute(
812 "UPDATE persistent.keyentry SET state = ? WHERE state = ?;",
813 params![KeyLifeCycle::Unreferenced, KeyLifeCycle::Existing],
814 )
815 .context("In cleanup_leftovers.")
816 }
817
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800818 /// Atomically loads a key entry and associated metadata or creates it using the
819 /// callback create_new_key callback. The callback is called during a database
820 /// transaction. This means that implementers should be mindful about using
821 /// blocking operations such as IPC or grabbing mutexes.
822 pub fn get_or_create_key_with<F>(
823 &mut self,
824 domain: Domain,
825 namespace: i64,
826 alias: &str,
827 create_new_key: F,
828 ) -> Result<(KeyIdGuard, KeyEntry)>
829 where
830 F: FnOnce() -> Result<(Vec<u8>, KeyMetaData)>,
831 {
832 let tx = self
833 .conn
834 .transaction_with_behavior(TransactionBehavior::Immediate)
835 .context("In get_or_create_key_with: Failed to initialize transaction.")?;
836
837 let id = {
838 let mut stmt = tx
839 .prepare(
840 "SELECT id FROM persistent.keyentry
841 WHERE
842 key_type = ?
843 AND domain = ?
844 AND namespace = ?
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800845 AND alias = ?
846 AND state = ?;",
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800847 )
848 .context("In get_or_create_key_with: Failed to select from keyentry table.")?;
849 let mut rows = stmt
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800850 .query(params![KeyType::Super, domain.0, namespace, alias, KeyLifeCycle::Live])
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800851 .context("In get_or_create_key_with: Failed to query from keyentry table.")?;
852
853 db_utils::with_rows_extract_one(&mut rows, |row| {
854 Ok(match row {
855 Some(r) => r.get(0).context("Failed to unpack id.")?,
856 None => None,
857 })
858 })
859 .context("In get_or_create_key_with.")?
860 };
861
862 let (id, entry) = match id {
863 Some(id) => (
864 id,
865 Self::load_key_components(&tx, KeyEntryLoadBits::KM, id)
866 .context("In get_or_create_key_with.")?,
867 ),
868
869 None => {
870 let id = Self::insert_with_retry(|id| {
871 tx.execute(
872 "INSERT into persistent.keyentry
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800873 (id, key_type, domain, namespace, alias, state)
874 VALUES(?, ?, ?, ?, ?, ?);",
875 params![id, KeyType::Super, domain.0, namespace, alias, KeyLifeCycle::Live],
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800876 )
877 })
878 .context("In get_or_create_key_with.")?;
879
880 let (blob, metadata) = create_new_key().context("In get_or_create_key_with.")?;
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800881 Self::insert_blob_internal(&tx, id, SubComponentType::KEY_BLOB, &blob)
882 .context("In get_of_create_key_with.")?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800883 metadata.store_in_db(id, &tx).context("In get_or_create_key_with.")?;
884 (id, KeyEntry { id, km_blob: Some(blob), metadata, ..Default::default() })
885 }
886 };
887 tx.commit().context("In get_or_create_key_with: Failed to commit transaction.")?;
888 Ok((KEY_ID_LOCK.get(id), entry))
889 }
890
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800891 /// Creates a transaction with the given behavior and executes f with the new transaction.
892 /// The transaction is committed only if f returns Ok.
893 fn with_transaction<T, F>(&mut self, behavior: TransactionBehavior, f: F) -> Result<T>
894 where
895 F: FnOnce(&Transaction) -> Result<T>,
896 {
897 let tx = self
898 .conn
899 .transaction_with_behavior(behavior)
900 .context("In with_transaction: Failed to initialize transaction.")?;
901 f(&tx).and_then(|result| {
902 tx.commit().context("In with_transaction: Failed to commit transaction.")?;
903 Ok(result)
904 })
905 }
906
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700907 /// Creates a new key entry and allocates a new randomized id for the new key.
908 /// The key id gets associated with a domain and namespace but not with an alias.
909 /// To complete key generation `rebind_alias` should be called after all of the
910 /// key artifacts, i.e., blobs and parameters have been associated with the new
911 /// key id. Finalizing with `rebind_alias` makes the creation of a new key entry
912 /// atomic even if key generation is not.
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800913 pub fn create_key_entry(&mut self, domain: Domain, namespace: i64) -> Result<KeyIdGuard> {
914 self.with_transaction(TransactionBehavior::Immediate, |tx| {
915 Self::create_key_entry_internal(tx, domain, namespace)
916 })
917 .context("In create_key_entry.")
918 }
919
920 fn create_key_entry_internal(
921 tx: &Transaction,
922 domain: Domain,
923 namespace: i64,
924 ) -> Result<KeyIdGuard> {
Joel Galenson0891bc12020-07-20 10:37:03 -0700925 match domain {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700926 Domain::APP | Domain::SELINUX => {}
Joel Galenson0891bc12020-07-20 10:37:03 -0700927 _ => {
928 return Err(KsError::sys())
929 .context(format!("Domain {:?} must be either App or SELinux.", domain));
930 }
931 }
Janis Danisevskisaec14592020-11-12 09:41:49 -0800932 Ok(KEY_ID_LOCK.get(
933 Self::insert_with_retry(|id| {
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800934 tx.execute(
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800935 "INSERT into persistent.keyentry
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800936 (id, key_type, domain, namespace, alias, state)
937 VALUES(?, ?, ?, ?, NULL, ?);",
938 params![
939 id,
940 KeyType::Client,
941 domain.0 as u32,
942 namespace,
943 KeyLifeCycle::Existing
944 ],
Janis Danisevskisaec14592020-11-12 09:41:49 -0800945 )
946 })
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800947 .context("In create_key_entry_internal")?,
Janis Danisevskisaec14592020-11-12 09:41:49 -0800948 ))
Joel Galenson26f4d012020-07-17 14:57:21 -0700949 }
Joel Galenson33c04ad2020-08-03 11:04:38 -0700950
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700951 /// Inserts a new blob and associates it with the given key id. Each blob
952 /// has a sub component type and a security level.
953 /// Each key can have one of each sub component type associated. If more
954 /// are added only the most recent can be retrieved, and superseded blobs
955 /// will get garbage collected. The security level field of components
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800956 /// other than `SubComponentType::KEY_BLOB` are ignored.
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700957 pub fn insert_blob(
958 &mut self,
Janis Danisevskisaec14592020-11-12 09:41:49 -0800959 key_id: &KeyIdGuard,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700960 sc_type: SubComponentType,
961 blob: &[u8],
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700962 ) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800963 self.with_transaction(TransactionBehavior::Immediate, |tx| {
964 Self::insert_blob_internal(&tx, key_id.0, sc_type, blob)
965 })
966 .context("In insert_blob.")
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800967 }
968
969 fn insert_blob_internal(
970 tx: &Transaction,
971 key_id: i64,
972 sc_type: SubComponentType,
973 blob: &[u8],
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800974 ) -> Result<()> {
975 tx.execute(
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800976 "INSERT into persistent.blobentry (subcomponent_type, keyentryid, blob)
977 VALUES (?, ?, ?);",
978 params![sc_type, key_id, blob],
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800979 )
980 .context("In insert_blob_internal: Failed to insert blob.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700981 Ok(())
982 }
983
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700984 /// Inserts a collection of key parameters into the `persistent.keyparameter` table
985 /// and associates them with the given `key_id`.
986 pub fn insert_keyparameter<'a>(
987 &mut self,
Janis Danisevskisaec14592020-11-12 09:41:49 -0800988 key_id: &KeyIdGuard,
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700989 params: impl IntoIterator<Item = &'a KeyParameter>,
990 ) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800991 self.with_transaction(TransactionBehavior::Immediate, |tx| {
992 Self::insert_keyparameter_internal(tx, key_id, params)
993 })
994 .context("In insert_keyparameter.")
995 }
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700996
Janis Danisevskis93927dd2020-12-23 12:23:08 -0800997 fn insert_keyparameter_internal<'a>(
998 tx: &Transaction,
999 key_id: &KeyIdGuard,
1000 params: impl IntoIterator<Item = &'a KeyParameter>,
1001 ) -> Result<()> {
1002 let mut stmt = tx
1003 .prepare(
1004 "INSERT into persistent.keyparameter (keyentryid, tag, data, security_level)
1005 VALUES (?, ?, ?, ?);",
1006 )
1007 .context("In insert_keyparameter_internal: Failed to prepare statement.")?;
1008
1009 let iter = params.into_iter();
1010 for p in iter {
1011 stmt.insert(params![
1012 key_id.0,
1013 p.get_tag().0,
1014 p.key_parameter_value(),
1015 p.security_level().0
1016 ])
1017 .with_context(|| {
1018 format!("In insert_keyparameter_internal: Failed to insert {:?}", p)
1019 })?;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001020 }
1021 Ok(())
1022 }
1023
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001024 /// Insert a set of key entry specific metadata into the database.
1025 pub fn insert_key_metadata(
1026 &mut self,
1027 key_id: &KeyIdGuard,
1028 metadata: &KeyMetaData,
1029 ) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001030 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1031 metadata.store_in_db(key_id.0, &tx)
1032 })
1033 .context("In insert_key_metadata.")
1034 }
1035
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001036 /// Updates the alias column of the given key id `newid` with the given alias,
1037 /// and atomically, removes the alias, domain, and namespace from another row
1038 /// with the same alias-domain-namespace tuple if such row exits.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001039 /// Returns Ok(true) if an old key was marked unreferenced as a hint to the garbage
1040 /// collector.
1041 fn rebind_alias(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001042 tx: &Transaction,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001043 newid: &KeyIdGuard,
Joel Galenson33c04ad2020-08-03 11:04:38 -07001044 alias: &str,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001045 domain: Domain,
Joel Galenson33c04ad2020-08-03 11:04:38 -07001046 namespace: i64,
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001047 ) -> Result<bool> {
Joel Galenson33c04ad2020-08-03 11:04:38 -07001048 match domain {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001049 Domain::APP | Domain::SELINUX => {}
Joel Galenson33c04ad2020-08-03 11:04:38 -07001050 _ => {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001051 return Err(KsError::sys()).context(format!(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001052 "In rebind_alias: Domain {:?} must be either App or SELinux.",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001053 domain
1054 ));
Joel Galenson33c04ad2020-08-03 11:04:38 -07001055 }
1056 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001057 let updated = tx
1058 .execute(
1059 "UPDATE persistent.keyentry
1060 SET alias = NULL, domain = NULL, namespace = NULL, state = ?
Joel Galenson33c04ad2020-08-03 11:04:38 -07001061 WHERE alias = ? AND domain = ? AND namespace = ?;",
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001062 params![KeyLifeCycle::Unreferenced, alias, domain.0 as u32, namespace],
1063 )
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001064 .context("In rebind_alias: Failed to rebind existing entry.")?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07001065 let result = tx
1066 .execute(
1067 "UPDATE persistent.keyentry
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001068 SET alias = ?, state = ?
1069 WHERE id = ? AND domain = ? AND namespace = ? AND state = ?;",
1070 params![
1071 alias,
1072 KeyLifeCycle::Live,
1073 newid.0,
1074 domain.0 as u32,
1075 namespace,
1076 KeyLifeCycle::Existing
1077 ],
Joel Galenson33c04ad2020-08-03 11:04:38 -07001078 )
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001079 .context("In rebind_alias: Failed to set alias.")?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07001080 if result != 1 {
Joel Galenson33c04ad2020-08-03 11:04:38 -07001081 return Err(KsError::sys()).context(format!(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001082 "In rebind_alias: Expected to update a single entry but instead updated {}.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07001083 result
1084 ));
1085 }
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001086 Ok(updated != 0)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001087 }
1088
1089 /// Store a new key in a single transaction.
1090 /// The function creates a new key entry, populates the blob, key parameter, and metadata
1091 /// fields, and rebinds the given alias to the new key.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001092 /// The boolean returned is a hint for the garbage collector. If true, a key was replaced,
1093 /// is now unreferenced and needs to be collected.
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001094 pub fn store_new_key<'a>(
1095 &mut self,
1096 key: KeyDescriptor,
1097 params: impl IntoIterator<Item = &'a KeyParameter>,
1098 blob: &[u8],
1099 cert: Option<&[u8]>,
1100 cert_chain: Option<&[u8]>,
1101 metadata: &KeyMetaData,
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001102 ) -> Result<(bool, KeyIdGuard)> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001103 let (alias, domain, namespace) = match key {
1104 KeyDescriptor { alias: Some(alias), domain: Domain::APP, nspace, blob: None }
1105 | KeyDescriptor { alias: Some(alias), domain: Domain::SELINUX, nspace, blob: None } => {
1106 (alias, key.domain, nspace)
1107 }
1108 _ => {
1109 return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT))
1110 .context("In store_new_key: Need alias and domain must be APP or SELINUX.")
1111 }
1112 };
1113 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1114 let key_id = Self::create_key_entry_internal(tx, domain, namespace)
1115 .context("Trying to create new key entry.")?;
1116 Self::insert_blob_internal(tx, key_id.id(), SubComponentType::KEY_BLOB, blob)
1117 .context("Trying to insert the key blob.")?;
1118 if let Some(cert) = cert {
1119 Self::insert_blob_internal(tx, key_id.id(), SubComponentType::CERT, cert)
1120 .context("Trying to insert the certificate.")?;
1121 }
1122 if let Some(cert_chain) = cert_chain {
1123 Self::insert_blob_internal(
1124 tx,
1125 key_id.id(),
1126 SubComponentType::CERT_CHAIN,
1127 cert_chain,
1128 )
1129 .context("Trying to insert the certificate chain.")?;
1130 }
1131 Self::insert_keyparameter_internal(tx, &key_id, params)
1132 .context("Trying to insert key parameters.")?;
1133 metadata.store_in_db(key_id.id(), tx).context("Tryin to insert key metadata.")?;
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001134 let need_gc = Self::rebind_alias(tx, &key_id, &alias, domain, namespace)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001135 .context("Trying to rebind alias.")?;
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001136 Ok((need_gc, key_id))
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001137 })
1138 .context("In store_new_key.")
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001139 }
1140
1141 // Helper function loading the key_id given the key descriptor
1142 // tuple comprising domain, namespace, and alias.
1143 // Requires a valid transaction.
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001144 fn load_key_entry_id(tx: &Transaction, key: &KeyDescriptor, key_type: KeyType) -> Result<i64> {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001145 let alias = key
1146 .alias
1147 .as_ref()
1148 .map_or_else(|| Err(KsError::sys()), Ok)
1149 .context("In load_key_entry_id: Alias must be specified.")?;
1150 let mut stmt = tx
1151 .prepare(
1152 "SELECT id FROM persistent.keyentry
1153 WHERE
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001154 key_type = ?
1155 AND domain = ?
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001156 AND namespace = ?
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001157 AND alias = ?
1158 AND state = ?;",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001159 )
1160 .context("In load_key_entry_id: Failed to select from keyentry table.")?;
1161 let mut rows = stmt
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001162 .query(params![key_type, key.domain.0 as u32, key.nspace, alias, KeyLifeCycle::Live])
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001163 .context("In load_key_entry_id: Failed to read from keyentry table.")?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08001164 db_utils::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001165 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001166 .get(0)
1167 .context("Failed to unpack id.")
1168 })
1169 .context("In load_key_entry_id.")
1170 }
1171
1172 /// This helper function completes the access tuple of a key, which is required
1173 /// to perform access control. The strategy depends on the `domain` field in the
1174 /// key descriptor.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001175 /// * Domain::SELINUX: The access tuple is complete and this function only loads
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001176 /// the key_id for further processing.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001177 /// * Domain::APP: Like Domain::SELINUX, but the tuple is completed by `caller_uid`
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001178 /// which serves as the namespace.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001179 /// * Domain::GRANT: The grant table is queried for the `key_id` and the
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001180 /// `access_vector`.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001181 /// * Domain::KEY_ID: The keyentry table is queried for the owning `domain` and
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001182 /// `namespace`.
1183 /// In each case the information returned is sufficient to perform the access
1184 /// check and the key id can be used to load further key artifacts.
1185 fn load_access_tuple(
1186 tx: &Transaction,
1187 key: KeyDescriptor,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001188 key_type: KeyType,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001189 caller_uid: u32,
1190 ) -> Result<(i64, KeyDescriptor, Option<KeyPermSet>)> {
1191 match key.domain {
1192 // Domain App or SELinux. In this case we load the key_id from
1193 // the keyentry database for further loading of key components.
1194 // We already have the full access tuple to perform access control.
1195 // The only distinction is that we use the caller_uid instead
1196 // of the caller supplied namespace if the domain field is
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001197 // Domain::APP.
1198 Domain::APP | Domain::SELINUX => {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001199 let mut access_key = key;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001200 if access_key.domain == Domain::APP {
1201 access_key.nspace = caller_uid as i64;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001202 }
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001203 let key_id = Self::load_key_entry_id(&tx, &access_key, key_type)
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001204 .with_context(|| format!("With key.domain = {:?}.", access_key.domain))?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001205
1206 Ok((key_id, access_key, None))
1207 }
1208
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001209 // Domain::GRANT. In this case we load the key_id and the access_vector
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001210 // from the grant table.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001211 Domain::GRANT => {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001212 let mut stmt = tx
1213 .prepare(
Janis Danisevskisbf15d732020-12-08 10:35:26 -08001214 "SELECT keyentryid, access_vector FROM persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001215 WHERE grantee = ? AND id = ?;",
1216 )
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001217 .context("Domain::GRANT prepare statement failed")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001218 let mut rows = stmt
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001219 .query(params![caller_uid as i64, key.nspace])
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001220 .context("Domain:Grant: query failed.")?;
1221 let (key_id, access_vector): (i64, i32) =
Janis Danisevskisbf15d732020-12-08 10:35:26 -08001222 db_utils::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001223 let r =
1224 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001225 Ok((
1226 r.get(0).context("Failed to unpack key_id.")?,
1227 r.get(1).context("Failed to unpack access_vector.")?,
1228 ))
1229 })
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001230 .context("Domain::GRANT.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001231 Ok((key_id, key, Some(access_vector.into())))
1232 }
1233
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001234 // Domain::KEY_ID. In this case we load the domain and namespace from the
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001235 // keyentry database because we need them for access control.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001236 Domain::KEY_ID => {
Janis Danisevskis45760022021-01-19 16:34:10 -08001237 let (domain, namespace): (Domain, i64) = {
1238 let mut stmt = tx
1239 .prepare(
1240 "SELECT domain, namespace FROM persistent.keyentry
1241 WHERE
1242 id = ?
1243 AND state = ?;",
1244 )
1245 .context("Domain::KEY_ID: prepare statement failed")?;
1246 let mut rows = stmt
1247 .query(params![key.nspace, KeyLifeCycle::Live])
1248 .context("Domain::KEY_ID: query failed.")?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08001249 db_utils::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001250 let r =
1251 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001252 Ok((
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001253 Domain(r.get(0).context("Failed to unpack domain.")?),
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001254 r.get(1).context("Failed to unpack namespace.")?,
1255 ))
1256 })
Janis Danisevskis45760022021-01-19 16:34:10 -08001257 .context("Domain::KEY_ID.")?
1258 };
1259
1260 // We may use a key by id after loading it by grant.
1261 // In this case we have to check if the caller has a grant for this particular
1262 // key. We can skip this if we already know that the caller is the owner.
1263 // But we cannot know this if domain is anything but App. E.g. in the case
1264 // of Domain::SELINUX we have to speculatively check for grants because we have to
1265 // consult the SEPolicy before we know if the caller is the owner.
1266 let access_vector: Option<KeyPermSet> =
1267 if domain != Domain::APP || namespace != caller_uid as i64 {
1268 let access_vector: Option<i32> = tx
1269 .query_row(
1270 "SELECT access_vector FROM persistent.grant
1271 WHERE grantee = ? AND keyentryid = ?;",
1272 params![caller_uid as i64, key.nspace],
1273 |row| row.get(0),
1274 )
1275 .optional()
1276 .context("Domain::KEY_ID: query grant failed.")?;
1277 access_vector.map(|p| p.into())
1278 } else {
1279 None
1280 };
1281
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001282 let key_id = key.nspace;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001283 let mut access_key = key;
1284 access_key.domain = domain;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001285 access_key.nspace = namespace;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001286
Janis Danisevskis45760022021-01-19 16:34:10 -08001287 Ok((key_id, access_key, access_vector))
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001288 }
1289 _ => Err(anyhow!(KsError::sys())),
1290 }
1291 }
1292
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001293 fn load_blob_components(
1294 key_id: i64,
1295 load_bits: KeyEntryLoadBits,
1296 tx: &Transaction,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001297 ) -> Result<(Option<Vec<u8>>, Option<Vec<u8>>, Option<Vec<u8>>)> {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001298 let mut stmt = tx
1299 .prepare(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001300 "SELECT MAX(id), subcomponent_type, blob FROM persistent.blobentry
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001301 WHERE keyentryid = ? GROUP BY subcomponent_type;",
1302 )
1303 .context("In load_blob_components: prepare statement failed.")?;
1304
1305 let mut rows =
1306 stmt.query(params![key_id]).context("In load_blob_components: query failed.")?;
1307
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001308 let mut km_blob: Option<Vec<u8>> = None;
1309 let mut cert_blob: Option<Vec<u8>> = None;
1310 let mut cert_chain_blob: Option<Vec<u8>> = None;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08001311 db_utils::with_rows_extract_all(&mut rows, |row| {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001312 let sub_type: SubComponentType =
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001313 row.get(1).context("Failed to extract subcomponent_type.")?;
1314 match (sub_type, load_bits.load_public(), load_bits.load_km()) {
1315 (SubComponentType::KEY_BLOB, _, true) => {
1316 km_blob = Some(row.get(2).context("Failed to extract KM blob.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001317 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001318 (SubComponentType::CERT, true, _) => {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001319 cert_blob =
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001320 Some(row.get(2).context("Failed to extract public certificate blob.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001321 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001322 (SubComponentType::CERT_CHAIN, true, _) => {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001323 cert_chain_blob =
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001324 Some(row.get(2).context("Failed to extract certificate chain blob.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001325 }
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001326 (SubComponentType::CERT, _, _)
1327 | (SubComponentType::CERT_CHAIN, _, _)
1328 | (SubComponentType::KEY_BLOB, _, _) => {}
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001329 _ => Err(KsError::sys()).context("Unknown subcomponent type.")?,
1330 }
1331 Ok(())
1332 })
1333 .context("In load_blob_components.")?;
1334
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001335 Ok((km_blob, cert_blob, cert_chain_blob))
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001336 }
1337
1338 fn load_key_parameters(key_id: i64, tx: &Transaction) -> Result<Vec<KeyParameter>> {
1339 let mut stmt = tx
1340 .prepare(
1341 "SELECT tag, data, security_level from persistent.keyparameter
1342 WHERE keyentryid = ?;",
1343 )
1344 .context("In load_key_parameters: prepare statement failed.")?;
1345
1346 let mut parameters: Vec<KeyParameter> = Vec::new();
1347
1348 let mut rows =
1349 stmt.query(params![key_id]).context("In load_key_parameters: query failed.")?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08001350 db_utils::with_rows_extract_all(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001351 let tag = Tag(row.get(0).context("Failed to read tag.")?);
1352 let sec_level = SecurityLevel(row.get(2).context("Failed to read sec_level.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001353 parameters.push(
1354 KeyParameter::new_from_sql(tag, &SqlField::new(1, &row), sec_level)
1355 .context("Failed to read KeyParameter.")?,
1356 );
1357 Ok(())
1358 })
1359 .context("In load_key_parameters.")?;
1360
1361 Ok(parameters)
1362 }
1363
Qi Wub9433b52020-12-01 14:52:46 +08001364 /// Decrements the usage count of a limited use key. This function first checks whether the
1365 /// usage has been exhausted, if not, decreases the usage count. If the usage count reaches
1366 /// zero, the key also gets marked unreferenced and scheduled for deletion.
1367 /// Returns Ok(true) if the key was marked unreferenced as a hint to the garbage collector.
1368 pub fn check_and_update_key_usage_count(&mut self, key_id: i64) -> Result<bool> {
1369 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1370 let limit: Option<i32> = tx
1371 .query_row(
1372 "SELECT data FROM persistent.keyparameter WHERE keyentryid = ? AND tag = ?;",
1373 params![key_id, Tag::USAGE_COUNT_LIMIT.0],
1374 |row| row.get(0),
1375 )
1376 .optional()
1377 .context("Trying to load usage count")?;
1378
1379 let limit = limit
1380 .ok_or(KsError::Km(ErrorCode::INVALID_KEY_BLOB))
1381 .context("The Key no longer exists. Key is exhausted.")?;
1382
1383 tx.execute(
1384 "UPDATE persistent.keyparameter
1385 SET data = data - 1
1386 WHERE keyentryid = ? AND tag = ? AND data > 0;",
1387 params![key_id, Tag::USAGE_COUNT_LIMIT.0],
1388 )
1389 .context("Failed to update key usage count.")?;
1390
1391 match limit {
1392 1 => Self::mark_unreferenced(tx, key_id)
1393 .context("Trying to mark limited use key for deletion."),
1394 0 => Err(KsError::Km(ErrorCode::INVALID_KEY_BLOB)).context("Key is exhausted."),
1395 _ => Ok(false),
1396 }
1397 })
1398 .context("In check_and_update_key_usage_count.")
1399 }
1400
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001401 /// Load a key entry by the given key descriptor.
1402 /// It uses the `check_permission` callback to verify if the access is allowed
1403 /// given the key access tuple read from the database using `load_access_tuple`.
1404 /// With `load_bits` the caller may specify which blobs shall be loaded from
1405 /// the blob database.
1406 pub fn load_key_entry(
1407 &mut self,
1408 key: KeyDescriptor,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001409 key_type: KeyType,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001410 load_bits: KeyEntryLoadBits,
1411 caller_uid: u32,
1412 check_permission: impl FnOnce(&KeyDescriptor, Option<KeyPermSet>) -> Result<()>,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001413 ) -> Result<(KeyIdGuard, KeyEntry)> {
1414 // KEY ID LOCK 1/2
1415 // If we got a key descriptor with a key id we can get the lock right away.
1416 // Otherwise we have to defer it until we know the key id.
1417 let key_id_guard = match key.domain {
1418 Domain::KEY_ID => Some(KEY_ID_LOCK.get(key.nspace)),
1419 _ => None,
1420 };
1421
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001422 let tx = self
1423 .conn
Janis Danisevskisaec14592020-11-12 09:41:49 -08001424 .unchecked_transaction()
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001425 .context("In load_key_entry: Failed to initialize transaction.")?;
1426
1427 // Load the key_id and complete the access control tuple.
1428 let (key_id, access_key_descriptor, access_vector) =
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001429 Self::load_access_tuple(&tx, key, key_type, caller_uid)
1430 .context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001431
1432 // Perform access control. It is vital that we return here if the permission is denied.
1433 // So do not touch that '?' at the end.
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001434 check_permission(&access_key_descriptor, access_vector).context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001435
Janis Danisevskisaec14592020-11-12 09:41:49 -08001436 // KEY ID LOCK 2/2
1437 // If we did not get a key id lock by now, it was because we got a key descriptor
1438 // without a key id. At this point we got the key id, so we can try and get a lock.
1439 // However, we cannot block here, because we are in the middle of the transaction.
1440 // So first we try to get the lock non blocking. If that fails, we roll back the
1441 // transaction and block until we get the lock. After we successfully got the lock,
1442 // we start a new transaction and load the access tuple again.
1443 //
1444 // We don't need to perform access control again, because we already established
1445 // that the caller had access to the given key. But we need to make sure that the
1446 // key id still exists. So we have to load the key entry by key id this time.
1447 let (key_id_guard, tx) = match key_id_guard {
1448 None => match KEY_ID_LOCK.try_get(key_id) {
1449 None => {
1450 // Roll back the transaction.
1451 tx.rollback().context("In load_key_entry: Failed to roll back transaction.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001452
Janis Danisevskisaec14592020-11-12 09:41:49 -08001453 // Block until we have a key id lock.
1454 let key_id_guard = KEY_ID_LOCK.get(key_id);
1455
1456 // Create a new transaction.
1457 let tx = self.conn.unchecked_transaction().context(
1458 "In load_key_entry: Failed to initialize transaction. (deferred key lock)",
1459 )?;
1460
1461 Self::load_access_tuple(
1462 &tx,
1463 // This time we have to load the key by the retrieved key id, because the
1464 // alias may have been rebound after we rolled back the transaction.
1465 KeyDescriptor {
1466 domain: Domain::KEY_ID,
1467 nspace: key_id,
1468 ..Default::default()
1469 },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001470 key_type,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001471 caller_uid,
1472 )
1473 .context("In load_key_entry. (deferred key lock)")?;
1474 (key_id_guard, tx)
1475 }
1476 Some(l) => (l, tx),
1477 },
1478 Some(key_id_guard) => (key_id_guard, tx),
1479 };
1480
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001481 let key_entry = Self::load_key_components(&tx, load_bits, key_id_guard.id())
1482 .context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001483
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001484 tx.commit().context("In load_key_entry: Failed to commit transaction.")?;
1485
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001486 Ok((key_id_guard, key_entry))
1487 }
1488
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001489 fn mark_unreferenced(tx: &Transaction, key_id: i64) -> Result<bool> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001490 let updated = tx
1491 .execute(
1492 "UPDATE persistent.keyentry SET state = ? WHERE id = ?;",
1493 params![KeyLifeCycle::Unreferenced, key_id],
1494 )
1495 .context("In mark_unreferenced: Failed to update state of key entry.")?;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001496 tx.execute("DELETE from persistent.grant WHERE keyentryid = ?;", params![key_id])
1497 .context("In mark_unreferenced: Failed to drop grants.")?;
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001498 Ok(updated != 0)
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001499 }
1500
1501 /// Marks the given key as unreferenced and removes all of the grants to this key.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001502 /// Returns Ok(true) if a key was marked unreferenced as a hint for the garbage collector.
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001503 pub fn unbind_key(
1504 &mut self,
1505 key: KeyDescriptor,
1506 key_type: KeyType,
1507 caller_uid: u32,
1508 check_permission: impl FnOnce(&KeyDescriptor, Option<KeyPermSet>) -> Result<()>,
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001509 ) -> Result<bool> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001510 self.with_transaction(TransactionBehavior::Immediate, |tx| {
1511 let (key_id, access_key_descriptor, access_vector) =
1512 Self::load_access_tuple(tx, key, key_type, caller_uid)
1513 .context("Trying to get access tuple.")?;
1514
1515 // Perform access control. It is vital that we return here if the permission is denied.
1516 // So do not touch that '?' at the end.
1517 check_permission(&access_key_descriptor, access_vector)
1518 .context("While checking permission.")?;
1519
1520 Self::mark_unreferenced(tx, key_id).context("Trying to mark the key unreferenced.")
1521 })
1522 .context("In unbind_key.")
1523 }
1524
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001525 fn load_key_components(
1526 tx: &Transaction,
1527 load_bits: KeyEntryLoadBits,
1528 key_id: i64,
1529 ) -> Result<KeyEntry> {
1530 let metadata = KeyMetaData::load_from_db(key_id, &tx).context("In load_key_components.")?;
1531
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001532 let (km_blob, cert_blob, cert_chain_blob) =
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001533 Self::load_blob_components(key_id, load_bits, &tx)
1534 .context("In load_key_components.")?;
1535
1536 let parameters =
1537 Self::load_key_parameters(key_id, &tx).context("In load_key_components.")?;
1538
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001539 // Extract the security level by checking the security level of the origin tag.
1540 // Super keys don't have key parameters so we use security_level software by default.
1541 let sec_level = parameters
1542 .iter()
1543 .find_map(|k| match k.get_tag() {
1544 Tag::ORIGIN => Some(*k.security_level()),
1545 _ => None,
1546 })
1547 .unwrap_or(SecurityLevel::SOFTWARE);
1548
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001549 Ok(KeyEntry {
1550 id: key_id,
1551 km_blob,
1552 cert: cert_blob,
1553 cert_chain: cert_chain_blob,
1554 sec_level,
1555 parameters,
1556 metadata,
1557 })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001558 }
1559
Janis Danisevskise92a5e62020-12-02 12:57:41 -08001560 /// Returns a list of KeyDescriptors in the selected domain/namespace.
1561 /// The key descriptors will have the domain, nspace, and alias field set.
1562 /// Domain must be APP or SELINUX, the caller must make sure of that.
1563 pub fn list(&mut self, domain: Domain, namespace: i64) -> Result<Vec<KeyDescriptor>> {
1564 let mut stmt = self
1565 .conn
1566 .prepare(
1567 "SELECT alias FROM persistent.keyentry
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001568 WHERE domain = ? AND namespace = ? AND alias IS NOT NULL AND state = ?;",
Janis Danisevskise92a5e62020-12-02 12:57:41 -08001569 )
1570 .context("In list: Failed to prepare.")?;
1571
Janis Danisevskis93927dd2020-12-23 12:23:08 -08001572 let mut rows = stmt
1573 .query(params![domain.0 as u32, namespace, KeyLifeCycle::Live])
1574 .context("In list: Failed to query.")?;
Janis Danisevskise92a5e62020-12-02 12:57:41 -08001575
1576 let mut descriptors: Vec<KeyDescriptor> = Vec::new();
1577 db_utils::with_rows_extract_all(&mut rows, |row| {
1578 descriptors.push(KeyDescriptor {
1579 domain,
1580 nspace: namespace,
1581 alias: Some(row.get(0).context("Trying to extract alias.")?),
1582 blob: None,
1583 });
1584 Ok(())
1585 })
1586 .context("In list.")?;
1587 Ok(descriptors)
1588 }
1589
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001590 /// Adds a grant to the grant table.
1591 /// Like `load_key_entry` this function loads the access tuple before
1592 /// it uses the callback for a permission check. Upon success,
1593 /// it inserts the `grantee_uid`, `key_id`, and `access_vector` into the
1594 /// grant table. The new row will have a randomized id, which is used as
1595 /// grant id in the namespace field of the resulting KeyDescriptor.
1596 pub fn grant(
1597 &mut self,
1598 key: KeyDescriptor,
1599 caller_uid: u32,
1600 grantee_uid: u32,
1601 access_vector: KeyPermSet,
1602 check_permission: impl FnOnce(&KeyDescriptor, &KeyPermSet) -> Result<()>,
1603 ) -> Result<KeyDescriptor> {
1604 let tx = self
1605 .conn
1606 .transaction_with_behavior(TransactionBehavior::Immediate)
1607 .context("In grant: Failed to initialize transaction.")?;
1608
1609 // Load the key_id and complete the access control tuple.
1610 // We ignore the access vector here because grants cannot be granted.
1611 // The access vector returned here expresses the permissions the
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001612 // grantee has if key.domain == Domain::GRANT. But this vector
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001613 // cannot include the grant permission by design, so there is no way the
1614 // subsequent permission check can pass.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001615 // We could check key.domain == Domain::GRANT and fail early.
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001616 // But even if we load the access tuple by grant here, the permission
1617 // check denies the attempt to create a grant by grant descriptor.
1618 let (key_id, access_key_descriptor, _) =
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001619 Self::load_access_tuple(&tx, key, KeyType::Client, caller_uid).context("In grant")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001620
1621 // Perform access control. It is vital that we return here if the permission
1622 // was denied. So do not touch that '?' at the end of the line.
1623 // This permission check checks if the caller has the grant permission
1624 // for the given key and in addition to all of the permissions
1625 // expressed in `access_vector`.
1626 check_permission(&access_key_descriptor, &access_vector)
1627 .context("In grant: check_permission failed.")?;
1628
1629 let grant_id = if let Some(grant_id) = tx
1630 .query_row(
Janis Danisevskisbf15d732020-12-08 10:35:26 -08001631 "SELECT id FROM persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001632 WHERE keyentryid = ? AND grantee = ?;",
1633 params![key_id, grantee_uid],
1634 |row| row.get(0),
1635 )
1636 .optional()
1637 .context("In grant: Failed get optional existing grant id.")?
1638 {
1639 tx.execute(
Janis Danisevskisbf15d732020-12-08 10:35:26 -08001640 "UPDATE persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001641 SET access_vector = ?
1642 WHERE id = ?;",
1643 params![i32::from(access_vector), grant_id],
1644 )
1645 .context("In grant: Failed to update existing grant.")?;
1646 grant_id
1647 } else {
Joel Galenson845f74b2020-09-09 14:11:55 -07001648 Self::insert_with_retry(|id| {
1649 tx.execute(
Janis Danisevskisbf15d732020-12-08 10:35:26 -08001650 "INSERT INTO persistent.grant (id, grantee, keyentryid, access_vector)
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001651 VALUES (?, ?, ?, ?);",
Joel Galenson845f74b2020-09-09 14:11:55 -07001652 params![id, grantee_uid, key_id, i32::from(access_vector)],
1653 )
1654 })
1655 .context("In grant")?
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001656 };
1657 tx.commit().context("In grant: failed to commit transaction.")?;
1658
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001659 Ok(KeyDescriptor { domain: Domain::GRANT, nspace: grant_id, alias: None, blob: None })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001660 }
1661
1662 /// This function checks permissions like `grant` and `load_key_entry`
1663 /// before removing a grant from the grant table.
1664 pub fn ungrant(
1665 &mut self,
1666 key: KeyDescriptor,
1667 caller_uid: u32,
1668 grantee_uid: u32,
1669 check_permission: impl FnOnce(&KeyDescriptor) -> Result<()>,
1670 ) -> Result<()> {
1671 let tx = self
1672 .conn
1673 .transaction_with_behavior(TransactionBehavior::Immediate)
1674 .context("In ungrant: Failed to initialize transaction.")?;
1675
1676 // Load the key_id and complete the access control tuple.
1677 // We ignore the access vector here because grants cannot be granted.
1678 let (key_id, access_key_descriptor, _) =
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001679 Self::load_access_tuple(&tx, key, KeyType::Client, caller_uid)
1680 .context("In ungrant.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001681
1682 // Perform access control. We must return here if the permission
1683 // was denied. So do not touch the '?' at the end of this line.
1684 check_permission(&access_key_descriptor).context("In grant: check_permission failed.")?;
1685
1686 tx.execute(
Janis Danisevskisbf15d732020-12-08 10:35:26 -08001687 "DELETE FROM persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001688 WHERE keyentryid = ? AND grantee = ?;",
1689 params![key_id, grantee_uid],
1690 )
1691 .context("Failed to delete grant.")?;
1692
1693 tx.commit().context("In ungrant: failed to commit transaction.")?;
1694
1695 Ok(())
1696 }
1697
Joel Galenson845f74b2020-09-09 14:11:55 -07001698 // Generates a random id and passes it to the given function, which will
1699 // try to insert it into a database. If that insertion fails, retry;
1700 // otherwise return the id.
1701 fn insert_with_retry(inserter: impl Fn(i64) -> rusqlite::Result<usize>) -> Result<i64> {
1702 loop {
1703 let newid: i64 = random();
1704 match inserter(newid) {
1705 // If the id already existed, try again.
1706 Err(rusqlite::Error::SqliteFailure(
1707 libsqlite3_sys::Error {
1708 code: libsqlite3_sys::ErrorCode::ConstraintViolation,
1709 extended_code: libsqlite3_sys::SQLITE_CONSTRAINT_UNIQUE,
1710 },
1711 _,
1712 )) => (),
1713 Err(e) => {
1714 return Err(e).context("In insert_with_retry: failed to insert into database.")
1715 }
1716 _ => return Ok(newid),
1717 }
1718 }
1719 }
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00001720
1721 /// Insert or replace the auth token based on the UNIQUE constraint of the auth token table
1722 pub fn insert_auth_token(&mut self, auth_token: &HardwareAuthToken) -> Result<()> {
1723 self.conn
1724 .execute(
1725 "INSERT OR REPLACE INTO perboot.authtoken (challenge, user_id, auth_id,
1726 authenticator_type, timestamp, mac, time_received) VALUES(?, ?, ?, ?, ?, ?, ?);",
1727 params![
1728 auth_token.challenge,
1729 auth_token.userId,
1730 auth_token.authenticatorId,
1731 auth_token.authenticatorType.0 as i32,
1732 auth_token.timestamp.milliSeconds as i64,
1733 auth_token.mac,
1734 MonotonicRawTime::now(),
1735 ],
1736 )
1737 .context("In insert_auth_token: failed to insert auth token into the database")?;
1738 Ok(())
1739 }
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00001740
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08001741 /// Find the newest auth token matching the given predicate.
1742 pub fn find_auth_token_entry<F>(
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00001743 &mut self,
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08001744 p: F,
1745 ) -> Result<Option<(AuthTokenEntry, MonotonicRawTime)>>
1746 where
1747 F: Fn(&AuthTokenEntry) -> bool,
1748 {
1749 self.with_transaction(TransactionBehavior::Deferred, |tx| {
1750 let mut stmt = tx
1751 .prepare("SELECT * from perboot.authtoken ORDER BY time_received DESC;")
1752 .context("Prepare statement failed.")?;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00001753
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08001754 let mut rows = stmt.query(NO_PARAMS).context("Failed to query.")?;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00001755
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08001756 while let Some(row) = rows.next().context("Failed to get next row.")? {
1757 let entry = AuthTokenEntry::new(
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00001758 HardwareAuthToken {
1759 challenge: row.get(1)?,
1760 userId: row.get(2)?,
1761 authenticatorId: row.get(3)?,
1762 authenticatorType: HardwareAuthenticatorType(row.get(4)?),
1763 timestamp: Timestamp { milliSeconds: row.get(5)? },
1764 mac: row.get(6)?,
1765 },
1766 row.get(7)?,
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08001767 );
1768 if p(&entry) {
1769 return Ok(Some((
1770 entry,
1771 Self::get_last_off_body(tx)
1772 .context("In find_auth_token_entry: Trying to get last off body")?,
1773 )));
1774 }
1775 }
1776 Ok(None)
1777 })
1778 .context("In find_auth_token_entry.")
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00001779 }
1780
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08001781 /// Insert last_off_body into the metadata table at the initialization of auth token table
1782 pub fn insert_last_off_body(&self, last_off_body: MonotonicRawTime) -> Result<()> {
1783 self.conn
1784 .execute(
1785 "INSERT OR REPLACE INTO perboot.metadata (key, value) VALUES (?, ?);",
1786 params!["last_off_body", last_off_body],
1787 )
1788 .context("In insert_last_off_body: failed to insert.")?;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00001789 Ok(())
1790 }
1791
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08001792 /// Update last_off_body when on_device_off_body is called
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00001793 pub fn update_last_off_body(&self, last_off_body: MonotonicRawTime) -> Result<()> {
1794 self.conn
1795 .execute(
1796 "UPDATE perboot.metadata SET value = ? WHERE key = ?;",
1797 params![last_off_body, "last_off_body"],
1798 )
1799 .context("In update_last_off_body: failed to update.")?;
1800 Ok(())
1801 }
1802
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08001803 /// Get last_off_body time when finding auth tokens
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00001804 fn get_last_off_body(tx: &Transaction) -> Result<MonotonicRawTime> {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08001805 tx.query_row(
1806 "SELECT value from perboot.metadata WHERE key = ?;",
1807 params!["last_off_body"],
1808 |row| Ok(row.get(0)?),
1809 )
1810 .context("In get_last_off_body: query_row failed.")
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00001811 }
Joel Galenson26f4d012020-07-17 14:57:21 -07001812}
1813
1814#[cfg(test)]
1815mod tests {
1816
1817 use super::*;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001818 use crate::key_parameter::{
1819 Algorithm, BlockMode, Digest, EcCurve, HardwareAuthenticatorType, KeyOrigin, KeyParameter,
1820 KeyParameterValue, KeyPurpose, PaddingMode, SecurityLevel,
1821 };
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001822 use crate::key_perm_set;
1823 use crate::permission::{KeyPerm, KeyPermSet};
Janis Danisevskis2a8330a2021-01-20 15:34:26 -08001824 use keystore2_test_utils::TempDir;
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00001825 use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
1826 HardwareAuthToken::HardwareAuthToken,
1827 HardwareAuthenticatorType::HardwareAuthenticatorType as kmhw_authenticator_type,
Janis Danisevskisc3a496b2021-01-05 10:37:22 -08001828 };
1829 use android_hardware_security_secureclock::aidl::android::hardware::security::secureclock::{
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00001830 Timestamp::Timestamp,
1831 };
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001832 use rusqlite::NO_PARAMS;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00001833 use rusqlite::{Error, TransactionBehavior};
Joel Galenson0891bc12020-07-20 10:37:03 -07001834 use std::cell::RefCell;
Janis Danisevskisaec14592020-11-12 09:41:49 -08001835 use std::sync::atomic::{AtomicU8, Ordering};
1836 use std::sync::Arc;
1837 use std::thread;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00001838 use std::time::{Duration, SystemTime};
Joel Galenson0891bc12020-07-20 10:37:03 -07001839
Janis Danisevskis4df44f42020-08-26 14:40:03 -07001840 fn new_test_db() -> Result<KeystoreDB> {
1841 let conn = KeystoreDB::make_connection("file::memory:", "file::memory:")?;
1842
1843 KeystoreDB::init_tables(&conn).context("Failed to initialize tables.")?;
1844 Ok(KeystoreDB { conn })
1845 }
1846
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08001847 fn rebind_alias(
1848 db: &mut KeystoreDB,
1849 newid: &KeyIdGuard,
1850 alias: &str,
1851 domain: Domain,
1852 namespace: i64,
1853 ) -> Result<bool> {
1854 db.with_transaction(TransactionBehavior::Immediate, |tx| {
1855 KeystoreDB::rebind_alias(tx, newid, alias, domain, namespace)
1856 })
1857 .context("In rebind_alias.")
1858 }
1859
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001860 #[test]
1861 fn datetime() -> Result<()> {
1862 let conn = Connection::open_in_memory()?;
1863 conn.execute("CREATE TABLE test (ts DATETIME);", NO_PARAMS)?;
1864 let now = SystemTime::now();
1865 let duration = Duration::from_secs(1000);
1866 let then = now.checked_sub(duration).unwrap();
1867 let soon = now.checked_add(duration).unwrap();
1868 conn.execute(
1869 "INSERT INTO test (ts) VALUES (?), (?), (?);",
1870 params![DateTime::try_from(now)?, DateTime::try_from(then)?, DateTime::try_from(soon)?],
1871 )?;
1872 let mut stmt = conn.prepare("SELECT ts FROM test ORDER BY ts ASC;")?;
1873 let mut rows = stmt.query(NO_PARAMS)?;
1874 assert_eq!(DateTime::try_from(then)?, rows.next()?.unwrap().get(0)?);
1875 assert_eq!(DateTime::try_from(now)?, rows.next()?.unwrap().get(0)?);
1876 assert_eq!(DateTime::try_from(soon)?, rows.next()?.unwrap().get(0)?);
1877 assert!(rows.next()?.is_none());
1878 assert!(DateTime::try_from(then)? < DateTime::try_from(now)?);
1879 assert!(DateTime::try_from(then)? < DateTime::try_from(soon)?);
1880 assert!(DateTime::try_from(now)? < DateTime::try_from(soon)?);
1881 Ok(())
1882 }
1883
Joel Galenson0891bc12020-07-20 10:37:03 -07001884 // Ensure that we're using the "injected" random function, not the real one.
1885 #[test]
1886 fn test_mocked_random() {
1887 let rand1 = random();
1888 let rand2 = random();
1889 let rand3 = random();
1890 if rand1 == rand2 {
1891 assert_eq!(rand2 + 1, rand3);
1892 } else {
1893 assert_eq!(rand1 + 1, rand2);
1894 assert_eq!(rand2, rand3);
1895 }
1896 }
Joel Galenson26f4d012020-07-17 14:57:21 -07001897
Joel Galenson26f4d012020-07-17 14:57:21 -07001898 // Test that we have the correct tables.
1899 #[test]
1900 fn test_tables() -> Result<()> {
Janis Danisevskis4df44f42020-08-26 14:40:03 -07001901 let db = new_test_db()?;
Joel Galenson26f4d012020-07-17 14:57:21 -07001902 let tables = db
1903 .conn
Joel Galenson2aab4432020-07-22 15:27:57 -07001904 .prepare("SELECT name from persistent.sqlite_master WHERE type='table' ORDER BY name;")?
Joel Galenson26f4d012020-07-17 14:57:21 -07001905 .query_map(params![], |row| row.get(0))?
1906 .collect::<rusqlite::Result<Vec<String>>>()?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001907 assert_eq!(tables.len(), 5);
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001908 assert_eq!(tables[0], "blobentry");
Janis Danisevskisbf15d732020-12-08 10:35:26 -08001909 assert_eq!(tables[1], "grant");
1910 assert_eq!(tables[2], "keyentry");
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001911 assert_eq!(tables[3], "keymetadata");
1912 assert_eq!(tables[4], "keyparameter");
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001913 let tables = db
1914 .conn
1915 .prepare("SELECT name from perboot.sqlite_master WHERE type='table' ORDER BY name;")?
1916 .query_map(params![], |row| row.get(0))?
1917 .collect::<rusqlite::Result<Vec<String>>>()?;
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00001918
1919 assert_eq!(tables.len(), 2);
1920 assert_eq!(tables[0], "authtoken");
1921 assert_eq!(tables[1], "metadata");
Joel Galenson2aab4432020-07-22 15:27:57 -07001922 Ok(())
1923 }
1924
1925 #[test]
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00001926 fn test_auth_token_table_invariant() -> Result<()> {
1927 let mut db = new_test_db()?;
1928 let auth_token1 = HardwareAuthToken {
1929 challenge: i64::MAX,
1930 userId: 200,
1931 authenticatorId: 200,
1932 authenticatorType: kmhw_authenticator_type(kmhw_authenticator_type::PASSWORD.0),
1933 timestamp: Timestamp { milliSeconds: 500 },
1934 mac: String::from("mac").into_bytes(),
1935 };
1936 db.insert_auth_token(&auth_token1)?;
1937 let auth_tokens_returned = get_auth_tokens(&mut db)?;
1938 assert_eq!(auth_tokens_returned.len(), 1);
1939
1940 // insert another auth token with the same values for the columns in the UNIQUE constraint
1941 // of the auth token table and different value for timestamp
1942 let auth_token2 = HardwareAuthToken {
1943 challenge: i64::MAX,
1944 userId: 200,
1945 authenticatorId: 200,
1946 authenticatorType: kmhw_authenticator_type(kmhw_authenticator_type::PASSWORD.0),
1947 timestamp: Timestamp { milliSeconds: 600 },
1948 mac: String::from("mac").into_bytes(),
1949 };
1950
1951 db.insert_auth_token(&auth_token2)?;
1952 let mut auth_tokens_returned = get_auth_tokens(&mut db)?;
1953 assert_eq!(auth_tokens_returned.len(), 1);
1954
1955 if let Some(auth_token) = auth_tokens_returned.pop() {
1956 assert_eq!(auth_token.auth_token.timestamp.milliSeconds, 600);
1957 }
1958
1959 // insert another auth token with the different values for the columns in the UNIQUE
1960 // constraint of the auth token table
1961 let auth_token3 = HardwareAuthToken {
1962 challenge: i64::MAX,
1963 userId: 201,
1964 authenticatorId: 200,
1965 authenticatorType: kmhw_authenticator_type(kmhw_authenticator_type::PASSWORD.0),
1966 timestamp: Timestamp { milliSeconds: 600 },
1967 mac: String::from("mac").into_bytes(),
1968 };
1969
1970 db.insert_auth_token(&auth_token3)?;
1971 let auth_tokens_returned = get_auth_tokens(&mut db)?;
1972 assert_eq!(auth_tokens_returned.len(), 2);
1973
1974 Ok(())
1975 }
1976
1977 // utility function for test_auth_token_table_invariant()
1978 fn get_auth_tokens(db: &mut KeystoreDB) -> Result<Vec<AuthTokenEntry>> {
1979 let mut stmt = db.conn.prepare("SELECT * from perboot.authtoken;")?;
1980
1981 let auth_token_entries: Vec<AuthTokenEntry> = stmt
1982 .query_map(NO_PARAMS, |row| {
1983 Ok(AuthTokenEntry::new(
1984 HardwareAuthToken {
1985 challenge: row.get(1)?,
1986 userId: row.get(2)?,
1987 authenticatorId: row.get(3)?,
1988 authenticatorType: HardwareAuthenticatorType(row.get(4)?),
1989 timestamp: Timestamp { milliSeconds: row.get(5)? },
1990 mac: row.get(6)?,
1991 },
1992 row.get(7)?,
1993 ))
1994 })?
1995 .collect::<Result<Vec<AuthTokenEntry>, Error>>()?;
1996 Ok(auth_token_entries)
1997 }
1998
1999 #[test]
Joel Galenson2aab4432020-07-22 15:27:57 -07002000 fn test_persistence_for_files() -> Result<()> {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002001 let temp_dir = TempDir::new("persistent_db_test")?;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002002 let mut db = KeystoreDB::new(temp_dir.path())?;
Joel Galenson2aab4432020-07-22 15:27:57 -07002003
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002004 db.create_key_entry(Domain::APP, 100)?;
Joel Galenson2aab4432020-07-22 15:27:57 -07002005 let entries = get_keyentry(&db)?;
2006 assert_eq!(entries.len(), 1);
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002007
2008 let db = KeystoreDB::new(temp_dir.path())?;
Joel Galenson2aab4432020-07-22 15:27:57 -07002009
2010 let entries_new = get_keyentry(&db)?;
2011 assert_eq!(entries, entries_new);
2012 Ok(())
2013 }
2014
2015 #[test]
Joel Galenson0891bc12020-07-20 10:37:03 -07002016 fn test_create_key_entry() -> Result<()> {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002017 fn extractor(ke: &KeyEntryRow) -> (Domain, i64, Option<&str>) {
Joel Galenson0891bc12020-07-20 10:37:03 -07002018 (ke.domain.unwrap(), ke.namespace.unwrap(), ke.alias.as_deref())
2019 }
2020
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002021 let mut db = new_test_db()?;
Joel Galenson0891bc12020-07-20 10:37:03 -07002022
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002023 db.create_key_entry(Domain::APP, 100)?;
2024 db.create_key_entry(Domain::SELINUX, 101)?;
Joel Galenson0891bc12020-07-20 10:37:03 -07002025
2026 let entries = get_keyentry(&db)?;
2027 assert_eq!(entries.len(), 2);
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002028 assert_eq!(extractor(&entries[0]), (Domain::APP, 100, None));
2029 assert_eq!(extractor(&entries[1]), (Domain::SELINUX, 101, None));
Joel Galenson0891bc12020-07-20 10:37:03 -07002030
2031 // Test that we must pass in a valid Domain.
2032 check_result_is_error_containing_string(
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002033 db.create_key_entry(Domain::GRANT, 102),
2034 "Domain Domain(1) must be either App or SELinux.",
Joel Galenson0891bc12020-07-20 10:37:03 -07002035 );
2036 check_result_is_error_containing_string(
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002037 db.create_key_entry(Domain::BLOB, 103),
2038 "Domain Domain(3) must be either App or SELinux.",
Joel Galenson0891bc12020-07-20 10:37:03 -07002039 );
2040 check_result_is_error_containing_string(
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002041 db.create_key_entry(Domain::KEY_ID, 104),
2042 "Domain Domain(4) must be either App or SELinux.",
Joel Galenson0891bc12020-07-20 10:37:03 -07002043 );
2044
2045 Ok(())
2046 }
2047
Joel Galenson33c04ad2020-08-03 11:04:38 -07002048 #[test]
2049 fn test_rebind_alias() -> Result<()> {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002050 fn extractor(ke: &KeyEntryRow) -> (Option<Domain>, Option<i64>, Option<&str>) {
Joel Galenson33c04ad2020-08-03 11:04:38 -07002051 (ke.domain, ke.namespace, ke.alias.as_deref())
2052 }
2053
Janis Danisevskis4df44f42020-08-26 14:40:03 -07002054 let mut db = new_test_db()?;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002055 db.create_key_entry(Domain::APP, 42)?;
2056 db.create_key_entry(Domain::APP, 42)?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07002057 let entries = get_keyentry(&db)?;
2058 assert_eq!(entries.len(), 2);
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002059 assert_eq!(extractor(&entries[0]), (Some(Domain::APP), Some(42), None));
2060 assert_eq!(extractor(&entries[1]), (Some(Domain::APP), Some(42), None));
Joel Galenson33c04ad2020-08-03 11:04:38 -07002061
2062 // Test that the first call to rebind_alias sets the alias.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002063 rebind_alias(&mut db, &KEY_ID_LOCK.get(entries[0].id), "foo", Domain::APP, 42)?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07002064 let entries = get_keyentry(&db)?;
2065 assert_eq!(entries.len(), 2);
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002066 assert_eq!(extractor(&entries[0]), (Some(Domain::APP), Some(42), Some("foo")));
2067 assert_eq!(extractor(&entries[1]), (Some(Domain::APP), Some(42), None));
Joel Galenson33c04ad2020-08-03 11:04:38 -07002068
2069 // Test that the second call to rebind_alias also empties the old one.
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002070 rebind_alias(&mut db, &KEY_ID_LOCK.get(entries[1].id), "foo", Domain::APP, 42)?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07002071 let entries = get_keyentry(&db)?;
2072 assert_eq!(entries.len(), 2);
Joel Galenson7fa5c412020-11-19 10:56:54 -08002073 assert_eq!(extractor(&entries[0]), (None, None, None));
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002074 assert_eq!(extractor(&entries[1]), (Some(Domain::APP), Some(42), Some("foo")));
Joel Galenson33c04ad2020-08-03 11:04:38 -07002075
2076 // Test that we must pass in a valid Domain.
2077 check_result_is_error_containing_string(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002078 rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::GRANT, 42),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002079 "Domain Domain(1) must be either App or SELinux.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07002080 );
2081 check_result_is_error_containing_string(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002082 rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::BLOB, 42),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002083 "Domain Domain(3) must be either App or SELinux.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07002084 );
2085 check_result_is_error_containing_string(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002086 rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::KEY_ID, 42),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002087 "Domain Domain(4) must be either App or SELinux.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07002088 );
2089
2090 // Test that we correctly handle setting an alias for something that does not exist.
2091 check_result_is_error_containing_string(
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08002092 rebind_alias(&mut db, &KEY_ID_LOCK.get(0), "foo", Domain::SELINUX, 42),
Joel Galenson33c04ad2020-08-03 11:04:38 -07002093 "Expected to update a single entry but instead updated 0",
2094 );
2095 // Test that we correctly abort the transaction in this case.
2096 let entries = get_keyentry(&db)?;
2097 assert_eq!(entries.len(), 2);
Joel Galenson7fa5c412020-11-19 10:56:54 -08002098 assert_eq!(extractor(&entries[0]), (None, None, None));
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002099 assert_eq!(extractor(&entries[1]), (Some(Domain::APP), Some(42), Some("foo")));
Joel Galenson33c04ad2020-08-03 11:04:38 -07002100
2101 Ok(())
2102 }
2103
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002104 #[test]
2105 fn test_grant_ungrant() -> Result<()> {
2106 const CALLER_UID: u32 = 15;
2107 const GRANTEE_UID: u32 = 12;
2108 const SELINUX_NAMESPACE: i64 = 7;
2109
2110 let mut db = new_test_db()?;
2111 db.conn.execute(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002112 "INSERT INTO persistent.keyentry (id, key_type, domain, namespace, alias, state)
2113 VALUES (1, 0, 0, 15, 'key', 1), (2, 0, 2, 7, 'yek', 1);",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002114 NO_PARAMS,
2115 )?;
2116 let app_key = KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002117 domain: super::Domain::APP,
2118 nspace: 0,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002119 alias: Some("key".to_string()),
2120 blob: None,
2121 };
2122 const PVEC1: KeyPermSet = key_perm_set![KeyPerm::use_(), KeyPerm::get_info()];
2123 const PVEC2: KeyPermSet = key_perm_set![KeyPerm::use_()];
2124
2125 // Reset totally predictable random number generator in case we
2126 // are not the first test running on this thread.
2127 reset_random();
2128 let next_random = 0i64;
2129
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002130 let app_granted_key = db
2131 .grant(app_key.clone(), CALLER_UID, GRANTEE_UID, PVEC1, |k, a| {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002132 assert_eq!(*a, PVEC1);
2133 assert_eq!(
2134 *k,
2135 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002136 domain: super::Domain::APP,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002137 // namespace must be set to the caller_uid.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002138 nspace: CALLER_UID as i64,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002139 alias: Some("key".to_string()),
2140 blob: None,
2141 }
2142 );
2143 Ok(())
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002144 })
2145 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002146
2147 assert_eq!(
2148 app_granted_key,
2149 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002150 domain: super::Domain::GRANT,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002151 // The grantid is next_random due to the mock random number generator.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002152 nspace: next_random,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002153 alias: None,
2154 blob: None,
2155 }
2156 );
2157
2158 let selinux_key = KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002159 domain: super::Domain::SELINUX,
2160 nspace: SELINUX_NAMESPACE,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002161 alias: Some("yek".to_string()),
2162 blob: None,
2163 };
2164
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002165 let selinux_granted_key = db
2166 .grant(selinux_key.clone(), CALLER_UID, 12, PVEC1, |k, a| {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002167 assert_eq!(*a, PVEC1);
2168 assert_eq!(
2169 *k,
2170 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002171 domain: super::Domain::SELINUX,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002172 // namespace must be the supplied SELinux
2173 // namespace.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002174 nspace: SELINUX_NAMESPACE,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002175 alias: Some("yek".to_string()),
2176 blob: None,
2177 }
2178 );
2179 Ok(())
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002180 })
2181 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002182
2183 assert_eq!(
2184 selinux_granted_key,
2185 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002186 domain: super::Domain::GRANT,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002187 // The grantid is next_random + 1 due to the mock random number generator.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002188 nspace: next_random + 1,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002189 alias: None,
2190 blob: None,
2191 }
2192 );
2193
2194 // This should update the existing grant with PVEC2.
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002195 let selinux_granted_key = db
2196 .grant(selinux_key.clone(), CALLER_UID, 12, PVEC2, |k, a| {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002197 assert_eq!(*a, PVEC2);
2198 assert_eq!(
2199 *k,
2200 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002201 domain: super::Domain::SELINUX,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002202 // namespace must be the supplied SELinux
2203 // namespace.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002204 nspace: SELINUX_NAMESPACE,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002205 alias: Some("yek".to_string()),
2206 blob: None,
2207 }
2208 );
2209 Ok(())
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002210 })
2211 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002212
2213 assert_eq!(
2214 selinux_granted_key,
2215 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002216 domain: super::Domain::GRANT,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002217 // Same grant id as before. The entry was only updated.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002218 nspace: next_random + 1,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002219 alias: None,
2220 blob: None,
2221 }
2222 );
2223
2224 {
2225 // Limiting scope of stmt, because it borrows db.
2226 let mut stmt = db
2227 .conn
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002228 .prepare("SELECT id, grantee, keyentryid, access_vector FROM persistent.grant;")?;
Janis Danisevskisee10b5f2020-09-22 16:42:35 -07002229 let mut rows =
2230 stmt.query_map::<(i64, u32, i64, KeyPermSet), _, _>(NO_PARAMS, |row| {
2231 Ok((
2232 row.get(0)?,
2233 row.get(1)?,
2234 row.get(2)?,
2235 KeyPermSet::from(row.get::<_, i32>(3)?),
2236 ))
2237 })?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002238
2239 let r = rows.next().unwrap().unwrap();
Janis Danisevskisee10b5f2020-09-22 16:42:35 -07002240 assert_eq!(r, (next_random, GRANTEE_UID, 1, PVEC1));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002241 let r = rows.next().unwrap().unwrap();
Janis Danisevskisee10b5f2020-09-22 16:42:35 -07002242 assert_eq!(r, (next_random + 1, GRANTEE_UID, 2, PVEC2));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002243 assert!(rows.next().is_none());
2244 }
2245
2246 debug_dump_keyentry_table(&mut db)?;
2247 println!("app_key {:?}", app_key);
2248 println!("selinux_key {:?}", selinux_key);
2249
2250 db.ungrant(app_key, CALLER_UID, GRANTEE_UID, |_| Ok(()))?;
2251 db.ungrant(selinux_key, CALLER_UID, GRANTEE_UID, |_| Ok(()))?;
2252
2253 Ok(())
2254 }
2255
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002256 static TEST_KEY_BLOB: &[u8] = b"my test blob";
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002257 static TEST_CERT_BLOB: &[u8] = b"my test cert";
2258 static TEST_CERT_CHAIN_BLOB: &[u8] = b"my test cert_chain";
2259
2260 #[test]
2261 fn test_insert_blob() -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002262 let key_id = KEY_ID_LOCK.get(3000);
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002263 let mut db = new_test_db()?;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002264 db.insert_blob(&key_id, SubComponentType::KEY_BLOB, TEST_KEY_BLOB)?;
2265 db.insert_blob(&key_id, SubComponentType::CERT, TEST_CERT_BLOB)?;
2266 db.insert_blob(&key_id, SubComponentType::CERT_CHAIN, TEST_CERT_CHAIN_BLOB)?;
2267 drop(key_id);
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002268
2269 let mut stmt = db.conn.prepare(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002270 "SELECT subcomponent_type, keyentryid, blob FROM persistent.blobentry
2271 ORDER BY subcomponent_type ASC;",
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002272 )?;
2273 let mut rows = stmt
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002274 .query_map::<(SubComponentType, i64, Vec<u8>), _, _>(NO_PARAMS, |row| {
2275 Ok((row.get(0)?, row.get(1)?, row.get(2)?))
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002276 })?;
2277 let r = rows.next().unwrap().unwrap();
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002278 assert_eq!(r, (SubComponentType::KEY_BLOB, 3000, TEST_KEY_BLOB.to_vec()));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002279 let r = rows.next().unwrap().unwrap();
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002280 assert_eq!(r, (SubComponentType::CERT, 3000, TEST_CERT_BLOB.to_vec()));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002281 let r = rows.next().unwrap().unwrap();
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002282 assert_eq!(r, (SubComponentType::CERT_CHAIN, 3000, TEST_CERT_CHAIN_BLOB.to_vec()));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002283
2284 Ok(())
2285 }
2286
2287 static TEST_ALIAS: &str = "my super duper key";
2288
2289 #[test]
2290 fn test_insert_and_load_full_keyentry_domain_app() -> Result<()> {
2291 let mut db = new_test_db()?;
Qi Wub9433b52020-12-01 14:52:46 +08002292 let key_id = make_test_key_entry(&mut db, Domain::APP, 1, TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08002293 .context("test_insert_and_load_full_keyentry_domain_app")?
2294 .0;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002295 let (_key_guard, key_entry) = db
2296 .load_key_entry(
2297 KeyDescriptor {
2298 domain: Domain::APP,
2299 nspace: 0,
2300 alias: Some(TEST_ALIAS.to_string()),
2301 blob: None,
2302 },
2303 KeyType::Client,
2304 KeyEntryLoadBits::BOTH,
2305 1,
2306 |_k, _av| Ok(()),
2307 )
2308 .unwrap();
Qi Wub9433b52020-12-01 14:52:46 +08002309 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002310
2311 db.unbind_key(
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002312 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002313 domain: Domain::APP,
2314 nspace: 0,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002315 alias: Some(TEST_ALIAS.to_string()),
2316 blob: None,
2317 },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002318 KeyType::Client,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002319 1,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002320 |_, _| Ok(()),
2321 )
2322 .unwrap();
2323
2324 assert_eq!(
2325 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
2326 db.load_key_entry(
2327 KeyDescriptor {
2328 domain: Domain::APP,
2329 nspace: 0,
2330 alias: Some(TEST_ALIAS.to_string()),
2331 blob: None,
2332 },
2333 KeyType::Client,
2334 KeyEntryLoadBits::NONE,
2335 1,
2336 |_k, _av| Ok(()),
2337 )
2338 .unwrap_err()
2339 .root_cause()
2340 .downcast_ref::<KsError>()
2341 );
2342
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002343 Ok(())
2344 }
2345
2346 #[test]
2347 fn test_insert_and_load_full_keyentry_domain_selinux() -> Result<()> {
2348 let mut db = new_test_db()?;
Qi Wub9433b52020-12-01 14:52:46 +08002349 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08002350 .context("test_insert_and_load_full_keyentry_domain_selinux")?
2351 .0;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002352 let (_key_guard, key_entry) = db
2353 .load_key_entry(
2354 KeyDescriptor {
2355 domain: Domain::SELINUX,
2356 nspace: 1,
2357 alias: Some(TEST_ALIAS.to_string()),
2358 blob: None,
2359 },
2360 KeyType::Client,
2361 KeyEntryLoadBits::BOTH,
2362 1,
2363 |_k, _av| Ok(()),
2364 )
2365 .unwrap();
Qi Wub9433b52020-12-01 14:52:46 +08002366 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002367
2368 db.unbind_key(
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002369 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002370 domain: Domain::SELINUX,
2371 nspace: 1,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002372 alias: Some(TEST_ALIAS.to_string()),
2373 blob: None,
2374 },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002375 KeyType::Client,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002376 1,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002377 |_, _| Ok(()),
2378 )
2379 .unwrap();
2380
2381 assert_eq!(
2382 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
2383 db.load_key_entry(
2384 KeyDescriptor {
2385 domain: Domain::SELINUX,
2386 nspace: 1,
2387 alias: Some(TEST_ALIAS.to_string()),
2388 blob: None,
2389 },
2390 KeyType::Client,
2391 KeyEntryLoadBits::NONE,
2392 1,
2393 |_k, _av| Ok(()),
2394 )
2395 .unwrap_err()
2396 .root_cause()
2397 .downcast_ref::<KsError>()
2398 );
2399
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002400 Ok(())
2401 }
2402
2403 #[test]
2404 fn test_insert_and_load_full_keyentry_domain_key_id() -> Result<()> {
2405 let mut db = new_test_db()?;
Qi Wub9433b52020-12-01 14:52:46 +08002406 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08002407 .context("test_insert_and_load_full_keyentry_domain_key_id")?
2408 .0;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002409 let (_, key_entry) = db
2410 .load_key_entry(
2411 KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
2412 KeyType::Client,
2413 KeyEntryLoadBits::BOTH,
2414 1,
2415 |_k, _av| Ok(()),
2416 )
2417 .unwrap();
2418
Qi Wub9433b52020-12-01 14:52:46 +08002419 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002420
2421 db.unbind_key(
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002422 KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002423 KeyType::Client,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002424 1,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002425 |_, _| Ok(()),
2426 )
2427 .unwrap();
2428
2429 assert_eq!(
2430 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
2431 db.load_key_entry(
2432 KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
2433 KeyType::Client,
2434 KeyEntryLoadBits::NONE,
2435 1,
2436 |_k, _av| Ok(()),
2437 )
2438 .unwrap_err()
2439 .root_cause()
2440 .downcast_ref::<KsError>()
2441 );
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002442
2443 Ok(())
2444 }
2445
2446 #[test]
Qi Wub9433b52020-12-01 14:52:46 +08002447 fn test_check_and_update_key_usage_count_with_limited_use_key() -> Result<()> {
2448 let mut db = new_test_db()?;
2449 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, Some(123))
2450 .context("test_check_and_update_key_usage_count_with_limited_use_key")?
2451 .0;
2452 // Update the usage count of the limited use key.
2453 db.check_and_update_key_usage_count(key_id)?;
2454
2455 let (_key_guard, key_entry) = db.load_key_entry(
2456 KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
2457 KeyType::Client,
2458 KeyEntryLoadBits::BOTH,
2459 1,
2460 |_k, _av| Ok(()),
2461 )?;
2462
2463 // The usage count is decremented now.
2464 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, Some(122)));
2465
2466 Ok(())
2467 }
2468
2469 #[test]
2470 fn test_check_and_update_key_usage_count_with_exhausted_limited_use_key() -> Result<()> {
2471 let mut db = new_test_db()?;
2472 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS, Some(1))
2473 .context("test_check_and_update_key_usage_count_with_exhausted_limited_use_key")?
2474 .0;
2475 // Update the usage count of the limited use key.
2476 db.check_and_update_key_usage_count(key_id).expect(concat!(
2477 "In test_check_and_update_key_usage_count_with_exhausted_limited_use_key: ",
2478 "This should succeed."
2479 ));
2480
2481 // Try to update the exhausted limited use key.
2482 let e = db.check_and_update_key_usage_count(key_id).expect_err(concat!(
2483 "In test_check_and_update_key_usage_count_with_exhausted_limited_use_key: ",
2484 "This should fail."
2485 ));
2486 assert_eq!(
2487 &KsError::Km(ErrorCode::INVALID_KEY_BLOB),
2488 e.root_cause().downcast_ref::<KsError>().unwrap()
2489 );
2490
2491 Ok(())
2492 }
2493
2494 #[test]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002495 fn test_insert_and_load_full_keyentry_from_grant() -> Result<()> {
2496 let mut db = new_test_db()?;
Qi Wub9433b52020-12-01 14:52:46 +08002497 let key_id = make_test_key_entry(&mut db, Domain::APP, 1, TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08002498 .context("test_insert_and_load_full_keyentry_from_grant")?
2499 .0;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002500
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002501 let granted_key = db
2502 .grant(
2503 KeyDescriptor {
2504 domain: Domain::APP,
2505 nspace: 0,
2506 alias: Some(TEST_ALIAS.to_string()),
2507 blob: None,
2508 },
2509 1,
2510 2,
2511 key_perm_set![KeyPerm::use_()],
2512 |_k, _av| Ok(()),
2513 )
2514 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002515
2516 debug_dump_grant_table(&mut db)?;
2517
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002518 let (_key_guard, key_entry) = db
2519 .load_key_entry(
2520 granted_key.clone(),
2521 KeyType::Client,
2522 KeyEntryLoadBits::BOTH,
2523 2,
2524 |k, av| {
2525 assert_eq!(Domain::GRANT, k.domain);
2526 assert!(av.unwrap().includes(KeyPerm::use_()));
2527 Ok(())
2528 },
2529 )
2530 .unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002531
Qi Wub9433b52020-12-01 14:52:46 +08002532 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002533
2534 db.unbind_key(granted_key.clone(), KeyType::Client, 2, |_, _| Ok(())).unwrap();
2535
2536 assert_eq!(
2537 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
2538 db.load_key_entry(
2539 granted_key,
2540 KeyType::Client,
2541 KeyEntryLoadBits::NONE,
2542 2,
2543 |_k, _av| Ok(()),
2544 )
2545 .unwrap_err()
2546 .root_cause()
2547 .downcast_ref::<KsError>()
2548 );
2549
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002550 Ok(())
2551 }
2552
Janis Danisevskis45760022021-01-19 16:34:10 -08002553 // This test attempts to load a key by key id while the caller is not the owner
2554 // but a grant exists for the given key and the caller.
2555 #[test]
2556 fn test_insert_and_load_full_keyentry_from_grant_by_key_id() -> Result<()> {
2557 let mut db = new_test_db()?;
2558 const OWNER_UID: u32 = 1u32;
2559 const GRANTEE_UID: u32 = 2u32;
2560 const SOMEONE_ELSE_UID: u32 = 3u32;
2561 let key_id = make_test_key_entry(&mut db, Domain::APP, OWNER_UID as i64, TEST_ALIAS, None)
2562 .context("test_insert_and_load_full_keyentry_from_grant_by_key_id")?
2563 .0;
2564
2565 db.grant(
2566 KeyDescriptor {
2567 domain: Domain::APP,
2568 nspace: 0,
2569 alias: Some(TEST_ALIAS.to_string()),
2570 blob: None,
2571 },
2572 OWNER_UID,
2573 GRANTEE_UID,
2574 key_perm_set![KeyPerm::use_()],
2575 |_k, _av| Ok(()),
2576 )
2577 .unwrap();
2578
2579 debug_dump_grant_table(&mut db)?;
2580
2581 let id_descriptor =
2582 KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, ..Default::default() };
2583
2584 let (_, key_entry) = db
2585 .load_key_entry(
2586 id_descriptor.clone(),
2587 KeyType::Client,
2588 KeyEntryLoadBits::BOTH,
2589 GRANTEE_UID,
2590 |k, av| {
2591 assert_eq!(Domain::APP, k.domain);
2592 assert_eq!(OWNER_UID as i64, k.nspace);
2593 assert!(av.unwrap().includes(KeyPerm::use_()));
2594 Ok(())
2595 },
2596 )
2597 .unwrap();
2598
2599 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
2600
2601 let (_, key_entry) = db
2602 .load_key_entry(
2603 id_descriptor.clone(),
2604 KeyType::Client,
2605 KeyEntryLoadBits::BOTH,
2606 SOMEONE_ELSE_UID,
2607 |k, av| {
2608 assert_eq!(Domain::APP, k.domain);
2609 assert_eq!(OWNER_UID as i64, k.nspace);
2610 assert!(av.is_none());
2611 Ok(())
2612 },
2613 )
2614 .unwrap();
2615
2616 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
2617
2618 db.unbind_key(id_descriptor.clone(), KeyType::Client, OWNER_UID, |_, _| Ok(())).unwrap();
2619
2620 assert_eq!(
2621 Some(&KsError::Rc(ResponseCode::KEY_NOT_FOUND)),
2622 db.load_key_entry(
2623 id_descriptor,
2624 KeyType::Client,
2625 KeyEntryLoadBits::NONE,
2626 GRANTEE_UID,
2627 |_k, _av| Ok(()),
2628 )
2629 .unwrap_err()
2630 .root_cause()
2631 .downcast_ref::<KsError>()
2632 );
2633
2634 Ok(())
2635 }
2636
Janis Danisevskisaec14592020-11-12 09:41:49 -08002637 static KEY_LOCK_TEST_ALIAS: &str = "my super duper locked key";
2638
Janis Danisevskisaec14592020-11-12 09:41:49 -08002639 #[test]
2640 fn test_insert_and_load_full_keyentry_domain_app_concurrently() -> Result<()> {
2641 let handle = {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002642 let temp_dir = Arc::new(TempDir::new("id_lock_test")?);
2643 let temp_dir_clone = temp_dir.clone();
2644 let mut db = KeystoreDB::new(temp_dir.path())?;
Qi Wub9433b52020-12-01 14:52:46 +08002645 let key_id = make_test_key_entry(&mut db, Domain::APP, 33, KEY_LOCK_TEST_ALIAS, None)
Janis Danisevskisaec14592020-11-12 09:41:49 -08002646 .context("test_insert_and_load_full_keyentry_domain_app")?
2647 .0;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002648 let (_key_guard, key_entry) = db
2649 .load_key_entry(
2650 KeyDescriptor {
2651 domain: Domain::APP,
2652 nspace: 0,
2653 alias: Some(KEY_LOCK_TEST_ALIAS.to_string()),
2654 blob: None,
2655 },
2656 KeyType::Client,
2657 KeyEntryLoadBits::BOTH,
2658 33,
2659 |_k, _av| Ok(()),
2660 )
2661 .unwrap();
Qi Wub9433b52020-12-01 14:52:46 +08002662 assert_eq!(key_entry, make_test_key_entry_test_vector(key_id, None));
Janis Danisevskisaec14592020-11-12 09:41:49 -08002663 let state = Arc::new(AtomicU8::new(1));
2664 let state2 = state.clone();
2665
2666 // Spawning a second thread that attempts to acquire the key id lock
2667 // for the same key as the primary thread. The primary thread then
2668 // waits, thereby forcing the secondary thread into the second stage
2669 // of acquiring the lock (see KEY ID LOCK 2/2 above).
2670 // The test succeeds if the secondary thread observes the transition
2671 // of `state` from 1 to 2, despite having a whole second to overtake
2672 // the primary thread.
2673 let handle = thread::spawn(move || {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002674 let temp_dir = temp_dir_clone;
2675 let mut db = KeystoreDB::new(temp_dir.path()).unwrap();
Janis Danisevskisaec14592020-11-12 09:41:49 -08002676 assert!(db
2677 .load_key_entry(
2678 KeyDescriptor {
2679 domain: Domain::APP,
2680 nspace: 0,
2681 alias: Some(KEY_LOCK_TEST_ALIAS.to_string()),
2682 blob: None,
2683 },
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002684 KeyType::Client,
Janis Danisevskisaec14592020-11-12 09:41:49 -08002685 KeyEntryLoadBits::BOTH,
2686 33,
2687 |_k, _av| Ok(()),
2688 )
2689 .is_ok());
2690 // We should only see a 2 here because we can only return
2691 // from load_key_entry when the `_key_guard` expires,
2692 // which happens at the end of the scope.
2693 assert_eq!(2, state2.load(Ordering::Relaxed));
2694 });
2695
2696 thread::sleep(std::time::Duration::from_millis(1000));
2697
2698 assert_eq!(Ok(1), state.compare_exchange(1, 2, Ordering::Relaxed, Ordering::Relaxed));
2699
2700 // Return the handle from this scope so we can join with the
2701 // secondary thread after the key id lock has expired.
2702 handle
2703 // This is where the `_key_guard` goes out of scope,
2704 // which is the reason for concurrent load_key_entry on the same key
2705 // to unblock.
2706 };
2707 // Join with the secondary thread and unwrap, to propagate failing asserts to the
2708 // main test thread. We will not see failing asserts in secondary threads otherwise.
2709 handle.join().unwrap();
2710 Ok(())
2711 }
2712
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002713 #[test]
2714 fn list() -> Result<()> {
2715 let temp_dir = TempDir::new("list_test")?;
2716 let mut db = KeystoreDB::new(temp_dir.path())?;
2717 static LIST_O_ENTRIES: &[(Domain, i64, &str)] = &[
2718 (Domain::APP, 1, "test1"),
2719 (Domain::APP, 1, "test2"),
2720 (Domain::APP, 1, "test3"),
2721 (Domain::APP, 1, "test4"),
2722 (Domain::APP, 1, "test5"),
2723 (Domain::APP, 1, "test6"),
2724 (Domain::APP, 1, "test7"),
2725 (Domain::APP, 2, "test1"),
2726 (Domain::APP, 2, "test2"),
2727 (Domain::APP, 2, "test3"),
2728 (Domain::APP, 2, "test4"),
2729 (Domain::APP, 2, "test5"),
2730 (Domain::APP, 2, "test6"),
2731 (Domain::APP, 2, "test8"),
2732 (Domain::SELINUX, 100, "test1"),
2733 (Domain::SELINUX, 100, "test2"),
2734 (Domain::SELINUX, 100, "test3"),
2735 (Domain::SELINUX, 100, "test4"),
2736 (Domain::SELINUX, 100, "test5"),
2737 (Domain::SELINUX, 100, "test6"),
2738 (Domain::SELINUX, 100, "test9"),
2739 ];
2740
2741 let list_o_keys: Vec<(i64, i64)> = LIST_O_ENTRIES
2742 .iter()
2743 .map(|(domain, ns, alias)| {
Qi Wub9433b52020-12-01 14:52:46 +08002744 let entry = make_test_key_entry(&mut db, *domain, *ns, *alias, None)
2745 .unwrap_or_else(|e| {
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002746 panic!("Failed to insert {:?} {} {}. Error {:?}", domain, ns, alias, e)
2747 });
2748 (entry.id(), *ns)
2749 })
2750 .collect();
2751
2752 for (domain, namespace) in
2753 &[(Domain::APP, 1i64), (Domain::APP, 2i64), (Domain::SELINUX, 100i64)]
2754 {
2755 let mut list_o_descriptors: Vec<KeyDescriptor> = LIST_O_ENTRIES
2756 .iter()
2757 .filter_map(|(domain, ns, alias)| match ns {
2758 ns if *ns == *namespace => Some(KeyDescriptor {
2759 domain: *domain,
2760 nspace: *ns,
2761 alias: Some(alias.to_string()),
2762 blob: None,
2763 }),
2764 _ => None,
2765 })
2766 .collect();
2767 list_o_descriptors.sort();
2768 let mut list_result = db.list(*domain, *namespace)?;
2769 list_result.sort();
2770 assert_eq!(list_o_descriptors, list_result);
2771
2772 let mut list_o_ids: Vec<i64> = list_o_descriptors
2773 .into_iter()
2774 .map(|d| {
2775 let (_, entry) = db
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002776 .load_key_entry(
2777 d,
2778 KeyType::Client,
2779 KeyEntryLoadBits::NONE,
2780 *namespace as u32,
2781 |_, _| Ok(()),
2782 )
Janis Danisevskise92a5e62020-12-02 12:57:41 -08002783 .unwrap();
2784 entry.id()
2785 })
2786 .collect();
2787 list_o_ids.sort_unstable();
2788 let mut loaded_entries: Vec<i64> = list_o_keys
2789 .iter()
2790 .filter_map(|(id, ns)| match ns {
2791 ns if *ns == *namespace => Some(*id),
2792 _ => None,
2793 })
2794 .collect();
2795 loaded_entries.sort_unstable();
2796 assert_eq!(list_o_ids, loaded_entries);
2797 }
2798 assert_eq!(Vec::<KeyDescriptor>::new(), db.list(Domain::SELINUX, 101)?);
2799
2800 Ok(())
2801 }
2802
Joel Galenson0891bc12020-07-20 10:37:03 -07002803 // Helpers
2804
2805 // Checks that the given result is an error containing the given string.
2806 fn check_result_is_error_containing_string<T>(result: Result<T>, target: &str) {
2807 let error_str = format!(
2808 "{:#?}",
2809 result.err().unwrap_or_else(|| panic!("Expected the error: {}", target))
2810 );
2811 assert!(
2812 error_str.contains(target),
2813 "The string \"{}\" should contain \"{}\"",
2814 error_str,
2815 target
2816 );
2817 }
2818
Joel Galenson2aab4432020-07-22 15:27:57 -07002819 #[derive(Debug, PartialEq)]
Joel Galenson0891bc12020-07-20 10:37:03 -07002820 #[allow(dead_code)]
2821 struct KeyEntryRow {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002822 id: i64,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002823 key_type: KeyType,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002824 domain: Option<Domain>,
Joel Galenson0891bc12020-07-20 10:37:03 -07002825 namespace: Option<i64>,
2826 alias: Option<String>,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002827 state: KeyLifeCycle,
Joel Galenson0891bc12020-07-20 10:37:03 -07002828 }
2829
2830 fn get_keyentry(db: &KeystoreDB) -> Result<Vec<KeyEntryRow>> {
2831 db.conn
Joel Galenson2aab4432020-07-22 15:27:57 -07002832 .prepare("SELECT * FROM persistent.keyentry;")?
Joel Galenson0891bc12020-07-20 10:37:03 -07002833 .query_map(NO_PARAMS, |row| {
Joel Galenson0891bc12020-07-20 10:37:03 -07002834 Ok(KeyEntryRow {
2835 id: row.get(0)?,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08002836 key_type: row.get(1)?,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002837 domain: match row.get(2)? {
2838 Some(i) => Some(Domain(i)),
2839 None => None,
2840 },
Joel Galenson0891bc12020-07-20 10:37:03 -07002841 namespace: row.get(3)?,
2842 alias: row.get(4)?,
Janis Danisevskis93927dd2020-12-23 12:23:08 -08002843 state: row.get(5)?,
Joel Galenson0891bc12020-07-20 10:37:03 -07002844 })
2845 })?
2846 .map(|r| r.context("Could not read keyentry row."))
2847 .collect::<Result<Vec<_>>>()
2848 }
2849
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002850 // Note: The parameters and SecurityLevel associations are nonsensical. This
2851 // collection is only used to check if the parameters are preserved as expected by the
2852 // database.
Qi Wub9433b52020-12-01 14:52:46 +08002853 fn make_test_params(max_usage_count: Option<i32>) -> Vec<KeyParameter> {
2854 let mut params = vec![
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07002855 KeyParameter::new(KeyParameterValue::Invalid, SecurityLevel::TRUSTED_ENVIRONMENT),
2856 KeyParameter::new(
2857 KeyParameterValue::KeyPurpose(KeyPurpose::SIGN),
2858 SecurityLevel::TRUSTED_ENVIRONMENT,
2859 ),
2860 KeyParameter::new(
2861 KeyParameterValue::KeyPurpose(KeyPurpose::DECRYPT),
2862 SecurityLevel::TRUSTED_ENVIRONMENT,
2863 ),
2864 KeyParameter::new(
2865 KeyParameterValue::Algorithm(Algorithm::RSA),
2866 SecurityLevel::TRUSTED_ENVIRONMENT,
2867 ),
2868 KeyParameter::new(KeyParameterValue::KeySize(1024), SecurityLevel::TRUSTED_ENVIRONMENT),
2869 KeyParameter::new(
2870 KeyParameterValue::BlockMode(BlockMode::ECB),
2871 SecurityLevel::TRUSTED_ENVIRONMENT,
2872 ),
2873 KeyParameter::new(
2874 KeyParameterValue::BlockMode(BlockMode::GCM),
2875 SecurityLevel::TRUSTED_ENVIRONMENT,
2876 ),
2877 KeyParameter::new(KeyParameterValue::Digest(Digest::NONE), SecurityLevel::STRONGBOX),
2878 KeyParameter::new(
2879 KeyParameterValue::Digest(Digest::MD5),
2880 SecurityLevel::TRUSTED_ENVIRONMENT,
2881 ),
2882 KeyParameter::new(
2883 KeyParameterValue::Digest(Digest::SHA_2_224),
2884 SecurityLevel::TRUSTED_ENVIRONMENT,
2885 ),
2886 KeyParameter::new(
2887 KeyParameterValue::Digest(Digest::SHA_2_256),
2888 SecurityLevel::STRONGBOX,
2889 ),
2890 KeyParameter::new(
2891 KeyParameterValue::PaddingMode(PaddingMode::NONE),
2892 SecurityLevel::TRUSTED_ENVIRONMENT,
2893 ),
2894 KeyParameter::new(
2895 KeyParameterValue::PaddingMode(PaddingMode::RSA_OAEP),
2896 SecurityLevel::TRUSTED_ENVIRONMENT,
2897 ),
2898 KeyParameter::new(
2899 KeyParameterValue::PaddingMode(PaddingMode::RSA_PSS),
2900 SecurityLevel::STRONGBOX,
2901 ),
2902 KeyParameter::new(
2903 KeyParameterValue::PaddingMode(PaddingMode::RSA_PKCS1_1_5_SIGN),
2904 SecurityLevel::TRUSTED_ENVIRONMENT,
2905 ),
2906 KeyParameter::new(KeyParameterValue::CallerNonce, SecurityLevel::TRUSTED_ENVIRONMENT),
2907 KeyParameter::new(KeyParameterValue::MinMacLength(256), SecurityLevel::STRONGBOX),
2908 KeyParameter::new(
2909 KeyParameterValue::EcCurve(EcCurve::P_224),
2910 SecurityLevel::TRUSTED_ENVIRONMENT,
2911 ),
2912 KeyParameter::new(KeyParameterValue::EcCurve(EcCurve::P_256), SecurityLevel::STRONGBOX),
2913 KeyParameter::new(
2914 KeyParameterValue::EcCurve(EcCurve::P_384),
2915 SecurityLevel::TRUSTED_ENVIRONMENT,
2916 ),
2917 KeyParameter::new(
2918 KeyParameterValue::EcCurve(EcCurve::P_521),
2919 SecurityLevel::TRUSTED_ENVIRONMENT,
2920 ),
2921 KeyParameter::new(
2922 KeyParameterValue::RSAPublicExponent(3),
2923 SecurityLevel::TRUSTED_ENVIRONMENT,
2924 ),
2925 KeyParameter::new(
2926 KeyParameterValue::IncludeUniqueID,
2927 SecurityLevel::TRUSTED_ENVIRONMENT,
2928 ),
2929 KeyParameter::new(KeyParameterValue::BootLoaderOnly, SecurityLevel::STRONGBOX),
2930 KeyParameter::new(KeyParameterValue::RollbackResistance, SecurityLevel::STRONGBOX),
2931 KeyParameter::new(
2932 KeyParameterValue::ActiveDateTime(1234567890),
2933 SecurityLevel::STRONGBOX,
2934 ),
2935 KeyParameter::new(
2936 KeyParameterValue::OriginationExpireDateTime(1234567890),
2937 SecurityLevel::TRUSTED_ENVIRONMENT,
2938 ),
2939 KeyParameter::new(
2940 KeyParameterValue::UsageExpireDateTime(1234567890),
2941 SecurityLevel::TRUSTED_ENVIRONMENT,
2942 ),
2943 KeyParameter::new(
2944 KeyParameterValue::MinSecondsBetweenOps(1234567890),
2945 SecurityLevel::TRUSTED_ENVIRONMENT,
2946 ),
2947 KeyParameter::new(
2948 KeyParameterValue::MaxUsesPerBoot(1234567890),
2949 SecurityLevel::TRUSTED_ENVIRONMENT,
2950 ),
2951 KeyParameter::new(KeyParameterValue::UserID(1), SecurityLevel::STRONGBOX),
2952 KeyParameter::new(KeyParameterValue::UserSecureID(42), SecurityLevel::STRONGBOX),
2953 KeyParameter::new(
2954 KeyParameterValue::NoAuthRequired,
2955 SecurityLevel::TRUSTED_ENVIRONMENT,
2956 ),
2957 KeyParameter::new(
2958 KeyParameterValue::HardwareAuthenticatorType(HardwareAuthenticatorType::PASSWORD),
2959 SecurityLevel::TRUSTED_ENVIRONMENT,
2960 ),
2961 KeyParameter::new(KeyParameterValue::AuthTimeout(1234567890), SecurityLevel::SOFTWARE),
2962 KeyParameter::new(KeyParameterValue::AllowWhileOnBody, SecurityLevel::SOFTWARE),
2963 KeyParameter::new(
2964 KeyParameterValue::TrustedUserPresenceRequired,
2965 SecurityLevel::TRUSTED_ENVIRONMENT,
2966 ),
2967 KeyParameter::new(
2968 KeyParameterValue::TrustedConfirmationRequired,
2969 SecurityLevel::TRUSTED_ENVIRONMENT,
2970 ),
2971 KeyParameter::new(
2972 KeyParameterValue::UnlockedDeviceRequired,
2973 SecurityLevel::TRUSTED_ENVIRONMENT,
2974 ),
2975 KeyParameter::new(
2976 KeyParameterValue::ApplicationID(vec![1u8, 2u8, 3u8, 4u8]),
2977 SecurityLevel::SOFTWARE,
2978 ),
2979 KeyParameter::new(
2980 KeyParameterValue::ApplicationData(vec![4u8, 3u8, 2u8, 1u8]),
2981 SecurityLevel::SOFTWARE,
2982 ),
2983 KeyParameter::new(
2984 KeyParameterValue::CreationDateTime(12345677890),
2985 SecurityLevel::SOFTWARE,
2986 ),
2987 KeyParameter::new(
2988 KeyParameterValue::KeyOrigin(KeyOrigin::GENERATED),
2989 SecurityLevel::TRUSTED_ENVIRONMENT,
2990 ),
2991 KeyParameter::new(
2992 KeyParameterValue::RootOfTrust(vec![3u8, 2u8, 1u8, 4u8]),
2993 SecurityLevel::TRUSTED_ENVIRONMENT,
2994 ),
2995 KeyParameter::new(KeyParameterValue::OSVersion(1), SecurityLevel::TRUSTED_ENVIRONMENT),
2996 KeyParameter::new(KeyParameterValue::OSPatchLevel(2), SecurityLevel::SOFTWARE),
2997 KeyParameter::new(
2998 KeyParameterValue::UniqueID(vec![4u8, 3u8, 1u8, 2u8]),
2999 SecurityLevel::SOFTWARE,
3000 ),
3001 KeyParameter::new(
3002 KeyParameterValue::AttestationChallenge(vec![4u8, 3u8, 1u8, 2u8]),
3003 SecurityLevel::TRUSTED_ENVIRONMENT,
3004 ),
3005 KeyParameter::new(
3006 KeyParameterValue::AttestationApplicationID(vec![4u8, 3u8, 1u8, 2u8]),
3007 SecurityLevel::TRUSTED_ENVIRONMENT,
3008 ),
3009 KeyParameter::new(
3010 KeyParameterValue::AttestationIdBrand(vec![4u8, 3u8, 1u8, 2u8]),
3011 SecurityLevel::TRUSTED_ENVIRONMENT,
3012 ),
3013 KeyParameter::new(
3014 KeyParameterValue::AttestationIdDevice(vec![4u8, 3u8, 1u8, 2u8]),
3015 SecurityLevel::TRUSTED_ENVIRONMENT,
3016 ),
3017 KeyParameter::new(
3018 KeyParameterValue::AttestationIdProduct(vec![4u8, 3u8, 1u8, 2u8]),
3019 SecurityLevel::TRUSTED_ENVIRONMENT,
3020 ),
3021 KeyParameter::new(
3022 KeyParameterValue::AttestationIdSerial(vec![4u8, 3u8, 1u8, 2u8]),
3023 SecurityLevel::TRUSTED_ENVIRONMENT,
3024 ),
3025 KeyParameter::new(
3026 KeyParameterValue::AttestationIdIMEI(vec![4u8, 3u8, 1u8, 2u8]),
3027 SecurityLevel::TRUSTED_ENVIRONMENT,
3028 ),
3029 KeyParameter::new(
3030 KeyParameterValue::AttestationIdMEID(vec![4u8, 3u8, 1u8, 2u8]),
3031 SecurityLevel::TRUSTED_ENVIRONMENT,
3032 ),
3033 KeyParameter::new(
3034 KeyParameterValue::AttestationIdManufacturer(vec![4u8, 3u8, 1u8, 2u8]),
3035 SecurityLevel::TRUSTED_ENVIRONMENT,
3036 ),
3037 KeyParameter::new(
3038 KeyParameterValue::AttestationIdModel(vec![4u8, 3u8, 1u8, 2u8]),
3039 SecurityLevel::TRUSTED_ENVIRONMENT,
3040 ),
3041 KeyParameter::new(
3042 KeyParameterValue::VendorPatchLevel(3),
3043 SecurityLevel::TRUSTED_ENVIRONMENT,
3044 ),
3045 KeyParameter::new(
3046 KeyParameterValue::BootPatchLevel(4),
3047 SecurityLevel::TRUSTED_ENVIRONMENT,
3048 ),
3049 KeyParameter::new(
3050 KeyParameterValue::AssociatedData(vec![4u8, 3u8, 1u8, 2u8]),
3051 SecurityLevel::TRUSTED_ENVIRONMENT,
3052 ),
3053 KeyParameter::new(
3054 KeyParameterValue::Nonce(vec![4u8, 3u8, 1u8, 2u8]),
3055 SecurityLevel::TRUSTED_ENVIRONMENT,
3056 ),
3057 KeyParameter::new(
3058 KeyParameterValue::MacLength(256),
3059 SecurityLevel::TRUSTED_ENVIRONMENT,
3060 ),
3061 KeyParameter::new(
3062 KeyParameterValue::ResetSinceIdRotation,
3063 SecurityLevel::TRUSTED_ENVIRONMENT,
3064 ),
3065 KeyParameter::new(
3066 KeyParameterValue::ConfirmationToken(vec![5u8, 5u8, 5u8, 5u8]),
3067 SecurityLevel::TRUSTED_ENVIRONMENT,
3068 ),
Qi Wub9433b52020-12-01 14:52:46 +08003069 ];
3070 if let Some(value) = max_usage_count {
3071 params.push(KeyParameter::new(
3072 KeyParameterValue::UsageCountLimit(value),
3073 SecurityLevel::SOFTWARE,
3074 ));
3075 }
3076 params
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07003077 }
3078
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003079 fn make_test_key_entry(
3080 db: &mut KeystoreDB,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07003081 domain: Domain,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003082 namespace: i64,
3083 alias: &str,
Qi Wub9433b52020-12-01 14:52:46 +08003084 max_usage_count: Option<i32>,
Janis Danisevskisaec14592020-11-12 09:41:49 -08003085 ) -> Result<KeyIdGuard> {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003086 let key_id = db.create_key_entry(domain, namespace)?;
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003087 db.insert_blob(&key_id, SubComponentType::KEY_BLOB, TEST_KEY_BLOB)?;
3088 db.insert_blob(&key_id, SubComponentType::CERT, TEST_CERT_BLOB)?;
3089 db.insert_blob(&key_id, SubComponentType::CERT_CHAIN, TEST_CERT_CHAIN_BLOB)?;
Qi Wub9433b52020-12-01 14:52:46 +08003090
3091 let params = make_test_params(max_usage_count);
3092 db.insert_keyparameter(&key_id, &params)?;
3093
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003094 let mut metadata = KeyMetaData::new();
3095 metadata.add(KeyMetaEntry::EncryptedBy(EncryptedBy::Password));
3096 metadata.add(KeyMetaEntry::Salt(vec![1, 2, 3]));
3097 metadata.add(KeyMetaEntry::Iv(vec![2, 3, 1]));
3098 metadata.add(KeyMetaEntry::AeadTag(vec![3, 1, 2]));
3099 db.insert_key_metadata(&key_id, &metadata)?;
Janis Danisevskis4507f3b2021-01-13 16:34:39 -08003100 rebind_alias(db, &key_id, alias, domain, namespace)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003101 Ok(key_id)
3102 }
3103
Qi Wub9433b52020-12-01 14:52:46 +08003104 fn make_test_key_entry_test_vector(key_id: i64, max_usage_count: Option<i32>) -> KeyEntry {
3105 let params = make_test_params(max_usage_count);
3106
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003107 let mut metadata = KeyMetaData::new();
3108 metadata.add(KeyMetaEntry::EncryptedBy(EncryptedBy::Password));
3109 metadata.add(KeyMetaEntry::Salt(vec![1, 2, 3]));
3110 metadata.add(KeyMetaEntry::Iv(vec![2, 3, 1]));
3111 metadata.add(KeyMetaEntry::AeadTag(vec![3, 1, 2]));
3112
3113 KeyEntry {
3114 id: key_id,
3115 km_blob: Some(TEST_KEY_BLOB.to_vec()),
3116 cert: Some(TEST_CERT_BLOB.to_vec()),
3117 cert_chain: Some(TEST_CERT_CHAIN_BLOB.to_vec()),
3118 sec_level: SecurityLevel::TRUSTED_ENVIRONMENT,
Qi Wub9433b52020-12-01 14:52:46 +08003119 parameters: params,
Janis Danisevskisb42fc182020-12-15 08:41:27 -08003120 metadata,
3121 }
3122 }
3123
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003124 fn debug_dump_keyentry_table(db: &mut KeystoreDB) -> Result<()> {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003125 let mut stmt = db.conn.prepare(
3126 "SELECT id, key_type, domain, namespace, alias, state FROM persistent.keyentry;",
3127 )?;
3128 let rows = stmt.query_map::<(i64, KeyType, i32, i64, String, KeyLifeCycle), _, _>(
3129 NO_PARAMS,
3130 |row| {
3131 Ok((row.get(0)?, row.get(1)?, row.get(2)?, row.get(3)?, row.get(4)?, row.get(5)?))
3132 },
3133 )?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003134
3135 println!("Key entry table rows:");
3136 for r in rows {
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003137 let (id, key_type, domain, namespace, alias, state) = r.unwrap();
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003138 println!(
Janis Danisevskis93927dd2020-12-23 12:23:08 -08003139 " id: {} KeyType: {:?} Domain: {} Namespace: {} Alias: {} State: {:?}",
3140 id, key_type, domain, namespace, alias, state
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003141 );
3142 }
3143 Ok(())
3144 }
3145
3146 fn debug_dump_grant_table(db: &mut KeystoreDB) -> Result<()> {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08003147 let mut stmt = db
3148 .conn
3149 .prepare("SELECT id, grantee, keyentryid, access_vector FROM persistent.grant;")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003150 let rows = stmt.query_map::<(i64, i64, i64, i64), _, _>(NO_PARAMS, |row| {
3151 Ok((row.get(0)?, row.get(1)?, row.get(2)?, row.get(3)?))
3152 })?;
3153
3154 println!("Grant table rows:");
3155 for r in rows {
3156 let (id, gt, ki, av) = r.unwrap();
3157 println!(" id: {} grantee: {} key_id: {} access_vector: {}", id, gt, ki, av);
3158 }
3159 Ok(())
3160 }
3161
Joel Galenson0891bc12020-07-20 10:37:03 -07003162 // Use a custom random number generator that repeats each number once.
3163 // This allows us to test repeated elements.
3164
3165 thread_local! {
3166 static RANDOM_COUNTER: RefCell<i64> = RefCell::new(0);
3167 }
3168
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07003169 fn reset_random() {
3170 RANDOM_COUNTER.with(|counter| {
3171 *counter.borrow_mut() = 0;
3172 })
3173 }
3174
Joel Galenson0891bc12020-07-20 10:37:03 -07003175 pub fn random() -> i64 {
3176 RANDOM_COUNTER.with(|counter| {
3177 let result = *counter.borrow() / 2;
3178 *counter.borrow_mut() += 1;
3179 result
3180 })
3181 }
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00003182
3183 #[test]
3184 fn test_last_off_body() -> Result<()> {
3185 let mut db = new_test_db()?;
Janis Danisevskis5ed8c532021-01-11 14:19:42 -08003186 db.insert_last_off_body(MonotonicRawTime::now())?;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +00003187 let tx = db.conn.transaction_with_behavior(TransactionBehavior::Immediate)?;
3188 let last_off_body_1 = KeystoreDB::get_last_off_body(&tx)?;
3189 tx.commit()?;
3190 let one_second = Duration::from_secs(1);
3191 thread::sleep(one_second);
3192 db.update_last_off_body(MonotonicRawTime::now())?;
3193 let tx2 = db.conn.transaction_with_behavior(TransactionBehavior::Immediate)?;
3194 let last_off_body_2 = KeystoreDB::get_last_off_body(&tx2)?;
3195 tx2.commit()?;
3196 assert!(last_off_body_1.seconds() < last_off_body_2.seconds());
3197 Ok(())
3198 }
Joel Galenson26f4d012020-07-17 14:57:21 -07003199}