blob: 0ce4ad6fca51fa73652fff68f5a44a4bb79aba3e [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 Danisevskisc5b210b2020-09-11 13:27:37 -070044use crate::error::{Error as KsError, ResponseCode};
45use crate::key_parameter::{KeyParameter, SqlField, Tag};
46use crate::permission::KeyPermSet;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -070047use anyhow::{anyhow, Context, Result};
Janis Danisevskis60400fe2020-08-26 15:24:42 -070048
Janis Danisevskis04b02832020-10-26 09:21:40 -070049use android_hardware_keymint::aidl::android::hardware::keymint::SecurityLevel::SecurityLevel;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -070050use android_system_keystore2::aidl::android::system::keystore2::{
Janis Danisevskis04b02832020-10-26 09:21:40 -070051 Domain::Domain, KeyDescriptor::KeyDescriptor,
Janis Danisevskis60400fe2020-08-26 15:24:42 -070052};
53
Janis Danisevskisaec14592020-11-12 09:41:49 -080054use lazy_static::lazy_static;
Joel Galenson0891bc12020-07-20 10:37:03 -070055#[cfg(not(test))]
56use rand::prelude::random;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -070057use rusqlite::{
58 params, types::FromSql, types::FromSqlResult, types::ToSqlOutput, types::ValueRef, Connection,
59 OptionalExtension, Row, Rows, ToSql, Transaction, TransactionBehavior, NO_PARAMS,
60};
Janis Danisevskisaec14592020-11-12 09:41:49 -080061use std::{
62 collections::HashSet,
63 sync::{Condvar, Mutex, Once},
64};
Joel Galenson0891bc12020-07-20 10:37:03 -070065#[cfg(test)]
66use tests::random;
Joel Galenson26f4d012020-07-17 14:57:21 -070067
Janis Danisevskis63f7bc82020-09-03 10:12:56 -070068/// Keys have a KeyMint blob component and optional public certificate and
69/// certificate chain components.
70/// KeyEntryLoadBits is a bitmap that indicates to `KeystoreDB::load_key_entry`
71/// which components shall be loaded from the database if present.
72#[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
73pub struct KeyEntryLoadBits(u32);
74
75impl KeyEntryLoadBits {
76 /// Indicate to `KeystoreDB::load_key_entry` that no component shall be loaded.
77 pub const NONE: KeyEntryLoadBits = Self(0);
78 /// Indicate to `KeystoreDB::load_key_entry` that the KeyMint component shall be loaded.
79 pub const KM: KeyEntryLoadBits = Self(1);
80 /// Indicate to `KeystoreDB::load_key_entry` that the Public components shall be loaded.
81 pub const PUBLIC: KeyEntryLoadBits = Self(2);
82 /// Indicate to `KeystoreDB::load_key_entry` that both components shall be loaded.
83 pub const BOTH: KeyEntryLoadBits = Self(3);
84
85 /// Returns true if this object indicates that the public components shall be loaded.
86 pub const fn load_public(&self) -> bool {
87 self.0 & Self::PUBLIC.0 != 0
88 }
89
90 /// Returns true if the object indicates that the KeyMint component shall be loaded.
91 pub const fn load_km(&self) -> bool {
92 self.0 & Self::KM.0 != 0
93 }
94}
95
Janis Danisevskisaec14592020-11-12 09:41:49 -080096lazy_static! {
97 static ref KEY_ID_LOCK: KeyIdLockDb = KeyIdLockDb::new();
98}
99
100struct KeyIdLockDb {
101 locked_keys: Mutex<HashSet<i64>>,
102 cond_var: Condvar,
103}
104
105/// A locked key. While a guard exists for a given key id, the same key cannot be loaded
106/// from the database a second time. Most functions manipulating the key blob database
107/// require a KeyIdGuard.
108#[derive(Debug)]
109pub struct KeyIdGuard(i64);
110
111impl KeyIdLockDb {
112 fn new() -> Self {
113 Self { locked_keys: Mutex::new(HashSet::new()), cond_var: Condvar::new() }
114 }
115
116 /// This function blocks until an exclusive lock for the given key entry id can
117 /// be acquired. It returns a guard object, that represents the lifecycle of the
118 /// acquired lock.
119 pub fn get(&self, key_id: i64) -> KeyIdGuard {
120 let mut locked_keys = self.locked_keys.lock().unwrap();
121 while locked_keys.contains(&key_id) {
122 locked_keys = self.cond_var.wait(locked_keys).unwrap();
123 }
124 locked_keys.insert(key_id);
125 KeyIdGuard(key_id)
126 }
127
128 /// This function attempts to acquire an exclusive lock on a given key id. If the
129 /// given key id is already taken the function returns None immediately. If a lock
130 /// can be acquired this function returns a guard object, that represents the
131 /// lifecycle of the acquired lock.
132 pub fn try_get(&self, key_id: i64) -> Option<KeyIdGuard> {
133 let mut locked_keys = self.locked_keys.lock().unwrap();
134 if locked_keys.insert(key_id) {
135 Some(KeyIdGuard(key_id))
136 } else {
137 None
138 }
139 }
140}
141
142impl KeyIdGuard {
143 /// Get the numeric key id of the locked key.
144 pub fn id(&self) -> i64 {
145 self.0
146 }
147}
148
149impl Drop for KeyIdGuard {
150 fn drop(&mut self) {
151 let mut locked_keys = KEY_ID_LOCK.locked_keys.lock().unwrap();
152 locked_keys.remove(&self.0);
153 KEY_ID_LOCK.cond_var.notify_all();
154 }
155}
156
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700157/// This type represents a Keystore 2.0 key entry.
158/// An entry has a unique `id` by which it can be found in the database.
159/// It has a security level field, key parameters, and three optional fields
160/// for the KeyMint blob, public certificate and a public certificate chain.
Janis Danisevskisaec14592020-11-12 09:41:49 -0800161#[derive(Debug, Default, Eq, PartialEq, Ord, PartialOrd)]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700162pub struct KeyEntry {
163 id: i64,
164 km_blob: Option<Vec<u8>>,
165 cert: Option<Vec<u8>>,
166 cert_chain: Option<Vec<u8>>,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700167 sec_level: SecurityLevel,
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700168 parameters: Vec<KeyParameter>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700169}
170
171impl KeyEntry {
172 /// Returns the unique id of the Key entry.
173 pub fn id(&self) -> i64 {
174 self.id
175 }
176 /// Exposes the optional KeyMint blob.
177 pub fn km_blob(&self) -> &Option<Vec<u8>> {
178 &self.km_blob
179 }
180 /// Extracts the Optional KeyMint blob.
181 pub fn take_km_blob(&mut self) -> Option<Vec<u8>> {
182 self.km_blob.take()
183 }
184 /// Exposes the optional public certificate.
185 pub fn cert(&self) -> &Option<Vec<u8>> {
186 &self.cert
187 }
188 /// Extracts the optional public certificate.
189 pub fn take_cert(&mut self) -> Option<Vec<u8>> {
190 self.cert.take()
191 }
192 /// Exposes the optional public certificate chain.
193 pub fn cert_chain(&self) -> &Option<Vec<u8>> {
194 &self.cert_chain
195 }
196 /// Extracts the optional public certificate_chain.
197 pub fn take_cert_chain(&mut self) -> Option<Vec<u8>> {
198 self.cert_chain.take()
199 }
200 /// Returns the security level of the key entry.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700201 pub fn sec_level(&self) -> SecurityLevel {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700202 self.sec_level
203 }
Janis Danisevskis04b02832020-10-26 09:21:40 -0700204 /// Exposes the key parameters of this key entry.
205 pub fn key_parameters(&self) -> &Vec<KeyParameter> {
206 &self.parameters
207 }
208 /// Consumes this key entry and extracts the keyparameters from it.
209 pub fn into_key_parameters(self) -> Vec<KeyParameter> {
210 self.parameters
211 }
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700212}
213
214/// Indicates the sub component of a key entry for persistent storage.
215#[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
216pub struct SubComponentType(u32);
217impl SubComponentType {
218 /// Persistent identifier for a KeyMint blob.
219 pub const KM_BLOB: SubComponentType = Self(0);
220 /// Persistent identifier for a certificate blob.
221 pub const CERT: SubComponentType = Self(1);
222 /// Persistent identifier for a certificate chain blob.
223 pub const CERT_CHAIN: SubComponentType = Self(2);
224}
225
226impl ToSql for SubComponentType {
227 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
228 self.0.to_sql()
229 }
230}
231
232impl FromSql for SubComponentType {
233 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
234 Ok(Self(u32::column_result(value)?))
235 }
236}
237
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700238static INIT_TABLES: Once = Once::new();
239
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700240/// KeystoreDB wraps a connection to an SQLite database and tracks its
241/// ownership. It also implements all of Keystore 2.0's database functionality.
Joel Galenson26f4d012020-07-17 14:57:21 -0700242pub struct KeystoreDB {
Joel Galenson26f4d012020-07-17 14:57:21 -0700243 conn: Connection,
244}
245
246impl KeystoreDB {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700247 /// This will create a new database connection connecting the two
248 /// files persistent.sqlite and perboot.sqlite in the current working
249 /// directory, which is usually `/data/misc/keystore/`.
250 /// It also attempts to initialize all of the tables on the first instantiation
251 /// per service startup. KeystoreDB cannot be used by multiple threads.
252 /// Each thread should open their own connection using `thread_local!`.
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700253 pub fn new() -> Result<Self> {
254 let conn = Self::make_connection("file:persistent.sqlite", "file:perboot.sqlite")?;
255
256 INIT_TABLES.call_once(|| Self::init_tables(&conn).expect("Failed to initialize tables."));
257 Ok(Self { conn })
Joel Galenson2aab4432020-07-22 15:27:57 -0700258 }
259
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700260 fn init_tables(conn: &Connection) -> Result<()> {
261 conn.execute(
262 "CREATE TABLE IF NOT EXISTS persistent.keyentry (
Joel Galenson0891bc12020-07-20 10:37:03 -0700263 id INTEGER UNIQUE,
264 creation_date DATETIME,
265 domain INTEGER,
266 namespace INTEGER,
267 alias TEXT);",
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700268 NO_PARAMS,
269 )
270 .context("Failed to initialize \"keyentry\" table.")?;
271
272 conn.execute(
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700273 "CREATE VIEW IF NOT EXISTS persistent.orphaned AS
274 SELECT id FROM persistent.keyentry WHERE domain IS NULL;",
275 NO_PARAMS,
276 )
277 .context("Failed to initialize \"orphaned\" view")?;
278
279 conn.execute(
280 "CREATE TABLE IF NOT EXISTS persistent.blobentry (
281 id INTEGER PRIMARY KEY,
282 subcomponent_type INTEGER,
283 keyentryid INTEGER,
284 blob BLOB,
285 sec_level INTEGER);",
286 NO_PARAMS,
287 )
288 .context("Failed to initialize \"blobentry\" table.")?;
289
290 conn.execute(
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700291 "CREATE TABLE IF NOT EXISTS persistent.keyparameter (
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000292 keyentryid INTEGER,
293 tag INTEGER,
294 data ANY,
295 security_level INTEGER);",
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700296 NO_PARAMS,
297 )
298 .context("Failed to initialize \"keyparameter\" table.")?;
299
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700300 // TODO only drop the perboot table if we start up for the first time per boot.
301 // Right now this is done once per startup which will lose some information
302 // upon a crash.
303 // Note: This is no regression with respect to the legacy Keystore.
304 conn.execute("DROP TABLE IF EXISTS perboot.grant;", NO_PARAMS)
305 .context("Failed to drop perboot.grant table")?;
306 conn.execute(
307 "CREATE TABLE perboot.grant (
308 id INTEGER UNIQUE,
309 grantee INTEGER,
310 keyentryid INTEGER,
311 access_vector INTEGER);",
312 NO_PARAMS,
313 )
314 .context("Failed to initialize \"grant\" table.")?;
315
Joel Galenson0891bc12020-07-20 10:37:03 -0700316 Ok(())
317 }
318
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700319 fn make_connection(persistent_file: &str, perboot_file: &str) -> Result<Connection> {
320 let conn =
321 Connection::open_in_memory().context("Failed to initialize SQLite connection.")?;
322
323 conn.execute("ATTACH DATABASE ? as persistent;", params![persistent_file])
324 .context("Failed to attach database persistent.")?;
325 conn.execute("ATTACH DATABASE ? as perboot;", params![perboot_file])
326 .context("Failed to attach database perboot.")?;
327
328 Ok(conn)
329 }
330
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700331 /// Creates a new key entry and allocates a new randomized id for the new key.
332 /// The key id gets associated with a domain and namespace but not with an alias.
333 /// To complete key generation `rebind_alias` should be called after all of the
334 /// key artifacts, i.e., blobs and parameters have been associated with the new
335 /// key id. Finalizing with `rebind_alias` makes the creation of a new key entry
336 /// atomic even if key generation is not.
Janis Danisevskisaec14592020-11-12 09:41:49 -0800337 pub fn create_key_entry(&self, domain: Domain, namespace: i64) -> Result<KeyIdGuard> {
Joel Galenson0891bc12020-07-20 10:37:03 -0700338 match domain {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700339 Domain::APP | Domain::SELINUX => {}
Joel Galenson0891bc12020-07-20 10:37:03 -0700340 _ => {
341 return Err(KsError::sys())
342 .context(format!("Domain {:?} must be either App or SELinux.", domain));
343 }
344 }
Janis Danisevskisaec14592020-11-12 09:41:49 -0800345 Ok(KEY_ID_LOCK.get(
346 Self::insert_with_retry(|id| {
347 self.conn.execute(
348 "INSERT into persistent.keyentry (id, creation_date, domain, namespace, alias)
Joel Galenson0891bc12020-07-20 10:37:03 -0700349 VALUES(?, datetime('now'), ?, ?, NULL);",
Janis Danisevskisaec14592020-11-12 09:41:49 -0800350 params![id, domain.0 as u32, namespace],
351 )
352 })
353 .context("In create_key_entry")?,
354 ))
Joel Galenson26f4d012020-07-17 14:57:21 -0700355 }
Joel Galenson33c04ad2020-08-03 11:04:38 -0700356
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700357 /// Inserts a new blob and associates it with the given key id. Each blob
358 /// has a sub component type and a security level.
359 /// Each key can have one of each sub component type associated. If more
360 /// are added only the most recent can be retrieved, and superseded blobs
361 /// will get garbage collected. The security level field of components
362 /// other than `SubComponentType::KM_BLOB` are ignored.
363 pub fn insert_blob(
364 &mut self,
Janis Danisevskisaec14592020-11-12 09:41:49 -0800365 key_id: &KeyIdGuard,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700366 sc_type: SubComponentType,
367 blob: &[u8],
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700368 sec_level: SecurityLevel,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700369 ) -> Result<()> {
370 self.conn
371 .execute(
372 "INSERT into persistent.blobentry (subcomponent_type, keyentryid, blob, sec_level)
373 VALUES (?, ?, ?, ?);",
Janis Danisevskisaec14592020-11-12 09:41:49 -0800374 params![sc_type, key_id.0, blob, sec_level.0],
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700375 )
376 .context("Failed to insert blob.")?;
377 Ok(())
378 }
379
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700380 /// Inserts a collection of key parameters into the `persistent.keyparameter` table
381 /// and associates them with the given `key_id`.
382 pub fn insert_keyparameter<'a>(
383 &mut self,
Janis Danisevskisaec14592020-11-12 09:41:49 -0800384 key_id: &KeyIdGuard,
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700385 params: impl IntoIterator<Item = &'a KeyParameter>,
386 ) -> Result<()> {
387 let mut stmt = self
388 .conn
389 .prepare(
390 "INSERT into persistent.keyparameter (keyentryid, tag, data, security_level)
391 VALUES (?, ?, ?, ?);",
392 )
393 .context("In insert_keyparameter: Failed to prepare statement.")?;
394
395 let iter = params.into_iter();
396 for p in iter {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700397 stmt.insert(params![
Janis Danisevskisaec14592020-11-12 09:41:49 -0800398 key_id.0,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700399 p.get_tag().0,
400 p.key_parameter_value(),
401 p.security_level().0
402 ])
403 .with_context(|| format!("In insert_keyparameter: Failed to insert {:?}", p))?;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700404 }
405 Ok(())
406 }
407
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700408 /// Updates the alias column of the given key id `newid` with the given alias,
409 /// and atomically, removes the alias, domain, and namespace from another row
410 /// with the same alias-domain-namespace tuple if such row exits.
Joel Galenson33c04ad2020-08-03 11:04:38 -0700411 pub fn rebind_alias(
412 &mut self,
Janis Danisevskisaec14592020-11-12 09:41:49 -0800413 newid: &KeyIdGuard,
Joel Galenson33c04ad2020-08-03 11:04:38 -0700414 alias: &str,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700415 domain: Domain,
Joel Galenson33c04ad2020-08-03 11:04:38 -0700416 namespace: i64,
417 ) -> Result<()> {
418 match domain {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700419 Domain::APP | Domain::SELINUX => {}
Joel Galenson33c04ad2020-08-03 11:04:38 -0700420 _ => {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700421 return Err(KsError::sys()).context(format!(
422 "In rebind_alias: Domain {:?} must be either App or SELinux.",
423 domain
424 ));
Joel Galenson33c04ad2020-08-03 11:04:38 -0700425 }
426 }
427 let tx = self
428 .conn
429 .transaction_with_behavior(TransactionBehavior::Immediate)
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700430 .context("In rebind_alias: Failed to initialize transaction.")?;
Joel Galenson33c04ad2020-08-03 11:04:38 -0700431 tx.execute(
432 "UPDATE persistent.keyentry
433 SET alias = NULL, domain = NULL, namespace = NULL
434 WHERE alias = ? AND domain = ? AND namespace = ?;",
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700435 params![alias, domain.0 as u32, namespace],
Joel Galenson33c04ad2020-08-03 11:04:38 -0700436 )
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700437 .context("In rebind_alias: Failed to rebind existing entry.")?;
Joel Galenson33c04ad2020-08-03 11:04:38 -0700438 let result = tx
439 .execute(
440 "UPDATE persistent.keyentry
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700441 SET alias = ?
442 WHERE id = ? AND domain = ? AND namespace = ?;",
Janis Danisevskisaec14592020-11-12 09:41:49 -0800443 params![alias, newid.0, domain.0 as u32, namespace],
Joel Galenson33c04ad2020-08-03 11:04:38 -0700444 )
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700445 .context("In rebind_alias: Failed to set alias.")?;
Joel Galenson33c04ad2020-08-03 11:04:38 -0700446 if result != 1 {
447 // Note that this explicit rollback is not required, as
448 // the transaction should rollback if we do not commit it.
449 // We leave it here for readability.
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700450 tx.rollback().context("In rebind_alias: Failed to rollback a failed transaction.")?;
Joel Galenson33c04ad2020-08-03 11:04:38 -0700451 return Err(KsError::sys()).context(format!(
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700452 "In rebind_alias: Expected to update a single entry but instead updated {}.",
Joel Galenson33c04ad2020-08-03 11:04:38 -0700453 result
454 ));
455 }
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700456 tx.commit().context("In rebind_alias: Failed to commit transaction.")
457 }
458
459 // Helper function loading the key_id given the key descriptor
460 // tuple comprising domain, namespace, and alias.
461 // Requires a valid transaction.
462 fn load_key_entry_id(key: &KeyDescriptor, tx: &Transaction) -> Result<i64> {
463 let alias = key
464 .alias
465 .as_ref()
466 .map_or_else(|| Err(KsError::sys()), Ok)
467 .context("In load_key_entry_id: Alias must be specified.")?;
468 let mut stmt = tx
469 .prepare(
470 "SELECT id FROM persistent.keyentry
471 WHERE
472 domain = ?
473 AND namespace = ?
474 AND alias = ?;",
475 )
476 .context("In load_key_entry_id: Failed to select from keyentry table.")?;
477 let mut rows = stmt
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700478 .query(params![key.domain.0 as u32, key.nspace, alias])
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700479 .context("In load_key_entry_id: Failed to read from keyentry table.")?;
480 Self::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700481 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700482 .get(0)
483 .context("Failed to unpack id.")
484 })
485 .context("In load_key_entry_id.")
486 }
487
488 /// This helper function completes the access tuple of a key, which is required
489 /// to perform access control. The strategy depends on the `domain` field in the
490 /// key descriptor.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700491 /// * Domain::SELINUX: The access tuple is complete and this function only loads
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700492 /// the key_id for further processing.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700493 /// * Domain::APP: Like Domain::SELINUX, but the tuple is completed by `caller_uid`
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700494 /// which serves as the namespace.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700495 /// * Domain::GRANT: The grant table is queried for the `key_id` and the
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700496 /// `access_vector`.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700497 /// * Domain::KEY_ID: The keyentry table is queried for the owning `domain` and
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700498 /// `namespace`.
499 /// In each case the information returned is sufficient to perform the access
500 /// check and the key id can be used to load further key artifacts.
501 fn load_access_tuple(
502 tx: &Transaction,
503 key: KeyDescriptor,
504 caller_uid: u32,
505 ) -> Result<(i64, KeyDescriptor, Option<KeyPermSet>)> {
506 match key.domain {
507 // Domain App or SELinux. In this case we load the key_id from
508 // the keyentry database for further loading of key components.
509 // We already have the full access tuple to perform access control.
510 // The only distinction is that we use the caller_uid instead
511 // of the caller supplied namespace if the domain field is
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700512 // Domain::APP.
513 Domain::APP | Domain::SELINUX => {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700514 let mut access_key = key;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700515 if access_key.domain == Domain::APP {
516 access_key.nspace = caller_uid as i64;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700517 }
518 let key_id = Self::load_key_entry_id(&access_key, &tx)
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700519 .with_context(|| format!("With key.domain = {:?}.", access_key.domain))?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700520
521 Ok((key_id, access_key, None))
522 }
523
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700524 // Domain::GRANT. In this case we load the key_id and the access_vector
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700525 // from the grant table.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700526 Domain::GRANT => {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700527 let mut stmt = tx
528 .prepare(
529 "SELECT keyentryid, access_vector FROM perboot.grant
530 WHERE grantee = ? AND id = ?;",
531 )
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700532 .context("Domain::GRANT prepare statement failed")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700533 let mut rows = stmt
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700534 .query(params![caller_uid as i64, key.nspace])
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700535 .context("Domain:Grant: query failed.")?;
536 let (key_id, access_vector): (i64, i32) =
537 Self::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700538 let r =
539 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700540 Ok((
541 r.get(0).context("Failed to unpack key_id.")?,
542 r.get(1).context("Failed to unpack access_vector.")?,
543 ))
544 })
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700545 .context("Domain::GRANT.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700546 Ok((key_id, key, Some(access_vector.into())))
547 }
548
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700549 // Domain::KEY_ID. In this case we load the domain and namespace from the
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700550 // keyentry database because we need them for access control.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700551 Domain::KEY_ID => {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700552 let mut stmt = tx
553 .prepare(
554 "SELECT domain, namespace FROM persistent.keyentry
555 WHERE
556 id = ?;",
557 )
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700558 .context("Domain::KEY_ID: prepare statement failed")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700559 let mut rows =
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700560 stmt.query(params![key.nspace]).context("Domain::KEY_ID: query failed.")?;
561 let (domain, namespace): (Domain, i64) =
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700562 Self::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700563 let r =
564 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700565 Ok((
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700566 Domain(r.get(0).context("Failed to unpack domain.")?),
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700567 r.get(1).context("Failed to unpack namespace.")?,
568 ))
569 })
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700570 .context("Domain::KEY_ID.")?;
571 let key_id = key.nspace;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700572 let mut access_key = key;
573 access_key.domain = domain;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700574 access_key.nspace = namespace;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700575
576 Ok((key_id, access_key, None))
577 }
578 _ => Err(anyhow!(KsError::sys())),
579 }
580 }
581
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700582 fn load_blob_components(
583 key_id: i64,
584 load_bits: KeyEntryLoadBits,
585 tx: &Transaction,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700586 ) -> Result<(SecurityLevel, Option<Vec<u8>>, Option<Vec<u8>>, Option<Vec<u8>>)> {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700587 let mut stmt = tx
588 .prepare(
589 "SELECT MAX(id), sec_level, subcomponent_type, blob FROM persistent.blobentry
590 WHERE keyentryid = ? GROUP BY subcomponent_type;",
591 )
592 .context("In load_blob_components: prepare statement failed.")?;
593
594 let mut rows =
595 stmt.query(params![key_id]).context("In load_blob_components: query failed.")?;
596
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700597 let mut sec_level: SecurityLevel = Default::default();
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700598 let mut km_blob: Option<Vec<u8>> = None;
599 let mut cert_blob: Option<Vec<u8>> = None;
600 let mut cert_chain_blob: Option<Vec<u8>> = None;
601 Self::with_rows_extract_all(&mut rows, |row| {
602 let sub_type: SubComponentType =
603 row.get(2).context("Failed to extract subcomponent_type.")?;
604 match (sub_type, load_bits.load_public()) {
605 (SubComponentType::KM_BLOB, _) => {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700606 sec_level =
607 SecurityLevel(row.get(1).context("Failed to extract security level.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700608 if load_bits.load_km() {
609 km_blob = Some(row.get(3).context("Failed to extract KM blob.")?);
610 }
611 }
612 (SubComponentType::CERT, true) => {
613 cert_blob =
614 Some(row.get(3).context("Failed to extract public certificate blob.")?);
615 }
616 (SubComponentType::CERT_CHAIN, true) => {
617 cert_chain_blob =
618 Some(row.get(3).context("Failed to extract certificate chain blob.")?);
619 }
620 (SubComponentType::CERT, _) | (SubComponentType::CERT_CHAIN, _) => {}
621 _ => Err(KsError::sys()).context("Unknown subcomponent type.")?,
622 }
623 Ok(())
624 })
625 .context("In load_blob_components.")?;
626
627 Ok((sec_level, km_blob, cert_blob, cert_chain_blob))
628 }
629
630 fn load_key_parameters(key_id: i64, tx: &Transaction) -> Result<Vec<KeyParameter>> {
631 let mut stmt = tx
632 .prepare(
633 "SELECT tag, data, security_level from persistent.keyparameter
634 WHERE keyentryid = ?;",
635 )
636 .context("In load_key_parameters: prepare statement failed.")?;
637
638 let mut parameters: Vec<KeyParameter> = Vec::new();
639
640 let mut rows =
641 stmt.query(params![key_id]).context("In load_key_parameters: query failed.")?;
642 Self::with_rows_extract_all(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700643 let tag = Tag(row.get(0).context("Failed to read tag.")?);
644 let sec_level = SecurityLevel(row.get(2).context("Failed to read sec_level.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700645 parameters.push(
646 KeyParameter::new_from_sql(tag, &SqlField::new(1, &row), sec_level)
647 .context("Failed to read KeyParameter.")?,
648 );
649 Ok(())
650 })
651 .context("In load_key_parameters.")?;
652
653 Ok(parameters)
654 }
655
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700656 /// Load a key entry by the given key descriptor.
657 /// It uses the `check_permission` callback to verify if the access is allowed
658 /// given the key access tuple read from the database using `load_access_tuple`.
659 /// With `load_bits` the caller may specify which blobs shall be loaded from
660 /// the blob database.
661 pub fn load_key_entry(
662 &mut self,
663 key: KeyDescriptor,
664 load_bits: KeyEntryLoadBits,
665 caller_uid: u32,
666 check_permission: impl FnOnce(&KeyDescriptor, Option<KeyPermSet>) -> Result<()>,
Janis Danisevskisaec14592020-11-12 09:41:49 -0800667 ) -> Result<(KeyIdGuard, KeyEntry)> {
668 // KEY ID LOCK 1/2
669 // If we got a key descriptor with a key id we can get the lock right away.
670 // Otherwise we have to defer it until we know the key id.
671 let key_id_guard = match key.domain {
672 Domain::KEY_ID => Some(KEY_ID_LOCK.get(key.nspace)),
673 _ => None,
674 };
675
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700676 let tx = self
677 .conn
Janis Danisevskisaec14592020-11-12 09:41:49 -0800678 .unchecked_transaction()
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700679 .context("In load_key_entry: Failed to initialize transaction.")?;
680
681 // Load the key_id and complete the access control tuple.
682 let (key_id, access_key_descriptor, access_vector) =
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700683 Self::load_access_tuple(&tx, key, caller_uid).context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700684
685 // Perform access control. It is vital that we return here if the permission is denied.
686 // So do not touch that '?' at the end.
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700687 check_permission(&access_key_descriptor, access_vector).context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700688
Janis Danisevskisaec14592020-11-12 09:41:49 -0800689 // KEY ID LOCK 2/2
690 // If we did not get a key id lock by now, it was because we got a key descriptor
691 // without a key id. At this point we got the key id, so we can try and get a lock.
692 // However, we cannot block here, because we are in the middle of the transaction.
693 // So first we try to get the lock non blocking. If that fails, we roll back the
694 // transaction and block until we get the lock. After we successfully got the lock,
695 // we start a new transaction and load the access tuple again.
696 //
697 // We don't need to perform access control again, because we already established
698 // that the caller had access to the given key. But we need to make sure that the
699 // key id still exists. So we have to load the key entry by key id this time.
700 let (key_id_guard, tx) = match key_id_guard {
701 None => match KEY_ID_LOCK.try_get(key_id) {
702 None => {
703 // Roll back the transaction.
704 tx.rollback().context("In load_key_entry: Failed to roll back transaction.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700705
Janis Danisevskisaec14592020-11-12 09:41:49 -0800706 // Block until we have a key id lock.
707 let key_id_guard = KEY_ID_LOCK.get(key_id);
708
709 // Create a new transaction.
710 let tx = self.conn.unchecked_transaction().context(
711 "In load_key_entry: Failed to initialize transaction. (deferred key lock)",
712 )?;
713
714 Self::load_access_tuple(
715 &tx,
716 // This time we have to load the key by the retrieved key id, because the
717 // alias may have been rebound after we rolled back the transaction.
718 KeyDescriptor {
719 domain: Domain::KEY_ID,
720 nspace: key_id,
721 ..Default::default()
722 },
723 caller_uid,
724 )
725 .context("In load_key_entry. (deferred key lock)")?;
726 (key_id_guard, tx)
727 }
728 Some(l) => (l, tx),
729 },
730 Some(key_id_guard) => (key_id_guard, tx),
731 };
732
733 let (sec_level, km_blob, cert_blob, cert_chain_blob) =
734 Self::load_blob_components(key_id_guard.id(), load_bits, &tx)
735 .context("In load_key_entry.")?;
736
737 let parameters =
738 Self::load_key_parameters(key_id_guard.id(), &tx).context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700739
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700740 tx.commit().context("In load_key_entry: Failed to commit transaction.")?;
741
Janis Danisevskisaec14592020-11-12 09:41:49 -0800742 let key_id = key_id_guard.id();
743 Ok((
744 key_id_guard,
745 KeyEntry {
746 id: key_id,
747 km_blob,
748 cert: cert_blob,
749 cert_chain: cert_chain_blob,
750 sec_level,
751 parameters,
752 },
753 ))
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700754 }
755
756 /// Adds a grant to the grant table.
757 /// Like `load_key_entry` this function loads the access tuple before
758 /// it uses the callback for a permission check. Upon success,
759 /// it inserts the `grantee_uid`, `key_id`, and `access_vector` into the
760 /// grant table. The new row will have a randomized id, which is used as
761 /// grant id in the namespace field of the resulting KeyDescriptor.
762 pub fn grant(
763 &mut self,
764 key: KeyDescriptor,
765 caller_uid: u32,
766 grantee_uid: u32,
767 access_vector: KeyPermSet,
768 check_permission: impl FnOnce(&KeyDescriptor, &KeyPermSet) -> Result<()>,
769 ) -> Result<KeyDescriptor> {
770 let tx = self
771 .conn
772 .transaction_with_behavior(TransactionBehavior::Immediate)
773 .context("In grant: Failed to initialize transaction.")?;
774
775 // Load the key_id and complete the access control tuple.
776 // We ignore the access vector here because grants cannot be granted.
777 // The access vector returned here expresses the permissions the
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700778 // grantee has if key.domain == Domain::GRANT. But this vector
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700779 // cannot include the grant permission by design, so there is no way the
780 // subsequent permission check can pass.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700781 // We could check key.domain == Domain::GRANT and fail early.
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700782 // But even if we load the access tuple by grant here, the permission
783 // check denies the attempt to create a grant by grant descriptor.
784 let (key_id, access_key_descriptor, _) =
785 Self::load_access_tuple(&tx, key, caller_uid).context("In grant")?;
786
787 // Perform access control. It is vital that we return here if the permission
788 // was denied. So do not touch that '?' at the end of the line.
789 // This permission check checks if the caller has the grant permission
790 // for the given key and in addition to all of the permissions
791 // expressed in `access_vector`.
792 check_permission(&access_key_descriptor, &access_vector)
793 .context("In grant: check_permission failed.")?;
794
795 let grant_id = if let Some(grant_id) = tx
796 .query_row(
797 "SELECT id FROM perboot.grant
798 WHERE keyentryid = ? AND grantee = ?;",
799 params![key_id, grantee_uid],
800 |row| row.get(0),
801 )
802 .optional()
803 .context("In grant: Failed get optional existing grant id.")?
804 {
805 tx.execute(
806 "UPDATE perboot.grant
807 SET access_vector = ?
808 WHERE id = ?;",
809 params![i32::from(access_vector), grant_id],
810 )
811 .context("In grant: Failed to update existing grant.")?;
812 grant_id
813 } else {
Joel Galenson845f74b2020-09-09 14:11:55 -0700814 Self::insert_with_retry(|id| {
815 tx.execute(
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700816 "INSERT INTO perboot.grant (id, grantee, keyentryid, access_vector)
817 VALUES (?, ?, ?, ?);",
Joel Galenson845f74b2020-09-09 14:11:55 -0700818 params![id, grantee_uid, key_id, i32::from(access_vector)],
819 )
820 })
821 .context("In grant")?
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700822 };
823 tx.commit().context("In grant: failed to commit transaction.")?;
824
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700825 Ok(KeyDescriptor { domain: Domain::GRANT, nspace: grant_id, alias: None, blob: None })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700826 }
827
828 /// This function checks permissions like `grant` and `load_key_entry`
829 /// before removing a grant from the grant table.
830 pub fn ungrant(
831 &mut self,
832 key: KeyDescriptor,
833 caller_uid: u32,
834 grantee_uid: u32,
835 check_permission: impl FnOnce(&KeyDescriptor) -> Result<()>,
836 ) -> Result<()> {
837 let tx = self
838 .conn
839 .transaction_with_behavior(TransactionBehavior::Immediate)
840 .context("In ungrant: Failed to initialize transaction.")?;
841
842 // Load the key_id and complete the access control tuple.
843 // We ignore the access vector here because grants cannot be granted.
844 let (key_id, access_key_descriptor, _) =
845 Self::load_access_tuple(&tx, key, caller_uid).context("In ungrant.")?;
846
847 // Perform access control. We must return here if the permission
848 // was denied. So do not touch the '?' at the end of this line.
849 check_permission(&access_key_descriptor).context("In grant: check_permission failed.")?;
850
851 tx.execute(
852 "DELETE FROM perboot.grant
853 WHERE keyentryid = ? AND grantee = ?;",
854 params![key_id, grantee_uid],
855 )
856 .context("Failed to delete grant.")?;
857
858 tx.commit().context("In ungrant: failed to commit transaction.")?;
859
860 Ok(())
861 }
862
Joel Galenson845f74b2020-09-09 14:11:55 -0700863 // Generates a random id and passes it to the given function, which will
864 // try to insert it into a database. If that insertion fails, retry;
865 // otherwise return the id.
866 fn insert_with_retry(inserter: impl Fn(i64) -> rusqlite::Result<usize>) -> Result<i64> {
867 loop {
868 let newid: i64 = random();
869 match inserter(newid) {
870 // If the id already existed, try again.
871 Err(rusqlite::Error::SqliteFailure(
872 libsqlite3_sys::Error {
873 code: libsqlite3_sys::ErrorCode::ConstraintViolation,
874 extended_code: libsqlite3_sys::SQLITE_CONSTRAINT_UNIQUE,
875 },
876 _,
877 )) => (),
878 Err(e) => {
879 return Err(e).context("In insert_with_retry: failed to insert into database.")
880 }
881 _ => return Ok(newid),
882 }
883 }
884 }
885
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700886 // Takes Rows as returned by a query call on prepared statement.
887 // Extracts exactly one row with the `row_extractor` and fails if more
888 // rows are available.
889 // If no row was found, `None` is passed to the `row_extractor`.
890 // This allows the row extractor to decide on an error condition or
891 // a different default behavior.
892 fn with_rows_extract_one<'a, T, F>(rows: &mut Rows<'a>, row_extractor: F) -> Result<T>
893 where
894 F: FnOnce(Option<&Row<'a>>) -> Result<T>,
895 {
896 let result =
897 row_extractor(rows.next().context("with_rows_extract_one: Failed to unpack row.")?);
898
899 rows.next()
900 .context("In with_rows_extract_one: Failed to unpack unexpected row.")?
901 .map_or_else(|| Ok(()), |_| Err(KsError::sys()))
902 .context("In with_rows_extract_one: Unexpected row.")?;
903
904 result
905 }
906
907 fn with_rows_extract_all<'a, F>(rows: &mut Rows<'a>, mut row_extractor: F) -> Result<()>
908 where
909 F: FnMut(&Row<'a>) -> Result<()>,
910 {
911 loop {
912 match rows.next().context("In with_rows_extract_all: Failed to unpack row")? {
913 Some(row) => {
914 row_extractor(&row).context("In with_rows_extract_all.")?;
915 }
916 None => break Ok(()),
917 }
918 }
Joel Galenson33c04ad2020-08-03 11:04:38 -0700919 }
Joel Galenson26f4d012020-07-17 14:57:21 -0700920}
921
922#[cfg(test)]
923mod tests {
924
925 use super::*;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700926 use crate::key_parameter::{
927 Algorithm, BlockMode, Digest, EcCurve, HardwareAuthenticatorType, KeyOrigin, KeyParameter,
928 KeyParameterValue, KeyPurpose, PaddingMode, SecurityLevel,
929 };
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700930 use crate::key_perm_set;
931 use crate::permission::{KeyPerm, KeyPermSet};
932 use rusqlite::NO_PARAMS;
Joel Galenson0891bc12020-07-20 10:37:03 -0700933 use std::cell::RefCell;
Janis Danisevskisaec14592020-11-12 09:41:49 -0800934 use std::sync::atomic::{AtomicU8, Ordering};
935 use std::sync::Arc;
936 use std::thread;
Joel Galenson0891bc12020-07-20 10:37:03 -0700937
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700938 static PERSISTENT_TEST_SQL: &str = "/data/local/tmp/persistent.sqlite";
939 static PERBOOT_TEST_SQL: &str = "/data/local/tmp/perboot.sqlite";
940
941 fn new_test_db() -> Result<KeystoreDB> {
942 let conn = KeystoreDB::make_connection("file::memory:", "file::memory:")?;
943
944 KeystoreDB::init_tables(&conn).context("Failed to initialize tables.")?;
945 Ok(KeystoreDB { conn })
946 }
947
948 fn new_test_db_with_persistent_file() -> Result<KeystoreDB> {
949 let conn = KeystoreDB::make_connection(PERSISTENT_TEST_SQL, PERBOOT_TEST_SQL)?;
950
951 KeystoreDB::init_tables(&conn).context("Failed to initialize tables.")?;
952 Ok(KeystoreDB { conn })
953 }
954
Joel Galenson0891bc12020-07-20 10:37:03 -0700955 // Ensure that we're using the "injected" random function, not the real one.
956 #[test]
957 fn test_mocked_random() {
958 let rand1 = random();
959 let rand2 = random();
960 let rand3 = random();
961 if rand1 == rand2 {
962 assert_eq!(rand2 + 1, rand3);
963 } else {
964 assert_eq!(rand1 + 1, rand2);
965 assert_eq!(rand2, rand3);
966 }
967 }
Joel Galenson26f4d012020-07-17 14:57:21 -0700968
Joel Galenson26f4d012020-07-17 14:57:21 -0700969 // Test that we have the correct tables.
970 #[test]
971 fn test_tables() -> Result<()> {
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700972 let db = new_test_db()?;
Joel Galenson26f4d012020-07-17 14:57:21 -0700973 let tables = db
974 .conn
Joel Galenson2aab4432020-07-22 15:27:57 -0700975 .prepare("SELECT name from persistent.sqlite_master WHERE type='table' ORDER BY name;")?
Joel Galenson26f4d012020-07-17 14:57:21 -0700976 .query_map(params![], |row| row.get(0))?
977 .collect::<rusqlite::Result<Vec<String>>>()?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700978 assert_eq!(tables.len(), 3);
979 assert_eq!(tables[0], "blobentry");
980 assert_eq!(tables[1], "keyentry");
981 assert_eq!(tables[2], "keyparameter");
982 let tables = db
983 .conn
984 .prepare("SELECT name from perboot.sqlite_master WHERE type='table' ORDER BY name;")?
985 .query_map(params![], |row| row.get(0))?
986 .collect::<rusqlite::Result<Vec<String>>>()?;
987 assert_eq!(tables.len(), 1);
988 assert_eq!(tables[0], "grant");
Joel Galenson26f4d012020-07-17 14:57:21 -0700989 Ok(())
990 }
Joel Galenson0891bc12020-07-20 10:37:03 -0700991
992 #[test]
Joel Galenson2aab4432020-07-22 15:27:57 -0700993 fn test_no_persistence_for_tests() -> Result<()> {
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700994 let db = new_test_db()?;
Joel Galenson2aab4432020-07-22 15:27:57 -0700995
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700996 db.create_key_entry(Domain::APP, 100)?;
Joel Galenson2aab4432020-07-22 15:27:57 -0700997 let entries = get_keyentry(&db)?;
998 assert_eq!(entries.len(), 1);
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700999 let db = new_test_db()?;
Joel Galenson2aab4432020-07-22 15:27:57 -07001000
1001 let entries = get_keyentry(&db)?;
1002 assert_eq!(entries.len(), 0);
1003 Ok(())
1004 }
1005
1006 #[test]
1007 fn test_persistence_for_files() -> Result<()> {
Janis Danisevskis4df44f42020-08-26 14:40:03 -07001008 let _file_guard_persistent = TempFile { filename: PERSISTENT_TEST_SQL };
1009 let _file_guard_perboot = TempFile { filename: PERBOOT_TEST_SQL };
1010 let db = new_test_db_with_persistent_file()?;
Joel Galenson2aab4432020-07-22 15:27:57 -07001011
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001012 db.create_key_entry(Domain::APP, 100)?;
Joel Galenson2aab4432020-07-22 15:27:57 -07001013 let entries = get_keyentry(&db)?;
1014 assert_eq!(entries.len(), 1);
Janis Danisevskis4df44f42020-08-26 14:40:03 -07001015 let db = new_test_db_with_persistent_file()?;
Joel Galenson2aab4432020-07-22 15:27:57 -07001016
1017 let entries_new = get_keyentry(&db)?;
1018 assert_eq!(entries, entries_new);
1019 Ok(())
1020 }
1021
1022 #[test]
Joel Galenson0891bc12020-07-20 10:37:03 -07001023 fn test_create_key_entry() -> Result<()> {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001024 fn extractor(ke: &KeyEntryRow) -> (Domain, i64, Option<&str>) {
Joel Galenson0891bc12020-07-20 10:37:03 -07001025 (ke.domain.unwrap(), ke.namespace.unwrap(), ke.alias.as_deref())
1026 }
1027
Janis Danisevskis4df44f42020-08-26 14:40:03 -07001028 let db = new_test_db()?;
Joel Galenson0891bc12020-07-20 10:37:03 -07001029
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001030 db.create_key_entry(Domain::APP, 100)?;
1031 db.create_key_entry(Domain::SELINUX, 101)?;
Joel Galenson0891bc12020-07-20 10:37:03 -07001032
1033 let entries = get_keyentry(&db)?;
1034 assert_eq!(entries.len(), 2);
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001035 assert_eq!(extractor(&entries[0]), (Domain::APP, 100, None));
1036 assert_eq!(extractor(&entries[1]), (Domain::SELINUX, 101, None));
Joel Galenson0891bc12020-07-20 10:37:03 -07001037
1038 // Test that we must pass in a valid Domain.
1039 check_result_is_error_containing_string(
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001040 db.create_key_entry(Domain::GRANT, 102),
1041 "Domain Domain(1) must be either App or SELinux.",
Joel Galenson0891bc12020-07-20 10:37:03 -07001042 );
1043 check_result_is_error_containing_string(
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001044 db.create_key_entry(Domain::BLOB, 103),
1045 "Domain Domain(3) must be either App or SELinux.",
Joel Galenson0891bc12020-07-20 10:37:03 -07001046 );
1047 check_result_is_error_containing_string(
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001048 db.create_key_entry(Domain::KEY_ID, 104),
1049 "Domain Domain(4) must be either App or SELinux.",
Joel Galenson0891bc12020-07-20 10:37:03 -07001050 );
1051
1052 Ok(())
1053 }
1054
Joel Galenson33c04ad2020-08-03 11:04:38 -07001055 #[test]
1056 fn test_rebind_alias() -> Result<()> {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001057 fn extractor(ke: &KeyEntryRow) -> (Option<Domain>, Option<i64>, Option<&str>) {
Joel Galenson33c04ad2020-08-03 11:04:38 -07001058 (ke.domain, ke.namespace, ke.alias.as_deref())
1059 }
1060
Janis Danisevskis4df44f42020-08-26 14:40:03 -07001061 let mut db = new_test_db()?;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001062 db.create_key_entry(Domain::APP, 42)?;
1063 db.create_key_entry(Domain::APP, 42)?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07001064 let entries = get_keyentry(&db)?;
1065 assert_eq!(entries.len(), 2);
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001066 assert_eq!(extractor(&entries[0]), (Some(Domain::APP), Some(42), None));
1067 assert_eq!(extractor(&entries[1]), (Some(Domain::APP), Some(42), None));
Joel Galenson33c04ad2020-08-03 11:04:38 -07001068
1069 // Test that the first call to rebind_alias sets the alias.
Janis Danisevskisaec14592020-11-12 09:41:49 -08001070 db.rebind_alias(&KEY_ID_LOCK.get(entries[0].id), "foo", Domain::APP, 42)?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07001071 let entries = get_keyentry(&db)?;
1072 assert_eq!(entries.len(), 2);
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001073 assert_eq!(extractor(&entries[0]), (Some(Domain::APP), Some(42), Some("foo")));
1074 assert_eq!(extractor(&entries[1]), (Some(Domain::APP), Some(42), None));
Joel Galenson33c04ad2020-08-03 11:04:38 -07001075
1076 // Test that the second call to rebind_alias also empties the old one.
Janis Danisevskisaec14592020-11-12 09:41:49 -08001077 db.rebind_alias(&KEY_ID_LOCK.get(entries[1].id), "foo", Domain::APP, 42)?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07001078 let entries = get_keyentry(&db)?;
1079 assert_eq!(entries.len(), 2);
Joel Galenson7fa5c412020-11-19 10:56:54 -08001080 assert_eq!(extractor(&entries[0]), (None, None, None));
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001081 assert_eq!(extractor(&entries[1]), (Some(Domain::APP), Some(42), Some("foo")));
Joel Galenson33c04ad2020-08-03 11:04:38 -07001082
1083 // Test that we must pass in a valid Domain.
1084 check_result_is_error_containing_string(
Janis Danisevskisaec14592020-11-12 09:41:49 -08001085 db.rebind_alias(&KEY_ID_LOCK.get(0), "foo", Domain::GRANT, 42),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001086 "Domain Domain(1) must be either App or SELinux.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07001087 );
1088 check_result_is_error_containing_string(
Janis Danisevskisaec14592020-11-12 09:41:49 -08001089 db.rebind_alias(&KEY_ID_LOCK.get(0), "foo", Domain::BLOB, 42),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001090 "Domain Domain(3) must be either App or SELinux.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07001091 );
1092 check_result_is_error_containing_string(
Janis Danisevskisaec14592020-11-12 09:41:49 -08001093 db.rebind_alias(&KEY_ID_LOCK.get(0), "foo", Domain::KEY_ID, 42),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001094 "Domain Domain(4) must be either App or SELinux.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07001095 );
1096
1097 // Test that we correctly handle setting an alias for something that does not exist.
1098 check_result_is_error_containing_string(
Janis Danisevskisaec14592020-11-12 09:41:49 -08001099 db.rebind_alias(&KEY_ID_LOCK.get(0), "foo", Domain::SELINUX, 42),
Joel Galenson33c04ad2020-08-03 11:04:38 -07001100 "Expected to update a single entry but instead updated 0",
1101 );
1102 // Test that we correctly abort the transaction in this case.
1103 let entries = get_keyentry(&db)?;
1104 assert_eq!(entries.len(), 2);
Joel Galenson7fa5c412020-11-19 10:56:54 -08001105 assert_eq!(extractor(&entries[0]), (None, None, None));
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001106 assert_eq!(extractor(&entries[1]), (Some(Domain::APP), Some(42), Some("foo")));
Joel Galenson33c04ad2020-08-03 11:04:38 -07001107
1108 Ok(())
1109 }
1110
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001111 #[test]
1112 fn test_grant_ungrant() -> Result<()> {
1113 const CALLER_UID: u32 = 15;
1114 const GRANTEE_UID: u32 = 12;
1115 const SELINUX_NAMESPACE: i64 = 7;
1116
1117 let mut db = new_test_db()?;
1118 db.conn.execute(
1119 "INSERT INTO persistent.keyentry (id, creation_date, domain, namespace, alias)
1120 VALUES (1, '1980', 0, 15, 'key'), (2, '1980', 2, 7, 'yek');",
1121 NO_PARAMS,
1122 )?;
1123 let app_key = KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001124 domain: super::Domain::APP,
1125 nspace: 0,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001126 alias: Some("key".to_string()),
1127 blob: None,
1128 };
1129 const PVEC1: KeyPermSet = key_perm_set![KeyPerm::use_(), KeyPerm::get_info()];
1130 const PVEC2: KeyPermSet = key_perm_set![KeyPerm::use_()];
1131
1132 // Reset totally predictable random number generator in case we
1133 // are not the first test running on this thread.
1134 reset_random();
1135 let next_random = 0i64;
1136
1137 let app_granted_key =
1138 db.grant(app_key.clone(), CALLER_UID, GRANTEE_UID, PVEC1, |k, a| {
1139 assert_eq!(*a, PVEC1);
1140 assert_eq!(
1141 *k,
1142 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001143 domain: super::Domain::APP,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001144 // namespace must be set to the caller_uid.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001145 nspace: CALLER_UID as i64,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001146 alias: Some("key".to_string()),
1147 blob: None,
1148 }
1149 );
1150 Ok(())
1151 })?;
1152
1153 assert_eq!(
1154 app_granted_key,
1155 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001156 domain: super::Domain::GRANT,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001157 // The grantid is next_random due to the mock random number generator.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001158 nspace: next_random,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001159 alias: None,
1160 blob: None,
1161 }
1162 );
1163
1164 let selinux_key = KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001165 domain: super::Domain::SELINUX,
1166 nspace: SELINUX_NAMESPACE,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001167 alias: Some("yek".to_string()),
1168 blob: None,
1169 };
1170
1171 let selinux_granted_key =
1172 db.grant(selinux_key.clone(), CALLER_UID, 12, PVEC1, |k, a| {
1173 assert_eq!(*a, PVEC1);
1174 assert_eq!(
1175 *k,
1176 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001177 domain: super::Domain::SELINUX,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001178 // namespace must be the supplied SELinux
1179 // namespace.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001180 nspace: SELINUX_NAMESPACE,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001181 alias: Some("yek".to_string()),
1182 blob: None,
1183 }
1184 );
1185 Ok(())
1186 })?;
1187
1188 assert_eq!(
1189 selinux_granted_key,
1190 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001191 domain: super::Domain::GRANT,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001192 // The grantid is next_random + 1 due to the mock random number generator.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001193 nspace: next_random + 1,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001194 alias: None,
1195 blob: None,
1196 }
1197 );
1198
1199 // This should update the existing grant with PVEC2.
1200 let selinux_granted_key =
1201 db.grant(selinux_key.clone(), CALLER_UID, 12, PVEC2, |k, a| {
1202 assert_eq!(*a, PVEC2);
1203 assert_eq!(
1204 *k,
1205 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001206 domain: super::Domain::SELINUX,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001207 // namespace must be the supplied SELinux
1208 // namespace.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001209 nspace: SELINUX_NAMESPACE,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001210 alias: Some("yek".to_string()),
1211 blob: None,
1212 }
1213 );
1214 Ok(())
1215 })?;
1216
1217 assert_eq!(
1218 selinux_granted_key,
1219 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001220 domain: super::Domain::GRANT,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001221 // Same grant id as before. The entry was only updated.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001222 nspace: next_random + 1,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001223 alias: None,
1224 blob: None,
1225 }
1226 );
1227
1228 {
1229 // Limiting scope of stmt, because it borrows db.
1230 let mut stmt = db
1231 .conn
1232 .prepare("SELECT id, grantee, keyentryid, access_vector FROM perboot.grant;")?;
Janis Danisevskisee10b5f2020-09-22 16:42:35 -07001233 let mut rows =
1234 stmt.query_map::<(i64, u32, i64, KeyPermSet), _, _>(NO_PARAMS, |row| {
1235 Ok((
1236 row.get(0)?,
1237 row.get(1)?,
1238 row.get(2)?,
1239 KeyPermSet::from(row.get::<_, i32>(3)?),
1240 ))
1241 })?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001242
1243 let r = rows.next().unwrap().unwrap();
Janis Danisevskisee10b5f2020-09-22 16:42:35 -07001244 assert_eq!(r, (next_random, GRANTEE_UID, 1, PVEC1));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001245 let r = rows.next().unwrap().unwrap();
Janis Danisevskisee10b5f2020-09-22 16:42:35 -07001246 assert_eq!(r, (next_random + 1, GRANTEE_UID, 2, PVEC2));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001247 assert!(rows.next().is_none());
1248 }
1249
1250 debug_dump_keyentry_table(&mut db)?;
1251 println!("app_key {:?}", app_key);
1252 println!("selinux_key {:?}", selinux_key);
1253
1254 db.ungrant(app_key, CALLER_UID, GRANTEE_UID, |_| Ok(()))?;
1255 db.ungrant(selinux_key, CALLER_UID, GRANTEE_UID, |_| Ok(()))?;
1256
1257 Ok(())
1258 }
1259
1260 static TEST_KM_BLOB: &[u8] = b"my test blob";
1261 static TEST_CERT_BLOB: &[u8] = b"my test cert";
1262 static TEST_CERT_CHAIN_BLOB: &[u8] = b"my test cert_chain";
1263
1264 #[test]
1265 fn test_insert_blob() -> Result<()> {
1266 let mut db = new_test_db()?;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001267 db.insert_blob(
Janis Danisevskisaec14592020-11-12 09:41:49 -08001268 &KEY_ID_LOCK.get(1),
1269 SubComponentType::KM_BLOB,
1270 TEST_KM_BLOB,
1271 SecurityLevel::SOFTWARE,
1272 )?;
1273 db.insert_blob(
1274 &KEY_ID_LOCK.get(1),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001275 SubComponentType::CERT,
1276 TEST_CERT_BLOB,
1277 SecurityLevel::TRUSTED_ENVIRONMENT,
1278 )?;
1279 db.insert_blob(
Janis Danisevskisaec14592020-11-12 09:41:49 -08001280 &KEY_ID_LOCK.get(1),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001281 SubComponentType::CERT_CHAIN,
1282 TEST_CERT_CHAIN_BLOB,
1283 SecurityLevel::STRONGBOX,
1284 )?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001285
1286 let mut stmt = db.conn.prepare(
1287 "SELECT subcomponent_type, keyentryid, blob, sec_level FROM persistent.blobentry
1288 ORDER BY sec_level ASC;",
1289 )?;
1290 let mut rows = stmt
1291 .query_map::<(SubComponentType, i64, Vec<u8>, i64), _, _>(NO_PARAMS, |row| {
1292 Ok((row.get(0)?, row.get(1)?, row.get(2)?, row.get(3)?))
1293 })?;
1294 let r = rows.next().unwrap().unwrap();
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001295 assert_eq!(r, (SubComponentType::KM_BLOB, 1, TEST_KM_BLOB.to_vec(), 0));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001296 let r = rows.next().unwrap().unwrap();
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001297 assert_eq!(r, (SubComponentType::CERT, 1, TEST_CERT_BLOB.to_vec(), 1));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001298 let r = rows.next().unwrap().unwrap();
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001299 assert_eq!(r, (SubComponentType::CERT_CHAIN, 1, TEST_CERT_CHAIN_BLOB.to_vec(), 2));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001300
1301 Ok(())
1302 }
1303
1304 static TEST_ALIAS: &str = "my super duper key";
1305
1306 #[test]
1307 fn test_insert_and_load_full_keyentry_domain_app() -> Result<()> {
1308 let mut db = new_test_db()?;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001309 let key_id = make_test_key_entry(&mut db, Domain::APP, 1, TEST_ALIAS)
Janis Danisevskisaec14592020-11-12 09:41:49 -08001310 .context("test_insert_and_load_full_keyentry_domain_app")?
1311 .0;
1312 let (_key_guard, key_entry) = db.load_key_entry(
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001313 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001314 domain: Domain::APP,
1315 nspace: 0,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001316 alias: Some(TEST_ALIAS.to_string()),
1317 blob: None,
1318 },
1319 KeyEntryLoadBits::BOTH,
1320 1,
1321 |_k, _av| Ok(()),
1322 )?;
1323 assert_eq!(
1324 key_entry,
1325 KeyEntry {
1326 id: key_id,
1327 km_blob: Some(TEST_KM_BLOB.to_vec()),
1328 cert: Some(TEST_CERT_BLOB.to_vec()),
1329 cert_chain: Some(TEST_CERT_CHAIN_BLOB.to_vec()),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001330 sec_level: SecurityLevel::TRUSTED_ENVIRONMENT,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001331 parameters: make_test_params(),
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001332 }
1333 );
1334 Ok(())
1335 }
1336
1337 #[test]
1338 fn test_insert_and_load_full_keyentry_domain_selinux() -> Result<()> {
1339 let mut db = new_test_db()?;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001340 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS)
Janis Danisevskisaec14592020-11-12 09:41:49 -08001341 .context("test_insert_and_load_full_keyentry_domain_selinux")?
1342 .0;
1343 let (_key_guard, key_entry) = db.load_key_entry(
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001344 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001345 domain: Domain::SELINUX,
1346 nspace: 1,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001347 alias: Some(TEST_ALIAS.to_string()),
1348 blob: None,
1349 },
1350 KeyEntryLoadBits::BOTH,
1351 1,
1352 |_k, _av| Ok(()),
1353 )?;
1354 assert_eq!(
1355 key_entry,
1356 KeyEntry {
1357 id: key_id,
1358 km_blob: Some(TEST_KM_BLOB.to_vec()),
1359 cert: Some(TEST_CERT_BLOB.to_vec()),
1360 cert_chain: Some(TEST_CERT_CHAIN_BLOB.to_vec()),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001361 sec_level: SecurityLevel::TRUSTED_ENVIRONMENT,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001362 parameters: make_test_params(),
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001363 }
1364 );
1365 Ok(())
1366 }
1367
1368 #[test]
1369 fn test_insert_and_load_full_keyentry_domain_key_id() -> Result<()> {
1370 let mut db = new_test_db()?;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001371 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS)
Janis Danisevskisaec14592020-11-12 09:41:49 -08001372 .context("test_insert_and_load_full_keyentry_domain_key_id")?
1373 .0;
1374 let (_key_guard, key_entry) = db.load_key_entry(
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001375 KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001376 KeyEntryLoadBits::BOTH,
1377 1,
1378 |_k, _av| Ok(()),
1379 )?;
1380 assert_eq!(
1381 key_entry,
1382 KeyEntry {
1383 id: key_id,
1384 km_blob: Some(TEST_KM_BLOB.to_vec()),
1385 cert: Some(TEST_CERT_BLOB.to_vec()),
1386 cert_chain: Some(TEST_CERT_CHAIN_BLOB.to_vec()),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001387 sec_level: SecurityLevel::TRUSTED_ENVIRONMENT,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001388 parameters: make_test_params(),
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001389 }
1390 );
1391
1392 Ok(())
1393 }
1394
1395 #[test]
1396 fn test_insert_and_load_full_keyentry_from_grant() -> Result<()> {
1397 let mut db = new_test_db()?;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001398 let key_id = make_test_key_entry(&mut db, Domain::APP, 1, TEST_ALIAS)
Janis Danisevskisaec14592020-11-12 09:41:49 -08001399 .context("test_insert_and_load_full_keyentry_from_grant")?
1400 .0;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001401
1402 let granted_key = db.grant(
1403 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001404 domain: Domain::APP,
1405 nspace: 0,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001406 alias: Some(TEST_ALIAS.to_string()),
1407 blob: None,
1408 },
1409 1,
1410 2,
1411 key_perm_set![KeyPerm::use_()],
1412 |_k, _av| Ok(()),
1413 )?;
1414
1415 debug_dump_grant_table(&mut db)?;
1416
Janis Danisevskisaec14592020-11-12 09:41:49 -08001417 let (_key_guard, key_entry) =
1418 db.load_key_entry(granted_key, KeyEntryLoadBits::BOTH, 2, |k, av| {
1419 assert_eq!(Domain::GRANT, k.domain);
1420 assert!(av.unwrap().includes(KeyPerm::use_()));
1421 Ok(())
1422 })?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001423
1424 assert_eq!(
1425 key_entry,
1426 KeyEntry {
1427 id: key_id,
1428 km_blob: Some(TEST_KM_BLOB.to_vec()),
1429 cert: Some(TEST_CERT_BLOB.to_vec()),
1430 cert_chain: Some(TEST_CERT_CHAIN_BLOB.to_vec()),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001431 sec_level: SecurityLevel::TRUSTED_ENVIRONMENT,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001432 parameters: make_test_params(),
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001433 }
1434 );
1435 Ok(())
1436 }
1437
Janis Danisevskisaec14592020-11-12 09:41:49 -08001438 static KEY_LOCK_TEST_ALIAS: &str = "my super duper locked key";
1439
1440 static KEY_LOCK_TEST_SQL: &str = "/data/local/tmp/persistent_key_lock.sqlite";
1441 static KEY_LOCK_PERBOOT_TEST_SQL: &str = "/data/local/tmp/perboot_key_lock.sqlite";
1442
1443 fn new_test_db_with_persistent_file_key_lock() -> Result<KeystoreDB> {
1444 let conn = KeystoreDB::make_connection(KEY_LOCK_TEST_SQL, KEY_LOCK_PERBOOT_TEST_SQL)?;
1445
1446 KeystoreDB::init_tables(&conn).context("Failed to initialize tables.")?;
1447 Ok(KeystoreDB { conn })
1448 }
1449
1450 #[test]
1451 fn test_insert_and_load_full_keyentry_domain_app_concurrently() -> Result<()> {
1452 let handle = {
1453 let _file_guard_persistent = Arc::new(TempFile { filename: KEY_LOCK_TEST_SQL });
1454 let _file_guard_perboot = Arc::new(TempFile { filename: KEY_LOCK_PERBOOT_TEST_SQL });
1455 let mut db = new_test_db_with_persistent_file_key_lock()?;
1456 let key_id = make_test_key_entry(&mut db, Domain::APP, 33, KEY_LOCK_TEST_ALIAS)
1457 .context("test_insert_and_load_full_keyentry_domain_app")?
1458 .0;
1459 let (_key_guard, key_entry) = db.load_key_entry(
1460 KeyDescriptor {
1461 domain: Domain::APP,
1462 nspace: 0,
1463 alias: Some(KEY_LOCK_TEST_ALIAS.to_string()),
1464 blob: None,
1465 },
1466 KeyEntryLoadBits::BOTH,
1467 33,
1468 |_k, _av| Ok(()),
1469 )?;
1470 assert_eq!(
1471 key_entry,
1472 KeyEntry {
1473 id: key_id,
1474 km_blob: Some(TEST_KM_BLOB.to_vec()),
1475 cert: Some(TEST_CERT_BLOB.to_vec()),
1476 cert_chain: Some(TEST_CERT_CHAIN_BLOB.to_vec()),
1477 sec_level: SecurityLevel::TRUSTED_ENVIRONMENT,
1478 parameters: make_test_params(),
1479 }
1480 );
1481 let state = Arc::new(AtomicU8::new(1));
1482 let state2 = state.clone();
1483
1484 // Spawning a second thread that attempts to acquire the key id lock
1485 // for the same key as the primary thread. The primary thread then
1486 // waits, thereby forcing the secondary thread into the second stage
1487 // of acquiring the lock (see KEY ID LOCK 2/2 above).
1488 // The test succeeds if the secondary thread observes the transition
1489 // of `state` from 1 to 2, despite having a whole second to overtake
1490 // the primary thread.
1491 let handle = thread::spawn(move || {
1492 let _file_a = _file_guard_persistent;
1493 let _file_b = _file_guard_perboot;
1494 let mut db = new_test_db_with_persistent_file_key_lock().unwrap();
1495 assert!(db
1496 .load_key_entry(
1497 KeyDescriptor {
1498 domain: Domain::APP,
1499 nspace: 0,
1500 alias: Some(KEY_LOCK_TEST_ALIAS.to_string()),
1501 blob: None,
1502 },
1503 KeyEntryLoadBits::BOTH,
1504 33,
1505 |_k, _av| Ok(()),
1506 )
1507 .is_ok());
1508 // We should only see a 2 here because we can only return
1509 // from load_key_entry when the `_key_guard` expires,
1510 // which happens at the end of the scope.
1511 assert_eq!(2, state2.load(Ordering::Relaxed));
1512 });
1513
1514 thread::sleep(std::time::Duration::from_millis(1000));
1515
1516 assert_eq!(Ok(1), state.compare_exchange(1, 2, Ordering::Relaxed, Ordering::Relaxed));
1517
1518 // Return the handle from this scope so we can join with the
1519 // secondary thread after the key id lock has expired.
1520 handle
1521 // This is where the `_key_guard` goes out of scope,
1522 // which is the reason for concurrent load_key_entry on the same key
1523 // to unblock.
1524 };
1525 // Join with the secondary thread and unwrap, to propagate failing asserts to the
1526 // main test thread. We will not see failing asserts in secondary threads otherwise.
1527 handle.join().unwrap();
1528 Ok(())
1529 }
1530
Joel Galenson0891bc12020-07-20 10:37:03 -07001531 // Helpers
1532
1533 // Checks that the given result is an error containing the given string.
1534 fn check_result_is_error_containing_string<T>(result: Result<T>, target: &str) {
1535 let error_str = format!(
1536 "{:#?}",
1537 result.err().unwrap_or_else(|| panic!("Expected the error: {}", target))
1538 );
1539 assert!(
1540 error_str.contains(target),
1541 "The string \"{}\" should contain \"{}\"",
1542 error_str,
1543 target
1544 );
1545 }
1546
Joel Galenson2aab4432020-07-22 15:27:57 -07001547 #[derive(Debug, PartialEq)]
Joel Galenson0891bc12020-07-20 10:37:03 -07001548 #[allow(dead_code)]
1549 struct KeyEntryRow {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001550 id: i64,
Joel Galenson0891bc12020-07-20 10:37:03 -07001551 creation_date: String,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001552 domain: Option<Domain>,
Joel Galenson0891bc12020-07-20 10:37:03 -07001553 namespace: Option<i64>,
1554 alias: Option<String>,
1555 }
1556
1557 fn get_keyentry(db: &KeystoreDB) -> Result<Vec<KeyEntryRow>> {
1558 db.conn
Joel Galenson2aab4432020-07-22 15:27:57 -07001559 .prepare("SELECT * FROM persistent.keyentry;")?
Joel Galenson0891bc12020-07-20 10:37:03 -07001560 .query_map(NO_PARAMS, |row| {
Joel Galenson0891bc12020-07-20 10:37:03 -07001561 Ok(KeyEntryRow {
1562 id: row.get(0)?,
1563 creation_date: row.get(1)?,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001564 domain: match row.get(2)? {
1565 Some(i) => Some(Domain(i)),
1566 None => None,
1567 },
Joel Galenson0891bc12020-07-20 10:37:03 -07001568 namespace: row.get(3)?,
1569 alias: row.get(4)?,
1570 })
1571 })?
1572 .map(|r| r.context("Could not read keyentry row."))
1573 .collect::<Result<Vec<_>>>()
1574 }
1575
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001576 // Note: The parameters and SecurityLevel associations are nonsensical. This
1577 // collection is only used to check if the parameters are preserved as expected by the
1578 // database.
1579 fn make_test_params() -> Vec<KeyParameter> {
1580 vec![
1581 KeyParameter::new(KeyParameterValue::Invalid, SecurityLevel::TRUSTED_ENVIRONMENT),
1582 KeyParameter::new(
1583 KeyParameterValue::KeyPurpose(KeyPurpose::SIGN),
1584 SecurityLevel::TRUSTED_ENVIRONMENT,
1585 ),
1586 KeyParameter::new(
1587 KeyParameterValue::KeyPurpose(KeyPurpose::DECRYPT),
1588 SecurityLevel::TRUSTED_ENVIRONMENT,
1589 ),
1590 KeyParameter::new(
1591 KeyParameterValue::Algorithm(Algorithm::RSA),
1592 SecurityLevel::TRUSTED_ENVIRONMENT,
1593 ),
1594 KeyParameter::new(KeyParameterValue::KeySize(1024), SecurityLevel::TRUSTED_ENVIRONMENT),
1595 KeyParameter::new(
1596 KeyParameterValue::BlockMode(BlockMode::ECB),
1597 SecurityLevel::TRUSTED_ENVIRONMENT,
1598 ),
1599 KeyParameter::new(
1600 KeyParameterValue::BlockMode(BlockMode::GCM),
1601 SecurityLevel::TRUSTED_ENVIRONMENT,
1602 ),
1603 KeyParameter::new(KeyParameterValue::Digest(Digest::NONE), SecurityLevel::STRONGBOX),
1604 KeyParameter::new(
1605 KeyParameterValue::Digest(Digest::MD5),
1606 SecurityLevel::TRUSTED_ENVIRONMENT,
1607 ),
1608 KeyParameter::new(
1609 KeyParameterValue::Digest(Digest::SHA_2_224),
1610 SecurityLevel::TRUSTED_ENVIRONMENT,
1611 ),
1612 KeyParameter::new(
1613 KeyParameterValue::Digest(Digest::SHA_2_256),
1614 SecurityLevel::STRONGBOX,
1615 ),
1616 KeyParameter::new(
1617 KeyParameterValue::PaddingMode(PaddingMode::NONE),
1618 SecurityLevel::TRUSTED_ENVIRONMENT,
1619 ),
1620 KeyParameter::new(
1621 KeyParameterValue::PaddingMode(PaddingMode::RSA_OAEP),
1622 SecurityLevel::TRUSTED_ENVIRONMENT,
1623 ),
1624 KeyParameter::new(
1625 KeyParameterValue::PaddingMode(PaddingMode::RSA_PSS),
1626 SecurityLevel::STRONGBOX,
1627 ),
1628 KeyParameter::new(
1629 KeyParameterValue::PaddingMode(PaddingMode::RSA_PKCS1_1_5_SIGN),
1630 SecurityLevel::TRUSTED_ENVIRONMENT,
1631 ),
1632 KeyParameter::new(KeyParameterValue::CallerNonce, SecurityLevel::TRUSTED_ENVIRONMENT),
1633 KeyParameter::new(KeyParameterValue::MinMacLength(256), SecurityLevel::STRONGBOX),
1634 KeyParameter::new(
1635 KeyParameterValue::EcCurve(EcCurve::P_224),
1636 SecurityLevel::TRUSTED_ENVIRONMENT,
1637 ),
1638 KeyParameter::new(KeyParameterValue::EcCurve(EcCurve::P_256), SecurityLevel::STRONGBOX),
1639 KeyParameter::new(
1640 KeyParameterValue::EcCurve(EcCurve::P_384),
1641 SecurityLevel::TRUSTED_ENVIRONMENT,
1642 ),
1643 KeyParameter::new(
1644 KeyParameterValue::EcCurve(EcCurve::P_521),
1645 SecurityLevel::TRUSTED_ENVIRONMENT,
1646 ),
1647 KeyParameter::new(
1648 KeyParameterValue::RSAPublicExponent(3),
1649 SecurityLevel::TRUSTED_ENVIRONMENT,
1650 ),
1651 KeyParameter::new(
1652 KeyParameterValue::IncludeUniqueID,
1653 SecurityLevel::TRUSTED_ENVIRONMENT,
1654 ),
1655 KeyParameter::new(KeyParameterValue::BootLoaderOnly, SecurityLevel::STRONGBOX),
1656 KeyParameter::new(KeyParameterValue::RollbackResistance, SecurityLevel::STRONGBOX),
1657 KeyParameter::new(
1658 KeyParameterValue::ActiveDateTime(1234567890),
1659 SecurityLevel::STRONGBOX,
1660 ),
1661 KeyParameter::new(
1662 KeyParameterValue::OriginationExpireDateTime(1234567890),
1663 SecurityLevel::TRUSTED_ENVIRONMENT,
1664 ),
1665 KeyParameter::new(
1666 KeyParameterValue::UsageExpireDateTime(1234567890),
1667 SecurityLevel::TRUSTED_ENVIRONMENT,
1668 ),
1669 KeyParameter::new(
1670 KeyParameterValue::MinSecondsBetweenOps(1234567890),
1671 SecurityLevel::TRUSTED_ENVIRONMENT,
1672 ),
1673 KeyParameter::new(
1674 KeyParameterValue::MaxUsesPerBoot(1234567890),
1675 SecurityLevel::TRUSTED_ENVIRONMENT,
1676 ),
1677 KeyParameter::new(KeyParameterValue::UserID(1), SecurityLevel::STRONGBOX),
1678 KeyParameter::new(KeyParameterValue::UserSecureID(42), SecurityLevel::STRONGBOX),
1679 KeyParameter::new(
1680 KeyParameterValue::NoAuthRequired,
1681 SecurityLevel::TRUSTED_ENVIRONMENT,
1682 ),
1683 KeyParameter::new(
1684 KeyParameterValue::HardwareAuthenticatorType(HardwareAuthenticatorType::PASSWORD),
1685 SecurityLevel::TRUSTED_ENVIRONMENT,
1686 ),
1687 KeyParameter::new(KeyParameterValue::AuthTimeout(1234567890), SecurityLevel::SOFTWARE),
1688 KeyParameter::new(KeyParameterValue::AllowWhileOnBody, SecurityLevel::SOFTWARE),
1689 KeyParameter::new(
1690 KeyParameterValue::TrustedUserPresenceRequired,
1691 SecurityLevel::TRUSTED_ENVIRONMENT,
1692 ),
1693 KeyParameter::new(
1694 KeyParameterValue::TrustedConfirmationRequired,
1695 SecurityLevel::TRUSTED_ENVIRONMENT,
1696 ),
1697 KeyParameter::new(
1698 KeyParameterValue::UnlockedDeviceRequired,
1699 SecurityLevel::TRUSTED_ENVIRONMENT,
1700 ),
1701 KeyParameter::new(
1702 KeyParameterValue::ApplicationID(vec![1u8, 2u8, 3u8, 4u8]),
1703 SecurityLevel::SOFTWARE,
1704 ),
1705 KeyParameter::new(
1706 KeyParameterValue::ApplicationData(vec![4u8, 3u8, 2u8, 1u8]),
1707 SecurityLevel::SOFTWARE,
1708 ),
1709 KeyParameter::new(
1710 KeyParameterValue::CreationDateTime(12345677890),
1711 SecurityLevel::SOFTWARE,
1712 ),
1713 KeyParameter::new(
1714 KeyParameterValue::KeyOrigin(KeyOrigin::GENERATED),
1715 SecurityLevel::TRUSTED_ENVIRONMENT,
1716 ),
1717 KeyParameter::new(
1718 KeyParameterValue::RootOfTrust(vec![3u8, 2u8, 1u8, 4u8]),
1719 SecurityLevel::TRUSTED_ENVIRONMENT,
1720 ),
1721 KeyParameter::new(KeyParameterValue::OSVersion(1), SecurityLevel::TRUSTED_ENVIRONMENT),
1722 KeyParameter::new(KeyParameterValue::OSPatchLevel(2), SecurityLevel::SOFTWARE),
1723 KeyParameter::new(
1724 KeyParameterValue::UniqueID(vec![4u8, 3u8, 1u8, 2u8]),
1725 SecurityLevel::SOFTWARE,
1726 ),
1727 KeyParameter::new(
1728 KeyParameterValue::AttestationChallenge(vec![4u8, 3u8, 1u8, 2u8]),
1729 SecurityLevel::TRUSTED_ENVIRONMENT,
1730 ),
1731 KeyParameter::new(
1732 KeyParameterValue::AttestationApplicationID(vec![4u8, 3u8, 1u8, 2u8]),
1733 SecurityLevel::TRUSTED_ENVIRONMENT,
1734 ),
1735 KeyParameter::new(
1736 KeyParameterValue::AttestationIdBrand(vec![4u8, 3u8, 1u8, 2u8]),
1737 SecurityLevel::TRUSTED_ENVIRONMENT,
1738 ),
1739 KeyParameter::new(
1740 KeyParameterValue::AttestationIdDevice(vec![4u8, 3u8, 1u8, 2u8]),
1741 SecurityLevel::TRUSTED_ENVIRONMENT,
1742 ),
1743 KeyParameter::new(
1744 KeyParameterValue::AttestationIdProduct(vec![4u8, 3u8, 1u8, 2u8]),
1745 SecurityLevel::TRUSTED_ENVIRONMENT,
1746 ),
1747 KeyParameter::new(
1748 KeyParameterValue::AttestationIdSerial(vec![4u8, 3u8, 1u8, 2u8]),
1749 SecurityLevel::TRUSTED_ENVIRONMENT,
1750 ),
1751 KeyParameter::new(
1752 KeyParameterValue::AttestationIdIMEI(vec![4u8, 3u8, 1u8, 2u8]),
1753 SecurityLevel::TRUSTED_ENVIRONMENT,
1754 ),
1755 KeyParameter::new(
1756 KeyParameterValue::AttestationIdMEID(vec![4u8, 3u8, 1u8, 2u8]),
1757 SecurityLevel::TRUSTED_ENVIRONMENT,
1758 ),
1759 KeyParameter::new(
1760 KeyParameterValue::AttestationIdManufacturer(vec![4u8, 3u8, 1u8, 2u8]),
1761 SecurityLevel::TRUSTED_ENVIRONMENT,
1762 ),
1763 KeyParameter::new(
1764 KeyParameterValue::AttestationIdModel(vec![4u8, 3u8, 1u8, 2u8]),
1765 SecurityLevel::TRUSTED_ENVIRONMENT,
1766 ),
1767 KeyParameter::new(
1768 KeyParameterValue::VendorPatchLevel(3),
1769 SecurityLevel::TRUSTED_ENVIRONMENT,
1770 ),
1771 KeyParameter::new(
1772 KeyParameterValue::BootPatchLevel(4),
1773 SecurityLevel::TRUSTED_ENVIRONMENT,
1774 ),
1775 KeyParameter::new(
1776 KeyParameterValue::AssociatedData(vec![4u8, 3u8, 1u8, 2u8]),
1777 SecurityLevel::TRUSTED_ENVIRONMENT,
1778 ),
1779 KeyParameter::new(
1780 KeyParameterValue::Nonce(vec![4u8, 3u8, 1u8, 2u8]),
1781 SecurityLevel::TRUSTED_ENVIRONMENT,
1782 ),
1783 KeyParameter::new(
1784 KeyParameterValue::MacLength(256),
1785 SecurityLevel::TRUSTED_ENVIRONMENT,
1786 ),
1787 KeyParameter::new(
1788 KeyParameterValue::ResetSinceIdRotation,
1789 SecurityLevel::TRUSTED_ENVIRONMENT,
1790 ),
1791 KeyParameter::new(
1792 KeyParameterValue::ConfirmationToken(vec![5u8, 5u8, 5u8, 5u8]),
1793 SecurityLevel::TRUSTED_ENVIRONMENT,
1794 ),
1795 ]
1796 }
1797
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001798 fn make_test_key_entry(
1799 db: &mut KeystoreDB,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001800 domain: Domain,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001801 namespace: i64,
1802 alias: &str,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001803 ) -> Result<KeyIdGuard> {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001804 let key_id = db.create_key_entry(domain, namespace)?;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001805 db.insert_blob(
Janis Danisevskisaec14592020-11-12 09:41:49 -08001806 &key_id,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001807 SubComponentType::KM_BLOB,
1808 TEST_KM_BLOB,
1809 SecurityLevel::TRUSTED_ENVIRONMENT,
1810 )?;
1811 db.insert_blob(
Janis Danisevskisaec14592020-11-12 09:41:49 -08001812 &key_id,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001813 SubComponentType::CERT,
1814 TEST_CERT_BLOB,
1815 SecurityLevel::TRUSTED_ENVIRONMENT,
1816 )?;
1817 db.insert_blob(
Janis Danisevskisaec14592020-11-12 09:41:49 -08001818 &key_id,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001819 SubComponentType::CERT_CHAIN,
1820 TEST_CERT_CHAIN_BLOB,
1821 SecurityLevel::TRUSTED_ENVIRONMENT,
1822 )?;
Janis Danisevskisaec14592020-11-12 09:41:49 -08001823 db.insert_keyparameter(&key_id, &make_test_params())?;
1824 db.rebind_alias(&key_id, alias, domain, namespace)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001825 Ok(key_id)
1826 }
1827
1828 fn debug_dump_keyentry_table(db: &mut KeystoreDB) -> Result<()> {
1829 let mut stmt = db.conn.prepare(
1830 "SELECT id, creation_date, domain, namespace, alias FROM persistent.keyentry;",
1831 )?;
1832 let rows = stmt.query_map::<(i64, i64, i32, i64, String), _, _>(NO_PARAMS, |row| {
1833 Ok((row.get(0)?, row.get(1)?, row.get(2)?, row.get(3)?, row.get(4)?))
1834 })?;
1835
1836 println!("Key entry table rows:");
1837 for r in rows {
1838 let (id, cdate, domain, namespace, alias) = r.unwrap();
1839 println!(
1840 " id: {} Creation date: {} Domain: {} Namespace: {} Alias: {}",
1841 id, cdate, domain, namespace, alias
1842 );
1843 }
1844 Ok(())
1845 }
1846
1847 fn debug_dump_grant_table(db: &mut KeystoreDB) -> Result<()> {
1848 let mut stmt =
1849 db.conn.prepare("SELECT id, grantee, keyentryid, access_vector FROM perboot.grant;")?;
1850 let rows = stmt.query_map::<(i64, i64, i64, i64), _, _>(NO_PARAMS, |row| {
1851 Ok((row.get(0)?, row.get(1)?, row.get(2)?, row.get(3)?))
1852 })?;
1853
1854 println!("Grant table rows:");
1855 for r in rows {
1856 let (id, gt, ki, av) = r.unwrap();
1857 println!(" id: {} grantee: {} key_id: {} access_vector: {}", id, gt, ki, av);
1858 }
1859 Ok(())
1860 }
1861
Joel Galenson2aab4432020-07-22 15:27:57 -07001862 // A class that deletes a file when it is dropped.
1863 // TODO: If we ever add a crate that does this, we can use it instead.
1864 struct TempFile {
1865 filename: &'static str,
1866 }
1867
1868 impl Drop for TempFile {
1869 fn drop(&mut self) {
1870 std::fs::remove_file(self.filename).expect("Cannot delete temporary file");
1871 }
1872 }
1873
Joel Galenson0891bc12020-07-20 10:37:03 -07001874 // Use a custom random number generator that repeats each number once.
1875 // This allows us to test repeated elements.
1876
1877 thread_local! {
1878 static RANDOM_COUNTER: RefCell<i64> = RefCell::new(0);
1879 }
1880
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001881 fn reset_random() {
1882 RANDOM_COUNTER.with(|counter| {
1883 *counter.borrow_mut() = 0;
1884 })
1885 }
1886
Joel Galenson0891bc12020-07-20 10:37:03 -07001887 pub fn random() -> i64 {
1888 RANDOM_COUNTER.with(|counter| {
1889 let result = *counter.borrow() / 2;
1890 *counter.borrow_mut() += 1;
1891 result
1892 })
1893 }
Joel Galenson26f4d012020-07-17 14:57:21 -07001894}