blob: df71d9450d071abb050b2dec4f2e4272a2bc7545 [file] [log] [blame]
Joel Galenson26f4d012020-07-17 14:57:21 -07001// Copyright 2020, The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
Janis Danisevskis63f7bc82020-09-03 10:12:56 -070015//! This is the Keystore 2.0 database module.
16//! The database module provides a connection to the backing SQLite store.
17//! We have two databases one for persistent key blob storage and one for
18//! items that have a per boot life cycle.
19//!
20//! ## Persistent database
21//! The persistent database has tables for key blobs. They are organized
22//! as follows:
23//! The `keyentry` table is the primary table for key entries. It is
24//! accompanied by two tables for blobs and parameters.
25//! Each key entry occupies exactly one row in the `keyentry` table and
26//! zero or more rows in the tables `blobentry` and `keyparameter`.
27//!
28//! ## Per boot database
29//! The per boot database stores items with a per boot lifecycle.
30//! Currently, there is only the `grant` table in this database.
31//! Grants are references to a key that can be used to access a key by
32//! clients that don't own that key. Grants can only be created by the
33//! owner of a key. And only certain components can create grants.
34//! This is governed by SEPolicy.
35//!
36//! ## Access control
37//! Some database functions that load keys or create grants perform
38//! access control. This is because in some cases access control
39//! can only be performed after some information about the designated
40//! key was loaded from the database. To decouple the permission checks
41//! from the database module these functions take permission check
42//! callbacks.
Joel Galenson26f4d012020-07-17 14:57:21 -070043
Janis Danisevskisc5b210b2020-09-11 13:27:37 -070044use crate::error::{Error as KsError, ResponseCode};
45use crate::key_parameter::{KeyParameter, SqlField, Tag};
46use crate::permission::KeyPermSet;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -070047use anyhow::{anyhow, Context, Result};
Janis Danisevskis60400fe2020-08-26 15:24:42 -070048
Janis Danisevskisc5b210b2020-09-11 13:27:37 -070049use android_system_keystore2::aidl::android::system::keystore2::{
50 Domain::Domain, KeyDescriptor::KeyDescriptor, SecurityLevel::SecurityLevel,
Janis Danisevskis60400fe2020-08-26 15:24:42 -070051};
52
Joel Galenson0891bc12020-07-20 10:37:03 -070053#[cfg(not(test))]
54use rand::prelude::random;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -070055use rusqlite::{
56 params, types::FromSql, types::FromSqlResult, types::ToSqlOutput, types::ValueRef, Connection,
57 OptionalExtension, Row, Rows, ToSql, Transaction, TransactionBehavior, NO_PARAMS,
58};
Janis Danisevskis4df44f42020-08-26 14:40:03 -070059use std::sync::Once;
Joel Galenson0891bc12020-07-20 10:37:03 -070060#[cfg(test)]
61use tests::random;
Joel Galenson26f4d012020-07-17 14:57:21 -070062
Janis Danisevskis63f7bc82020-09-03 10:12:56 -070063/// Keys have a KeyMint blob component and optional public certificate and
64/// certificate chain components.
65/// KeyEntryLoadBits is a bitmap that indicates to `KeystoreDB::load_key_entry`
66/// which components shall be loaded from the database if present.
67#[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
68pub struct KeyEntryLoadBits(u32);
69
70impl KeyEntryLoadBits {
71 /// Indicate to `KeystoreDB::load_key_entry` that no component shall be loaded.
72 pub const NONE: KeyEntryLoadBits = Self(0);
73 /// Indicate to `KeystoreDB::load_key_entry` that the KeyMint component shall be loaded.
74 pub const KM: KeyEntryLoadBits = Self(1);
75 /// Indicate to `KeystoreDB::load_key_entry` that the Public components shall be loaded.
76 pub const PUBLIC: KeyEntryLoadBits = Self(2);
77 /// Indicate to `KeystoreDB::load_key_entry` that both components shall be loaded.
78 pub const BOTH: KeyEntryLoadBits = Self(3);
79
80 /// Returns true if this object indicates that the public components shall be loaded.
81 pub const fn load_public(&self) -> bool {
82 self.0 & Self::PUBLIC.0 != 0
83 }
84
85 /// Returns true if the object indicates that the KeyMint component shall be loaded.
86 pub const fn load_km(&self) -> bool {
87 self.0 & Self::KM.0 != 0
88 }
89}
90
91/// This type represents a Keystore 2.0 key entry.
92/// An entry has a unique `id` by which it can be found in the database.
93/// It has a security level field, key parameters, and three optional fields
94/// for the KeyMint blob, public certificate and a public certificate chain.
95#[derive(Debug, Default, Clone, Eq, PartialEq, Ord, PartialOrd)]
96pub struct KeyEntry {
97 id: i64,
98 km_blob: Option<Vec<u8>>,
99 cert: Option<Vec<u8>>,
100 cert_chain: Option<Vec<u8>>,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700101 sec_level: SecurityLevel,
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700102 parameters: Vec<KeyParameter>,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700103}
104
105impl KeyEntry {
106 /// Returns the unique id of the Key entry.
107 pub fn id(&self) -> i64 {
108 self.id
109 }
110 /// Exposes the optional KeyMint blob.
111 pub fn km_blob(&self) -> &Option<Vec<u8>> {
112 &self.km_blob
113 }
114 /// Extracts the Optional KeyMint blob.
115 pub fn take_km_blob(&mut self) -> Option<Vec<u8>> {
116 self.km_blob.take()
117 }
118 /// Exposes the optional public certificate.
119 pub fn cert(&self) -> &Option<Vec<u8>> {
120 &self.cert
121 }
122 /// Extracts the optional public certificate.
123 pub fn take_cert(&mut self) -> Option<Vec<u8>> {
124 self.cert.take()
125 }
126 /// Exposes the optional public certificate chain.
127 pub fn cert_chain(&self) -> &Option<Vec<u8>> {
128 &self.cert_chain
129 }
130 /// Extracts the optional public certificate_chain.
131 pub fn take_cert_chain(&mut self) -> Option<Vec<u8>> {
132 self.cert_chain.take()
133 }
134 /// Returns the security level of the key entry.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700135 pub fn sec_level(&self) -> SecurityLevel {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700136 self.sec_level
137 }
138}
139
140/// Indicates the sub component of a key entry for persistent storage.
141#[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
142pub struct SubComponentType(u32);
143impl SubComponentType {
144 /// Persistent identifier for a KeyMint blob.
145 pub const KM_BLOB: SubComponentType = Self(0);
146 /// Persistent identifier for a certificate blob.
147 pub const CERT: SubComponentType = Self(1);
148 /// Persistent identifier for a certificate chain blob.
149 pub const CERT_CHAIN: SubComponentType = Self(2);
150}
151
152impl ToSql for SubComponentType {
153 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
154 self.0.to_sql()
155 }
156}
157
158impl FromSql for SubComponentType {
159 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
160 Ok(Self(u32::column_result(value)?))
161 }
162}
163
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700164static INIT_TABLES: Once = Once::new();
165
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700166/// KeystoreDB wraps a connection to an SQLite database and tracks its
167/// ownership. It also implements all of Keystore 2.0's database functionality.
Joel Galenson26f4d012020-07-17 14:57:21 -0700168pub struct KeystoreDB {
Joel Galenson26f4d012020-07-17 14:57:21 -0700169 conn: Connection,
170}
171
172impl KeystoreDB {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700173 /// This will create a new database connection connecting the two
174 /// files persistent.sqlite and perboot.sqlite in the current working
175 /// directory, which is usually `/data/misc/keystore/`.
176 /// It also attempts to initialize all of the tables on the first instantiation
177 /// per service startup. KeystoreDB cannot be used by multiple threads.
178 /// Each thread should open their own connection using `thread_local!`.
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700179 pub fn new() -> Result<Self> {
180 let conn = Self::make_connection("file:persistent.sqlite", "file:perboot.sqlite")?;
181
182 INIT_TABLES.call_once(|| Self::init_tables(&conn).expect("Failed to initialize tables."));
183 Ok(Self { conn })
Joel Galenson2aab4432020-07-22 15:27:57 -0700184 }
185
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700186 fn init_tables(conn: &Connection) -> Result<()> {
187 conn.execute(
188 "CREATE TABLE IF NOT EXISTS persistent.keyentry (
Joel Galenson0891bc12020-07-20 10:37:03 -0700189 id INTEGER UNIQUE,
190 creation_date DATETIME,
191 domain INTEGER,
192 namespace INTEGER,
193 alias TEXT);",
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700194 NO_PARAMS,
195 )
196 .context("Failed to initialize \"keyentry\" table.")?;
197
198 conn.execute(
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700199 "CREATE VIEW IF NOT EXISTS persistent.orphaned AS
200 SELECT id FROM persistent.keyentry WHERE domain IS NULL;",
201 NO_PARAMS,
202 )
203 .context("Failed to initialize \"orphaned\" view")?;
204
205 conn.execute(
206 "CREATE TABLE IF NOT EXISTS persistent.blobentry (
207 id INTEGER PRIMARY KEY,
208 subcomponent_type INTEGER,
209 keyentryid INTEGER,
210 blob BLOB,
211 sec_level INTEGER);",
212 NO_PARAMS,
213 )
214 .context("Failed to initialize \"blobentry\" table.")?;
215
216 conn.execute(
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700217 "CREATE TABLE IF NOT EXISTS persistent.keyparameter (
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000218 keyentryid INTEGER,
219 tag INTEGER,
220 data ANY,
221 security_level INTEGER);",
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700222 NO_PARAMS,
223 )
224 .context("Failed to initialize \"keyparameter\" table.")?;
225
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700226 // TODO only drop the perboot table if we start up for the first time per boot.
227 // Right now this is done once per startup which will lose some information
228 // upon a crash.
229 // Note: This is no regression with respect to the legacy Keystore.
230 conn.execute("DROP TABLE IF EXISTS perboot.grant;", NO_PARAMS)
231 .context("Failed to drop perboot.grant table")?;
232 conn.execute(
233 "CREATE TABLE perboot.grant (
234 id INTEGER UNIQUE,
235 grantee INTEGER,
236 keyentryid INTEGER,
237 access_vector INTEGER);",
238 NO_PARAMS,
239 )
240 .context("Failed to initialize \"grant\" table.")?;
241
Joel Galenson0891bc12020-07-20 10:37:03 -0700242 Ok(())
243 }
244
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700245 fn make_connection(persistent_file: &str, perboot_file: &str) -> Result<Connection> {
246 let conn =
247 Connection::open_in_memory().context("Failed to initialize SQLite connection.")?;
248
249 conn.execute("ATTACH DATABASE ? as persistent;", params![persistent_file])
250 .context("Failed to attach database persistent.")?;
251 conn.execute("ATTACH DATABASE ? as perboot;", params![perboot_file])
252 .context("Failed to attach database perboot.")?;
253
254 Ok(conn)
255 }
256
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700257 /// Creates a new key entry and allocates a new randomized id for the new key.
258 /// The key id gets associated with a domain and namespace but not with an alias.
259 /// To complete key generation `rebind_alias` should be called after all of the
260 /// key artifacts, i.e., blobs and parameters have been associated with the new
261 /// key id. Finalizing with `rebind_alias` makes the creation of a new key entry
262 /// atomic even if key generation is not.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700263 pub fn create_key_entry(&self, domain: Domain, namespace: i64) -> Result<i64> {
Joel Galenson0891bc12020-07-20 10:37:03 -0700264 match domain {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700265 Domain::APP | Domain::SELINUX => {}
Joel Galenson0891bc12020-07-20 10:37:03 -0700266 _ => {
267 return Err(KsError::sys())
268 .context(format!("Domain {:?} must be either App or SELinux.", domain));
269 }
270 }
Joel Galenson845f74b2020-09-09 14:11:55 -0700271 Self::insert_with_retry(|id| {
272 self.conn.execute(
Joel Galenson2aab4432020-07-22 15:27:57 -0700273 "INSERT into persistent.keyentry (id, creation_date, domain, namespace, alias)
Joel Galenson0891bc12020-07-20 10:37:03 -0700274 VALUES(?, datetime('now'), ?, ?, NULL);",
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700275 params![id, domain.0 as u32, namespace],
Joel Galenson845f74b2020-09-09 14:11:55 -0700276 )
277 })
278 .context("In create_key_entry")
Joel Galenson26f4d012020-07-17 14:57:21 -0700279 }
Joel Galenson33c04ad2020-08-03 11:04:38 -0700280
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700281 /// Inserts a new blob and associates it with the given key id. Each blob
282 /// has a sub component type and a security level.
283 /// Each key can have one of each sub component type associated. If more
284 /// are added only the most recent can be retrieved, and superseded blobs
285 /// will get garbage collected. The security level field of components
286 /// other than `SubComponentType::KM_BLOB` are ignored.
287 pub fn insert_blob(
288 &mut self,
289 key_id: i64,
290 sc_type: SubComponentType,
291 blob: &[u8],
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700292 sec_level: SecurityLevel,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700293 ) -> Result<()> {
294 self.conn
295 .execute(
296 "INSERT into persistent.blobentry (subcomponent_type, keyentryid, blob, sec_level)
297 VALUES (?, ?, ?, ?);",
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700298 params![sc_type, key_id, blob, sec_level.0],
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700299 )
300 .context("Failed to insert blob.")?;
301 Ok(())
302 }
303
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700304 /// Inserts a collection of key parameters into the `persistent.keyparameter` table
305 /// and associates them with the given `key_id`.
306 pub fn insert_keyparameter<'a>(
307 &mut self,
308 key_id: i64,
309 params: impl IntoIterator<Item = &'a KeyParameter>,
310 ) -> Result<()> {
311 let mut stmt = self
312 .conn
313 .prepare(
314 "INSERT into persistent.keyparameter (keyentryid, tag, data, security_level)
315 VALUES (?, ?, ?, ?);",
316 )
317 .context("In insert_keyparameter: Failed to prepare statement.")?;
318
319 let iter = params.into_iter();
320 for p in iter {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700321 stmt.insert(params![
322 key_id,
323 p.get_tag().0,
324 p.key_parameter_value(),
325 p.security_level().0
326 ])
327 .with_context(|| format!("In insert_keyparameter: Failed to insert {:?}", p))?;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700328 }
329 Ok(())
330 }
331
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700332 /// Updates the alias column of the given key id `newid` with the given alias,
333 /// and atomically, removes the alias, domain, and namespace from another row
334 /// with the same alias-domain-namespace tuple if such row exits.
Joel Galenson33c04ad2020-08-03 11:04:38 -0700335 pub fn rebind_alias(
336 &mut self,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700337 newid: i64,
Joel Galenson33c04ad2020-08-03 11:04:38 -0700338 alias: &str,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700339 domain: Domain,
Joel Galenson33c04ad2020-08-03 11:04:38 -0700340 namespace: i64,
341 ) -> Result<()> {
342 match domain {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700343 Domain::APP | Domain::SELINUX => {}
Joel Galenson33c04ad2020-08-03 11:04:38 -0700344 _ => {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700345 return Err(KsError::sys()).context(format!(
346 "In rebind_alias: Domain {:?} must be either App or SELinux.",
347 domain
348 ));
Joel Galenson33c04ad2020-08-03 11:04:38 -0700349 }
350 }
351 let tx = self
352 .conn
353 .transaction_with_behavior(TransactionBehavior::Immediate)
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700354 .context("In rebind_alias: Failed to initialize transaction.")?;
Joel Galenson33c04ad2020-08-03 11:04:38 -0700355 tx.execute(
356 "UPDATE persistent.keyentry
357 SET alias = NULL, domain = NULL, namespace = NULL
358 WHERE alias = ? AND domain = ? AND namespace = ?;",
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700359 params![alias, domain.0 as u32, namespace],
Joel Galenson33c04ad2020-08-03 11:04:38 -0700360 )
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700361 .context("In rebind_alias: Failed to rebind existing entry.")?;
Joel Galenson33c04ad2020-08-03 11:04:38 -0700362 let result = tx
363 .execute(
364 "UPDATE persistent.keyentry
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700365 SET alias = ?
366 WHERE id = ? AND domain = ? AND namespace = ?;",
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700367 params![alias, newid, domain.0 as u32, namespace],
Joel Galenson33c04ad2020-08-03 11:04:38 -0700368 )
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700369 .context("In rebind_alias: Failed to set alias.")?;
Joel Galenson33c04ad2020-08-03 11:04:38 -0700370 if result != 1 {
371 // Note that this explicit rollback is not required, as
372 // the transaction should rollback if we do not commit it.
373 // We leave it here for readability.
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700374 tx.rollback().context("In rebind_alias: Failed to rollback a failed transaction.")?;
Joel Galenson33c04ad2020-08-03 11:04:38 -0700375 return Err(KsError::sys()).context(format!(
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700376 "In rebind_alias: Expected to update a single entry but instead updated {}.",
Joel Galenson33c04ad2020-08-03 11:04:38 -0700377 result
378 ));
379 }
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700380 tx.commit().context("In rebind_alias: Failed to commit transaction.")
381 }
382
383 // Helper function loading the key_id given the key descriptor
384 // tuple comprising domain, namespace, and alias.
385 // Requires a valid transaction.
386 fn load_key_entry_id(key: &KeyDescriptor, tx: &Transaction) -> Result<i64> {
387 let alias = key
388 .alias
389 .as_ref()
390 .map_or_else(|| Err(KsError::sys()), Ok)
391 .context("In load_key_entry_id: Alias must be specified.")?;
392 let mut stmt = tx
393 .prepare(
394 "SELECT id FROM persistent.keyentry
395 WHERE
396 domain = ?
397 AND namespace = ?
398 AND alias = ?;",
399 )
400 .context("In load_key_entry_id: Failed to select from keyentry table.")?;
401 let mut rows = stmt
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700402 .query(params![key.domain.0 as u32, key.nspace, alias])
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700403 .context("In load_key_entry_id: Failed to read from keyentry table.")?;
404 Self::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700405 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700406 .get(0)
407 .context("Failed to unpack id.")
408 })
409 .context("In load_key_entry_id.")
410 }
411
412 /// This helper function completes the access tuple of a key, which is required
413 /// to perform access control. The strategy depends on the `domain` field in the
414 /// key descriptor.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700415 /// * Domain::SELINUX: The access tuple is complete and this function only loads
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700416 /// the key_id for further processing.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700417 /// * Domain::APP: Like Domain::SELINUX, but the tuple is completed by `caller_uid`
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700418 /// which serves as the namespace.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700419 /// * Domain::GRANT: The grant table is queried for the `key_id` and the
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700420 /// `access_vector`.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700421 /// * Domain::KEY_ID: The keyentry table is queried for the owning `domain` and
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700422 /// `namespace`.
423 /// In each case the information returned is sufficient to perform the access
424 /// check and the key id can be used to load further key artifacts.
425 fn load_access_tuple(
426 tx: &Transaction,
427 key: KeyDescriptor,
428 caller_uid: u32,
429 ) -> Result<(i64, KeyDescriptor, Option<KeyPermSet>)> {
430 match key.domain {
431 // Domain App or SELinux. In this case we load the key_id from
432 // the keyentry database for further loading of key components.
433 // We already have the full access tuple to perform access control.
434 // The only distinction is that we use the caller_uid instead
435 // of the caller supplied namespace if the domain field is
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700436 // Domain::APP.
437 Domain::APP | Domain::SELINUX => {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700438 let mut access_key = key;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700439 if access_key.domain == Domain::APP {
440 access_key.nspace = caller_uid as i64;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700441 }
442 let key_id = Self::load_key_entry_id(&access_key, &tx)
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700443 .with_context(|| format!("With key.domain = {:?}.", access_key.domain))?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700444
445 Ok((key_id, access_key, None))
446 }
447
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700448 // Domain::GRANT. In this case we load the key_id and the access_vector
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700449 // from the grant table.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700450 Domain::GRANT => {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700451 let mut stmt = tx
452 .prepare(
453 "SELECT keyentryid, access_vector FROM perboot.grant
454 WHERE grantee = ? AND id = ?;",
455 )
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700456 .context("Domain::GRANT prepare statement failed")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700457 let mut rows = stmt
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700458 .query(params![caller_uid as i64, key.nspace])
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700459 .context("Domain:Grant: query failed.")?;
460 let (key_id, access_vector): (i64, i32) =
461 Self::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700462 let r =
463 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700464 Ok((
465 r.get(0).context("Failed to unpack key_id.")?,
466 r.get(1).context("Failed to unpack access_vector.")?,
467 ))
468 })
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700469 .context("Domain::GRANT.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700470 Ok((key_id, key, Some(access_vector.into())))
471 }
472
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700473 // Domain::KEY_ID. In this case we load the domain and namespace from the
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700474 // keyentry database because we need them for access control.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700475 Domain::KEY_ID => {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700476 let mut stmt = tx
477 .prepare(
478 "SELECT domain, namespace FROM persistent.keyentry
479 WHERE
480 id = ?;",
481 )
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700482 .context("Domain::KEY_ID: prepare statement failed")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700483 let mut rows =
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700484 stmt.query(params![key.nspace]).context("Domain::KEY_ID: query failed.")?;
485 let (domain, namespace): (Domain, i64) =
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700486 Self::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700487 let r =
488 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700489 Ok((
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700490 Domain(r.get(0).context("Failed to unpack domain.")?),
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700491 r.get(1).context("Failed to unpack namespace.")?,
492 ))
493 })
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700494 .context("Domain::KEY_ID.")?;
495 let key_id = key.nspace;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700496 let mut access_key = key;
497 access_key.domain = domain;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700498 access_key.nspace = namespace;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700499
500 Ok((key_id, access_key, None))
501 }
502 _ => Err(anyhow!(KsError::sys())),
503 }
504 }
505
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700506 fn load_blob_components(
507 key_id: i64,
508 load_bits: KeyEntryLoadBits,
509 tx: &Transaction,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700510 ) -> Result<(SecurityLevel, Option<Vec<u8>>, Option<Vec<u8>>, Option<Vec<u8>>)> {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700511 let mut stmt = tx
512 .prepare(
513 "SELECT MAX(id), sec_level, subcomponent_type, blob FROM persistent.blobentry
514 WHERE keyentryid = ? GROUP BY subcomponent_type;",
515 )
516 .context("In load_blob_components: prepare statement failed.")?;
517
518 let mut rows =
519 stmt.query(params![key_id]).context("In load_blob_components: query failed.")?;
520
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700521 let mut sec_level: SecurityLevel = Default::default();
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700522 let mut km_blob: Option<Vec<u8>> = None;
523 let mut cert_blob: Option<Vec<u8>> = None;
524 let mut cert_chain_blob: Option<Vec<u8>> = None;
525 Self::with_rows_extract_all(&mut rows, |row| {
526 let sub_type: SubComponentType =
527 row.get(2).context("Failed to extract subcomponent_type.")?;
528 match (sub_type, load_bits.load_public()) {
529 (SubComponentType::KM_BLOB, _) => {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700530 sec_level =
531 SecurityLevel(row.get(1).context("Failed to extract security level.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700532 if load_bits.load_km() {
533 km_blob = Some(row.get(3).context("Failed to extract KM blob.")?);
534 }
535 }
536 (SubComponentType::CERT, true) => {
537 cert_blob =
538 Some(row.get(3).context("Failed to extract public certificate blob.")?);
539 }
540 (SubComponentType::CERT_CHAIN, true) => {
541 cert_chain_blob =
542 Some(row.get(3).context("Failed to extract certificate chain blob.")?);
543 }
544 (SubComponentType::CERT, _) | (SubComponentType::CERT_CHAIN, _) => {}
545 _ => Err(KsError::sys()).context("Unknown subcomponent type.")?,
546 }
547 Ok(())
548 })
549 .context("In load_blob_components.")?;
550
551 Ok((sec_level, km_blob, cert_blob, cert_chain_blob))
552 }
553
554 fn load_key_parameters(key_id: i64, tx: &Transaction) -> Result<Vec<KeyParameter>> {
555 let mut stmt = tx
556 .prepare(
557 "SELECT tag, data, security_level from persistent.keyparameter
558 WHERE keyentryid = ?;",
559 )
560 .context("In load_key_parameters: prepare statement failed.")?;
561
562 let mut parameters: Vec<KeyParameter> = Vec::new();
563
564 let mut rows =
565 stmt.query(params![key_id]).context("In load_key_parameters: query failed.")?;
566 Self::with_rows_extract_all(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700567 let tag = Tag(row.get(0).context("Failed to read tag.")?);
568 let sec_level = SecurityLevel(row.get(2).context("Failed to read sec_level.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700569 parameters.push(
570 KeyParameter::new_from_sql(tag, &SqlField::new(1, &row), sec_level)
571 .context("Failed to read KeyParameter.")?,
572 );
573 Ok(())
574 })
575 .context("In load_key_parameters.")?;
576
577 Ok(parameters)
578 }
579
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700580 /// Load a key entry by the given key descriptor.
581 /// It uses the `check_permission` callback to verify if the access is allowed
582 /// given the key access tuple read from the database using `load_access_tuple`.
583 /// With `load_bits` the caller may specify which blobs shall be loaded from
584 /// the blob database.
585 pub fn load_key_entry(
586 &mut self,
587 key: KeyDescriptor,
588 load_bits: KeyEntryLoadBits,
589 caller_uid: u32,
590 check_permission: impl FnOnce(&KeyDescriptor, Option<KeyPermSet>) -> Result<()>,
591 ) -> Result<KeyEntry> {
592 let tx = self
593 .conn
594 .transaction_with_behavior(TransactionBehavior::Deferred)
595 .context("In load_key_entry: Failed to initialize transaction.")?;
596
597 // Load the key_id and complete the access control tuple.
598 let (key_id, access_key_descriptor, access_vector) =
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700599 Self::load_access_tuple(&tx, key, caller_uid).context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700600
601 // Perform access control. It is vital that we return here if the permission is denied.
602 // So do not touch that '?' at the end.
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700603 check_permission(&access_key_descriptor, access_vector).context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700604
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700605 let (sec_level, km_blob, cert_blob, cert_chain_blob) =
606 Self::load_blob_components(key_id, load_bits, &tx).context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700607
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700608 let parameters = Self::load_key_parameters(key_id, &tx).context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700609
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700610 tx.commit().context("In load_key_entry: Failed to commit transaction.")?;
611
612 Ok(KeyEntry {
613 id: key_id,
614 km_blob,
615 cert: cert_blob,
616 cert_chain: cert_chain_blob,
617 sec_level,
618 parameters,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700619 })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700620 }
621
622 /// Adds a grant to the grant table.
623 /// Like `load_key_entry` this function loads the access tuple before
624 /// it uses the callback for a permission check. Upon success,
625 /// it inserts the `grantee_uid`, `key_id`, and `access_vector` into the
626 /// grant table. The new row will have a randomized id, which is used as
627 /// grant id in the namespace field of the resulting KeyDescriptor.
628 pub fn grant(
629 &mut self,
630 key: KeyDescriptor,
631 caller_uid: u32,
632 grantee_uid: u32,
633 access_vector: KeyPermSet,
634 check_permission: impl FnOnce(&KeyDescriptor, &KeyPermSet) -> Result<()>,
635 ) -> Result<KeyDescriptor> {
636 let tx = self
637 .conn
638 .transaction_with_behavior(TransactionBehavior::Immediate)
639 .context("In grant: Failed to initialize transaction.")?;
640
641 // Load the key_id and complete the access control tuple.
642 // We ignore the access vector here because grants cannot be granted.
643 // The access vector returned here expresses the permissions the
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700644 // grantee has if key.domain == Domain::GRANT. But this vector
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700645 // cannot include the grant permission by design, so there is no way the
646 // subsequent permission check can pass.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700647 // We could check key.domain == Domain::GRANT and fail early.
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700648 // But even if we load the access tuple by grant here, the permission
649 // check denies the attempt to create a grant by grant descriptor.
650 let (key_id, access_key_descriptor, _) =
651 Self::load_access_tuple(&tx, key, caller_uid).context("In grant")?;
652
653 // Perform access control. It is vital that we return here if the permission
654 // was denied. So do not touch that '?' at the end of the line.
655 // This permission check checks if the caller has the grant permission
656 // for the given key and in addition to all of the permissions
657 // expressed in `access_vector`.
658 check_permission(&access_key_descriptor, &access_vector)
659 .context("In grant: check_permission failed.")?;
660
661 let grant_id = if let Some(grant_id) = tx
662 .query_row(
663 "SELECT id FROM perboot.grant
664 WHERE keyentryid = ? AND grantee = ?;",
665 params![key_id, grantee_uid],
666 |row| row.get(0),
667 )
668 .optional()
669 .context("In grant: Failed get optional existing grant id.")?
670 {
671 tx.execute(
672 "UPDATE perboot.grant
673 SET access_vector = ?
674 WHERE id = ?;",
675 params![i32::from(access_vector), grant_id],
676 )
677 .context("In grant: Failed to update existing grant.")?;
678 grant_id
679 } else {
Joel Galenson845f74b2020-09-09 14:11:55 -0700680 Self::insert_with_retry(|id| {
681 tx.execute(
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700682 "INSERT INTO perboot.grant (id, grantee, keyentryid, access_vector)
683 VALUES (?, ?, ?, ?);",
Joel Galenson845f74b2020-09-09 14:11:55 -0700684 params![id, grantee_uid, key_id, i32::from(access_vector)],
685 )
686 })
687 .context("In grant")?
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700688 };
689 tx.commit().context("In grant: failed to commit transaction.")?;
690
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700691 Ok(KeyDescriptor { domain: Domain::GRANT, nspace: grant_id, alias: None, blob: None })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700692 }
693
694 /// This function checks permissions like `grant` and `load_key_entry`
695 /// before removing a grant from the grant table.
696 pub fn ungrant(
697 &mut self,
698 key: KeyDescriptor,
699 caller_uid: u32,
700 grantee_uid: u32,
701 check_permission: impl FnOnce(&KeyDescriptor) -> Result<()>,
702 ) -> Result<()> {
703 let tx = self
704 .conn
705 .transaction_with_behavior(TransactionBehavior::Immediate)
706 .context("In ungrant: Failed to initialize transaction.")?;
707
708 // Load the key_id and complete the access control tuple.
709 // We ignore the access vector here because grants cannot be granted.
710 let (key_id, access_key_descriptor, _) =
711 Self::load_access_tuple(&tx, key, caller_uid).context("In ungrant.")?;
712
713 // Perform access control. We must return here if the permission
714 // was denied. So do not touch the '?' at the end of this line.
715 check_permission(&access_key_descriptor).context("In grant: check_permission failed.")?;
716
717 tx.execute(
718 "DELETE FROM perboot.grant
719 WHERE keyentryid = ? AND grantee = ?;",
720 params![key_id, grantee_uid],
721 )
722 .context("Failed to delete grant.")?;
723
724 tx.commit().context("In ungrant: failed to commit transaction.")?;
725
726 Ok(())
727 }
728
Joel Galenson845f74b2020-09-09 14:11:55 -0700729 // Generates a random id and passes it to the given function, which will
730 // try to insert it into a database. If that insertion fails, retry;
731 // otherwise return the id.
732 fn insert_with_retry(inserter: impl Fn(i64) -> rusqlite::Result<usize>) -> Result<i64> {
733 loop {
734 let newid: i64 = random();
735 match inserter(newid) {
736 // If the id already existed, try again.
737 Err(rusqlite::Error::SqliteFailure(
738 libsqlite3_sys::Error {
739 code: libsqlite3_sys::ErrorCode::ConstraintViolation,
740 extended_code: libsqlite3_sys::SQLITE_CONSTRAINT_UNIQUE,
741 },
742 _,
743 )) => (),
744 Err(e) => {
745 return Err(e).context("In insert_with_retry: failed to insert into database.")
746 }
747 _ => return Ok(newid),
748 }
749 }
750 }
751
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700752 // Takes Rows as returned by a query call on prepared statement.
753 // Extracts exactly one row with the `row_extractor` and fails if more
754 // rows are available.
755 // If no row was found, `None` is passed to the `row_extractor`.
756 // This allows the row extractor to decide on an error condition or
757 // a different default behavior.
758 fn with_rows_extract_one<'a, T, F>(rows: &mut Rows<'a>, row_extractor: F) -> Result<T>
759 where
760 F: FnOnce(Option<&Row<'a>>) -> Result<T>,
761 {
762 let result =
763 row_extractor(rows.next().context("with_rows_extract_one: Failed to unpack row.")?);
764
765 rows.next()
766 .context("In with_rows_extract_one: Failed to unpack unexpected row.")?
767 .map_or_else(|| Ok(()), |_| Err(KsError::sys()))
768 .context("In with_rows_extract_one: Unexpected row.")?;
769
770 result
771 }
772
773 fn with_rows_extract_all<'a, F>(rows: &mut Rows<'a>, mut row_extractor: F) -> Result<()>
774 where
775 F: FnMut(&Row<'a>) -> Result<()>,
776 {
777 loop {
778 match rows.next().context("In with_rows_extract_all: Failed to unpack row")? {
779 Some(row) => {
780 row_extractor(&row).context("In with_rows_extract_all.")?;
781 }
782 None => break Ok(()),
783 }
784 }
Joel Galenson33c04ad2020-08-03 11:04:38 -0700785 }
Joel Galenson26f4d012020-07-17 14:57:21 -0700786}
787
788#[cfg(test)]
789mod tests {
790
791 use super::*;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700792 use crate::key_parameter::{
793 Algorithm, BlockMode, Digest, EcCurve, HardwareAuthenticatorType, KeyOrigin, KeyParameter,
794 KeyParameterValue, KeyPurpose, PaddingMode, SecurityLevel,
795 };
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700796 use crate::key_perm_set;
797 use crate::permission::{KeyPerm, KeyPermSet};
798 use rusqlite::NO_PARAMS;
Joel Galenson0891bc12020-07-20 10:37:03 -0700799 use std::cell::RefCell;
800
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700801 static PERSISTENT_TEST_SQL: &str = "/data/local/tmp/persistent.sqlite";
802 static PERBOOT_TEST_SQL: &str = "/data/local/tmp/perboot.sqlite";
803
804 fn new_test_db() -> Result<KeystoreDB> {
805 let conn = KeystoreDB::make_connection("file::memory:", "file::memory:")?;
806
807 KeystoreDB::init_tables(&conn).context("Failed to initialize tables.")?;
808 Ok(KeystoreDB { conn })
809 }
810
811 fn new_test_db_with_persistent_file() -> Result<KeystoreDB> {
812 let conn = KeystoreDB::make_connection(PERSISTENT_TEST_SQL, PERBOOT_TEST_SQL)?;
813
814 KeystoreDB::init_tables(&conn).context("Failed to initialize tables.")?;
815 Ok(KeystoreDB { conn })
816 }
817
Joel Galenson0891bc12020-07-20 10:37:03 -0700818 // Ensure that we're using the "injected" random function, not the real one.
819 #[test]
820 fn test_mocked_random() {
821 let rand1 = random();
822 let rand2 = random();
823 let rand3 = random();
824 if rand1 == rand2 {
825 assert_eq!(rand2 + 1, rand3);
826 } else {
827 assert_eq!(rand1 + 1, rand2);
828 assert_eq!(rand2, rand3);
829 }
830 }
Joel Galenson26f4d012020-07-17 14:57:21 -0700831
Joel Galenson26f4d012020-07-17 14:57:21 -0700832 // Test that we have the correct tables.
833 #[test]
834 fn test_tables() -> Result<()> {
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700835 let db = new_test_db()?;
Joel Galenson26f4d012020-07-17 14:57:21 -0700836 let tables = db
837 .conn
Joel Galenson2aab4432020-07-22 15:27:57 -0700838 .prepare("SELECT name from persistent.sqlite_master WHERE type='table' ORDER BY name;")?
Joel Galenson26f4d012020-07-17 14:57:21 -0700839 .query_map(params![], |row| row.get(0))?
840 .collect::<rusqlite::Result<Vec<String>>>()?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700841 assert_eq!(tables.len(), 3);
842 assert_eq!(tables[0], "blobentry");
843 assert_eq!(tables[1], "keyentry");
844 assert_eq!(tables[2], "keyparameter");
845 let tables = db
846 .conn
847 .prepare("SELECT name from perboot.sqlite_master WHERE type='table' ORDER BY name;")?
848 .query_map(params![], |row| row.get(0))?
849 .collect::<rusqlite::Result<Vec<String>>>()?;
850 assert_eq!(tables.len(), 1);
851 assert_eq!(tables[0], "grant");
Joel Galenson26f4d012020-07-17 14:57:21 -0700852 Ok(())
853 }
Joel Galenson0891bc12020-07-20 10:37:03 -0700854
855 #[test]
Joel Galenson2aab4432020-07-22 15:27:57 -0700856 fn test_no_persistence_for_tests() -> Result<()> {
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700857 let db = new_test_db()?;
Joel Galenson2aab4432020-07-22 15:27:57 -0700858
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700859 db.create_key_entry(Domain::APP, 100)?;
Joel Galenson2aab4432020-07-22 15:27:57 -0700860 let entries = get_keyentry(&db)?;
861 assert_eq!(entries.len(), 1);
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700862 let db = new_test_db()?;
Joel Galenson2aab4432020-07-22 15:27:57 -0700863
864 let entries = get_keyentry(&db)?;
865 assert_eq!(entries.len(), 0);
866 Ok(())
867 }
868
869 #[test]
870 fn test_persistence_for_files() -> Result<()> {
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700871 let _file_guard_persistent = TempFile { filename: PERSISTENT_TEST_SQL };
872 let _file_guard_perboot = TempFile { filename: PERBOOT_TEST_SQL };
873 let db = new_test_db_with_persistent_file()?;
Joel Galenson2aab4432020-07-22 15:27:57 -0700874
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700875 db.create_key_entry(Domain::APP, 100)?;
Joel Galenson2aab4432020-07-22 15:27:57 -0700876 let entries = get_keyentry(&db)?;
877 assert_eq!(entries.len(), 1);
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700878 let db = new_test_db_with_persistent_file()?;
Joel Galenson2aab4432020-07-22 15:27:57 -0700879
880 let entries_new = get_keyentry(&db)?;
881 assert_eq!(entries, entries_new);
882 Ok(())
883 }
884
885 #[test]
Joel Galenson0891bc12020-07-20 10:37:03 -0700886 fn test_create_key_entry() -> Result<()> {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700887 fn extractor(ke: &KeyEntryRow) -> (Domain, i64, Option<&str>) {
Joel Galenson0891bc12020-07-20 10:37:03 -0700888 (ke.domain.unwrap(), ke.namespace.unwrap(), ke.alias.as_deref())
889 }
890
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700891 let db = new_test_db()?;
Joel Galenson0891bc12020-07-20 10:37:03 -0700892
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700893 db.create_key_entry(Domain::APP, 100)?;
894 db.create_key_entry(Domain::SELINUX, 101)?;
Joel Galenson0891bc12020-07-20 10:37:03 -0700895
896 let entries = get_keyentry(&db)?;
897 assert_eq!(entries.len(), 2);
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700898 assert_eq!(extractor(&entries[0]), (Domain::APP, 100, None));
899 assert_eq!(extractor(&entries[1]), (Domain::SELINUX, 101, None));
Joel Galenson0891bc12020-07-20 10:37:03 -0700900
901 // Test that we must pass in a valid Domain.
902 check_result_is_error_containing_string(
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700903 db.create_key_entry(Domain::GRANT, 102),
904 "Domain Domain(1) must be either App or SELinux.",
Joel Galenson0891bc12020-07-20 10:37:03 -0700905 );
906 check_result_is_error_containing_string(
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700907 db.create_key_entry(Domain::BLOB, 103),
908 "Domain Domain(3) must be either App or SELinux.",
Joel Galenson0891bc12020-07-20 10:37:03 -0700909 );
910 check_result_is_error_containing_string(
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700911 db.create_key_entry(Domain::KEY_ID, 104),
912 "Domain Domain(4) must be either App or SELinux.",
Joel Galenson0891bc12020-07-20 10:37:03 -0700913 );
914
915 Ok(())
916 }
917
Joel Galenson33c04ad2020-08-03 11:04:38 -0700918 #[test]
919 fn test_rebind_alias() -> Result<()> {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700920 fn extractor(ke: &KeyEntryRow) -> (Option<Domain>, Option<i64>, Option<&str>) {
Joel Galenson33c04ad2020-08-03 11:04:38 -0700921 (ke.domain, ke.namespace, ke.alias.as_deref())
922 }
923
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700924 let mut db = new_test_db()?;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700925 db.create_key_entry(Domain::APP, 42)?;
926 db.create_key_entry(Domain::APP, 42)?;
Joel Galenson33c04ad2020-08-03 11:04:38 -0700927 let entries = get_keyentry(&db)?;
928 assert_eq!(entries.len(), 2);
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700929 assert_eq!(extractor(&entries[0]), (Some(Domain::APP), Some(42), None));
930 assert_eq!(extractor(&entries[1]), (Some(Domain::APP), Some(42), None));
Joel Galenson33c04ad2020-08-03 11:04:38 -0700931
932 // Test that the first call to rebind_alias sets the alias.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700933 db.rebind_alias(entries[0].id, "foo", Domain::APP, 42)?;
Joel Galenson33c04ad2020-08-03 11:04:38 -0700934 let entries = get_keyentry(&db)?;
935 assert_eq!(entries.len(), 2);
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700936 assert_eq!(extractor(&entries[0]), (Some(Domain::APP), Some(42), Some("foo")));
937 assert_eq!(extractor(&entries[1]), (Some(Domain::APP), Some(42), None));
Joel Galenson33c04ad2020-08-03 11:04:38 -0700938
939 // Test that the second call to rebind_alias also empties the old one.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700940 db.rebind_alias(entries[1].id, "foo", Domain::APP, 42)?;
Joel Galenson33c04ad2020-08-03 11:04:38 -0700941 let entries = get_keyentry(&db)?;
942 assert_eq!(entries.len(), 2);
943 assert_eq!(extractor(&entries[0]), (None, None, None));
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700944 assert_eq!(extractor(&entries[1]), (Some(Domain::APP), Some(42), Some("foo")));
Joel Galenson33c04ad2020-08-03 11:04:38 -0700945
946 // Test that we must pass in a valid Domain.
947 check_result_is_error_containing_string(
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700948 db.rebind_alias(0, "foo", Domain::GRANT, 42),
949 "Domain Domain(1) must be either App or SELinux.",
Joel Galenson33c04ad2020-08-03 11:04:38 -0700950 );
951 check_result_is_error_containing_string(
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700952 db.rebind_alias(0, "foo", Domain::BLOB, 42),
953 "Domain Domain(3) must be either App or SELinux.",
Joel Galenson33c04ad2020-08-03 11:04:38 -0700954 );
955 check_result_is_error_containing_string(
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700956 db.rebind_alias(0, "foo", Domain::KEY_ID, 42),
957 "Domain Domain(4) must be either App or SELinux.",
Joel Galenson33c04ad2020-08-03 11:04:38 -0700958 );
959
960 // Test that we correctly handle setting an alias for something that does not exist.
961 check_result_is_error_containing_string(
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700962 db.rebind_alias(0, "foo", Domain::SELINUX, 42),
Joel Galenson33c04ad2020-08-03 11:04:38 -0700963 "Expected to update a single entry but instead updated 0",
964 );
965 // Test that we correctly abort the transaction in this case.
966 let entries = get_keyentry(&db)?;
967 assert_eq!(entries.len(), 2);
968 assert_eq!(extractor(&entries[0]), (None, None, None));
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700969 assert_eq!(extractor(&entries[1]), (Some(Domain::APP), Some(42), Some("foo")));
Joel Galenson33c04ad2020-08-03 11:04:38 -0700970
971 Ok(())
972 }
973
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700974 #[test]
975 fn test_grant_ungrant() -> Result<()> {
976 const CALLER_UID: u32 = 15;
977 const GRANTEE_UID: u32 = 12;
978 const SELINUX_NAMESPACE: i64 = 7;
979
980 let mut db = new_test_db()?;
981 db.conn.execute(
982 "INSERT INTO persistent.keyentry (id, creation_date, domain, namespace, alias)
983 VALUES (1, '1980', 0, 15, 'key'), (2, '1980', 2, 7, 'yek');",
984 NO_PARAMS,
985 )?;
986 let app_key = KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700987 domain: super::Domain::APP,
988 nspace: 0,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700989 alias: Some("key".to_string()),
990 blob: None,
991 };
992 const PVEC1: KeyPermSet = key_perm_set![KeyPerm::use_(), KeyPerm::get_info()];
993 const PVEC2: KeyPermSet = key_perm_set![KeyPerm::use_()];
994
995 // Reset totally predictable random number generator in case we
996 // are not the first test running on this thread.
997 reset_random();
998 let next_random = 0i64;
999
1000 let app_granted_key =
1001 db.grant(app_key.clone(), CALLER_UID, GRANTEE_UID, PVEC1, |k, a| {
1002 assert_eq!(*a, PVEC1);
1003 assert_eq!(
1004 *k,
1005 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001006 domain: super::Domain::APP,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001007 // namespace must be set to the caller_uid.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001008 nspace: CALLER_UID as i64,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001009 alias: Some("key".to_string()),
1010 blob: None,
1011 }
1012 );
1013 Ok(())
1014 })?;
1015
1016 assert_eq!(
1017 app_granted_key,
1018 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001019 domain: super::Domain::GRANT,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001020 // The grantid is next_random due to the mock random number generator.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001021 nspace: next_random,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001022 alias: None,
1023 blob: None,
1024 }
1025 );
1026
1027 let selinux_key = KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001028 domain: super::Domain::SELINUX,
1029 nspace: SELINUX_NAMESPACE,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001030 alias: Some("yek".to_string()),
1031 blob: None,
1032 };
1033
1034 let selinux_granted_key =
1035 db.grant(selinux_key.clone(), CALLER_UID, 12, PVEC1, |k, a| {
1036 assert_eq!(*a, PVEC1);
1037 assert_eq!(
1038 *k,
1039 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001040 domain: super::Domain::SELINUX,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001041 // namespace must be the supplied SELinux
1042 // namespace.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001043 nspace: SELINUX_NAMESPACE,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001044 alias: Some("yek".to_string()),
1045 blob: None,
1046 }
1047 );
1048 Ok(())
1049 })?;
1050
1051 assert_eq!(
1052 selinux_granted_key,
1053 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001054 domain: super::Domain::GRANT,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001055 // The grantid is next_random + 1 due to the mock random number generator.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001056 nspace: next_random + 1,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001057 alias: None,
1058 blob: None,
1059 }
1060 );
1061
1062 // This should update the existing grant with PVEC2.
1063 let selinux_granted_key =
1064 db.grant(selinux_key.clone(), CALLER_UID, 12, PVEC2, |k, a| {
1065 assert_eq!(*a, PVEC2);
1066 assert_eq!(
1067 *k,
1068 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001069 domain: super::Domain::SELINUX,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001070 // namespace must be the supplied SELinux
1071 // namespace.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001072 nspace: SELINUX_NAMESPACE,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001073 alias: Some("yek".to_string()),
1074 blob: None,
1075 }
1076 );
1077 Ok(())
1078 })?;
1079
1080 assert_eq!(
1081 selinux_granted_key,
1082 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001083 domain: super::Domain::GRANT,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001084 // Same grant id as before. The entry was only updated.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001085 nspace: next_random + 1,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001086 alias: None,
1087 blob: None,
1088 }
1089 );
1090
1091 {
1092 // Limiting scope of stmt, because it borrows db.
1093 let mut stmt = db
1094 .conn
1095 .prepare("SELECT id, grantee, keyentryid, access_vector FROM perboot.grant;")?;
Janis Danisevskisee10b5f2020-09-22 16:42:35 -07001096 let mut rows =
1097 stmt.query_map::<(i64, u32, i64, KeyPermSet), _, _>(NO_PARAMS, |row| {
1098 Ok((
1099 row.get(0)?,
1100 row.get(1)?,
1101 row.get(2)?,
1102 KeyPermSet::from(row.get::<_, i32>(3)?),
1103 ))
1104 })?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001105
1106 let r = rows.next().unwrap().unwrap();
Janis Danisevskisee10b5f2020-09-22 16:42:35 -07001107 assert_eq!(r, (next_random, GRANTEE_UID, 1, PVEC1));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001108 let r = rows.next().unwrap().unwrap();
Janis Danisevskisee10b5f2020-09-22 16:42:35 -07001109 assert_eq!(r, (next_random + 1, GRANTEE_UID, 2, PVEC2));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001110 assert!(rows.next().is_none());
1111 }
1112
1113 debug_dump_keyentry_table(&mut db)?;
1114 println!("app_key {:?}", app_key);
1115 println!("selinux_key {:?}", selinux_key);
1116
1117 db.ungrant(app_key, CALLER_UID, GRANTEE_UID, |_| Ok(()))?;
1118 db.ungrant(selinux_key, CALLER_UID, GRANTEE_UID, |_| Ok(()))?;
1119
1120 Ok(())
1121 }
1122
1123 static TEST_KM_BLOB: &[u8] = b"my test blob";
1124 static TEST_CERT_BLOB: &[u8] = b"my test cert";
1125 static TEST_CERT_CHAIN_BLOB: &[u8] = b"my test cert_chain";
1126
1127 #[test]
1128 fn test_insert_blob() -> Result<()> {
1129 let mut db = new_test_db()?;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001130 db.insert_blob(1, SubComponentType::KM_BLOB, TEST_KM_BLOB, SecurityLevel::SOFTWARE)?;
1131 db.insert_blob(
1132 1,
1133 SubComponentType::CERT,
1134 TEST_CERT_BLOB,
1135 SecurityLevel::TRUSTED_ENVIRONMENT,
1136 )?;
1137 db.insert_blob(
1138 1,
1139 SubComponentType::CERT_CHAIN,
1140 TEST_CERT_CHAIN_BLOB,
1141 SecurityLevel::STRONGBOX,
1142 )?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001143
1144 let mut stmt = db.conn.prepare(
1145 "SELECT subcomponent_type, keyentryid, blob, sec_level FROM persistent.blobentry
1146 ORDER BY sec_level ASC;",
1147 )?;
1148 let mut rows = stmt
1149 .query_map::<(SubComponentType, i64, Vec<u8>, i64), _, _>(NO_PARAMS, |row| {
1150 Ok((row.get(0)?, row.get(1)?, row.get(2)?, row.get(3)?))
1151 })?;
1152 let r = rows.next().unwrap().unwrap();
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001153 assert_eq!(r, (SubComponentType::KM_BLOB, 1, TEST_KM_BLOB.to_vec(), 0));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001154 let r = rows.next().unwrap().unwrap();
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001155 assert_eq!(r, (SubComponentType::CERT, 1, TEST_CERT_BLOB.to_vec(), 1));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001156 let r = rows.next().unwrap().unwrap();
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001157 assert_eq!(r, (SubComponentType::CERT_CHAIN, 1, TEST_CERT_CHAIN_BLOB.to_vec(), 2));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001158
1159 Ok(())
1160 }
1161
1162 static TEST_ALIAS: &str = "my super duper key";
1163
1164 #[test]
1165 fn test_insert_and_load_full_keyentry_domain_app() -> Result<()> {
1166 let mut db = new_test_db()?;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001167 let key_id = make_test_key_entry(&mut db, Domain::APP, 1, TEST_ALIAS)
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001168 .context("test_insert_and_load_full_keyentry_domain_app")?;
1169 let key_entry = db.load_key_entry(
1170 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001171 domain: Domain::APP,
1172 nspace: 0,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001173 alias: Some(TEST_ALIAS.to_string()),
1174 blob: None,
1175 },
1176 KeyEntryLoadBits::BOTH,
1177 1,
1178 |_k, _av| Ok(()),
1179 )?;
1180 assert_eq!(
1181 key_entry,
1182 KeyEntry {
1183 id: key_id,
1184 km_blob: Some(TEST_KM_BLOB.to_vec()),
1185 cert: Some(TEST_CERT_BLOB.to_vec()),
1186 cert_chain: Some(TEST_CERT_CHAIN_BLOB.to_vec()),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001187 sec_level: SecurityLevel::TRUSTED_ENVIRONMENT,
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001188 parameters: make_test_params()
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001189 }
1190 );
1191 Ok(())
1192 }
1193
1194 #[test]
1195 fn test_insert_and_load_full_keyentry_domain_selinux() -> Result<()> {
1196 let mut db = new_test_db()?;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001197 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS)
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001198 .context("test_insert_and_load_full_keyentry_domain_selinux")?;
1199 let key_entry = db.load_key_entry(
1200 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001201 domain: Domain::SELINUX,
1202 nspace: 1,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001203 alias: Some(TEST_ALIAS.to_string()),
1204 blob: None,
1205 },
1206 KeyEntryLoadBits::BOTH,
1207 1,
1208 |_k, _av| Ok(()),
1209 )?;
1210 assert_eq!(
1211 key_entry,
1212 KeyEntry {
1213 id: key_id,
1214 km_blob: Some(TEST_KM_BLOB.to_vec()),
1215 cert: Some(TEST_CERT_BLOB.to_vec()),
1216 cert_chain: Some(TEST_CERT_CHAIN_BLOB.to_vec()),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001217 sec_level: SecurityLevel::TRUSTED_ENVIRONMENT,
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001218 parameters: make_test_params()
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001219 }
1220 );
1221 Ok(())
1222 }
1223
1224 #[test]
1225 fn test_insert_and_load_full_keyentry_domain_key_id() -> Result<()> {
1226 let mut db = new_test_db()?;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001227 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS)
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001228 .context("test_insert_and_load_full_keyentry_domain_key_id")?;
1229 let key_entry = db.load_key_entry(
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001230 KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001231 KeyEntryLoadBits::BOTH,
1232 1,
1233 |_k, _av| Ok(()),
1234 )?;
1235 assert_eq!(
1236 key_entry,
1237 KeyEntry {
1238 id: key_id,
1239 km_blob: Some(TEST_KM_BLOB.to_vec()),
1240 cert: Some(TEST_CERT_BLOB.to_vec()),
1241 cert_chain: Some(TEST_CERT_CHAIN_BLOB.to_vec()),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001242 sec_level: SecurityLevel::TRUSTED_ENVIRONMENT,
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001243 parameters: make_test_params()
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001244 }
1245 );
1246
1247 Ok(())
1248 }
1249
1250 #[test]
1251 fn test_insert_and_load_full_keyentry_from_grant() -> Result<()> {
1252 let mut db = new_test_db()?;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001253 let key_id = make_test_key_entry(&mut db, Domain::APP, 1, TEST_ALIAS)
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001254 .context("test_insert_and_load_full_keyentry_from_grant")?;
1255
1256 let granted_key = db.grant(
1257 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001258 domain: Domain::APP,
1259 nspace: 0,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001260 alias: Some(TEST_ALIAS.to_string()),
1261 blob: None,
1262 },
1263 1,
1264 2,
1265 key_perm_set![KeyPerm::use_()],
1266 |_k, _av| Ok(()),
1267 )?;
1268
1269 debug_dump_grant_table(&mut db)?;
1270
1271 let key_entry = db.load_key_entry(granted_key, KeyEntryLoadBits::BOTH, 2, |k, av| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001272 assert_eq!(Domain::GRANT, k.domain);
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001273 assert!(av.unwrap().includes(KeyPerm::use_()));
1274 Ok(())
1275 })?;
1276
1277 assert_eq!(
1278 key_entry,
1279 KeyEntry {
1280 id: key_id,
1281 km_blob: Some(TEST_KM_BLOB.to_vec()),
1282 cert: Some(TEST_CERT_BLOB.to_vec()),
1283 cert_chain: Some(TEST_CERT_CHAIN_BLOB.to_vec()),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001284 sec_level: SecurityLevel::TRUSTED_ENVIRONMENT,
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001285 parameters: make_test_params()
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001286 }
1287 );
1288 Ok(())
1289 }
1290
Joel Galenson0891bc12020-07-20 10:37:03 -07001291 // Helpers
1292
1293 // Checks that the given result is an error containing the given string.
1294 fn check_result_is_error_containing_string<T>(result: Result<T>, target: &str) {
1295 let error_str = format!(
1296 "{:#?}",
1297 result.err().unwrap_or_else(|| panic!("Expected the error: {}", target))
1298 );
1299 assert!(
1300 error_str.contains(target),
1301 "The string \"{}\" should contain \"{}\"",
1302 error_str,
1303 target
1304 );
1305 }
1306
Joel Galenson2aab4432020-07-22 15:27:57 -07001307 #[derive(Debug, PartialEq)]
Joel Galenson0891bc12020-07-20 10:37:03 -07001308 #[allow(dead_code)]
1309 struct KeyEntryRow {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001310 id: i64,
Joel Galenson0891bc12020-07-20 10:37:03 -07001311 creation_date: String,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001312 domain: Option<Domain>,
Joel Galenson0891bc12020-07-20 10:37:03 -07001313 namespace: Option<i64>,
1314 alias: Option<String>,
1315 }
1316
1317 fn get_keyentry(db: &KeystoreDB) -> Result<Vec<KeyEntryRow>> {
1318 db.conn
Joel Galenson2aab4432020-07-22 15:27:57 -07001319 .prepare("SELECT * FROM persistent.keyentry;")?
Joel Galenson0891bc12020-07-20 10:37:03 -07001320 .query_map(NO_PARAMS, |row| {
Joel Galenson0891bc12020-07-20 10:37:03 -07001321 Ok(KeyEntryRow {
1322 id: row.get(0)?,
1323 creation_date: row.get(1)?,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001324 domain: match row.get(2)? {
1325 Some(i) => Some(Domain(i)),
1326 None => None,
1327 },
Joel Galenson0891bc12020-07-20 10:37:03 -07001328 namespace: row.get(3)?,
1329 alias: row.get(4)?,
1330 })
1331 })?
1332 .map(|r| r.context("Could not read keyentry row."))
1333 .collect::<Result<Vec<_>>>()
1334 }
1335
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001336 // Note: The parameters and SecurityLevel associations are nonsensical. This
1337 // collection is only used to check if the parameters are preserved as expected by the
1338 // database.
1339 fn make_test_params() -> Vec<KeyParameter> {
1340 vec![
1341 KeyParameter::new(KeyParameterValue::Invalid, SecurityLevel::TRUSTED_ENVIRONMENT),
1342 KeyParameter::new(
1343 KeyParameterValue::KeyPurpose(KeyPurpose::SIGN),
1344 SecurityLevel::TRUSTED_ENVIRONMENT,
1345 ),
1346 KeyParameter::new(
1347 KeyParameterValue::KeyPurpose(KeyPurpose::DECRYPT),
1348 SecurityLevel::TRUSTED_ENVIRONMENT,
1349 ),
1350 KeyParameter::new(
1351 KeyParameterValue::Algorithm(Algorithm::RSA),
1352 SecurityLevel::TRUSTED_ENVIRONMENT,
1353 ),
1354 KeyParameter::new(KeyParameterValue::KeySize(1024), SecurityLevel::TRUSTED_ENVIRONMENT),
1355 KeyParameter::new(
1356 KeyParameterValue::BlockMode(BlockMode::ECB),
1357 SecurityLevel::TRUSTED_ENVIRONMENT,
1358 ),
1359 KeyParameter::new(
1360 KeyParameterValue::BlockMode(BlockMode::GCM),
1361 SecurityLevel::TRUSTED_ENVIRONMENT,
1362 ),
1363 KeyParameter::new(KeyParameterValue::Digest(Digest::NONE), SecurityLevel::STRONGBOX),
1364 KeyParameter::new(
1365 KeyParameterValue::Digest(Digest::MD5),
1366 SecurityLevel::TRUSTED_ENVIRONMENT,
1367 ),
1368 KeyParameter::new(
1369 KeyParameterValue::Digest(Digest::SHA_2_224),
1370 SecurityLevel::TRUSTED_ENVIRONMENT,
1371 ),
1372 KeyParameter::new(
1373 KeyParameterValue::Digest(Digest::SHA_2_256),
1374 SecurityLevel::STRONGBOX,
1375 ),
1376 KeyParameter::new(
1377 KeyParameterValue::PaddingMode(PaddingMode::NONE),
1378 SecurityLevel::TRUSTED_ENVIRONMENT,
1379 ),
1380 KeyParameter::new(
1381 KeyParameterValue::PaddingMode(PaddingMode::RSA_OAEP),
1382 SecurityLevel::TRUSTED_ENVIRONMENT,
1383 ),
1384 KeyParameter::new(
1385 KeyParameterValue::PaddingMode(PaddingMode::RSA_PSS),
1386 SecurityLevel::STRONGBOX,
1387 ),
1388 KeyParameter::new(
1389 KeyParameterValue::PaddingMode(PaddingMode::RSA_PKCS1_1_5_SIGN),
1390 SecurityLevel::TRUSTED_ENVIRONMENT,
1391 ),
1392 KeyParameter::new(KeyParameterValue::CallerNonce, SecurityLevel::TRUSTED_ENVIRONMENT),
1393 KeyParameter::new(KeyParameterValue::MinMacLength(256), SecurityLevel::STRONGBOX),
1394 KeyParameter::new(
1395 KeyParameterValue::EcCurve(EcCurve::P_224),
1396 SecurityLevel::TRUSTED_ENVIRONMENT,
1397 ),
1398 KeyParameter::new(KeyParameterValue::EcCurve(EcCurve::P_256), SecurityLevel::STRONGBOX),
1399 KeyParameter::new(
1400 KeyParameterValue::EcCurve(EcCurve::P_384),
1401 SecurityLevel::TRUSTED_ENVIRONMENT,
1402 ),
1403 KeyParameter::new(
1404 KeyParameterValue::EcCurve(EcCurve::P_521),
1405 SecurityLevel::TRUSTED_ENVIRONMENT,
1406 ),
1407 KeyParameter::new(
1408 KeyParameterValue::RSAPublicExponent(3),
1409 SecurityLevel::TRUSTED_ENVIRONMENT,
1410 ),
1411 KeyParameter::new(
1412 KeyParameterValue::IncludeUniqueID,
1413 SecurityLevel::TRUSTED_ENVIRONMENT,
1414 ),
1415 KeyParameter::new(KeyParameterValue::BootLoaderOnly, SecurityLevel::STRONGBOX),
1416 KeyParameter::new(KeyParameterValue::RollbackResistance, SecurityLevel::STRONGBOX),
1417 KeyParameter::new(
1418 KeyParameterValue::ActiveDateTime(1234567890),
1419 SecurityLevel::STRONGBOX,
1420 ),
1421 KeyParameter::new(
1422 KeyParameterValue::OriginationExpireDateTime(1234567890),
1423 SecurityLevel::TRUSTED_ENVIRONMENT,
1424 ),
1425 KeyParameter::new(
1426 KeyParameterValue::UsageExpireDateTime(1234567890),
1427 SecurityLevel::TRUSTED_ENVIRONMENT,
1428 ),
1429 KeyParameter::new(
1430 KeyParameterValue::MinSecondsBetweenOps(1234567890),
1431 SecurityLevel::TRUSTED_ENVIRONMENT,
1432 ),
1433 KeyParameter::new(
1434 KeyParameterValue::MaxUsesPerBoot(1234567890),
1435 SecurityLevel::TRUSTED_ENVIRONMENT,
1436 ),
1437 KeyParameter::new(KeyParameterValue::UserID(1), SecurityLevel::STRONGBOX),
1438 KeyParameter::new(KeyParameterValue::UserSecureID(42), SecurityLevel::STRONGBOX),
1439 KeyParameter::new(
1440 KeyParameterValue::NoAuthRequired,
1441 SecurityLevel::TRUSTED_ENVIRONMENT,
1442 ),
1443 KeyParameter::new(
1444 KeyParameterValue::HardwareAuthenticatorType(HardwareAuthenticatorType::PASSWORD),
1445 SecurityLevel::TRUSTED_ENVIRONMENT,
1446 ),
1447 KeyParameter::new(KeyParameterValue::AuthTimeout(1234567890), SecurityLevel::SOFTWARE),
1448 KeyParameter::new(KeyParameterValue::AllowWhileOnBody, SecurityLevel::SOFTWARE),
1449 KeyParameter::new(
1450 KeyParameterValue::TrustedUserPresenceRequired,
1451 SecurityLevel::TRUSTED_ENVIRONMENT,
1452 ),
1453 KeyParameter::new(
1454 KeyParameterValue::TrustedConfirmationRequired,
1455 SecurityLevel::TRUSTED_ENVIRONMENT,
1456 ),
1457 KeyParameter::new(
1458 KeyParameterValue::UnlockedDeviceRequired,
1459 SecurityLevel::TRUSTED_ENVIRONMENT,
1460 ),
1461 KeyParameter::new(
1462 KeyParameterValue::ApplicationID(vec![1u8, 2u8, 3u8, 4u8]),
1463 SecurityLevel::SOFTWARE,
1464 ),
1465 KeyParameter::new(
1466 KeyParameterValue::ApplicationData(vec![4u8, 3u8, 2u8, 1u8]),
1467 SecurityLevel::SOFTWARE,
1468 ),
1469 KeyParameter::new(
1470 KeyParameterValue::CreationDateTime(12345677890),
1471 SecurityLevel::SOFTWARE,
1472 ),
1473 KeyParameter::new(
1474 KeyParameterValue::KeyOrigin(KeyOrigin::GENERATED),
1475 SecurityLevel::TRUSTED_ENVIRONMENT,
1476 ),
1477 KeyParameter::new(
1478 KeyParameterValue::RootOfTrust(vec![3u8, 2u8, 1u8, 4u8]),
1479 SecurityLevel::TRUSTED_ENVIRONMENT,
1480 ),
1481 KeyParameter::new(KeyParameterValue::OSVersion(1), SecurityLevel::TRUSTED_ENVIRONMENT),
1482 KeyParameter::new(KeyParameterValue::OSPatchLevel(2), SecurityLevel::SOFTWARE),
1483 KeyParameter::new(
1484 KeyParameterValue::UniqueID(vec![4u8, 3u8, 1u8, 2u8]),
1485 SecurityLevel::SOFTWARE,
1486 ),
1487 KeyParameter::new(
1488 KeyParameterValue::AttestationChallenge(vec![4u8, 3u8, 1u8, 2u8]),
1489 SecurityLevel::TRUSTED_ENVIRONMENT,
1490 ),
1491 KeyParameter::new(
1492 KeyParameterValue::AttestationApplicationID(vec![4u8, 3u8, 1u8, 2u8]),
1493 SecurityLevel::TRUSTED_ENVIRONMENT,
1494 ),
1495 KeyParameter::new(
1496 KeyParameterValue::AttestationIdBrand(vec![4u8, 3u8, 1u8, 2u8]),
1497 SecurityLevel::TRUSTED_ENVIRONMENT,
1498 ),
1499 KeyParameter::new(
1500 KeyParameterValue::AttestationIdDevice(vec![4u8, 3u8, 1u8, 2u8]),
1501 SecurityLevel::TRUSTED_ENVIRONMENT,
1502 ),
1503 KeyParameter::new(
1504 KeyParameterValue::AttestationIdProduct(vec![4u8, 3u8, 1u8, 2u8]),
1505 SecurityLevel::TRUSTED_ENVIRONMENT,
1506 ),
1507 KeyParameter::new(
1508 KeyParameterValue::AttestationIdSerial(vec![4u8, 3u8, 1u8, 2u8]),
1509 SecurityLevel::TRUSTED_ENVIRONMENT,
1510 ),
1511 KeyParameter::new(
1512 KeyParameterValue::AttestationIdIMEI(vec![4u8, 3u8, 1u8, 2u8]),
1513 SecurityLevel::TRUSTED_ENVIRONMENT,
1514 ),
1515 KeyParameter::new(
1516 KeyParameterValue::AttestationIdMEID(vec![4u8, 3u8, 1u8, 2u8]),
1517 SecurityLevel::TRUSTED_ENVIRONMENT,
1518 ),
1519 KeyParameter::new(
1520 KeyParameterValue::AttestationIdManufacturer(vec![4u8, 3u8, 1u8, 2u8]),
1521 SecurityLevel::TRUSTED_ENVIRONMENT,
1522 ),
1523 KeyParameter::new(
1524 KeyParameterValue::AttestationIdModel(vec![4u8, 3u8, 1u8, 2u8]),
1525 SecurityLevel::TRUSTED_ENVIRONMENT,
1526 ),
1527 KeyParameter::new(
1528 KeyParameterValue::VendorPatchLevel(3),
1529 SecurityLevel::TRUSTED_ENVIRONMENT,
1530 ),
1531 KeyParameter::new(
1532 KeyParameterValue::BootPatchLevel(4),
1533 SecurityLevel::TRUSTED_ENVIRONMENT,
1534 ),
1535 KeyParameter::new(
1536 KeyParameterValue::AssociatedData(vec![4u8, 3u8, 1u8, 2u8]),
1537 SecurityLevel::TRUSTED_ENVIRONMENT,
1538 ),
1539 KeyParameter::new(
1540 KeyParameterValue::Nonce(vec![4u8, 3u8, 1u8, 2u8]),
1541 SecurityLevel::TRUSTED_ENVIRONMENT,
1542 ),
1543 KeyParameter::new(
1544 KeyParameterValue::MacLength(256),
1545 SecurityLevel::TRUSTED_ENVIRONMENT,
1546 ),
1547 KeyParameter::new(
1548 KeyParameterValue::ResetSinceIdRotation,
1549 SecurityLevel::TRUSTED_ENVIRONMENT,
1550 ),
1551 KeyParameter::new(
1552 KeyParameterValue::ConfirmationToken(vec![5u8, 5u8, 5u8, 5u8]),
1553 SecurityLevel::TRUSTED_ENVIRONMENT,
1554 ),
1555 ]
1556 }
1557
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001558 fn make_test_key_entry(
1559 db: &mut KeystoreDB,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001560 domain: Domain,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001561 namespace: i64,
1562 alias: &str,
1563 ) -> Result<i64> {
1564 let key_id = db.create_key_entry(domain, namespace)?;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001565 db.insert_blob(
1566 key_id,
1567 SubComponentType::KM_BLOB,
1568 TEST_KM_BLOB,
1569 SecurityLevel::TRUSTED_ENVIRONMENT,
1570 )?;
1571 db.insert_blob(
1572 key_id,
1573 SubComponentType::CERT,
1574 TEST_CERT_BLOB,
1575 SecurityLevel::TRUSTED_ENVIRONMENT,
1576 )?;
1577 db.insert_blob(
1578 key_id,
1579 SubComponentType::CERT_CHAIN,
1580 TEST_CERT_CHAIN_BLOB,
1581 SecurityLevel::TRUSTED_ENVIRONMENT,
1582 )?;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001583 db.insert_keyparameter(key_id, &make_test_params())?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001584 db.rebind_alias(key_id, alias, domain, namespace)?;
1585 Ok(key_id)
1586 }
1587
1588 fn debug_dump_keyentry_table(db: &mut KeystoreDB) -> Result<()> {
1589 let mut stmt = db.conn.prepare(
1590 "SELECT id, creation_date, domain, namespace, alias FROM persistent.keyentry;",
1591 )?;
1592 let rows = stmt.query_map::<(i64, i64, i32, i64, String), _, _>(NO_PARAMS, |row| {
1593 Ok((row.get(0)?, row.get(1)?, row.get(2)?, row.get(3)?, row.get(4)?))
1594 })?;
1595
1596 println!("Key entry table rows:");
1597 for r in rows {
1598 let (id, cdate, domain, namespace, alias) = r.unwrap();
1599 println!(
1600 " id: {} Creation date: {} Domain: {} Namespace: {} Alias: {}",
1601 id, cdate, domain, namespace, alias
1602 );
1603 }
1604 Ok(())
1605 }
1606
1607 fn debug_dump_grant_table(db: &mut KeystoreDB) -> Result<()> {
1608 let mut stmt =
1609 db.conn.prepare("SELECT id, grantee, keyentryid, access_vector FROM perboot.grant;")?;
1610 let rows = stmt.query_map::<(i64, i64, i64, i64), _, _>(NO_PARAMS, |row| {
1611 Ok((row.get(0)?, row.get(1)?, row.get(2)?, row.get(3)?))
1612 })?;
1613
1614 println!("Grant table rows:");
1615 for r in rows {
1616 let (id, gt, ki, av) = r.unwrap();
1617 println!(" id: {} grantee: {} key_id: {} access_vector: {}", id, gt, ki, av);
1618 }
1619 Ok(())
1620 }
1621
Joel Galenson2aab4432020-07-22 15:27:57 -07001622 // A class that deletes a file when it is dropped.
1623 // TODO: If we ever add a crate that does this, we can use it instead.
1624 struct TempFile {
1625 filename: &'static str,
1626 }
1627
1628 impl Drop for TempFile {
1629 fn drop(&mut self) {
1630 std::fs::remove_file(self.filename).expect("Cannot delete temporary file");
1631 }
1632 }
1633
Joel Galenson0891bc12020-07-20 10:37:03 -07001634 // Use a custom random number generator that repeats each number once.
1635 // This allows us to test repeated elements.
1636
1637 thread_local! {
1638 static RANDOM_COUNTER: RefCell<i64> = RefCell::new(0);
1639 }
1640
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001641 fn reset_random() {
1642 RANDOM_COUNTER.with(|counter| {
1643 *counter.borrow_mut() = 0;
1644 })
1645 }
1646
Joel Galenson0891bc12020-07-20 10:37:03 -07001647 pub fn random() -> i64 {
1648 RANDOM_COUNTER.with(|counter| {
1649 let result = *counter.borrow() / 2;
1650 *counter.borrow_mut() += 1;
1651 result
1652 })
1653 }
Joel Galenson26f4d012020-07-17 14:57:21 -07001654}