blob: a2cd6cd8a5d7fbc17716a3bde015aae426ce20f4 [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 Danisevskisbf15d732020-12-08 10:35:26 -080044use crate::db_utils;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -070045use crate::error::{Error as KsError, ResponseCode};
46use crate::key_parameter::{KeyParameter, SqlField, Tag};
47use crate::permission::KeyPermSet;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -070048use anyhow::{anyhow, Context, Result};
Janis Danisevskis60400fe2020-08-26 15:24:42 -070049
Shawn Willden708744a2020-12-11 13:05:27 +000050use android_hardware_security_keymint::aidl::android::hardware::security::keymint::SecurityLevel::SecurityLevel;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -070051use android_system_keystore2::aidl::android::system::keystore2::{
Janis Danisevskis04b02832020-10-26 09:21:40 -070052 Domain::Domain, KeyDescriptor::KeyDescriptor,
Janis Danisevskis60400fe2020-08-26 15:24:42 -070053};
54
Janis Danisevskisaec14592020-11-12 09:41:49 -080055use lazy_static::lazy_static;
Joel Galenson0891bc12020-07-20 10:37:03 -070056#[cfg(not(test))]
57use rand::prelude::random;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -070058use rusqlite::{
59 params, types::FromSql, types::FromSqlResult, types::ToSqlOutput, types::ValueRef, Connection,
Janis Danisevskisbf15d732020-12-08 10:35:26 -080060 OptionalExtension, ToSql, Transaction, TransactionBehavior, NO_PARAMS,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -070061};
Janis Danisevskisaec14592020-11-12 09:41:49 -080062use std::{
63 collections::HashSet,
Janis Danisevskisbf15d732020-12-08 10:35:26 -080064 path::Path,
65 sync::{Condvar, Mutex},
Janis Danisevskisaec14592020-11-12 09:41:49 -080066};
Joel Galenson0891bc12020-07-20 10:37:03 -070067#[cfg(test)]
68use tests::random;
Joel Galenson26f4d012020-07-17 14:57:21 -070069
Janis Danisevskis63f7bc82020-09-03 10:12:56 -070070/// Keys have a KeyMint blob component and optional public certificate and
71/// certificate chain components.
72/// KeyEntryLoadBits is a bitmap that indicates to `KeystoreDB::load_key_entry`
73/// which components shall be loaded from the database if present.
74#[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
75pub struct KeyEntryLoadBits(u32);
76
77impl KeyEntryLoadBits {
78 /// Indicate to `KeystoreDB::load_key_entry` that no component shall be loaded.
79 pub const NONE: KeyEntryLoadBits = Self(0);
80 /// Indicate to `KeystoreDB::load_key_entry` that the KeyMint component shall be loaded.
81 pub const KM: KeyEntryLoadBits = Self(1);
82 /// Indicate to `KeystoreDB::load_key_entry` that the Public components shall be loaded.
83 pub const PUBLIC: KeyEntryLoadBits = Self(2);
84 /// Indicate to `KeystoreDB::load_key_entry` that both components shall be loaded.
85 pub const BOTH: KeyEntryLoadBits = Self(3);
86
87 /// Returns true if this object indicates that the public components shall be loaded.
88 pub const fn load_public(&self) -> bool {
89 self.0 & Self::PUBLIC.0 != 0
90 }
91
92 /// Returns true if the object indicates that the KeyMint component shall be loaded.
93 pub const fn load_km(&self) -> bool {
94 self.0 & Self::KM.0 != 0
95 }
96}
97
Janis Danisevskisaec14592020-11-12 09:41:49 -080098lazy_static! {
99 static ref KEY_ID_LOCK: KeyIdLockDb = KeyIdLockDb::new();
100}
101
102struct KeyIdLockDb {
103 locked_keys: Mutex<HashSet<i64>>,
104 cond_var: Condvar,
105}
106
107/// A locked key. While a guard exists for a given key id, the same key cannot be loaded
108/// from the database a second time. Most functions manipulating the key blob database
109/// require a KeyIdGuard.
110#[derive(Debug)]
111pub struct KeyIdGuard(i64);
112
113impl KeyIdLockDb {
114 fn new() -> Self {
115 Self { locked_keys: Mutex::new(HashSet::new()), cond_var: Condvar::new() }
116 }
117
118 /// This function blocks until an exclusive lock for the given key entry id can
119 /// be acquired. It returns a guard object, that represents the lifecycle of the
120 /// acquired lock.
121 pub fn get(&self, key_id: i64) -> KeyIdGuard {
122 let mut locked_keys = self.locked_keys.lock().unwrap();
123 while locked_keys.contains(&key_id) {
124 locked_keys = self.cond_var.wait(locked_keys).unwrap();
125 }
126 locked_keys.insert(key_id);
127 KeyIdGuard(key_id)
128 }
129
130 /// This function attempts to acquire an exclusive lock on a given key id. If the
131 /// given key id is already taken the function returns None immediately. If a lock
132 /// can be acquired this function returns a guard object, that represents the
133 /// lifecycle of the acquired lock.
134 pub fn try_get(&self, key_id: i64) -> Option<KeyIdGuard> {
135 let mut locked_keys = self.locked_keys.lock().unwrap();
136 if locked_keys.insert(key_id) {
137 Some(KeyIdGuard(key_id))
138 } else {
139 None
140 }
141 }
142}
143
144impl KeyIdGuard {
145 /// Get the numeric key id of the locked key.
146 pub fn id(&self) -> i64 {
147 self.0
148 }
149}
150
151impl Drop for KeyIdGuard {
152 fn drop(&mut self) {
153 let mut locked_keys = KEY_ID_LOCK.locked_keys.lock().unwrap();
154 locked_keys.remove(&self.0);
Janis Danisevskis7fd53582020-11-23 13:40:34 -0800155 drop(locked_keys);
Janis Danisevskisaec14592020-11-12 09:41:49 -0800156 KEY_ID_LOCK.cond_var.notify_all();
157 }
158}
159
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700160/// This type represents a Keystore 2.0 key entry.
161/// An entry has a unique `id` by which it can be found in the database.
162/// It has a security level field, key parameters, and three optional fields
163/// for the KeyMint blob, public certificate and a public certificate chain.
Janis Danisevskisaec14592020-11-12 09:41:49 -0800164#[derive(Debug, Default, Eq, PartialEq, Ord, PartialOrd)]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700165pub struct KeyEntry {
166 id: i64,
167 km_blob: Option<Vec<u8>>,
168 cert: Option<Vec<u8>>,
169 cert_chain: Option<Vec<u8>>,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700170 sec_level: SecurityLevel,
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700171 parameters: Vec<KeyParameter>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700172}
173
174impl KeyEntry {
175 /// Returns the unique id of the Key entry.
176 pub fn id(&self) -> i64 {
177 self.id
178 }
179 /// Exposes the optional KeyMint blob.
180 pub fn km_blob(&self) -> &Option<Vec<u8>> {
181 &self.km_blob
182 }
183 /// Extracts the Optional KeyMint blob.
184 pub fn take_km_blob(&mut self) -> Option<Vec<u8>> {
185 self.km_blob.take()
186 }
187 /// Exposes the optional public certificate.
188 pub fn cert(&self) -> &Option<Vec<u8>> {
189 &self.cert
190 }
191 /// Extracts the optional public certificate.
192 pub fn take_cert(&mut self) -> Option<Vec<u8>> {
193 self.cert.take()
194 }
195 /// Exposes the optional public certificate chain.
196 pub fn cert_chain(&self) -> &Option<Vec<u8>> {
197 &self.cert_chain
198 }
199 /// Extracts the optional public certificate_chain.
200 pub fn take_cert_chain(&mut self) -> Option<Vec<u8>> {
201 self.cert_chain.take()
202 }
203 /// Returns the security level of the key entry.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700204 pub fn sec_level(&self) -> SecurityLevel {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700205 self.sec_level
206 }
Janis Danisevskis04b02832020-10-26 09:21:40 -0700207 /// Exposes the key parameters of this key entry.
208 pub fn key_parameters(&self) -> &Vec<KeyParameter> {
209 &self.parameters
210 }
211 /// Consumes this key entry and extracts the keyparameters from it.
212 pub fn into_key_parameters(self) -> Vec<KeyParameter> {
213 self.parameters
214 }
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700215}
216
217/// Indicates the sub component of a key entry for persistent storage.
218#[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
219pub struct SubComponentType(u32);
220impl SubComponentType {
221 /// Persistent identifier for a KeyMint blob.
222 pub const KM_BLOB: SubComponentType = Self(0);
223 /// Persistent identifier for a certificate blob.
224 pub const CERT: SubComponentType = Self(1);
225 /// Persistent identifier for a certificate chain blob.
226 pub const CERT_CHAIN: SubComponentType = Self(2);
227}
228
229impl ToSql for SubComponentType {
230 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
231 self.0.to_sql()
232 }
233}
234
235impl FromSql for SubComponentType {
236 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
237 Ok(Self(u32::column_result(value)?))
238 }
239}
240
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700241/// KeystoreDB wraps a connection to an SQLite database and tracks its
242/// ownership. It also implements all of Keystore 2.0's database functionality.
Joel Galenson26f4d012020-07-17 14:57:21 -0700243pub struct KeystoreDB {
Joel Galenson26f4d012020-07-17 14:57:21 -0700244 conn: Connection,
245}
246
247impl KeystoreDB {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700248 /// This will create a new database connection connecting the two
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800249 /// files persistent.sqlite and perboot.sqlite in the given directory.
250 /// It also attempts to initialize all of the tables.
251 /// KeystoreDB cannot be used by multiple threads.
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700252 /// Each thread should open their own connection using `thread_local!`.
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800253 pub fn new(db_root: &Path) -> Result<Self> {
254 // Build the path to the sqlite files.
255 let mut persistent_path = db_root.to_path_buf();
256 persistent_path.push("persistent.sqlite");
257 let mut perboot_path = db_root.to_path_buf();
258 perboot_path.push("perboot.sqlite");
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700259
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800260 // Now convert them to strings prefixed with "file:"
261 let mut persistent_path_str = "file:".to_owned();
262 persistent_path_str.push_str(&persistent_path.to_string_lossy());
263 let mut perboot_path_str = "file:".to_owned();
264 perboot_path_str.push_str(&perboot_path.to_string_lossy());
265
266 let conn = Self::make_connection(&persistent_path_str, &perboot_path_str)?;
267
268 Self::init_tables(&conn)?;
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700269 Ok(Self { conn })
Joel Galenson2aab4432020-07-22 15:27:57 -0700270 }
271
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700272 fn init_tables(conn: &Connection) -> Result<()> {
273 conn.execute(
274 "CREATE TABLE IF NOT EXISTS persistent.keyentry (
Joel Galenson0891bc12020-07-20 10:37:03 -0700275 id INTEGER UNIQUE,
276 creation_date DATETIME,
277 domain INTEGER,
278 namespace INTEGER,
Joel Galenson319bb652020-12-01 13:24:08 -0800279 alias BLOB);",
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700280 NO_PARAMS,
281 )
282 .context("Failed to initialize \"keyentry\" table.")?;
283
284 conn.execute(
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700285 "CREATE VIEW IF NOT EXISTS persistent.orphaned AS
286 SELECT id FROM persistent.keyentry WHERE domain IS NULL;",
287 NO_PARAMS,
288 )
289 .context("Failed to initialize \"orphaned\" view")?;
290
291 conn.execute(
292 "CREATE TABLE IF NOT EXISTS persistent.blobentry (
293 id INTEGER PRIMARY KEY,
294 subcomponent_type INTEGER,
295 keyentryid INTEGER,
296 blob BLOB,
297 sec_level INTEGER);",
298 NO_PARAMS,
299 )
300 .context("Failed to initialize \"blobentry\" table.")?;
301
302 conn.execute(
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700303 "CREATE TABLE IF NOT EXISTS persistent.keyparameter (
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000304 keyentryid INTEGER,
305 tag INTEGER,
306 data ANY,
307 security_level INTEGER);",
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700308 NO_PARAMS,
309 )
310 .context("Failed to initialize \"keyparameter\" table.")?;
311
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700312 conn.execute(
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800313 "CREATE TABLE IF NOT EXISTS persistent.grant (
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700314 id INTEGER UNIQUE,
315 grantee INTEGER,
316 keyentryid INTEGER,
317 access_vector INTEGER);",
318 NO_PARAMS,
319 )
320 .context("Failed to initialize \"grant\" table.")?;
321
Joel Galenson0891bc12020-07-20 10:37:03 -0700322 Ok(())
323 }
324
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700325 fn make_connection(persistent_file: &str, perboot_file: &str) -> Result<Connection> {
326 let conn =
327 Connection::open_in_memory().context("Failed to initialize SQLite connection.")?;
328
329 conn.execute("ATTACH DATABASE ? as persistent;", params![persistent_file])
330 .context("Failed to attach database persistent.")?;
331 conn.execute("ATTACH DATABASE ? as perboot;", params![perboot_file])
332 .context("Failed to attach database perboot.")?;
333
334 Ok(conn)
335 }
336
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700337 /// Creates a new key entry and allocates a new randomized id for the new key.
338 /// The key id gets associated with a domain and namespace but not with an alias.
339 /// To complete key generation `rebind_alias` should be called after all of the
340 /// key artifacts, i.e., blobs and parameters have been associated with the new
341 /// key id. Finalizing with `rebind_alias` makes the creation of a new key entry
342 /// atomic even if key generation is not.
Janis Danisevskisaec14592020-11-12 09:41:49 -0800343 pub fn create_key_entry(&self, domain: Domain, namespace: i64) -> Result<KeyIdGuard> {
Joel Galenson0891bc12020-07-20 10:37:03 -0700344 match domain {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700345 Domain::APP | Domain::SELINUX => {}
Joel Galenson0891bc12020-07-20 10:37:03 -0700346 _ => {
347 return Err(KsError::sys())
348 .context(format!("Domain {:?} must be either App or SELinux.", domain));
349 }
350 }
Janis Danisevskisaec14592020-11-12 09:41:49 -0800351 Ok(KEY_ID_LOCK.get(
352 Self::insert_with_retry(|id| {
353 self.conn.execute(
354 "INSERT into persistent.keyentry (id, creation_date, domain, namespace, alias)
Joel Galenson0891bc12020-07-20 10:37:03 -0700355 VALUES(?, datetime('now'), ?, ?, NULL);",
Janis Danisevskisaec14592020-11-12 09:41:49 -0800356 params![id, domain.0 as u32, namespace],
357 )
358 })
359 .context("In create_key_entry")?,
360 ))
Joel Galenson26f4d012020-07-17 14:57:21 -0700361 }
Joel Galenson33c04ad2020-08-03 11:04:38 -0700362
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700363 /// Inserts a new blob and associates it with the given key id. Each blob
364 /// has a sub component type and a security level.
365 /// Each key can have one of each sub component type associated. If more
366 /// are added only the most recent can be retrieved, and superseded blobs
367 /// will get garbage collected. The security level field of components
368 /// other than `SubComponentType::KM_BLOB` are ignored.
369 pub fn insert_blob(
370 &mut self,
Janis Danisevskisaec14592020-11-12 09:41:49 -0800371 key_id: &KeyIdGuard,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700372 sc_type: SubComponentType,
373 blob: &[u8],
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700374 sec_level: SecurityLevel,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700375 ) -> Result<()> {
376 self.conn
377 .execute(
378 "INSERT into persistent.blobentry (subcomponent_type, keyentryid, blob, sec_level)
379 VALUES (?, ?, ?, ?);",
Janis Danisevskisaec14592020-11-12 09:41:49 -0800380 params![sc_type, key_id.0, blob, sec_level.0],
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700381 )
382 .context("Failed to insert blob.")?;
383 Ok(())
384 }
385
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700386 /// Inserts a collection of key parameters into the `persistent.keyparameter` table
387 /// and associates them with the given `key_id`.
388 pub fn insert_keyparameter<'a>(
389 &mut self,
Janis Danisevskisaec14592020-11-12 09:41:49 -0800390 key_id: &KeyIdGuard,
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700391 params: impl IntoIterator<Item = &'a KeyParameter>,
392 ) -> Result<()> {
393 let mut stmt = self
394 .conn
395 .prepare(
396 "INSERT into persistent.keyparameter (keyentryid, tag, data, security_level)
397 VALUES (?, ?, ?, ?);",
398 )
399 .context("In insert_keyparameter: Failed to prepare statement.")?;
400
401 let iter = params.into_iter();
402 for p in iter {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700403 stmt.insert(params![
Janis Danisevskisaec14592020-11-12 09:41:49 -0800404 key_id.0,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700405 p.get_tag().0,
406 p.key_parameter_value(),
407 p.security_level().0
408 ])
409 .with_context(|| format!("In insert_keyparameter: Failed to insert {:?}", p))?;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700410 }
411 Ok(())
412 }
413
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700414 /// Updates the alias column of the given key id `newid` with the given alias,
415 /// and atomically, removes the alias, domain, and namespace from another row
416 /// with the same alias-domain-namespace tuple if such row exits.
Joel Galenson33c04ad2020-08-03 11:04:38 -0700417 pub fn rebind_alias(
418 &mut self,
Janis Danisevskisaec14592020-11-12 09:41:49 -0800419 newid: &KeyIdGuard,
Joel Galenson33c04ad2020-08-03 11:04:38 -0700420 alias: &str,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700421 domain: Domain,
Joel Galenson33c04ad2020-08-03 11:04:38 -0700422 namespace: i64,
423 ) -> Result<()> {
424 match domain {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700425 Domain::APP | Domain::SELINUX => {}
Joel Galenson33c04ad2020-08-03 11:04:38 -0700426 _ => {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700427 return Err(KsError::sys()).context(format!(
428 "In rebind_alias: Domain {:?} must be either App or SELinux.",
429 domain
430 ));
Joel Galenson33c04ad2020-08-03 11:04:38 -0700431 }
432 }
433 let tx = self
434 .conn
435 .transaction_with_behavior(TransactionBehavior::Immediate)
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700436 .context("In rebind_alias: Failed to initialize transaction.")?;
Joel Galenson33c04ad2020-08-03 11:04:38 -0700437 tx.execute(
438 "UPDATE persistent.keyentry
439 SET alias = NULL, domain = NULL, namespace = NULL
440 WHERE alias = ? AND domain = ? AND namespace = ?;",
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700441 params![alias, domain.0 as u32, namespace],
Joel Galenson33c04ad2020-08-03 11:04:38 -0700442 )
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700443 .context("In rebind_alias: Failed to rebind existing entry.")?;
Joel Galenson33c04ad2020-08-03 11:04:38 -0700444 let result = tx
445 .execute(
446 "UPDATE persistent.keyentry
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700447 SET alias = ?
448 WHERE id = ? AND domain = ? AND namespace = ?;",
Janis Danisevskisaec14592020-11-12 09:41:49 -0800449 params![alias, newid.0, domain.0 as u32, namespace],
Joel Galenson33c04ad2020-08-03 11:04:38 -0700450 )
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700451 .context("In rebind_alias: Failed to set alias.")?;
Joel Galenson33c04ad2020-08-03 11:04:38 -0700452 if result != 1 {
453 // Note that this explicit rollback is not required, as
454 // the transaction should rollback if we do not commit it.
455 // We leave it here for readability.
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700456 tx.rollback().context("In rebind_alias: Failed to rollback a failed transaction.")?;
Joel Galenson33c04ad2020-08-03 11:04:38 -0700457 return Err(KsError::sys()).context(format!(
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700458 "In rebind_alias: Expected to update a single entry but instead updated {}.",
Joel Galenson33c04ad2020-08-03 11:04:38 -0700459 result
460 ));
461 }
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700462 tx.commit().context("In rebind_alias: Failed to commit transaction.")
463 }
464
465 // Helper function loading the key_id given the key descriptor
466 // tuple comprising domain, namespace, and alias.
467 // Requires a valid transaction.
468 fn load_key_entry_id(key: &KeyDescriptor, tx: &Transaction) -> Result<i64> {
469 let alias = key
470 .alias
471 .as_ref()
472 .map_or_else(|| Err(KsError::sys()), Ok)
473 .context("In load_key_entry_id: Alias must be specified.")?;
474 let mut stmt = tx
475 .prepare(
476 "SELECT id FROM persistent.keyentry
477 WHERE
478 domain = ?
479 AND namespace = ?
480 AND alias = ?;",
481 )
482 .context("In load_key_entry_id: Failed to select from keyentry table.")?;
483 let mut rows = stmt
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700484 .query(params![key.domain.0 as u32, key.nspace, alias])
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700485 .context("In load_key_entry_id: Failed to read from keyentry table.")?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800486 db_utils::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700487 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700488 .get(0)
489 .context("Failed to unpack id.")
490 })
491 .context("In load_key_entry_id.")
492 }
493
494 /// This helper function completes the access tuple of a key, which is required
495 /// to perform access control. The strategy depends on the `domain` field in the
496 /// key descriptor.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700497 /// * Domain::SELINUX: The access tuple is complete and this function only loads
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700498 /// the key_id for further processing.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700499 /// * Domain::APP: Like Domain::SELINUX, but the tuple is completed by `caller_uid`
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700500 /// which serves as the namespace.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700501 /// * Domain::GRANT: The grant table is queried for the `key_id` and the
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700502 /// `access_vector`.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700503 /// * Domain::KEY_ID: The keyentry table is queried for the owning `domain` and
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700504 /// `namespace`.
505 /// In each case the information returned is sufficient to perform the access
506 /// check and the key id can be used to load further key artifacts.
507 fn load_access_tuple(
508 tx: &Transaction,
509 key: KeyDescriptor,
510 caller_uid: u32,
511 ) -> Result<(i64, KeyDescriptor, Option<KeyPermSet>)> {
512 match key.domain {
513 // Domain App or SELinux. In this case we load the key_id from
514 // the keyentry database for further loading of key components.
515 // We already have the full access tuple to perform access control.
516 // The only distinction is that we use the caller_uid instead
517 // of the caller supplied namespace if the domain field is
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700518 // Domain::APP.
519 Domain::APP | Domain::SELINUX => {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700520 let mut access_key = key;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700521 if access_key.domain == Domain::APP {
522 access_key.nspace = caller_uid as i64;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700523 }
524 let key_id = Self::load_key_entry_id(&access_key, &tx)
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700525 .with_context(|| format!("With key.domain = {:?}.", access_key.domain))?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700526
527 Ok((key_id, access_key, None))
528 }
529
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700530 // Domain::GRANT. In this case we load the key_id and the access_vector
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700531 // from the grant table.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700532 Domain::GRANT => {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700533 let mut stmt = tx
534 .prepare(
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800535 "SELECT keyentryid, access_vector FROM persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700536 WHERE grantee = ? AND id = ?;",
537 )
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700538 .context("Domain::GRANT prepare statement failed")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700539 let mut rows = stmt
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700540 .query(params![caller_uid as i64, key.nspace])
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700541 .context("Domain:Grant: query failed.")?;
542 let (key_id, access_vector): (i64, i32) =
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800543 db_utils::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700544 let r =
545 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700546 Ok((
547 r.get(0).context("Failed to unpack key_id.")?,
548 r.get(1).context("Failed to unpack access_vector.")?,
549 ))
550 })
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700551 .context("Domain::GRANT.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700552 Ok((key_id, key, Some(access_vector.into())))
553 }
554
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700555 // Domain::KEY_ID. In this case we load the domain and namespace from the
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700556 // keyentry database because we need them for access control.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700557 Domain::KEY_ID => {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700558 let mut stmt = tx
559 .prepare(
560 "SELECT domain, namespace FROM persistent.keyentry
561 WHERE
562 id = ?;",
563 )
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700564 .context("Domain::KEY_ID: prepare statement failed")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700565 let mut rows =
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700566 stmt.query(params![key.nspace]).context("Domain::KEY_ID: query failed.")?;
567 let (domain, namespace): (Domain, i64) =
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800568 db_utils::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700569 let r =
570 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700571 Ok((
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700572 Domain(r.get(0).context("Failed to unpack domain.")?),
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700573 r.get(1).context("Failed to unpack namespace.")?,
574 ))
575 })
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700576 .context("Domain::KEY_ID.")?;
577 let key_id = key.nspace;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700578 let mut access_key = key;
579 access_key.domain = domain;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700580 access_key.nspace = namespace;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700581
582 Ok((key_id, access_key, None))
583 }
584 _ => Err(anyhow!(KsError::sys())),
585 }
586 }
587
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700588 fn load_blob_components(
589 key_id: i64,
590 load_bits: KeyEntryLoadBits,
591 tx: &Transaction,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700592 ) -> Result<(SecurityLevel, Option<Vec<u8>>, Option<Vec<u8>>, Option<Vec<u8>>)> {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700593 let mut stmt = tx
594 .prepare(
595 "SELECT MAX(id), sec_level, subcomponent_type, blob FROM persistent.blobentry
596 WHERE keyentryid = ? GROUP BY subcomponent_type;",
597 )
598 .context("In load_blob_components: prepare statement failed.")?;
599
600 let mut rows =
601 stmt.query(params![key_id]).context("In load_blob_components: query failed.")?;
602
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700603 let mut sec_level: SecurityLevel = Default::default();
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700604 let mut km_blob: Option<Vec<u8>> = None;
605 let mut cert_blob: Option<Vec<u8>> = None;
606 let mut cert_chain_blob: Option<Vec<u8>> = None;
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800607 db_utils::with_rows_extract_all(&mut rows, |row| {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700608 let sub_type: SubComponentType =
609 row.get(2).context("Failed to extract subcomponent_type.")?;
610 match (sub_type, load_bits.load_public()) {
611 (SubComponentType::KM_BLOB, _) => {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700612 sec_level =
613 SecurityLevel(row.get(1).context("Failed to extract security level.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700614 if load_bits.load_km() {
615 km_blob = Some(row.get(3).context("Failed to extract KM blob.")?);
616 }
617 }
618 (SubComponentType::CERT, true) => {
619 cert_blob =
620 Some(row.get(3).context("Failed to extract public certificate blob.")?);
621 }
622 (SubComponentType::CERT_CHAIN, true) => {
623 cert_chain_blob =
624 Some(row.get(3).context("Failed to extract certificate chain blob.")?);
625 }
626 (SubComponentType::CERT, _) | (SubComponentType::CERT_CHAIN, _) => {}
627 _ => Err(KsError::sys()).context("Unknown subcomponent type.")?,
628 }
629 Ok(())
630 })
631 .context("In load_blob_components.")?;
632
633 Ok((sec_level, km_blob, cert_blob, cert_chain_blob))
634 }
635
636 fn load_key_parameters(key_id: i64, tx: &Transaction) -> Result<Vec<KeyParameter>> {
637 let mut stmt = tx
638 .prepare(
639 "SELECT tag, data, security_level from persistent.keyparameter
640 WHERE keyentryid = ?;",
641 )
642 .context("In load_key_parameters: prepare statement failed.")?;
643
644 let mut parameters: Vec<KeyParameter> = Vec::new();
645
646 let mut rows =
647 stmt.query(params![key_id]).context("In load_key_parameters: query failed.")?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800648 db_utils::with_rows_extract_all(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700649 let tag = Tag(row.get(0).context("Failed to read tag.")?);
650 let sec_level = SecurityLevel(row.get(2).context("Failed to read sec_level.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700651 parameters.push(
652 KeyParameter::new_from_sql(tag, &SqlField::new(1, &row), sec_level)
653 .context("Failed to read KeyParameter.")?,
654 );
655 Ok(())
656 })
657 .context("In load_key_parameters.")?;
658
659 Ok(parameters)
660 }
661
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700662 /// Load a key entry by the given key descriptor.
663 /// It uses the `check_permission` callback to verify if the access is allowed
664 /// given the key access tuple read from the database using `load_access_tuple`.
665 /// With `load_bits` the caller may specify which blobs shall be loaded from
666 /// the blob database.
667 pub fn load_key_entry(
668 &mut self,
669 key: KeyDescriptor,
670 load_bits: KeyEntryLoadBits,
671 caller_uid: u32,
672 check_permission: impl FnOnce(&KeyDescriptor, Option<KeyPermSet>) -> Result<()>,
Janis Danisevskisaec14592020-11-12 09:41:49 -0800673 ) -> Result<(KeyIdGuard, KeyEntry)> {
674 // KEY ID LOCK 1/2
675 // If we got a key descriptor with a key id we can get the lock right away.
676 // Otherwise we have to defer it until we know the key id.
677 let key_id_guard = match key.domain {
678 Domain::KEY_ID => Some(KEY_ID_LOCK.get(key.nspace)),
679 _ => None,
680 };
681
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700682 let tx = self
683 .conn
Janis Danisevskisaec14592020-11-12 09:41:49 -0800684 .unchecked_transaction()
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700685 .context("In load_key_entry: Failed to initialize transaction.")?;
686
687 // Load the key_id and complete the access control tuple.
688 let (key_id, access_key_descriptor, access_vector) =
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700689 Self::load_access_tuple(&tx, key, caller_uid).context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700690
691 // Perform access control. It is vital that we return here if the permission is denied.
692 // So do not touch that '?' at the end.
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700693 check_permission(&access_key_descriptor, access_vector).context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700694
Janis Danisevskisaec14592020-11-12 09:41:49 -0800695 // KEY ID LOCK 2/2
696 // If we did not get a key id lock by now, it was because we got a key descriptor
697 // without a key id. At this point we got the key id, so we can try and get a lock.
698 // However, we cannot block here, because we are in the middle of the transaction.
699 // So first we try to get the lock non blocking. If that fails, we roll back the
700 // transaction and block until we get the lock. After we successfully got the lock,
701 // we start a new transaction and load the access tuple again.
702 //
703 // We don't need to perform access control again, because we already established
704 // that the caller had access to the given key. But we need to make sure that the
705 // key id still exists. So we have to load the key entry by key id this time.
706 let (key_id_guard, tx) = match key_id_guard {
707 None => match KEY_ID_LOCK.try_get(key_id) {
708 None => {
709 // Roll back the transaction.
710 tx.rollback().context("In load_key_entry: Failed to roll back transaction.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700711
Janis Danisevskisaec14592020-11-12 09:41:49 -0800712 // Block until we have a key id lock.
713 let key_id_guard = KEY_ID_LOCK.get(key_id);
714
715 // Create a new transaction.
716 let tx = self.conn.unchecked_transaction().context(
717 "In load_key_entry: Failed to initialize transaction. (deferred key lock)",
718 )?;
719
720 Self::load_access_tuple(
721 &tx,
722 // This time we have to load the key by the retrieved key id, because the
723 // alias may have been rebound after we rolled back the transaction.
724 KeyDescriptor {
725 domain: Domain::KEY_ID,
726 nspace: key_id,
727 ..Default::default()
728 },
729 caller_uid,
730 )
731 .context("In load_key_entry. (deferred key lock)")?;
732 (key_id_guard, tx)
733 }
734 Some(l) => (l, tx),
735 },
736 Some(key_id_guard) => (key_id_guard, tx),
737 };
738
739 let (sec_level, km_blob, cert_blob, cert_chain_blob) =
740 Self::load_blob_components(key_id_guard.id(), load_bits, &tx)
741 .context("In load_key_entry.")?;
742
743 let parameters =
744 Self::load_key_parameters(key_id_guard.id(), &tx).context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700745
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700746 tx.commit().context("In load_key_entry: Failed to commit transaction.")?;
747
Janis Danisevskisaec14592020-11-12 09:41:49 -0800748 let key_id = key_id_guard.id();
749 Ok((
750 key_id_guard,
751 KeyEntry {
752 id: key_id,
753 km_blob,
754 cert: cert_blob,
755 cert_chain: cert_chain_blob,
756 sec_level,
757 parameters,
758 },
759 ))
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700760 }
761
762 /// Adds a grant to the grant table.
763 /// Like `load_key_entry` this function loads the access tuple before
764 /// it uses the callback for a permission check. Upon success,
765 /// it inserts the `grantee_uid`, `key_id`, and `access_vector` into the
766 /// grant table. The new row will have a randomized id, which is used as
767 /// grant id in the namespace field of the resulting KeyDescriptor.
768 pub fn grant(
769 &mut self,
770 key: KeyDescriptor,
771 caller_uid: u32,
772 grantee_uid: u32,
773 access_vector: KeyPermSet,
774 check_permission: impl FnOnce(&KeyDescriptor, &KeyPermSet) -> Result<()>,
775 ) -> Result<KeyDescriptor> {
776 let tx = self
777 .conn
778 .transaction_with_behavior(TransactionBehavior::Immediate)
779 .context("In grant: Failed to initialize transaction.")?;
780
781 // Load the key_id and complete the access control tuple.
782 // We ignore the access vector here because grants cannot be granted.
783 // The access vector returned here expresses the permissions the
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700784 // grantee has if key.domain == Domain::GRANT. But this vector
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700785 // cannot include the grant permission by design, so there is no way the
786 // subsequent permission check can pass.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700787 // We could check key.domain == Domain::GRANT and fail early.
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700788 // But even if we load the access tuple by grant here, the permission
789 // check denies the attempt to create a grant by grant descriptor.
790 let (key_id, access_key_descriptor, _) =
791 Self::load_access_tuple(&tx, key, caller_uid).context("In grant")?;
792
793 // Perform access control. It is vital that we return here if the permission
794 // was denied. So do not touch that '?' at the end of the line.
795 // This permission check checks if the caller has the grant permission
796 // for the given key and in addition to all of the permissions
797 // expressed in `access_vector`.
798 check_permission(&access_key_descriptor, &access_vector)
799 .context("In grant: check_permission failed.")?;
800
801 let grant_id = if let Some(grant_id) = tx
802 .query_row(
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800803 "SELECT id FROM persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700804 WHERE keyentryid = ? AND grantee = ?;",
805 params![key_id, grantee_uid],
806 |row| row.get(0),
807 )
808 .optional()
809 .context("In grant: Failed get optional existing grant id.")?
810 {
811 tx.execute(
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800812 "UPDATE persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700813 SET access_vector = ?
814 WHERE id = ?;",
815 params![i32::from(access_vector), grant_id],
816 )
817 .context("In grant: Failed to update existing grant.")?;
818 grant_id
819 } else {
Joel Galenson845f74b2020-09-09 14:11:55 -0700820 Self::insert_with_retry(|id| {
821 tx.execute(
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800822 "INSERT INTO persistent.grant (id, grantee, keyentryid, access_vector)
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700823 VALUES (?, ?, ?, ?);",
Joel Galenson845f74b2020-09-09 14:11:55 -0700824 params![id, grantee_uid, key_id, i32::from(access_vector)],
825 )
826 })
827 .context("In grant")?
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700828 };
829 tx.commit().context("In grant: failed to commit transaction.")?;
830
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700831 Ok(KeyDescriptor { domain: Domain::GRANT, nspace: grant_id, alias: None, blob: None })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700832 }
833
834 /// This function checks permissions like `grant` and `load_key_entry`
835 /// before removing a grant from the grant table.
836 pub fn ungrant(
837 &mut self,
838 key: KeyDescriptor,
839 caller_uid: u32,
840 grantee_uid: u32,
841 check_permission: impl FnOnce(&KeyDescriptor) -> Result<()>,
842 ) -> Result<()> {
843 let tx = self
844 .conn
845 .transaction_with_behavior(TransactionBehavior::Immediate)
846 .context("In ungrant: Failed to initialize transaction.")?;
847
848 // Load the key_id and complete the access control tuple.
849 // We ignore the access vector here because grants cannot be granted.
850 let (key_id, access_key_descriptor, _) =
851 Self::load_access_tuple(&tx, key, caller_uid).context("In ungrant.")?;
852
853 // Perform access control. We must return here if the permission
854 // was denied. So do not touch the '?' at the end of this line.
855 check_permission(&access_key_descriptor).context("In grant: check_permission failed.")?;
856
857 tx.execute(
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800858 "DELETE FROM persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700859 WHERE keyentryid = ? AND grantee = ?;",
860 params![key_id, grantee_uid],
861 )
862 .context("Failed to delete grant.")?;
863
864 tx.commit().context("In ungrant: failed to commit transaction.")?;
865
866 Ok(())
867 }
868
Joel Galenson845f74b2020-09-09 14:11:55 -0700869 // Generates a random id and passes it to the given function, which will
870 // try to insert it into a database. If that insertion fails, retry;
871 // otherwise return the id.
872 fn insert_with_retry(inserter: impl Fn(i64) -> rusqlite::Result<usize>) -> Result<i64> {
873 loop {
874 let newid: i64 = random();
875 match inserter(newid) {
876 // If the id already existed, try again.
877 Err(rusqlite::Error::SqliteFailure(
878 libsqlite3_sys::Error {
879 code: libsqlite3_sys::ErrorCode::ConstraintViolation,
880 extended_code: libsqlite3_sys::SQLITE_CONSTRAINT_UNIQUE,
881 },
882 _,
883 )) => (),
884 Err(e) => {
885 return Err(e).context("In insert_with_retry: failed to insert into database.")
886 }
887 _ => return Ok(newid),
888 }
889 }
890 }
Joel Galenson26f4d012020-07-17 14:57:21 -0700891}
892
893#[cfg(test)]
894mod tests {
895
896 use super::*;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700897 use crate::key_parameter::{
898 Algorithm, BlockMode, Digest, EcCurve, HardwareAuthenticatorType, KeyOrigin, KeyParameter,
899 KeyParameterValue, KeyPurpose, PaddingMode, SecurityLevel,
900 };
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700901 use crate::key_perm_set;
902 use crate::permission::{KeyPerm, KeyPermSet};
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800903 use crate::test::utils::TempDir;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700904 use rusqlite::NO_PARAMS;
Joel Galenson0891bc12020-07-20 10:37:03 -0700905 use std::cell::RefCell;
Janis Danisevskisaec14592020-11-12 09:41:49 -0800906 use std::sync::atomic::{AtomicU8, Ordering};
907 use std::sync::Arc;
908 use std::thread;
Joel Galenson0891bc12020-07-20 10:37:03 -0700909
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700910 fn new_test_db() -> Result<KeystoreDB> {
911 let conn = KeystoreDB::make_connection("file::memory:", "file::memory:")?;
912
913 KeystoreDB::init_tables(&conn).context("Failed to initialize tables.")?;
914 Ok(KeystoreDB { conn })
915 }
916
Joel Galenson0891bc12020-07-20 10:37:03 -0700917 // Ensure that we're using the "injected" random function, not the real one.
918 #[test]
919 fn test_mocked_random() {
920 let rand1 = random();
921 let rand2 = random();
922 let rand3 = random();
923 if rand1 == rand2 {
924 assert_eq!(rand2 + 1, rand3);
925 } else {
926 assert_eq!(rand1 + 1, rand2);
927 assert_eq!(rand2, rand3);
928 }
929 }
Joel Galenson26f4d012020-07-17 14:57:21 -0700930
Joel Galenson26f4d012020-07-17 14:57:21 -0700931 // Test that we have the correct tables.
932 #[test]
933 fn test_tables() -> Result<()> {
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700934 let db = new_test_db()?;
Joel Galenson26f4d012020-07-17 14:57:21 -0700935 let tables = db
936 .conn
Joel Galenson2aab4432020-07-22 15:27:57 -0700937 .prepare("SELECT name from persistent.sqlite_master WHERE type='table' ORDER BY name;")?
Joel Galenson26f4d012020-07-17 14:57:21 -0700938 .query_map(params![], |row| row.get(0))?
939 .collect::<rusqlite::Result<Vec<String>>>()?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800940 assert_eq!(tables.len(), 4);
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700941 assert_eq!(tables[0], "blobentry");
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800942 assert_eq!(tables[1], "grant");
943 assert_eq!(tables[2], "keyentry");
944 assert_eq!(tables[3], "keyparameter");
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700945 let tables = db
946 .conn
947 .prepare("SELECT name from perboot.sqlite_master WHERE type='table' ORDER BY name;")?
948 .query_map(params![], |row| row.get(0))?
949 .collect::<rusqlite::Result<Vec<String>>>()?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800950 assert_eq!(tables.len(), 0);
Joel Galenson2aab4432020-07-22 15:27:57 -0700951 Ok(())
952 }
953
954 #[test]
955 fn test_persistence_for_files() -> Result<()> {
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800956 let temp_dir = TempDir::new("persistent_db_test")?;
957 let db = KeystoreDB::new(temp_dir.path())?;
Joel Galenson2aab4432020-07-22 15:27:57 -0700958
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700959 db.create_key_entry(Domain::APP, 100)?;
Joel Galenson2aab4432020-07-22 15:27:57 -0700960 let entries = get_keyentry(&db)?;
961 assert_eq!(entries.len(), 1);
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800962
963 let db = KeystoreDB::new(temp_dir.path())?;
Joel Galenson2aab4432020-07-22 15:27:57 -0700964
965 let entries_new = get_keyentry(&db)?;
966 assert_eq!(entries, entries_new);
967 Ok(())
968 }
969
970 #[test]
Joel Galenson0891bc12020-07-20 10:37:03 -0700971 fn test_create_key_entry() -> Result<()> {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700972 fn extractor(ke: &KeyEntryRow) -> (Domain, i64, Option<&str>) {
Joel Galenson0891bc12020-07-20 10:37:03 -0700973 (ke.domain.unwrap(), ke.namespace.unwrap(), ke.alias.as_deref())
974 }
975
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700976 let db = new_test_db()?;
Joel Galenson0891bc12020-07-20 10:37:03 -0700977
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700978 db.create_key_entry(Domain::APP, 100)?;
979 db.create_key_entry(Domain::SELINUX, 101)?;
Joel Galenson0891bc12020-07-20 10:37:03 -0700980
981 let entries = get_keyentry(&db)?;
982 assert_eq!(entries.len(), 2);
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700983 assert_eq!(extractor(&entries[0]), (Domain::APP, 100, None));
984 assert_eq!(extractor(&entries[1]), (Domain::SELINUX, 101, None));
Joel Galenson0891bc12020-07-20 10:37:03 -0700985
986 // Test that we must pass in a valid Domain.
987 check_result_is_error_containing_string(
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700988 db.create_key_entry(Domain::GRANT, 102),
989 "Domain Domain(1) must be either App or SELinux.",
Joel Galenson0891bc12020-07-20 10:37:03 -0700990 );
991 check_result_is_error_containing_string(
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700992 db.create_key_entry(Domain::BLOB, 103),
993 "Domain Domain(3) must be either App or SELinux.",
Joel Galenson0891bc12020-07-20 10:37:03 -0700994 );
995 check_result_is_error_containing_string(
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700996 db.create_key_entry(Domain::KEY_ID, 104),
997 "Domain Domain(4) must be either App or SELinux.",
Joel Galenson0891bc12020-07-20 10:37:03 -0700998 );
999
1000 Ok(())
1001 }
1002
Joel Galenson33c04ad2020-08-03 11:04:38 -07001003 #[test]
1004 fn test_rebind_alias() -> Result<()> {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001005 fn extractor(ke: &KeyEntryRow) -> (Option<Domain>, Option<i64>, Option<&str>) {
Joel Galenson33c04ad2020-08-03 11:04:38 -07001006 (ke.domain, ke.namespace, ke.alias.as_deref())
1007 }
1008
Janis Danisevskis4df44f42020-08-26 14:40:03 -07001009 let mut db = new_test_db()?;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001010 db.create_key_entry(Domain::APP, 42)?;
1011 db.create_key_entry(Domain::APP, 42)?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07001012 let entries = get_keyentry(&db)?;
1013 assert_eq!(entries.len(), 2);
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001014 assert_eq!(extractor(&entries[0]), (Some(Domain::APP), Some(42), None));
1015 assert_eq!(extractor(&entries[1]), (Some(Domain::APP), Some(42), None));
Joel Galenson33c04ad2020-08-03 11:04:38 -07001016
1017 // Test that the first call to rebind_alias sets the alias.
Janis Danisevskisaec14592020-11-12 09:41:49 -08001018 db.rebind_alias(&KEY_ID_LOCK.get(entries[0].id), "foo", Domain::APP, 42)?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07001019 let entries = get_keyentry(&db)?;
1020 assert_eq!(entries.len(), 2);
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001021 assert_eq!(extractor(&entries[0]), (Some(Domain::APP), Some(42), Some("foo")));
1022 assert_eq!(extractor(&entries[1]), (Some(Domain::APP), Some(42), None));
Joel Galenson33c04ad2020-08-03 11:04:38 -07001023
1024 // Test that the second call to rebind_alias also empties the old one.
Janis Danisevskisaec14592020-11-12 09:41:49 -08001025 db.rebind_alias(&KEY_ID_LOCK.get(entries[1].id), "foo", Domain::APP, 42)?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07001026 let entries = get_keyentry(&db)?;
1027 assert_eq!(entries.len(), 2);
Joel Galenson7fa5c412020-11-19 10:56:54 -08001028 assert_eq!(extractor(&entries[0]), (None, None, None));
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001029 assert_eq!(extractor(&entries[1]), (Some(Domain::APP), Some(42), Some("foo")));
Joel Galenson33c04ad2020-08-03 11:04:38 -07001030
1031 // Test that we must pass in a valid Domain.
1032 check_result_is_error_containing_string(
Janis Danisevskisaec14592020-11-12 09:41:49 -08001033 db.rebind_alias(&KEY_ID_LOCK.get(0), "foo", Domain::GRANT, 42),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001034 "Domain Domain(1) must be either App or SELinux.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07001035 );
1036 check_result_is_error_containing_string(
Janis Danisevskisaec14592020-11-12 09:41:49 -08001037 db.rebind_alias(&KEY_ID_LOCK.get(0), "foo", Domain::BLOB, 42),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001038 "Domain Domain(3) must be either App or SELinux.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07001039 );
1040 check_result_is_error_containing_string(
Janis Danisevskisaec14592020-11-12 09:41:49 -08001041 db.rebind_alias(&KEY_ID_LOCK.get(0), "foo", Domain::KEY_ID, 42),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001042 "Domain Domain(4) must be either App or SELinux.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07001043 );
1044
1045 // Test that we correctly handle setting an alias for something that does not exist.
1046 check_result_is_error_containing_string(
Janis Danisevskisaec14592020-11-12 09:41:49 -08001047 db.rebind_alias(&KEY_ID_LOCK.get(0), "foo", Domain::SELINUX, 42),
Joel Galenson33c04ad2020-08-03 11:04:38 -07001048 "Expected to update a single entry but instead updated 0",
1049 );
1050 // Test that we correctly abort the transaction in this case.
1051 let entries = get_keyentry(&db)?;
1052 assert_eq!(entries.len(), 2);
Joel Galenson7fa5c412020-11-19 10:56:54 -08001053 assert_eq!(extractor(&entries[0]), (None, None, None));
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001054 assert_eq!(extractor(&entries[1]), (Some(Domain::APP), Some(42), Some("foo")));
Joel Galenson33c04ad2020-08-03 11:04:38 -07001055
1056 Ok(())
1057 }
1058
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001059 #[test]
1060 fn test_grant_ungrant() -> Result<()> {
1061 const CALLER_UID: u32 = 15;
1062 const GRANTEE_UID: u32 = 12;
1063 const SELINUX_NAMESPACE: i64 = 7;
1064
1065 let mut db = new_test_db()?;
1066 db.conn.execute(
1067 "INSERT INTO persistent.keyentry (id, creation_date, domain, namespace, alias)
1068 VALUES (1, '1980', 0, 15, 'key'), (2, '1980', 2, 7, 'yek');",
1069 NO_PARAMS,
1070 )?;
1071 let app_key = KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001072 domain: super::Domain::APP,
1073 nspace: 0,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001074 alias: Some("key".to_string()),
1075 blob: None,
1076 };
1077 const PVEC1: KeyPermSet = key_perm_set![KeyPerm::use_(), KeyPerm::get_info()];
1078 const PVEC2: KeyPermSet = key_perm_set![KeyPerm::use_()];
1079
1080 // Reset totally predictable random number generator in case we
1081 // are not the first test running on this thread.
1082 reset_random();
1083 let next_random = 0i64;
1084
1085 let app_granted_key =
1086 db.grant(app_key.clone(), CALLER_UID, GRANTEE_UID, PVEC1, |k, a| {
1087 assert_eq!(*a, PVEC1);
1088 assert_eq!(
1089 *k,
1090 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001091 domain: super::Domain::APP,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001092 // namespace must be set to the caller_uid.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001093 nspace: CALLER_UID as i64,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001094 alias: Some("key".to_string()),
1095 blob: None,
1096 }
1097 );
1098 Ok(())
1099 })?;
1100
1101 assert_eq!(
1102 app_granted_key,
1103 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001104 domain: super::Domain::GRANT,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001105 // The grantid is next_random due to the mock random number generator.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001106 nspace: next_random,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001107 alias: None,
1108 blob: None,
1109 }
1110 );
1111
1112 let selinux_key = KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001113 domain: super::Domain::SELINUX,
1114 nspace: SELINUX_NAMESPACE,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001115 alias: Some("yek".to_string()),
1116 blob: None,
1117 };
1118
1119 let selinux_granted_key =
1120 db.grant(selinux_key.clone(), CALLER_UID, 12, PVEC1, |k, a| {
1121 assert_eq!(*a, PVEC1);
1122 assert_eq!(
1123 *k,
1124 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001125 domain: super::Domain::SELINUX,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001126 // namespace must be the supplied SELinux
1127 // namespace.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001128 nspace: SELINUX_NAMESPACE,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001129 alias: Some("yek".to_string()),
1130 blob: None,
1131 }
1132 );
1133 Ok(())
1134 })?;
1135
1136 assert_eq!(
1137 selinux_granted_key,
1138 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001139 domain: super::Domain::GRANT,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001140 // The grantid is next_random + 1 due to the mock random number generator.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001141 nspace: next_random + 1,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001142 alias: None,
1143 blob: None,
1144 }
1145 );
1146
1147 // This should update the existing grant with PVEC2.
1148 let selinux_granted_key =
1149 db.grant(selinux_key.clone(), CALLER_UID, 12, PVEC2, |k, a| {
1150 assert_eq!(*a, PVEC2);
1151 assert_eq!(
1152 *k,
1153 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001154 domain: super::Domain::SELINUX,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001155 // namespace must be the supplied SELinux
1156 // namespace.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001157 nspace: SELINUX_NAMESPACE,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001158 alias: Some("yek".to_string()),
1159 blob: None,
1160 }
1161 );
1162 Ok(())
1163 })?;
1164
1165 assert_eq!(
1166 selinux_granted_key,
1167 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001168 domain: super::Domain::GRANT,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001169 // Same grant id as before. The entry was only updated.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001170 nspace: next_random + 1,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001171 alias: None,
1172 blob: None,
1173 }
1174 );
1175
1176 {
1177 // Limiting scope of stmt, because it borrows db.
1178 let mut stmt = db
1179 .conn
Janis Danisevskisbf15d732020-12-08 10:35:26 -08001180 .prepare("SELECT id, grantee, keyentryid, access_vector FROM persistent.grant;")?;
Janis Danisevskisee10b5f2020-09-22 16:42:35 -07001181 let mut rows =
1182 stmt.query_map::<(i64, u32, i64, KeyPermSet), _, _>(NO_PARAMS, |row| {
1183 Ok((
1184 row.get(0)?,
1185 row.get(1)?,
1186 row.get(2)?,
1187 KeyPermSet::from(row.get::<_, i32>(3)?),
1188 ))
1189 })?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001190
1191 let r = rows.next().unwrap().unwrap();
Janis Danisevskisee10b5f2020-09-22 16:42:35 -07001192 assert_eq!(r, (next_random, GRANTEE_UID, 1, PVEC1));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001193 let r = rows.next().unwrap().unwrap();
Janis Danisevskisee10b5f2020-09-22 16:42:35 -07001194 assert_eq!(r, (next_random + 1, GRANTEE_UID, 2, PVEC2));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001195 assert!(rows.next().is_none());
1196 }
1197
1198 debug_dump_keyentry_table(&mut db)?;
1199 println!("app_key {:?}", app_key);
1200 println!("selinux_key {:?}", selinux_key);
1201
1202 db.ungrant(app_key, CALLER_UID, GRANTEE_UID, |_| Ok(()))?;
1203 db.ungrant(selinux_key, CALLER_UID, GRANTEE_UID, |_| Ok(()))?;
1204
1205 Ok(())
1206 }
1207
1208 static TEST_KM_BLOB: &[u8] = b"my test blob";
1209 static TEST_CERT_BLOB: &[u8] = b"my test cert";
1210 static TEST_CERT_CHAIN_BLOB: &[u8] = b"my test cert_chain";
1211
1212 #[test]
1213 fn test_insert_blob() -> Result<()> {
1214 let mut db = new_test_db()?;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001215 db.insert_blob(
Janis Danisevskisaec14592020-11-12 09:41:49 -08001216 &KEY_ID_LOCK.get(1),
1217 SubComponentType::KM_BLOB,
1218 TEST_KM_BLOB,
1219 SecurityLevel::SOFTWARE,
1220 )?;
1221 db.insert_blob(
1222 &KEY_ID_LOCK.get(1),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001223 SubComponentType::CERT,
1224 TEST_CERT_BLOB,
1225 SecurityLevel::TRUSTED_ENVIRONMENT,
1226 )?;
1227 db.insert_blob(
Janis Danisevskisaec14592020-11-12 09:41:49 -08001228 &KEY_ID_LOCK.get(1),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001229 SubComponentType::CERT_CHAIN,
1230 TEST_CERT_CHAIN_BLOB,
1231 SecurityLevel::STRONGBOX,
1232 )?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001233
1234 let mut stmt = db.conn.prepare(
1235 "SELECT subcomponent_type, keyentryid, blob, sec_level FROM persistent.blobentry
1236 ORDER BY sec_level ASC;",
1237 )?;
1238 let mut rows = stmt
1239 .query_map::<(SubComponentType, i64, Vec<u8>, i64), _, _>(NO_PARAMS, |row| {
1240 Ok((row.get(0)?, row.get(1)?, row.get(2)?, row.get(3)?))
1241 })?;
1242 let r = rows.next().unwrap().unwrap();
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001243 assert_eq!(r, (SubComponentType::KM_BLOB, 1, TEST_KM_BLOB.to_vec(), 0));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001244 let r = rows.next().unwrap().unwrap();
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001245 assert_eq!(r, (SubComponentType::CERT, 1, TEST_CERT_BLOB.to_vec(), 1));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001246 let r = rows.next().unwrap().unwrap();
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001247 assert_eq!(r, (SubComponentType::CERT_CHAIN, 1, TEST_CERT_CHAIN_BLOB.to_vec(), 2));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001248
1249 Ok(())
1250 }
1251
1252 static TEST_ALIAS: &str = "my super duper key";
1253
1254 #[test]
1255 fn test_insert_and_load_full_keyentry_domain_app() -> Result<()> {
1256 let mut db = new_test_db()?;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001257 let key_id = make_test_key_entry(&mut db, Domain::APP, 1, TEST_ALIAS)
Janis Danisevskisaec14592020-11-12 09:41:49 -08001258 .context("test_insert_and_load_full_keyentry_domain_app")?
1259 .0;
1260 let (_key_guard, key_entry) = db.load_key_entry(
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001261 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001262 domain: Domain::APP,
1263 nspace: 0,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001264 alias: Some(TEST_ALIAS.to_string()),
1265 blob: None,
1266 },
1267 KeyEntryLoadBits::BOTH,
1268 1,
1269 |_k, _av| Ok(()),
1270 )?;
1271 assert_eq!(
1272 key_entry,
1273 KeyEntry {
1274 id: key_id,
1275 km_blob: Some(TEST_KM_BLOB.to_vec()),
1276 cert: Some(TEST_CERT_BLOB.to_vec()),
1277 cert_chain: Some(TEST_CERT_CHAIN_BLOB.to_vec()),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001278 sec_level: SecurityLevel::TRUSTED_ENVIRONMENT,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001279 parameters: make_test_params(),
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001280 }
1281 );
1282 Ok(())
1283 }
1284
1285 #[test]
1286 fn test_insert_and_load_full_keyentry_domain_selinux() -> Result<()> {
1287 let mut db = new_test_db()?;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001288 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS)
Janis Danisevskisaec14592020-11-12 09:41:49 -08001289 .context("test_insert_and_load_full_keyentry_domain_selinux")?
1290 .0;
1291 let (_key_guard, key_entry) = db.load_key_entry(
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001292 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001293 domain: Domain::SELINUX,
1294 nspace: 1,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001295 alias: Some(TEST_ALIAS.to_string()),
1296 blob: None,
1297 },
1298 KeyEntryLoadBits::BOTH,
1299 1,
1300 |_k, _av| Ok(()),
1301 )?;
1302 assert_eq!(
1303 key_entry,
1304 KeyEntry {
1305 id: key_id,
1306 km_blob: Some(TEST_KM_BLOB.to_vec()),
1307 cert: Some(TEST_CERT_BLOB.to_vec()),
1308 cert_chain: Some(TEST_CERT_CHAIN_BLOB.to_vec()),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001309 sec_level: SecurityLevel::TRUSTED_ENVIRONMENT,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001310 parameters: make_test_params(),
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001311 }
1312 );
1313 Ok(())
1314 }
1315
1316 #[test]
1317 fn test_insert_and_load_full_keyentry_domain_key_id() -> Result<()> {
1318 let mut db = new_test_db()?;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001319 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS)
Janis Danisevskisaec14592020-11-12 09:41:49 -08001320 .context("test_insert_and_load_full_keyentry_domain_key_id")?
1321 .0;
1322 let (_key_guard, key_entry) = db.load_key_entry(
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001323 KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001324 KeyEntryLoadBits::BOTH,
1325 1,
1326 |_k, _av| Ok(()),
1327 )?;
1328 assert_eq!(
1329 key_entry,
1330 KeyEntry {
1331 id: key_id,
1332 km_blob: Some(TEST_KM_BLOB.to_vec()),
1333 cert: Some(TEST_CERT_BLOB.to_vec()),
1334 cert_chain: Some(TEST_CERT_CHAIN_BLOB.to_vec()),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001335 sec_level: SecurityLevel::TRUSTED_ENVIRONMENT,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001336 parameters: make_test_params(),
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001337 }
1338 );
1339
1340 Ok(())
1341 }
1342
1343 #[test]
1344 fn test_insert_and_load_full_keyentry_from_grant() -> Result<()> {
1345 let mut db = new_test_db()?;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001346 let key_id = make_test_key_entry(&mut db, Domain::APP, 1, TEST_ALIAS)
Janis Danisevskisaec14592020-11-12 09:41:49 -08001347 .context("test_insert_and_load_full_keyentry_from_grant")?
1348 .0;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001349
1350 let granted_key = db.grant(
1351 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001352 domain: Domain::APP,
1353 nspace: 0,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001354 alias: Some(TEST_ALIAS.to_string()),
1355 blob: None,
1356 },
1357 1,
1358 2,
1359 key_perm_set![KeyPerm::use_()],
1360 |_k, _av| Ok(()),
1361 )?;
1362
1363 debug_dump_grant_table(&mut db)?;
1364
Janis Danisevskisaec14592020-11-12 09:41:49 -08001365 let (_key_guard, key_entry) =
1366 db.load_key_entry(granted_key, KeyEntryLoadBits::BOTH, 2, |k, av| {
1367 assert_eq!(Domain::GRANT, k.domain);
1368 assert!(av.unwrap().includes(KeyPerm::use_()));
1369 Ok(())
1370 })?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001371
1372 assert_eq!(
1373 key_entry,
1374 KeyEntry {
1375 id: key_id,
1376 km_blob: Some(TEST_KM_BLOB.to_vec()),
1377 cert: Some(TEST_CERT_BLOB.to_vec()),
1378 cert_chain: Some(TEST_CERT_CHAIN_BLOB.to_vec()),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001379 sec_level: SecurityLevel::TRUSTED_ENVIRONMENT,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001380 parameters: make_test_params(),
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001381 }
1382 );
1383 Ok(())
1384 }
1385
Janis Danisevskisaec14592020-11-12 09:41:49 -08001386 static KEY_LOCK_TEST_ALIAS: &str = "my super duper locked key";
1387
Janis Danisevskisaec14592020-11-12 09:41:49 -08001388 #[test]
1389 fn test_insert_and_load_full_keyentry_domain_app_concurrently() -> Result<()> {
1390 let handle = {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08001391 let temp_dir = Arc::new(TempDir::new("id_lock_test")?);
1392 let temp_dir_clone = temp_dir.clone();
1393 let mut db = KeystoreDB::new(temp_dir.path())?;
Janis Danisevskisaec14592020-11-12 09:41:49 -08001394 let key_id = make_test_key_entry(&mut db, Domain::APP, 33, KEY_LOCK_TEST_ALIAS)
1395 .context("test_insert_and_load_full_keyentry_domain_app")?
1396 .0;
1397 let (_key_guard, key_entry) = db.load_key_entry(
1398 KeyDescriptor {
1399 domain: Domain::APP,
1400 nspace: 0,
1401 alias: Some(KEY_LOCK_TEST_ALIAS.to_string()),
1402 blob: None,
1403 },
1404 KeyEntryLoadBits::BOTH,
1405 33,
1406 |_k, _av| Ok(()),
1407 )?;
1408 assert_eq!(
1409 key_entry,
1410 KeyEntry {
1411 id: key_id,
1412 km_blob: Some(TEST_KM_BLOB.to_vec()),
1413 cert: Some(TEST_CERT_BLOB.to_vec()),
1414 cert_chain: Some(TEST_CERT_CHAIN_BLOB.to_vec()),
1415 sec_level: SecurityLevel::TRUSTED_ENVIRONMENT,
1416 parameters: make_test_params(),
1417 }
1418 );
1419 let state = Arc::new(AtomicU8::new(1));
1420 let state2 = state.clone();
1421
1422 // Spawning a second thread that attempts to acquire the key id lock
1423 // for the same key as the primary thread. The primary thread then
1424 // waits, thereby forcing the secondary thread into the second stage
1425 // of acquiring the lock (see KEY ID LOCK 2/2 above).
1426 // The test succeeds if the secondary thread observes the transition
1427 // of `state` from 1 to 2, despite having a whole second to overtake
1428 // the primary thread.
1429 let handle = thread::spawn(move || {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08001430 let temp_dir = temp_dir_clone;
1431 let mut db = KeystoreDB::new(temp_dir.path()).unwrap();
Janis Danisevskisaec14592020-11-12 09:41:49 -08001432 assert!(db
1433 .load_key_entry(
1434 KeyDescriptor {
1435 domain: Domain::APP,
1436 nspace: 0,
1437 alias: Some(KEY_LOCK_TEST_ALIAS.to_string()),
1438 blob: None,
1439 },
1440 KeyEntryLoadBits::BOTH,
1441 33,
1442 |_k, _av| Ok(()),
1443 )
1444 .is_ok());
1445 // We should only see a 2 here because we can only return
1446 // from load_key_entry when the `_key_guard` expires,
1447 // which happens at the end of the scope.
1448 assert_eq!(2, state2.load(Ordering::Relaxed));
1449 });
1450
1451 thread::sleep(std::time::Duration::from_millis(1000));
1452
1453 assert_eq!(Ok(1), state.compare_exchange(1, 2, Ordering::Relaxed, Ordering::Relaxed));
1454
1455 // Return the handle from this scope so we can join with the
1456 // secondary thread after the key id lock has expired.
1457 handle
1458 // This is where the `_key_guard` goes out of scope,
1459 // which is the reason for concurrent load_key_entry on the same key
1460 // to unblock.
1461 };
1462 // Join with the secondary thread and unwrap, to propagate failing asserts to the
1463 // main test thread. We will not see failing asserts in secondary threads otherwise.
1464 handle.join().unwrap();
1465 Ok(())
1466 }
1467
Joel Galenson0891bc12020-07-20 10:37:03 -07001468 // Helpers
1469
1470 // Checks that the given result is an error containing the given string.
1471 fn check_result_is_error_containing_string<T>(result: Result<T>, target: &str) {
1472 let error_str = format!(
1473 "{:#?}",
1474 result.err().unwrap_or_else(|| panic!("Expected the error: {}", target))
1475 );
1476 assert!(
1477 error_str.contains(target),
1478 "The string \"{}\" should contain \"{}\"",
1479 error_str,
1480 target
1481 );
1482 }
1483
Joel Galenson2aab4432020-07-22 15:27:57 -07001484 #[derive(Debug, PartialEq)]
Joel Galenson0891bc12020-07-20 10:37:03 -07001485 #[allow(dead_code)]
1486 struct KeyEntryRow {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001487 id: i64,
Joel Galenson0891bc12020-07-20 10:37:03 -07001488 creation_date: String,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001489 domain: Option<Domain>,
Joel Galenson0891bc12020-07-20 10:37:03 -07001490 namespace: Option<i64>,
1491 alias: Option<String>,
1492 }
1493
1494 fn get_keyentry(db: &KeystoreDB) -> Result<Vec<KeyEntryRow>> {
1495 db.conn
Joel Galenson2aab4432020-07-22 15:27:57 -07001496 .prepare("SELECT * FROM persistent.keyentry;")?
Joel Galenson0891bc12020-07-20 10:37:03 -07001497 .query_map(NO_PARAMS, |row| {
Joel Galenson0891bc12020-07-20 10:37:03 -07001498 Ok(KeyEntryRow {
1499 id: row.get(0)?,
1500 creation_date: row.get(1)?,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001501 domain: match row.get(2)? {
1502 Some(i) => Some(Domain(i)),
1503 None => None,
1504 },
Joel Galenson0891bc12020-07-20 10:37:03 -07001505 namespace: row.get(3)?,
1506 alias: row.get(4)?,
1507 })
1508 })?
1509 .map(|r| r.context("Could not read keyentry row."))
1510 .collect::<Result<Vec<_>>>()
1511 }
1512
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001513 // Note: The parameters and SecurityLevel associations are nonsensical. This
1514 // collection is only used to check if the parameters are preserved as expected by the
1515 // database.
1516 fn make_test_params() -> Vec<KeyParameter> {
1517 vec![
1518 KeyParameter::new(KeyParameterValue::Invalid, SecurityLevel::TRUSTED_ENVIRONMENT),
1519 KeyParameter::new(
1520 KeyParameterValue::KeyPurpose(KeyPurpose::SIGN),
1521 SecurityLevel::TRUSTED_ENVIRONMENT,
1522 ),
1523 KeyParameter::new(
1524 KeyParameterValue::KeyPurpose(KeyPurpose::DECRYPT),
1525 SecurityLevel::TRUSTED_ENVIRONMENT,
1526 ),
1527 KeyParameter::new(
1528 KeyParameterValue::Algorithm(Algorithm::RSA),
1529 SecurityLevel::TRUSTED_ENVIRONMENT,
1530 ),
1531 KeyParameter::new(KeyParameterValue::KeySize(1024), SecurityLevel::TRUSTED_ENVIRONMENT),
1532 KeyParameter::new(
1533 KeyParameterValue::BlockMode(BlockMode::ECB),
1534 SecurityLevel::TRUSTED_ENVIRONMENT,
1535 ),
1536 KeyParameter::new(
1537 KeyParameterValue::BlockMode(BlockMode::GCM),
1538 SecurityLevel::TRUSTED_ENVIRONMENT,
1539 ),
1540 KeyParameter::new(KeyParameterValue::Digest(Digest::NONE), SecurityLevel::STRONGBOX),
1541 KeyParameter::new(
1542 KeyParameterValue::Digest(Digest::MD5),
1543 SecurityLevel::TRUSTED_ENVIRONMENT,
1544 ),
1545 KeyParameter::new(
1546 KeyParameterValue::Digest(Digest::SHA_2_224),
1547 SecurityLevel::TRUSTED_ENVIRONMENT,
1548 ),
1549 KeyParameter::new(
1550 KeyParameterValue::Digest(Digest::SHA_2_256),
1551 SecurityLevel::STRONGBOX,
1552 ),
1553 KeyParameter::new(
1554 KeyParameterValue::PaddingMode(PaddingMode::NONE),
1555 SecurityLevel::TRUSTED_ENVIRONMENT,
1556 ),
1557 KeyParameter::new(
1558 KeyParameterValue::PaddingMode(PaddingMode::RSA_OAEP),
1559 SecurityLevel::TRUSTED_ENVIRONMENT,
1560 ),
1561 KeyParameter::new(
1562 KeyParameterValue::PaddingMode(PaddingMode::RSA_PSS),
1563 SecurityLevel::STRONGBOX,
1564 ),
1565 KeyParameter::new(
1566 KeyParameterValue::PaddingMode(PaddingMode::RSA_PKCS1_1_5_SIGN),
1567 SecurityLevel::TRUSTED_ENVIRONMENT,
1568 ),
1569 KeyParameter::new(KeyParameterValue::CallerNonce, SecurityLevel::TRUSTED_ENVIRONMENT),
1570 KeyParameter::new(KeyParameterValue::MinMacLength(256), SecurityLevel::STRONGBOX),
1571 KeyParameter::new(
1572 KeyParameterValue::EcCurve(EcCurve::P_224),
1573 SecurityLevel::TRUSTED_ENVIRONMENT,
1574 ),
1575 KeyParameter::new(KeyParameterValue::EcCurve(EcCurve::P_256), SecurityLevel::STRONGBOX),
1576 KeyParameter::new(
1577 KeyParameterValue::EcCurve(EcCurve::P_384),
1578 SecurityLevel::TRUSTED_ENVIRONMENT,
1579 ),
1580 KeyParameter::new(
1581 KeyParameterValue::EcCurve(EcCurve::P_521),
1582 SecurityLevel::TRUSTED_ENVIRONMENT,
1583 ),
1584 KeyParameter::new(
1585 KeyParameterValue::RSAPublicExponent(3),
1586 SecurityLevel::TRUSTED_ENVIRONMENT,
1587 ),
1588 KeyParameter::new(
1589 KeyParameterValue::IncludeUniqueID,
1590 SecurityLevel::TRUSTED_ENVIRONMENT,
1591 ),
1592 KeyParameter::new(KeyParameterValue::BootLoaderOnly, SecurityLevel::STRONGBOX),
1593 KeyParameter::new(KeyParameterValue::RollbackResistance, SecurityLevel::STRONGBOX),
1594 KeyParameter::new(
1595 KeyParameterValue::ActiveDateTime(1234567890),
1596 SecurityLevel::STRONGBOX,
1597 ),
1598 KeyParameter::new(
1599 KeyParameterValue::OriginationExpireDateTime(1234567890),
1600 SecurityLevel::TRUSTED_ENVIRONMENT,
1601 ),
1602 KeyParameter::new(
1603 KeyParameterValue::UsageExpireDateTime(1234567890),
1604 SecurityLevel::TRUSTED_ENVIRONMENT,
1605 ),
1606 KeyParameter::new(
1607 KeyParameterValue::MinSecondsBetweenOps(1234567890),
1608 SecurityLevel::TRUSTED_ENVIRONMENT,
1609 ),
1610 KeyParameter::new(
1611 KeyParameterValue::MaxUsesPerBoot(1234567890),
1612 SecurityLevel::TRUSTED_ENVIRONMENT,
1613 ),
1614 KeyParameter::new(KeyParameterValue::UserID(1), SecurityLevel::STRONGBOX),
1615 KeyParameter::new(KeyParameterValue::UserSecureID(42), SecurityLevel::STRONGBOX),
1616 KeyParameter::new(
1617 KeyParameterValue::NoAuthRequired,
1618 SecurityLevel::TRUSTED_ENVIRONMENT,
1619 ),
1620 KeyParameter::new(
1621 KeyParameterValue::HardwareAuthenticatorType(HardwareAuthenticatorType::PASSWORD),
1622 SecurityLevel::TRUSTED_ENVIRONMENT,
1623 ),
1624 KeyParameter::new(KeyParameterValue::AuthTimeout(1234567890), SecurityLevel::SOFTWARE),
1625 KeyParameter::new(KeyParameterValue::AllowWhileOnBody, SecurityLevel::SOFTWARE),
1626 KeyParameter::new(
1627 KeyParameterValue::TrustedUserPresenceRequired,
1628 SecurityLevel::TRUSTED_ENVIRONMENT,
1629 ),
1630 KeyParameter::new(
1631 KeyParameterValue::TrustedConfirmationRequired,
1632 SecurityLevel::TRUSTED_ENVIRONMENT,
1633 ),
1634 KeyParameter::new(
1635 KeyParameterValue::UnlockedDeviceRequired,
1636 SecurityLevel::TRUSTED_ENVIRONMENT,
1637 ),
1638 KeyParameter::new(
1639 KeyParameterValue::ApplicationID(vec![1u8, 2u8, 3u8, 4u8]),
1640 SecurityLevel::SOFTWARE,
1641 ),
1642 KeyParameter::new(
1643 KeyParameterValue::ApplicationData(vec![4u8, 3u8, 2u8, 1u8]),
1644 SecurityLevel::SOFTWARE,
1645 ),
1646 KeyParameter::new(
1647 KeyParameterValue::CreationDateTime(12345677890),
1648 SecurityLevel::SOFTWARE,
1649 ),
1650 KeyParameter::new(
1651 KeyParameterValue::KeyOrigin(KeyOrigin::GENERATED),
1652 SecurityLevel::TRUSTED_ENVIRONMENT,
1653 ),
1654 KeyParameter::new(
1655 KeyParameterValue::RootOfTrust(vec![3u8, 2u8, 1u8, 4u8]),
1656 SecurityLevel::TRUSTED_ENVIRONMENT,
1657 ),
1658 KeyParameter::new(KeyParameterValue::OSVersion(1), SecurityLevel::TRUSTED_ENVIRONMENT),
1659 KeyParameter::new(KeyParameterValue::OSPatchLevel(2), SecurityLevel::SOFTWARE),
1660 KeyParameter::new(
1661 KeyParameterValue::UniqueID(vec![4u8, 3u8, 1u8, 2u8]),
1662 SecurityLevel::SOFTWARE,
1663 ),
1664 KeyParameter::new(
1665 KeyParameterValue::AttestationChallenge(vec![4u8, 3u8, 1u8, 2u8]),
1666 SecurityLevel::TRUSTED_ENVIRONMENT,
1667 ),
1668 KeyParameter::new(
1669 KeyParameterValue::AttestationApplicationID(vec![4u8, 3u8, 1u8, 2u8]),
1670 SecurityLevel::TRUSTED_ENVIRONMENT,
1671 ),
1672 KeyParameter::new(
1673 KeyParameterValue::AttestationIdBrand(vec![4u8, 3u8, 1u8, 2u8]),
1674 SecurityLevel::TRUSTED_ENVIRONMENT,
1675 ),
1676 KeyParameter::new(
1677 KeyParameterValue::AttestationIdDevice(vec![4u8, 3u8, 1u8, 2u8]),
1678 SecurityLevel::TRUSTED_ENVIRONMENT,
1679 ),
1680 KeyParameter::new(
1681 KeyParameterValue::AttestationIdProduct(vec![4u8, 3u8, 1u8, 2u8]),
1682 SecurityLevel::TRUSTED_ENVIRONMENT,
1683 ),
1684 KeyParameter::new(
1685 KeyParameterValue::AttestationIdSerial(vec![4u8, 3u8, 1u8, 2u8]),
1686 SecurityLevel::TRUSTED_ENVIRONMENT,
1687 ),
1688 KeyParameter::new(
1689 KeyParameterValue::AttestationIdIMEI(vec![4u8, 3u8, 1u8, 2u8]),
1690 SecurityLevel::TRUSTED_ENVIRONMENT,
1691 ),
1692 KeyParameter::new(
1693 KeyParameterValue::AttestationIdMEID(vec![4u8, 3u8, 1u8, 2u8]),
1694 SecurityLevel::TRUSTED_ENVIRONMENT,
1695 ),
1696 KeyParameter::new(
1697 KeyParameterValue::AttestationIdManufacturer(vec![4u8, 3u8, 1u8, 2u8]),
1698 SecurityLevel::TRUSTED_ENVIRONMENT,
1699 ),
1700 KeyParameter::new(
1701 KeyParameterValue::AttestationIdModel(vec![4u8, 3u8, 1u8, 2u8]),
1702 SecurityLevel::TRUSTED_ENVIRONMENT,
1703 ),
1704 KeyParameter::new(
1705 KeyParameterValue::VendorPatchLevel(3),
1706 SecurityLevel::TRUSTED_ENVIRONMENT,
1707 ),
1708 KeyParameter::new(
1709 KeyParameterValue::BootPatchLevel(4),
1710 SecurityLevel::TRUSTED_ENVIRONMENT,
1711 ),
1712 KeyParameter::new(
1713 KeyParameterValue::AssociatedData(vec![4u8, 3u8, 1u8, 2u8]),
1714 SecurityLevel::TRUSTED_ENVIRONMENT,
1715 ),
1716 KeyParameter::new(
1717 KeyParameterValue::Nonce(vec![4u8, 3u8, 1u8, 2u8]),
1718 SecurityLevel::TRUSTED_ENVIRONMENT,
1719 ),
1720 KeyParameter::new(
1721 KeyParameterValue::MacLength(256),
1722 SecurityLevel::TRUSTED_ENVIRONMENT,
1723 ),
1724 KeyParameter::new(
1725 KeyParameterValue::ResetSinceIdRotation,
1726 SecurityLevel::TRUSTED_ENVIRONMENT,
1727 ),
1728 KeyParameter::new(
1729 KeyParameterValue::ConfirmationToken(vec![5u8, 5u8, 5u8, 5u8]),
1730 SecurityLevel::TRUSTED_ENVIRONMENT,
1731 ),
1732 ]
1733 }
1734
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001735 fn make_test_key_entry(
1736 db: &mut KeystoreDB,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001737 domain: Domain,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001738 namespace: i64,
1739 alias: &str,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001740 ) -> Result<KeyIdGuard> {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001741 let key_id = db.create_key_entry(domain, namespace)?;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001742 db.insert_blob(
Janis Danisevskisaec14592020-11-12 09:41:49 -08001743 &key_id,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001744 SubComponentType::KM_BLOB,
1745 TEST_KM_BLOB,
1746 SecurityLevel::TRUSTED_ENVIRONMENT,
1747 )?;
1748 db.insert_blob(
Janis Danisevskisaec14592020-11-12 09:41:49 -08001749 &key_id,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001750 SubComponentType::CERT,
1751 TEST_CERT_BLOB,
1752 SecurityLevel::TRUSTED_ENVIRONMENT,
1753 )?;
1754 db.insert_blob(
Janis Danisevskisaec14592020-11-12 09:41:49 -08001755 &key_id,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001756 SubComponentType::CERT_CHAIN,
1757 TEST_CERT_CHAIN_BLOB,
1758 SecurityLevel::TRUSTED_ENVIRONMENT,
1759 )?;
Janis Danisevskisaec14592020-11-12 09:41:49 -08001760 db.insert_keyparameter(&key_id, &make_test_params())?;
1761 db.rebind_alias(&key_id, alias, domain, namespace)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001762 Ok(key_id)
1763 }
1764
1765 fn debug_dump_keyentry_table(db: &mut KeystoreDB) -> Result<()> {
1766 let mut stmt = db.conn.prepare(
1767 "SELECT id, creation_date, domain, namespace, alias FROM persistent.keyentry;",
1768 )?;
1769 let rows = stmt.query_map::<(i64, i64, i32, i64, String), _, _>(NO_PARAMS, |row| {
1770 Ok((row.get(0)?, row.get(1)?, row.get(2)?, row.get(3)?, row.get(4)?))
1771 })?;
1772
1773 println!("Key entry table rows:");
1774 for r in rows {
1775 let (id, cdate, domain, namespace, alias) = r.unwrap();
1776 println!(
1777 " id: {} Creation date: {} Domain: {} Namespace: {} Alias: {}",
1778 id, cdate, domain, namespace, alias
1779 );
1780 }
1781 Ok(())
1782 }
1783
1784 fn debug_dump_grant_table(db: &mut KeystoreDB) -> Result<()> {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08001785 let mut stmt = db
1786 .conn
1787 .prepare("SELECT id, grantee, keyentryid, access_vector FROM persistent.grant;")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001788 let rows = stmt.query_map::<(i64, i64, i64, i64), _, _>(NO_PARAMS, |row| {
1789 Ok((row.get(0)?, row.get(1)?, row.get(2)?, row.get(3)?))
1790 })?;
1791
1792 println!("Grant table rows:");
1793 for r in rows {
1794 let (id, gt, ki, av) = r.unwrap();
1795 println!(" id: {} grantee: {} key_id: {} access_vector: {}", id, gt, ki, av);
1796 }
1797 Ok(())
1798 }
1799
Joel Galenson0891bc12020-07-20 10:37:03 -07001800 // Use a custom random number generator that repeats each number once.
1801 // This allows us to test repeated elements.
1802
1803 thread_local! {
1804 static RANDOM_COUNTER: RefCell<i64> = RefCell::new(0);
1805 }
1806
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001807 fn reset_random() {
1808 RANDOM_COUNTER.with(|counter| {
1809 *counter.borrow_mut() = 0;
1810 })
1811 }
1812
Joel Galenson0891bc12020-07-20 10:37:03 -07001813 pub fn random() -> i64 {
1814 RANDOM_COUNTER.with(|counter| {
1815 let result = *counter.borrow() / 2;
1816 *counter.borrow_mut() += 1;
1817 result
1818 })
1819 }
Joel Galenson26f4d012020-07-17 14:57:21 -07001820}