blob: f9b320f85ebf1edc9f040633325dfd6854a8dd38 [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
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +000015//TODO: remove this in the future CLs in the stack.
16#![allow(dead_code)]
17
Janis Danisevskis63f7bc82020-09-03 10:12:56 -070018//! This is the Keystore 2.0 database module.
19//! The database module provides a connection to the backing SQLite store.
20//! We have two databases one for persistent key blob storage and one for
21//! items that have a per boot life cycle.
22//!
23//! ## Persistent database
24//! The persistent database has tables for key blobs. They are organized
25//! as follows:
26//! The `keyentry` table is the primary table for key entries. It is
27//! accompanied by two tables for blobs and parameters.
28//! Each key entry occupies exactly one row in the `keyentry` table and
29//! zero or more rows in the tables `blobentry` and `keyparameter`.
30//!
31//! ## Per boot database
32//! The per boot database stores items with a per boot lifecycle.
33//! Currently, there is only the `grant` table in this database.
34//! Grants are references to a key that can be used to access a key by
35//! clients that don't own that key. Grants can only be created by the
36//! owner of a key. And only certain components can create grants.
37//! This is governed by SEPolicy.
38//!
39//! ## Access control
40//! Some database functions that load keys or create grants perform
41//! access control. This is because in some cases access control
42//! can only be performed after some information about the designated
43//! key was loaded from the database. To decouple the permission checks
44//! from the database module these functions take permission check
45//! callbacks.
Joel Galenson26f4d012020-07-17 14:57:21 -070046
Janis Danisevskis4522c2b2020-11-27 18:04:58 -080047use crate::db_utils::{self, SqlField};
Janis Danisevskisc5b210b2020-09-11 13:27:37 -070048use crate::error::{Error as KsError, ResponseCode};
Janis Danisevskis4522c2b2020-11-27 18:04:58 -080049use crate::key_parameter::{KeyParameter, Tag};
Janis Danisevskisc5b210b2020-09-11 13:27:37 -070050use crate::permission::KeyPermSet;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -070051use anyhow::{anyhow, Context, Result};
Janis Danisevskis60400fe2020-08-26 15:24:42 -070052
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +000053use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
54 HardwareAuthToken::HardwareAuthToken, HardwareAuthenticatorType::HardwareAuthenticatorType,
55 SecurityLevel::SecurityLevel,
56};
Janis Danisevskisc5b210b2020-09-11 13:27:37 -070057use android_system_keystore2::aidl::android::system::keystore2::{
Janis Danisevskis04b02832020-10-26 09:21:40 -070058 Domain::Domain, KeyDescriptor::KeyDescriptor,
Janis Danisevskis60400fe2020-08-26 15:24:42 -070059};
60
Janis Danisevskisaec14592020-11-12 09:41:49 -080061use lazy_static::lazy_static;
Joel Galenson0891bc12020-07-20 10:37:03 -070062#[cfg(not(test))]
63use rand::prelude::random;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -070064use rusqlite::{
65 params, types::FromSql, types::FromSqlResult, types::ToSqlOutput, types::ValueRef, Connection,
Janis Danisevskisbf15d732020-12-08 10:35:26 -080066 OptionalExtension, ToSql, Transaction, TransactionBehavior, NO_PARAMS,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -070067};
Janis Danisevskisaec14592020-11-12 09:41:49 -080068use std::{
69 collections::HashSet,
Janis Danisevskisbf15d732020-12-08 10:35:26 -080070 path::Path,
71 sync::{Condvar, Mutex},
Janis Danisevskisaec14592020-11-12 09:41:49 -080072};
Joel Galenson0891bc12020-07-20 10:37:03 -070073#[cfg(test)]
74use tests::random;
Joel Galenson26f4d012020-07-17 14:57:21 -070075
Janis Danisevskis63f7bc82020-09-03 10:12:56 -070076/// Keys have a KeyMint blob component and optional public certificate and
77/// certificate chain components.
78/// KeyEntryLoadBits is a bitmap that indicates to `KeystoreDB::load_key_entry`
79/// which components shall be loaded from the database if present.
80#[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
81pub struct KeyEntryLoadBits(u32);
82
83impl KeyEntryLoadBits {
84 /// Indicate to `KeystoreDB::load_key_entry` that no component shall be loaded.
85 pub const NONE: KeyEntryLoadBits = Self(0);
86 /// Indicate to `KeystoreDB::load_key_entry` that the KeyMint component shall be loaded.
87 pub const KM: KeyEntryLoadBits = Self(1);
88 /// Indicate to `KeystoreDB::load_key_entry` that the Public components shall be loaded.
89 pub const PUBLIC: KeyEntryLoadBits = Self(2);
90 /// Indicate to `KeystoreDB::load_key_entry` that both components shall be loaded.
91 pub const BOTH: KeyEntryLoadBits = Self(3);
92
93 /// Returns true if this object indicates that the public components shall be loaded.
94 pub const fn load_public(&self) -> bool {
95 self.0 & Self::PUBLIC.0 != 0
96 }
97
98 /// Returns true if the object indicates that the KeyMint component shall be loaded.
99 pub const fn load_km(&self) -> bool {
100 self.0 & Self::KM.0 != 0
101 }
102}
103
Janis Danisevskisaec14592020-11-12 09:41:49 -0800104lazy_static! {
105 static ref KEY_ID_LOCK: KeyIdLockDb = KeyIdLockDb::new();
106}
107
108struct KeyIdLockDb {
109 locked_keys: Mutex<HashSet<i64>>,
110 cond_var: Condvar,
111}
112
113/// A locked key. While a guard exists for a given key id, the same key cannot be loaded
114/// from the database a second time. Most functions manipulating the key blob database
115/// require a KeyIdGuard.
116#[derive(Debug)]
117pub struct KeyIdGuard(i64);
118
119impl KeyIdLockDb {
120 fn new() -> Self {
121 Self { locked_keys: Mutex::new(HashSet::new()), cond_var: Condvar::new() }
122 }
123
124 /// This function blocks until an exclusive lock for the given key entry id can
125 /// be acquired. It returns a guard object, that represents the lifecycle of the
126 /// acquired lock.
127 pub fn get(&self, key_id: i64) -> KeyIdGuard {
128 let mut locked_keys = self.locked_keys.lock().unwrap();
129 while locked_keys.contains(&key_id) {
130 locked_keys = self.cond_var.wait(locked_keys).unwrap();
131 }
132 locked_keys.insert(key_id);
133 KeyIdGuard(key_id)
134 }
135
136 /// This function attempts to acquire an exclusive lock on a given key id. If the
137 /// given key id is already taken the function returns None immediately. If a lock
138 /// can be acquired this function returns a guard object, that represents the
139 /// lifecycle of the acquired lock.
140 pub fn try_get(&self, key_id: i64) -> Option<KeyIdGuard> {
141 let mut locked_keys = self.locked_keys.lock().unwrap();
142 if locked_keys.insert(key_id) {
143 Some(KeyIdGuard(key_id))
144 } else {
145 None
146 }
147 }
148}
149
150impl KeyIdGuard {
151 /// Get the numeric key id of the locked key.
152 pub fn id(&self) -> i64 {
153 self.0
154 }
155}
156
157impl Drop for KeyIdGuard {
158 fn drop(&mut self) {
159 let mut locked_keys = KEY_ID_LOCK.locked_keys.lock().unwrap();
160 locked_keys.remove(&self.0);
Janis Danisevskis7fd53582020-11-23 13:40:34 -0800161 drop(locked_keys);
Janis Danisevskisaec14592020-11-12 09:41:49 -0800162 KEY_ID_LOCK.cond_var.notify_all();
163 }
164}
165
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700166/// This type represents a Keystore 2.0 key entry.
167/// An entry has a unique `id` by which it can be found in the database.
168/// It has a security level field, key parameters, and three optional fields
169/// for the KeyMint blob, public certificate and a public certificate chain.
Janis Danisevskisaec14592020-11-12 09:41:49 -0800170#[derive(Debug, Default, Eq, PartialEq, Ord, PartialOrd)]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700171pub struct KeyEntry {
172 id: i64,
173 km_blob: Option<Vec<u8>>,
174 cert: Option<Vec<u8>>,
175 cert_chain: Option<Vec<u8>>,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700176 sec_level: SecurityLevel,
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700177 parameters: Vec<KeyParameter>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700178}
179
180impl KeyEntry {
181 /// Returns the unique id of the Key entry.
182 pub fn id(&self) -> i64 {
183 self.id
184 }
185 /// Exposes the optional KeyMint blob.
186 pub fn km_blob(&self) -> &Option<Vec<u8>> {
187 &self.km_blob
188 }
189 /// Extracts the Optional KeyMint blob.
190 pub fn take_km_blob(&mut self) -> Option<Vec<u8>> {
191 self.km_blob.take()
192 }
193 /// Exposes the optional public certificate.
194 pub fn cert(&self) -> &Option<Vec<u8>> {
195 &self.cert
196 }
197 /// Extracts the optional public certificate.
198 pub fn take_cert(&mut self) -> Option<Vec<u8>> {
199 self.cert.take()
200 }
201 /// Exposes the optional public certificate chain.
202 pub fn cert_chain(&self) -> &Option<Vec<u8>> {
203 &self.cert_chain
204 }
205 /// Extracts the optional public certificate_chain.
206 pub fn take_cert_chain(&mut self) -> Option<Vec<u8>> {
207 self.cert_chain.take()
208 }
209 /// Returns the security level of the key entry.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700210 pub fn sec_level(&self) -> SecurityLevel {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700211 self.sec_level
212 }
Janis Danisevskis04b02832020-10-26 09:21:40 -0700213 /// Exposes the key parameters of this key entry.
214 pub fn key_parameters(&self) -> &Vec<KeyParameter> {
215 &self.parameters
216 }
217 /// Consumes this key entry and extracts the keyparameters from it.
218 pub fn into_key_parameters(self) -> Vec<KeyParameter> {
219 self.parameters
220 }
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700221}
222
223/// Indicates the sub component of a key entry for persistent storage.
224#[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
225pub struct SubComponentType(u32);
226impl SubComponentType {
227 /// Persistent identifier for a KeyMint blob.
228 pub const KM_BLOB: SubComponentType = Self(0);
229 /// Persistent identifier for a certificate blob.
230 pub const CERT: SubComponentType = Self(1);
231 /// Persistent identifier for a certificate chain blob.
232 pub const CERT_CHAIN: SubComponentType = Self(2);
233}
234
235impl ToSql for SubComponentType {
236 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
237 self.0.to_sql()
238 }
239}
240
241impl FromSql for SubComponentType {
242 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
243 Ok(Self(u32::column_result(value)?))
244 }
245}
246
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700247/// KeystoreDB wraps a connection to an SQLite database and tracks its
248/// ownership. It also implements all of Keystore 2.0's database functionality.
Joel Galenson26f4d012020-07-17 14:57:21 -0700249pub struct KeystoreDB {
Joel Galenson26f4d012020-07-17 14:57:21 -0700250 conn: Connection,
251}
252
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000253/// This struct encapsulates the information to be stored in the database about the auth tokens
254/// received by keystore.
255pub struct AuthTokenEntry {
256 auth_token: HardwareAuthToken,
257 time_received: i32,
258}
259
260impl AuthTokenEntry {
261 fn new(auth_token: HardwareAuthToken, time_received: i32) -> Self {
262 AuthTokenEntry { auth_token, time_received }
263 }
264
265 /// Checks if this auth token satisfies the given authentication information.
266 pub fn satisfies_auth(
267 auth_token: &HardwareAuthToken,
268 user_secure_ids: &[i64],
269 auth_type: HardwareAuthenticatorType,
270 ) -> bool {
271 user_secure_ids.iter().any(|&sid| {
272 (sid == auth_token.userId || sid == auth_token.authenticatorId)
273 && (((auth_type.0 as i32) & (auth_token.authenticatorType.0 as i32)) != 0)
274 })
275 }
276
277 fn is_newer_than(&self, other: &AuthTokenEntry) -> bool {
278 // NOTE: Although in legacy keystore both timestamp and time_received are involved in this
279 // check, we decided to only consider time_received in keystore2 code.
280 self.time_received > other.time_received
281 }
282
283 /// Returns the auth token wrapped by the AuthTokenEntry
284 pub fn get_auth_token(self) -> HardwareAuthToken {
285 self.auth_token
286 }
287}
288
Joel Galenson26f4d012020-07-17 14:57:21 -0700289impl KeystoreDB {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700290 /// This will create a new database connection connecting the two
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800291 /// files persistent.sqlite and perboot.sqlite in the given directory.
292 /// It also attempts to initialize all of the tables.
293 /// KeystoreDB cannot be used by multiple threads.
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700294 /// Each thread should open their own connection using `thread_local!`.
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800295 pub fn new(db_root: &Path) -> Result<Self> {
296 // Build the path to the sqlite files.
297 let mut persistent_path = db_root.to_path_buf();
298 persistent_path.push("persistent.sqlite");
299 let mut perboot_path = db_root.to_path_buf();
300 perboot_path.push("perboot.sqlite");
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700301
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800302 // Now convert them to strings prefixed with "file:"
303 let mut persistent_path_str = "file:".to_owned();
304 persistent_path_str.push_str(&persistent_path.to_string_lossy());
305 let mut perboot_path_str = "file:".to_owned();
306 perboot_path_str.push_str(&perboot_path.to_string_lossy());
307
308 let conn = Self::make_connection(&persistent_path_str, &perboot_path_str)?;
309
310 Self::init_tables(&conn)?;
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700311 Ok(Self { conn })
Joel Galenson2aab4432020-07-22 15:27:57 -0700312 }
313
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700314 fn init_tables(conn: &Connection) -> Result<()> {
315 conn.execute(
316 "CREATE TABLE IF NOT EXISTS persistent.keyentry (
Joel Galenson0891bc12020-07-20 10:37:03 -0700317 id INTEGER UNIQUE,
318 creation_date DATETIME,
319 domain INTEGER,
320 namespace INTEGER,
Joel Galenson319bb652020-12-01 13:24:08 -0800321 alias BLOB);",
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700322 NO_PARAMS,
323 )
324 .context("Failed to initialize \"keyentry\" table.")?;
325
326 conn.execute(
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700327 "CREATE VIEW IF NOT EXISTS persistent.orphaned AS
328 SELECT id FROM persistent.keyentry WHERE domain IS NULL;",
329 NO_PARAMS,
330 )
331 .context("Failed to initialize \"orphaned\" view")?;
332
333 conn.execute(
334 "CREATE TABLE IF NOT EXISTS persistent.blobentry (
335 id INTEGER PRIMARY KEY,
336 subcomponent_type INTEGER,
337 keyentryid INTEGER,
338 blob BLOB,
339 sec_level INTEGER);",
340 NO_PARAMS,
341 )
342 .context("Failed to initialize \"blobentry\" table.")?;
343
344 conn.execute(
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700345 "CREATE TABLE IF NOT EXISTS persistent.keyparameter (
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000346 keyentryid INTEGER,
347 tag INTEGER,
348 data ANY,
349 security_level INTEGER);",
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700350 NO_PARAMS,
351 )
352 .context("Failed to initialize \"keyparameter\" table.")?;
353
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700354 conn.execute(
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800355 "CREATE TABLE IF NOT EXISTS persistent.grant (
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700356 id INTEGER UNIQUE,
357 grantee INTEGER,
358 keyentryid INTEGER,
359 access_vector INTEGER);",
360 NO_PARAMS,
361 )
362 .context("Failed to initialize \"grant\" table.")?;
363
Joel Galenson0891bc12020-07-20 10:37:03 -0700364 Ok(())
365 }
366
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700367 fn make_connection(persistent_file: &str, perboot_file: &str) -> Result<Connection> {
368 let conn =
369 Connection::open_in_memory().context("Failed to initialize SQLite connection.")?;
370
371 conn.execute("ATTACH DATABASE ? as persistent;", params![persistent_file])
372 .context("Failed to attach database persistent.")?;
373 conn.execute("ATTACH DATABASE ? as perboot;", params![perboot_file])
374 .context("Failed to attach database perboot.")?;
375
376 Ok(conn)
377 }
378
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700379 /// Creates a new key entry and allocates a new randomized id for the new key.
380 /// The key id gets associated with a domain and namespace but not with an alias.
381 /// To complete key generation `rebind_alias` should be called after all of the
382 /// key artifacts, i.e., blobs and parameters have been associated with the new
383 /// key id. Finalizing with `rebind_alias` makes the creation of a new key entry
384 /// atomic even if key generation is not.
Janis Danisevskisaec14592020-11-12 09:41:49 -0800385 pub fn create_key_entry(&self, domain: Domain, namespace: i64) -> Result<KeyIdGuard> {
Joel Galenson0891bc12020-07-20 10:37:03 -0700386 match domain {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700387 Domain::APP | Domain::SELINUX => {}
Joel Galenson0891bc12020-07-20 10:37:03 -0700388 _ => {
389 return Err(KsError::sys())
390 .context(format!("Domain {:?} must be either App or SELinux.", domain));
391 }
392 }
Janis Danisevskisaec14592020-11-12 09:41:49 -0800393 Ok(KEY_ID_LOCK.get(
394 Self::insert_with_retry(|id| {
395 self.conn.execute(
396 "INSERT into persistent.keyentry (id, creation_date, domain, namespace, alias)
Joel Galenson0891bc12020-07-20 10:37:03 -0700397 VALUES(?, datetime('now'), ?, ?, NULL);",
Janis Danisevskisaec14592020-11-12 09:41:49 -0800398 params![id, domain.0 as u32, namespace],
399 )
400 })
401 .context("In create_key_entry")?,
402 ))
Joel Galenson26f4d012020-07-17 14:57:21 -0700403 }
Joel Galenson33c04ad2020-08-03 11:04:38 -0700404
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700405 /// Inserts a new blob and associates it with the given key id. Each blob
406 /// has a sub component type and a security level.
407 /// Each key can have one of each sub component type associated. If more
408 /// are added only the most recent can be retrieved, and superseded blobs
409 /// will get garbage collected. The security level field of components
410 /// other than `SubComponentType::KM_BLOB` are ignored.
411 pub fn insert_blob(
412 &mut self,
Janis Danisevskisaec14592020-11-12 09:41:49 -0800413 key_id: &KeyIdGuard,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700414 sc_type: SubComponentType,
415 blob: &[u8],
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700416 sec_level: SecurityLevel,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700417 ) -> Result<()> {
418 self.conn
419 .execute(
420 "INSERT into persistent.blobentry (subcomponent_type, keyentryid, blob, sec_level)
421 VALUES (?, ?, ?, ?);",
Janis Danisevskisaec14592020-11-12 09:41:49 -0800422 params![sc_type, key_id.0, blob, sec_level.0],
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700423 )
424 .context("Failed to insert blob.")?;
425 Ok(())
426 }
427
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700428 /// Inserts a collection of key parameters into the `persistent.keyparameter` table
429 /// and associates them with the given `key_id`.
430 pub fn insert_keyparameter<'a>(
431 &mut self,
Janis Danisevskisaec14592020-11-12 09:41:49 -0800432 key_id: &KeyIdGuard,
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700433 params: impl IntoIterator<Item = &'a KeyParameter>,
434 ) -> Result<()> {
Janis Danisevskise92a5e62020-12-02 12:57:41 -0800435 let tx = self
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700436 .conn
Janis Danisevskise92a5e62020-12-02 12:57:41 -0800437 .transaction_with_behavior(TransactionBehavior::Immediate)
438 .context("In insert_keyparameter: Failed to start transaction.")?;
439 {
440 let mut stmt = tx
441 .prepare(
442 "INSERT into persistent.keyparameter (keyentryid, tag, data, security_level)
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700443 VALUES (?, ?, ?, ?);",
Janis Danisevskise92a5e62020-12-02 12:57:41 -0800444 )
445 .context("In insert_keyparameter: Failed to prepare statement.")?;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700446
Janis Danisevskise92a5e62020-12-02 12:57:41 -0800447 let iter = params.into_iter();
448 for p in iter {
449 stmt.insert(params![
450 key_id.0,
451 p.get_tag().0,
452 p.key_parameter_value(),
453 p.security_level().0
454 ])
455 .with_context(|| format!("In insert_keyparameter: Failed to insert {:?}", p))?;
456 }
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700457 }
Janis Danisevskise92a5e62020-12-02 12:57:41 -0800458 tx.commit().context("In insert_keyparameter: Failed to commit transaction.")?;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700459 Ok(())
460 }
461
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700462 /// Updates the alias column of the given key id `newid` with the given alias,
463 /// and atomically, removes the alias, domain, and namespace from another row
464 /// with the same alias-domain-namespace tuple if such row exits.
Joel Galenson33c04ad2020-08-03 11:04:38 -0700465 pub fn rebind_alias(
466 &mut self,
Janis Danisevskisaec14592020-11-12 09:41:49 -0800467 newid: &KeyIdGuard,
Joel Galenson33c04ad2020-08-03 11:04:38 -0700468 alias: &str,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700469 domain: Domain,
Joel Galenson33c04ad2020-08-03 11:04:38 -0700470 namespace: i64,
471 ) -> Result<()> {
472 match domain {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700473 Domain::APP | Domain::SELINUX => {}
Joel Galenson33c04ad2020-08-03 11:04:38 -0700474 _ => {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700475 return Err(KsError::sys()).context(format!(
476 "In rebind_alias: Domain {:?} must be either App or SELinux.",
477 domain
478 ));
Joel Galenson33c04ad2020-08-03 11:04:38 -0700479 }
480 }
481 let tx = self
482 .conn
483 .transaction_with_behavior(TransactionBehavior::Immediate)
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700484 .context("In rebind_alias: Failed to initialize transaction.")?;
Joel Galenson33c04ad2020-08-03 11:04:38 -0700485 tx.execute(
486 "UPDATE persistent.keyentry
487 SET alias = NULL, domain = NULL, namespace = NULL
488 WHERE alias = ? AND domain = ? AND namespace = ?;",
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700489 params![alias, domain.0 as u32, namespace],
Joel Galenson33c04ad2020-08-03 11:04:38 -0700490 )
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700491 .context("In rebind_alias: Failed to rebind existing entry.")?;
Joel Galenson33c04ad2020-08-03 11:04:38 -0700492 let result = tx
493 .execute(
494 "UPDATE persistent.keyentry
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700495 SET alias = ?
496 WHERE id = ? AND domain = ? AND namespace = ?;",
Janis Danisevskisaec14592020-11-12 09:41:49 -0800497 params![alias, newid.0, domain.0 as u32, namespace],
Joel Galenson33c04ad2020-08-03 11:04:38 -0700498 )
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700499 .context("In rebind_alias: Failed to set alias.")?;
Joel Galenson33c04ad2020-08-03 11:04:38 -0700500 if result != 1 {
501 // Note that this explicit rollback is not required, as
502 // the transaction should rollback if we do not commit it.
503 // We leave it here for readability.
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700504 tx.rollback().context("In rebind_alias: Failed to rollback a failed transaction.")?;
Joel Galenson33c04ad2020-08-03 11:04:38 -0700505 return Err(KsError::sys()).context(format!(
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700506 "In rebind_alias: Expected to update a single entry but instead updated {}.",
Joel Galenson33c04ad2020-08-03 11:04:38 -0700507 result
508 ));
509 }
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700510 tx.commit().context("In rebind_alias: Failed to commit transaction.")
511 }
512
513 // Helper function loading the key_id given the key descriptor
514 // tuple comprising domain, namespace, and alias.
515 // Requires a valid transaction.
516 fn load_key_entry_id(key: &KeyDescriptor, tx: &Transaction) -> Result<i64> {
517 let alias = key
518 .alias
519 .as_ref()
520 .map_or_else(|| Err(KsError::sys()), Ok)
521 .context("In load_key_entry_id: Alias must be specified.")?;
522 let mut stmt = tx
523 .prepare(
524 "SELECT id FROM persistent.keyentry
525 WHERE
526 domain = ?
527 AND namespace = ?
528 AND alias = ?;",
529 )
530 .context("In load_key_entry_id: Failed to select from keyentry table.")?;
531 let mut rows = stmt
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700532 .query(params![key.domain.0 as u32, key.nspace, alias])
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700533 .context("In load_key_entry_id: Failed to read from keyentry table.")?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800534 db_utils::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700535 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700536 .get(0)
537 .context("Failed to unpack id.")
538 })
539 .context("In load_key_entry_id.")
540 }
541
542 /// This helper function completes the access tuple of a key, which is required
543 /// to perform access control. The strategy depends on the `domain` field in the
544 /// key descriptor.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700545 /// * Domain::SELINUX: The access tuple is complete and this function only loads
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700546 /// the key_id for further processing.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700547 /// * Domain::APP: Like Domain::SELINUX, but the tuple is completed by `caller_uid`
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700548 /// which serves as the namespace.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700549 /// * Domain::GRANT: The grant table is queried for the `key_id` and the
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700550 /// `access_vector`.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700551 /// * Domain::KEY_ID: The keyentry table is queried for the owning `domain` and
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700552 /// `namespace`.
553 /// In each case the information returned is sufficient to perform the access
554 /// check and the key id can be used to load further key artifacts.
555 fn load_access_tuple(
556 tx: &Transaction,
557 key: KeyDescriptor,
558 caller_uid: u32,
559 ) -> Result<(i64, KeyDescriptor, Option<KeyPermSet>)> {
560 match key.domain {
561 // Domain App or SELinux. In this case we load the key_id from
562 // the keyentry database for further loading of key components.
563 // We already have the full access tuple to perform access control.
564 // The only distinction is that we use the caller_uid instead
565 // of the caller supplied namespace if the domain field is
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700566 // Domain::APP.
567 Domain::APP | Domain::SELINUX => {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700568 let mut access_key = key;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700569 if access_key.domain == Domain::APP {
570 access_key.nspace = caller_uid as i64;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700571 }
572 let key_id = Self::load_key_entry_id(&access_key, &tx)
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700573 .with_context(|| format!("With key.domain = {:?}.", access_key.domain))?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700574
575 Ok((key_id, access_key, None))
576 }
577
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700578 // Domain::GRANT. In this case we load the key_id and the access_vector
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700579 // from the grant table.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700580 Domain::GRANT => {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700581 let mut stmt = tx
582 .prepare(
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800583 "SELECT keyentryid, access_vector FROM persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700584 WHERE grantee = ? AND id = ?;",
585 )
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700586 .context("Domain::GRANT prepare statement failed")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700587 let mut rows = stmt
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700588 .query(params![caller_uid as i64, key.nspace])
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700589 .context("Domain:Grant: query failed.")?;
590 let (key_id, access_vector): (i64, i32) =
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800591 db_utils::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700592 let r =
593 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700594 Ok((
595 r.get(0).context("Failed to unpack key_id.")?,
596 r.get(1).context("Failed to unpack access_vector.")?,
597 ))
598 })
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700599 .context("Domain::GRANT.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700600 Ok((key_id, key, Some(access_vector.into())))
601 }
602
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700603 // Domain::KEY_ID. In this case we load the domain and namespace from the
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700604 // keyentry database because we need them for access control.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700605 Domain::KEY_ID => {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700606 let mut stmt = tx
607 .prepare(
608 "SELECT domain, namespace FROM persistent.keyentry
609 WHERE
610 id = ?;",
611 )
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700612 .context("Domain::KEY_ID: prepare statement failed")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700613 let mut rows =
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700614 stmt.query(params![key.nspace]).context("Domain::KEY_ID: query failed.")?;
615 let (domain, namespace): (Domain, i64) =
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800616 db_utils::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700617 let r =
618 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700619 Ok((
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700620 Domain(r.get(0).context("Failed to unpack domain.")?),
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700621 r.get(1).context("Failed to unpack namespace.")?,
622 ))
623 })
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700624 .context("Domain::KEY_ID.")?;
625 let key_id = key.nspace;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700626 let mut access_key = key;
627 access_key.domain = domain;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700628 access_key.nspace = namespace;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700629
630 Ok((key_id, access_key, None))
631 }
632 _ => Err(anyhow!(KsError::sys())),
633 }
634 }
635
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700636 fn load_blob_components(
637 key_id: i64,
638 load_bits: KeyEntryLoadBits,
639 tx: &Transaction,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700640 ) -> Result<(SecurityLevel, Option<Vec<u8>>, Option<Vec<u8>>, Option<Vec<u8>>)> {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700641 let mut stmt = tx
642 .prepare(
643 "SELECT MAX(id), sec_level, subcomponent_type, blob FROM persistent.blobentry
644 WHERE keyentryid = ? GROUP BY subcomponent_type;",
645 )
646 .context("In load_blob_components: prepare statement failed.")?;
647
648 let mut rows =
649 stmt.query(params![key_id]).context("In load_blob_components: query failed.")?;
650
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700651 let mut sec_level: SecurityLevel = Default::default();
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700652 let mut km_blob: Option<Vec<u8>> = None;
653 let mut cert_blob: Option<Vec<u8>> = None;
654 let mut cert_chain_blob: Option<Vec<u8>> = None;
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800655 db_utils::with_rows_extract_all(&mut rows, |row| {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700656 let sub_type: SubComponentType =
657 row.get(2).context("Failed to extract subcomponent_type.")?;
658 match (sub_type, load_bits.load_public()) {
659 (SubComponentType::KM_BLOB, _) => {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700660 sec_level =
661 SecurityLevel(row.get(1).context("Failed to extract security level.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700662 if load_bits.load_km() {
663 km_blob = Some(row.get(3).context("Failed to extract KM blob.")?);
664 }
665 }
666 (SubComponentType::CERT, true) => {
667 cert_blob =
668 Some(row.get(3).context("Failed to extract public certificate blob.")?);
669 }
670 (SubComponentType::CERT_CHAIN, true) => {
671 cert_chain_blob =
672 Some(row.get(3).context("Failed to extract certificate chain blob.")?);
673 }
674 (SubComponentType::CERT, _) | (SubComponentType::CERT_CHAIN, _) => {}
675 _ => Err(KsError::sys()).context("Unknown subcomponent type.")?,
676 }
677 Ok(())
678 })
679 .context("In load_blob_components.")?;
680
681 Ok((sec_level, km_blob, cert_blob, cert_chain_blob))
682 }
683
684 fn load_key_parameters(key_id: i64, tx: &Transaction) -> Result<Vec<KeyParameter>> {
685 let mut stmt = tx
686 .prepare(
687 "SELECT tag, data, security_level from persistent.keyparameter
688 WHERE keyentryid = ?;",
689 )
690 .context("In load_key_parameters: prepare statement failed.")?;
691
692 let mut parameters: Vec<KeyParameter> = Vec::new();
693
694 let mut rows =
695 stmt.query(params![key_id]).context("In load_key_parameters: query failed.")?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800696 db_utils::with_rows_extract_all(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700697 let tag = Tag(row.get(0).context("Failed to read tag.")?);
698 let sec_level = SecurityLevel(row.get(2).context("Failed to read sec_level.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700699 parameters.push(
700 KeyParameter::new_from_sql(tag, &SqlField::new(1, &row), sec_level)
701 .context("Failed to read KeyParameter.")?,
702 );
703 Ok(())
704 })
705 .context("In load_key_parameters.")?;
706
707 Ok(parameters)
708 }
709
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700710 /// Load a key entry by the given key descriptor.
711 /// It uses the `check_permission` callback to verify if the access is allowed
712 /// given the key access tuple read from the database using `load_access_tuple`.
713 /// With `load_bits` the caller may specify which blobs shall be loaded from
714 /// the blob database.
715 pub fn load_key_entry(
716 &mut self,
717 key: KeyDescriptor,
718 load_bits: KeyEntryLoadBits,
719 caller_uid: u32,
720 check_permission: impl FnOnce(&KeyDescriptor, Option<KeyPermSet>) -> Result<()>,
Janis Danisevskisaec14592020-11-12 09:41:49 -0800721 ) -> Result<(KeyIdGuard, KeyEntry)> {
722 // KEY ID LOCK 1/2
723 // If we got a key descriptor with a key id we can get the lock right away.
724 // Otherwise we have to defer it until we know the key id.
725 let key_id_guard = match key.domain {
726 Domain::KEY_ID => Some(KEY_ID_LOCK.get(key.nspace)),
727 _ => None,
728 };
729
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700730 let tx = self
731 .conn
Janis Danisevskisaec14592020-11-12 09:41:49 -0800732 .unchecked_transaction()
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700733 .context("In load_key_entry: Failed to initialize transaction.")?;
734
735 // Load the key_id and complete the access control tuple.
736 let (key_id, access_key_descriptor, access_vector) =
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700737 Self::load_access_tuple(&tx, key, caller_uid).context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700738
739 // Perform access control. It is vital that we return here if the permission is denied.
740 // So do not touch that '?' at the end.
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700741 check_permission(&access_key_descriptor, access_vector).context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700742
Janis Danisevskisaec14592020-11-12 09:41:49 -0800743 // KEY ID LOCK 2/2
744 // If we did not get a key id lock by now, it was because we got a key descriptor
745 // without a key id. At this point we got the key id, so we can try and get a lock.
746 // However, we cannot block here, because we are in the middle of the transaction.
747 // So first we try to get the lock non blocking. If that fails, we roll back the
748 // transaction and block until we get the lock. After we successfully got the lock,
749 // we start a new transaction and load the access tuple again.
750 //
751 // We don't need to perform access control again, because we already established
752 // that the caller had access to the given key. But we need to make sure that the
753 // key id still exists. So we have to load the key entry by key id this time.
754 let (key_id_guard, tx) = match key_id_guard {
755 None => match KEY_ID_LOCK.try_get(key_id) {
756 None => {
757 // Roll back the transaction.
758 tx.rollback().context("In load_key_entry: Failed to roll back transaction.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700759
Janis Danisevskisaec14592020-11-12 09:41:49 -0800760 // Block until we have a key id lock.
761 let key_id_guard = KEY_ID_LOCK.get(key_id);
762
763 // Create a new transaction.
764 let tx = self.conn.unchecked_transaction().context(
765 "In load_key_entry: Failed to initialize transaction. (deferred key lock)",
766 )?;
767
768 Self::load_access_tuple(
769 &tx,
770 // This time we have to load the key by the retrieved key id, because the
771 // alias may have been rebound after we rolled back the transaction.
772 KeyDescriptor {
773 domain: Domain::KEY_ID,
774 nspace: key_id,
775 ..Default::default()
776 },
777 caller_uid,
778 )
779 .context("In load_key_entry. (deferred key lock)")?;
780 (key_id_guard, tx)
781 }
782 Some(l) => (l, tx),
783 },
784 Some(key_id_guard) => (key_id_guard, tx),
785 };
786
787 let (sec_level, km_blob, cert_blob, cert_chain_blob) =
788 Self::load_blob_components(key_id_guard.id(), load_bits, &tx)
789 .context("In load_key_entry.")?;
790
791 let parameters =
792 Self::load_key_parameters(key_id_guard.id(), &tx).context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700793
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700794 tx.commit().context("In load_key_entry: Failed to commit transaction.")?;
795
Janis Danisevskisaec14592020-11-12 09:41:49 -0800796 let key_id = key_id_guard.id();
797 Ok((
798 key_id_guard,
799 KeyEntry {
800 id: key_id,
801 km_blob,
802 cert: cert_blob,
803 cert_chain: cert_chain_blob,
804 sec_level,
805 parameters,
806 },
807 ))
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700808 }
809
Janis Danisevskise92a5e62020-12-02 12:57:41 -0800810 /// Returns a list of KeyDescriptors in the selected domain/namespace.
811 /// The key descriptors will have the domain, nspace, and alias field set.
812 /// Domain must be APP or SELINUX, the caller must make sure of that.
813 pub fn list(&mut self, domain: Domain, namespace: i64) -> Result<Vec<KeyDescriptor>> {
814 let mut stmt = self
815 .conn
816 .prepare(
817 "SELECT alias FROM persistent.keyentry
818 WHERE domain = ? AND namespace = ? AND alias IS NOT NULL;",
819 )
820 .context("In list: Failed to prepare.")?;
821
822 let mut rows =
823 stmt.query(params![domain.0 as u32, namespace]).context("In list: Failed to query.")?;
824
825 let mut descriptors: Vec<KeyDescriptor> = Vec::new();
826 db_utils::with_rows_extract_all(&mut rows, |row| {
827 descriptors.push(KeyDescriptor {
828 domain,
829 nspace: namespace,
830 alias: Some(row.get(0).context("Trying to extract alias.")?),
831 blob: None,
832 });
833 Ok(())
834 })
835 .context("In list.")?;
836 Ok(descriptors)
837 }
838
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700839 /// Adds a grant to the grant table.
840 /// Like `load_key_entry` this function loads the access tuple before
841 /// it uses the callback for a permission check. Upon success,
842 /// it inserts the `grantee_uid`, `key_id`, and `access_vector` into the
843 /// grant table. The new row will have a randomized id, which is used as
844 /// grant id in the namespace field of the resulting KeyDescriptor.
845 pub fn grant(
846 &mut self,
847 key: KeyDescriptor,
848 caller_uid: u32,
849 grantee_uid: u32,
850 access_vector: KeyPermSet,
851 check_permission: impl FnOnce(&KeyDescriptor, &KeyPermSet) -> Result<()>,
852 ) -> Result<KeyDescriptor> {
853 let tx = self
854 .conn
855 .transaction_with_behavior(TransactionBehavior::Immediate)
856 .context("In grant: Failed to initialize transaction.")?;
857
858 // Load the key_id and complete the access control tuple.
859 // We ignore the access vector here because grants cannot be granted.
860 // The access vector returned here expresses the permissions the
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700861 // grantee has if key.domain == Domain::GRANT. But this vector
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700862 // cannot include the grant permission by design, so there is no way the
863 // subsequent permission check can pass.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700864 // We could check key.domain == Domain::GRANT and fail early.
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700865 // But even if we load the access tuple by grant here, the permission
866 // check denies the attempt to create a grant by grant descriptor.
867 let (key_id, access_key_descriptor, _) =
868 Self::load_access_tuple(&tx, key, caller_uid).context("In grant")?;
869
870 // Perform access control. It is vital that we return here if the permission
871 // was denied. So do not touch that '?' at the end of the line.
872 // This permission check checks if the caller has the grant permission
873 // for the given key and in addition to all of the permissions
874 // expressed in `access_vector`.
875 check_permission(&access_key_descriptor, &access_vector)
876 .context("In grant: check_permission failed.")?;
877
878 let grant_id = if let Some(grant_id) = tx
879 .query_row(
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800880 "SELECT id FROM persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700881 WHERE keyentryid = ? AND grantee = ?;",
882 params![key_id, grantee_uid],
883 |row| row.get(0),
884 )
885 .optional()
886 .context("In grant: Failed get optional existing grant id.")?
887 {
888 tx.execute(
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800889 "UPDATE persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700890 SET access_vector = ?
891 WHERE id = ?;",
892 params![i32::from(access_vector), grant_id],
893 )
894 .context("In grant: Failed to update existing grant.")?;
895 grant_id
896 } else {
Joel Galenson845f74b2020-09-09 14:11:55 -0700897 Self::insert_with_retry(|id| {
898 tx.execute(
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800899 "INSERT INTO persistent.grant (id, grantee, keyentryid, access_vector)
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700900 VALUES (?, ?, ?, ?);",
Joel Galenson845f74b2020-09-09 14:11:55 -0700901 params![id, grantee_uid, key_id, i32::from(access_vector)],
902 )
903 })
904 .context("In grant")?
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700905 };
906 tx.commit().context("In grant: failed to commit transaction.")?;
907
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700908 Ok(KeyDescriptor { domain: Domain::GRANT, nspace: grant_id, alias: None, blob: None })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700909 }
910
911 /// This function checks permissions like `grant` and `load_key_entry`
912 /// before removing a grant from the grant table.
913 pub fn ungrant(
914 &mut self,
915 key: KeyDescriptor,
916 caller_uid: u32,
917 grantee_uid: u32,
918 check_permission: impl FnOnce(&KeyDescriptor) -> Result<()>,
919 ) -> Result<()> {
920 let tx = self
921 .conn
922 .transaction_with_behavior(TransactionBehavior::Immediate)
923 .context("In ungrant: Failed to initialize transaction.")?;
924
925 // Load the key_id and complete the access control tuple.
926 // We ignore the access vector here because grants cannot be granted.
927 let (key_id, access_key_descriptor, _) =
928 Self::load_access_tuple(&tx, key, caller_uid).context("In ungrant.")?;
929
930 // Perform access control. We must return here if the permission
931 // was denied. So do not touch the '?' at the end of this line.
932 check_permission(&access_key_descriptor).context("In grant: check_permission failed.")?;
933
934 tx.execute(
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800935 "DELETE FROM persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700936 WHERE keyentryid = ? AND grantee = ?;",
937 params![key_id, grantee_uid],
938 )
939 .context("Failed to delete grant.")?;
940
941 tx.commit().context("In ungrant: failed to commit transaction.")?;
942
943 Ok(())
944 }
945
Joel Galenson845f74b2020-09-09 14:11:55 -0700946 // Generates a random id and passes it to the given function, which will
947 // try to insert it into a database. If that insertion fails, retry;
948 // otherwise return the id.
949 fn insert_with_retry(inserter: impl Fn(i64) -> rusqlite::Result<usize>) -> Result<i64> {
950 loop {
951 let newid: i64 = random();
952 match inserter(newid) {
953 // If the id already existed, try again.
954 Err(rusqlite::Error::SqliteFailure(
955 libsqlite3_sys::Error {
956 code: libsqlite3_sys::ErrorCode::ConstraintViolation,
957 extended_code: libsqlite3_sys::SQLITE_CONSTRAINT_UNIQUE,
958 },
959 _,
960 )) => (),
961 Err(e) => {
962 return Err(e).context("In insert_with_retry: failed to insert into database.")
963 }
964 _ => return Ok(newid),
965 }
966 }
967 }
Joel Galenson26f4d012020-07-17 14:57:21 -0700968}
969
970#[cfg(test)]
971mod tests {
972
973 use super::*;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700974 use crate::key_parameter::{
975 Algorithm, BlockMode, Digest, EcCurve, HardwareAuthenticatorType, KeyOrigin, KeyParameter,
976 KeyParameterValue, KeyPurpose, PaddingMode, SecurityLevel,
977 };
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700978 use crate::key_perm_set;
979 use crate::permission::{KeyPerm, KeyPermSet};
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800980 use crate::test::utils::TempDir;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700981 use rusqlite::NO_PARAMS;
Joel Galenson0891bc12020-07-20 10:37:03 -0700982 use std::cell::RefCell;
Janis Danisevskisaec14592020-11-12 09:41:49 -0800983 use std::sync::atomic::{AtomicU8, Ordering};
984 use std::sync::Arc;
985 use std::thread;
Joel Galenson0891bc12020-07-20 10:37:03 -0700986
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700987 fn new_test_db() -> Result<KeystoreDB> {
988 let conn = KeystoreDB::make_connection("file::memory:", "file::memory:")?;
989
990 KeystoreDB::init_tables(&conn).context("Failed to initialize tables.")?;
991 Ok(KeystoreDB { conn })
992 }
993
Joel Galenson0891bc12020-07-20 10:37:03 -0700994 // Ensure that we're using the "injected" random function, not the real one.
995 #[test]
996 fn test_mocked_random() {
997 let rand1 = random();
998 let rand2 = random();
999 let rand3 = random();
1000 if rand1 == rand2 {
1001 assert_eq!(rand2 + 1, rand3);
1002 } else {
1003 assert_eq!(rand1 + 1, rand2);
1004 assert_eq!(rand2, rand3);
1005 }
1006 }
Joel Galenson26f4d012020-07-17 14:57:21 -07001007
Joel Galenson26f4d012020-07-17 14:57:21 -07001008 // Test that we have the correct tables.
1009 #[test]
1010 fn test_tables() -> Result<()> {
Janis Danisevskis4df44f42020-08-26 14:40:03 -07001011 let db = new_test_db()?;
Joel Galenson26f4d012020-07-17 14:57:21 -07001012 let tables = db
1013 .conn
Joel Galenson2aab4432020-07-22 15:27:57 -07001014 .prepare("SELECT name from persistent.sqlite_master WHERE type='table' ORDER BY name;")?
Joel Galenson26f4d012020-07-17 14:57:21 -07001015 .query_map(params![], |row| row.get(0))?
1016 .collect::<rusqlite::Result<Vec<String>>>()?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08001017 assert_eq!(tables.len(), 4);
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001018 assert_eq!(tables[0], "blobentry");
Janis Danisevskisbf15d732020-12-08 10:35:26 -08001019 assert_eq!(tables[1], "grant");
1020 assert_eq!(tables[2], "keyentry");
1021 assert_eq!(tables[3], "keyparameter");
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001022 let tables = db
1023 .conn
1024 .prepare("SELECT name from perboot.sqlite_master WHERE type='table' ORDER BY name;")?
1025 .query_map(params![], |row| row.get(0))?
1026 .collect::<rusqlite::Result<Vec<String>>>()?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08001027 assert_eq!(tables.len(), 0);
Joel Galenson2aab4432020-07-22 15:27:57 -07001028 Ok(())
1029 }
1030
1031 #[test]
1032 fn test_persistence_for_files() -> Result<()> {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08001033 let temp_dir = TempDir::new("persistent_db_test")?;
1034 let db = KeystoreDB::new(temp_dir.path())?;
Joel Galenson2aab4432020-07-22 15:27:57 -07001035
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001036 db.create_key_entry(Domain::APP, 100)?;
Joel Galenson2aab4432020-07-22 15:27:57 -07001037 let entries = get_keyentry(&db)?;
1038 assert_eq!(entries.len(), 1);
Janis Danisevskisbf15d732020-12-08 10:35:26 -08001039
1040 let db = KeystoreDB::new(temp_dir.path())?;
Joel Galenson2aab4432020-07-22 15:27:57 -07001041
1042 let entries_new = get_keyentry(&db)?;
1043 assert_eq!(entries, entries_new);
1044 Ok(())
1045 }
1046
1047 #[test]
Joel Galenson0891bc12020-07-20 10:37:03 -07001048 fn test_create_key_entry() -> Result<()> {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001049 fn extractor(ke: &KeyEntryRow) -> (Domain, i64, Option<&str>) {
Joel Galenson0891bc12020-07-20 10:37:03 -07001050 (ke.domain.unwrap(), ke.namespace.unwrap(), ke.alias.as_deref())
1051 }
1052
Janis Danisevskis4df44f42020-08-26 14:40:03 -07001053 let db = new_test_db()?;
Joel Galenson0891bc12020-07-20 10:37:03 -07001054
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001055 db.create_key_entry(Domain::APP, 100)?;
1056 db.create_key_entry(Domain::SELINUX, 101)?;
Joel Galenson0891bc12020-07-20 10:37:03 -07001057
1058 let entries = get_keyentry(&db)?;
1059 assert_eq!(entries.len(), 2);
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001060 assert_eq!(extractor(&entries[0]), (Domain::APP, 100, None));
1061 assert_eq!(extractor(&entries[1]), (Domain::SELINUX, 101, None));
Joel Galenson0891bc12020-07-20 10:37:03 -07001062
1063 // Test that we must pass in a valid Domain.
1064 check_result_is_error_containing_string(
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001065 db.create_key_entry(Domain::GRANT, 102),
1066 "Domain Domain(1) must be either App or SELinux.",
Joel Galenson0891bc12020-07-20 10:37:03 -07001067 );
1068 check_result_is_error_containing_string(
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001069 db.create_key_entry(Domain::BLOB, 103),
1070 "Domain Domain(3) must be either App or SELinux.",
Joel Galenson0891bc12020-07-20 10:37:03 -07001071 );
1072 check_result_is_error_containing_string(
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001073 db.create_key_entry(Domain::KEY_ID, 104),
1074 "Domain Domain(4) must be either App or SELinux.",
Joel Galenson0891bc12020-07-20 10:37:03 -07001075 );
1076
1077 Ok(())
1078 }
1079
Joel Galenson33c04ad2020-08-03 11:04:38 -07001080 #[test]
1081 fn test_rebind_alias() -> Result<()> {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001082 fn extractor(ke: &KeyEntryRow) -> (Option<Domain>, Option<i64>, Option<&str>) {
Joel Galenson33c04ad2020-08-03 11:04:38 -07001083 (ke.domain, ke.namespace, ke.alias.as_deref())
1084 }
1085
Janis Danisevskis4df44f42020-08-26 14:40:03 -07001086 let mut db = new_test_db()?;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001087 db.create_key_entry(Domain::APP, 42)?;
1088 db.create_key_entry(Domain::APP, 42)?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07001089 let entries = get_keyentry(&db)?;
1090 assert_eq!(entries.len(), 2);
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001091 assert_eq!(extractor(&entries[0]), (Some(Domain::APP), Some(42), None));
1092 assert_eq!(extractor(&entries[1]), (Some(Domain::APP), Some(42), None));
Joel Galenson33c04ad2020-08-03 11:04:38 -07001093
1094 // Test that the first call to rebind_alias sets the alias.
Janis Danisevskisaec14592020-11-12 09:41:49 -08001095 db.rebind_alias(&KEY_ID_LOCK.get(entries[0].id), "foo", Domain::APP, 42)?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07001096 let entries = get_keyentry(&db)?;
1097 assert_eq!(entries.len(), 2);
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001098 assert_eq!(extractor(&entries[0]), (Some(Domain::APP), Some(42), Some("foo")));
1099 assert_eq!(extractor(&entries[1]), (Some(Domain::APP), Some(42), None));
Joel Galenson33c04ad2020-08-03 11:04:38 -07001100
1101 // Test that the second call to rebind_alias also empties the old one.
Janis Danisevskisaec14592020-11-12 09:41:49 -08001102 db.rebind_alias(&KEY_ID_LOCK.get(entries[1].id), "foo", Domain::APP, 42)?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07001103 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 // Test that we must pass in a valid Domain.
1109 check_result_is_error_containing_string(
Janis Danisevskisaec14592020-11-12 09:41:49 -08001110 db.rebind_alias(&KEY_ID_LOCK.get(0), "foo", Domain::GRANT, 42),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001111 "Domain Domain(1) must be either App or SELinux.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07001112 );
1113 check_result_is_error_containing_string(
Janis Danisevskisaec14592020-11-12 09:41:49 -08001114 db.rebind_alias(&KEY_ID_LOCK.get(0), "foo", Domain::BLOB, 42),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001115 "Domain Domain(3) must be either App or SELinux.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07001116 );
1117 check_result_is_error_containing_string(
Janis Danisevskisaec14592020-11-12 09:41:49 -08001118 db.rebind_alias(&KEY_ID_LOCK.get(0), "foo", Domain::KEY_ID, 42),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001119 "Domain Domain(4) must be either App or SELinux.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07001120 );
1121
1122 // Test that we correctly handle setting an alias for something that does not exist.
1123 check_result_is_error_containing_string(
Janis Danisevskisaec14592020-11-12 09:41:49 -08001124 db.rebind_alias(&KEY_ID_LOCK.get(0), "foo", Domain::SELINUX, 42),
Joel Galenson33c04ad2020-08-03 11:04:38 -07001125 "Expected to update a single entry but instead updated 0",
1126 );
1127 // Test that we correctly abort the transaction in this case.
1128 let entries = get_keyentry(&db)?;
1129 assert_eq!(entries.len(), 2);
Joel Galenson7fa5c412020-11-19 10:56:54 -08001130 assert_eq!(extractor(&entries[0]), (None, None, None));
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001131 assert_eq!(extractor(&entries[1]), (Some(Domain::APP), Some(42), Some("foo")));
Joel Galenson33c04ad2020-08-03 11:04:38 -07001132
1133 Ok(())
1134 }
1135
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001136 #[test]
1137 fn test_grant_ungrant() -> Result<()> {
1138 const CALLER_UID: u32 = 15;
1139 const GRANTEE_UID: u32 = 12;
1140 const SELINUX_NAMESPACE: i64 = 7;
1141
1142 let mut db = new_test_db()?;
1143 db.conn.execute(
1144 "INSERT INTO persistent.keyentry (id, creation_date, domain, namespace, alias)
1145 VALUES (1, '1980', 0, 15, 'key'), (2, '1980', 2, 7, 'yek');",
1146 NO_PARAMS,
1147 )?;
1148 let app_key = KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001149 domain: super::Domain::APP,
1150 nspace: 0,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001151 alias: Some("key".to_string()),
1152 blob: None,
1153 };
1154 const PVEC1: KeyPermSet = key_perm_set![KeyPerm::use_(), KeyPerm::get_info()];
1155 const PVEC2: KeyPermSet = key_perm_set![KeyPerm::use_()];
1156
1157 // Reset totally predictable random number generator in case we
1158 // are not the first test running on this thread.
1159 reset_random();
1160 let next_random = 0i64;
1161
1162 let app_granted_key =
1163 db.grant(app_key.clone(), CALLER_UID, GRANTEE_UID, PVEC1, |k, a| {
1164 assert_eq!(*a, PVEC1);
1165 assert_eq!(
1166 *k,
1167 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001168 domain: super::Domain::APP,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001169 // namespace must be set to the caller_uid.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001170 nspace: CALLER_UID as i64,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001171 alias: Some("key".to_string()),
1172 blob: None,
1173 }
1174 );
1175 Ok(())
1176 })?;
1177
1178 assert_eq!(
1179 app_granted_key,
1180 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001181 domain: super::Domain::GRANT,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001182 // The grantid is next_random due to the mock random number generator.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001183 nspace: next_random,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001184 alias: None,
1185 blob: None,
1186 }
1187 );
1188
1189 let selinux_key = KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001190 domain: super::Domain::SELINUX,
1191 nspace: SELINUX_NAMESPACE,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001192 alias: Some("yek".to_string()),
1193 blob: None,
1194 };
1195
1196 let selinux_granted_key =
1197 db.grant(selinux_key.clone(), CALLER_UID, 12, PVEC1, |k, a| {
1198 assert_eq!(*a, PVEC1);
1199 assert_eq!(
1200 *k,
1201 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001202 domain: super::Domain::SELINUX,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001203 // namespace must be the supplied SELinux
1204 // namespace.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001205 nspace: SELINUX_NAMESPACE,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001206 alias: Some("yek".to_string()),
1207 blob: None,
1208 }
1209 );
1210 Ok(())
1211 })?;
1212
1213 assert_eq!(
1214 selinux_granted_key,
1215 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001216 domain: super::Domain::GRANT,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001217 // The grantid is next_random + 1 due to the mock random number generator.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001218 nspace: next_random + 1,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001219 alias: None,
1220 blob: None,
1221 }
1222 );
1223
1224 // This should update the existing grant with PVEC2.
1225 let selinux_granted_key =
1226 db.grant(selinux_key.clone(), CALLER_UID, 12, PVEC2, |k, a| {
1227 assert_eq!(*a, PVEC2);
1228 assert_eq!(
1229 *k,
1230 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001231 domain: super::Domain::SELINUX,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001232 // namespace must be the supplied SELinux
1233 // namespace.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001234 nspace: SELINUX_NAMESPACE,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001235 alias: Some("yek".to_string()),
1236 blob: None,
1237 }
1238 );
1239 Ok(())
1240 })?;
1241
1242 assert_eq!(
1243 selinux_granted_key,
1244 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001245 domain: super::Domain::GRANT,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001246 // Same grant id as before. The entry was only updated.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001247 nspace: next_random + 1,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001248 alias: None,
1249 blob: None,
1250 }
1251 );
1252
1253 {
1254 // Limiting scope of stmt, because it borrows db.
1255 let mut stmt = db
1256 .conn
Janis Danisevskisbf15d732020-12-08 10:35:26 -08001257 .prepare("SELECT id, grantee, keyentryid, access_vector FROM persistent.grant;")?;
Janis Danisevskisee10b5f2020-09-22 16:42:35 -07001258 let mut rows =
1259 stmt.query_map::<(i64, u32, i64, KeyPermSet), _, _>(NO_PARAMS, |row| {
1260 Ok((
1261 row.get(0)?,
1262 row.get(1)?,
1263 row.get(2)?,
1264 KeyPermSet::from(row.get::<_, i32>(3)?),
1265 ))
1266 })?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001267
1268 let r = rows.next().unwrap().unwrap();
Janis Danisevskisee10b5f2020-09-22 16:42:35 -07001269 assert_eq!(r, (next_random, GRANTEE_UID, 1, PVEC1));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001270 let r = rows.next().unwrap().unwrap();
Janis Danisevskisee10b5f2020-09-22 16:42:35 -07001271 assert_eq!(r, (next_random + 1, GRANTEE_UID, 2, PVEC2));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001272 assert!(rows.next().is_none());
1273 }
1274
1275 debug_dump_keyentry_table(&mut db)?;
1276 println!("app_key {:?}", app_key);
1277 println!("selinux_key {:?}", selinux_key);
1278
1279 db.ungrant(app_key, CALLER_UID, GRANTEE_UID, |_| Ok(()))?;
1280 db.ungrant(selinux_key, CALLER_UID, GRANTEE_UID, |_| Ok(()))?;
1281
1282 Ok(())
1283 }
1284
1285 static TEST_KM_BLOB: &[u8] = b"my test blob";
1286 static TEST_CERT_BLOB: &[u8] = b"my test cert";
1287 static TEST_CERT_CHAIN_BLOB: &[u8] = b"my test cert_chain";
1288
1289 #[test]
1290 fn test_insert_blob() -> Result<()> {
1291 let mut db = new_test_db()?;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001292 db.insert_blob(
Janis Danisevskisaec14592020-11-12 09:41:49 -08001293 &KEY_ID_LOCK.get(1),
1294 SubComponentType::KM_BLOB,
1295 TEST_KM_BLOB,
1296 SecurityLevel::SOFTWARE,
1297 )?;
1298 db.insert_blob(
1299 &KEY_ID_LOCK.get(1),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001300 SubComponentType::CERT,
1301 TEST_CERT_BLOB,
1302 SecurityLevel::TRUSTED_ENVIRONMENT,
1303 )?;
1304 db.insert_blob(
Janis Danisevskisaec14592020-11-12 09:41:49 -08001305 &KEY_ID_LOCK.get(1),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001306 SubComponentType::CERT_CHAIN,
1307 TEST_CERT_CHAIN_BLOB,
1308 SecurityLevel::STRONGBOX,
1309 )?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001310
1311 let mut stmt = db.conn.prepare(
1312 "SELECT subcomponent_type, keyentryid, blob, sec_level FROM persistent.blobentry
1313 ORDER BY sec_level ASC;",
1314 )?;
1315 let mut rows = stmt
1316 .query_map::<(SubComponentType, i64, Vec<u8>, i64), _, _>(NO_PARAMS, |row| {
1317 Ok((row.get(0)?, row.get(1)?, row.get(2)?, row.get(3)?))
1318 })?;
1319 let r = rows.next().unwrap().unwrap();
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001320 assert_eq!(r, (SubComponentType::KM_BLOB, 1, TEST_KM_BLOB.to_vec(), 0));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001321 let r = rows.next().unwrap().unwrap();
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001322 assert_eq!(r, (SubComponentType::CERT, 1, TEST_CERT_BLOB.to_vec(), 1));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001323 let r = rows.next().unwrap().unwrap();
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001324 assert_eq!(r, (SubComponentType::CERT_CHAIN, 1, TEST_CERT_CHAIN_BLOB.to_vec(), 2));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001325
1326 Ok(())
1327 }
1328
1329 static TEST_ALIAS: &str = "my super duper key";
1330
1331 #[test]
1332 fn test_insert_and_load_full_keyentry_domain_app() -> Result<()> {
1333 let mut db = new_test_db()?;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001334 let key_id = make_test_key_entry(&mut db, Domain::APP, 1, TEST_ALIAS)
Janis Danisevskisaec14592020-11-12 09:41:49 -08001335 .context("test_insert_and_load_full_keyentry_domain_app")?
1336 .0;
1337 let (_key_guard, key_entry) = db.load_key_entry(
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001338 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001339 domain: Domain::APP,
1340 nspace: 0,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001341 alias: Some(TEST_ALIAS.to_string()),
1342 blob: None,
1343 },
1344 KeyEntryLoadBits::BOTH,
1345 1,
1346 |_k, _av| Ok(()),
1347 )?;
1348 assert_eq!(
1349 key_entry,
1350 KeyEntry {
1351 id: key_id,
1352 km_blob: Some(TEST_KM_BLOB.to_vec()),
1353 cert: Some(TEST_CERT_BLOB.to_vec()),
1354 cert_chain: Some(TEST_CERT_CHAIN_BLOB.to_vec()),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001355 sec_level: SecurityLevel::TRUSTED_ENVIRONMENT,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001356 parameters: make_test_params(),
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001357 }
1358 );
1359 Ok(())
1360 }
1361
1362 #[test]
1363 fn test_insert_and_load_full_keyentry_domain_selinux() -> Result<()> {
1364 let mut db = new_test_db()?;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001365 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS)
Janis Danisevskisaec14592020-11-12 09:41:49 -08001366 .context("test_insert_and_load_full_keyentry_domain_selinux")?
1367 .0;
1368 let (_key_guard, key_entry) = db.load_key_entry(
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001369 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001370 domain: Domain::SELINUX,
1371 nspace: 1,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001372 alias: Some(TEST_ALIAS.to_string()),
1373 blob: None,
1374 },
1375 KeyEntryLoadBits::BOTH,
1376 1,
1377 |_k, _av| Ok(()),
1378 )?;
1379 assert_eq!(
1380 key_entry,
1381 KeyEntry {
1382 id: key_id,
1383 km_blob: Some(TEST_KM_BLOB.to_vec()),
1384 cert: Some(TEST_CERT_BLOB.to_vec()),
1385 cert_chain: Some(TEST_CERT_CHAIN_BLOB.to_vec()),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001386 sec_level: SecurityLevel::TRUSTED_ENVIRONMENT,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001387 parameters: make_test_params(),
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001388 }
1389 );
1390 Ok(())
1391 }
1392
1393 #[test]
1394 fn test_insert_and_load_full_keyentry_domain_key_id() -> Result<()> {
1395 let mut db = new_test_db()?;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001396 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS)
Janis Danisevskisaec14592020-11-12 09:41:49 -08001397 .context("test_insert_and_load_full_keyentry_domain_key_id")?
1398 .0;
1399 let (_key_guard, key_entry) = db.load_key_entry(
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001400 KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001401 KeyEntryLoadBits::BOTH,
1402 1,
1403 |_k, _av| Ok(()),
1404 )?;
1405 assert_eq!(
1406 key_entry,
1407 KeyEntry {
1408 id: key_id,
1409 km_blob: Some(TEST_KM_BLOB.to_vec()),
1410 cert: Some(TEST_CERT_BLOB.to_vec()),
1411 cert_chain: Some(TEST_CERT_CHAIN_BLOB.to_vec()),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001412 sec_level: SecurityLevel::TRUSTED_ENVIRONMENT,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001413 parameters: make_test_params(),
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001414 }
1415 );
1416
1417 Ok(())
1418 }
1419
1420 #[test]
1421 fn test_insert_and_load_full_keyentry_from_grant() -> Result<()> {
1422 let mut db = new_test_db()?;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001423 let key_id = make_test_key_entry(&mut db, Domain::APP, 1, TEST_ALIAS)
Janis Danisevskisaec14592020-11-12 09:41:49 -08001424 .context("test_insert_and_load_full_keyentry_from_grant")?
1425 .0;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001426
1427 let granted_key = db.grant(
1428 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001429 domain: Domain::APP,
1430 nspace: 0,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001431 alias: Some(TEST_ALIAS.to_string()),
1432 blob: None,
1433 },
1434 1,
1435 2,
1436 key_perm_set![KeyPerm::use_()],
1437 |_k, _av| Ok(()),
1438 )?;
1439
1440 debug_dump_grant_table(&mut db)?;
1441
Janis Danisevskisaec14592020-11-12 09:41:49 -08001442 let (_key_guard, key_entry) =
1443 db.load_key_entry(granted_key, KeyEntryLoadBits::BOTH, 2, |k, av| {
1444 assert_eq!(Domain::GRANT, k.domain);
1445 assert!(av.unwrap().includes(KeyPerm::use_()));
1446 Ok(())
1447 })?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001448
1449 assert_eq!(
1450 key_entry,
1451 KeyEntry {
1452 id: key_id,
1453 km_blob: Some(TEST_KM_BLOB.to_vec()),
1454 cert: Some(TEST_CERT_BLOB.to_vec()),
1455 cert_chain: Some(TEST_CERT_CHAIN_BLOB.to_vec()),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001456 sec_level: SecurityLevel::TRUSTED_ENVIRONMENT,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001457 parameters: make_test_params(),
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001458 }
1459 );
1460 Ok(())
1461 }
1462
Janis Danisevskisaec14592020-11-12 09:41:49 -08001463 static KEY_LOCK_TEST_ALIAS: &str = "my super duper locked key";
1464
Janis Danisevskisaec14592020-11-12 09:41:49 -08001465 #[test]
1466 fn test_insert_and_load_full_keyentry_domain_app_concurrently() -> Result<()> {
1467 let handle = {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08001468 let temp_dir = Arc::new(TempDir::new("id_lock_test")?);
1469 let temp_dir_clone = temp_dir.clone();
1470 let mut db = KeystoreDB::new(temp_dir.path())?;
Janis Danisevskisaec14592020-11-12 09:41:49 -08001471 let key_id = make_test_key_entry(&mut db, Domain::APP, 33, KEY_LOCK_TEST_ALIAS)
1472 .context("test_insert_and_load_full_keyentry_domain_app")?
1473 .0;
1474 let (_key_guard, key_entry) = db.load_key_entry(
1475 KeyDescriptor {
1476 domain: Domain::APP,
1477 nspace: 0,
1478 alias: Some(KEY_LOCK_TEST_ALIAS.to_string()),
1479 blob: None,
1480 },
1481 KeyEntryLoadBits::BOTH,
1482 33,
1483 |_k, _av| Ok(()),
1484 )?;
1485 assert_eq!(
1486 key_entry,
1487 KeyEntry {
1488 id: key_id,
1489 km_blob: Some(TEST_KM_BLOB.to_vec()),
1490 cert: Some(TEST_CERT_BLOB.to_vec()),
1491 cert_chain: Some(TEST_CERT_CHAIN_BLOB.to_vec()),
1492 sec_level: SecurityLevel::TRUSTED_ENVIRONMENT,
1493 parameters: make_test_params(),
1494 }
1495 );
1496 let state = Arc::new(AtomicU8::new(1));
1497 let state2 = state.clone();
1498
1499 // Spawning a second thread that attempts to acquire the key id lock
1500 // for the same key as the primary thread. The primary thread then
1501 // waits, thereby forcing the secondary thread into the second stage
1502 // of acquiring the lock (see KEY ID LOCK 2/2 above).
1503 // The test succeeds if the secondary thread observes the transition
1504 // of `state` from 1 to 2, despite having a whole second to overtake
1505 // the primary thread.
1506 let handle = thread::spawn(move || {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08001507 let temp_dir = temp_dir_clone;
1508 let mut db = KeystoreDB::new(temp_dir.path()).unwrap();
Janis Danisevskisaec14592020-11-12 09:41:49 -08001509 assert!(db
1510 .load_key_entry(
1511 KeyDescriptor {
1512 domain: Domain::APP,
1513 nspace: 0,
1514 alias: Some(KEY_LOCK_TEST_ALIAS.to_string()),
1515 blob: None,
1516 },
1517 KeyEntryLoadBits::BOTH,
1518 33,
1519 |_k, _av| Ok(()),
1520 )
1521 .is_ok());
1522 // We should only see a 2 here because we can only return
1523 // from load_key_entry when the `_key_guard` expires,
1524 // which happens at the end of the scope.
1525 assert_eq!(2, state2.load(Ordering::Relaxed));
1526 });
1527
1528 thread::sleep(std::time::Duration::from_millis(1000));
1529
1530 assert_eq!(Ok(1), state.compare_exchange(1, 2, Ordering::Relaxed, Ordering::Relaxed));
1531
1532 // Return the handle from this scope so we can join with the
1533 // secondary thread after the key id lock has expired.
1534 handle
1535 // This is where the `_key_guard` goes out of scope,
1536 // which is the reason for concurrent load_key_entry on the same key
1537 // to unblock.
1538 };
1539 // Join with the secondary thread and unwrap, to propagate failing asserts to the
1540 // main test thread. We will not see failing asserts in secondary threads otherwise.
1541 handle.join().unwrap();
1542 Ok(())
1543 }
1544
Janis Danisevskise92a5e62020-12-02 12:57:41 -08001545 #[test]
1546 fn list() -> Result<()> {
1547 let temp_dir = TempDir::new("list_test")?;
1548 let mut db = KeystoreDB::new(temp_dir.path())?;
1549 static LIST_O_ENTRIES: &[(Domain, i64, &str)] = &[
1550 (Domain::APP, 1, "test1"),
1551 (Domain::APP, 1, "test2"),
1552 (Domain::APP, 1, "test3"),
1553 (Domain::APP, 1, "test4"),
1554 (Domain::APP, 1, "test5"),
1555 (Domain::APP, 1, "test6"),
1556 (Domain::APP, 1, "test7"),
1557 (Domain::APP, 2, "test1"),
1558 (Domain::APP, 2, "test2"),
1559 (Domain::APP, 2, "test3"),
1560 (Domain::APP, 2, "test4"),
1561 (Domain::APP, 2, "test5"),
1562 (Domain::APP, 2, "test6"),
1563 (Domain::APP, 2, "test8"),
1564 (Domain::SELINUX, 100, "test1"),
1565 (Domain::SELINUX, 100, "test2"),
1566 (Domain::SELINUX, 100, "test3"),
1567 (Domain::SELINUX, 100, "test4"),
1568 (Domain::SELINUX, 100, "test5"),
1569 (Domain::SELINUX, 100, "test6"),
1570 (Domain::SELINUX, 100, "test9"),
1571 ];
1572
1573 let list_o_keys: Vec<(i64, i64)> = LIST_O_ENTRIES
1574 .iter()
1575 .map(|(domain, ns, alias)| {
1576 let entry =
1577 make_test_key_entry(&mut db, *domain, *ns, *alias).unwrap_or_else(|e| {
1578 panic!("Failed to insert {:?} {} {}. Error {:?}", domain, ns, alias, e)
1579 });
1580 (entry.id(), *ns)
1581 })
1582 .collect();
1583
1584 for (domain, namespace) in
1585 &[(Domain::APP, 1i64), (Domain::APP, 2i64), (Domain::SELINUX, 100i64)]
1586 {
1587 let mut list_o_descriptors: Vec<KeyDescriptor> = LIST_O_ENTRIES
1588 .iter()
1589 .filter_map(|(domain, ns, alias)| match ns {
1590 ns if *ns == *namespace => Some(KeyDescriptor {
1591 domain: *domain,
1592 nspace: *ns,
1593 alias: Some(alias.to_string()),
1594 blob: None,
1595 }),
1596 _ => None,
1597 })
1598 .collect();
1599 list_o_descriptors.sort();
1600 let mut list_result = db.list(*domain, *namespace)?;
1601 list_result.sort();
1602 assert_eq!(list_o_descriptors, list_result);
1603
1604 let mut list_o_ids: Vec<i64> = list_o_descriptors
1605 .into_iter()
1606 .map(|d| {
1607 let (_, entry) = db
1608 .load_key_entry(d, KeyEntryLoadBits::NONE, *namespace as u32, |_, _| Ok(()))
1609 .unwrap();
1610 entry.id()
1611 })
1612 .collect();
1613 list_o_ids.sort_unstable();
1614 let mut loaded_entries: Vec<i64> = list_o_keys
1615 .iter()
1616 .filter_map(|(id, ns)| match ns {
1617 ns if *ns == *namespace => Some(*id),
1618 _ => None,
1619 })
1620 .collect();
1621 loaded_entries.sort_unstable();
1622 assert_eq!(list_o_ids, loaded_entries);
1623 }
1624 assert_eq!(Vec::<KeyDescriptor>::new(), db.list(Domain::SELINUX, 101)?);
1625
1626 Ok(())
1627 }
1628
Joel Galenson0891bc12020-07-20 10:37:03 -07001629 // Helpers
1630
1631 // Checks that the given result is an error containing the given string.
1632 fn check_result_is_error_containing_string<T>(result: Result<T>, target: &str) {
1633 let error_str = format!(
1634 "{:#?}",
1635 result.err().unwrap_or_else(|| panic!("Expected the error: {}", target))
1636 );
1637 assert!(
1638 error_str.contains(target),
1639 "The string \"{}\" should contain \"{}\"",
1640 error_str,
1641 target
1642 );
1643 }
1644
Joel Galenson2aab4432020-07-22 15:27:57 -07001645 #[derive(Debug, PartialEq)]
Joel Galenson0891bc12020-07-20 10:37:03 -07001646 #[allow(dead_code)]
1647 struct KeyEntryRow {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001648 id: i64,
Joel Galenson0891bc12020-07-20 10:37:03 -07001649 creation_date: String,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001650 domain: Option<Domain>,
Joel Galenson0891bc12020-07-20 10:37:03 -07001651 namespace: Option<i64>,
1652 alias: Option<String>,
1653 }
1654
1655 fn get_keyentry(db: &KeystoreDB) -> Result<Vec<KeyEntryRow>> {
1656 db.conn
Joel Galenson2aab4432020-07-22 15:27:57 -07001657 .prepare("SELECT * FROM persistent.keyentry;")?
Joel Galenson0891bc12020-07-20 10:37:03 -07001658 .query_map(NO_PARAMS, |row| {
Joel Galenson0891bc12020-07-20 10:37:03 -07001659 Ok(KeyEntryRow {
1660 id: row.get(0)?,
1661 creation_date: row.get(1)?,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001662 domain: match row.get(2)? {
1663 Some(i) => Some(Domain(i)),
1664 None => None,
1665 },
Joel Galenson0891bc12020-07-20 10:37:03 -07001666 namespace: row.get(3)?,
1667 alias: row.get(4)?,
1668 })
1669 })?
1670 .map(|r| r.context("Could not read keyentry row."))
1671 .collect::<Result<Vec<_>>>()
1672 }
1673
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001674 // Note: The parameters and SecurityLevel associations are nonsensical. This
1675 // collection is only used to check if the parameters are preserved as expected by the
1676 // database.
1677 fn make_test_params() -> Vec<KeyParameter> {
1678 vec![
1679 KeyParameter::new(KeyParameterValue::Invalid, SecurityLevel::TRUSTED_ENVIRONMENT),
1680 KeyParameter::new(
1681 KeyParameterValue::KeyPurpose(KeyPurpose::SIGN),
1682 SecurityLevel::TRUSTED_ENVIRONMENT,
1683 ),
1684 KeyParameter::new(
1685 KeyParameterValue::KeyPurpose(KeyPurpose::DECRYPT),
1686 SecurityLevel::TRUSTED_ENVIRONMENT,
1687 ),
1688 KeyParameter::new(
1689 KeyParameterValue::Algorithm(Algorithm::RSA),
1690 SecurityLevel::TRUSTED_ENVIRONMENT,
1691 ),
1692 KeyParameter::new(KeyParameterValue::KeySize(1024), SecurityLevel::TRUSTED_ENVIRONMENT),
1693 KeyParameter::new(
1694 KeyParameterValue::BlockMode(BlockMode::ECB),
1695 SecurityLevel::TRUSTED_ENVIRONMENT,
1696 ),
1697 KeyParameter::new(
1698 KeyParameterValue::BlockMode(BlockMode::GCM),
1699 SecurityLevel::TRUSTED_ENVIRONMENT,
1700 ),
1701 KeyParameter::new(KeyParameterValue::Digest(Digest::NONE), SecurityLevel::STRONGBOX),
1702 KeyParameter::new(
1703 KeyParameterValue::Digest(Digest::MD5),
1704 SecurityLevel::TRUSTED_ENVIRONMENT,
1705 ),
1706 KeyParameter::new(
1707 KeyParameterValue::Digest(Digest::SHA_2_224),
1708 SecurityLevel::TRUSTED_ENVIRONMENT,
1709 ),
1710 KeyParameter::new(
1711 KeyParameterValue::Digest(Digest::SHA_2_256),
1712 SecurityLevel::STRONGBOX,
1713 ),
1714 KeyParameter::new(
1715 KeyParameterValue::PaddingMode(PaddingMode::NONE),
1716 SecurityLevel::TRUSTED_ENVIRONMENT,
1717 ),
1718 KeyParameter::new(
1719 KeyParameterValue::PaddingMode(PaddingMode::RSA_OAEP),
1720 SecurityLevel::TRUSTED_ENVIRONMENT,
1721 ),
1722 KeyParameter::new(
1723 KeyParameterValue::PaddingMode(PaddingMode::RSA_PSS),
1724 SecurityLevel::STRONGBOX,
1725 ),
1726 KeyParameter::new(
1727 KeyParameterValue::PaddingMode(PaddingMode::RSA_PKCS1_1_5_SIGN),
1728 SecurityLevel::TRUSTED_ENVIRONMENT,
1729 ),
1730 KeyParameter::new(KeyParameterValue::CallerNonce, SecurityLevel::TRUSTED_ENVIRONMENT),
1731 KeyParameter::new(KeyParameterValue::MinMacLength(256), SecurityLevel::STRONGBOX),
1732 KeyParameter::new(
1733 KeyParameterValue::EcCurve(EcCurve::P_224),
1734 SecurityLevel::TRUSTED_ENVIRONMENT,
1735 ),
1736 KeyParameter::new(KeyParameterValue::EcCurve(EcCurve::P_256), SecurityLevel::STRONGBOX),
1737 KeyParameter::new(
1738 KeyParameterValue::EcCurve(EcCurve::P_384),
1739 SecurityLevel::TRUSTED_ENVIRONMENT,
1740 ),
1741 KeyParameter::new(
1742 KeyParameterValue::EcCurve(EcCurve::P_521),
1743 SecurityLevel::TRUSTED_ENVIRONMENT,
1744 ),
1745 KeyParameter::new(
1746 KeyParameterValue::RSAPublicExponent(3),
1747 SecurityLevel::TRUSTED_ENVIRONMENT,
1748 ),
1749 KeyParameter::new(
1750 KeyParameterValue::IncludeUniqueID,
1751 SecurityLevel::TRUSTED_ENVIRONMENT,
1752 ),
1753 KeyParameter::new(KeyParameterValue::BootLoaderOnly, SecurityLevel::STRONGBOX),
1754 KeyParameter::new(KeyParameterValue::RollbackResistance, SecurityLevel::STRONGBOX),
1755 KeyParameter::new(
1756 KeyParameterValue::ActiveDateTime(1234567890),
1757 SecurityLevel::STRONGBOX,
1758 ),
1759 KeyParameter::new(
1760 KeyParameterValue::OriginationExpireDateTime(1234567890),
1761 SecurityLevel::TRUSTED_ENVIRONMENT,
1762 ),
1763 KeyParameter::new(
1764 KeyParameterValue::UsageExpireDateTime(1234567890),
1765 SecurityLevel::TRUSTED_ENVIRONMENT,
1766 ),
1767 KeyParameter::new(
1768 KeyParameterValue::MinSecondsBetweenOps(1234567890),
1769 SecurityLevel::TRUSTED_ENVIRONMENT,
1770 ),
1771 KeyParameter::new(
1772 KeyParameterValue::MaxUsesPerBoot(1234567890),
1773 SecurityLevel::TRUSTED_ENVIRONMENT,
1774 ),
1775 KeyParameter::new(KeyParameterValue::UserID(1), SecurityLevel::STRONGBOX),
1776 KeyParameter::new(KeyParameterValue::UserSecureID(42), SecurityLevel::STRONGBOX),
1777 KeyParameter::new(
1778 KeyParameterValue::NoAuthRequired,
1779 SecurityLevel::TRUSTED_ENVIRONMENT,
1780 ),
1781 KeyParameter::new(
1782 KeyParameterValue::HardwareAuthenticatorType(HardwareAuthenticatorType::PASSWORD),
1783 SecurityLevel::TRUSTED_ENVIRONMENT,
1784 ),
1785 KeyParameter::new(KeyParameterValue::AuthTimeout(1234567890), SecurityLevel::SOFTWARE),
1786 KeyParameter::new(KeyParameterValue::AllowWhileOnBody, SecurityLevel::SOFTWARE),
1787 KeyParameter::new(
1788 KeyParameterValue::TrustedUserPresenceRequired,
1789 SecurityLevel::TRUSTED_ENVIRONMENT,
1790 ),
1791 KeyParameter::new(
1792 KeyParameterValue::TrustedConfirmationRequired,
1793 SecurityLevel::TRUSTED_ENVIRONMENT,
1794 ),
1795 KeyParameter::new(
1796 KeyParameterValue::UnlockedDeviceRequired,
1797 SecurityLevel::TRUSTED_ENVIRONMENT,
1798 ),
1799 KeyParameter::new(
1800 KeyParameterValue::ApplicationID(vec![1u8, 2u8, 3u8, 4u8]),
1801 SecurityLevel::SOFTWARE,
1802 ),
1803 KeyParameter::new(
1804 KeyParameterValue::ApplicationData(vec![4u8, 3u8, 2u8, 1u8]),
1805 SecurityLevel::SOFTWARE,
1806 ),
1807 KeyParameter::new(
1808 KeyParameterValue::CreationDateTime(12345677890),
1809 SecurityLevel::SOFTWARE,
1810 ),
1811 KeyParameter::new(
1812 KeyParameterValue::KeyOrigin(KeyOrigin::GENERATED),
1813 SecurityLevel::TRUSTED_ENVIRONMENT,
1814 ),
1815 KeyParameter::new(
1816 KeyParameterValue::RootOfTrust(vec![3u8, 2u8, 1u8, 4u8]),
1817 SecurityLevel::TRUSTED_ENVIRONMENT,
1818 ),
1819 KeyParameter::new(KeyParameterValue::OSVersion(1), SecurityLevel::TRUSTED_ENVIRONMENT),
1820 KeyParameter::new(KeyParameterValue::OSPatchLevel(2), SecurityLevel::SOFTWARE),
1821 KeyParameter::new(
1822 KeyParameterValue::UniqueID(vec![4u8, 3u8, 1u8, 2u8]),
1823 SecurityLevel::SOFTWARE,
1824 ),
1825 KeyParameter::new(
1826 KeyParameterValue::AttestationChallenge(vec![4u8, 3u8, 1u8, 2u8]),
1827 SecurityLevel::TRUSTED_ENVIRONMENT,
1828 ),
1829 KeyParameter::new(
1830 KeyParameterValue::AttestationApplicationID(vec![4u8, 3u8, 1u8, 2u8]),
1831 SecurityLevel::TRUSTED_ENVIRONMENT,
1832 ),
1833 KeyParameter::new(
1834 KeyParameterValue::AttestationIdBrand(vec![4u8, 3u8, 1u8, 2u8]),
1835 SecurityLevel::TRUSTED_ENVIRONMENT,
1836 ),
1837 KeyParameter::new(
1838 KeyParameterValue::AttestationIdDevice(vec![4u8, 3u8, 1u8, 2u8]),
1839 SecurityLevel::TRUSTED_ENVIRONMENT,
1840 ),
1841 KeyParameter::new(
1842 KeyParameterValue::AttestationIdProduct(vec![4u8, 3u8, 1u8, 2u8]),
1843 SecurityLevel::TRUSTED_ENVIRONMENT,
1844 ),
1845 KeyParameter::new(
1846 KeyParameterValue::AttestationIdSerial(vec![4u8, 3u8, 1u8, 2u8]),
1847 SecurityLevel::TRUSTED_ENVIRONMENT,
1848 ),
1849 KeyParameter::new(
1850 KeyParameterValue::AttestationIdIMEI(vec![4u8, 3u8, 1u8, 2u8]),
1851 SecurityLevel::TRUSTED_ENVIRONMENT,
1852 ),
1853 KeyParameter::new(
1854 KeyParameterValue::AttestationIdMEID(vec![4u8, 3u8, 1u8, 2u8]),
1855 SecurityLevel::TRUSTED_ENVIRONMENT,
1856 ),
1857 KeyParameter::new(
1858 KeyParameterValue::AttestationIdManufacturer(vec![4u8, 3u8, 1u8, 2u8]),
1859 SecurityLevel::TRUSTED_ENVIRONMENT,
1860 ),
1861 KeyParameter::new(
1862 KeyParameterValue::AttestationIdModel(vec![4u8, 3u8, 1u8, 2u8]),
1863 SecurityLevel::TRUSTED_ENVIRONMENT,
1864 ),
1865 KeyParameter::new(
1866 KeyParameterValue::VendorPatchLevel(3),
1867 SecurityLevel::TRUSTED_ENVIRONMENT,
1868 ),
1869 KeyParameter::new(
1870 KeyParameterValue::BootPatchLevel(4),
1871 SecurityLevel::TRUSTED_ENVIRONMENT,
1872 ),
1873 KeyParameter::new(
1874 KeyParameterValue::AssociatedData(vec![4u8, 3u8, 1u8, 2u8]),
1875 SecurityLevel::TRUSTED_ENVIRONMENT,
1876 ),
1877 KeyParameter::new(
1878 KeyParameterValue::Nonce(vec![4u8, 3u8, 1u8, 2u8]),
1879 SecurityLevel::TRUSTED_ENVIRONMENT,
1880 ),
1881 KeyParameter::new(
1882 KeyParameterValue::MacLength(256),
1883 SecurityLevel::TRUSTED_ENVIRONMENT,
1884 ),
1885 KeyParameter::new(
1886 KeyParameterValue::ResetSinceIdRotation,
1887 SecurityLevel::TRUSTED_ENVIRONMENT,
1888 ),
1889 KeyParameter::new(
1890 KeyParameterValue::ConfirmationToken(vec![5u8, 5u8, 5u8, 5u8]),
1891 SecurityLevel::TRUSTED_ENVIRONMENT,
1892 ),
1893 ]
1894 }
1895
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001896 fn make_test_key_entry(
1897 db: &mut KeystoreDB,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001898 domain: Domain,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001899 namespace: i64,
1900 alias: &str,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001901 ) -> Result<KeyIdGuard> {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001902 let key_id = db.create_key_entry(domain, namespace)?;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001903 db.insert_blob(
Janis Danisevskisaec14592020-11-12 09:41:49 -08001904 &key_id,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001905 SubComponentType::KM_BLOB,
1906 TEST_KM_BLOB,
1907 SecurityLevel::TRUSTED_ENVIRONMENT,
1908 )?;
1909 db.insert_blob(
Janis Danisevskisaec14592020-11-12 09:41:49 -08001910 &key_id,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001911 SubComponentType::CERT,
1912 TEST_CERT_BLOB,
1913 SecurityLevel::TRUSTED_ENVIRONMENT,
1914 )?;
1915 db.insert_blob(
Janis Danisevskisaec14592020-11-12 09:41:49 -08001916 &key_id,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001917 SubComponentType::CERT_CHAIN,
1918 TEST_CERT_CHAIN_BLOB,
1919 SecurityLevel::TRUSTED_ENVIRONMENT,
1920 )?;
Janis Danisevskisaec14592020-11-12 09:41:49 -08001921 db.insert_keyparameter(&key_id, &make_test_params())?;
1922 db.rebind_alias(&key_id, alias, domain, namespace)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001923 Ok(key_id)
1924 }
1925
1926 fn debug_dump_keyentry_table(db: &mut KeystoreDB) -> Result<()> {
1927 let mut stmt = db.conn.prepare(
1928 "SELECT id, creation_date, domain, namespace, alias FROM persistent.keyentry;",
1929 )?;
1930 let rows = stmt.query_map::<(i64, i64, i32, i64, String), _, _>(NO_PARAMS, |row| {
1931 Ok((row.get(0)?, row.get(1)?, row.get(2)?, row.get(3)?, row.get(4)?))
1932 })?;
1933
1934 println!("Key entry table rows:");
1935 for r in rows {
1936 let (id, cdate, domain, namespace, alias) = r.unwrap();
1937 println!(
1938 " id: {} Creation date: {} Domain: {} Namespace: {} Alias: {}",
1939 id, cdate, domain, namespace, alias
1940 );
1941 }
1942 Ok(())
1943 }
1944
1945 fn debug_dump_grant_table(db: &mut KeystoreDB) -> Result<()> {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08001946 let mut stmt = db
1947 .conn
1948 .prepare("SELECT id, grantee, keyentryid, access_vector FROM persistent.grant;")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001949 let rows = stmt.query_map::<(i64, i64, i64, i64), _, _>(NO_PARAMS, |row| {
1950 Ok((row.get(0)?, row.get(1)?, row.get(2)?, row.get(3)?))
1951 })?;
1952
1953 println!("Grant table rows:");
1954 for r in rows {
1955 let (id, gt, ki, av) = r.unwrap();
1956 println!(" id: {} grantee: {} key_id: {} access_vector: {}", id, gt, ki, av);
1957 }
1958 Ok(())
1959 }
1960
Joel Galenson0891bc12020-07-20 10:37:03 -07001961 // Use a custom random number generator that repeats each number once.
1962 // This allows us to test repeated elements.
1963
1964 thread_local! {
1965 static RANDOM_COUNTER: RefCell<i64> = RefCell::new(0);
1966 }
1967
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001968 fn reset_random() {
1969 RANDOM_COUNTER.with(|counter| {
1970 *counter.borrow_mut() = 0;
1971 })
1972 }
1973
Joel Galenson0891bc12020-07-20 10:37:03 -07001974 pub fn random() -> i64 {
1975 RANDOM_COUNTER.with(|counter| {
1976 let result = *counter.borrow() / 2;
1977 *counter.borrow_mut() += 1;
1978 result
1979 })
1980 }
Joel Galenson26f4d012020-07-17 14:57:21 -07001981}