blob: 9d20c75a4cb7a8089861a0b23da6c36cb6b63212 [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);
Janis Danisevskis7fd53582020-11-23 13:40:34 -0800153 drop(locked_keys);
Janis Danisevskisaec14592020-11-12 09:41:49 -0800154 KEY_ID_LOCK.cond_var.notify_all();
155 }
156}
157
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700158/// This type represents a Keystore 2.0 key entry.
159/// An entry has a unique `id` by which it can be found in the database.
160/// It has a security level field, key parameters, and three optional fields
161/// for the KeyMint blob, public certificate and a public certificate chain.
Janis Danisevskisaec14592020-11-12 09:41:49 -0800162#[derive(Debug, Default, Eq, PartialEq, Ord, PartialOrd)]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700163pub struct KeyEntry {
164 id: i64,
165 km_blob: Option<Vec<u8>>,
166 cert: Option<Vec<u8>>,
167 cert_chain: Option<Vec<u8>>,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700168 sec_level: SecurityLevel,
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700169 parameters: Vec<KeyParameter>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700170}
171
172impl KeyEntry {
173 /// Returns the unique id of the Key entry.
174 pub fn id(&self) -> i64 {
175 self.id
176 }
177 /// Exposes the optional KeyMint blob.
178 pub fn km_blob(&self) -> &Option<Vec<u8>> {
179 &self.km_blob
180 }
181 /// Extracts the Optional KeyMint blob.
182 pub fn take_km_blob(&mut self) -> Option<Vec<u8>> {
183 self.km_blob.take()
184 }
185 /// Exposes the optional public certificate.
186 pub fn cert(&self) -> &Option<Vec<u8>> {
187 &self.cert
188 }
189 /// Extracts the optional public certificate.
190 pub fn take_cert(&mut self) -> Option<Vec<u8>> {
191 self.cert.take()
192 }
193 /// Exposes the optional public certificate chain.
194 pub fn cert_chain(&self) -> &Option<Vec<u8>> {
195 &self.cert_chain
196 }
197 /// Extracts the optional public certificate_chain.
198 pub fn take_cert_chain(&mut self) -> Option<Vec<u8>> {
199 self.cert_chain.take()
200 }
201 /// Returns the security level of the key entry.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700202 pub fn sec_level(&self) -> SecurityLevel {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700203 self.sec_level
204 }
Janis Danisevskis04b02832020-10-26 09:21:40 -0700205 /// Exposes the key parameters of this key entry.
206 pub fn key_parameters(&self) -> &Vec<KeyParameter> {
207 &self.parameters
208 }
209 /// Consumes this key entry and extracts the keyparameters from it.
210 pub fn into_key_parameters(self) -> Vec<KeyParameter> {
211 self.parameters
212 }
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700213}
214
215/// Indicates the sub component of a key entry for persistent storage.
216#[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
217pub struct SubComponentType(u32);
218impl SubComponentType {
219 /// Persistent identifier for a KeyMint blob.
220 pub const KM_BLOB: SubComponentType = Self(0);
221 /// Persistent identifier for a certificate blob.
222 pub const CERT: SubComponentType = Self(1);
223 /// Persistent identifier for a certificate chain blob.
224 pub const CERT_CHAIN: SubComponentType = Self(2);
225}
226
227impl ToSql for SubComponentType {
228 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
229 self.0.to_sql()
230 }
231}
232
233impl FromSql for SubComponentType {
234 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
235 Ok(Self(u32::column_result(value)?))
236 }
237}
238
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700239static INIT_TABLES: Once = Once::new();
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
249 /// files persistent.sqlite and perboot.sqlite in the current working
250 /// directory, which is usually `/data/misc/keystore/`.
251 /// It also attempts to initialize all of the tables on the first instantiation
252 /// per service startup. KeystoreDB cannot be used by multiple threads.
253 /// Each thread should open their own connection using `thread_local!`.
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700254 pub fn new() -> Result<Self> {
255 let conn = Self::make_connection("file:persistent.sqlite", "file:perboot.sqlite")?;
256
257 INIT_TABLES.call_once(|| Self::init_tables(&conn).expect("Failed to initialize tables."));
258 Ok(Self { conn })
Joel Galenson2aab4432020-07-22 15:27:57 -0700259 }
260
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700261 fn init_tables(conn: &Connection) -> Result<()> {
262 conn.execute(
263 "CREATE TABLE IF NOT EXISTS persistent.keyentry (
Joel Galenson0891bc12020-07-20 10:37:03 -0700264 id INTEGER UNIQUE,
265 creation_date DATETIME,
266 domain INTEGER,
267 namespace INTEGER,
268 alias TEXT);",
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700269 NO_PARAMS,
270 )
271 .context("Failed to initialize \"keyentry\" table.")?;
272
273 conn.execute(
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700274 "CREATE VIEW IF NOT EXISTS persistent.orphaned AS
275 SELECT id FROM persistent.keyentry WHERE domain IS NULL;",
276 NO_PARAMS,
277 )
278 .context("Failed to initialize \"orphaned\" view")?;
279
280 conn.execute(
281 "CREATE TABLE IF NOT EXISTS persistent.blobentry (
282 id INTEGER PRIMARY KEY,
283 subcomponent_type INTEGER,
284 keyentryid INTEGER,
285 blob BLOB,
286 sec_level INTEGER);",
287 NO_PARAMS,
288 )
289 .context("Failed to initialize \"blobentry\" table.")?;
290
291 conn.execute(
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700292 "CREATE TABLE IF NOT EXISTS persistent.keyparameter (
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000293 keyentryid INTEGER,
294 tag INTEGER,
295 data ANY,
296 security_level INTEGER);",
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700297 NO_PARAMS,
298 )
299 .context("Failed to initialize \"keyparameter\" table.")?;
300
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700301 // TODO only drop the perboot table if we start up for the first time per boot.
302 // Right now this is done once per startup which will lose some information
303 // upon a crash.
304 // Note: This is no regression with respect to the legacy Keystore.
305 conn.execute("DROP TABLE IF EXISTS perboot.grant;", NO_PARAMS)
306 .context("Failed to drop perboot.grant table")?;
307 conn.execute(
308 "CREATE TABLE perboot.grant (
309 id INTEGER UNIQUE,
310 grantee INTEGER,
311 keyentryid INTEGER,
312 access_vector INTEGER);",
313 NO_PARAMS,
314 )
315 .context("Failed to initialize \"grant\" table.")?;
316
Joel Galenson0891bc12020-07-20 10:37:03 -0700317 Ok(())
318 }
319
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700320 fn make_connection(persistent_file: &str, perboot_file: &str) -> Result<Connection> {
321 let conn =
322 Connection::open_in_memory().context("Failed to initialize SQLite connection.")?;
323
324 conn.execute("ATTACH DATABASE ? as persistent;", params![persistent_file])
325 .context("Failed to attach database persistent.")?;
326 conn.execute("ATTACH DATABASE ? as perboot;", params![perboot_file])
327 .context("Failed to attach database perboot.")?;
328
329 Ok(conn)
330 }
331
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700332 /// Creates a new key entry and allocates a new randomized id for the new key.
333 /// The key id gets associated with a domain and namespace but not with an alias.
334 /// To complete key generation `rebind_alias` should be called after all of the
335 /// key artifacts, i.e., blobs and parameters have been associated with the new
336 /// key id. Finalizing with `rebind_alias` makes the creation of a new key entry
337 /// atomic even if key generation is not.
Janis Danisevskisaec14592020-11-12 09:41:49 -0800338 pub fn create_key_entry(&self, domain: Domain, namespace: i64) -> Result<KeyIdGuard> {
Joel Galenson0891bc12020-07-20 10:37:03 -0700339 match domain {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700340 Domain::APP | Domain::SELINUX => {}
Joel Galenson0891bc12020-07-20 10:37:03 -0700341 _ => {
342 return Err(KsError::sys())
343 .context(format!("Domain {:?} must be either App or SELinux.", domain));
344 }
345 }
Janis Danisevskisaec14592020-11-12 09:41:49 -0800346 Ok(KEY_ID_LOCK.get(
347 Self::insert_with_retry(|id| {
348 self.conn.execute(
349 "INSERT into persistent.keyentry (id, creation_date, domain, namespace, alias)
Joel Galenson0891bc12020-07-20 10:37:03 -0700350 VALUES(?, datetime('now'), ?, ?, NULL);",
Janis Danisevskisaec14592020-11-12 09:41:49 -0800351 params![id, domain.0 as u32, namespace],
352 )
353 })
354 .context("In create_key_entry")?,
355 ))
Joel Galenson26f4d012020-07-17 14:57:21 -0700356 }
Joel Galenson33c04ad2020-08-03 11:04:38 -0700357
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700358 /// Inserts a new blob and associates it with the given key id. Each blob
359 /// has a sub component type and a security level.
360 /// Each key can have one of each sub component type associated. If more
361 /// are added only the most recent can be retrieved, and superseded blobs
362 /// will get garbage collected. The security level field of components
363 /// other than `SubComponentType::KM_BLOB` are ignored.
364 pub fn insert_blob(
365 &mut self,
Janis Danisevskisaec14592020-11-12 09:41:49 -0800366 key_id: &KeyIdGuard,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700367 sc_type: SubComponentType,
368 blob: &[u8],
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700369 sec_level: SecurityLevel,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700370 ) -> Result<()> {
371 self.conn
372 .execute(
373 "INSERT into persistent.blobentry (subcomponent_type, keyentryid, blob, sec_level)
374 VALUES (?, ?, ?, ?);",
Janis Danisevskisaec14592020-11-12 09:41:49 -0800375 params![sc_type, key_id.0, blob, sec_level.0],
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700376 )
377 .context("Failed to insert blob.")?;
378 Ok(())
379 }
380
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700381 /// Inserts a collection of key parameters into the `persistent.keyparameter` table
382 /// and associates them with the given `key_id`.
383 pub fn insert_keyparameter<'a>(
384 &mut self,
Janis Danisevskisaec14592020-11-12 09:41:49 -0800385 key_id: &KeyIdGuard,
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700386 params: impl IntoIterator<Item = &'a KeyParameter>,
387 ) -> Result<()> {
388 let mut stmt = self
389 .conn
390 .prepare(
391 "INSERT into persistent.keyparameter (keyentryid, tag, data, security_level)
392 VALUES (?, ?, ?, ?);",
393 )
394 .context("In insert_keyparameter: Failed to prepare statement.")?;
395
396 let iter = params.into_iter();
397 for p in iter {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700398 stmt.insert(params![
Janis Danisevskisaec14592020-11-12 09:41:49 -0800399 key_id.0,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700400 p.get_tag().0,
401 p.key_parameter_value(),
402 p.security_level().0
403 ])
404 .with_context(|| format!("In insert_keyparameter: Failed to insert {:?}", p))?;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700405 }
406 Ok(())
407 }
408
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700409 /// Updates the alias column of the given key id `newid` with the given alias,
410 /// and atomically, removes the alias, domain, and namespace from another row
411 /// with the same alias-domain-namespace tuple if such row exits.
Joel Galenson33c04ad2020-08-03 11:04:38 -0700412 pub fn rebind_alias(
413 &mut self,
Janis Danisevskisaec14592020-11-12 09:41:49 -0800414 newid: &KeyIdGuard,
Joel Galenson33c04ad2020-08-03 11:04:38 -0700415 alias: &str,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700416 domain: Domain,
Joel Galenson33c04ad2020-08-03 11:04:38 -0700417 namespace: i64,
418 ) -> Result<()> {
419 match domain {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700420 Domain::APP | Domain::SELINUX => {}
Joel Galenson33c04ad2020-08-03 11:04:38 -0700421 _ => {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700422 return Err(KsError::sys()).context(format!(
423 "In rebind_alias: Domain {:?} must be either App or SELinux.",
424 domain
425 ));
Joel Galenson33c04ad2020-08-03 11:04:38 -0700426 }
427 }
428 let tx = self
429 .conn
430 .transaction_with_behavior(TransactionBehavior::Immediate)
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700431 .context("In rebind_alias: Failed to initialize transaction.")?;
Joel Galenson33c04ad2020-08-03 11:04:38 -0700432 tx.execute(
433 "UPDATE persistent.keyentry
434 SET alias = NULL, domain = NULL, namespace = NULL
435 WHERE alias = ? AND domain = ? AND namespace = ?;",
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700436 params![alias, domain.0 as u32, namespace],
Joel Galenson33c04ad2020-08-03 11:04:38 -0700437 )
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700438 .context("In rebind_alias: Failed to rebind existing entry.")?;
Joel Galenson33c04ad2020-08-03 11:04:38 -0700439 let result = tx
440 .execute(
441 "UPDATE persistent.keyentry
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700442 SET alias = ?
443 WHERE id = ? AND domain = ? AND namespace = ?;",
Janis Danisevskisaec14592020-11-12 09:41:49 -0800444 params![alias, newid.0, domain.0 as u32, namespace],
Joel Galenson33c04ad2020-08-03 11:04:38 -0700445 )
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700446 .context("In rebind_alias: Failed to set alias.")?;
Joel Galenson33c04ad2020-08-03 11:04:38 -0700447 if result != 1 {
448 // Note that this explicit rollback is not required, as
449 // the transaction should rollback if we do not commit it.
450 // We leave it here for readability.
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700451 tx.rollback().context("In rebind_alias: Failed to rollback a failed transaction.")?;
Joel Galenson33c04ad2020-08-03 11:04:38 -0700452 return Err(KsError::sys()).context(format!(
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700453 "In rebind_alias: Expected to update a single entry but instead updated {}.",
Joel Galenson33c04ad2020-08-03 11:04:38 -0700454 result
455 ));
456 }
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700457 tx.commit().context("In rebind_alias: Failed to commit transaction.")
458 }
459
460 // Helper function loading the key_id given the key descriptor
461 // tuple comprising domain, namespace, and alias.
462 // Requires a valid transaction.
463 fn load_key_entry_id(key: &KeyDescriptor, tx: &Transaction) -> Result<i64> {
464 let alias = key
465 .alias
466 .as_ref()
467 .map_or_else(|| Err(KsError::sys()), Ok)
468 .context("In load_key_entry_id: Alias must be specified.")?;
469 let mut stmt = tx
470 .prepare(
471 "SELECT id FROM persistent.keyentry
472 WHERE
473 domain = ?
474 AND namespace = ?
475 AND alias = ?;",
476 )
477 .context("In load_key_entry_id: Failed to select from keyentry table.")?;
478 let mut rows = stmt
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700479 .query(params![key.domain.0 as u32, key.nspace, alias])
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700480 .context("In load_key_entry_id: Failed to read from keyentry table.")?;
481 Self::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700482 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700483 .get(0)
484 .context("Failed to unpack id.")
485 })
486 .context("In load_key_entry_id.")
487 }
488
489 /// This helper function completes the access tuple of a key, which is required
490 /// to perform access control. The strategy depends on the `domain` field in the
491 /// key descriptor.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700492 /// * Domain::SELINUX: The access tuple is complete and this function only loads
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700493 /// the key_id for further processing.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700494 /// * Domain::APP: Like Domain::SELINUX, but the tuple is completed by `caller_uid`
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700495 /// which serves as the namespace.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700496 /// * Domain::GRANT: The grant table is queried for the `key_id` and the
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700497 /// `access_vector`.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700498 /// * Domain::KEY_ID: The keyentry table is queried for the owning `domain` and
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700499 /// `namespace`.
500 /// In each case the information returned is sufficient to perform the access
501 /// check and the key id can be used to load further key artifacts.
502 fn load_access_tuple(
503 tx: &Transaction,
504 key: KeyDescriptor,
505 caller_uid: u32,
506 ) -> Result<(i64, KeyDescriptor, Option<KeyPermSet>)> {
507 match key.domain {
508 // Domain App or SELinux. In this case we load the key_id from
509 // the keyentry database for further loading of key components.
510 // We already have the full access tuple to perform access control.
511 // The only distinction is that we use the caller_uid instead
512 // of the caller supplied namespace if the domain field is
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700513 // Domain::APP.
514 Domain::APP | Domain::SELINUX => {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700515 let mut access_key = key;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700516 if access_key.domain == Domain::APP {
517 access_key.nspace = caller_uid as i64;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700518 }
519 let key_id = Self::load_key_entry_id(&access_key, &tx)
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700520 .with_context(|| format!("With key.domain = {:?}.", access_key.domain))?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700521
522 Ok((key_id, access_key, None))
523 }
524
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700525 // Domain::GRANT. In this case we load the key_id and the access_vector
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700526 // from the grant table.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700527 Domain::GRANT => {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700528 let mut stmt = tx
529 .prepare(
530 "SELECT keyentryid, access_vector FROM perboot.grant
531 WHERE grantee = ? AND id = ?;",
532 )
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700533 .context("Domain::GRANT prepare statement failed")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700534 let mut rows = stmt
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700535 .query(params![caller_uid as i64, key.nspace])
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700536 .context("Domain:Grant: query failed.")?;
537 let (key_id, access_vector): (i64, i32) =
538 Self::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700539 let r =
540 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700541 Ok((
542 r.get(0).context("Failed to unpack key_id.")?,
543 r.get(1).context("Failed to unpack access_vector.")?,
544 ))
545 })
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700546 .context("Domain::GRANT.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700547 Ok((key_id, key, Some(access_vector.into())))
548 }
549
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700550 // Domain::KEY_ID. In this case we load the domain and namespace from the
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700551 // keyentry database because we need them for access control.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700552 Domain::KEY_ID => {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700553 let mut stmt = tx
554 .prepare(
555 "SELECT domain, namespace FROM persistent.keyentry
556 WHERE
557 id = ?;",
558 )
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700559 .context("Domain::KEY_ID: prepare statement failed")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700560 let mut rows =
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700561 stmt.query(params![key.nspace]).context("Domain::KEY_ID: query failed.")?;
562 let (domain, namespace): (Domain, i64) =
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700563 Self::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700564 let r =
565 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700566 Ok((
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700567 Domain(r.get(0).context("Failed to unpack domain.")?),
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700568 r.get(1).context("Failed to unpack namespace.")?,
569 ))
570 })
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700571 .context("Domain::KEY_ID.")?;
572 let key_id = key.nspace;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700573 let mut access_key = key;
574 access_key.domain = domain;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700575 access_key.nspace = namespace;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700576
577 Ok((key_id, access_key, None))
578 }
579 _ => Err(anyhow!(KsError::sys())),
580 }
581 }
582
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700583 fn load_blob_components(
584 key_id: i64,
585 load_bits: KeyEntryLoadBits,
586 tx: &Transaction,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700587 ) -> Result<(SecurityLevel, Option<Vec<u8>>, Option<Vec<u8>>, Option<Vec<u8>>)> {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700588 let mut stmt = tx
589 .prepare(
590 "SELECT MAX(id), sec_level, subcomponent_type, blob FROM persistent.blobentry
591 WHERE keyentryid = ? GROUP BY subcomponent_type;",
592 )
593 .context("In load_blob_components: prepare statement failed.")?;
594
595 let mut rows =
596 stmt.query(params![key_id]).context("In load_blob_components: query failed.")?;
597
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700598 let mut sec_level: SecurityLevel = Default::default();
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700599 let mut km_blob: Option<Vec<u8>> = None;
600 let mut cert_blob: Option<Vec<u8>> = None;
601 let mut cert_chain_blob: Option<Vec<u8>> = None;
602 Self::with_rows_extract_all(&mut rows, |row| {
603 let sub_type: SubComponentType =
604 row.get(2).context("Failed to extract subcomponent_type.")?;
605 match (sub_type, load_bits.load_public()) {
606 (SubComponentType::KM_BLOB, _) => {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700607 sec_level =
608 SecurityLevel(row.get(1).context("Failed to extract security level.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700609 if load_bits.load_km() {
610 km_blob = Some(row.get(3).context("Failed to extract KM blob.")?);
611 }
612 }
613 (SubComponentType::CERT, true) => {
614 cert_blob =
615 Some(row.get(3).context("Failed to extract public certificate blob.")?);
616 }
617 (SubComponentType::CERT_CHAIN, true) => {
618 cert_chain_blob =
619 Some(row.get(3).context("Failed to extract certificate chain blob.")?);
620 }
621 (SubComponentType::CERT, _) | (SubComponentType::CERT_CHAIN, _) => {}
622 _ => Err(KsError::sys()).context("Unknown subcomponent type.")?,
623 }
624 Ok(())
625 })
626 .context("In load_blob_components.")?;
627
628 Ok((sec_level, km_blob, cert_blob, cert_chain_blob))
629 }
630
631 fn load_key_parameters(key_id: i64, tx: &Transaction) -> Result<Vec<KeyParameter>> {
632 let mut stmt = tx
633 .prepare(
634 "SELECT tag, data, security_level from persistent.keyparameter
635 WHERE keyentryid = ?;",
636 )
637 .context("In load_key_parameters: prepare statement failed.")?;
638
639 let mut parameters: Vec<KeyParameter> = Vec::new();
640
641 let mut rows =
642 stmt.query(params![key_id]).context("In load_key_parameters: query failed.")?;
643 Self::with_rows_extract_all(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700644 let tag = Tag(row.get(0).context("Failed to read tag.")?);
645 let sec_level = SecurityLevel(row.get(2).context("Failed to read sec_level.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700646 parameters.push(
647 KeyParameter::new_from_sql(tag, &SqlField::new(1, &row), sec_level)
648 .context("Failed to read KeyParameter.")?,
649 );
650 Ok(())
651 })
652 .context("In load_key_parameters.")?;
653
654 Ok(parameters)
655 }
656
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700657 /// Load a key entry by the given key descriptor.
658 /// It uses the `check_permission` callback to verify if the access is allowed
659 /// given the key access tuple read from the database using `load_access_tuple`.
660 /// With `load_bits` the caller may specify which blobs shall be loaded from
661 /// the blob database.
662 pub fn load_key_entry(
663 &mut self,
664 key: KeyDescriptor,
665 load_bits: KeyEntryLoadBits,
666 caller_uid: u32,
667 check_permission: impl FnOnce(&KeyDescriptor, Option<KeyPermSet>) -> Result<()>,
Janis Danisevskisaec14592020-11-12 09:41:49 -0800668 ) -> Result<(KeyIdGuard, KeyEntry)> {
669 // KEY ID LOCK 1/2
670 // If we got a key descriptor with a key id we can get the lock right away.
671 // Otherwise we have to defer it until we know the key id.
672 let key_id_guard = match key.domain {
673 Domain::KEY_ID => Some(KEY_ID_LOCK.get(key.nspace)),
674 _ => None,
675 };
676
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700677 let tx = self
678 .conn
Janis Danisevskisaec14592020-11-12 09:41:49 -0800679 .unchecked_transaction()
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700680 .context("In load_key_entry: Failed to initialize transaction.")?;
681
682 // Load the key_id and complete the access control tuple.
683 let (key_id, access_key_descriptor, access_vector) =
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700684 Self::load_access_tuple(&tx, key, caller_uid).context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700685
686 // Perform access control. It is vital that we return here if the permission is denied.
687 // So do not touch that '?' at the end.
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700688 check_permission(&access_key_descriptor, access_vector).context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700689
Janis Danisevskisaec14592020-11-12 09:41:49 -0800690 // KEY ID LOCK 2/2
691 // If we did not get a key id lock by now, it was because we got a key descriptor
692 // without a key id. At this point we got the key id, so we can try and get a lock.
693 // However, we cannot block here, because we are in the middle of the transaction.
694 // So first we try to get the lock non blocking. If that fails, we roll back the
695 // transaction and block until we get the lock. After we successfully got the lock,
696 // we start a new transaction and load the access tuple again.
697 //
698 // We don't need to perform access control again, because we already established
699 // that the caller had access to the given key. But we need to make sure that the
700 // key id still exists. So we have to load the key entry by key id this time.
701 let (key_id_guard, tx) = match key_id_guard {
702 None => match KEY_ID_LOCK.try_get(key_id) {
703 None => {
704 // Roll back the transaction.
705 tx.rollback().context("In load_key_entry: Failed to roll back transaction.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700706
Janis Danisevskisaec14592020-11-12 09:41:49 -0800707 // Block until we have a key id lock.
708 let key_id_guard = KEY_ID_LOCK.get(key_id);
709
710 // Create a new transaction.
711 let tx = self.conn.unchecked_transaction().context(
712 "In load_key_entry: Failed to initialize transaction. (deferred key lock)",
713 )?;
714
715 Self::load_access_tuple(
716 &tx,
717 // This time we have to load the key by the retrieved key id, because the
718 // alias may have been rebound after we rolled back the transaction.
719 KeyDescriptor {
720 domain: Domain::KEY_ID,
721 nspace: key_id,
722 ..Default::default()
723 },
724 caller_uid,
725 )
726 .context("In load_key_entry. (deferred key lock)")?;
727 (key_id_guard, tx)
728 }
729 Some(l) => (l, tx),
730 },
731 Some(key_id_guard) => (key_id_guard, tx),
732 };
733
734 let (sec_level, km_blob, cert_blob, cert_chain_blob) =
735 Self::load_blob_components(key_id_guard.id(), load_bits, &tx)
736 .context("In load_key_entry.")?;
737
738 let parameters =
739 Self::load_key_parameters(key_id_guard.id(), &tx).context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700740
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700741 tx.commit().context("In load_key_entry: Failed to commit transaction.")?;
742
Janis Danisevskisaec14592020-11-12 09:41:49 -0800743 let key_id = key_id_guard.id();
744 Ok((
745 key_id_guard,
746 KeyEntry {
747 id: key_id,
748 km_blob,
749 cert: cert_blob,
750 cert_chain: cert_chain_blob,
751 sec_level,
752 parameters,
753 },
754 ))
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700755 }
756
757 /// Adds a grant to the grant table.
758 /// Like `load_key_entry` this function loads the access tuple before
759 /// it uses the callback for a permission check. Upon success,
760 /// it inserts the `grantee_uid`, `key_id`, and `access_vector` into the
761 /// grant table. The new row will have a randomized id, which is used as
762 /// grant id in the namespace field of the resulting KeyDescriptor.
763 pub fn grant(
764 &mut self,
765 key: KeyDescriptor,
766 caller_uid: u32,
767 grantee_uid: u32,
768 access_vector: KeyPermSet,
769 check_permission: impl FnOnce(&KeyDescriptor, &KeyPermSet) -> Result<()>,
770 ) -> Result<KeyDescriptor> {
771 let tx = self
772 .conn
773 .transaction_with_behavior(TransactionBehavior::Immediate)
774 .context("In grant: Failed to initialize transaction.")?;
775
776 // Load the key_id and complete the access control tuple.
777 // We ignore the access vector here because grants cannot be granted.
778 // The access vector returned here expresses the permissions the
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700779 // grantee has if key.domain == Domain::GRANT. But this vector
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700780 // cannot include the grant permission by design, so there is no way the
781 // subsequent permission check can pass.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700782 // We could check key.domain == Domain::GRANT and fail early.
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700783 // But even if we load the access tuple by grant here, the permission
784 // check denies the attempt to create a grant by grant descriptor.
785 let (key_id, access_key_descriptor, _) =
786 Self::load_access_tuple(&tx, key, caller_uid).context("In grant")?;
787
788 // Perform access control. It is vital that we return here if the permission
789 // was denied. So do not touch that '?' at the end of the line.
790 // This permission check checks if the caller has the grant permission
791 // for the given key and in addition to all of the permissions
792 // expressed in `access_vector`.
793 check_permission(&access_key_descriptor, &access_vector)
794 .context("In grant: check_permission failed.")?;
795
796 let grant_id = if let Some(grant_id) = tx
797 .query_row(
798 "SELECT id FROM perboot.grant
799 WHERE keyentryid = ? AND grantee = ?;",
800 params![key_id, grantee_uid],
801 |row| row.get(0),
802 )
803 .optional()
804 .context("In grant: Failed get optional existing grant id.")?
805 {
806 tx.execute(
807 "UPDATE perboot.grant
808 SET access_vector = ?
809 WHERE id = ?;",
810 params![i32::from(access_vector), grant_id],
811 )
812 .context("In grant: Failed to update existing grant.")?;
813 grant_id
814 } else {
Joel Galenson845f74b2020-09-09 14:11:55 -0700815 Self::insert_with_retry(|id| {
816 tx.execute(
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700817 "INSERT INTO perboot.grant (id, grantee, keyentryid, access_vector)
818 VALUES (?, ?, ?, ?);",
Joel Galenson845f74b2020-09-09 14:11:55 -0700819 params![id, grantee_uid, key_id, i32::from(access_vector)],
820 )
821 })
822 .context("In grant")?
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700823 };
824 tx.commit().context("In grant: failed to commit transaction.")?;
825
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700826 Ok(KeyDescriptor { domain: Domain::GRANT, nspace: grant_id, alias: None, blob: None })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700827 }
828
829 /// This function checks permissions like `grant` and `load_key_entry`
830 /// before removing a grant from the grant table.
831 pub fn ungrant(
832 &mut self,
833 key: KeyDescriptor,
834 caller_uid: u32,
835 grantee_uid: u32,
836 check_permission: impl FnOnce(&KeyDescriptor) -> Result<()>,
837 ) -> Result<()> {
838 let tx = self
839 .conn
840 .transaction_with_behavior(TransactionBehavior::Immediate)
841 .context("In ungrant: Failed to initialize transaction.")?;
842
843 // Load the key_id and complete the access control tuple.
844 // We ignore the access vector here because grants cannot be granted.
845 let (key_id, access_key_descriptor, _) =
846 Self::load_access_tuple(&tx, key, caller_uid).context("In ungrant.")?;
847
848 // Perform access control. We must return here if the permission
849 // was denied. So do not touch the '?' at the end of this line.
850 check_permission(&access_key_descriptor).context("In grant: check_permission failed.")?;
851
852 tx.execute(
853 "DELETE FROM perboot.grant
854 WHERE keyentryid = ? AND grantee = ?;",
855 params![key_id, grantee_uid],
856 )
857 .context("Failed to delete grant.")?;
858
859 tx.commit().context("In ungrant: failed to commit transaction.")?;
860
861 Ok(())
862 }
863
Joel Galenson845f74b2020-09-09 14:11:55 -0700864 // Generates a random id and passes it to the given function, which will
865 // try to insert it into a database. If that insertion fails, retry;
866 // otherwise return the id.
867 fn insert_with_retry(inserter: impl Fn(i64) -> rusqlite::Result<usize>) -> Result<i64> {
868 loop {
869 let newid: i64 = random();
870 match inserter(newid) {
871 // If the id already existed, try again.
872 Err(rusqlite::Error::SqliteFailure(
873 libsqlite3_sys::Error {
874 code: libsqlite3_sys::ErrorCode::ConstraintViolation,
875 extended_code: libsqlite3_sys::SQLITE_CONSTRAINT_UNIQUE,
876 },
877 _,
878 )) => (),
879 Err(e) => {
880 return Err(e).context("In insert_with_retry: failed to insert into database.")
881 }
882 _ => return Ok(newid),
883 }
884 }
885 }
886
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700887 // Takes Rows as returned by a query call on prepared statement.
888 // Extracts exactly one row with the `row_extractor` and fails if more
889 // rows are available.
890 // If no row was found, `None` is passed to the `row_extractor`.
891 // This allows the row extractor to decide on an error condition or
892 // a different default behavior.
893 fn with_rows_extract_one<'a, T, F>(rows: &mut Rows<'a>, row_extractor: F) -> Result<T>
894 where
895 F: FnOnce(Option<&Row<'a>>) -> Result<T>,
896 {
897 let result =
898 row_extractor(rows.next().context("with_rows_extract_one: Failed to unpack row.")?);
899
900 rows.next()
901 .context("In with_rows_extract_one: Failed to unpack unexpected row.")?
902 .map_or_else(|| Ok(()), |_| Err(KsError::sys()))
903 .context("In with_rows_extract_one: Unexpected row.")?;
904
905 result
906 }
907
908 fn with_rows_extract_all<'a, F>(rows: &mut Rows<'a>, mut row_extractor: F) -> Result<()>
909 where
910 F: FnMut(&Row<'a>) -> Result<()>,
911 {
912 loop {
913 match rows.next().context("In with_rows_extract_all: Failed to unpack row")? {
914 Some(row) => {
915 row_extractor(&row).context("In with_rows_extract_all.")?;
916 }
917 None => break Ok(()),
918 }
919 }
Joel Galenson33c04ad2020-08-03 11:04:38 -0700920 }
Joel Galenson26f4d012020-07-17 14:57:21 -0700921}
922
923#[cfg(test)]
924mod tests {
925
926 use super::*;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700927 use crate::key_parameter::{
928 Algorithm, BlockMode, Digest, EcCurve, HardwareAuthenticatorType, KeyOrigin, KeyParameter,
929 KeyParameterValue, KeyPurpose, PaddingMode, SecurityLevel,
930 };
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700931 use crate::key_perm_set;
932 use crate::permission::{KeyPerm, KeyPermSet};
933 use rusqlite::NO_PARAMS;
Joel Galenson0891bc12020-07-20 10:37:03 -0700934 use std::cell::RefCell;
Janis Danisevskisaec14592020-11-12 09:41:49 -0800935 use std::sync::atomic::{AtomicU8, Ordering};
936 use std::sync::Arc;
937 use std::thread;
Joel Galenson0891bc12020-07-20 10:37:03 -0700938
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700939 static PERSISTENT_TEST_SQL: &str = "/data/local/tmp/persistent.sqlite";
940 static PERBOOT_TEST_SQL: &str = "/data/local/tmp/perboot.sqlite";
941
942 fn new_test_db() -> Result<KeystoreDB> {
943 let conn = KeystoreDB::make_connection("file::memory:", "file::memory:")?;
944
945 KeystoreDB::init_tables(&conn).context("Failed to initialize tables.")?;
946 Ok(KeystoreDB { conn })
947 }
948
949 fn new_test_db_with_persistent_file() -> Result<KeystoreDB> {
950 let conn = KeystoreDB::make_connection(PERSISTENT_TEST_SQL, PERBOOT_TEST_SQL)?;
951
952 KeystoreDB::init_tables(&conn).context("Failed to initialize tables.")?;
953 Ok(KeystoreDB { conn })
954 }
955
Joel Galenson0891bc12020-07-20 10:37:03 -0700956 // Ensure that we're using the "injected" random function, not the real one.
957 #[test]
958 fn test_mocked_random() {
959 let rand1 = random();
960 let rand2 = random();
961 let rand3 = random();
962 if rand1 == rand2 {
963 assert_eq!(rand2 + 1, rand3);
964 } else {
965 assert_eq!(rand1 + 1, rand2);
966 assert_eq!(rand2, rand3);
967 }
968 }
Joel Galenson26f4d012020-07-17 14:57:21 -0700969
Joel Galenson26f4d012020-07-17 14:57:21 -0700970 // Test that we have the correct tables.
971 #[test]
972 fn test_tables() -> Result<()> {
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700973 let db = new_test_db()?;
Joel Galenson26f4d012020-07-17 14:57:21 -0700974 let tables = db
975 .conn
Joel Galenson2aab4432020-07-22 15:27:57 -0700976 .prepare("SELECT name from persistent.sqlite_master WHERE type='table' ORDER BY name;")?
Joel Galenson26f4d012020-07-17 14:57:21 -0700977 .query_map(params![], |row| row.get(0))?
978 .collect::<rusqlite::Result<Vec<String>>>()?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700979 assert_eq!(tables.len(), 3);
980 assert_eq!(tables[0], "blobentry");
981 assert_eq!(tables[1], "keyentry");
982 assert_eq!(tables[2], "keyparameter");
983 let tables = db
984 .conn
985 .prepare("SELECT name from perboot.sqlite_master WHERE type='table' ORDER BY name;")?
986 .query_map(params![], |row| row.get(0))?
987 .collect::<rusqlite::Result<Vec<String>>>()?;
988 assert_eq!(tables.len(), 1);
989 assert_eq!(tables[0], "grant");
Joel Galenson26f4d012020-07-17 14:57:21 -0700990 Ok(())
991 }
Joel Galenson0891bc12020-07-20 10:37:03 -0700992
993 #[test]
Joel Galenson2aab4432020-07-22 15:27:57 -0700994 fn test_no_persistence_for_tests() -> Result<()> {
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700995 let db = new_test_db()?;
Joel Galenson2aab4432020-07-22 15:27:57 -0700996
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700997 db.create_key_entry(Domain::APP, 100)?;
Joel Galenson2aab4432020-07-22 15:27:57 -0700998 let entries = get_keyentry(&db)?;
999 assert_eq!(entries.len(), 1);
Janis Danisevskis4df44f42020-08-26 14:40:03 -07001000 let db = new_test_db()?;
Joel Galenson2aab4432020-07-22 15:27:57 -07001001
1002 let entries = get_keyentry(&db)?;
1003 assert_eq!(entries.len(), 0);
1004 Ok(())
1005 }
1006
1007 #[test]
1008 fn test_persistence_for_files() -> Result<()> {
Janis Danisevskis4df44f42020-08-26 14:40:03 -07001009 let _file_guard_persistent = TempFile { filename: PERSISTENT_TEST_SQL };
1010 let _file_guard_perboot = TempFile { filename: PERBOOT_TEST_SQL };
1011 let db = new_test_db_with_persistent_file()?;
Joel Galenson2aab4432020-07-22 15:27:57 -07001012
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001013 db.create_key_entry(Domain::APP, 100)?;
Joel Galenson2aab4432020-07-22 15:27:57 -07001014 let entries = get_keyentry(&db)?;
1015 assert_eq!(entries.len(), 1);
Janis Danisevskis4df44f42020-08-26 14:40:03 -07001016 let db = new_test_db_with_persistent_file()?;
Joel Galenson2aab4432020-07-22 15:27:57 -07001017
1018 let entries_new = get_keyentry(&db)?;
1019 assert_eq!(entries, entries_new);
1020 Ok(())
1021 }
1022
1023 #[test]
Joel Galenson0891bc12020-07-20 10:37:03 -07001024 fn test_create_key_entry() -> Result<()> {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001025 fn extractor(ke: &KeyEntryRow) -> (Domain, i64, Option<&str>) {
Joel Galenson0891bc12020-07-20 10:37:03 -07001026 (ke.domain.unwrap(), ke.namespace.unwrap(), ke.alias.as_deref())
1027 }
1028
Janis Danisevskis4df44f42020-08-26 14:40:03 -07001029 let db = new_test_db()?;
Joel Galenson0891bc12020-07-20 10:37:03 -07001030
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001031 db.create_key_entry(Domain::APP, 100)?;
1032 db.create_key_entry(Domain::SELINUX, 101)?;
Joel Galenson0891bc12020-07-20 10:37:03 -07001033
1034 let entries = get_keyentry(&db)?;
1035 assert_eq!(entries.len(), 2);
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001036 assert_eq!(extractor(&entries[0]), (Domain::APP, 100, None));
1037 assert_eq!(extractor(&entries[1]), (Domain::SELINUX, 101, None));
Joel Galenson0891bc12020-07-20 10:37:03 -07001038
1039 // Test that we must pass in a valid Domain.
1040 check_result_is_error_containing_string(
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001041 db.create_key_entry(Domain::GRANT, 102),
1042 "Domain Domain(1) must be either App or SELinux.",
Joel Galenson0891bc12020-07-20 10:37:03 -07001043 );
1044 check_result_is_error_containing_string(
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001045 db.create_key_entry(Domain::BLOB, 103),
1046 "Domain Domain(3) must be either App or SELinux.",
Joel Galenson0891bc12020-07-20 10:37:03 -07001047 );
1048 check_result_is_error_containing_string(
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001049 db.create_key_entry(Domain::KEY_ID, 104),
1050 "Domain Domain(4) must be either App or SELinux.",
Joel Galenson0891bc12020-07-20 10:37:03 -07001051 );
1052
1053 Ok(())
1054 }
1055
Joel Galenson33c04ad2020-08-03 11:04:38 -07001056 #[test]
1057 fn test_rebind_alias() -> Result<()> {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001058 fn extractor(ke: &KeyEntryRow) -> (Option<Domain>, Option<i64>, Option<&str>) {
Joel Galenson33c04ad2020-08-03 11:04:38 -07001059 (ke.domain, ke.namespace, ke.alias.as_deref())
1060 }
1061
Janis Danisevskis4df44f42020-08-26 14:40:03 -07001062 let mut db = new_test_db()?;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001063 db.create_key_entry(Domain::APP, 42)?;
1064 db.create_key_entry(Domain::APP, 42)?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07001065 let entries = get_keyentry(&db)?;
1066 assert_eq!(entries.len(), 2);
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001067 assert_eq!(extractor(&entries[0]), (Some(Domain::APP), Some(42), None));
1068 assert_eq!(extractor(&entries[1]), (Some(Domain::APP), Some(42), None));
Joel Galenson33c04ad2020-08-03 11:04:38 -07001069
1070 // Test that the first call to rebind_alias sets the alias.
Janis Danisevskisaec14592020-11-12 09:41:49 -08001071 db.rebind_alias(&KEY_ID_LOCK.get(entries[0].id), "foo", Domain::APP, 42)?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07001072 let entries = get_keyentry(&db)?;
1073 assert_eq!(entries.len(), 2);
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001074 assert_eq!(extractor(&entries[0]), (Some(Domain::APP), Some(42), Some("foo")));
1075 assert_eq!(extractor(&entries[1]), (Some(Domain::APP), Some(42), None));
Joel Galenson33c04ad2020-08-03 11:04:38 -07001076
1077 // Test that the second call to rebind_alias also empties the old one.
Janis Danisevskisaec14592020-11-12 09:41:49 -08001078 db.rebind_alias(&KEY_ID_LOCK.get(entries[1].id), "foo", Domain::APP, 42)?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07001079 let entries = get_keyentry(&db)?;
1080 assert_eq!(entries.len(), 2);
Joel Galenson7fa5c412020-11-19 10:56:54 -08001081 assert_eq!(extractor(&entries[0]), (None, None, None));
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001082 assert_eq!(extractor(&entries[1]), (Some(Domain::APP), Some(42), Some("foo")));
Joel Galenson33c04ad2020-08-03 11:04:38 -07001083
1084 // Test that we must pass in a valid Domain.
1085 check_result_is_error_containing_string(
Janis Danisevskisaec14592020-11-12 09:41:49 -08001086 db.rebind_alias(&KEY_ID_LOCK.get(0), "foo", Domain::GRANT, 42),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001087 "Domain Domain(1) must be either App or SELinux.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07001088 );
1089 check_result_is_error_containing_string(
Janis Danisevskisaec14592020-11-12 09:41:49 -08001090 db.rebind_alias(&KEY_ID_LOCK.get(0), "foo", Domain::BLOB, 42),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001091 "Domain Domain(3) must be either App or SELinux.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07001092 );
1093 check_result_is_error_containing_string(
Janis Danisevskisaec14592020-11-12 09:41:49 -08001094 db.rebind_alias(&KEY_ID_LOCK.get(0), "foo", Domain::KEY_ID, 42),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001095 "Domain Domain(4) must be either App or SELinux.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07001096 );
1097
1098 // Test that we correctly handle setting an alias for something that does not exist.
1099 check_result_is_error_containing_string(
Janis Danisevskisaec14592020-11-12 09:41:49 -08001100 db.rebind_alias(&KEY_ID_LOCK.get(0), "foo", Domain::SELINUX, 42),
Joel Galenson33c04ad2020-08-03 11:04:38 -07001101 "Expected to update a single entry but instead updated 0",
1102 );
1103 // Test that we correctly abort the transaction in this case.
1104 let entries = get_keyentry(&db)?;
1105 assert_eq!(entries.len(), 2);
Joel Galenson7fa5c412020-11-19 10:56:54 -08001106 assert_eq!(extractor(&entries[0]), (None, None, None));
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001107 assert_eq!(extractor(&entries[1]), (Some(Domain::APP), Some(42), Some("foo")));
Joel Galenson33c04ad2020-08-03 11:04:38 -07001108
1109 Ok(())
1110 }
1111
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001112 #[test]
1113 fn test_grant_ungrant() -> Result<()> {
1114 const CALLER_UID: u32 = 15;
1115 const GRANTEE_UID: u32 = 12;
1116 const SELINUX_NAMESPACE: i64 = 7;
1117
1118 let mut db = new_test_db()?;
1119 db.conn.execute(
1120 "INSERT INTO persistent.keyentry (id, creation_date, domain, namespace, alias)
1121 VALUES (1, '1980', 0, 15, 'key'), (2, '1980', 2, 7, 'yek');",
1122 NO_PARAMS,
1123 )?;
1124 let app_key = KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001125 domain: super::Domain::APP,
1126 nspace: 0,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001127 alias: Some("key".to_string()),
1128 blob: None,
1129 };
1130 const PVEC1: KeyPermSet = key_perm_set![KeyPerm::use_(), KeyPerm::get_info()];
1131 const PVEC2: KeyPermSet = key_perm_set![KeyPerm::use_()];
1132
1133 // Reset totally predictable random number generator in case we
1134 // are not the first test running on this thread.
1135 reset_random();
1136 let next_random = 0i64;
1137
1138 let app_granted_key =
1139 db.grant(app_key.clone(), CALLER_UID, GRANTEE_UID, PVEC1, |k, a| {
1140 assert_eq!(*a, PVEC1);
1141 assert_eq!(
1142 *k,
1143 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001144 domain: super::Domain::APP,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001145 // namespace must be set to the caller_uid.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001146 nspace: CALLER_UID as i64,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001147 alias: Some("key".to_string()),
1148 blob: None,
1149 }
1150 );
1151 Ok(())
1152 })?;
1153
1154 assert_eq!(
1155 app_granted_key,
1156 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001157 domain: super::Domain::GRANT,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001158 // The grantid is next_random due to the mock random number generator.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001159 nspace: next_random,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001160 alias: None,
1161 blob: None,
1162 }
1163 );
1164
1165 let selinux_key = KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001166 domain: super::Domain::SELINUX,
1167 nspace: SELINUX_NAMESPACE,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001168 alias: Some("yek".to_string()),
1169 blob: None,
1170 };
1171
1172 let selinux_granted_key =
1173 db.grant(selinux_key.clone(), CALLER_UID, 12, PVEC1, |k, a| {
1174 assert_eq!(*a, PVEC1);
1175 assert_eq!(
1176 *k,
1177 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001178 domain: super::Domain::SELINUX,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001179 // namespace must be the supplied SELinux
1180 // namespace.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001181 nspace: SELINUX_NAMESPACE,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001182 alias: Some("yek".to_string()),
1183 blob: None,
1184 }
1185 );
1186 Ok(())
1187 })?;
1188
1189 assert_eq!(
1190 selinux_granted_key,
1191 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001192 domain: super::Domain::GRANT,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001193 // The grantid is next_random + 1 due to the mock random number generator.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001194 nspace: next_random + 1,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001195 alias: None,
1196 blob: None,
1197 }
1198 );
1199
1200 // This should update the existing grant with PVEC2.
1201 let selinux_granted_key =
1202 db.grant(selinux_key.clone(), CALLER_UID, 12, PVEC2, |k, a| {
1203 assert_eq!(*a, PVEC2);
1204 assert_eq!(
1205 *k,
1206 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001207 domain: super::Domain::SELINUX,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001208 // namespace must be the supplied SELinux
1209 // namespace.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001210 nspace: SELINUX_NAMESPACE,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001211 alias: Some("yek".to_string()),
1212 blob: None,
1213 }
1214 );
1215 Ok(())
1216 })?;
1217
1218 assert_eq!(
1219 selinux_granted_key,
1220 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001221 domain: super::Domain::GRANT,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001222 // Same grant id as before. The entry was only updated.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001223 nspace: next_random + 1,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001224 alias: None,
1225 blob: None,
1226 }
1227 );
1228
1229 {
1230 // Limiting scope of stmt, because it borrows db.
1231 let mut stmt = db
1232 .conn
1233 .prepare("SELECT id, grantee, keyentryid, access_vector FROM perboot.grant;")?;
Janis Danisevskisee10b5f2020-09-22 16:42:35 -07001234 let mut rows =
1235 stmt.query_map::<(i64, u32, i64, KeyPermSet), _, _>(NO_PARAMS, |row| {
1236 Ok((
1237 row.get(0)?,
1238 row.get(1)?,
1239 row.get(2)?,
1240 KeyPermSet::from(row.get::<_, i32>(3)?),
1241 ))
1242 })?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001243
1244 let r = rows.next().unwrap().unwrap();
Janis Danisevskisee10b5f2020-09-22 16:42:35 -07001245 assert_eq!(r, (next_random, GRANTEE_UID, 1, PVEC1));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001246 let r = rows.next().unwrap().unwrap();
Janis Danisevskisee10b5f2020-09-22 16:42:35 -07001247 assert_eq!(r, (next_random + 1, GRANTEE_UID, 2, PVEC2));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001248 assert!(rows.next().is_none());
1249 }
1250
1251 debug_dump_keyentry_table(&mut db)?;
1252 println!("app_key {:?}", app_key);
1253 println!("selinux_key {:?}", selinux_key);
1254
1255 db.ungrant(app_key, CALLER_UID, GRANTEE_UID, |_| Ok(()))?;
1256 db.ungrant(selinux_key, CALLER_UID, GRANTEE_UID, |_| Ok(()))?;
1257
1258 Ok(())
1259 }
1260
1261 static TEST_KM_BLOB: &[u8] = b"my test blob";
1262 static TEST_CERT_BLOB: &[u8] = b"my test cert";
1263 static TEST_CERT_CHAIN_BLOB: &[u8] = b"my test cert_chain";
1264
1265 #[test]
1266 fn test_insert_blob() -> Result<()> {
1267 let mut db = new_test_db()?;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001268 db.insert_blob(
Janis Danisevskisaec14592020-11-12 09:41:49 -08001269 &KEY_ID_LOCK.get(1),
1270 SubComponentType::KM_BLOB,
1271 TEST_KM_BLOB,
1272 SecurityLevel::SOFTWARE,
1273 )?;
1274 db.insert_blob(
1275 &KEY_ID_LOCK.get(1),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001276 SubComponentType::CERT,
1277 TEST_CERT_BLOB,
1278 SecurityLevel::TRUSTED_ENVIRONMENT,
1279 )?;
1280 db.insert_blob(
Janis Danisevskisaec14592020-11-12 09:41:49 -08001281 &KEY_ID_LOCK.get(1),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001282 SubComponentType::CERT_CHAIN,
1283 TEST_CERT_CHAIN_BLOB,
1284 SecurityLevel::STRONGBOX,
1285 )?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001286
1287 let mut stmt = db.conn.prepare(
1288 "SELECT subcomponent_type, keyentryid, blob, sec_level FROM persistent.blobentry
1289 ORDER BY sec_level ASC;",
1290 )?;
1291 let mut rows = stmt
1292 .query_map::<(SubComponentType, i64, Vec<u8>, i64), _, _>(NO_PARAMS, |row| {
1293 Ok((row.get(0)?, row.get(1)?, row.get(2)?, row.get(3)?))
1294 })?;
1295 let r = rows.next().unwrap().unwrap();
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001296 assert_eq!(r, (SubComponentType::KM_BLOB, 1, TEST_KM_BLOB.to_vec(), 0));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001297 let r = rows.next().unwrap().unwrap();
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001298 assert_eq!(r, (SubComponentType::CERT, 1, TEST_CERT_BLOB.to_vec(), 1));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001299 let r = rows.next().unwrap().unwrap();
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001300 assert_eq!(r, (SubComponentType::CERT_CHAIN, 1, TEST_CERT_CHAIN_BLOB.to_vec(), 2));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001301
1302 Ok(())
1303 }
1304
1305 static TEST_ALIAS: &str = "my super duper key";
1306
1307 #[test]
1308 fn test_insert_and_load_full_keyentry_domain_app() -> Result<()> {
1309 let mut db = new_test_db()?;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001310 let key_id = make_test_key_entry(&mut db, Domain::APP, 1, TEST_ALIAS)
Janis Danisevskisaec14592020-11-12 09:41:49 -08001311 .context("test_insert_and_load_full_keyentry_domain_app")?
1312 .0;
1313 let (_key_guard, key_entry) = db.load_key_entry(
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001314 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001315 domain: Domain::APP,
1316 nspace: 0,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001317 alias: Some(TEST_ALIAS.to_string()),
1318 blob: None,
1319 },
1320 KeyEntryLoadBits::BOTH,
1321 1,
1322 |_k, _av| Ok(()),
1323 )?;
1324 assert_eq!(
1325 key_entry,
1326 KeyEntry {
1327 id: key_id,
1328 km_blob: Some(TEST_KM_BLOB.to_vec()),
1329 cert: Some(TEST_CERT_BLOB.to_vec()),
1330 cert_chain: Some(TEST_CERT_CHAIN_BLOB.to_vec()),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001331 sec_level: SecurityLevel::TRUSTED_ENVIRONMENT,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001332 parameters: make_test_params(),
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001333 }
1334 );
1335 Ok(())
1336 }
1337
1338 #[test]
1339 fn test_insert_and_load_full_keyentry_domain_selinux() -> Result<()> {
1340 let mut db = new_test_db()?;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001341 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS)
Janis Danisevskisaec14592020-11-12 09:41:49 -08001342 .context("test_insert_and_load_full_keyentry_domain_selinux")?
1343 .0;
1344 let (_key_guard, key_entry) = db.load_key_entry(
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001345 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001346 domain: Domain::SELINUX,
1347 nspace: 1,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001348 alias: Some(TEST_ALIAS.to_string()),
1349 blob: None,
1350 },
1351 KeyEntryLoadBits::BOTH,
1352 1,
1353 |_k, _av| Ok(()),
1354 )?;
1355 assert_eq!(
1356 key_entry,
1357 KeyEntry {
1358 id: key_id,
1359 km_blob: Some(TEST_KM_BLOB.to_vec()),
1360 cert: Some(TEST_CERT_BLOB.to_vec()),
1361 cert_chain: Some(TEST_CERT_CHAIN_BLOB.to_vec()),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001362 sec_level: SecurityLevel::TRUSTED_ENVIRONMENT,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001363 parameters: make_test_params(),
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001364 }
1365 );
1366 Ok(())
1367 }
1368
1369 #[test]
1370 fn test_insert_and_load_full_keyentry_domain_key_id() -> Result<()> {
1371 let mut db = new_test_db()?;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001372 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS)
Janis Danisevskisaec14592020-11-12 09:41:49 -08001373 .context("test_insert_and_load_full_keyentry_domain_key_id")?
1374 .0;
1375 let (_key_guard, key_entry) = db.load_key_entry(
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001376 KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001377 KeyEntryLoadBits::BOTH,
1378 1,
1379 |_k, _av| Ok(()),
1380 )?;
1381 assert_eq!(
1382 key_entry,
1383 KeyEntry {
1384 id: key_id,
1385 km_blob: Some(TEST_KM_BLOB.to_vec()),
1386 cert: Some(TEST_CERT_BLOB.to_vec()),
1387 cert_chain: Some(TEST_CERT_CHAIN_BLOB.to_vec()),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001388 sec_level: SecurityLevel::TRUSTED_ENVIRONMENT,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001389 parameters: make_test_params(),
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001390 }
1391 );
1392
1393 Ok(())
1394 }
1395
1396 #[test]
1397 fn test_insert_and_load_full_keyentry_from_grant() -> Result<()> {
1398 let mut db = new_test_db()?;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001399 let key_id = make_test_key_entry(&mut db, Domain::APP, 1, TEST_ALIAS)
Janis Danisevskisaec14592020-11-12 09:41:49 -08001400 .context("test_insert_and_load_full_keyentry_from_grant")?
1401 .0;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001402
1403 let granted_key = db.grant(
1404 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001405 domain: Domain::APP,
1406 nspace: 0,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001407 alias: Some(TEST_ALIAS.to_string()),
1408 blob: None,
1409 },
1410 1,
1411 2,
1412 key_perm_set![KeyPerm::use_()],
1413 |_k, _av| Ok(()),
1414 )?;
1415
1416 debug_dump_grant_table(&mut db)?;
1417
Janis Danisevskisaec14592020-11-12 09:41:49 -08001418 let (_key_guard, key_entry) =
1419 db.load_key_entry(granted_key, KeyEntryLoadBits::BOTH, 2, |k, av| {
1420 assert_eq!(Domain::GRANT, k.domain);
1421 assert!(av.unwrap().includes(KeyPerm::use_()));
1422 Ok(())
1423 })?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001424
1425 assert_eq!(
1426 key_entry,
1427 KeyEntry {
1428 id: key_id,
1429 km_blob: Some(TEST_KM_BLOB.to_vec()),
1430 cert: Some(TEST_CERT_BLOB.to_vec()),
1431 cert_chain: Some(TEST_CERT_CHAIN_BLOB.to_vec()),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001432 sec_level: SecurityLevel::TRUSTED_ENVIRONMENT,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001433 parameters: make_test_params(),
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001434 }
1435 );
1436 Ok(())
1437 }
1438
Janis Danisevskisaec14592020-11-12 09:41:49 -08001439 static KEY_LOCK_TEST_ALIAS: &str = "my super duper locked key";
1440
1441 static KEY_LOCK_TEST_SQL: &str = "/data/local/tmp/persistent_key_lock.sqlite";
1442 static KEY_LOCK_PERBOOT_TEST_SQL: &str = "/data/local/tmp/perboot_key_lock.sqlite";
1443
1444 fn new_test_db_with_persistent_file_key_lock() -> Result<KeystoreDB> {
1445 let conn = KeystoreDB::make_connection(KEY_LOCK_TEST_SQL, KEY_LOCK_PERBOOT_TEST_SQL)?;
1446
1447 KeystoreDB::init_tables(&conn).context("Failed to initialize tables.")?;
1448 Ok(KeystoreDB { conn })
1449 }
1450
1451 #[test]
1452 fn test_insert_and_load_full_keyentry_domain_app_concurrently() -> Result<()> {
1453 let handle = {
1454 let _file_guard_persistent = Arc::new(TempFile { filename: KEY_LOCK_TEST_SQL });
1455 let _file_guard_perboot = Arc::new(TempFile { filename: KEY_LOCK_PERBOOT_TEST_SQL });
1456 let mut db = new_test_db_with_persistent_file_key_lock()?;
1457 let key_id = make_test_key_entry(&mut db, Domain::APP, 33, KEY_LOCK_TEST_ALIAS)
1458 .context("test_insert_and_load_full_keyentry_domain_app")?
1459 .0;
1460 let (_key_guard, key_entry) = db.load_key_entry(
1461 KeyDescriptor {
1462 domain: Domain::APP,
1463 nspace: 0,
1464 alias: Some(KEY_LOCK_TEST_ALIAS.to_string()),
1465 blob: None,
1466 },
1467 KeyEntryLoadBits::BOTH,
1468 33,
1469 |_k, _av| Ok(()),
1470 )?;
1471 assert_eq!(
1472 key_entry,
1473 KeyEntry {
1474 id: key_id,
1475 km_blob: Some(TEST_KM_BLOB.to_vec()),
1476 cert: Some(TEST_CERT_BLOB.to_vec()),
1477 cert_chain: Some(TEST_CERT_CHAIN_BLOB.to_vec()),
1478 sec_level: SecurityLevel::TRUSTED_ENVIRONMENT,
1479 parameters: make_test_params(),
1480 }
1481 );
1482 let state = Arc::new(AtomicU8::new(1));
1483 let state2 = state.clone();
1484
1485 // Spawning a second thread that attempts to acquire the key id lock
1486 // for the same key as the primary thread. The primary thread then
1487 // waits, thereby forcing the secondary thread into the second stage
1488 // of acquiring the lock (see KEY ID LOCK 2/2 above).
1489 // The test succeeds if the secondary thread observes the transition
1490 // of `state` from 1 to 2, despite having a whole second to overtake
1491 // the primary thread.
1492 let handle = thread::spawn(move || {
1493 let _file_a = _file_guard_persistent;
1494 let _file_b = _file_guard_perboot;
1495 let mut db = new_test_db_with_persistent_file_key_lock().unwrap();
1496 assert!(db
1497 .load_key_entry(
1498 KeyDescriptor {
1499 domain: Domain::APP,
1500 nspace: 0,
1501 alias: Some(KEY_LOCK_TEST_ALIAS.to_string()),
1502 blob: None,
1503 },
1504 KeyEntryLoadBits::BOTH,
1505 33,
1506 |_k, _av| Ok(()),
1507 )
1508 .is_ok());
1509 // We should only see a 2 here because we can only return
1510 // from load_key_entry when the `_key_guard` expires,
1511 // which happens at the end of the scope.
1512 assert_eq!(2, state2.load(Ordering::Relaxed));
1513 });
1514
1515 thread::sleep(std::time::Duration::from_millis(1000));
1516
1517 assert_eq!(Ok(1), state.compare_exchange(1, 2, Ordering::Relaxed, Ordering::Relaxed));
1518
1519 // Return the handle from this scope so we can join with the
1520 // secondary thread after the key id lock has expired.
1521 handle
1522 // This is where the `_key_guard` goes out of scope,
1523 // which is the reason for concurrent load_key_entry on the same key
1524 // to unblock.
1525 };
1526 // Join with the secondary thread and unwrap, to propagate failing asserts to the
1527 // main test thread. We will not see failing asserts in secondary threads otherwise.
1528 handle.join().unwrap();
1529 Ok(())
1530 }
1531
Joel Galenson0891bc12020-07-20 10:37:03 -07001532 // Helpers
1533
1534 // Checks that the given result is an error containing the given string.
1535 fn check_result_is_error_containing_string<T>(result: Result<T>, target: &str) {
1536 let error_str = format!(
1537 "{:#?}",
1538 result.err().unwrap_or_else(|| panic!("Expected the error: {}", target))
1539 );
1540 assert!(
1541 error_str.contains(target),
1542 "The string \"{}\" should contain \"{}\"",
1543 error_str,
1544 target
1545 );
1546 }
1547
Joel Galenson2aab4432020-07-22 15:27:57 -07001548 #[derive(Debug, PartialEq)]
Joel Galenson0891bc12020-07-20 10:37:03 -07001549 #[allow(dead_code)]
1550 struct KeyEntryRow {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001551 id: i64,
Joel Galenson0891bc12020-07-20 10:37:03 -07001552 creation_date: String,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001553 domain: Option<Domain>,
Joel Galenson0891bc12020-07-20 10:37:03 -07001554 namespace: Option<i64>,
1555 alias: Option<String>,
1556 }
1557
1558 fn get_keyentry(db: &KeystoreDB) -> Result<Vec<KeyEntryRow>> {
1559 db.conn
Joel Galenson2aab4432020-07-22 15:27:57 -07001560 .prepare("SELECT * FROM persistent.keyentry;")?
Joel Galenson0891bc12020-07-20 10:37:03 -07001561 .query_map(NO_PARAMS, |row| {
Joel Galenson0891bc12020-07-20 10:37:03 -07001562 Ok(KeyEntryRow {
1563 id: row.get(0)?,
1564 creation_date: row.get(1)?,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001565 domain: match row.get(2)? {
1566 Some(i) => Some(Domain(i)),
1567 None => None,
1568 },
Joel Galenson0891bc12020-07-20 10:37:03 -07001569 namespace: row.get(3)?,
1570 alias: row.get(4)?,
1571 })
1572 })?
1573 .map(|r| r.context("Could not read keyentry row."))
1574 .collect::<Result<Vec<_>>>()
1575 }
1576
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001577 // Note: The parameters and SecurityLevel associations are nonsensical. This
1578 // collection is only used to check if the parameters are preserved as expected by the
1579 // database.
1580 fn make_test_params() -> Vec<KeyParameter> {
1581 vec![
1582 KeyParameter::new(KeyParameterValue::Invalid, SecurityLevel::TRUSTED_ENVIRONMENT),
1583 KeyParameter::new(
1584 KeyParameterValue::KeyPurpose(KeyPurpose::SIGN),
1585 SecurityLevel::TRUSTED_ENVIRONMENT,
1586 ),
1587 KeyParameter::new(
1588 KeyParameterValue::KeyPurpose(KeyPurpose::DECRYPT),
1589 SecurityLevel::TRUSTED_ENVIRONMENT,
1590 ),
1591 KeyParameter::new(
1592 KeyParameterValue::Algorithm(Algorithm::RSA),
1593 SecurityLevel::TRUSTED_ENVIRONMENT,
1594 ),
1595 KeyParameter::new(KeyParameterValue::KeySize(1024), SecurityLevel::TRUSTED_ENVIRONMENT),
1596 KeyParameter::new(
1597 KeyParameterValue::BlockMode(BlockMode::ECB),
1598 SecurityLevel::TRUSTED_ENVIRONMENT,
1599 ),
1600 KeyParameter::new(
1601 KeyParameterValue::BlockMode(BlockMode::GCM),
1602 SecurityLevel::TRUSTED_ENVIRONMENT,
1603 ),
1604 KeyParameter::new(KeyParameterValue::Digest(Digest::NONE), SecurityLevel::STRONGBOX),
1605 KeyParameter::new(
1606 KeyParameterValue::Digest(Digest::MD5),
1607 SecurityLevel::TRUSTED_ENVIRONMENT,
1608 ),
1609 KeyParameter::new(
1610 KeyParameterValue::Digest(Digest::SHA_2_224),
1611 SecurityLevel::TRUSTED_ENVIRONMENT,
1612 ),
1613 KeyParameter::new(
1614 KeyParameterValue::Digest(Digest::SHA_2_256),
1615 SecurityLevel::STRONGBOX,
1616 ),
1617 KeyParameter::new(
1618 KeyParameterValue::PaddingMode(PaddingMode::NONE),
1619 SecurityLevel::TRUSTED_ENVIRONMENT,
1620 ),
1621 KeyParameter::new(
1622 KeyParameterValue::PaddingMode(PaddingMode::RSA_OAEP),
1623 SecurityLevel::TRUSTED_ENVIRONMENT,
1624 ),
1625 KeyParameter::new(
1626 KeyParameterValue::PaddingMode(PaddingMode::RSA_PSS),
1627 SecurityLevel::STRONGBOX,
1628 ),
1629 KeyParameter::new(
1630 KeyParameterValue::PaddingMode(PaddingMode::RSA_PKCS1_1_5_SIGN),
1631 SecurityLevel::TRUSTED_ENVIRONMENT,
1632 ),
1633 KeyParameter::new(KeyParameterValue::CallerNonce, SecurityLevel::TRUSTED_ENVIRONMENT),
1634 KeyParameter::new(KeyParameterValue::MinMacLength(256), SecurityLevel::STRONGBOX),
1635 KeyParameter::new(
1636 KeyParameterValue::EcCurve(EcCurve::P_224),
1637 SecurityLevel::TRUSTED_ENVIRONMENT,
1638 ),
1639 KeyParameter::new(KeyParameterValue::EcCurve(EcCurve::P_256), SecurityLevel::STRONGBOX),
1640 KeyParameter::new(
1641 KeyParameterValue::EcCurve(EcCurve::P_384),
1642 SecurityLevel::TRUSTED_ENVIRONMENT,
1643 ),
1644 KeyParameter::new(
1645 KeyParameterValue::EcCurve(EcCurve::P_521),
1646 SecurityLevel::TRUSTED_ENVIRONMENT,
1647 ),
1648 KeyParameter::new(
1649 KeyParameterValue::RSAPublicExponent(3),
1650 SecurityLevel::TRUSTED_ENVIRONMENT,
1651 ),
1652 KeyParameter::new(
1653 KeyParameterValue::IncludeUniqueID,
1654 SecurityLevel::TRUSTED_ENVIRONMENT,
1655 ),
1656 KeyParameter::new(KeyParameterValue::BootLoaderOnly, SecurityLevel::STRONGBOX),
1657 KeyParameter::new(KeyParameterValue::RollbackResistance, SecurityLevel::STRONGBOX),
1658 KeyParameter::new(
1659 KeyParameterValue::ActiveDateTime(1234567890),
1660 SecurityLevel::STRONGBOX,
1661 ),
1662 KeyParameter::new(
1663 KeyParameterValue::OriginationExpireDateTime(1234567890),
1664 SecurityLevel::TRUSTED_ENVIRONMENT,
1665 ),
1666 KeyParameter::new(
1667 KeyParameterValue::UsageExpireDateTime(1234567890),
1668 SecurityLevel::TRUSTED_ENVIRONMENT,
1669 ),
1670 KeyParameter::new(
1671 KeyParameterValue::MinSecondsBetweenOps(1234567890),
1672 SecurityLevel::TRUSTED_ENVIRONMENT,
1673 ),
1674 KeyParameter::new(
1675 KeyParameterValue::MaxUsesPerBoot(1234567890),
1676 SecurityLevel::TRUSTED_ENVIRONMENT,
1677 ),
1678 KeyParameter::new(KeyParameterValue::UserID(1), SecurityLevel::STRONGBOX),
1679 KeyParameter::new(KeyParameterValue::UserSecureID(42), SecurityLevel::STRONGBOX),
1680 KeyParameter::new(
1681 KeyParameterValue::NoAuthRequired,
1682 SecurityLevel::TRUSTED_ENVIRONMENT,
1683 ),
1684 KeyParameter::new(
1685 KeyParameterValue::HardwareAuthenticatorType(HardwareAuthenticatorType::PASSWORD),
1686 SecurityLevel::TRUSTED_ENVIRONMENT,
1687 ),
1688 KeyParameter::new(KeyParameterValue::AuthTimeout(1234567890), SecurityLevel::SOFTWARE),
1689 KeyParameter::new(KeyParameterValue::AllowWhileOnBody, SecurityLevel::SOFTWARE),
1690 KeyParameter::new(
1691 KeyParameterValue::TrustedUserPresenceRequired,
1692 SecurityLevel::TRUSTED_ENVIRONMENT,
1693 ),
1694 KeyParameter::new(
1695 KeyParameterValue::TrustedConfirmationRequired,
1696 SecurityLevel::TRUSTED_ENVIRONMENT,
1697 ),
1698 KeyParameter::new(
1699 KeyParameterValue::UnlockedDeviceRequired,
1700 SecurityLevel::TRUSTED_ENVIRONMENT,
1701 ),
1702 KeyParameter::new(
1703 KeyParameterValue::ApplicationID(vec![1u8, 2u8, 3u8, 4u8]),
1704 SecurityLevel::SOFTWARE,
1705 ),
1706 KeyParameter::new(
1707 KeyParameterValue::ApplicationData(vec![4u8, 3u8, 2u8, 1u8]),
1708 SecurityLevel::SOFTWARE,
1709 ),
1710 KeyParameter::new(
1711 KeyParameterValue::CreationDateTime(12345677890),
1712 SecurityLevel::SOFTWARE,
1713 ),
1714 KeyParameter::new(
1715 KeyParameterValue::KeyOrigin(KeyOrigin::GENERATED),
1716 SecurityLevel::TRUSTED_ENVIRONMENT,
1717 ),
1718 KeyParameter::new(
1719 KeyParameterValue::RootOfTrust(vec![3u8, 2u8, 1u8, 4u8]),
1720 SecurityLevel::TRUSTED_ENVIRONMENT,
1721 ),
1722 KeyParameter::new(KeyParameterValue::OSVersion(1), SecurityLevel::TRUSTED_ENVIRONMENT),
1723 KeyParameter::new(KeyParameterValue::OSPatchLevel(2), SecurityLevel::SOFTWARE),
1724 KeyParameter::new(
1725 KeyParameterValue::UniqueID(vec![4u8, 3u8, 1u8, 2u8]),
1726 SecurityLevel::SOFTWARE,
1727 ),
1728 KeyParameter::new(
1729 KeyParameterValue::AttestationChallenge(vec![4u8, 3u8, 1u8, 2u8]),
1730 SecurityLevel::TRUSTED_ENVIRONMENT,
1731 ),
1732 KeyParameter::new(
1733 KeyParameterValue::AttestationApplicationID(vec![4u8, 3u8, 1u8, 2u8]),
1734 SecurityLevel::TRUSTED_ENVIRONMENT,
1735 ),
1736 KeyParameter::new(
1737 KeyParameterValue::AttestationIdBrand(vec![4u8, 3u8, 1u8, 2u8]),
1738 SecurityLevel::TRUSTED_ENVIRONMENT,
1739 ),
1740 KeyParameter::new(
1741 KeyParameterValue::AttestationIdDevice(vec![4u8, 3u8, 1u8, 2u8]),
1742 SecurityLevel::TRUSTED_ENVIRONMENT,
1743 ),
1744 KeyParameter::new(
1745 KeyParameterValue::AttestationIdProduct(vec![4u8, 3u8, 1u8, 2u8]),
1746 SecurityLevel::TRUSTED_ENVIRONMENT,
1747 ),
1748 KeyParameter::new(
1749 KeyParameterValue::AttestationIdSerial(vec![4u8, 3u8, 1u8, 2u8]),
1750 SecurityLevel::TRUSTED_ENVIRONMENT,
1751 ),
1752 KeyParameter::new(
1753 KeyParameterValue::AttestationIdIMEI(vec![4u8, 3u8, 1u8, 2u8]),
1754 SecurityLevel::TRUSTED_ENVIRONMENT,
1755 ),
1756 KeyParameter::new(
1757 KeyParameterValue::AttestationIdMEID(vec![4u8, 3u8, 1u8, 2u8]),
1758 SecurityLevel::TRUSTED_ENVIRONMENT,
1759 ),
1760 KeyParameter::new(
1761 KeyParameterValue::AttestationIdManufacturer(vec![4u8, 3u8, 1u8, 2u8]),
1762 SecurityLevel::TRUSTED_ENVIRONMENT,
1763 ),
1764 KeyParameter::new(
1765 KeyParameterValue::AttestationIdModel(vec![4u8, 3u8, 1u8, 2u8]),
1766 SecurityLevel::TRUSTED_ENVIRONMENT,
1767 ),
1768 KeyParameter::new(
1769 KeyParameterValue::VendorPatchLevel(3),
1770 SecurityLevel::TRUSTED_ENVIRONMENT,
1771 ),
1772 KeyParameter::new(
1773 KeyParameterValue::BootPatchLevel(4),
1774 SecurityLevel::TRUSTED_ENVIRONMENT,
1775 ),
1776 KeyParameter::new(
1777 KeyParameterValue::AssociatedData(vec![4u8, 3u8, 1u8, 2u8]),
1778 SecurityLevel::TRUSTED_ENVIRONMENT,
1779 ),
1780 KeyParameter::new(
1781 KeyParameterValue::Nonce(vec![4u8, 3u8, 1u8, 2u8]),
1782 SecurityLevel::TRUSTED_ENVIRONMENT,
1783 ),
1784 KeyParameter::new(
1785 KeyParameterValue::MacLength(256),
1786 SecurityLevel::TRUSTED_ENVIRONMENT,
1787 ),
1788 KeyParameter::new(
1789 KeyParameterValue::ResetSinceIdRotation,
1790 SecurityLevel::TRUSTED_ENVIRONMENT,
1791 ),
1792 KeyParameter::new(
1793 KeyParameterValue::ConfirmationToken(vec![5u8, 5u8, 5u8, 5u8]),
1794 SecurityLevel::TRUSTED_ENVIRONMENT,
1795 ),
1796 ]
1797 }
1798
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001799 fn make_test_key_entry(
1800 db: &mut KeystoreDB,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001801 domain: Domain,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001802 namespace: i64,
1803 alias: &str,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001804 ) -> Result<KeyIdGuard> {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001805 let key_id = db.create_key_entry(domain, namespace)?;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001806 db.insert_blob(
Janis Danisevskisaec14592020-11-12 09:41:49 -08001807 &key_id,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001808 SubComponentType::KM_BLOB,
1809 TEST_KM_BLOB,
1810 SecurityLevel::TRUSTED_ENVIRONMENT,
1811 )?;
1812 db.insert_blob(
Janis Danisevskisaec14592020-11-12 09:41:49 -08001813 &key_id,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001814 SubComponentType::CERT,
1815 TEST_CERT_BLOB,
1816 SecurityLevel::TRUSTED_ENVIRONMENT,
1817 )?;
1818 db.insert_blob(
Janis Danisevskisaec14592020-11-12 09:41:49 -08001819 &key_id,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001820 SubComponentType::CERT_CHAIN,
1821 TEST_CERT_CHAIN_BLOB,
1822 SecurityLevel::TRUSTED_ENVIRONMENT,
1823 )?;
Janis Danisevskisaec14592020-11-12 09:41:49 -08001824 db.insert_keyparameter(&key_id, &make_test_params())?;
1825 db.rebind_alias(&key_id, alias, domain, namespace)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001826 Ok(key_id)
1827 }
1828
1829 fn debug_dump_keyentry_table(db: &mut KeystoreDB) -> Result<()> {
1830 let mut stmt = db.conn.prepare(
1831 "SELECT id, creation_date, domain, namespace, alias FROM persistent.keyentry;",
1832 )?;
1833 let rows = stmt.query_map::<(i64, i64, i32, i64, String), _, _>(NO_PARAMS, |row| {
1834 Ok((row.get(0)?, row.get(1)?, row.get(2)?, row.get(3)?, row.get(4)?))
1835 })?;
1836
1837 println!("Key entry table rows:");
1838 for r in rows {
1839 let (id, cdate, domain, namespace, alias) = r.unwrap();
1840 println!(
1841 " id: {} Creation date: {} Domain: {} Namespace: {} Alias: {}",
1842 id, cdate, domain, namespace, alias
1843 );
1844 }
1845 Ok(())
1846 }
1847
1848 fn debug_dump_grant_table(db: &mut KeystoreDB) -> Result<()> {
1849 let mut stmt =
1850 db.conn.prepare("SELECT id, grantee, keyentryid, access_vector FROM perboot.grant;")?;
1851 let rows = stmt.query_map::<(i64, i64, i64, i64), _, _>(NO_PARAMS, |row| {
1852 Ok((row.get(0)?, row.get(1)?, row.get(2)?, row.get(3)?))
1853 })?;
1854
1855 println!("Grant table rows:");
1856 for r in rows {
1857 let (id, gt, ki, av) = r.unwrap();
1858 println!(" id: {} grantee: {} key_id: {} access_vector: {}", id, gt, ki, av);
1859 }
1860 Ok(())
1861 }
1862
Joel Galenson2aab4432020-07-22 15:27:57 -07001863 // A class that deletes a file when it is dropped.
1864 // TODO: If we ever add a crate that does this, we can use it instead.
1865 struct TempFile {
1866 filename: &'static str,
1867 }
1868
1869 impl Drop for TempFile {
1870 fn drop(&mut self) {
1871 std::fs::remove_file(self.filename).expect("Cannot delete temporary file");
1872 }
1873 }
1874
Joel Galenson0891bc12020-07-20 10:37:03 -07001875 // Use a custom random number generator that repeats each number once.
1876 // This allows us to test repeated elements.
1877
1878 thread_local! {
1879 static RANDOM_COUNTER: RefCell<i64> = RefCell::new(0);
1880 }
1881
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001882 fn reset_random() {
1883 RANDOM_COUNTER.with(|counter| {
1884 *counter.borrow_mut() = 0;
1885 })
1886 }
1887
Joel Galenson0891bc12020-07-20 10:37:03 -07001888 pub fn random() -> i64 {
1889 RANDOM_COUNTER.with(|counter| {
1890 let result = *counter.borrow() / 2;
1891 *counter.borrow_mut() += 1;
1892 result
1893 })
1894 }
Joel Galenson26f4d012020-07-17 14:57:21 -07001895}