blob: 03523ffc18496778cac6528e00679d0799d8d8e1 [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;
Hasini Gunasinghe557b1032020-11-10 01:35:30 +000051use crate::utils::get_current_time_in_seconds;
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};
Hasini Gunasinghe557b1032020-11-10 01:35:30 +000060use anyhow::{anyhow, Context, Result};
Janis Danisevskis60400fe2020-08-26 15:24:42 -070061
Janis Danisevskisaec14592020-11-12 09:41:49 -080062use lazy_static::lazy_static;
Joel Galenson0891bc12020-07-20 10:37:03 -070063#[cfg(not(test))]
64use rand::prelude::random;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -070065use rusqlite::{
Hasini Gunasinghe557b1032020-11-10 01:35:30 +000066 params, types::FromSql, types::FromSqlResult, types::ToSqlOutput, types::Value,
67 types::ValueRef, Connection, OptionalExtension, ToSql, Transaction, TransactionBehavior,
68 NO_PARAMS,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -070069};
Janis Danisevskisaec14592020-11-12 09:41:49 -080070use std::{
71 collections::HashSet,
Janis Danisevskisbf15d732020-12-08 10:35:26 -080072 path::Path,
73 sync::{Condvar, Mutex},
Janis Danisevskisaec14592020-11-12 09:41:49 -080074};
Joel Galenson0891bc12020-07-20 10:37:03 -070075#[cfg(test)]
76use tests::random;
Joel Galenson26f4d012020-07-17 14:57:21 -070077
Janis Danisevskis63f7bc82020-09-03 10:12:56 -070078/// Keys have a KeyMint blob component and optional public certificate and
79/// certificate chain components.
80/// KeyEntryLoadBits is a bitmap that indicates to `KeystoreDB::load_key_entry`
81/// which components shall be loaded from the database if present.
82#[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
83pub struct KeyEntryLoadBits(u32);
84
85impl KeyEntryLoadBits {
86 /// Indicate to `KeystoreDB::load_key_entry` that no component shall be loaded.
87 pub const NONE: KeyEntryLoadBits = Self(0);
88 /// Indicate to `KeystoreDB::load_key_entry` that the KeyMint component shall be loaded.
89 pub const KM: KeyEntryLoadBits = Self(1);
90 /// Indicate to `KeystoreDB::load_key_entry` that the Public components shall be loaded.
91 pub const PUBLIC: KeyEntryLoadBits = Self(2);
92 /// Indicate to `KeystoreDB::load_key_entry` that both components shall be loaded.
93 pub const BOTH: KeyEntryLoadBits = Self(3);
94
95 /// Returns true if this object indicates that the public components shall be loaded.
96 pub const fn load_public(&self) -> bool {
97 self.0 & Self::PUBLIC.0 != 0
98 }
99
100 /// Returns true if the object indicates that the KeyMint component shall be loaded.
101 pub const fn load_km(&self) -> bool {
102 self.0 & Self::KM.0 != 0
103 }
104}
105
Janis Danisevskisaec14592020-11-12 09:41:49 -0800106lazy_static! {
107 static ref KEY_ID_LOCK: KeyIdLockDb = KeyIdLockDb::new();
108}
109
110struct KeyIdLockDb {
111 locked_keys: Mutex<HashSet<i64>>,
112 cond_var: Condvar,
113}
114
115/// A locked key. While a guard exists for a given key id, the same key cannot be loaded
116/// from the database a second time. Most functions manipulating the key blob database
117/// require a KeyIdGuard.
118#[derive(Debug)]
119pub struct KeyIdGuard(i64);
120
121impl KeyIdLockDb {
122 fn new() -> Self {
123 Self { locked_keys: Mutex::new(HashSet::new()), cond_var: Condvar::new() }
124 }
125
126 /// This function blocks until an exclusive lock for the given key entry id can
127 /// be acquired. It returns a guard object, that represents the lifecycle of the
128 /// acquired lock.
129 pub fn get(&self, key_id: i64) -> KeyIdGuard {
130 let mut locked_keys = self.locked_keys.lock().unwrap();
131 while locked_keys.contains(&key_id) {
132 locked_keys = self.cond_var.wait(locked_keys).unwrap();
133 }
134 locked_keys.insert(key_id);
135 KeyIdGuard(key_id)
136 }
137
138 /// This function attempts to acquire an exclusive lock on a given key id. If the
139 /// given key id is already taken the function returns None immediately. If a lock
140 /// can be acquired this function returns a guard object, that represents the
141 /// lifecycle of the acquired lock.
142 pub fn try_get(&self, key_id: i64) -> Option<KeyIdGuard> {
143 let mut locked_keys = self.locked_keys.lock().unwrap();
144 if locked_keys.insert(key_id) {
145 Some(KeyIdGuard(key_id))
146 } else {
147 None
148 }
149 }
150}
151
152impl KeyIdGuard {
153 /// Get the numeric key id of the locked key.
154 pub fn id(&self) -> i64 {
155 self.0
156 }
157}
158
159impl Drop for KeyIdGuard {
160 fn drop(&mut self) {
161 let mut locked_keys = KEY_ID_LOCK.locked_keys.lock().unwrap();
162 locked_keys.remove(&self.0);
Janis Danisevskis7fd53582020-11-23 13:40:34 -0800163 drop(locked_keys);
Janis Danisevskisaec14592020-11-12 09:41:49 -0800164 KEY_ID_LOCK.cond_var.notify_all();
165 }
166}
167
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700168/// This type represents a Keystore 2.0 key entry.
169/// An entry has a unique `id` by which it can be found in the database.
170/// It has a security level field, key parameters, and three optional fields
171/// for the KeyMint blob, public certificate and a public certificate chain.
Janis Danisevskisaec14592020-11-12 09:41:49 -0800172#[derive(Debug, Default, Eq, PartialEq, Ord, PartialOrd)]
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700173pub struct KeyEntry {
174 id: i64,
175 km_blob: Option<Vec<u8>>,
176 cert: Option<Vec<u8>>,
177 cert_chain: Option<Vec<u8>>,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700178 sec_level: SecurityLevel,
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700179 parameters: Vec<KeyParameter>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700180}
181
182impl KeyEntry {
183 /// Returns the unique id of the Key entry.
184 pub fn id(&self) -> i64 {
185 self.id
186 }
187 /// Exposes the optional KeyMint blob.
188 pub fn km_blob(&self) -> &Option<Vec<u8>> {
189 &self.km_blob
190 }
191 /// Extracts the Optional KeyMint blob.
192 pub fn take_km_blob(&mut self) -> Option<Vec<u8>> {
193 self.km_blob.take()
194 }
195 /// Exposes the optional public certificate.
196 pub fn cert(&self) -> &Option<Vec<u8>> {
197 &self.cert
198 }
199 /// Extracts the optional public certificate.
200 pub fn take_cert(&mut self) -> Option<Vec<u8>> {
201 self.cert.take()
202 }
203 /// Exposes the optional public certificate chain.
204 pub fn cert_chain(&self) -> &Option<Vec<u8>> {
205 &self.cert_chain
206 }
207 /// Extracts the optional public certificate_chain.
208 pub fn take_cert_chain(&mut self) -> Option<Vec<u8>> {
209 self.cert_chain.take()
210 }
211 /// Returns the security level of the key entry.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700212 pub fn sec_level(&self) -> SecurityLevel {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700213 self.sec_level
214 }
Janis Danisevskis04b02832020-10-26 09:21:40 -0700215 /// Exposes the key parameters of this key entry.
216 pub fn key_parameters(&self) -> &Vec<KeyParameter> {
217 &self.parameters
218 }
219 /// Consumes this key entry and extracts the keyparameters from it.
220 pub fn into_key_parameters(self) -> Vec<KeyParameter> {
221 self.parameters
222 }
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700223}
224
225/// Indicates the sub component of a key entry for persistent storage.
226#[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
227pub struct SubComponentType(u32);
228impl SubComponentType {
229 /// Persistent identifier for a KeyMint blob.
230 pub const KM_BLOB: SubComponentType = Self(0);
231 /// Persistent identifier for a certificate blob.
232 pub const CERT: SubComponentType = Self(1);
233 /// Persistent identifier for a certificate chain blob.
234 pub const CERT_CHAIN: SubComponentType = Self(2);
235}
236
237impl ToSql for SubComponentType {
238 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
239 self.0.to_sql()
240 }
241}
242
243impl FromSql for SubComponentType {
244 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
245 Ok(Self(u32::column_result(value)?))
246 }
247}
248
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700249/// KeystoreDB wraps a connection to an SQLite database and tracks its
250/// ownership. It also implements all of Keystore 2.0's database functionality.
Joel Galenson26f4d012020-07-17 14:57:21 -0700251pub struct KeystoreDB {
Joel Galenson26f4d012020-07-17 14:57:21 -0700252 conn: Connection,
253}
254
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000255/// Database representation of the monotonic time retrieved from the system call clock_gettime with
256/// CLOCK_MONOTONIC_RAW. Stores monotonic time as i64 in seconds.
257#[derive(Debug, Copy, Clone, Default, Eq, PartialEq, Ord, PartialOrd)]
258pub struct MonotonicRawTime(i64);
259
260impl MonotonicRawTime {
261 /// Constructs a new MonotonicRawTime
262 pub fn now() -> Self {
263 Self(get_current_time_in_seconds())
264 }
265
266 /// Returns the integer value of MonotonicRawTime as i64
267 pub fn seconds(&self) -> i64 {
268 self.0
269 }
270}
271
272impl ToSql for MonotonicRawTime {
273 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
274 Ok(ToSqlOutput::Owned(Value::Integer(self.0)))
275 }
276}
277
278impl FromSql for MonotonicRawTime {
279 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
280 Ok(Self(i64::column_result(value)?))
281 }
282}
283
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000284/// This struct encapsulates the information to be stored in the database about the auth tokens
285/// received by keystore.
286pub struct AuthTokenEntry {
287 auth_token: HardwareAuthToken,
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000288 time_received: MonotonicRawTime,
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000289}
290
291impl AuthTokenEntry {
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000292 fn new(auth_token: HardwareAuthToken, time_received: MonotonicRawTime) -> Self {
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000293 AuthTokenEntry { auth_token, time_received }
294 }
295
296 /// Checks if this auth token satisfies the given authentication information.
297 pub fn satisfies_auth(
298 auth_token: &HardwareAuthToken,
299 user_secure_ids: &[i64],
300 auth_type: HardwareAuthenticatorType,
301 ) -> bool {
302 user_secure_ids.iter().any(|&sid| {
303 (sid == auth_token.userId || sid == auth_token.authenticatorId)
304 && (((auth_type.0 as i32) & (auth_token.authenticatorType.0 as i32)) != 0)
305 })
306 }
307
308 fn is_newer_than(&self, other: &AuthTokenEntry) -> bool {
309 // NOTE: Although in legacy keystore both timestamp and time_received are involved in this
310 // check, we decided to only consider time_received in keystore2 code.
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000311 self.time_received.seconds() > other.time_received.seconds()
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000312 }
313
314 /// Returns the auth token wrapped by the AuthTokenEntry
315 pub fn get_auth_token(self) -> HardwareAuthToken {
316 self.auth_token
317 }
318}
319
Joel Galenson26f4d012020-07-17 14:57:21 -0700320impl KeystoreDB {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700321 /// This will create a new database connection connecting the two
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800322 /// files persistent.sqlite and perboot.sqlite in the given directory.
323 /// It also attempts to initialize all of the tables.
324 /// KeystoreDB cannot be used by multiple threads.
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700325 /// Each thread should open their own connection using `thread_local!`.
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800326 pub fn new(db_root: &Path) -> Result<Self> {
327 // Build the path to the sqlite files.
328 let mut persistent_path = db_root.to_path_buf();
329 persistent_path.push("persistent.sqlite");
330 let mut perboot_path = db_root.to_path_buf();
331 perboot_path.push("perboot.sqlite");
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700332
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800333 // Now convert them to strings prefixed with "file:"
334 let mut persistent_path_str = "file:".to_owned();
335 persistent_path_str.push_str(&persistent_path.to_string_lossy());
336 let mut perboot_path_str = "file:".to_owned();
337 perboot_path_str.push_str(&perboot_path.to_string_lossy());
338
339 let conn = Self::make_connection(&persistent_path_str, &perboot_path_str)?;
340
341 Self::init_tables(&conn)?;
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700342 Ok(Self { conn })
Joel Galenson2aab4432020-07-22 15:27:57 -0700343 }
344
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700345 fn init_tables(conn: &Connection) -> Result<()> {
346 conn.execute(
347 "CREATE TABLE IF NOT EXISTS persistent.keyentry (
Joel Galenson0891bc12020-07-20 10:37:03 -0700348 id INTEGER UNIQUE,
349 creation_date DATETIME,
350 domain INTEGER,
351 namespace INTEGER,
Joel Galenson319bb652020-12-01 13:24:08 -0800352 alias BLOB);",
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700353 NO_PARAMS,
354 )
355 .context("Failed to initialize \"keyentry\" table.")?;
356
357 conn.execute(
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700358 "CREATE VIEW IF NOT EXISTS persistent.orphaned AS
359 SELECT id FROM persistent.keyentry WHERE domain IS NULL;",
360 NO_PARAMS,
361 )
362 .context("Failed to initialize \"orphaned\" view")?;
363
364 conn.execute(
365 "CREATE TABLE IF NOT EXISTS persistent.blobentry (
366 id INTEGER PRIMARY KEY,
367 subcomponent_type INTEGER,
368 keyentryid INTEGER,
369 blob BLOB,
370 sec_level INTEGER);",
371 NO_PARAMS,
372 )
373 .context("Failed to initialize \"blobentry\" table.")?;
374
375 conn.execute(
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700376 "CREATE TABLE IF NOT EXISTS persistent.keyparameter (
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000377 keyentryid INTEGER,
378 tag INTEGER,
379 data ANY,
380 security_level INTEGER);",
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700381 NO_PARAMS,
382 )
383 .context("Failed to initialize \"keyparameter\" table.")?;
384
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700385 conn.execute(
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800386 "CREATE TABLE IF NOT EXISTS persistent.grant (
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700387 id INTEGER UNIQUE,
388 grantee INTEGER,
389 keyentryid INTEGER,
390 access_vector INTEGER);",
391 NO_PARAMS,
392 )
393 .context("Failed to initialize \"grant\" table.")?;
394
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000395 //TODO: only drop the following two perboot tables if this is the first start up
396 //during the boot (b/175716626).
397 // conn.execute("DROP TABLE IF EXISTS perboot.authtoken;", NO_PARAMS)
398 // .context("Failed to drop perboot.authtoken table")?;
399 conn.execute(
400 "CREATE TABLE IF NOT EXISTS perboot.authtoken (
401 id INTEGER PRIMARY KEY,
402 challenge INTEGER,
403 user_id INTEGER,
404 auth_id INTEGER,
405 authenticator_type INTEGER,
406 timestamp INTEGER,
407 mac BLOB,
408 time_received INTEGER,
409 UNIQUE(user_id, auth_id, authenticator_type));",
410 NO_PARAMS,
411 )
412 .context("Failed to initialize \"authtoken\" table.")?;
413
414 // conn.execute("DROP TABLE IF EXISTS perboot.metadata;", NO_PARAMS)
415 // .context("Failed to drop perboot.metadata table")?;
416 // metadata table stores certain miscellaneous information required for keystore functioning
417 // during a boot cycle, as key-value pairs.
418 conn.execute(
419 "CREATE TABLE IF NOT EXISTS perboot.metadata (
420 key TEXT,
421 value BLOB,
422 UNIQUE(key));",
423 NO_PARAMS,
424 )
425 .context("Failed to initialize \"metadata\" table.")?;
426
Joel Galenson0891bc12020-07-20 10:37:03 -0700427 Ok(())
428 }
429
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700430 fn make_connection(persistent_file: &str, perboot_file: &str) -> Result<Connection> {
431 let conn =
432 Connection::open_in_memory().context("Failed to initialize SQLite connection.")?;
433
434 conn.execute("ATTACH DATABASE ? as persistent;", params![persistent_file])
435 .context("Failed to attach database persistent.")?;
436 conn.execute("ATTACH DATABASE ? as perboot;", params![perboot_file])
437 .context("Failed to attach database perboot.")?;
438
439 Ok(conn)
440 }
441
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700442 /// Creates a new key entry and allocates a new randomized id for the new key.
443 /// The key id gets associated with a domain and namespace but not with an alias.
444 /// To complete key generation `rebind_alias` should be called after all of the
445 /// key artifacts, i.e., blobs and parameters have been associated with the new
446 /// key id. Finalizing with `rebind_alias` makes the creation of a new key entry
447 /// atomic even if key generation is not.
Janis Danisevskisaec14592020-11-12 09:41:49 -0800448 pub fn create_key_entry(&self, domain: Domain, namespace: i64) -> Result<KeyIdGuard> {
Joel Galenson0891bc12020-07-20 10:37:03 -0700449 match domain {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700450 Domain::APP | Domain::SELINUX => {}
Joel Galenson0891bc12020-07-20 10:37:03 -0700451 _ => {
452 return Err(KsError::sys())
453 .context(format!("Domain {:?} must be either App or SELinux.", domain));
454 }
455 }
Janis Danisevskisaec14592020-11-12 09:41:49 -0800456 Ok(KEY_ID_LOCK.get(
457 Self::insert_with_retry(|id| {
458 self.conn.execute(
459 "INSERT into persistent.keyentry (id, creation_date, domain, namespace, alias)
Joel Galenson0891bc12020-07-20 10:37:03 -0700460 VALUES(?, datetime('now'), ?, ?, NULL);",
Janis Danisevskisaec14592020-11-12 09:41:49 -0800461 params![id, domain.0 as u32, namespace],
462 )
463 })
464 .context("In create_key_entry")?,
465 ))
Joel Galenson26f4d012020-07-17 14:57:21 -0700466 }
Joel Galenson33c04ad2020-08-03 11:04:38 -0700467
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700468 /// Inserts a new blob and associates it with the given key id. Each blob
469 /// has a sub component type and a security level.
470 /// Each key can have one of each sub component type associated. If more
471 /// are added only the most recent can be retrieved, and superseded blobs
472 /// will get garbage collected. The security level field of components
473 /// other than `SubComponentType::KM_BLOB` are ignored.
474 pub fn insert_blob(
475 &mut self,
Janis Danisevskisaec14592020-11-12 09:41:49 -0800476 key_id: &KeyIdGuard,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700477 sc_type: SubComponentType,
478 blob: &[u8],
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700479 sec_level: SecurityLevel,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700480 ) -> Result<()> {
481 self.conn
482 .execute(
483 "INSERT into persistent.blobentry (subcomponent_type, keyentryid, blob, sec_level)
484 VALUES (?, ?, ?, ?);",
Janis Danisevskisaec14592020-11-12 09:41:49 -0800485 params![sc_type, key_id.0, blob, sec_level.0],
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700486 )
487 .context("Failed to insert blob.")?;
488 Ok(())
489 }
490
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700491 /// Inserts a collection of key parameters into the `persistent.keyparameter` table
492 /// and associates them with the given `key_id`.
493 pub fn insert_keyparameter<'a>(
494 &mut self,
Janis Danisevskisaec14592020-11-12 09:41:49 -0800495 key_id: &KeyIdGuard,
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700496 params: impl IntoIterator<Item = &'a KeyParameter>,
497 ) -> Result<()> {
Janis Danisevskise92a5e62020-12-02 12:57:41 -0800498 let tx = self
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700499 .conn
Janis Danisevskise92a5e62020-12-02 12:57:41 -0800500 .transaction_with_behavior(TransactionBehavior::Immediate)
501 .context("In insert_keyparameter: Failed to start transaction.")?;
502 {
503 let mut stmt = tx
504 .prepare(
505 "INSERT into persistent.keyparameter (keyentryid, tag, data, security_level)
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700506 VALUES (?, ?, ?, ?);",
Janis Danisevskise92a5e62020-12-02 12:57:41 -0800507 )
508 .context("In insert_keyparameter: Failed to prepare statement.")?;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700509
Janis Danisevskise92a5e62020-12-02 12:57:41 -0800510 let iter = params.into_iter();
511 for p in iter {
512 stmt.insert(params![
513 key_id.0,
514 p.get_tag().0,
515 p.key_parameter_value(),
516 p.security_level().0
517 ])
518 .with_context(|| format!("In insert_keyparameter: Failed to insert {:?}", p))?;
519 }
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700520 }
Janis Danisevskise92a5e62020-12-02 12:57:41 -0800521 tx.commit().context("In insert_keyparameter: Failed to commit transaction.")?;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700522 Ok(())
523 }
524
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700525 /// Updates the alias column of the given key id `newid` with the given alias,
526 /// and atomically, removes the alias, domain, and namespace from another row
527 /// with the same alias-domain-namespace tuple if such row exits.
Joel Galenson33c04ad2020-08-03 11:04:38 -0700528 pub fn rebind_alias(
529 &mut self,
Janis Danisevskisaec14592020-11-12 09:41:49 -0800530 newid: &KeyIdGuard,
Joel Galenson33c04ad2020-08-03 11:04:38 -0700531 alias: &str,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700532 domain: Domain,
Joel Galenson33c04ad2020-08-03 11:04:38 -0700533 namespace: i64,
534 ) -> Result<()> {
535 match domain {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700536 Domain::APP | Domain::SELINUX => {}
Joel Galenson33c04ad2020-08-03 11:04:38 -0700537 _ => {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700538 return Err(KsError::sys()).context(format!(
539 "In rebind_alias: Domain {:?} must be either App or SELinux.",
540 domain
541 ));
Joel Galenson33c04ad2020-08-03 11:04:38 -0700542 }
543 }
544 let tx = self
545 .conn
546 .transaction_with_behavior(TransactionBehavior::Immediate)
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700547 .context("In rebind_alias: Failed to initialize transaction.")?;
Joel Galenson33c04ad2020-08-03 11:04:38 -0700548 tx.execute(
549 "UPDATE persistent.keyentry
550 SET alias = NULL, domain = NULL, namespace = NULL
551 WHERE alias = ? AND domain = ? AND namespace = ?;",
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700552 params![alias, domain.0 as u32, namespace],
Joel Galenson33c04ad2020-08-03 11:04:38 -0700553 )
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700554 .context("In rebind_alias: Failed to rebind existing entry.")?;
Joel Galenson33c04ad2020-08-03 11:04:38 -0700555 let result = tx
556 .execute(
557 "UPDATE persistent.keyentry
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700558 SET alias = ?
559 WHERE id = ? AND domain = ? AND namespace = ?;",
Janis Danisevskisaec14592020-11-12 09:41:49 -0800560 params![alias, newid.0, domain.0 as u32, namespace],
Joel Galenson33c04ad2020-08-03 11:04:38 -0700561 )
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700562 .context("In rebind_alias: Failed to set alias.")?;
Joel Galenson33c04ad2020-08-03 11:04:38 -0700563 if result != 1 {
564 // Note that this explicit rollback is not required, as
565 // the transaction should rollback if we do not commit it.
566 // We leave it here for readability.
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700567 tx.rollback().context("In rebind_alias: Failed to rollback a failed transaction.")?;
Joel Galenson33c04ad2020-08-03 11:04:38 -0700568 return Err(KsError::sys()).context(format!(
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700569 "In rebind_alias: Expected to update a single entry but instead updated {}.",
Joel Galenson33c04ad2020-08-03 11:04:38 -0700570 result
571 ));
572 }
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700573 tx.commit().context("In rebind_alias: Failed to commit transaction.")
574 }
575
576 // Helper function loading the key_id given the key descriptor
577 // tuple comprising domain, namespace, and alias.
578 // Requires a valid transaction.
579 fn load_key_entry_id(key: &KeyDescriptor, tx: &Transaction) -> Result<i64> {
580 let alias = key
581 .alias
582 .as_ref()
583 .map_or_else(|| Err(KsError::sys()), Ok)
584 .context("In load_key_entry_id: Alias must be specified.")?;
585 let mut stmt = tx
586 .prepare(
587 "SELECT id FROM persistent.keyentry
588 WHERE
589 domain = ?
590 AND namespace = ?
591 AND alias = ?;",
592 )
593 .context("In load_key_entry_id: Failed to select from keyentry table.")?;
594 let mut rows = stmt
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700595 .query(params![key.domain.0 as u32, key.nspace, alias])
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700596 .context("In load_key_entry_id: Failed to read from keyentry table.")?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800597 db_utils::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700598 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700599 .get(0)
600 .context("Failed to unpack id.")
601 })
602 .context("In load_key_entry_id.")
603 }
604
605 /// This helper function completes the access tuple of a key, which is required
606 /// to perform access control. The strategy depends on the `domain` field in the
607 /// key descriptor.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700608 /// * Domain::SELINUX: The access tuple is complete and this function only loads
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700609 /// the key_id for further processing.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700610 /// * Domain::APP: Like Domain::SELINUX, but the tuple is completed by `caller_uid`
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700611 /// which serves as the namespace.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700612 /// * Domain::GRANT: The grant table is queried for the `key_id` and the
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700613 /// `access_vector`.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700614 /// * Domain::KEY_ID: The keyentry table is queried for the owning `domain` and
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700615 /// `namespace`.
616 /// In each case the information returned is sufficient to perform the access
617 /// check and the key id can be used to load further key artifacts.
618 fn load_access_tuple(
619 tx: &Transaction,
620 key: KeyDescriptor,
621 caller_uid: u32,
622 ) -> Result<(i64, KeyDescriptor, Option<KeyPermSet>)> {
623 match key.domain {
624 // Domain App or SELinux. In this case we load the key_id from
625 // the keyentry database for further loading of key components.
626 // We already have the full access tuple to perform access control.
627 // The only distinction is that we use the caller_uid instead
628 // of the caller supplied namespace if the domain field is
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700629 // Domain::APP.
630 Domain::APP | Domain::SELINUX => {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700631 let mut access_key = key;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700632 if access_key.domain == Domain::APP {
633 access_key.nspace = caller_uid as i64;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700634 }
635 let key_id = Self::load_key_entry_id(&access_key, &tx)
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700636 .with_context(|| format!("With key.domain = {:?}.", access_key.domain))?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700637
638 Ok((key_id, access_key, None))
639 }
640
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700641 // Domain::GRANT. In this case we load the key_id and the access_vector
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700642 // from the grant table.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700643 Domain::GRANT => {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700644 let mut stmt = tx
645 .prepare(
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800646 "SELECT keyentryid, access_vector FROM persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700647 WHERE grantee = ? AND id = ?;",
648 )
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700649 .context("Domain::GRANT prepare statement failed")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700650 let mut rows = stmt
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700651 .query(params![caller_uid as i64, key.nspace])
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700652 .context("Domain:Grant: query failed.")?;
653 let (key_id, access_vector): (i64, i32) =
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800654 db_utils::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700655 let r =
656 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700657 Ok((
658 r.get(0).context("Failed to unpack key_id.")?,
659 r.get(1).context("Failed to unpack access_vector.")?,
660 ))
661 })
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700662 .context("Domain::GRANT.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700663 Ok((key_id, key, Some(access_vector.into())))
664 }
665
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700666 // Domain::KEY_ID. In this case we load the domain and namespace from the
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700667 // keyentry database because we need them for access control.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700668 Domain::KEY_ID => {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700669 let mut stmt = tx
670 .prepare(
671 "SELECT domain, namespace FROM persistent.keyentry
672 WHERE
673 id = ?;",
674 )
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700675 .context("Domain::KEY_ID: prepare statement failed")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700676 let mut rows =
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700677 stmt.query(params![key.nspace]).context("Domain::KEY_ID: query failed.")?;
678 let (domain, namespace): (Domain, i64) =
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800679 db_utils::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700680 let r =
681 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700682 Ok((
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700683 Domain(r.get(0).context("Failed to unpack domain.")?),
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700684 r.get(1).context("Failed to unpack namespace.")?,
685 ))
686 })
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700687 .context("Domain::KEY_ID.")?;
688 let key_id = key.nspace;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700689 let mut access_key = key;
690 access_key.domain = domain;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700691 access_key.nspace = namespace;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700692
693 Ok((key_id, access_key, None))
694 }
695 _ => Err(anyhow!(KsError::sys())),
696 }
697 }
698
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700699 fn load_blob_components(
700 key_id: i64,
701 load_bits: KeyEntryLoadBits,
702 tx: &Transaction,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700703 ) -> Result<(SecurityLevel, Option<Vec<u8>>, Option<Vec<u8>>, Option<Vec<u8>>)> {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700704 let mut stmt = tx
705 .prepare(
706 "SELECT MAX(id), sec_level, subcomponent_type, blob FROM persistent.blobentry
707 WHERE keyentryid = ? GROUP BY subcomponent_type;",
708 )
709 .context("In load_blob_components: prepare statement failed.")?;
710
711 let mut rows =
712 stmt.query(params![key_id]).context("In load_blob_components: query failed.")?;
713
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700714 let mut sec_level: SecurityLevel = Default::default();
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700715 let mut km_blob: Option<Vec<u8>> = None;
716 let mut cert_blob: Option<Vec<u8>> = None;
717 let mut cert_chain_blob: Option<Vec<u8>> = None;
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800718 db_utils::with_rows_extract_all(&mut rows, |row| {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700719 let sub_type: SubComponentType =
720 row.get(2).context("Failed to extract subcomponent_type.")?;
721 match (sub_type, load_bits.load_public()) {
722 (SubComponentType::KM_BLOB, _) => {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700723 sec_level =
724 SecurityLevel(row.get(1).context("Failed to extract security level.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700725 if load_bits.load_km() {
726 km_blob = Some(row.get(3).context("Failed to extract KM blob.")?);
727 }
728 }
729 (SubComponentType::CERT, true) => {
730 cert_blob =
731 Some(row.get(3).context("Failed to extract public certificate blob.")?);
732 }
733 (SubComponentType::CERT_CHAIN, true) => {
734 cert_chain_blob =
735 Some(row.get(3).context("Failed to extract certificate chain blob.")?);
736 }
737 (SubComponentType::CERT, _) | (SubComponentType::CERT_CHAIN, _) => {}
738 _ => Err(KsError::sys()).context("Unknown subcomponent type.")?,
739 }
740 Ok(())
741 })
742 .context("In load_blob_components.")?;
743
744 Ok((sec_level, km_blob, cert_blob, cert_chain_blob))
745 }
746
747 fn load_key_parameters(key_id: i64, tx: &Transaction) -> Result<Vec<KeyParameter>> {
748 let mut stmt = tx
749 .prepare(
750 "SELECT tag, data, security_level from persistent.keyparameter
751 WHERE keyentryid = ?;",
752 )
753 .context("In load_key_parameters: prepare statement failed.")?;
754
755 let mut parameters: Vec<KeyParameter> = Vec::new();
756
757 let mut rows =
758 stmt.query(params![key_id]).context("In load_key_parameters: query failed.")?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800759 db_utils::with_rows_extract_all(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700760 let tag = Tag(row.get(0).context("Failed to read tag.")?);
761 let sec_level = SecurityLevel(row.get(2).context("Failed to read sec_level.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700762 parameters.push(
763 KeyParameter::new_from_sql(tag, &SqlField::new(1, &row), sec_level)
764 .context("Failed to read KeyParameter.")?,
765 );
766 Ok(())
767 })
768 .context("In load_key_parameters.")?;
769
770 Ok(parameters)
771 }
772
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700773 /// Load a key entry by the given key descriptor.
774 /// It uses the `check_permission` callback to verify if the access is allowed
775 /// given the key access tuple read from the database using `load_access_tuple`.
776 /// With `load_bits` the caller may specify which blobs shall be loaded from
777 /// the blob database.
778 pub fn load_key_entry(
779 &mut self,
780 key: KeyDescriptor,
781 load_bits: KeyEntryLoadBits,
782 caller_uid: u32,
783 check_permission: impl FnOnce(&KeyDescriptor, Option<KeyPermSet>) -> Result<()>,
Janis Danisevskisaec14592020-11-12 09:41:49 -0800784 ) -> Result<(KeyIdGuard, KeyEntry)> {
785 // KEY ID LOCK 1/2
786 // If we got a key descriptor with a key id we can get the lock right away.
787 // Otherwise we have to defer it until we know the key id.
788 let key_id_guard = match key.domain {
789 Domain::KEY_ID => Some(KEY_ID_LOCK.get(key.nspace)),
790 _ => None,
791 };
792
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700793 let tx = self
794 .conn
Janis Danisevskisaec14592020-11-12 09:41:49 -0800795 .unchecked_transaction()
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700796 .context("In load_key_entry: Failed to initialize transaction.")?;
797
798 // Load the key_id and complete the access control tuple.
799 let (key_id, access_key_descriptor, access_vector) =
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700800 Self::load_access_tuple(&tx, key, caller_uid).context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700801
802 // Perform access control. It is vital that we return here if the permission is denied.
803 // So do not touch that '?' at the end.
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700804 check_permission(&access_key_descriptor, access_vector).context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700805
Janis Danisevskisaec14592020-11-12 09:41:49 -0800806 // KEY ID LOCK 2/2
807 // If we did not get a key id lock by now, it was because we got a key descriptor
808 // without a key id. At this point we got the key id, so we can try and get a lock.
809 // However, we cannot block here, because we are in the middle of the transaction.
810 // So first we try to get the lock non blocking. If that fails, we roll back the
811 // transaction and block until we get the lock. After we successfully got the lock,
812 // we start a new transaction and load the access tuple again.
813 //
814 // We don't need to perform access control again, because we already established
815 // that the caller had access to the given key. But we need to make sure that the
816 // key id still exists. So we have to load the key entry by key id this time.
817 let (key_id_guard, tx) = match key_id_guard {
818 None => match KEY_ID_LOCK.try_get(key_id) {
819 None => {
820 // Roll back the transaction.
821 tx.rollback().context("In load_key_entry: Failed to roll back transaction.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700822
Janis Danisevskisaec14592020-11-12 09:41:49 -0800823 // Block until we have a key id lock.
824 let key_id_guard = KEY_ID_LOCK.get(key_id);
825
826 // Create a new transaction.
827 let tx = self.conn.unchecked_transaction().context(
828 "In load_key_entry: Failed to initialize transaction. (deferred key lock)",
829 )?;
830
831 Self::load_access_tuple(
832 &tx,
833 // This time we have to load the key by the retrieved key id, because the
834 // alias may have been rebound after we rolled back the transaction.
835 KeyDescriptor {
836 domain: Domain::KEY_ID,
837 nspace: key_id,
838 ..Default::default()
839 },
840 caller_uid,
841 )
842 .context("In load_key_entry. (deferred key lock)")?;
843 (key_id_guard, tx)
844 }
845 Some(l) => (l, tx),
846 },
847 Some(key_id_guard) => (key_id_guard, tx),
848 };
849
850 let (sec_level, km_blob, cert_blob, cert_chain_blob) =
851 Self::load_blob_components(key_id_guard.id(), load_bits, &tx)
852 .context("In load_key_entry.")?;
853
854 let parameters =
855 Self::load_key_parameters(key_id_guard.id(), &tx).context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700856
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700857 tx.commit().context("In load_key_entry: Failed to commit transaction.")?;
858
Janis Danisevskisaec14592020-11-12 09:41:49 -0800859 let key_id = key_id_guard.id();
860 Ok((
861 key_id_guard,
862 KeyEntry {
863 id: key_id,
864 km_blob,
865 cert: cert_blob,
866 cert_chain: cert_chain_blob,
867 sec_level,
868 parameters,
869 },
870 ))
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700871 }
872
Janis Danisevskise92a5e62020-12-02 12:57:41 -0800873 /// Returns a list of KeyDescriptors in the selected domain/namespace.
874 /// The key descriptors will have the domain, nspace, and alias field set.
875 /// Domain must be APP or SELINUX, the caller must make sure of that.
876 pub fn list(&mut self, domain: Domain, namespace: i64) -> Result<Vec<KeyDescriptor>> {
877 let mut stmt = self
878 .conn
879 .prepare(
880 "SELECT alias FROM persistent.keyentry
881 WHERE domain = ? AND namespace = ? AND alias IS NOT NULL;",
882 )
883 .context("In list: Failed to prepare.")?;
884
885 let mut rows =
886 stmt.query(params![domain.0 as u32, namespace]).context("In list: Failed to query.")?;
887
888 let mut descriptors: Vec<KeyDescriptor> = Vec::new();
889 db_utils::with_rows_extract_all(&mut rows, |row| {
890 descriptors.push(KeyDescriptor {
891 domain,
892 nspace: namespace,
893 alias: Some(row.get(0).context("Trying to extract alias.")?),
894 blob: None,
895 });
896 Ok(())
897 })
898 .context("In list.")?;
899 Ok(descriptors)
900 }
901
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700902 /// Adds a grant to the grant table.
903 /// Like `load_key_entry` this function loads the access tuple before
904 /// it uses the callback for a permission check. Upon success,
905 /// it inserts the `grantee_uid`, `key_id`, and `access_vector` into the
906 /// grant table. The new row will have a randomized id, which is used as
907 /// grant id in the namespace field of the resulting KeyDescriptor.
908 pub fn grant(
909 &mut self,
910 key: KeyDescriptor,
911 caller_uid: u32,
912 grantee_uid: u32,
913 access_vector: KeyPermSet,
914 check_permission: impl FnOnce(&KeyDescriptor, &KeyPermSet) -> Result<()>,
915 ) -> Result<KeyDescriptor> {
916 let tx = self
917 .conn
918 .transaction_with_behavior(TransactionBehavior::Immediate)
919 .context("In grant: Failed to initialize transaction.")?;
920
921 // Load the key_id and complete the access control tuple.
922 // We ignore the access vector here because grants cannot be granted.
923 // The access vector returned here expresses the permissions the
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700924 // grantee has if key.domain == Domain::GRANT. But this vector
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700925 // cannot include the grant permission by design, so there is no way the
926 // subsequent permission check can pass.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700927 // We could check key.domain == Domain::GRANT and fail early.
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700928 // But even if we load the access tuple by grant here, the permission
929 // check denies the attempt to create a grant by grant descriptor.
930 let (key_id, access_key_descriptor, _) =
931 Self::load_access_tuple(&tx, key, caller_uid).context("In grant")?;
932
933 // Perform access control. It is vital that we return here if the permission
934 // was denied. So do not touch that '?' at the end of the line.
935 // This permission check checks if the caller has the grant permission
936 // for the given key and in addition to all of the permissions
937 // expressed in `access_vector`.
938 check_permission(&access_key_descriptor, &access_vector)
939 .context("In grant: check_permission failed.")?;
940
941 let grant_id = if let Some(grant_id) = tx
942 .query_row(
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800943 "SELECT id FROM persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700944 WHERE keyentryid = ? AND grantee = ?;",
945 params![key_id, grantee_uid],
946 |row| row.get(0),
947 )
948 .optional()
949 .context("In grant: Failed get optional existing grant id.")?
950 {
951 tx.execute(
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800952 "UPDATE persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700953 SET access_vector = ?
954 WHERE id = ?;",
955 params![i32::from(access_vector), grant_id],
956 )
957 .context("In grant: Failed to update existing grant.")?;
958 grant_id
959 } else {
Joel Galenson845f74b2020-09-09 14:11:55 -0700960 Self::insert_with_retry(|id| {
961 tx.execute(
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800962 "INSERT INTO persistent.grant (id, grantee, keyentryid, access_vector)
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700963 VALUES (?, ?, ?, ?);",
Joel Galenson845f74b2020-09-09 14:11:55 -0700964 params![id, grantee_uid, key_id, i32::from(access_vector)],
965 )
966 })
967 .context("In grant")?
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700968 };
969 tx.commit().context("In grant: failed to commit transaction.")?;
970
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700971 Ok(KeyDescriptor { domain: Domain::GRANT, nspace: grant_id, alias: None, blob: None })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700972 }
973
974 /// This function checks permissions like `grant` and `load_key_entry`
975 /// before removing a grant from the grant table.
976 pub fn ungrant(
977 &mut self,
978 key: KeyDescriptor,
979 caller_uid: u32,
980 grantee_uid: u32,
981 check_permission: impl FnOnce(&KeyDescriptor) -> Result<()>,
982 ) -> Result<()> {
983 let tx = self
984 .conn
985 .transaction_with_behavior(TransactionBehavior::Immediate)
986 .context("In ungrant: Failed to initialize transaction.")?;
987
988 // Load the key_id and complete the access control tuple.
989 // We ignore the access vector here because grants cannot be granted.
990 let (key_id, access_key_descriptor, _) =
991 Self::load_access_tuple(&tx, key, caller_uid).context("In ungrant.")?;
992
993 // Perform access control. We must return here if the permission
994 // was denied. So do not touch the '?' at the end of this line.
995 check_permission(&access_key_descriptor).context("In grant: check_permission failed.")?;
996
997 tx.execute(
Janis Danisevskisbf15d732020-12-08 10:35:26 -0800998 "DELETE FROM persistent.grant
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700999 WHERE keyentryid = ? AND grantee = ?;",
1000 params![key_id, grantee_uid],
1001 )
1002 .context("Failed to delete grant.")?;
1003
1004 tx.commit().context("In ungrant: failed to commit transaction.")?;
1005
1006 Ok(())
1007 }
1008
Joel Galenson845f74b2020-09-09 14:11:55 -07001009 // Generates a random id and passes it to the given function, which will
1010 // try to insert it into a database. If that insertion fails, retry;
1011 // otherwise return the id.
1012 fn insert_with_retry(inserter: impl Fn(i64) -> rusqlite::Result<usize>) -> Result<i64> {
1013 loop {
1014 let newid: i64 = random();
1015 match inserter(newid) {
1016 // If the id already existed, try again.
1017 Err(rusqlite::Error::SqliteFailure(
1018 libsqlite3_sys::Error {
1019 code: libsqlite3_sys::ErrorCode::ConstraintViolation,
1020 extended_code: libsqlite3_sys::SQLITE_CONSTRAINT_UNIQUE,
1021 },
1022 _,
1023 )) => (),
1024 Err(e) => {
1025 return Err(e).context("In insert_with_retry: failed to insert into database.")
1026 }
1027 _ => return Ok(newid),
1028 }
1029 }
1030 }
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00001031
1032 /// Insert or replace the auth token based on the UNIQUE constraint of the auth token table
1033 pub fn insert_auth_token(&mut self, auth_token: &HardwareAuthToken) -> Result<()> {
1034 self.conn
1035 .execute(
1036 "INSERT OR REPLACE INTO perboot.authtoken (challenge, user_id, auth_id,
1037 authenticator_type, timestamp, mac, time_received) VALUES(?, ?, ?, ?, ?, ?, ?);",
1038 params![
1039 auth_token.challenge,
1040 auth_token.userId,
1041 auth_token.authenticatorId,
1042 auth_token.authenticatorType.0 as i32,
1043 auth_token.timestamp.milliSeconds as i64,
1044 auth_token.mac,
1045 MonotonicRawTime::now(),
1046 ],
1047 )
1048 .context("In insert_auth_token: failed to insert auth token into the database")?;
1049 Ok(())
1050 }
Joel Galenson26f4d012020-07-17 14:57:21 -07001051}
1052
1053#[cfg(test)]
1054mod tests {
1055
1056 use super::*;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001057 use crate::key_parameter::{
1058 Algorithm, BlockMode, Digest, EcCurve, HardwareAuthenticatorType, KeyOrigin, KeyParameter,
1059 KeyParameterValue, KeyPurpose, PaddingMode, SecurityLevel,
1060 };
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001061 use crate::key_perm_set;
1062 use crate::permission::{KeyPerm, KeyPermSet};
Janis Danisevskisbf15d732020-12-08 10:35:26 -08001063 use crate::test::utils::TempDir;
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00001064 use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
1065 HardwareAuthToken::HardwareAuthToken,
1066 HardwareAuthenticatorType::HardwareAuthenticatorType as kmhw_authenticator_type,
1067 Timestamp::Timestamp,
1068 };
1069 use rusqlite::Error;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001070 use rusqlite::NO_PARAMS;
Joel Galenson0891bc12020-07-20 10:37:03 -07001071 use std::cell::RefCell;
Janis Danisevskisaec14592020-11-12 09:41:49 -08001072 use std::sync::atomic::{AtomicU8, Ordering};
1073 use std::sync::Arc;
1074 use std::thread;
Joel Galenson0891bc12020-07-20 10:37:03 -07001075
Janis Danisevskis4df44f42020-08-26 14:40:03 -07001076 fn new_test_db() -> Result<KeystoreDB> {
1077 let conn = KeystoreDB::make_connection("file::memory:", "file::memory:")?;
1078
1079 KeystoreDB::init_tables(&conn).context("Failed to initialize tables.")?;
1080 Ok(KeystoreDB { conn })
1081 }
1082
Joel Galenson0891bc12020-07-20 10:37:03 -07001083 // Ensure that we're using the "injected" random function, not the real one.
1084 #[test]
1085 fn test_mocked_random() {
1086 let rand1 = random();
1087 let rand2 = random();
1088 let rand3 = random();
1089 if rand1 == rand2 {
1090 assert_eq!(rand2 + 1, rand3);
1091 } else {
1092 assert_eq!(rand1 + 1, rand2);
1093 assert_eq!(rand2, rand3);
1094 }
1095 }
Joel Galenson26f4d012020-07-17 14:57:21 -07001096
Joel Galenson26f4d012020-07-17 14:57:21 -07001097 // Test that we have the correct tables.
1098 #[test]
1099 fn test_tables() -> Result<()> {
Janis Danisevskis4df44f42020-08-26 14:40:03 -07001100 let db = new_test_db()?;
Joel Galenson26f4d012020-07-17 14:57:21 -07001101 let tables = db
1102 .conn
Joel Galenson2aab4432020-07-22 15:27:57 -07001103 .prepare("SELECT name from persistent.sqlite_master WHERE type='table' ORDER BY name;")?
Joel Galenson26f4d012020-07-17 14:57:21 -07001104 .query_map(params![], |row| row.get(0))?
1105 .collect::<rusqlite::Result<Vec<String>>>()?;
Janis Danisevskisbf15d732020-12-08 10:35:26 -08001106 assert_eq!(tables.len(), 4);
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001107 assert_eq!(tables[0], "blobentry");
Janis Danisevskisbf15d732020-12-08 10:35:26 -08001108 assert_eq!(tables[1], "grant");
1109 assert_eq!(tables[2], "keyentry");
1110 assert_eq!(tables[3], "keyparameter");
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001111 let tables = db
1112 .conn
1113 .prepare("SELECT name from perboot.sqlite_master WHERE type='table' ORDER BY name;")?
1114 .query_map(params![], |row| row.get(0))?
1115 .collect::<rusqlite::Result<Vec<String>>>()?;
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00001116
1117 assert_eq!(tables.len(), 2);
1118 assert_eq!(tables[0], "authtoken");
1119 assert_eq!(tables[1], "metadata");
Joel Galenson2aab4432020-07-22 15:27:57 -07001120 Ok(())
1121 }
1122
1123 #[test]
Hasini Gunasinghe557b1032020-11-10 01:35:30 +00001124 fn test_auth_token_table_invariant() -> Result<()> {
1125 let mut db = new_test_db()?;
1126 let auth_token1 = HardwareAuthToken {
1127 challenge: i64::MAX,
1128 userId: 200,
1129 authenticatorId: 200,
1130 authenticatorType: kmhw_authenticator_type(kmhw_authenticator_type::PASSWORD.0),
1131 timestamp: Timestamp { milliSeconds: 500 },
1132 mac: String::from("mac").into_bytes(),
1133 };
1134 db.insert_auth_token(&auth_token1)?;
1135 let auth_tokens_returned = get_auth_tokens(&mut db)?;
1136 assert_eq!(auth_tokens_returned.len(), 1);
1137
1138 // insert another auth token with the same values for the columns in the UNIQUE constraint
1139 // of the auth token table and different value for timestamp
1140 let auth_token2 = HardwareAuthToken {
1141 challenge: i64::MAX,
1142 userId: 200,
1143 authenticatorId: 200,
1144 authenticatorType: kmhw_authenticator_type(kmhw_authenticator_type::PASSWORD.0),
1145 timestamp: Timestamp { milliSeconds: 600 },
1146 mac: String::from("mac").into_bytes(),
1147 };
1148
1149 db.insert_auth_token(&auth_token2)?;
1150 let mut auth_tokens_returned = get_auth_tokens(&mut db)?;
1151 assert_eq!(auth_tokens_returned.len(), 1);
1152
1153 if let Some(auth_token) = auth_tokens_returned.pop() {
1154 assert_eq!(auth_token.auth_token.timestamp.milliSeconds, 600);
1155 }
1156
1157 // insert another auth token with the different values for the columns in the UNIQUE
1158 // constraint of the auth token table
1159 let auth_token3 = HardwareAuthToken {
1160 challenge: i64::MAX,
1161 userId: 201,
1162 authenticatorId: 200,
1163 authenticatorType: kmhw_authenticator_type(kmhw_authenticator_type::PASSWORD.0),
1164 timestamp: Timestamp { milliSeconds: 600 },
1165 mac: String::from("mac").into_bytes(),
1166 };
1167
1168 db.insert_auth_token(&auth_token3)?;
1169 let auth_tokens_returned = get_auth_tokens(&mut db)?;
1170 assert_eq!(auth_tokens_returned.len(), 2);
1171
1172 Ok(())
1173 }
1174
1175 // utility function for test_auth_token_table_invariant()
1176 fn get_auth_tokens(db: &mut KeystoreDB) -> Result<Vec<AuthTokenEntry>> {
1177 let mut stmt = db.conn.prepare("SELECT * from perboot.authtoken;")?;
1178
1179 let auth_token_entries: Vec<AuthTokenEntry> = stmt
1180 .query_map(NO_PARAMS, |row| {
1181 Ok(AuthTokenEntry::new(
1182 HardwareAuthToken {
1183 challenge: row.get(1)?,
1184 userId: row.get(2)?,
1185 authenticatorId: row.get(3)?,
1186 authenticatorType: HardwareAuthenticatorType(row.get(4)?),
1187 timestamp: Timestamp { milliSeconds: row.get(5)? },
1188 mac: row.get(6)?,
1189 },
1190 row.get(7)?,
1191 ))
1192 })?
1193 .collect::<Result<Vec<AuthTokenEntry>, Error>>()?;
1194 Ok(auth_token_entries)
1195 }
1196
1197 #[test]
Joel Galenson2aab4432020-07-22 15:27:57 -07001198 fn test_persistence_for_files() -> Result<()> {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08001199 let temp_dir = TempDir::new("persistent_db_test")?;
1200 let db = KeystoreDB::new(temp_dir.path())?;
Joel Galenson2aab4432020-07-22 15:27:57 -07001201
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001202 db.create_key_entry(Domain::APP, 100)?;
Joel Galenson2aab4432020-07-22 15:27:57 -07001203 let entries = get_keyentry(&db)?;
1204 assert_eq!(entries.len(), 1);
Janis Danisevskisbf15d732020-12-08 10:35:26 -08001205
1206 let db = KeystoreDB::new(temp_dir.path())?;
Joel Galenson2aab4432020-07-22 15:27:57 -07001207
1208 let entries_new = get_keyentry(&db)?;
1209 assert_eq!(entries, entries_new);
1210 Ok(())
1211 }
1212
1213 #[test]
Joel Galenson0891bc12020-07-20 10:37:03 -07001214 fn test_create_key_entry() -> Result<()> {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001215 fn extractor(ke: &KeyEntryRow) -> (Domain, i64, Option<&str>) {
Joel Galenson0891bc12020-07-20 10:37:03 -07001216 (ke.domain.unwrap(), ke.namespace.unwrap(), ke.alias.as_deref())
1217 }
1218
Janis Danisevskis4df44f42020-08-26 14:40:03 -07001219 let db = new_test_db()?;
Joel Galenson0891bc12020-07-20 10:37:03 -07001220
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001221 db.create_key_entry(Domain::APP, 100)?;
1222 db.create_key_entry(Domain::SELINUX, 101)?;
Joel Galenson0891bc12020-07-20 10:37:03 -07001223
1224 let entries = get_keyentry(&db)?;
1225 assert_eq!(entries.len(), 2);
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001226 assert_eq!(extractor(&entries[0]), (Domain::APP, 100, None));
1227 assert_eq!(extractor(&entries[1]), (Domain::SELINUX, 101, None));
Joel Galenson0891bc12020-07-20 10:37:03 -07001228
1229 // Test that we must pass in a valid Domain.
1230 check_result_is_error_containing_string(
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001231 db.create_key_entry(Domain::GRANT, 102),
1232 "Domain Domain(1) must be either App or SELinux.",
Joel Galenson0891bc12020-07-20 10:37:03 -07001233 );
1234 check_result_is_error_containing_string(
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001235 db.create_key_entry(Domain::BLOB, 103),
1236 "Domain Domain(3) must be either App or SELinux.",
Joel Galenson0891bc12020-07-20 10:37:03 -07001237 );
1238 check_result_is_error_containing_string(
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001239 db.create_key_entry(Domain::KEY_ID, 104),
1240 "Domain Domain(4) must be either App or SELinux.",
Joel Galenson0891bc12020-07-20 10:37:03 -07001241 );
1242
1243 Ok(())
1244 }
1245
Joel Galenson33c04ad2020-08-03 11:04:38 -07001246 #[test]
1247 fn test_rebind_alias() -> Result<()> {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001248 fn extractor(ke: &KeyEntryRow) -> (Option<Domain>, Option<i64>, Option<&str>) {
Joel Galenson33c04ad2020-08-03 11:04:38 -07001249 (ke.domain, ke.namespace, ke.alias.as_deref())
1250 }
1251
Janis Danisevskis4df44f42020-08-26 14:40:03 -07001252 let mut db = new_test_db()?;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001253 db.create_key_entry(Domain::APP, 42)?;
1254 db.create_key_entry(Domain::APP, 42)?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07001255 let entries = get_keyentry(&db)?;
1256 assert_eq!(entries.len(), 2);
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001257 assert_eq!(extractor(&entries[0]), (Some(Domain::APP), Some(42), None));
1258 assert_eq!(extractor(&entries[1]), (Some(Domain::APP), Some(42), None));
Joel Galenson33c04ad2020-08-03 11:04:38 -07001259
1260 // Test that the first call to rebind_alias sets the alias.
Janis Danisevskisaec14592020-11-12 09:41:49 -08001261 db.rebind_alias(&KEY_ID_LOCK.get(entries[0].id), "foo", Domain::APP, 42)?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07001262 let entries = get_keyentry(&db)?;
1263 assert_eq!(entries.len(), 2);
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001264 assert_eq!(extractor(&entries[0]), (Some(Domain::APP), Some(42), Some("foo")));
1265 assert_eq!(extractor(&entries[1]), (Some(Domain::APP), Some(42), None));
Joel Galenson33c04ad2020-08-03 11:04:38 -07001266
1267 // Test that the second call to rebind_alias also empties the old one.
Janis Danisevskisaec14592020-11-12 09:41:49 -08001268 db.rebind_alias(&KEY_ID_LOCK.get(entries[1].id), "foo", Domain::APP, 42)?;
Joel Galenson33c04ad2020-08-03 11:04:38 -07001269 let entries = get_keyentry(&db)?;
1270 assert_eq!(entries.len(), 2);
Joel Galenson7fa5c412020-11-19 10:56:54 -08001271 assert_eq!(extractor(&entries[0]), (None, None, None));
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001272 assert_eq!(extractor(&entries[1]), (Some(Domain::APP), Some(42), Some("foo")));
Joel Galenson33c04ad2020-08-03 11:04:38 -07001273
1274 // Test that we must pass in a valid Domain.
1275 check_result_is_error_containing_string(
Janis Danisevskisaec14592020-11-12 09:41:49 -08001276 db.rebind_alias(&KEY_ID_LOCK.get(0), "foo", Domain::GRANT, 42),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001277 "Domain Domain(1) must be either App or SELinux.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07001278 );
1279 check_result_is_error_containing_string(
Janis Danisevskisaec14592020-11-12 09:41:49 -08001280 db.rebind_alias(&KEY_ID_LOCK.get(0), "foo", Domain::BLOB, 42),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001281 "Domain Domain(3) must be either App or SELinux.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07001282 );
1283 check_result_is_error_containing_string(
Janis Danisevskisaec14592020-11-12 09:41:49 -08001284 db.rebind_alias(&KEY_ID_LOCK.get(0), "foo", Domain::KEY_ID, 42),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001285 "Domain Domain(4) must be either App or SELinux.",
Joel Galenson33c04ad2020-08-03 11:04:38 -07001286 );
1287
1288 // Test that we correctly handle setting an alias for something that does not exist.
1289 check_result_is_error_containing_string(
Janis Danisevskisaec14592020-11-12 09:41:49 -08001290 db.rebind_alias(&KEY_ID_LOCK.get(0), "foo", Domain::SELINUX, 42),
Joel Galenson33c04ad2020-08-03 11:04:38 -07001291 "Expected to update a single entry but instead updated 0",
1292 );
1293 // Test that we correctly abort the transaction in this case.
1294 let entries = get_keyentry(&db)?;
1295 assert_eq!(entries.len(), 2);
Joel Galenson7fa5c412020-11-19 10:56:54 -08001296 assert_eq!(extractor(&entries[0]), (None, None, None));
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001297 assert_eq!(extractor(&entries[1]), (Some(Domain::APP), Some(42), Some("foo")));
Joel Galenson33c04ad2020-08-03 11:04:38 -07001298
1299 Ok(())
1300 }
1301
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001302 #[test]
1303 fn test_grant_ungrant() -> Result<()> {
1304 const CALLER_UID: u32 = 15;
1305 const GRANTEE_UID: u32 = 12;
1306 const SELINUX_NAMESPACE: i64 = 7;
1307
1308 let mut db = new_test_db()?;
1309 db.conn.execute(
1310 "INSERT INTO persistent.keyentry (id, creation_date, domain, namespace, alias)
1311 VALUES (1, '1980', 0, 15, 'key'), (2, '1980', 2, 7, 'yek');",
1312 NO_PARAMS,
1313 )?;
1314 let app_key = KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001315 domain: super::Domain::APP,
1316 nspace: 0,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001317 alias: Some("key".to_string()),
1318 blob: None,
1319 };
1320 const PVEC1: KeyPermSet = key_perm_set![KeyPerm::use_(), KeyPerm::get_info()];
1321 const PVEC2: KeyPermSet = key_perm_set![KeyPerm::use_()];
1322
1323 // Reset totally predictable random number generator in case we
1324 // are not the first test running on this thread.
1325 reset_random();
1326 let next_random = 0i64;
1327
1328 let app_granted_key =
1329 db.grant(app_key.clone(), CALLER_UID, GRANTEE_UID, PVEC1, |k, a| {
1330 assert_eq!(*a, PVEC1);
1331 assert_eq!(
1332 *k,
1333 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001334 domain: super::Domain::APP,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001335 // namespace must be set to the caller_uid.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001336 nspace: CALLER_UID as i64,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001337 alias: Some("key".to_string()),
1338 blob: None,
1339 }
1340 );
1341 Ok(())
1342 })?;
1343
1344 assert_eq!(
1345 app_granted_key,
1346 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001347 domain: super::Domain::GRANT,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001348 // The grantid is next_random due to the mock random number generator.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001349 nspace: next_random,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001350 alias: None,
1351 blob: None,
1352 }
1353 );
1354
1355 let selinux_key = KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001356 domain: super::Domain::SELINUX,
1357 nspace: SELINUX_NAMESPACE,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001358 alias: Some("yek".to_string()),
1359 blob: None,
1360 };
1361
1362 let selinux_granted_key =
1363 db.grant(selinux_key.clone(), CALLER_UID, 12, PVEC1, |k, a| {
1364 assert_eq!(*a, PVEC1);
1365 assert_eq!(
1366 *k,
1367 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001368 domain: super::Domain::SELINUX,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001369 // namespace must be the supplied SELinux
1370 // namespace.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001371 nspace: SELINUX_NAMESPACE,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001372 alias: Some("yek".to_string()),
1373 blob: None,
1374 }
1375 );
1376 Ok(())
1377 })?;
1378
1379 assert_eq!(
1380 selinux_granted_key,
1381 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001382 domain: super::Domain::GRANT,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001383 // The grantid is next_random + 1 due to the mock random number generator.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001384 nspace: next_random + 1,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001385 alias: None,
1386 blob: None,
1387 }
1388 );
1389
1390 // This should update the existing grant with PVEC2.
1391 let selinux_granted_key =
1392 db.grant(selinux_key.clone(), CALLER_UID, 12, PVEC2, |k, a| {
1393 assert_eq!(*a, PVEC2);
1394 assert_eq!(
1395 *k,
1396 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001397 domain: super::Domain::SELINUX,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001398 // namespace must be the supplied SELinux
1399 // namespace.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001400 nspace: SELINUX_NAMESPACE,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001401 alias: Some("yek".to_string()),
1402 blob: None,
1403 }
1404 );
1405 Ok(())
1406 })?;
1407
1408 assert_eq!(
1409 selinux_granted_key,
1410 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001411 domain: super::Domain::GRANT,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001412 // Same grant id as before. The entry was only updated.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001413 nspace: next_random + 1,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001414 alias: None,
1415 blob: None,
1416 }
1417 );
1418
1419 {
1420 // Limiting scope of stmt, because it borrows db.
1421 let mut stmt = db
1422 .conn
Janis Danisevskisbf15d732020-12-08 10:35:26 -08001423 .prepare("SELECT id, grantee, keyentryid, access_vector FROM persistent.grant;")?;
Janis Danisevskisee10b5f2020-09-22 16:42:35 -07001424 let mut rows =
1425 stmt.query_map::<(i64, u32, i64, KeyPermSet), _, _>(NO_PARAMS, |row| {
1426 Ok((
1427 row.get(0)?,
1428 row.get(1)?,
1429 row.get(2)?,
1430 KeyPermSet::from(row.get::<_, i32>(3)?),
1431 ))
1432 })?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001433
1434 let r = rows.next().unwrap().unwrap();
Janis Danisevskisee10b5f2020-09-22 16:42:35 -07001435 assert_eq!(r, (next_random, GRANTEE_UID, 1, PVEC1));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001436 let r = rows.next().unwrap().unwrap();
Janis Danisevskisee10b5f2020-09-22 16:42:35 -07001437 assert_eq!(r, (next_random + 1, GRANTEE_UID, 2, PVEC2));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001438 assert!(rows.next().is_none());
1439 }
1440
1441 debug_dump_keyentry_table(&mut db)?;
1442 println!("app_key {:?}", app_key);
1443 println!("selinux_key {:?}", selinux_key);
1444
1445 db.ungrant(app_key, CALLER_UID, GRANTEE_UID, |_| Ok(()))?;
1446 db.ungrant(selinux_key, CALLER_UID, GRANTEE_UID, |_| Ok(()))?;
1447
1448 Ok(())
1449 }
1450
1451 static TEST_KM_BLOB: &[u8] = b"my test blob";
1452 static TEST_CERT_BLOB: &[u8] = b"my test cert";
1453 static TEST_CERT_CHAIN_BLOB: &[u8] = b"my test cert_chain";
1454
1455 #[test]
1456 fn test_insert_blob() -> Result<()> {
1457 let mut db = new_test_db()?;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001458 db.insert_blob(
Janis Danisevskisaec14592020-11-12 09:41:49 -08001459 &KEY_ID_LOCK.get(1),
1460 SubComponentType::KM_BLOB,
1461 TEST_KM_BLOB,
1462 SecurityLevel::SOFTWARE,
1463 )?;
1464 db.insert_blob(
1465 &KEY_ID_LOCK.get(1),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001466 SubComponentType::CERT,
1467 TEST_CERT_BLOB,
1468 SecurityLevel::TRUSTED_ENVIRONMENT,
1469 )?;
1470 db.insert_blob(
Janis Danisevskisaec14592020-11-12 09:41:49 -08001471 &KEY_ID_LOCK.get(1),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001472 SubComponentType::CERT_CHAIN,
1473 TEST_CERT_CHAIN_BLOB,
1474 SecurityLevel::STRONGBOX,
1475 )?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001476
1477 let mut stmt = db.conn.prepare(
1478 "SELECT subcomponent_type, keyentryid, blob, sec_level FROM persistent.blobentry
1479 ORDER BY sec_level ASC;",
1480 )?;
1481 let mut rows = stmt
1482 .query_map::<(SubComponentType, i64, Vec<u8>, i64), _, _>(NO_PARAMS, |row| {
1483 Ok((row.get(0)?, row.get(1)?, row.get(2)?, row.get(3)?))
1484 })?;
1485 let r = rows.next().unwrap().unwrap();
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001486 assert_eq!(r, (SubComponentType::KM_BLOB, 1, TEST_KM_BLOB.to_vec(), 0));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001487 let r = rows.next().unwrap().unwrap();
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001488 assert_eq!(r, (SubComponentType::CERT, 1, TEST_CERT_BLOB.to_vec(), 1));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001489 let r = rows.next().unwrap().unwrap();
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001490 assert_eq!(r, (SubComponentType::CERT_CHAIN, 1, TEST_CERT_CHAIN_BLOB.to_vec(), 2));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001491
1492 Ok(())
1493 }
1494
1495 static TEST_ALIAS: &str = "my super duper key";
1496
1497 #[test]
1498 fn test_insert_and_load_full_keyentry_domain_app() -> Result<()> {
1499 let mut db = new_test_db()?;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001500 let key_id = make_test_key_entry(&mut db, Domain::APP, 1, TEST_ALIAS)
Janis Danisevskisaec14592020-11-12 09:41:49 -08001501 .context("test_insert_and_load_full_keyentry_domain_app")?
1502 .0;
1503 let (_key_guard, key_entry) = db.load_key_entry(
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001504 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001505 domain: Domain::APP,
1506 nspace: 0,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001507 alias: Some(TEST_ALIAS.to_string()),
1508 blob: None,
1509 },
1510 KeyEntryLoadBits::BOTH,
1511 1,
1512 |_k, _av| Ok(()),
1513 )?;
1514 assert_eq!(
1515 key_entry,
1516 KeyEntry {
1517 id: key_id,
1518 km_blob: Some(TEST_KM_BLOB.to_vec()),
1519 cert: Some(TEST_CERT_BLOB.to_vec()),
1520 cert_chain: Some(TEST_CERT_CHAIN_BLOB.to_vec()),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001521 sec_level: SecurityLevel::TRUSTED_ENVIRONMENT,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001522 parameters: make_test_params(),
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001523 }
1524 );
1525 Ok(())
1526 }
1527
1528 #[test]
1529 fn test_insert_and_load_full_keyentry_domain_selinux() -> Result<()> {
1530 let mut db = new_test_db()?;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001531 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS)
Janis Danisevskisaec14592020-11-12 09:41:49 -08001532 .context("test_insert_and_load_full_keyentry_domain_selinux")?
1533 .0;
1534 let (_key_guard, key_entry) = db.load_key_entry(
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001535 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001536 domain: Domain::SELINUX,
1537 nspace: 1,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001538 alias: Some(TEST_ALIAS.to_string()),
1539 blob: None,
1540 },
1541 KeyEntryLoadBits::BOTH,
1542 1,
1543 |_k, _av| Ok(()),
1544 )?;
1545 assert_eq!(
1546 key_entry,
1547 KeyEntry {
1548 id: key_id,
1549 km_blob: Some(TEST_KM_BLOB.to_vec()),
1550 cert: Some(TEST_CERT_BLOB.to_vec()),
1551 cert_chain: Some(TEST_CERT_CHAIN_BLOB.to_vec()),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001552 sec_level: SecurityLevel::TRUSTED_ENVIRONMENT,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001553 parameters: make_test_params(),
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001554 }
1555 );
1556 Ok(())
1557 }
1558
1559 #[test]
1560 fn test_insert_and_load_full_keyentry_domain_key_id() -> Result<()> {
1561 let mut db = new_test_db()?;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001562 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS)
Janis Danisevskisaec14592020-11-12 09:41:49 -08001563 .context("test_insert_and_load_full_keyentry_domain_key_id")?
1564 .0;
1565 let (_key_guard, key_entry) = db.load_key_entry(
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001566 KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001567 KeyEntryLoadBits::BOTH,
1568 1,
1569 |_k, _av| Ok(()),
1570 )?;
1571 assert_eq!(
1572 key_entry,
1573 KeyEntry {
1574 id: key_id,
1575 km_blob: Some(TEST_KM_BLOB.to_vec()),
1576 cert: Some(TEST_CERT_BLOB.to_vec()),
1577 cert_chain: Some(TEST_CERT_CHAIN_BLOB.to_vec()),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001578 sec_level: SecurityLevel::TRUSTED_ENVIRONMENT,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001579 parameters: make_test_params(),
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001580 }
1581 );
1582
1583 Ok(())
1584 }
1585
1586 #[test]
1587 fn test_insert_and_load_full_keyentry_from_grant() -> Result<()> {
1588 let mut db = new_test_db()?;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001589 let key_id = make_test_key_entry(&mut db, Domain::APP, 1, TEST_ALIAS)
Janis Danisevskisaec14592020-11-12 09:41:49 -08001590 .context("test_insert_and_load_full_keyentry_from_grant")?
1591 .0;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001592
1593 let granted_key = db.grant(
1594 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001595 domain: Domain::APP,
1596 nspace: 0,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001597 alias: Some(TEST_ALIAS.to_string()),
1598 blob: None,
1599 },
1600 1,
1601 2,
1602 key_perm_set![KeyPerm::use_()],
1603 |_k, _av| Ok(()),
1604 )?;
1605
1606 debug_dump_grant_table(&mut db)?;
1607
Janis Danisevskisaec14592020-11-12 09:41:49 -08001608 let (_key_guard, key_entry) =
1609 db.load_key_entry(granted_key, KeyEntryLoadBits::BOTH, 2, |k, av| {
1610 assert_eq!(Domain::GRANT, k.domain);
1611 assert!(av.unwrap().includes(KeyPerm::use_()));
1612 Ok(())
1613 })?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001614
1615 assert_eq!(
1616 key_entry,
1617 KeyEntry {
1618 id: key_id,
1619 km_blob: Some(TEST_KM_BLOB.to_vec()),
1620 cert: Some(TEST_CERT_BLOB.to_vec()),
1621 cert_chain: Some(TEST_CERT_CHAIN_BLOB.to_vec()),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001622 sec_level: SecurityLevel::TRUSTED_ENVIRONMENT,
Janis Danisevskisaec14592020-11-12 09:41:49 -08001623 parameters: make_test_params(),
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001624 }
1625 );
1626 Ok(())
1627 }
1628
Janis Danisevskisaec14592020-11-12 09:41:49 -08001629 static KEY_LOCK_TEST_ALIAS: &str = "my super duper locked key";
1630
Janis Danisevskisaec14592020-11-12 09:41:49 -08001631 #[test]
1632 fn test_insert_and_load_full_keyentry_domain_app_concurrently() -> Result<()> {
1633 let handle = {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08001634 let temp_dir = Arc::new(TempDir::new("id_lock_test")?);
1635 let temp_dir_clone = temp_dir.clone();
1636 let mut db = KeystoreDB::new(temp_dir.path())?;
Janis Danisevskisaec14592020-11-12 09:41:49 -08001637 let key_id = make_test_key_entry(&mut db, Domain::APP, 33, KEY_LOCK_TEST_ALIAS)
1638 .context("test_insert_and_load_full_keyentry_domain_app")?
1639 .0;
1640 let (_key_guard, key_entry) = db.load_key_entry(
1641 KeyDescriptor {
1642 domain: Domain::APP,
1643 nspace: 0,
1644 alias: Some(KEY_LOCK_TEST_ALIAS.to_string()),
1645 blob: None,
1646 },
1647 KeyEntryLoadBits::BOTH,
1648 33,
1649 |_k, _av| Ok(()),
1650 )?;
1651 assert_eq!(
1652 key_entry,
1653 KeyEntry {
1654 id: key_id,
1655 km_blob: Some(TEST_KM_BLOB.to_vec()),
1656 cert: Some(TEST_CERT_BLOB.to_vec()),
1657 cert_chain: Some(TEST_CERT_CHAIN_BLOB.to_vec()),
1658 sec_level: SecurityLevel::TRUSTED_ENVIRONMENT,
1659 parameters: make_test_params(),
1660 }
1661 );
1662 let state = Arc::new(AtomicU8::new(1));
1663 let state2 = state.clone();
1664
1665 // Spawning a second thread that attempts to acquire the key id lock
1666 // for the same key as the primary thread. The primary thread then
1667 // waits, thereby forcing the secondary thread into the second stage
1668 // of acquiring the lock (see KEY ID LOCK 2/2 above).
1669 // The test succeeds if the secondary thread observes the transition
1670 // of `state` from 1 to 2, despite having a whole second to overtake
1671 // the primary thread.
1672 let handle = thread::spawn(move || {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08001673 let temp_dir = temp_dir_clone;
1674 let mut db = KeystoreDB::new(temp_dir.path()).unwrap();
Janis Danisevskisaec14592020-11-12 09:41:49 -08001675 assert!(db
1676 .load_key_entry(
1677 KeyDescriptor {
1678 domain: Domain::APP,
1679 nspace: 0,
1680 alias: Some(KEY_LOCK_TEST_ALIAS.to_string()),
1681 blob: None,
1682 },
1683 KeyEntryLoadBits::BOTH,
1684 33,
1685 |_k, _av| Ok(()),
1686 )
1687 .is_ok());
1688 // We should only see a 2 here because we can only return
1689 // from load_key_entry when the `_key_guard` expires,
1690 // which happens at the end of the scope.
1691 assert_eq!(2, state2.load(Ordering::Relaxed));
1692 });
1693
1694 thread::sleep(std::time::Duration::from_millis(1000));
1695
1696 assert_eq!(Ok(1), state.compare_exchange(1, 2, Ordering::Relaxed, Ordering::Relaxed));
1697
1698 // Return the handle from this scope so we can join with the
1699 // secondary thread after the key id lock has expired.
1700 handle
1701 // This is where the `_key_guard` goes out of scope,
1702 // which is the reason for concurrent load_key_entry on the same key
1703 // to unblock.
1704 };
1705 // Join with the secondary thread and unwrap, to propagate failing asserts to the
1706 // main test thread. We will not see failing asserts in secondary threads otherwise.
1707 handle.join().unwrap();
1708 Ok(())
1709 }
1710
Janis Danisevskise92a5e62020-12-02 12:57:41 -08001711 #[test]
1712 fn list() -> Result<()> {
1713 let temp_dir = TempDir::new("list_test")?;
1714 let mut db = KeystoreDB::new(temp_dir.path())?;
1715 static LIST_O_ENTRIES: &[(Domain, i64, &str)] = &[
1716 (Domain::APP, 1, "test1"),
1717 (Domain::APP, 1, "test2"),
1718 (Domain::APP, 1, "test3"),
1719 (Domain::APP, 1, "test4"),
1720 (Domain::APP, 1, "test5"),
1721 (Domain::APP, 1, "test6"),
1722 (Domain::APP, 1, "test7"),
1723 (Domain::APP, 2, "test1"),
1724 (Domain::APP, 2, "test2"),
1725 (Domain::APP, 2, "test3"),
1726 (Domain::APP, 2, "test4"),
1727 (Domain::APP, 2, "test5"),
1728 (Domain::APP, 2, "test6"),
1729 (Domain::APP, 2, "test8"),
1730 (Domain::SELINUX, 100, "test1"),
1731 (Domain::SELINUX, 100, "test2"),
1732 (Domain::SELINUX, 100, "test3"),
1733 (Domain::SELINUX, 100, "test4"),
1734 (Domain::SELINUX, 100, "test5"),
1735 (Domain::SELINUX, 100, "test6"),
1736 (Domain::SELINUX, 100, "test9"),
1737 ];
1738
1739 let list_o_keys: Vec<(i64, i64)> = LIST_O_ENTRIES
1740 .iter()
1741 .map(|(domain, ns, alias)| {
1742 let entry =
1743 make_test_key_entry(&mut db, *domain, *ns, *alias).unwrap_or_else(|e| {
1744 panic!("Failed to insert {:?} {} {}. Error {:?}", domain, ns, alias, e)
1745 });
1746 (entry.id(), *ns)
1747 })
1748 .collect();
1749
1750 for (domain, namespace) in
1751 &[(Domain::APP, 1i64), (Domain::APP, 2i64), (Domain::SELINUX, 100i64)]
1752 {
1753 let mut list_o_descriptors: Vec<KeyDescriptor> = LIST_O_ENTRIES
1754 .iter()
1755 .filter_map(|(domain, ns, alias)| match ns {
1756 ns if *ns == *namespace => Some(KeyDescriptor {
1757 domain: *domain,
1758 nspace: *ns,
1759 alias: Some(alias.to_string()),
1760 blob: None,
1761 }),
1762 _ => None,
1763 })
1764 .collect();
1765 list_o_descriptors.sort();
1766 let mut list_result = db.list(*domain, *namespace)?;
1767 list_result.sort();
1768 assert_eq!(list_o_descriptors, list_result);
1769
1770 let mut list_o_ids: Vec<i64> = list_o_descriptors
1771 .into_iter()
1772 .map(|d| {
1773 let (_, entry) = db
1774 .load_key_entry(d, KeyEntryLoadBits::NONE, *namespace as u32, |_, _| Ok(()))
1775 .unwrap();
1776 entry.id()
1777 })
1778 .collect();
1779 list_o_ids.sort_unstable();
1780 let mut loaded_entries: Vec<i64> = list_o_keys
1781 .iter()
1782 .filter_map(|(id, ns)| match ns {
1783 ns if *ns == *namespace => Some(*id),
1784 _ => None,
1785 })
1786 .collect();
1787 loaded_entries.sort_unstable();
1788 assert_eq!(list_o_ids, loaded_entries);
1789 }
1790 assert_eq!(Vec::<KeyDescriptor>::new(), db.list(Domain::SELINUX, 101)?);
1791
1792 Ok(())
1793 }
1794
Joel Galenson0891bc12020-07-20 10:37:03 -07001795 // Helpers
1796
1797 // Checks that the given result is an error containing the given string.
1798 fn check_result_is_error_containing_string<T>(result: Result<T>, target: &str) {
1799 let error_str = format!(
1800 "{:#?}",
1801 result.err().unwrap_or_else(|| panic!("Expected the error: {}", target))
1802 );
1803 assert!(
1804 error_str.contains(target),
1805 "The string \"{}\" should contain \"{}\"",
1806 error_str,
1807 target
1808 );
1809 }
1810
Joel Galenson2aab4432020-07-22 15:27:57 -07001811 #[derive(Debug, PartialEq)]
Joel Galenson0891bc12020-07-20 10:37:03 -07001812 #[allow(dead_code)]
1813 struct KeyEntryRow {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001814 id: i64,
Joel Galenson0891bc12020-07-20 10:37:03 -07001815 creation_date: String,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001816 domain: Option<Domain>,
Joel Galenson0891bc12020-07-20 10:37:03 -07001817 namespace: Option<i64>,
1818 alias: Option<String>,
1819 }
1820
1821 fn get_keyentry(db: &KeystoreDB) -> Result<Vec<KeyEntryRow>> {
1822 db.conn
Joel Galenson2aab4432020-07-22 15:27:57 -07001823 .prepare("SELECT * FROM persistent.keyentry;")?
Joel Galenson0891bc12020-07-20 10:37:03 -07001824 .query_map(NO_PARAMS, |row| {
Joel Galenson0891bc12020-07-20 10:37:03 -07001825 Ok(KeyEntryRow {
1826 id: row.get(0)?,
1827 creation_date: row.get(1)?,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001828 domain: match row.get(2)? {
1829 Some(i) => Some(Domain(i)),
1830 None => None,
1831 },
Joel Galenson0891bc12020-07-20 10:37:03 -07001832 namespace: row.get(3)?,
1833 alias: row.get(4)?,
1834 })
1835 })?
1836 .map(|r| r.context("Could not read keyentry row."))
1837 .collect::<Result<Vec<_>>>()
1838 }
1839
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001840 // Note: The parameters and SecurityLevel associations are nonsensical. This
1841 // collection is only used to check if the parameters are preserved as expected by the
1842 // database.
1843 fn make_test_params() -> Vec<KeyParameter> {
1844 vec![
1845 KeyParameter::new(KeyParameterValue::Invalid, SecurityLevel::TRUSTED_ENVIRONMENT),
1846 KeyParameter::new(
1847 KeyParameterValue::KeyPurpose(KeyPurpose::SIGN),
1848 SecurityLevel::TRUSTED_ENVIRONMENT,
1849 ),
1850 KeyParameter::new(
1851 KeyParameterValue::KeyPurpose(KeyPurpose::DECRYPT),
1852 SecurityLevel::TRUSTED_ENVIRONMENT,
1853 ),
1854 KeyParameter::new(
1855 KeyParameterValue::Algorithm(Algorithm::RSA),
1856 SecurityLevel::TRUSTED_ENVIRONMENT,
1857 ),
1858 KeyParameter::new(KeyParameterValue::KeySize(1024), SecurityLevel::TRUSTED_ENVIRONMENT),
1859 KeyParameter::new(
1860 KeyParameterValue::BlockMode(BlockMode::ECB),
1861 SecurityLevel::TRUSTED_ENVIRONMENT,
1862 ),
1863 KeyParameter::new(
1864 KeyParameterValue::BlockMode(BlockMode::GCM),
1865 SecurityLevel::TRUSTED_ENVIRONMENT,
1866 ),
1867 KeyParameter::new(KeyParameterValue::Digest(Digest::NONE), SecurityLevel::STRONGBOX),
1868 KeyParameter::new(
1869 KeyParameterValue::Digest(Digest::MD5),
1870 SecurityLevel::TRUSTED_ENVIRONMENT,
1871 ),
1872 KeyParameter::new(
1873 KeyParameterValue::Digest(Digest::SHA_2_224),
1874 SecurityLevel::TRUSTED_ENVIRONMENT,
1875 ),
1876 KeyParameter::new(
1877 KeyParameterValue::Digest(Digest::SHA_2_256),
1878 SecurityLevel::STRONGBOX,
1879 ),
1880 KeyParameter::new(
1881 KeyParameterValue::PaddingMode(PaddingMode::NONE),
1882 SecurityLevel::TRUSTED_ENVIRONMENT,
1883 ),
1884 KeyParameter::new(
1885 KeyParameterValue::PaddingMode(PaddingMode::RSA_OAEP),
1886 SecurityLevel::TRUSTED_ENVIRONMENT,
1887 ),
1888 KeyParameter::new(
1889 KeyParameterValue::PaddingMode(PaddingMode::RSA_PSS),
1890 SecurityLevel::STRONGBOX,
1891 ),
1892 KeyParameter::new(
1893 KeyParameterValue::PaddingMode(PaddingMode::RSA_PKCS1_1_5_SIGN),
1894 SecurityLevel::TRUSTED_ENVIRONMENT,
1895 ),
1896 KeyParameter::new(KeyParameterValue::CallerNonce, SecurityLevel::TRUSTED_ENVIRONMENT),
1897 KeyParameter::new(KeyParameterValue::MinMacLength(256), SecurityLevel::STRONGBOX),
1898 KeyParameter::new(
1899 KeyParameterValue::EcCurve(EcCurve::P_224),
1900 SecurityLevel::TRUSTED_ENVIRONMENT,
1901 ),
1902 KeyParameter::new(KeyParameterValue::EcCurve(EcCurve::P_256), SecurityLevel::STRONGBOX),
1903 KeyParameter::new(
1904 KeyParameterValue::EcCurve(EcCurve::P_384),
1905 SecurityLevel::TRUSTED_ENVIRONMENT,
1906 ),
1907 KeyParameter::new(
1908 KeyParameterValue::EcCurve(EcCurve::P_521),
1909 SecurityLevel::TRUSTED_ENVIRONMENT,
1910 ),
1911 KeyParameter::new(
1912 KeyParameterValue::RSAPublicExponent(3),
1913 SecurityLevel::TRUSTED_ENVIRONMENT,
1914 ),
1915 KeyParameter::new(
1916 KeyParameterValue::IncludeUniqueID,
1917 SecurityLevel::TRUSTED_ENVIRONMENT,
1918 ),
1919 KeyParameter::new(KeyParameterValue::BootLoaderOnly, SecurityLevel::STRONGBOX),
1920 KeyParameter::new(KeyParameterValue::RollbackResistance, SecurityLevel::STRONGBOX),
1921 KeyParameter::new(
1922 KeyParameterValue::ActiveDateTime(1234567890),
1923 SecurityLevel::STRONGBOX,
1924 ),
1925 KeyParameter::new(
1926 KeyParameterValue::OriginationExpireDateTime(1234567890),
1927 SecurityLevel::TRUSTED_ENVIRONMENT,
1928 ),
1929 KeyParameter::new(
1930 KeyParameterValue::UsageExpireDateTime(1234567890),
1931 SecurityLevel::TRUSTED_ENVIRONMENT,
1932 ),
1933 KeyParameter::new(
1934 KeyParameterValue::MinSecondsBetweenOps(1234567890),
1935 SecurityLevel::TRUSTED_ENVIRONMENT,
1936 ),
1937 KeyParameter::new(
1938 KeyParameterValue::MaxUsesPerBoot(1234567890),
1939 SecurityLevel::TRUSTED_ENVIRONMENT,
1940 ),
1941 KeyParameter::new(KeyParameterValue::UserID(1), SecurityLevel::STRONGBOX),
1942 KeyParameter::new(KeyParameterValue::UserSecureID(42), SecurityLevel::STRONGBOX),
1943 KeyParameter::new(
1944 KeyParameterValue::NoAuthRequired,
1945 SecurityLevel::TRUSTED_ENVIRONMENT,
1946 ),
1947 KeyParameter::new(
1948 KeyParameterValue::HardwareAuthenticatorType(HardwareAuthenticatorType::PASSWORD),
1949 SecurityLevel::TRUSTED_ENVIRONMENT,
1950 ),
1951 KeyParameter::new(KeyParameterValue::AuthTimeout(1234567890), SecurityLevel::SOFTWARE),
1952 KeyParameter::new(KeyParameterValue::AllowWhileOnBody, SecurityLevel::SOFTWARE),
1953 KeyParameter::new(
1954 KeyParameterValue::TrustedUserPresenceRequired,
1955 SecurityLevel::TRUSTED_ENVIRONMENT,
1956 ),
1957 KeyParameter::new(
1958 KeyParameterValue::TrustedConfirmationRequired,
1959 SecurityLevel::TRUSTED_ENVIRONMENT,
1960 ),
1961 KeyParameter::new(
1962 KeyParameterValue::UnlockedDeviceRequired,
1963 SecurityLevel::TRUSTED_ENVIRONMENT,
1964 ),
1965 KeyParameter::new(
1966 KeyParameterValue::ApplicationID(vec![1u8, 2u8, 3u8, 4u8]),
1967 SecurityLevel::SOFTWARE,
1968 ),
1969 KeyParameter::new(
1970 KeyParameterValue::ApplicationData(vec![4u8, 3u8, 2u8, 1u8]),
1971 SecurityLevel::SOFTWARE,
1972 ),
1973 KeyParameter::new(
1974 KeyParameterValue::CreationDateTime(12345677890),
1975 SecurityLevel::SOFTWARE,
1976 ),
1977 KeyParameter::new(
1978 KeyParameterValue::KeyOrigin(KeyOrigin::GENERATED),
1979 SecurityLevel::TRUSTED_ENVIRONMENT,
1980 ),
1981 KeyParameter::new(
1982 KeyParameterValue::RootOfTrust(vec![3u8, 2u8, 1u8, 4u8]),
1983 SecurityLevel::TRUSTED_ENVIRONMENT,
1984 ),
1985 KeyParameter::new(KeyParameterValue::OSVersion(1), SecurityLevel::TRUSTED_ENVIRONMENT),
1986 KeyParameter::new(KeyParameterValue::OSPatchLevel(2), SecurityLevel::SOFTWARE),
1987 KeyParameter::new(
1988 KeyParameterValue::UniqueID(vec![4u8, 3u8, 1u8, 2u8]),
1989 SecurityLevel::SOFTWARE,
1990 ),
1991 KeyParameter::new(
1992 KeyParameterValue::AttestationChallenge(vec![4u8, 3u8, 1u8, 2u8]),
1993 SecurityLevel::TRUSTED_ENVIRONMENT,
1994 ),
1995 KeyParameter::new(
1996 KeyParameterValue::AttestationApplicationID(vec![4u8, 3u8, 1u8, 2u8]),
1997 SecurityLevel::TRUSTED_ENVIRONMENT,
1998 ),
1999 KeyParameter::new(
2000 KeyParameterValue::AttestationIdBrand(vec![4u8, 3u8, 1u8, 2u8]),
2001 SecurityLevel::TRUSTED_ENVIRONMENT,
2002 ),
2003 KeyParameter::new(
2004 KeyParameterValue::AttestationIdDevice(vec![4u8, 3u8, 1u8, 2u8]),
2005 SecurityLevel::TRUSTED_ENVIRONMENT,
2006 ),
2007 KeyParameter::new(
2008 KeyParameterValue::AttestationIdProduct(vec![4u8, 3u8, 1u8, 2u8]),
2009 SecurityLevel::TRUSTED_ENVIRONMENT,
2010 ),
2011 KeyParameter::new(
2012 KeyParameterValue::AttestationIdSerial(vec![4u8, 3u8, 1u8, 2u8]),
2013 SecurityLevel::TRUSTED_ENVIRONMENT,
2014 ),
2015 KeyParameter::new(
2016 KeyParameterValue::AttestationIdIMEI(vec![4u8, 3u8, 1u8, 2u8]),
2017 SecurityLevel::TRUSTED_ENVIRONMENT,
2018 ),
2019 KeyParameter::new(
2020 KeyParameterValue::AttestationIdMEID(vec![4u8, 3u8, 1u8, 2u8]),
2021 SecurityLevel::TRUSTED_ENVIRONMENT,
2022 ),
2023 KeyParameter::new(
2024 KeyParameterValue::AttestationIdManufacturer(vec![4u8, 3u8, 1u8, 2u8]),
2025 SecurityLevel::TRUSTED_ENVIRONMENT,
2026 ),
2027 KeyParameter::new(
2028 KeyParameterValue::AttestationIdModel(vec![4u8, 3u8, 1u8, 2u8]),
2029 SecurityLevel::TRUSTED_ENVIRONMENT,
2030 ),
2031 KeyParameter::new(
2032 KeyParameterValue::VendorPatchLevel(3),
2033 SecurityLevel::TRUSTED_ENVIRONMENT,
2034 ),
2035 KeyParameter::new(
2036 KeyParameterValue::BootPatchLevel(4),
2037 SecurityLevel::TRUSTED_ENVIRONMENT,
2038 ),
2039 KeyParameter::new(
2040 KeyParameterValue::AssociatedData(vec![4u8, 3u8, 1u8, 2u8]),
2041 SecurityLevel::TRUSTED_ENVIRONMENT,
2042 ),
2043 KeyParameter::new(
2044 KeyParameterValue::Nonce(vec![4u8, 3u8, 1u8, 2u8]),
2045 SecurityLevel::TRUSTED_ENVIRONMENT,
2046 ),
2047 KeyParameter::new(
2048 KeyParameterValue::MacLength(256),
2049 SecurityLevel::TRUSTED_ENVIRONMENT,
2050 ),
2051 KeyParameter::new(
2052 KeyParameterValue::ResetSinceIdRotation,
2053 SecurityLevel::TRUSTED_ENVIRONMENT,
2054 ),
2055 KeyParameter::new(
2056 KeyParameterValue::ConfirmationToken(vec![5u8, 5u8, 5u8, 5u8]),
2057 SecurityLevel::TRUSTED_ENVIRONMENT,
2058 ),
2059 ]
2060 }
2061
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002062 fn make_test_key_entry(
2063 db: &mut KeystoreDB,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002064 domain: Domain,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002065 namespace: i64,
2066 alias: &str,
Janis Danisevskisaec14592020-11-12 09:41:49 -08002067 ) -> Result<KeyIdGuard> {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002068 let key_id = db.create_key_entry(domain, namespace)?;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002069 db.insert_blob(
Janis Danisevskisaec14592020-11-12 09:41:49 -08002070 &key_id,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002071 SubComponentType::KM_BLOB,
2072 TEST_KM_BLOB,
2073 SecurityLevel::TRUSTED_ENVIRONMENT,
2074 )?;
2075 db.insert_blob(
Janis Danisevskisaec14592020-11-12 09:41:49 -08002076 &key_id,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002077 SubComponentType::CERT,
2078 TEST_CERT_BLOB,
2079 SecurityLevel::TRUSTED_ENVIRONMENT,
2080 )?;
2081 db.insert_blob(
Janis Danisevskisaec14592020-11-12 09:41:49 -08002082 &key_id,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07002083 SubComponentType::CERT_CHAIN,
2084 TEST_CERT_CHAIN_BLOB,
2085 SecurityLevel::TRUSTED_ENVIRONMENT,
2086 )?;
Janis Danisevskisaec14592020-11-12 09:41:49 -08002087 db.insert_keyparameter(&key_id, &make_test_params())?;
2088 db.rebind_alias(&key_id, alias, domain, namespace)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002089 Ok(key_id)
2090 }
2091
2092 fn debug_dump_keyentry_table(db: &mut KeystoreDB) -> Result<()> {
2093 let mut stmt = db.conn.prepare(
2094 "SELECT id, creation_date, domain, namespace, alias FROM persistent.keyentry;",
2095 )?;
2096 let rows = stmt.query_map::<(i64, i64, i32, i64, String), _, _>(NO_PARAMS, |row| {
2097 Ok((row.get(0)?, row.get(1)?, row.get(2)?, row.get(3)?, row.get(4)?))
2098 })?;
2099
2100 println!("Key entry table rows:");
2101 for r in rows {
2102 let (id, cdate, domain, namespace, alias) = r.unwrap();
2103 println!(
2104 " id: {} Creation date: {} Domain: {} Namespace: {} Alias: {}",
2105 id, cdate, domain, namespace, alias
2106 );
2107 }
2108 Ok(())
2109 }
2110
2111 fn debug_dump_grant_table(db: &mut KeystoreDB) -> Result<()> {
Janis Danisevskisbf15d732020-12-08 10:35:26 -08002112 let mut stmt = db
2113 .conn
2114 .prepare("SELECT id, grantee, keyentryid, access_vector FROM persistent.grant;")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002115 let rows = stmt.query_map::<(i64, i64, i64, i64), _, _>(NO_PARAMS, |row| {
2116 Ok((row.get(0)?, row.get(1)?, row.get(2)?, row.get(3)?))
2117 })?;
2118
2119 println!("Grant table rows:");
2120 for r in rows {
2121 let (id, gt, ki, av) = r.unwrap();
2122 println!(" id: {} grantee: {} key_id: {} access_vector: {}", id, gt, ki, av);
2123 }
2124 Ok(())
2125 }
2126
Joel Galenson0891bc12020-07-20 10:37:03 -07002127 // Use a custom random number generator that repeats each number once.
2128 // This allows us to test repeated elements.
2129
2130 thread_local! {
2131 static RANDOM_COUNTER: RefCell<i64> = RefCell::new(0);
2132 }
2133
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07002134 fn reset_random() {
2135 RANDOM_COUNTER.with(|counter| {
2136 *counter.borrow_mut() = 0;
2137 })
2138 }
2139
Joel Galenson0891bc12020-07-20 10:37:03 -07002140 pub fn random() -> i64 {
2141 RANDOM_COUNTER.with(|counter| {
2142 let result = *counter.borrow() / 2;
2143 *counter.borrow_mut() += 1;
2144 result
2145 })
2146 }
Joel Galenson26f4d012020-07-17 14:57:21 -07002147}