blob: 37adf0460663067a40f0aa6048d7caa50f91a258 [file] [log] [blame]
Joel Galenson26f4d012020-07-17 14:57:21 -07001// Copyright 2020, The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
Janis Danisevskis63f7bc82020-09-03 10:12:56 -070015//! This is the Keystore 2.0 database module.
16//! The database module provides a connection to the backing SQLite store.
17//! We have two databases one for persistent key blob storage and one for
18//! items that have a per boot life cycle.
19//!
20//! ## Persistent database
21//! The persistent database has tables for key blobs. They are organized
22//! as follows:
23//! The `keyentry` table is the primary table for key entries. It is
24//! accompanied by two tables for blobs and parameters.
25//! Each key entry occupies exactly one row in the `keyentry` table and
26//! zero or more rows in the tables `blobentry` and `keyparameter`.
27//!
28//! ## Per boot database
29//! The per boot database stores items with a per boot lifecycle.
30//! Currently, there is only the `grant` table in this database.
31//! Grants are references to a key that can be used to access a key by
32//! clients that don't own that key. Grants can only be created by the
33//! owner of a key. And only certain components can create grants.
34//! This is governed by SEPolicy.
35//!
36//! ## Access control
37//! Some database functions that load keys or create grants perform
38//! access control. This is because in some cases access control
39//! can only be performed after some information about the designated
40//! key was loaded from the database. To decouple the permission checks
41//! from the database module these functions take permission check
42//! callbacks.
Joel Galenson26f4d012020-07-17 14:57:21 -070043
Joel Galenson0891bc12020-07-20 10:37:03 -070044use crate::error::Error as KsError;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -070045use crate::key_parameter::{KeyParameter, SqlField, TagType};
Janis Danisevskis63f7bc82020-09-03 10:12:56 -070046use crate::{error, permission::KeyPermSet};
47use anyhow::{anyhow, Context, Result};
Janis Danisevskis60400fe2020-08-26 15:24:42 -070048
Janis Danisevskis3f322cb2020-09-03 14:46:22 -070049use android_hardware_keymint::aidl::android::hardware::keymint::SecurityLevel::SecurityLevel as SecurityLevelType;
Janis Danisevskis60400fe2020-08-26 15:24:42 -070050use android_security_keystore2::aidl::android::security::keystore2::{
Janis Danisevskis63f7bc82020-09-03 10:12:56 -070051 Domain, Domain::Domain as DomainType, KeyDescriptor::KeyDescriptor,
Janis Danisevskis60400fe2020-08-26 15:24:42 -070052};
53
Joel Galenson0891bc12020-07-20 10:37:03 -070054#[cfg(not(test))]
55use rand::prelude::random;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -070056use rusqlite::{
57 params, types::FromSql, types::FromSqlResult, types::ToSqlOutput, types::ValueRef, Connection,
58 OptionalExtension, Row, Rows, ToSql, Transaction, TransactionBehavior, NO_PARAMS,
59};
Janis Danisevskis4df44f42020-08-26 14:40:03 -070060use std::sync::Once;
Joel Galenson0891bc12020-07-20 10:37:03 -070061#[cfg(test)]
62use tests::random;
Joel Galenson26f4d012020-07-17 14:57:21 -070063
Janis Danisevskis63f7bc82020-09-03 10:12:56 -070064/// Keys have a KeyMint blob component and optional public certificate and
65/// certificate chain components.
66/// KeyEntryLoadBits is a bitmap that indicates to `KeystoreDB::load_key_entry`
67/// which components shall be loaded from the database if present.
68#[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
69pub struct KeyEntryLoadBits(u32);
70
71impl KeyEntryLoadBits {
72 /// Indicate to `KeystoreDB::load_key_entry` that no component shall be loaded.
73 pub const NONE: KeyEntryLoadBits = Self(0);
74 /// Indicate to `KeystoreDB::load_key_entry` that the KeyMint component shall be loaded.
75 pub const KM: KeyEntryLoadBits = Self(1);
76 /// Indicate to `KeystoreDB::load_key_entry` that the Public components shall be loaded.
77 pub const PUBLIC: KeyEntryLoadBits = Self(2);
78 /// Indicate to `KeystoreDB::load_key_entry` that both components shall be loaded.
79 pub const BOTH: KeyEntryLoadBits = Self(3);
80
81 /// Returns true if this object indicates that the public components shall be loaded.
82 pub const fn load_public(&self) -> bool {
83 self.0 & Self::PUBLIC.0 != 0
84 }
85
86 /// Returns true if the object indicates that the KeyMint component shall be loaded.
87 pub const fn load_km(&self) -> bool {
88 self.0 & Self::KM.0 != 0
89 }
90}
91
92/// This type represents a Keystore 2.0 key entry.
93/// An entry has a unique `id` by which it can be found in the database.
94/// It has a security level field, key parameters, and three optional fields
95/// for the KeyMint blob, public certificate and a public certificate chain.
96#[derive(Debug, Default, Clone, Eq, PartialEq, Ord, PartialOrd)]
97pub struct KeyEntry {
98 id: i64,
99 km_blob: Option<Vec<u8>>,
100 cert: Option<Vec<u8>>,
101 cert_chain: Option<Vec<u8>>,
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700102 sec_level: SecurityLevelType,
103 parameters: Vec<KeyParameter>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700104}
105
106impl KeyEntry {
107 /// Returns the unique id of the Key entry.
108 pub fn id(&self) -> i64 {
109 self.id
110 }
111 /// Exposes the optional KeyMint blob.
112 pub fn km_blob(&self) -> &Option<Vec<u8>> {
113 &self.km_blob
114 }
115 /// Extracts the Optional KeyMint blob.
116 pub fn take_km_blob(&mut self) -> Option<Vec<u8>> {
117 self.km_blob.take()
118 }
119 /// Exposes the optional public certificate.
120 pub fn cert(&self) -> &Option<Vec<u8>> {
121 &self.cert
122 }
123 /// Extracts the optional public certificate.
124 pub fn take_cert(&mut self) -> Option<Vec<u8>> {
125 self.cert.take()
126 }
127 /// Exposes the optional public certificate chain.
128 pub fn cert_chain(&self) -> &Option<Vec<u8>> {
129 &self.cert_chain
130 }
131 /// Extracts the optional public certificate_chain.
132 pub fn take_cert_chain(&mut self) -> Option<Vec<u8>> {
133 self.cert_chain.take()
134 }
135 /// Returns the security level of the key entry.
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700136 pub fn sec_level(&self) -> SecurityLevelType {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700137 self.sec_level
138 }
139}
140
141/// Indicates the sub component of a key entry for persistent storage.
142#[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
143pub struct SubComponentType(u32);
144impl SubComponentType {
145 /// Persistent identifier for a KeyMint blob.
146 pub const KM_BLOB: SubComponentType = Self(0);
147 /// Persistent identifier for a certificate blob.
148 pub const CERT: SubComponentType = Self(1);
149 /// Persistent identifier for a certificate chain blob.
150 pub const CERT_CHAIN: SubComponentType = Self(2);
151}
152
153impl ToSql for SubComponentType {
154 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
155 self.0.to_sql()
156 }
157}
158
159impl FromSql for SubComponentType {
160 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
161 Ok(Self(u32::column_result(value)?))
162 }
163}
164
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700165static INIT_TABLES: Once = Once::new();
166
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700167/// KeystoreDB wraps a connection to an SQLite database and tracks its
168/// ownership. It also implements all of Keystore 2.0's database functionality.
Joel Galenson26f4d012020-07-17 14:57:21 -0700169pub struct KeystoreDB {
Joel Galenson26f4d012020-07-17 14:57:21 -0700170 conn: Connection,
171}
172
173impl KeystoreDB {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700174 /// This will create a new database connection connecting the two
175 /// files persistent.sqlite and perboot.sqlite in the current working
176 /// directory, which is usually `/data/misc/keystore/`.
177 /// It also attempts to initialize all of the tables on the first instantiation
178 /// per service startup. KeystoreDB cannot be used by multiple threads.
179 /// Each thread should open their own connection using `thread_local!`.
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700180 pub fn new() -> Result<Self> {
181 let conn = Self::make_connection("file:persistent.sqlite", "file:perboot.sqlite")?;
182
183 INIT_TABLES.call_once(|| Self::init_tables(&conn).expect("Failed to initialize tables."));
184 Ok(Self { conn })
Joel Galenson2aab4432020-07-22 15:27:57 -0700185 }
186
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700187 fn init_tables(conn: &Connection) -> Result<()> {
188 conn.execute(
189 "CREATE TABLE IF NOT EXISTS persistent.keyentry (
Joel Galenson0891bc12020-07-20 10:37:03 -0700190 id INTEGER UNIQUE,
191 creation_date DATETIME,
192 domain INTEGER,
193 namespace INTEGER,
194 alias TEXT);",
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700195 NO_PARAMS,
196 )
197 .context("Failed to initialize \"keyentry\" table.")?;
198
199 conn.execute(
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700200 "CREATE VIEW IF NOT EXISTS persistent.orphaned AS
201 SELECT id FROM persistent.keyentry WHERE domain IS NULL;",
202 NO_PARAMS,
203 )
204 .context("Failed to initialize \"orphaned\" view")?;
205
206 conn.execute(
207 "CREATE TABLE IF NOT EXISTS persistent.blobentry (
208 id INTEGER PRIMARY KEY,
209 subcomponent_type INTEGER,
210 keyentryid INTEGER,
211 blob BLOB,
212 sec_level INTEGER);",
213 NO_PARAMS,
214 )
215 .context("Failed to initialize \"blobentry\" table.")?;
216
217 conn.execute(
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700218 "CREATE TABLE IF NOT EXISTS persistent.keyparameter (
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000219 keyentryid INTEGER,
220 tag INTEGER,
221 data ANY,
222 security_level INTEGER);",
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700223 NO_PARAMS,
224 )
225 .context("Failed to initialize \"keyparameter\" table.")?;
226
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700227 // TODO only drop the perboot table if we start up for the first time per boot.
228 // Right now this is done once per startup which will lose some information
229 // upon a crash.
230 // Note: This is no regression with respect to the legacy Keystore.
231 conn.execute("DROP TABLE IF EXISTS perboot.grant;", NO_PARAMS)
232 .context("Failed to drop perboot.grant table")?;
233 conn.execute(
234 "CREATE TABLE perboot.grant (
235 id INTEGER UNIQUE,
236 grantee INTEGER,
237 keyentryid INTEGER,
238 access_vector INTEGER);",
239 NO_PARAMS,
240 )
241 .context("Failed to initialize \"grant\" table.")?;
242
Joel Galenson0891bc12020-07-20 10:37:03 -0700243 Ok(())
244 }
245
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700246 fn make_connection(persistent_file: &str, perboot_file: &str) -> Result<Connection> {
247 let conn =
248 Connection::open_in_memory().context("Failed to initialize SQLite connection.")?;
249
250 conn.execute("ATTACH DATABASE ? as persistent;", params![persistent_file])
251 .context("Failed to attach database persistent.")?;
252 conn.execute("ATTACH DATABASE ? as perboot;", params![perboot_file])
253 .context("Failed to attach database perboot.")?;
254
255 Ok(conn)
256 }
257
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700258 /// Creates a new key entry and allocates a new randomized id for the new key.
259 /// The key id gets associated with a domain and namespace but not with an alias.
260 /// To complete key generation `rebind_alias` should be called after all of the
261 /// key artifacts, i.e., blobs and parameters have been associated with the new
262 /// key id. Finalizing with `rebind_alias` makes the creation of a new key entry
263 /// atomic even if key generation is not.
Janis Danisevskis60400fe2020-08-26 15:24:42 -0700264 pub fn create_key_entry(&self, domain: DomainType, namespace: i64) -> Result<i64> {
Joel Galenson0891bc12020-07-20 10:37:03 -0700265 match domain {
Janis Danisevskis60400fe2020-08-26 15:24:42 -0700266 Domain::App | Domain::SELinux => {}
Joel Galenson0891bc12020-07-20 10:37:03 -0700267 _ => {
268 return Err(KsError::sys())
269 .context(format!("Domain {:?} must be either App or SELinux.", domain));
270 }
271 }
272 // Loop until we get a unique id.
273 loop {
274 let newid: i64 = random();
275 let ret = self.conn.execute(
Joel Galenson2aab4432020-07-22 15:27:57 -0700276 "INSERT into persistent.keyentry (id, creation_date, domain, namespace, alias)
Joel Galenson0891bc12020-07-20 10:37:03 -0700277 VALUES(?, datetime('now'), ?, ?, NULL);",
278 params![newid, domain as i64, namespace],
279 );
280 match ret {
281 // If the id already existed, try again.
282 Err(rusqlite::Error::SqliteFailure(
283 libsqlite3_sys::Error {
284 code: libsqlite3_sys::ErrorCode::ConstraintViolation,
285 extended_code: libsqlite3_sys::SQLITE_CONSTRAINT_UNIQUE,
286 },
287 _,
288 )) => (),
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700289 Err(e) => return Err(e).context("Failed to create key entry."),
Joel Galenson0891bc12020-07-20 10:37:03 -0700290 _ => return Ok(newid),
291 }
292 }
Joel Galenson26f4d012020-07-17 14:57:21 -0700293 }
Joel Galenson33c04ad2020-08-03 11:04:38 -0700294
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700295 /// Inserts a new blob and associates it with the given key id. Each blob
296 /// has a sub component type and a security level.
297 /// Each key can have one of each sub component type associated. If more
298 /// are added only the most recent can be retrieved, and superseded blobs
299 /// will get garbage collected. The security level field of components
300 /// other than `SubComponentType::KM_BLOB` are ignored.
301 pub fn insert_blob(
302 &mut self,
303 key_id: i64,
304 sc_type: SubComponentType,
305 blob: &[u8],
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700306 sec_level: SecurityLevelType,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700307 ) -> Result<()> {
308 self.conn
309 .execute(
310 "INSERT into persistent.blobentry (subcomponent_type, keyentryid, blob, sec_level)
311 VALUES (?, ?, ?, ?);",
312 params![sc_type, key_id, blob, sec_level],
313 )
314 .context("Failed to insert blob.")?;
315 Ok(())
316 }
317
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700318 /// Inserts a collection of key parameters into the `persistent.keyparameter` table
319 /// and associates them with the given `key_id`.
320 pub fn insert_keyparameter<'a>(
321 &mut self,
322 key_id: i64,
323 params: impl IntoIterator<Item = &'a KeyParameter>,
324 ) -> Result<()> {
325 let mut stmt = self
326 .conn
327 .prepare(
328 "INSERT into persistent.keyparameter (keyentryid, tag, data, security_level)
329 VALUES (?, ?, ?, ?);",
330 )
331 .context("In insert_keyparameter: Failed to prepare statement.")?;
332
333 let iter = params.into_iter();
334 for p in iter {
335 stmt.insert(params![key_id, p.get_tag(), p.key_parameter_value(), p.security_level()])
336 .with_context(|| format!("In insert_keyparameter: Failed to insert {:?}", p))?;
337 }
338 Ok(())
339 }
340
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700341 /// Updates the alias column of the given key id `newid` with the given alias,
342 /// and atomically, removes the alias, domain, and namespace from another row
343 /// with the same alias-domain-namespace tuple if such row exits.
Joel Galenson33c04ad2020-08-03 11:04:38 -0700344 pub fn rebind_alias(
345 &mut self,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700346 newid: i64,
Joel Galenson33c04ad2020-08-03 11:04:38 -0700347 alias: &str,
Janis Danisevskis60400fe2020-08-26 15:24:42 -0700348 domain: DomainType,
Joel Galenson33c04ad2020-08-03 11:04:38 -0700349 namespace: i64,
350 ) -> Result<()> {
351 match domain {
Janis Danisevskis60400fe2020-08-26 15:24:42 -0700352 Domain::App | Domain::SELinux => {}
Joel Galenson33c04ad2020-08-03 11:04:38 -0700353 _ => {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700354 return Err(KsError::sys()).context(format!(
355 "In rebind_alias: Domain {:?} must be either App or SELinux.",
356 domain
357 ));
Joel Galenson33c04ad2020-08-03 11:04:38 -0700358 }
359 }
360 let tx = self
361 .conn
362 .transaction_with_behavior(TransactionBehavior::Immediate)
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700363 .context("In rebind_alias: Failed to initialize transaction.")?;
Joel Galenson33c04ad2020-08-03 11:04:38 -0700364 tx.execute(
365 "UPDATE persistent.keyentry
366 SET alias = NULL, domain = NULL, namespace = NULL
367 WHERE alias = ? AND domain = ? AND namespace = ?;",
368 params![alias, domain as i64, namespace],
369 )
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700370 .context("In rebind_alias: Failed to rebind existing entry.")?;
Joel Galenson33c04ad2020-08-03 11:04:38 -0700371 let result = tx
372 .execute(
373 "UPDATE persistent.keyentry
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700374 SET alias = ?
375 WHERE id = ? AND domain = ? AND namespace = ?;",
Joel Galenson33c04ad2020-08-03 11:04:38 -0700376 params![alias, newid, domain as i64, namespace],
377 )
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700378 .context("In rebind_alias: Failed to set alias.")?;
Joel Galenson33c04ad2020-08-03 11:04:38 -0700379 if result != 1 {
380 // Note that this explicit rollback is not required, as
381 // the transaction should rollback if we do not commit it.
382 // We leave it here for readability.
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700383 tx.rollback().context("In rebind_alias: Failed to rollback a failed transaction.")?;
Joel Galenson33c04ad2020-08-03 11:04:38 -0700384 return Err(KsError::sys()).context(format!(
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700385 "In rebind_alias: Expected to update a single entry but instead updated {}.",
Joel Galenson33c04ad2020-08-03 11:04:38 -0700386 result
387 ));
388 }
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700389 tx.commit().context("In rebind_alias: Failed to commit transaction.")
390 }
391
392 // Helper function loading the key_id given the key descriptor
393 // tuple comprising domain, namespace, and alias.
394 // Requires a valid transaction.
395 fn load_key_entry_id(key: &KeyDescriptor, tx: &Transaction) -> Result<i64> {
396 let alias = key
397 .alias
398 .as_ref()
399 .map_or_else(|| Err(KsError::sys()), Ok)
400 .context("In load_key_entry_id: Alias must be specified.")?;
401 let mut stmt = tx
402 .prepare(
403 "SELECT id FROM persistent.keyentry
404 WHERE
405 domain = ?
406 AND namespace = ?
407 AND alias = ?;",
408 )
409 .context("In load_key_entry_id: Failed to select from keyentry table.")?;
410 let mut rows = stmt
411 .query(params![key.domain, key.namespace_, alias])
412 .context("In load_key_entry_id: Failed to read from keyentry table.")?;
413 Self::with_rows_extract_one(&mut rows, |row| {
414 row.map_or_else(|| Err(KsError::Rc(error::Rc::KeyNotFound)), Ok)?
415 .get(0)
416 .context("Failed to unpack id.")
417 })
418 .context("In load_key_entry_id.")
419 }
420
421 /// This helper function completes the access tuple of a key, which is required
422 /// to perform access control. The strategy depends on the `domain` field in the
423 /// key descriptor.
424 /// * Domain::SELinux: The access tuple is complete and this function only loads
425 /// the key_id for further processing.
426 /// * Domain::App: Like Domain::SELinux, but the tuple is completed by `caller_uid`
427 /// which serves as the namespace.
428 /// * Domain::Grant: The grant table is queried for the `key_id` and the
429 /// `access_vector`.
430 /// * Domain::KeyId: The keyentry table is queried for the owning `domain` and
431 /// `namespace`.
432 /// In each case the information returned is sufficient to perform the access
433 /// check and the key id can be used to load further key artifacts.
434 fn load_access_tuple(
435 tx: &Transaction,
436 key: KeyDescriptor,
437 caller_uid: u32,
438 ) -> Result<(i64, KeyDescriptor, Option<KeyPermSet>)> {
439 match key.domain {
440 // Domain App or SELinux. In this case we load the key_id from
441 // the keyentry database for further loading of key components.
442 // We already have the full access tuple to perform access control.
443 // The only distinction is that we use the caller_uid instead
444 // of the caller supplied namespace if the domain field is
445 // Domain::App.
446 Domain::App | Domain::SELinux => {
447 let mut access_key = key;
448 if access_key.domain == Domain::App {
449 access_key.namespace_ = caller_uid as i64;
450 }
451 let key_id = Self::load_key_entry_id(&access_key, &tx)
452 .with_context(|| format!("With key.domain = {}.", access_key.domain))?;
453
454 Ok((key_id, access_key, None))
455 }
456
457 // Domain::Grant. In this case we load the key_id and the access_vector
458 // from the grant table.
459 Domain::Grant => {
460 let mut stmt = tx
461 .prepare(
462 "SELECT keyentryid, access_vector FROM perboot.grant
463 WHERE grantee = ? AND id = ?;",
464 )
465 .context("Domain::Grant prepare statement failed")?;
466 let mut rows = stmt
467 .query(params![caller_uid as i64, key.namespace_])
468 .context("Domain:Grant: query failed.")?;
469 let (key_id, access_vector): (i64, i32) =
470 Self::with_rows_extract_one(&mut rows, |row| {
471 let r = row.map_or_else(|| Err(KsError::Rc(error::Rc::KeyNotFound)), Ok)?;
472 Ok((
473 r.get(0).context("Failed to unpack key_id.")?,
474 r.get(1).context("Failed to unpack access_vector.")?,
475 ))
476 })
477 .context("Domain::Grant.")?;
478 Ok((key_id, key, Some(access_vector.into())))
479 }
480
481 // Domain::KeyId. In this case we load the domain and namespace from the
482 // keyentry database because we need them for access control.
483 Domain::KeyId => {
484 let mut stmt = tx
485 .prepare(
486 "SELECT domain, namespace FROM persistent.keyentry
487 WHERE
488 id = ?;",
489 )
490 .context("Domain::KeyId: prepare statement failed")?;
491 let mut rows =
492 stmt.query(params![key.namespace_]).context("Domain::KeyId: query failed.")?;
493 let (domain, namespace): (DomainType, i64) =
494 Self::with_rows_extract_one(&mut rows, |row| {
495 let r = row.map_or_else(|| Err(KsError::Rc(error::Rc::KeyNotFound)), Ok)?;
496 Ok((
497 r.get(0).context("Failed to unpack domain.")?,
498 r.get(1).context("Failed to unpack namespace.")?,
499 ))
500 })
501 .context("Domain::KeyId.")?;
502 let key_id = key.namespace_;
503 let mut access_key = key;
504 access_key.domain = domain;
505 access_key.namespace_ = namespace;
506
507 Ok((key_id, access_key, None))
508 }
509 _ => Err(anyhow!(KsError::sys())),
510 }
511 }
512
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700513 fn load_blob_components(
514 key_id: i64,
515 load_bits: KeyEntryLoadBits,
516 tx: &Transaction,
517 ) -> Result<(SecurityLevelType, Option<Vec<u8>>, Option<Vec<u8>>, Option<Vec<u8>>)> {
518 let mut stmt = tx
519 .prepare(
520 "SELECT MAX(id), sec_level, subcomponent_type, blob FROM persistent.blobentry
521 WHERE keyentryid = ? GROUP BY subcomponent_type;",
522 )
523 .context("In load_blob_components: prepare statement failed.")?;
524
525 let mut rows =
526 stmt.query(params![key_id]).context("In load_blob_components: query failed.")?;
527
528 let mut sec_level: SecurityLevelType = Default::default();
529 let mut km_blob: Option<Vec<u8>> = None;
530 let mut cert_blob: Option<Vec<u8>> = None;
531 let mut cert_chain_blob: Option<Vec<u8>> = None;
532 Self::with_rows_extract_all(&mut rows, |row| {
533 let sub_type: SubComponentType =
534 row.get(2).context("Failed to extract subcomponent_type.")?;
535 match (sub_type, load_bits.load_public()) {
536 (SubComponentType::KM_BLOB, _) => {
537 sec_level = row.get(1).context("Failed to extract security level.")?;
538 if load_bits.load_km() {
539 km_blob = Some(row.get(3).context("Failed to extract KM blob.")?);
540 }
541 }
542 (SubComponentType::CERT, true) => {
543 cert_blob =
544 Some(row.get(3).context("Failed to extract public certificate blob.")?);
545 }
546 (SubComponentType::CERT_CHAIN, true) => {
547 cert_chain_blob =
548 Some(row.get(3).context("Failed to extract certificate chain blob.")?);
549 }
550 (SubComponentType::CERT, _) | (SubComponentType::CERT_CHAIN, _) => {}
551 _ => Err(KsError::sys()).context("Unknown subcomponent type.")?,
552 }
553 Ok(())
554 })
555 .context("In load_blob_components.")?;
556
557 Ok((sec_level, km_blob, cert_blob, cert_chain_blob))
558 }
559
560 fn load_key_parameters(key_id: i64, tx: &Transaction) -> Result<Vec<KeyParameter>> {
561 let mut stmt = tx
562 .prepare(
563 "SELECT tag, data, security_level from persistent.keyparameter
564 WHERE keyentryid = ?;",
565 )
566 .context("In load_key_parameters: prepare statement failed.")?;
567
568 let mut parameters: Vec<KeyParameter> = Vec::new();
569
570 let mut rows =
571 stmt.query(params![key_id]).context("In load_key_parameters: query failed.")?;
572 Self::with_rows_extract_all(&mut rows, |row| {
573 let tag: TagType = row.get(0).context("Failed to read tag.")?;
574 let sec_level: SecurityLevelType = row.get(2).context("Failed to read sec_level.")?;
575 parameters.push(
576 KeyParameter::new_from_sql(tag, &SqlField::new(1, &row), sec_level)
577 .context("Failed to read KeyParameter.")?,
578 );
579 Ok(())
580 })
581 .context("In load_key_parameters.")?;
582
583 Ok(parameters)
584 }
585
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700586 /// Load a key entry by the given key descriptor.
587 /// It uses the `check_permission` callback to verify if the access is allowed
588 /// given the key access tuple read from the database using `load_access_tuple`.
589 /// With `load_bits` the caller may specify which blobs shall be loaded from
590 /// the blob database.
591 pub fn load_key_entry(
592 &mut self,
593 key: KeyDescriptor,
594 load_bits: KeyEntryLoadBits,
595 caller_uid: u32,
596 check_permission: impl FnOnce(&KeyDescriptor, Option<KeyPermSet>) -> Result<()>,
597 ) -> Result<KeyEntry> {
598 let tx = self
599 .conn
600 .transaction_with_behavior(TransactionBehavior::Deferred)
601 .context("In load_key_entry: Failed to initialize transaction.")?;
602
603 // Load the key_id and complete the access control tuple.
604 let (key_id, access_key_descriptor, access_vector) =
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700605 Self::load_access_tuple(&tx, key, caller_uid).context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700606
607 // Perform access control. It is vital that we return here if the permission is denied.
608 // So do not touch that '?' at the end.
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700609 check_permission(&access_key_descriptor, access_vector).context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700610
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700611 let (sec_level, km_blob, cert_blob, cert_chain_blob) =
612 Self::load_blob_components(key_id, load_bits, &tx).context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700613
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700614 let parameters = Self::load_key_parameters(key_id, &tx).context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700615
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700616 tx.commit().context("In load_key_entry: Failed to commit transaction.")?;
617
618 Ok(KeyEntry {
619 id: key_id,
620 km_blob,
621 cert: cert_blob,
622 cert_chain: cert_chain_blob,
623 sec_level,
624 parameters,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700625 })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700626 }
627
628 /// Adds a grant to the grant table.
629 /// Like `load_key_entry` this function loads the access tuple before
630 /// it uses the callback for a permission check. Upon success,
631 /// it inserts the `grantee_uid`, `key_id`, and `access_vector` into the
632 /// grant table. The new row will have a randomized id, which is used as
633 /// grant id in the namespace field of the resulting KeyDescriptor.
634 pub fn grant(
635 &mut self,
636 key: KeyDescriptor,
637 caller_uid: u32,
638 grantee_uid: u32,
639 access_vector: KeyPermSet,
640 check_permission: impl FnOnce(&KeyDescriptor, &KeyPermSet) -> Result<()>,
641 ) -> Result<KeyDescriptor> {
642 let tx = self
643 .conn
644 .transaction_with_behavior(TransactionBehavior::Immediate)
645 .context("In grant: Failed to initialize transaction.")?;
646
647 // Load the key_id and complete the access control tuple.
648 // We ignore the access vector here because grants cannot be granted.
649 // The access vector returned here expresses the permissions the
650 // grantee has if key.domain == Domain::Grant. But this vector
651 // cannot include the grant permission by design, so there is no way the
652 // subsequent permission check can pass.
653 // We could check key.domain == Domain::Grant and fail early.
654 // But even if we load the access tuple by grant here, the permission
655 // check denies the attempt to create a grant by grant descriptor.
656 let (key_id, access_key_descriptor, _) =
657 Self::load_access_tuple(&tx, key, caller_uid).context("In grant")?;
658
659 // Perform access control. It is vital that we return here if the permission
660 // was denied. So do not touch that '?' at the end of the line.
661 // This permission check checks if the caller has the grant permission
662 // for the given key and in addition to all of the permissions
663 // expressed in `access_vector`.
664 check_permission(&access_key_descriptor, &access_vector)
665 .context("In grant: check_permission failed.")?;
666
667 let grant_id = if let Some(grant_id) = tx
668 .query_row(
669 "SELECT id FROM perboot.grant
670 WHERE keyentryid = ? AND grantee = ?;",
671 params![key_id, grantee_uid],
672 |row| row.get(0),
673 )
674 .optional()
675 .context("In grant: Failed get optional existing grant id.")?
676 {
677 tx.execute(
678 "UPDATE perboot.grant
679 SET access_vector = ?
680 WHERE id = ?;",
681 params![i32::from(access_vector), grant_id],
682 )
683 .context("In grant: Failed to update existing grant.")?;
684 grant_id
685 } else {
686 loop {
687 let newid: i64 = random();
688 let ret = tx.execute(
689 "INSERT INTO perboot.grant (id, grantee, keyentryid, access_vector)
690 VALUES (?, ?, ?, ?);",
691 params![newid, grantee_uid, key_id, i32::from(access_vector)],
692 );
693 match ret {
694 // If the id already existed, try again.
695 Err(rusqlite::Error::SqliteFailure(
696 libsqlite3_sys::Error {
697 code: libsqlite3_sys::ErrorCode::ConstraintViolation,
698 extended_code: libsqlite3_sys::SQLITE_CONSTRAINT_UNIQUE,
699 },
700 _,
701 )) => (),
702 Err(e) => return Err(e).context("Failed to insert grant."),
703 Ok(_) => break newid,
704 }
705 }
706 };
707 tx.commit().context("In grant: failed to commit transaction.")?;
708
709 Ok(KeyDescriptor { domain: Domain::Grant, namespace_: grant_id, alias: None, blob: None })
710 }
711
712 /// This function checks permissions like `grant` and `load_key_entry`
713 /// before removing a grant from the grant table.
714 pub fn ungrant(
715 &mut self,
716 key: KeyDescriptor,
717 caller_uid: u32,
718 grantee_uid: u32,
719 check_permission: impl FnOnce(&KeyDescriptor) -> Result<()>,
720 ) -> Result<()> {
721 let tx = self
722 .conn
723 .transaction_with_behavior(TransactionBehavior::Immediate)
724 .context("In ungrant: Failed to initialize transaction.")?;
725
726 // Load the key_id and complete the access control tuple.
727 // We ignore the access vector here because grants cannot be granted.
728 let (key_id, access_key_descriptor, _) =
729 Self::load_access_tuple(&tx, key, caller_uid).context("In ungrant.")?;
730
731 // Perform access control. We must return here if the permission
732 // was denied. So do not touch the '?' at the end of this line.
733 check_permission(&access_key_descriptor).context("In grant: check_permission failed.")?;
734
735 tx.execute(
736 "DELETE FROM perboot.grant
737 WHERE keyentryid = ? AND grantee = ?;",
738 params![key_id, grantee_uid],
739 )
740 .context("Failed to delete grant.")?;
741
742 tx.commit().context("In ungrant: failed to commit transaction.")?;
743
744 Ok(())
745 }
746
747 // Takes Rows as returned by a query call on prepared statement.
748 // Extracts exactly one row with the `row_extractor` and fails if more
749 // rows are available.
750 // If no row was found, `None` is passed to the `row_extractor`.
751 // This allows the row extractor to decide on an error condition or
752 // a different default behavior.
753 fn with_rows_extract_one<'a, T, F>(rows: &mut Rows<'a>, row_extractor: F) -> Result<T>
754 where
755 F: FnOnce(Option<&Row<'a>>) -> Result<T>,
756 {
757 let result =
758 row_extractor(rows.next().context("with_rows_extract_one: Failed to unpack row.")?);
759
760 rows.next()
761 .context("In with_rows_extract_one: Failed to unpack unexpected row.")?
762 .map_or_else(|| Ok(()), |_| Err(KsError::sys()))
763 .context("In with_rows_extract_one: Unexpected row.")?;
764
765 result
766 }
767
768 fn with_rows_extract_all<'a, F>(rows: &mut Rows<'a>, mut row_extractor: F) -> Result<()>
769 where
770 F: FnMut(&Row<'a>) -> Result<()>,
771 {
772 loop {
773 match rows.next().context("In with_rows_extract_all: Failed to unpack row")? {
774 Some(row) => {
775 row_extractor(&row).context("In with_rows_extract_all.")?;
776 }
777 None => break Ok(()),
778 }
779 }
Joel Galenson33c04ad2020-08-03 11:04:38 -0700780 }
Joel Galenson26f4d012020-07-17 14:57:21 -0700781}
782
783#[cfg(test)]
784mod tests {
785
786 use super::*;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700787 use crate::key_parameter::{
788 Algorithm, BlockMode, Digest, EcCurve, HardwareAuthenticatorType, KeyOrigin, KeyParameter,
789 KeyParameterValue, KeyPurpose, PaddingMode, SecurityLevel,
790 };
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700791 use crate::key_perm_set;
792 use crate::permission::{KeyPerm, KeyPermSet};
793 use rusqlite::NO_PARAMS;
Joel Galenson0891bc12020-07-20 10:37:03 -0700794 use std::cell::RefCell;
795
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700796 static PERSISTENT_TEST_SQL: &str = "/data/local/tmp/persistent.sqlite";
797 static PERBOOT_TEST_SQL: &str = "/data/local/tmp/perboot.sqlite";
798
799 fn new_test_db() -> Result<KeystoreDB> {
800 let conn = KeystoreDB::make_connection("file::memory:", "file::memory:")?;
801
802 KeystoreDB::init_tables(&conn).context("Failed to initialize tables.")?;
803 Ok(KeystoreDB { conn })
804 }
805
806 fn new_test_db_with_persistent_file() -> Result<KeystoreDB> {
807 let conn = KeystoreDB::make_connection(PERSISTENT_TEST_SQL, PERBOOT_TEST_SQL)?;
808
809 KeystoreDB::init_tables(&conn).context("Failed to initialize tables.")?;
810 Ok(KeystoreDB { conn })
811 }
812
Joel Galenson0891bc12020-07-20 10:37:03 -0700813 // Ensure that we're using the "injected" random function, not the real one.
814 #[test]
815 fn test_mocked_random() {
816 let rand1 = random();
817 let rand2 = random();
818 let rand3 = random();
819 if rand1 == rand2 {
820 assert_eq!(rand2 + 1, rand3);
821 } else {
822 assert_eq!(rand1 + 1, rand2);
823 assert_eq!(rand2, rand3);
824 }
825 }
Joel Galenson26f4d012020-07-17 14:57:21 -0700826
Joel Galenson26f4d012020-07-17 14:57:21 -0700827 // Test that we have the correct tables.
828 #[test]
829 fn test_tables() -> Result<()> {
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700830 let db = new_test_db()?;
Joel Galenson26f4d012020-07-17 14:57:21 -0700831 let tables = db
832 .conn
Joel Galenson2aab4432020-07-22 15:27:57 -0700833 .prepare("SELECT name from persistent.sqlite_master WHERE type='table' ORDER BY name;")?
Joel Galenson26f4d012020-07-17 14:57:21 -0700834 .query_map(params![], |row| row.get(0))?
835 .collect::<rusqlite::Result<Vec<String>>>()?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700836 assert_eq!(tables.len(), 3);
837 assert_eq!(tables[0], "blobentry");
838 assert_eq!(tables[1], "keyentry");
839 assert_eq!(tables[2], "keyparameter");
840 let tables = db
841 .conn
842 .prepare("SELECT name from perboot.sqlite_master WHERE type='table' ORDER BY name;")?
843 .query_map(params![], |row| row.get(0))?
844 .collect::<rusqlite::Result<Vec<String>>>()?;
845 assert_eq!(tables.len(), 1);
846 assert_eq!(tables[0], "grant");
Joel Galenson26f4d012020-07-17 14:57:21 -0700847 Ok(())
848 }
Joel Galenson0891bc12020-07-20 10:37:03 -0700849
850 #[test]
Joel Galenson2aab4432020-07-22 15:27:57 -0700851 fn test_no_persistence_for_tests() -> Result<()> {
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700852 let db = new_test_db()?;
Joel Galenson2aab4432020-07-22 15:27:57 -0700853
Janis Danisevskis60400fe2020-08-26 15:24:42 -0700854 db.create_key_entry(Domain::App, 100)?;
Joel Galenson2aab4432020-07-22 15:27:57 -0700855 let entries = get_keyentry(&db)?;
856 assert_eq!(entries.len(), 1);
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700857 let db = new_test_db()?;
Joel Galenson2aab4432020-07-22 15:27:57 -0700858
859 let entries = get_keyentry(&db)?;
860 assert_eq!(entries.len(), 0);
861 Ok(())
862 }
863
864 #[test]
865 fn test_persistence_for_files() -> Result<()> {
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700866 let _file_guard_persistent = TempFile { filename: PERSISTENT_TEST_SQL };
867 let _file_guard_perboot = TempFile { filename: PERBOOT_TEST_SQL };
868 let db = new_test_db_with_persistent_file()?;
Joel Galenson2aab4432020-07-22 15:27:57 -0700869
Janis Danisevskis60400fe2020-08-26 15:24:42 -0700870 db.create_key_entry(Domain::App, 100)?;
Joel Galenson2aab4432020-07-22 15:27:57 -0700871 let entries = get_keyentry(&db)?;
872 assert_eq!(entries.len(), 1);
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700873 let db = new_test_db_with_persistent_file()?;
Joel Galenson2aab4432020-07-22 15:27:57 -0700874
875 let entries_new = get_keyentry(&db)?;
876 assert_eq!(entries, entries_new);
877 Ok(())
878 }
879
880 #[test]
Joel Galenson0891bc12020-07-20 10:37:03 -0700881 fn test_create_key_entry() -> Result<()> {
Janis Danisevskis60400fe2020-08-26 15:24:42 -0700882 fn extractor(ke: &KeyEntryRow) -> (DomainType, i64, Option<&str>) {
Joel Galenson0891bc12020-07-20 10:37:03 -0700883 (ke.domain.unwrap(), ke.namespace.unwrap(), ke.alias.as_deref())
884 }
885
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700886 let db = new_test_db()?;
Joel Galenson0891bc12020-07-20 10:37:03 -0700887
888 db.create_key_entry(Domain::App, 100)?;
889 db.create_key_entry(Domain::SELinux, 101)?;
890
891 let entries = get_keyentry(&db)?;
892 assert_eq!(entries.len(), 2);
893 assert_eq!(extractor(&entries[0]), (Domain::App, 100, None));
894 assert_eq!(extractor(&entries[1]), (Domain::SELinux, 101, None));
895
896 // Test that we must pass in a valid Domain.
897 check_result_is_error_containing_string(
898 db.create_key_entry(Domain::Grant, 102),
Janis Danisevskis60400fe2020-08-26 15:24:42 -0700899 "Domain 1 must be either App or SELinux.",
Joel Galenson0891bc12020-07-20 10:37:03 -0700900 );
901 check_result_is_error_containing_string(
902 db.create_key_entry(Domain::Blob, 103),
Janis Danisevskis60400fe2020-08-26 15:24:42 -0700903 "Domain 3 must be either App or SELinux.",
Joel Galenson0891bc12020-07-20 10:37:03 -0700904 );
905 check_result_is_error_containing_string(
906 db.create_key_entry(Domain::KeyId, 104),
Janis Danisevskis60400fe2020-08-26 15:24:42 -0700907 "Domain 4 must be either App or SELinux.",
Joel Galenson0891bc12020-07-20 10:37:03 -0700908 );
909
910 Ok(())
911 }
912
Joel Galenson33c04ad2020-08-03 11:04:38 -0700913 #[test]
914 fn test_rebind_alias() -> Result<()> {
Janis Danisevskis60400fe2020-08-26 15:24:42 -0700915 fn extractor(ke: &KeyEntryRow) -> (Option<DomainType>, Option<i64>, Option<&str>) {
Joel Galenson33c04ad2020-08-03 11:04:38 -0700916 (ke.domain, ke.namespace, ke.alias.as_deref())
917 }
918
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700919 let mut db = new_test_db()?;
Joel Galenson33c04ad2020-08-03 11:04:38 -0700920 db.create_key_entry(Domain::App, 42)?;
921 db.create_key_entry(Domain::App, 42)?;
922 let entries = get_keyentry(&db)?;
923 assert_eq!(entries.len(), 2);
924 assert_eq!(extractor(&entries[0]), (Some(Domain::App), Some(42), None));
925 assert_eq!(extractor(&entries[1]), (Some(Domain::App), Some(42), None));
926
927 // Test that the first call to rebind_alias sets the alias.
928 db.rebind_alias(entries[0].id, "foo", Domain::App, 42)?;
929 let entries = get_keyentry(&db)?;
930 assert_eq!(entries.len(), 2);
931 assert_eq!(extractor(&entries[0]), (Some(Domain::App), Some(42), Some("foo")));
932 assert_eq!(extractor(&entries[1]), (Some(Domain::App), Some(42), None));
933
934 // Test that the second call to rebind_alias also empties the old one.
935 db.rebind_alias(entries[1].id, "foo", Domain::App, 42)?;
936 let entries = get_keyentry(&db)?;
937 assert_eq!(entries.len(), 2);
938 assert_eq!(extractor(&entries[0]), (None, None, None));
939 assert_eq!(extractor(&entries[1]), (Some(Domain::App), Some(42), Some("foo")));
940
941 // Test that we must pass in a valid Domain.
942 check_result_is_error_containing_string(
943 db.rebind_alias(0, "foo", Domain::Grant, 42),
Janis Danisevskis60400fe2020-08-26 15:24:42 -0700944 "Domain 1 must be either App or SELinux.",
Joel Galenson33c04ad2020-08-03 11:04:38 -0700945 );
946 check_result_is_error_containing_string(
947 db.rebind_alias(0, "foo", Domain::Blob, 42),
Janis Danisevskis60400fe2020-08-26 15:24:42 -0700948 "Domain 3 must be either App or SELinux.",
Joel Galenson33c04ad2020-08-03 11:04:38 -0700949 );
950 check_result_is_error_containing_string(
951 db.rebind_alias(0, "foo", Domain::KeyId, 42),
Janis Danisevskis60400fe2020-08-26 15:24:42 -0700952 "Domain 4 must be either App or SELinux.",
Joel Galenson33c04ad2020-08-03 11:04:38 -0700953 );
954
955 // Test that we correctly handle setting an alias for something that does not exist.
956 check_result_is_error_containing_string(
957 db.rebind_alias(0, "foo", Domain::SELinux, 42),
958 "Expected to update a single entry but instead updated 0",
959 );
960 // Test that we correctly abort the transaction in this case.
961 let entries = get_keyentry(&db)?;
962 assert_eq!(entries.len(), 2);
963 assert_eq!(extractor(&entries[0]), (None, None, None));
964 assert_eq!(extractor(&entries[1]), (Some(Domain::App), Some(42), Some("foo")));
965
966 Ok(())
967 }
968
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700969 #[test]
970 fn test_grant_ungrant() -> Result<()> {
971 const CALLER_UID: u32 = 15;
972 const GRANTEE_UID: u32 = 12;
973 const SELINUX_NAMESPACE: i64 = 7;
974
975 let mut db = new_test_db()?;
976 db.conn.execute(
977 "INSERT INTO persistent.keyentry (id, creation_date, domain, namespace, alias)
978 VALUES (1, '1980', 0, 15, 'key'), (2, '1980', 2, 7, 'yek');",
979 NO_PARAMS,
980 )?;
981 let app_key = KeyDescriptor {
982 domain: super::Domain::App,
983 namespace_: 0,
984 alias: Some("key".to_string()),
985 blob: None,
986 };
987 const PVEC1: KeyPermSet = key_perm_set![KeyPerm::use_(), KeyPerm::get_info()];
988 const PVEC2: KeyPermSet = key_perm_set![KeyPerm::use_()];
989
990 // Reset totally predictable random number generator in case we
991 // are not the first test running on this thread.
992 reset_random();
993 let next_random = 0i64;
994
995 let app_granted_key =
996 db.grant(app_key.clone(), CALLER_UID, GRANTEE_UID, PVEC1, |k, a| {
997 assert_eq!(*a, PVEC1);
998 assert_eq!(
999 *k,
1000 KeyDescriptor {
1001 domain: super::Domain::App,
1002 // namespace must be set to the caller_uid.
1003 namespace_: CALLER_UID as i64,
1004 alias: Some("key".to_string()),
1005 blob: None,
1006 }
1007 );
1008 Ok(())
1009 })?;
1010
1011 assert_eq!(
1012 app_granted_key,
1013 KeyDescriptor {
1014 domain: super::Domain::Grant,
1015 // The grantid is next_random due to the mock random number generator.
1016 namespace_: next_random,
1017 alias: None,
1018 blob: None,
1019 }
1020 );
1021
1022 let selinux_key = KeyDescriptor {
1023 domain: super::Domain::SELinux,
1024 namespace_: SELINUX_NAMESPACE,
1025 alias: Some("yek".to_string()),
1026 blob: None,
1027 };
1028
1029 let selinux_granted_key =
1030 db.grant(selinux_key.clone(), CALLER_UID, 12, PVEC1, |k, a| {
1031 assert_eq!(*a, PVEC1);
1032 assert_eq!(
1033 *k,
1034 KeyDescriptor {
1035 domain: super::Domain::SELinux,
1036 // namespace must be the supplied SELinux
1037 // namespace.
1038 namespace_: SELINUX_NAMESPACE,
1039 alias: Some("yek".to_string()),
1040 blob: None,
1041 }
1042 );
1043 Ok(())
1044 })?;
1045
1046 assert_eq!(
1047 selinux_granted_key,
1048 KeyDescriptor {
1049 domain: super::Domain::Grant,
1050 // The grantid is next_random + 1 due to the mock random number generator.
1051 namespace_: next_random + 1,
1052 alias: None,
1053 blob: None,
1054 }
1055 );
1056
1057 // This should update the existing grant with PVEC2.
1058 let selinux_granted_key =
1059 db.grant(selinux_key.clone(), CALLER_UID, 12, PVEC2, |k, a| {
1060 assert_eq!(*a, PVEC2);
1061 assert_eq!(
1062 *k,
1063 KeyDescriptor {
1064 domain: super::Domain::SELinux,
1065 // namespace must be the supplied SELinux
1066 // namespace.
1067 namespace_: SELINUX_NAMESPACE,
1068 alias: Some("yek".to_string()),
1069 blob: None,
1070 }
1071 );
1072 Ok(())
1073 })?;
1074
1075 assert_eq!(
1076 selinux_granted_key,
1077 KeyDescriptor {
1078 domain: super::Domain::Grant,
1079 // Same grant id as before. The entry was only updated.
1080 namespace_: next_random + 1,
1081 alias: None,
1082 blob: None,
1083 }
1084 );
1085
1086 {
1087 // Limiting scope of stmt, because it borrows db.
1088 let mut stmt = db
1089 .conn
1090 .prepare("SELECT id, grantee, keyentryid, access_vector FROM perboot.grant;")?;
1091 let mut rows = stmt.query_map::<(i64, u32, i64, i32), _, _>(NO_PARAMS, |row| {
1092 Ok((row.get(0)?, row.get(1)?, row.get(2)?, row.get(3)?))
1093 })?;
1094
1095 let r = rows.next().unwrap().unwrap();
1096 assert_eq!(r, (next_random, GRANTEE_UID, 1, 516));
1097 let r = rows.next().unwrap().unwrap();
1098 assert_eq!(r, (next_random + 1, GRANTEE_UID, 2, 512));
1099 assert!(rows.next().is_none());
1100 }
1101
1102 debug_dump_keyentry_table(&mut db)?;
1103 println!("app_key {:?}", app_key);
1104 println!("selinux_key {:?}", selinux_key);
1105
1106 db.ungrant(app_key, CALLER_UID, GRANTEE_UID, |_| Ok(()))?;
1107 db.ungrant(selinux_key, CALLER_UID, GRANTEE_UID, |_| Ok(()))?;
1108
1109 Ok(())
1110 }
1111
1112 static TEST_KM_BLOB: &[u8] = b"my test blob";
1113 static TEST_CERT_BLOB: &[u8] = b"my test cert";
1114 static TEST_CERT_CHAIN_BLOB: &[u8] = b"my test cert_chain";
1115
1116 #[test]
1117 fn test_insert_blob() -> Result<()> {
1118 let mut db = new_test_db()?;
1119 db.insert_blob(1, SubComponentType::KM_BLOB, TEST_KM_BLOB, 1)?;
1120 db.insert_blob(1, SubComponentType::CERT, TEST_CERT_BLOB, 2)?;
1121 db.insert_blob(1, SubComponentType::CERT_CHAIN, TEST_CERT_CHAIN_BLOB, 3)?;
1122
1123 let mut stmt = db.conn.prepare(
1124 "SELECT subcomponent_type, keyentryid, blob, sec_level FROM persistent.blobentry
1125 ORDER BY sec_level ASC;",
1126 )?;
1127 let mut rows = stmt
1128 .query_map::<(SubComponentType, i64, Vec<u8>, i64), _, _>(NO_PARAMS, |row| {
1129 Ok((row.get(0)?, row.get(1)?, row.get(2)?, row.get(3)?))
1130 })?;
1131 let r = rows.next().unwrap().unwrap();
1132 assert_eq!(r, (SubComponentType::KM_BLOB, 1, TEST_KM_BLOB.to_vec(), 1));
1133 let r = rows.next().unwrap().unwrap();
1134 assert_eq!(r, (SubComponentType::CERT, 1, TEST_CERT_BLOB.to_vec(), 2));
1135 let r = rows.next().unwrap().unwrap();
1136 assert_eq!(r, (SubComponentType::CERT_CHAIN, 1, TEST_CERT_CHAIN_BLOB.to_vec(), 3));
1137
1138 Ok(())
1139 }
1140
1141 static TEST_ALIAS: &str = "my super duper key";
1142
1143 #[test]
1144 fn test_insert_and_load_full_keyentry_domain_app() -> Result<()> {
1145 let mut db = new_test_db()?;
1146 let key_id = make_test_key_entry(&mut db, Domain::App, 1, TEST_ALIAS)
1147 .context("test_insert_and_load_full_keyentry_domain_app")?;
1148 let key_entry = db.load_key_entry(
1149 KeyDescriptor {
1150 domain: Domain::App,
1151 namespace_: 0,
1152 alias: Some(TEST_ALIAS.to_string()),
1153 blob: None,
1154 },
1155 KeyEntryLoadBits::BOTH,
1156 1,
1157 |_k, _av| Ok(()),
1158 )?;
1159 assert_eq!(
1160 key_entry,
1161 KeyEntry {
1162 id: key_id,
1163 km_blob: Some(TEST_KM_BLOB.to_vec()),
1164 cert: Some(TEST_CERT_BLOB.to_vec()),
1165 cert_chain: Some(TEST_CERT_CHAIN_BLOB.to_vec()),
1166 sec_level: 1,
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001167 parameters: make_test_params()
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001168 }
1169 );
1170 Ok(())
1171 }
1172
1173 #[test]
1174 fn test_insert_and_load_full_keyentry_domain_selinux() -> Result<()> {
1175 let mut db = new_test_db()?;
1176 let key_id = make_test_key_entry(&mut db, Domain::SELinux, 1, TEST_ALIAS)
1177 .context("test_insert_and_load_full_keyentry_domain_selinux")?;
1178 let key_entry = db.load_key_entry(
1179 KeyDescriptor {
1180 domain: Domain::SELinux,
1181 namespace_: 1,
1182 alias: Some(TEST_ALIAS.to_string()),
1183 blob: None,
1184 },
1185 KeyEntryLoadBits::BOTH,
1186 1,
1187 |_k, _av| Ok(()),
1188 )?;
1189 assert_eq!(
1190 key_entry,
1191 KeyEntry {
1192 id: key_id,
1193 km_blob: Some(TEST_KM_BLOB.to_vec()),
1194 cert: Some(TEST_CERT_BLOB.to_vec()),
1195 cert_chain: Some(TEST_CERT_CHAIN_BLOB.to_vec()),
1196 sec_level: 1,
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001197 parameters: make_test_params()
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001198 }
1199 );
1200 Ok(())
1201 }
1202
1203 #[test]
1204 fn test_insert_and_load_full_keyentry_domain_key_id() -> Result<()> {
1205 let mut db = new_test_db()?;
1206 let key_id = make_test_key_entry(&mut db, Domain::SELinux, 1, TEST_ALIAS)
1207 .context("test_insert_and_load_full_keyentry_domain_key_id")?;
1208 let key_entry = db.load_key_entry(
1209 KeyDescriptor { domain: Domain::KeyId, namespace_: key_id, alias: None, blob: None },
1210 KeyEntryLoadBits::BOTH,
1211 1,
1212 |_k, _av| Ok(()),
1213 )?;
1214 assert_eq!(
1215 key_entry,
1216 KeyEntry {
1217 id: key_id,
1218 km_blob: Some(TEST_KM_BLOB.to_vec()),
1219 cert: Some(TEST_CERT_BLOB.to_vec()),
1220 cert_chain: Some(TEST_CERT_CHAIN_BLOB.to_vec()),
1221 sec_level: 1,
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001222 parameters: make_test_params()
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001223 }
1224 );
1225
1226 Ok(())
1227 }
1228
1229 #[test]
1230 fn test_insert_and_load_full_keyentry_from_grant() -> Result<()> {
1231 let mut db = new_test_db()?;
1232 let key_id = make_test_key_entry(&mut db, Domain::App, 1, TEST_ALIAS)
1233 .context("test_insert_and_load_full_keyentry_from_grant")?;
1234
1235 let granted_key = db.grant(
1236 KeyDescriptor {
1237 domain: Domain::App,
1238 namespace_: 0,
1239 alias: Some(TEST_ALIAS.to_string()),
1240 blob: None,
1241 },
1242 1,
1243 2,
1244 key_perm_set![KeyPerm::use_()],
1245 |_k, _av| Ok(()),
1246 )?;
1247
1248 debug_dump_grant_table(&mut db)?;
1249
1250 let key_entry = db.load_key_entry(granted_key, KeyEntryLoadBits::BOTH, 2, |k, av| {
1251 assert_eq!(Domain::Grant, k.domain);
1252 assert!(av.unwrap().includes(KeyPerm::use_()));
1253 Ok(())
1254 })?;
1255
1256 assert_eq!(
1257 key_entry,
1258 KeyEntry {
1259 id: key_id,
1260 km_blob: Some(TEST_KM_BLOB.to_vec()),
1261 cert: Some(TEST_CERT_BLOB.to_vec()),
1262 cert_chain: Some(TEST_CERT_CHAIN_BLOB.to_vec()),
1263 sec_level: 1,
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001264 parameters: make_test_params()
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001265 }
1266 );
1267 Ok(())
1268 }
1269
Joel Galenson0891bc12020-07-20 10:37:03 -07001270 // Helpers
1271
1272 // Checks that the given result is an error containing the given string.
1273 fn check_result_is_error_containing_string<T>(result: Result<T>, target: &str) {
1274 let error_str = format!(
1275 "{:#?}",
1276 result.err().unwrap_or_else(|| panic!("Expected the error: {}", target))
1277 );
1278 assert!(
1279 error_str.contains(target),
1280 "The string \"{}\" should contain \"{}\"",
1281 error_str,
1282 target
1283 );
1284 }
1285
Joel Galenson2aab4432020-07-22 15:27:57 -07001286 #[derive(Debug, PartialEq)]
Joel Galenson0891bc12020-07-20 10:37:03 -07001287 #[allow(dead_code)]
1288 struct KeyEntryRow {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001289 id: i64,
Joel Galenson0891bc12020-07-20 10:37:03 -07001290 creation_date: String,
Janis Danisevskis60400fe2020-08-26 15:24:42 -07001291 domain: Option<DomainType>,
Joel Galenson0891bc12020-07-20 10:37:03 -07001292 namespace: Option<i64>,
1293 alias: Option<String>,
1294 }
1295
1296 fn get_keyentry(db: &KeystoreDB) -> Result<Vec<KeyEntryRow>> {
1297 db.conn
Joel Galenson2aab4432020-07-22 15:27:57 -07001298 .prepare("SELECT * FROM persistent.keyentry;")?
Joel Galenson0891bc12020-07-20 10:37:03 -07001299 .query_map(NO_PARAMS, |row| {
Joel Galenson0891bc12020-07-20 10:37:03 -07001300 Ok(KeyEntryRow {
1301 id: row.get(0)?,
1302 creation_date: row.get(1)?,
Janis Danisevskis60400fe2020-08-26 15:24:42 -07001303 domain: row.get(2)?,
Joel Galenson0891bc12020-07-20 10:37:03 -07001304 namespace: row.get(3)?,
1305 alias: row.get(4)?,
1306 })
1307 })?
1308 .map(|r| r.context("Could not read keyentry row."))
1309 .collect::<Result<Vec<_>>>()
1310 }
1311
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001312 // Note: The parameters and SecurityLevel associations are nonsensical. This
1313 // collection is only used to check if the parameters are preserved as expected by the
1314 // database.
1315 fn make_test_params() -> Vec<KeyParameter> {
1316 vec![
1317 KeyParameter::new(KeyParameterValue::Invalid, SecurityLevel::TRUSTED_ENVIRONMENT),
1318 KeyParameter::new(
1319 KeyParameterValue::KeyPurpose(KeyPurpose::SIGN),
1320 SecurityLevel::TRUSTED_ENVIRONMENT,
1321 ),
1322 KeyParameter::new(
1323 KeyParameterValue::KeyPurpose(KeyPurpose::DECRYPT),
1324 SecurityLevel::TRUSTED_ENVIRONMENT,
1325 ),
1326 KeyParameter::new(
1327 KeyParameterValue::Algorithm(Algorithm::RSA),
1328 SecurityLevel::TRUSTED_ENVIRONMENT,
1329 ),
1330 KeyParameter::new(KeyParameterValue::KeySize(1024), SecurityLevel::TRUSTED_ENVIRONMENT),
1331 KeyParameter::new(
1332 KeyParameterValue::BlockMode(BlockMode::ECB),
1333 SecurityLevel::TRUSTED_ENVIRONMENT,
1334 ),
1335 KeyParameter::new(
1336 KeyParameterValue::BlockMode(BlockMode::GCM),
1337 SecurityLevel::TRUSTED_ENVIRONMENT,
1338 ),
1339 KeyParameter::new(KeyParameterValue::Digest(Digest::NONE), SecurityLevel::STRONGBOX),
1340 KeyParameter::new(
1341 KeyParameterValue::Digest(Digest::MD5),
1342 SecurityLevel::TRUSTED_ENVIRONMENT,
1343 ),
1344 KeyParameter::new(
1345 KeyParameterValue::Digest(Digest::SHA_2_224),
1346 SecurityLevel::TRUSTED_ENVIRONMENT,
1347 ),
1348 KeyParameter::new(
1349 KeyParameterValue::Digest(Digest::SHA_2_256),
1350 SecurityLevel::STRONGBOX,
1351 ),
1352 KeyParameter::new(
1353 KeyParameterValue::PaddingMode(PaddingMode::NONE),
1354 SecurityLevel::TRUSTED_ENVIRONMENT,
1355 ),
1356 KeyParameter::new(
1357 KeyParameterValue::PaddingMode(PaddingMode::RSA_OAEP),
1358 SecurityLevel::TRUSTED_ENVIRONMENT,
1359 ),
1360 KeyParameter::new(
1361 KeyParameterValue::PaddingMode(PaddingMode::RSA_PSS),
1362 SecurityLevel::STRONGBOX,
1363 ),
1364 KeyParameter::new(
1365 KeyParameterValue::PaddingMode(PaddingMode::RSA_PKCS1_1_5_SIGN),
1366 SecurityLevel::TRUSTED_ENVIRONMENT,
1367 ),
1368 KeyParameter::new(KeyParameterValue::CallerNonce, SecurityLevel::TRUSTED_ENVIRONMENT),
1369 KeyParameter::new(KeyParameterValue::MinMacLength(256), SecurityLevel::STRONGBOX),
1370 KeyParameter::new(
1371 KeyParameterValue::EcCurve(EcCurve::P_224),
1372 SecurityLevel::TRUSTED_ENVIRONMENT,
1373 ),
1374 KeyParameter::new(KeyParameterValue::EcCurve(EcCurve::P_256), SecurityLevel::STRONGBOX),
1375 KeyParameter::new(
1376 KeyParameterValue::EcCurve(EcCurve::P_384),
1377 SecurityLevel::TRUSTED_ENVIRONMENT,
1378 ),
1379 KeyParameter::new(
1380 KeyParameterValue::EcCurve(EcCurve::P_521),
1381 SecurityLevel::TRUSTED_ENVIRONMENT,
1382 ),
1383 KeyParameter::new(
1384 KeyParameterValue::RSAPublicExponent(3),
1385 SecurityLevel::TRUSTED_ENVIRONMENT,
1386 ),
1387 KeyParameter::new(
1388 KeyParameterValue::IncludeUniqueID,
1389 SecurityLevel::TRUSTED_ENVIRONMENT,
1390 ),
1391 KeyParameter::new(KeyParameterValue::BootLoaderOnly, SecurityLevel::STRONGBOX),
1392 KeyParameter::new(KeyParameterValue::RollbackResistance, SecurityLevel::STRONGBOX),
1393 KeyParameter::new(
1394 KeyParameterValue::ActiveDateTime(1234567890),
1395 SecurityLevel::STRONGBOX,
1396 ),
1397 KeyParameter::new(
1398 KeyParameterValue::OriginationExpireDateTime(1234567890),
1399 SecurityLevel::TRUSTED_ENVIRONMENT,
1400 ),
1401 KeyParameter::new(
1402 KeyParameterValue::UsageExpireDateTime(1234567890),
1403 SecurityLevel::TRUSTED_ENVIRONMENT,
1404 ),
1405 KeyParameter::new(
1406 KeyParameterValue::MinSecondsBetweenOps(1234567890),
1407 SecurityLevel::TRUSTED_ENVIRONMENT,
1408 ),
1409 KeyParameter::new(
1410 KeyParameterValue::MaxUsesPerBoot(1234567890),
1411 SecurityLevel::TRUSTED_ENVIRONMENT,
1412 ),
1413 KeyParameter::new(KeyParameterValue::UserID(1), SecurityLevel::STRONGBOX),
1414 KeyParameter::new(KeyParameterValue::UserSecureID(42), SecurityLevel::STRONGBOX),
1415 KeyParameter::new(
1416 KeyParameterValue::NoAuthRequired,
1417 SecurityLevel::TRUSTED_ENVIRONMENT,
1418 ),
1419 KeyParameter::new(
1420 KeyParameterValue::HardwareAuthenticatorType(HardwareAuthenticatorType::PASSWORD),
1421 SecurityLevel::TRUSTED_ENVIRONMENT,
1422 ),
1423 KeyParameter::new(KeyParameterValue::AuthTimeout(1234567890), SecurityLevel::SOFTWARE),
1424 KeyParameter::new(KeyParameterValue::AllowWhileOnBody, SecurityLevel::SOFTWARE),
1425 KeyParameter::new(
1426 KeyParameterValue::TrustedUserPresenceRequired,
1427 SecurityLevel::TRUSTED_ENVIRONMENT,
1428 ),
1429 KeyParameter::new(
1430 KeyParameterValue::TrustedConfirmationRequired,
1431 SecurityLevel::TRUSTED_ENVIRONMENT,
1432 ),
1433 KeyParameter::new(
1434 KeyParameterValue::UnlockedDeviceRequired,
1435 SecurityLevel::TRUSTED_ENVIRONMENT,
1436 ),
1437 KeyParameter::new(
1438 KeyParameterValue::ApplicationID(vec![1u8, 2u8, 3u8, 4u8]),
1439 SecurityLevel::SOFTWARE,
1440 ),
1441 KeyParameter::new(
1442 KeyParameterValue::ApplicationData(vec![4u8, 3u8, 2u8, 1u8]),
1443 SecurityLevel::SOFTWARE,
1444 ),
1445 KeyParameter::new(
1446 KeyParameterValue::CreationDateTime(12345677890),
1447 SecurityLevel::SOFTWARE,
1448 ),
1449 KeyParameter::new(
1450 KeyParameterValue::KeyOrigin(KeyOrigin::GENERATED),
1451 SecurityLevel::TRUSTED_ENVIRONMENT,
1452 ),
1453 KeyParameter::new(
1454 KeyParameterValue::RootOfTrust(vec![3u8, 2u8, 1u8, 4u8]),
1455 SecurityLevel::TRUSTED_ENVIRONMENT,
1456 ),
1457 KeyParameter::new(KeyParameterValue::OSVersion(1), SecurityLevel::TRUSTED_ENVIRONMENT),
1458 KeyParameter::new(KeyParameterValue::OSPatchLevel(2), SecurityLevel::SOFTWARE),
1459 KeyParameter::new(
1460 KeyParameterValue::UniqueID(vec![4u8, 3u8, 1u8, 2u8]),
1461 SecurityLevel::SOFTWARE,
1462 ),
1463 KeyParameter::new(
1464 KeyParameterValue::AttestationChallenge(vec![4u8, 3u8, 1u8, 2u8]),
1465 SecurityLevel::TRUSTED_ENVIRONMENT,
1466 ),
1467 KeyParameter::new(
1468 KeyParameterValue::AttestationApplicationID(vec![4u8, 3u8, 1u8, 2u8]),
1469 SecurityLevel::TRUSTED_ENVIRONMENT,
1470 ),
1471 KeyParameter::new(
1472 KeyParameterValue::AttestationIdBrand(vec![4u8, 3u8, 1u8, 2u8]),
1473 SecurityLevel::TRUSTED_ENVIRONMENT,
1474 ),
1475 KeyParameter::new(
1476 KeyParameterValue::AttestationIdDevice(vec![4u8, 3u8, 1u8, 2u8]),
1477 SecurityLevel::TRUSTED_ENVIRONMENT,
1478 ),
1479 KeyParameter::new(
1480 KeyParameterValue::AttestationIdProduct(vec![4u8, 3u8, 1u8, 2u8]),
1481 SecurityLevel::TRUSTED_ENVIRONMENT,
1482 ),
1483 KeyParameter::new(
1484 KeyParameterValue::AttestationIdSerial(vec![4u8, 3u8, 1u8, 2u8]),
1485 SecurityLevel::TRUSTED_ENVIRONMENT,
1486 ),
1487 KeyParameter::new(
1488 KeyParameterValue::AttestationIdIMEI(vec![4u8, 3u8, 1u8, 2u8]),
1489 SecurityLevel::TRUSTED_ENVIRONMENT,
1490 ),
1491 KeyParameter::new(
1492 KeyParameterValue::AttestationIdMEID(vec![4u8, 3u8, 1u8, 2u8]),
1493 SecurityLevel::TRUSTED_ENVIRONMENT,
1494 ),
1495 KeyParameter::new(
1496 KeyParameterValue::AttestationIdManufacturer(vec![4u8, 3u8, 1u8, 2u8]),
1497 SecurityLevel::TRUSTED_ENVIRONMENT,
1498 ),
1499 KeyParameter::new(
1500 KeyParameterValue::AttestationIdModel(vec![4u8, 3u8, 1u8, 2u8]),
1501 SecurityLevel::TRUSTED_ENVIRONMENT,
1502 ),
1503 KeyParameter::new(
1504 KeyParameterValue::VendorPatchLevel(3),
1505 SecurityLevel::TRUSTED_ENVIRONMENT,
1506 ),
1507 KeyParameter::new(
1508 KeyParameterValue::BootPatchLevel(4),
1509 SecurityLevel::TRUSTED_ENVIRONMENT,
1510 ),
1511 KeyParameter::new(
1512 KeyParameterValue::AssociatedData(vec![4u8, 3u8, 1u8, 2u8]),
1513 SecurityLevel::TRUSTED_ENVIRONMENT,
1514 ),
1515 KeyParameter::new(
1516 KeyParameterValue::Nonce(vec![4u8, 3u8, 1u8, 2u8]),
1517 SecurityLevel::TRUSTED_ENVIRONMENT,
1518 ),
1519 KeyParameter::new(
1520 KeyParameterValue::MacLength(256),
1521 SecurityLevel::TRUSTED_ENVIRONMENT,
1522 ),
1523 KeyParameter::new(
1524 KeyParameterValue::ResetSinceIdRotation,
1525 SecurityLevel::TRUSTED_ENVIRONMENT,
1526 ),
1527 KeyParameter::new(
1528 KeyParameterValue::ConfirmationToken(vec![5u8, 5u8, 5u8, 5u8]),
1529 SecurityLevel::TRUSTED_ENVIRONMENT,
1530 ),
1531 ]
1532 }
1533
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001534 fn make_test_key_entry(
1535 db: &mut KeystoreDB,
1536 domain: DomainType,
1537 namespace: i64,
1538 alias: &str,
1539 ) -> Result<i64> {
1540 let key_id = db.create_key_entry(domain, namespace)?;
1541 db.insert_blob(key_id, SubComponentType::KM_BLOB, TEST_KM_BLOB, 1)?;
1542 db.insert_blob(key_id, SubComponentType::CERT, TEST_CERT_BLOB, 1)?;
1543 db.insert_blob(key_id, SubComponentType::CERT_CHAIN, TEST_CERT_CHAIN_BLOB, 1)?;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001544 db.insert_keyparameter(key_id, &make_test_params())?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001545 db.rebind_alias(key_id, alias, domain, namespace)?;
1546 Ok(key_id)
1547 }
1548
1549 fn debug_dump_keyentry_table(db: &mut KeystoreDB) -> Result<()> {
1550 let mut stmt = db.conn.prepare(
1551 "SELECT id, creation_date, domain, namespace, alias FROM persistent.keyentry;",
1552 )?;
1553 let rows = stmt.query_map::<(i64, i64, i32, i64, String), _, _>(NO_PARAMS, |row| {
1554 Ok((row.get(0)?, row.get(1)?, row.get(2)?, row.get(3)?, row.get(4)?))
1555 })?;
1556
1557 println!("Key entry table rows:");
1558 for r in rows {
1559 let (id, cdate, domain, namespace, alias) = r.unwrap();
1560 println!(
1561 " id: {} Creation date: {} Domain: {} Namespace: {} Alias: {}",
1562 id, cdate, domain, namespace, alias
1563 );
1564 }
1565 Ok(())
1566 }
1567
1568 fn debug_dump_grant_table(db: &mut KeystoreDB) -> Result<()> {
1569 let mut stmt =
1570 db.conn.prepare("SELECT id, grantee, keyentryid, access_vector FROM perboot.grant;")?;
1571 let rows = stmt.query_map::<(i64, i64, i64, i64), _, _>(NO_PARAMS, |row| {
1572 Ok((row.get(0)?, row.get(1)?, row.get(2)?, row.get(3)?))
1573 })?;
1574
1575 println!("Grant table rows:");
1576 for r in rows {
1577 let (id, gt, ki, av) = r.unwrap();
1578 println!(" id: {} grantee: {} key_id: {} access_vector: {}", id, gt, ki, av);
1579 }
1580 Ok(())
1581 }
1582
Joel Galenson2aab4432020-07-22 15:27:57 -07001583 // A class that deletes a file when it is dropped.
1584 // TODO: If we ever add a crate that does this, we can use it instead.
1585 struct TempFile {
1586 filename: &'static str,
1587 }
1588
1589 impl Drop for TempFile {
1590 fn drop(&mut self) {
1591 std::fs::remove_file(self.filename).expect("Cannot delete temporary file");
1592 }
1593 }
1594
Joel Galenson0891bc12020-07-20 10:37:03 -07001595 // Use a custom random number generator that repeats each number once.
1596 // This allows us to test repeated elements.
1597
1598 thread_local! {
1599 static RANDOM_COUNTER: RefCell<i64> = RefCell::new(0);
1600 }
1601
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001602 fn reset_random() {
1603 RANDOM_COUNTER.with(|counter| {
1604 *counter.borrow_mut() = 0;
1605 })
1606 }
1607
Joel Galenson0891bc12020-07-20 10:37:03 -07001608 pub fn random() -> i64 {
1609 RANDOM_COUNTER.with(|counter| {
1610 let result = *counter.borrow() / 2;
1611 *counter.borrow_mut() += 1;
1612 result
1613 })
1614 }
Joel Galenson26f4d012020-07-17 14:57:21 -07001615}