blob: 56a8943f103c5b5a7307fdac2e8bc2139d358415 [file] [log] [blame]
Joel Galenson26f4d012020-07-17 14:57:21 -07001// Copyright 2020, The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
Janis Danisevskis63f7bc82020-09-03 10:12:56 -070015//! This is the Keystore 2.0 database module.
16//! The database module provides a connection to the backing SQLite store.
17//! We have two databases one for persistent key blob storage and one for
18//! items that have a per boot life cycle.
19//!
20//! ## Persistent database
21//! The persistent database has tables for key blobs. They are organized
22//! as follows:
23//! The `keyentry` table is the primary table for key entries. It is
24//! accompanied by two tables for blobs and parameters.
25//! Each key entry occupies exactly one row in the `keyentry` table and
26//! zero or more rows in the tables `blobentry` and `keyparameter`.
27//!
28//! ## Per boot database
29//! The per boot database stores items with a per boot lifecycle.
30//! Currently, there is only the `grant` table in this database.
31//! Grants are references to a key that can be used to access a key by
32//! clients that don't own that key. Grants can only be created by the
33//! owner of a key. And only certain components can create grants.
34//! This is governed by SEPolicy.
35//!
36//! ## Access control
37//! Some database functions that load keys or create grants perform
38//! access control. This is because in some cases access control
39//! can only be performed after some information about the designated
40//! key was loaded from the database. To decouple the permission checks
41//! from the database module these functions take permission check
42//! callbacks.
Joel Galenson26f4d012020-07-17 14:57:21 -070043
Janis Danisevskisc5b210b2020-09-11 13:27:37 -070044use crate::error::{Error as KsError, ResponseCode};
45use crate::key_parameter::{KeyParameter, SqlField, Tag};
46use crate::permission::KeyPermSet;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -070047use anyhow::{anyhow, Context, Result};
Janis Danisevskis60400fe2020-08-26 15:24:42 -070048
Janis Danisevskis04b02832020-10-26 09:21:40 -070049use android_hardware_keymint::aidl::android::hardware::keymint::SecurityLevel::SecurityLevel;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -070050use android_system_keystore2::aidl::android::system::keystore2::{
Janis Danisevskis04b02832020-10-26 09:21:40 -070051 Domain::Domain, KeyDescriptor::KeyDescriptor,
Janis Danisevskis60400fe2020-08-26 15:24:42 -070052};
53
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 Danisevskisc5b210b2020-09-11 13:27:37 -0700102 sec_level: SecurityLevel,
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700103 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 Danisevskisc5b210b2020-09-11 13:27:37 -0700136 pub fn sec_level(&self) -> SecurityLevel {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700137 self.sec_level
138 }
Janis Danisevskis04b02832020-10-26 09:21:40 -0700139 /// Exposes the key parameters of this key entry.
140 pub fn key_parameters(&self) -> &Vec<KeyParameter> {
141 &self.parameters
142 }
143 /// Consumes this key entry and extracts the keyparameters from it.
144 pub fn into_key_parameters(self) -> Vec<KeyParameter> {
145 self.parameters
146 }
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700147}
148
149/// Indicates the sub component of a key entry for persistent storage.
150#[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
151pub struct SubComponentType(u32);
152impl SubComponentType {
153 /// Persistent identifier for a KeyMint blob.
154 pub const KM_BLOB: SubComponentType = Self(0);
155 /// Persistent identifier for a certificate blob.
156 pub const CERT: SubComponentType = Self(1);
157 /// Persistent identifier for a certificate chain blob.
158 pub const CERT_CHAIN: SubComponentType = Self(2);
159}
160
161impl ToSql for SubComponentType {
162 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
163 self.0.to_sql()
164 }
165}
166
167impl FromSql for SubComponentType {
168 fn column_result(value: ValueRef) -> FromSqlResult<Self> {
169 Ok(Self(u32::column_result(value)?))
170 }
171}
172
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700173static INIT_TABLES: Once = Once::new();
174
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700175/// KeystoreDB wraps a connection to an SQLite database and tracks its
176/// ownership. It also implements all of Keystore 2.0's database functionality.
Joel Galenson26f4d012020-07-17 14:57:21 -0700177pub struct KeystoreDB {
Joel Galenson26f4d012020-07-17 14:57:21 -0700178 conn: Connection,
179}
180
181impl KeystoreDB {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700182 /// This will create a new database connection connecting the two
183 /// files persistent.sqlite and perboot.sqlite in the current working
184 /// directory, which is usually `/data/misc/keystore/`.
185 /// It also attempts to initialize all of the tables on the first instantiation
186 /// per service startup. KeystoreDB cannot be used by multiple threads.
187 /// Each thread should open their own connection using `thread_local!`.
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700188 pub fn new() -> Result<Self> {
189 let conn = Self::make_connection("file:persistent.sqlite", "file:perboot.sqlite")?;
190
191 INIT_TABLES.call_once(|| Self::init_tables(&conn).expect("Failed to initialize tables."));
192 Ok(Self { conn })
Joel Galenson2aab4432020-07-22 15:27:57 -0700193 }
194
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700195 fn init_tables(conn: &Connection) -> Result<()> {
196 conn.execute(
197 "CREATE TABLE IF NOT EXISTS persistent.keyentry (
Joel Galenson0891bc12020-07-20 10:37:03 -0700198 id INTEGER UNIQUE,
199 creation_date DATETIME,
200 domain INTEGER,
201 namespace INTEGER,
202 alias TEXT);",
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700203 NO_PARAMS,
204 )
205 .context("Failed to initialize \"keyentry\" table.")?;
206
207 conn.execute(
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700208 "CREATE VIEW IF NOT EXISTS persistent.orphaned AS
209 SELECT id FROM persistent.keyentry WHERE domain IS NULL;",
210 NO_PARAMS,
211 )
212 .context("Failed to initialize \"orphaned\" view")?;
213
214 conn.execute(
215 "CREATE TABLE IF NOT EXISTS persistent.blobentry (
216 id INTEGER PRIMARY KEY,
217 subcomponent_type INTEGER,
218 keyentryid INTEGER,
219 blob BLOB,
220 sec_level INTEGER);",
221 NO_PARAMS,
222 )
223 .context("Failed to initialize \"blobentry\" table.")?;
224
225 conn.execute(
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700226 "CREATE TABLE IF NOT EXISTS persistent.keyparameter (
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000227 keyentryid INTEGER,
228 tag INTEGER,
229 data ANY,
230 security_level INTEGER);",
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700231 NO_PARAMS,
232 )
233 .context("Failed to initialize \"keyparameter\" table.")?;
234
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700235 // TODO only drop the perboot table if we start up for the first time per boot.
236 // Right now this is done once per startup which will lose some information
237 // upon a crash.
238 // Note: This is no regression with respect to the legacy Keystore.
239 conn.execute("DROP TABLE IF EXISTS perboot.grant;", NO_PARAMS)
240 .context("Failed to drop perboot.grant table")?;
241 conn.execute(
242 "CREATE TABLE perboot.grant (
243 id INTEGER UNIQUE,
244 grantee INTEGER,
245 keyentryid INTEGER,
246 access_vector INTEGER);",
247 NO_PARAMS,
248 )
249 .context("Failed to initialize \"grant\" table.")?;
250
Joel Galenson0891bc12020-07-20 10:37:03 -0700251 Ok(())
252 }
253
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700254 fn make_connection(persistent_file: &str, perboot_file: &str) -> Result<Connection> {
255 let conn =
256 Connection::open_in_memory().context("Failed to initialize SQLite connection.")?;
257
258 conn.execute("ATTACH DATABASE ? as persistent;", params![persistent_file])
259 .context("Failed to attach database persistent.")?;
260 conn.execute("ATTACH DATABASE ? as perboot;", params![perboot_file])
261 .context("Failed to attach database perboot.")?;
262
263 Ok(conn)
264 }
265
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700266 /// Creates a new key entry and allocates a new randomized id for the new key.
267 /// The key id gets associated with a domain and namespace but not with an alias.
268 /// To complete key generation `rebind_alias` should be called after all of the
269 /// key artifacts, i.e., blobs and parameters have been associated with the new
270 /// key id. Finalizing with `rebind_alias` makes the creation of a new key entry
271 /// atomic even if key generation is not.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700272 pub fn create_key_entry(&self, domain: Domain, namespace: i64) -> Result<i64> {
Joel Galenson0891bc12020-07-20 10:37:03 -0700273 match domain {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700274 Domain::APP | Domain::SELINUX => {}
Joel Galenson0891bc12020-07-20 10:37:03 -0700275 _ => {
276 return Err(KsError::sys())
277 .context(format!("Domain {:?} must be either App or SELinux.", domain));
278 }
279 }
Joel Galenson845f74b2020-09-09 14:11:55 -0700280 Self::insert_with_retry(|id| {
281 self.conn.execute(
Joel Galenson2aab4432020-07-22 15:27:57 -0700282 "INSERT into persistent.keyentry (id, creation_date, domain, namespace, alias)
Joel Galenson0891bc12020-07-20 10:37:03 -0700283 VALUES(?, datetime('now'), ?, ?, NULL);",
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700284 params![id, domain.0 as u32, namespace],
Joel Galenson845f74b2020-09-09 14:11:55 -0700285 )
286 })
287 .context("In create_key_entry")
Joel Galenson26f4d012020-07-17 14:57:21 -0700288 }
Joel Galenson33c04ad2020-08-03 11:04:38 -0700289
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700290 /// Inserts a new blob and associates it with the given key id. Each blob
291 /// has a sub component type and a security level.
292 /// Each key can have one of each sub component type associated. If more
293 /// are added only the most recent can be retrieved, and superseded blobs
294 /// will get garbage collected. The security level field of components
295 /// other than `SubComponentType::KM_BLOB` are ignored.
296 pub fn insert_blob(
297 &mut self,
298 key_id: i64,
299 sc_type: SubComponentType,
300 blob: &[u8],
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700301 sec_level: SecurityLevel,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700302 ) -> Result<()> {
303 self.conn
304 .execute(
305 "INSERT into persistent.blobentry (subcomponent_type, keyentryid, blob, sec_level)
306 VALUES (?, ?, ?, ?);",
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700307 params![sc_type, key_id, blob, sec_level.0],
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700308 )
309 .context("Failed to insert blob.")?;
310 Ok(())
311 }
312
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700313 /// Inserts a collection of key parameters into the `persistent.keyparameter` table
314 /// and associates them with the given `key_id`.
315 pub fn insert_keyparameter<'a>(
316 &mut self,
317 key_id: i64,
318 params: impl IntoIterator<Item = &'a KeyParameter>,
319 ) -> Result<()> {
320 let mut stmt = self
321 .conn
322 .prepare(
323 "INSERT into persistent.keyparameter (keyentryid, tag, data, security_level)
324 VALUES (?, ?, ?, ?);",
325 )
326 .context("In insert_keyparameter: Failed to prepare statement.")?;
327
328 let iter = params.into_iter();
329 for p in iter {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700330 stmt.insert(params![
331 key_id,
332 p.get_tag().0,
333 p.key_parameter_value(),
334 p.security_level().0
335 ])
336 .with_context(|| format!("In insert_keyparameter: Failed to insert {:?}", p))?;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700337 }
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 Danisevskisc5b210b2020-09-11 13:27:37 -0700348 domain: Domain,
Joel Galenson33c04ad2020-08-03 11:04:38 -0700349 namespace: i64,
350 ) -> Result<()> {
351 match domain {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -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 = ?;",
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700368 params![alias, domain.0 as u32, namespace],
Joel Galenson33c04ad2020-08-03 11:04:38 -0700369 )
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 = ?;",
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700376 params![alias, newid, domain.0 as u32, namespace],
Joel Galenson33c04ad2020-08-03 11:04:38 -0700377 )
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
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700411 .query(params![key.domain.0 as u32, key.nspace, alias])
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700412 .context("In load_key_entry_id: Failed to read from keyentry table.")?;
413 Self::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700414 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700415 .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.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700424 /// * Domain::SELINUX: The access tuple is complete and this function only loads
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700425 /// the key_id for further processing.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700426 /// * Domain::APP: Like Domain::SELINUX, but the tuple is completed by `caller_uid`
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700427 /// which serves as the namespace.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700428 /// * Domain::GRANT: The grant table is queried for the `key_id` and the
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700429 /// `access_vector`.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700430 /// * Domain::KEY_ID: The keyentry table is queried for the owning `domain` and
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700431 /// `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
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700445 // Domain::APP.
446 Domain::APP | Domain::SELINUX => {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700447 let mut access_key = key;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700448 if access_key.domain == Domain::APP {
449 access_key.nspace = caller_uid as i64;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700450 }
451 let key_id = Self::load_key_entry_id(&access_key, &tx)
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700452 .with_context(|| format!("With key.domain = {:?}.", access_key.domain))?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700453
454 Ok((key_id, access_key, None))
455 }
456
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700457 // Domain::GRANT. In this case we load the key_id and the access_vector
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700458 // from the grant table.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700459 Domain::GRANT => {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700460 let mut stmt = tx
461 .prepare(
462 "SELECT keyentryid, access_vector FROM perboot.grant
463 WHERE grantee = ? AND id = ?;",
464 )
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700465 .context("Domain::GRANT prepare statement failed")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700466 let mut rows = stmt
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700467 .query(params![caller_uid as i64, key.nspace])
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700468 .context("Domain:Grant: query failed.")?;
469 let (key_id, access_vector): (i64, i32) =
470 Self::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700471 let r =
472 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700473 Ok((
474 r.get(0).context("Failed to unpack key_id.")?,
475 r.get(1).context("Failed to unpack access_vector.")?,
476 ))
477 })
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700478 .context("Domain::GRANT.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700479 Ok((key_id, key, Some(access_vector.into())))
480 }
481
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700482 // Domain::KEY_ID. In this case we load the domain and namespace from the
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700483 // keyentry database because we need them for access control.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700484 Domain::KEY_ID => {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700485 let mut stmt = tx
486 .prepare(
487 "SELECT domain, namespace FROM persistent.keyentry
488 WHERE
489 id = ?;",
490 )
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700491 .context("Domain::KEY_ID: prepare statement failed")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700492 let mut rows =
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700493 stmt.query(params![key.nspace]).context("Domain::KEY_ID: query failed.")?;
494 let (domain, namespace): (Domain, i64) =
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700495 Self::with_rows_extract_one(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700496 let r =
497 row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700498 Ok((
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700499 Domain(r.get(0).context("Failed to unpack domain.")?),
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700500 r.get(1).context("Failed to unpack namespace.")?,
501 ))
502 })
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700503 .context("Domain::KEY_ID.")?;
504 let key_id = key.nspace;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700505 let mut access_key = key;
506 access_key.domain = domain;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700507 access_key.nspace = namespace;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700508
509 Ok((key_id, access_key, None))
510 }
511 _ => Err(anyhow!(KsError::sys())),
512 }
513 }
514
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700515 fn load_blob_components(
516 key_id: i64,
517 load_bits: KeyEntryLoadBits,
518 tx: &Transaction,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700519 ) -> Result<(SecurityLevel, Option<Vec<u8>>, Option<Vec<u8>>, Option<Vec<u8>>)> {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700520 let mut stmt = tx
521 .prepare(
522 "SELECT MAX(id), sec_level, subcomponent_type, blob FROM persistent.blobentry
523 WHERE keyentryid = ? GROUP BY subcomponent_type;",
524 )
525 .context("In load_blob_components: prepare statement failed.")?;
526
527 let mut rows =
528 stmt.query(params![key_id]).context("In load_blob_components: query failed.")?;
529
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700530 let mut sec_level: SecurityLevel = Default::default();
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700531 let mut km_blob: Option<Vec<u8>> = None;
532 let mut cert_blob: Option<Vec<u8>> = None;
533 let mut cert_chain_blob: Option<Vec<u8>> = None;
534 Self::with_rows_extract_all(&mut rows, |row| {
535 let sub_type: SubComponentType =
536 row.get(2).context("Failed to extract subcomponent_type.")?;
537 match (sub_type, load_bits.load_public()) {
538 (SubComponentType::KM_BLOB, _) => {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700539 sec_level =
540 SecurityLevel(row.get(1).context("Failed to extract security level.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700541 if load_bits.load_km() {
542 km_blob = Some(row.get(3).context("Failed to extract KM blob.")?);
543 }
544 }
545 (SubComponentType::CERT, true) => {
546 cert_blob =
547 Some(row.get(3).context("Failed to extract public certificate blob.")?);
548 }
549 (SubComponentType::CERT_CHAIN, true) => {
550 cert_chain_blob =
551 Some(row.get(3).context("Failed to extract certificate chain blob.")?);
552 }
553 (SubComponentType::CERT, _) | (SubComponentType::CERT_CHAIN, _) => {}
554 _ => Err(KsError::sys()).context("Unknown subcomponent type.")?,
555 }
556 Ok(())
557 })
558 .context("In load_blob_components.")?;
559
560 Ok((sec_level, km_blob, cert_blob, cert_chain_blob))
561 }
562
563 fn load_key_parameters(key_id: i64, tx: &Transaction) -> Result<Vec<KeyParameter>> {
564 let mut stmt = tx
565 .prepare(
566 "SELECT tag, data, security_level from persistent.keyparameter
567 WHERE keyentryid = ?;",
568 )
569 .context("In load_key_parameters: prepare statement failed.")?;
570
571 let mut parameters: Vec<KeyParameter> = Vec::new();
572
573 let mut rows =
574 stmt.query(params![key_id]).context("In load_key_parameters: query failed.")?;
575 Self::with_rows_extract_all(&mut rows, |row| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700576 let tag = Tag(row.get(0).context("Failed to read tag.")?);
577 let sec_level = SecurityLevel(row.get(2).context("Failed to read sec_level.")?);
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700578 parameters.push(
579 KeyParameter::new_from_sql(tag, &SqlField::new(1, &row), sec_level)
580 .context("Failed to read KeyParameter.")?,
581 );
582 Ok(())
583 })
584 .context("In load_key_parameters.")?;
585
586 Ok(parameters)
587 }
588
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700589 /// Load a key entry by the given key descriptor.
590 /// It uses the `check_permission` callback to verify if the access is allowed
591 /// given the key access tuple read from the database using `load_access_tuple`.
592 /// With `load_bits` the caller may specify which blobs shall be loaded from
593 /// the blob database.
594 pub fn load_key_entry(
595 &mut self,
596 key: KeyDescriptor,
597 load_bits: KeyEntryLoadBits,
598 caller_uid: u32,
599 check_permission: impl FnOnce(&KeyDescriptor, Option<KeyPermSet>) -> Result<()>,
600 ) -> Result<KeyEntry> {
601 let tx = self
602 .conn
603 .transaction_with_behavior(TransactionBehavior::Deferred)
604 .context("In load_key_entry: Failed to initialize transaction.")?;
605
606 // Load the key_id and complete the access control tuple.
607 let (key_id, access_key_descriptor, access_vector) =
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700608 Self::load_access_tuple(&tx, key, caller_uid).context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700609
610 // Perform access control. It is vital that we return here if the permission is denied.
611 // So do not touch that '?' at the end.
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700612 check_permission(&access_key_descriptor, access_vector).context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700613
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700614 let (sec_level, km_blob, cert_blob, cert_chain_blob) =
615 Self::load_blob_components(key_id, load_bits, &tx).context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700616
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700617 let parameters = Self::load_key_parameters(key_id, &tx).context("In load_key_entry.")?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700618
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700619 tx.commit().context("In load_key_entry: Failed to commit transaction.")?;
620
621 Ok(KeyEntry {
622 id: key_id,
623 km_blob,
624 cert: cert_blob,
625 cert_chain: cert_chain_blob,
626 sec_level,
627 parameters,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700628 })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700629 }
630
631 /// Adds a grant to the grant table.
632 /// Like `load_key_entry` this function loads the access tuple before
633 /// it uses the callback for a permission check. Upon success,
634 /// it inserts the `grantee_uid`, `key_id`, and `access_vector` into the
635 /// grant table. The new row will have a randomized id, which is used as
636 /// grant id in the namespace field of the resulting KeyDescriptor.
637 pub fn grant(
638 &mut self,
639 key: KeyDescriptor,
640 caller_uid: u32,
641 grantee_uid: u32,
642 access_vector: KeyPermSet,
643 check_permission: impl FnOnce(&KeyDescriptor, &KeyPermSet) -> Result<()>,
644 ) -> Result<KeyDescriptor> {
645 let tx = self
646 .conn
647 .transaction_with_behavior(TransactionBehavior::Immediate)
648 .context("In grant: Failed to initialize transaction.")?;
649
650 // Load the key_id and complete the access control tuple.
651 // We ignore the access vector here because grants cannot be granted.
652 // The access vector returned here expresses the permissions the
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700653 // grantee has if key.domain == Domain::GRANT. But this vector
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700654 // cannot include the grant permission by design, so there is no way the
655 // subsequent permission check can pass.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700656 // We could check key.domain == Domain::GRANT and fail early.
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700657 // But even if we load the access tuple by grant here, the permission
658 // check denies the attempt to create a grant by grant descriptor.
659 let (key_id, access_key_descriptor, _) =
660 Self::load_access_tuple(&tx, key, caller_uid).context("In grant")?;
661
662 // Perform access control. It is vital that we return here if the permission
663 // was denied. So do not touch that '?' at the end of the line.
664 // This permission check checks if the caller has the grant permission
665 // for the given key and in addition to all of the permissions
666 // expressed in `access_vector`.
667 check_permission(&access_key_descriptor, &access_vector)
668 .context("In grant: check_permission failed.")?;
669
670 let grant_id = if let Some(grant_id) = tx
671 .query_row(
672 "SELECT id FROM perboot.grant
673 WHERE keyentryid = ? AND grantee = ?;",
674 params![key_id, grantee_uid],
675 |row| row.get(0),
676 )
677 .optional()
678 .context("In grant: Failed get optional existing grant id.")?
679 {
680 tx.execute(
681 "UPDATE perboot.grant
682 SET access_vector = ?
683 WHERE id = ?;",
684 params![i32::from(access_vector), grant_id],
685 )
686 .context("In grant: Failed to update existing grant.")?;
687 grant_id
688 } else {
Joel Galenson845f74b2020-09-09 14:11:55 -0700689 Self::insert_with_retry(|id| {
690 tx.execute(
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700691 "INSERT INTO perboot.grant (id, grantee, keyentryid, access_vector)
692 VALUES (?, ?, ?, ?);",
Joel Galenson845f74b2020-09-09 14:11:55 -0700693 params![id, grantee_uid, key_id, i32::from(access_vector)],
694 )
695 })
696 .context("In grant")?
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700697 };
698 tx.commit().context("In grant: failed to commit transaction.")?;
699
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700700 Ok(KeyDescriptor { domain: Domain::GRANT, nspace: grant_id, alias: None, blob: None })
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700701 }
702
703 /// This function checks permissions like `grant` and `load_key_entry`
704 /// before removing a grant from the grant table.
705 pub fn ungrant(
706 &mut self,
707 key: KeyDescriptor,
708 caller_uid: u32,
709 grantee_uid: u32,
710 check_permission: impl FnOnce(&KeyDescriptor) -> Result<()>,
711 ) -> Result<()> {
712 let tx = self
713 .conn
714 .transaction_with_behavior(TransactionBehavior::Immediate)
715 .context("In ungrant: Failed to initialize transaction.")?;
716
717 // Load the key_id and complete the access control tuple.
718 // We ignore the access vector here because grants cannot be granted.
719 let (key_id, access_key_descriptor, _) =
720 Self::load_access_tuple(&tx, key, caller_uid).context("In ungrant.")?;
721
722 // Perform access control. We must return here if the permission
723 // was denied. So do not touch the '?' at the end of this line.
724 check_permission(&access_key_descriptor).context("In grant: check_permission failed.")?;
725
726 tx.execute(
727 "DELETE FROM perboot.grant
728 WHERE keyentryid = ? AND grantee = ?;",
729 params![key_id, grantee_uid],
730 )
731 .context("Failed to delete grant.")?;
732
733 tx.commit().context("In ungrant: failed to commit transaction.")?;
734
735 Ok(())
736 }
737
Joel Galenson845f74b2020-09-09 14:11:55 -0700738 // Generates a random id and passes it to the given function, which will
739 // try to insert it into a database. If that insertion fails, retry;
740 // otherwise return the id.
741 fn insert_with_retry(inserter: impl Fn(i64) -> rusqlite::Result<usize>) -> Result<i64> {
742 loop {
743 let newid: i64 = random();
744 match inserter(newid) {
745 // If the id already existed, try again.
746 Err(rusqlite::Error::SqliteFailure(
747 libsqlite3_sys::Error {
748 code: libsqlite3_sys::ErrorCode::ConstraintViolation,
749 extended_code: libsqlite3_sys::SQLITE_CONSTRAINT_UNIQUE,
750 },
751 _,
752 )) => (),
753 Err(e) => {
754 return Err(e).context("In insert_with_retry: failed to insert into database.")
755 }
756 _ => return Ok(newid),
757 }
758 }
759 }
760
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700761 // Takes Rows as returned by a query call on prepared statement.
762 // Extracts exactly one row with the `row_extractor` and fails if more
763 // rows are available.
764 // If no row was found, `None` is passed to the `row_extractor`.
765 // This allows the row extractor to decide on an error condition or
766 // a different default behavior.
767 fn with_rows_extract_one<'a, T, F>(rows: &mut Rows<'a>, row_extractor: F) -> Result<T>
768 where
769 F: FnOnce(Option<&Row<'a>>) -> Result<T>,
770 {
771 let result =
772 row_extractor(rows.next().context("with_rows_extract_one: Failed to unpack row.")?);
773
774 rows.next()
775 .context("In with_rows_extract_one: Failed to unpack unexpected row.")?
776 .map_or_else(|| Ok(()), |_| Err(KsError::sys()))
777 .context("In with_rows_extract_one: Unexpected row.")?;
778
779 result
780 }
781
782 fn with_rows_extract_all<'a, F>(rows: &mut Rows<'a>, mut row_extractor: F) -> Result<()>
783 where
784 F: FnMut(&Row<'a>) -> Result<()>,
785 {
786 loop {
787 match rows.next().context("In with_rows_extract_all: Failed to unpack row")? {
788 Some(row) => {
789 row_extractor(&row).context("In with_rows_extract_all.")?;
790 }
791 None => break Ok(()),
792 }
793 }
Joel Galenson33c04ad2020-08-03 11:04:38 -0700794 }
Joel Galenson26f4d012020-07-17 14:57:21 -0700795}
796
797#[cfg(test)]
798mod tests {
799
800 use super::*;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700801 use crate::key_parameter::{
802 Algorithm, BlockMode, Digest, EcCurve, HardwareAuthenticatorType, KeyOrigin, KeyParameter,
803 KeyParameterValue, KeyPurpose, PaddingMode, SecurityLevel,
804 };
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700805 use crate::key_perm_set;
806 use crate::permission::{KeyPerm, KeyPermSet};
807 use rusqlite::NO_PARAMS;
Joel Galenson0891bc12020-07-20 10:37:03 -0700808 use std::cell::RefCell;
809
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700810 static PERSISTENT_TEST_SQL: &str = "/data/local/tmp/persistent.sqlite";
811 static PERBOOT_TEST_SQL: &str = "/data/local/tmp/perboot.sqlite";
812
813 fn new_test_db() -> Result<KeystoreDB> {
814 let conn = KeystoreDB::make_connection("file::memory:", "file::memory:")?;
815
816 KeystoreDB::init_tables(&conn).context("Failed to initialize tables.")?;
817 Ok(KeystoreDB { conn })
818 }
819
820 fn new_test_db_with_persistent_file() -> Result<KeystoreDB> {
821 let conn = KeystoreDB::make_connection(PERSISTENT_TEST_SQL, PERBOOT_TEST_SQL)?;
822
823 KeystoreDB::init_tables(&conn).context("Failed to initialize tables.")?;
824 Ok(KeystoreDB { conn })
825 }
826
Joel Galenson0891bc12020-07-20 10:37:03 -0700827 // Ensure that we're using the "injected" random function, not the real one.
828 #[test]
829 fn test_mocked_random() {
830 let rand1 = random();
831 let rand2 = random();
832 let rand3 = random();
833 if rand1 == rand2 {
834 assert_eq!(rand2 + 1, rand3);
835 } else {
836 assert_eq!(rand1 + 1, rand2);
837 assert_eq!(rand2, rand3);
838 }
839 }
Joel Galenson26f4d012020-07-17 14:57:21 -0700840
Joel Galenson26f4d012020-07-17 14:57:21 -0700841 // Test that we have the correct tables.
842 #[test]
843 fn test_tables() -> Result<()> {
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700844 let db = new_test_db()?;
Joel Galenson26f4d012020-07-17 14:57:21 -0700845 let tables = db
846 .conn
Joel Galenson2aab4432020-07-22 15:27:57 -0700847 .prepare("SELECT name from persistent.sqlite_master WHERE type='table' ORDER BY name;")?
Joel Galenson26f4d012020-07-17 14:57:21 -0700848 .query_map(params![], |row| row.get(0))?
849 .collect::<rusqlite::Result<Vec<String>>>()?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700850 assert_eq!(tables.len(), 3);
851 assert_eq!(tables[0], "blobentry");
852 assert_eq!(tables[1], "keyentry");
853 assert_eq!(tables[2], "keyparameter");
854 let tables = db
855 .conn
856 .prepare("SELECT name from perboot.sqlite_master WHERE type='table' ORDER BY name;")?
857 .query_map(params![], |row| row.get(0))?
858 .collect::<rusqlite::Result<Vec<String>>>()?;
859 assert_eq!(tables.len(), 1);
860 assert_eq!(tables[0], "grant");
Joel Galenson26f4d012020-07-17 14:57:21 -0700861 Ok(())
862 }
Joel Galenson0891bc12020-07-20 10:37:03 -0700863
864 #[test]
Joel Galenson2aab4432020-07-22 15:27:57 -0700865 fn test_no_persistence_for_tests() -> Result<()> {
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700866 let db = new_test_db()?;
Joel Galenson2aab4432020-07-22 15:27:57 -0700867
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700868 db.create_key_entry(Domain::APP, 100)?;
Joel Galenson2aab4432020-07-22 15:27:57 -0700869 let entries = get_keyentry(&db)?;
870 assert_eq!(entries.len(), 1);
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700871 let db = new_test_db()?;
Joel Galenson2aab4432020-07-22 15:27:57 -0700872
873 let entries = get_keyentry(&db)?;
874 assert_eq!(entries.len(), 0);
875 Ok(())
876 }
877
878 #[test]
879 fn test_persistence_for_files() -> Result<()> {
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700880 let _file_guard_persistent = TempFile { filename: PERSISTENT_TEST_SQL };
881 let _file_guard_perboot = TempFile { filename: PERBOOT_TEST_SQL };
882 let db = new_test_db_with_persistent_file()?;
Joel Galenson2aab4432020-07-22 15:27:57 -0700883
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700884 db.create_key_entry(Domain::APP, 100)?;
Joel Galenson2aab4432020-07-22 15:27:57 -0700885 let entries = get_keyentry(&db)?;
886 assert_eq!(entries.len(), 1);
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700887 let db = new_test_db_with_persistent_file()?;
Joel Galenson2aab4432020-07-22 15:27:57 -0700888
889 let entries_new = get_keyentry(&db)?;
890 assert_eq!(entries, entries_new);
891 Ok(())
892 }
893
894 #[test]
Joel Galenson0891bc12020-07-20 10:37:03 -0700895 fn test_create_key_entry() -> Result<()> {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700896 fn extractor(ke: &KeyEntryRow) -> (Domain, i64, Option<&str>) {
Joel Galenson0891bc12020-07-20 10:37:03 -0700897 (ke.domain.unwrap(), ke.namespace.unwrap(), ke.alias.as_deref())
898 }
899
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700900 let db = new_test_db()?;
Joel Galenson0891bc12020-07-20 10:37:03 -0700901
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700902 db.create_key_entry(Domain::APP, 100)?;
903 db.create_key_entry(Domain::SELINUX, 101)?;
Joel Galenson0891bc12020-07-20 10:37:03 -0700904
905 let entries = get_keyentry(&db)?;
906 assert_eq!(entries.len(), 2);
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700907 assert_eq!(extractor(&entries[0]), (Domain::APP, 100, None));
908 assert_eq!(extractor(&entries[1]), (Domain::SELINUX, 101, None));
Joel Galenson0891bc12020-07-20 10:37:03 -0700909
910 // Test that we must pass in a valid Domain.
911 check_result_is_error_containing_string(
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700912 db.create_key_entry(Domain::GRANT, 102),
913 "Domain Domain(1) must be either App or SELinux.",
Joel Galenson0891bc12020-07-20 10:37:03 -0700914 );
915 check_result_is_error_containing_string(
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700916 db.create_key_entry(Domain::BLOB, 103),
917 "Domain Domain(3) must be either App or SELinux.",
Joel Galenson0891bc12020-07-20 10:37:03 -0700918 );
919 check_result_is_error_containing_string(
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700920 db.create_key_entry(Domain::KEY_ID, 104),
921 "Domain Domain(4) must be either App or SELinux.",
Joel Galenson0891bc12020-07-20 10:37:03 -0700922 );
923
924 Ok(())
925 }
926
Joel Galenson33c04ad2020-08-03 11:04:38 -0700927 #[test]
928 fn test_rebind_alias() -> Result<()> {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700929 fn extractor(ke: &KeyEntryRow) -> (Option<Domain>, Option<i64>, Option<&str>) {
Joel Galenson33c04ad2020-08-03 11:04:38 -0700930 (ke.domain, ke.namespace, ke.alias.as_deref())
931 }
932
Janis Danisevskis4df44f42020-08-26 14:40:03 -0700933 let mut db = new_test_db()?;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700934 db.create_key_entry(Domain::APP, 42)?;
935 db.create_key_entry(Domain::APP, 42)?;
Joel Galenson33c04ad2020-08-03 11:04:38 -0700936 let entries = get_keyentry(&db)?;
937 assert_eq!(entries.len(), 2);
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700938 assert_eq!(extractor(&entries[0]), (Some(Domain::APP), Some(42), None));
939 assert_eq!(extractor(&entries[1]), (Some(Domain::APP), Some(42), None));
Joel Galenson33c04ad2020-08-03 11:04:38 -0700940
941 // Test that the first call to rebind_alias sets the alias.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700942 db.rebind_alias(entries[0].id, "foo", Domain::APP, 42)?;
Joel Galenson33c04ad2020-08-03 11:04:38 -0700943 let entries = get_keyentry(&db)?;
944 assert_eq!(entries.len(), 2);
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700945 assert_eq!(extractor(&entries[0]), (Some(Domain::APP), Some(42), Some("foo")));
946 assert_eq!(extractor(&entries[1]), (Some(Domain::APP), Some(42), None));
Joel Galenson33c04ad2020-08-03 11:04:38 -0700947
948 // Test that the second call to rebind_alias also empties the old one.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700949 db.rebind_alias(entries[1].id, "foo", Domain::APP, 42)?;
Joel Galenson33c04ad2020-08-03 11:04:38 -0700950 let entries = get_keyentry(&db)?;
951 assert_eq!(entries.len(), 2);
952 assert_eq!(extractor(&entries[0]), (None, None, None));
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700953 assert_eq!(extractor(&entries[1]), (Some(Domain::APP), Some(42), Some("foo")));
Joel Galenson33c04ad2020-08-03 11:04:38 -0700954
955 // Test that we must pass in a valid Domain.
956 check_result_is_error_containing_string(
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700957 db.rebind_alias(0, "foo", Domain::GRANT, 42),
958 "Domain Domain(1) must be either App or SELinux.",
Joel Galenson33c04ad2020-08-03 11:04:38 -0700959 );
960 check_result_is_error_containing_string(
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700961 db.rebind_alias(0, "foo", Domain::BLOB, 42),
962 "Domain Domain(3) must be either App or SELinux.",
Joel Galenson33c04ad2020-08-03 11:04:38 -0700963 );
964 check_result_is_error_containing_string(
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700965 db.rebind_alias(0, "foo", Domain::KEY_ID, 42),
966 "Domain Domain(4) must be either App or SELinux.",
Joel Galenson33c04ad2020-08-03 11:04:38 -0700967 );
968
969 // Test that we correctly handle setting an alias for something that does not exist.
970 check_result_is_error_containing_string(
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700971 db.rebind_alias(0, "foo", Domain::SELINUX, 42),
Joel Galenson33c04ad2020-08-03 11:04:38 -0700972 "Expected to update a single entry but instead updated 0",
973 );
974 // Test that we correctly abort the transaction in this case.
975 let entries = get_keyentry(&db)?;
976 assert_eq!(entries.len(), 2);
977 assert_eq!(extractor(&entries[0]), (None, None, None));
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700978 assert_eq!(extractor(&entries[1]), (Some(Domain::APP), Some(42), Some("foo")));
Joel Galenson33c04ad2020-08-03 11:04:38 -0700979
980 Ok(())
981 }
982
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700983 #[test]
984 fn test_grant_ungrant() -> Result<()> {
985 const CALLER_UID: u32 = 15;
986 const GRANTEE_UID: u32 = 12;
987 const SELINUX_NAMESPACE: i64 = 7;
988
989 let mut db = new_test_db()?;
990 db.conn.execute(
991 "INSERT INTO persistent.keyentry (id, creation_date, domain, namespace, alias)
992 VALUES (1, '1980', 0, 15, 'key'), (2, '1980', 2, 7, 'yek');",
993 NO_PARAMS,
994 )?;
995 let app_key = KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700996 domain: super::Domain::APP,
997 nspace: 0,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -0700998 alias: Some("key".to_string()),
999 blob: None,
1000 };
1001 const PVEC1: KeyPermSet = key_perm_set![KeyPerm::use_(), KeyPerm::get_info()];
1002 const PVEC2: KeyPermSet = key_perm_set![KeyPerm::use_()];
1003
1004 // Reset totally predictable random number generator in case we
1005 // are not the first test running on this thread.
1006 reset_random();
1007 let next_random = 0i64;
1008
1009 let app_granted_key =
1010 db.grant(app_key.clone(), CALLER_UID, GRANTEE_UID, PVEC1, |k, a| {
1011 assert_eq!(*a, PVEC1);
1012 assert_eq!(
1013 *k,
1014 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001015 domain: super::Domain::APP,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001016 // namespace must be set to the caller_uid.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001017 nspace: CALLER_UID as i64,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001018 alias: Some("key".to_string()),
1019 blob: None,
1020 }
1021 );
1022 Ok(())
1023 })?;
1024
1025 assert_eq!(
1026 app_granted_key,
1027 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001028 domain: super::Domain::GRANT,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001029 // The grantid is next_random due to the mock random number generator.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001030 nspace: next_random,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001031 alias: None,
1032 blob: None,
1033 }
1034 );
1035
1036 let selinux_key = KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001037 domain: super::Domain::SELINUX,
1038 nspace: SELINUX_NAMESPACE,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001039 alias: Some("yek".to_string()),
1040 blob: None,
1041 };
1042
1043 let selinux_granted_key =
1044 db.grant(selinux_key.clone(), CALLER_UID, 12, PVEC1, |k, a| {
1045 assert_eq!(*a, PVEC1);
1046 assert_eq!(
1047 *k,
1048 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001049 domain: super::Domain::SELINUX,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001050 // namespace must be the supplied SELinux
1051 // namespace.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001052 nspace: SELINUX_NAMESPACE,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001053 alias: Some("yek".to_string()),
1054 blob: None,
1055 }
1056 );
1057 Ok(())
1058 })?;
1059
1060 assert_eq!(
1061 selinux_granted_key,
1062 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001063 domain: super::Domain::GRANT,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001064 // The grantid is next_random + 1 due to the mock random number generator.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001065 nspace: next_random + 1,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001066 alias: None,
1067 blob: None,
1068 }
1069 );
1070
1071 // This should update the existing grant with PVEC2.
1072 let selinux_granted_key =
1073 db.grant(selinux_key.clone(), CALLER_UID, 12, PVEC2, |k, a| {
1074 assert_eq!(*a, PVEC2);
1075 assert_eq!(
1076 *k,
1077 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001078 domain: super::Domain::SELINUX,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001079 // namespace must be the supplied SELinux
1080 // namespace.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001081 nspace: SELINUX_NAMESPACE,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001082 alias: Some("yek".to_string()),
1083 blob: None,
1084 }
1085 );
1086 Ok(())
1087 })?;
1088
1089 assert_eq!(
1090 selinux_granted_key,
1091 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001092 domain: super::Domain::GRANT,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001093 // Same grant id as before. The entry was only updated.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001094 nspace: next_random + 1,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001095 alias: None,
1096 blob: None,
1097 }
1098 );
1099
1100 {
1101 // Limiting scope of stmt, because it borrows db.
1102 let mut stmt = db
1103 .conn
1104 .prepare("SELECT id, grantee, keyentryid, access_vector FROM perboot.grant;")?;
Janis Danisevskisee10b5f2020-09-22 16:42:35 -07001105 let mut rows =
1106 stmt.query_map::<(i64, u32, i64, KeyPermSet), _, _>(NO_PARAMS, |row| {
1107 Ok((
1108 row.get(0)?,
1109 row.get(1)?,
1110 row.get(2)?,
1111 KeyPermSet::from(row.get::<_, i32>(3)?),
1112 ))
1113 })?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001114
1115 let r = rows.next().unwrap().unwrap();
Janis Danisevskisee10b5f2020-09-22 16:42:35 -07001116 assert_eq!(r, (next_random, GRANTEE_UID, 1, PVEC1));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001117 let r = rows.next().unwrap().unwrap();
Janis Danisevskisee10b5f2020-09-22 16:42:35 -07001118 assert_eq!(r, (next_random + 1, GRANTEE_UID, 2, PVEC2));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001119 assert!(rows.next().is_none());
1120 }
1121
1122 debug_dump_keyentry_table(&mut db)?;
1123 println!("app_key {:?}", app_key);
1124 println!("selinux_key {:?}", selinux_key);
1125
1126 db.ungrant(app_key, CALLER_UID, GRANTEE_UID, |_| Ok(()))?;
1127 db.ungrant(selinux_key, CALLER_UID, GRANTEE_UID, |_| Ok(()))?;
1128
1129 Ok(())
1130 }
1131
1132 static TEST_KM_BLOB: &[u8] = b"my test blob";
1133 static TEST_CERT_BLOB: &[u8] = b"my test cert";
1134 static TEST_CERT_CHAIN_BLOB: &[u8] = b"my test cert_chain";
1135
1136 #[test]
1137 fn test_insert_blob() -> Result<()> {
1138 let mut db = new_test_db()?;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001139 db.insert_blob(1, SubComponentType::KM_BLOB, TEST_KM_BLOB, SecurityLevel::SOFTWARE)?;
1140 db.insert_blob(
1141 1,
1142 SubComponentType::CERT,
1143 TEST_CERT_BLOB,
1144 SecurityLevel::TRUSTED_ENVIRONMENT,
1145 )?;
1146 db.insert_blob(
1147 1,
1148 SubComponentType::CERT_CHAIN,
1149 TEST_CERT_CHAIN_BLOB,
1150 SecurityLevel::STRONGBOX,
1151 )?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001152
1153 let mut stmt = db.conn.prepare(
1154 "SELECT subcomponent_type, keyentryid, blob, sec_level FROM persistent.blobentry
1155 ORDER BY sec_level ASC;",
1156 )?;
1157 let mut rows = stmt
1158 .query_map::<(SubComponentType, i64, Vec<u8>, i64), _, _>(NO_PARAMS, |row| {
1159 Ok((row.get(0)?, row.get(1)?, row.get(2)?, row.get(3)?))
1160 })?;
1161 let r = rows.next().unwrap().unwrap();
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001162 assert_eq!(r, (SubComponentType::KM_BLOB, 1, TEST_KM_BLOB.to_vec(), 0));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001163 let r = rows.next().unwrap().unwrap();
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001164 assert_eq!(r, (SubComponentType::CERT, 1, TEST_CERT_BLOB.to_vec(), 1));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001165 let r = rows.next().unwrap().unwrap();
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001166 assert_eq!(r, (SubComponentType::CERT_CHAIN, 1, TEST_CERT_CHAIN_BLOB.to_vec(), 2));
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001167
1168 Ok(())
1169 }
1170
1171 static TEST_ALIAS: &str = "my super duper key";
1172
1173 #[test]
1174 fn test_insert_and_load_full_keyentry_domain_app() -> Result<()> {
1175 let mut db = new_test_db()?;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001176 let key_id = make_test_key_entry(&mut db, Domain::APP, 1, TEST_ALIAS)
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001177 .context("test_insert_and_load_full_keyentry_domain_app")?;
1178 let key_entry = db.load_key_entry(
1179 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001180 domain: Domain::APP,
1181 nspace: 0,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001182 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()),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001196 sec_level: SecurityLevel::TRUSTED_ENVIRONMENT,
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_selinux() -> Result<()> {
1205 let mut db = new_test_db()?;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001206 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS)
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001207 .context("test_insert_and_load_full_keyentry_domain_selinux")?;
1208 let key_entry = db.load_key_entry(
1209 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001210 domain: Domain::SELINUX,
1211 nspace: 1,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001212 alias: Some(TEST_ALIAS.to_string()),
1213 blob: None,
1214 },
1215 KeyEntryLoadBits::BOTH,
1216 1,
1217 |_k, _av| Ok(()),
1218 )?;
1219 assert_eq!(
1220 key_entry,
1221 KeyEntry {
1222 id: key_id,
1223 km_blob: Some(TEST_KM_BLOB.to_vec()),
1224 cert: Some(TEST_CERT_BLOB.to_vec()),
1225 cert_chain: Some(TEST_CERT_CHAIN_BLOB.to_vec()),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001226 sec_level: SecurityLevel::TRUSTED_ENVIRONMENT,
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001227 parameters: make_test_params()
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001228 }
1229 );
1230 Ok(())
1231 }
1232
1233 #[test]
1234 fn test_insert_and_load_full_keyentry_domain_key_id() -> Result<()> {
1235 let mut db = new_test_db()?;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001236 let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS)
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001237 .context("test_insert_and_load_full_keyentry_domain_key_id")?;
1238 let key_entry = db.load_key_entry(
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001239 KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001240 KeyEntryLoadBits::BOTH,
1241 1,
1242 |_k, _av| Ok(()),
1243 )?;
1244 assert_eq!(
1245 key_entry,
1246 KeyEntry {
1247 id: key_id,
1248 km_blob: Some(TEST_KM_BLOB.to_vec()),
1249 cert: Some(TEST_CERT_BLOB.to_vec()),
1250 cert_chain: Some(TEST_CERT_CHAIN_BLOB.to_vec()),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001251 sec_level: SecurityLevel::TRUSTED_ENVIRONMENT,
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001252 parameters: make_test_params()
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001253 }
1254 );
1255
1256 Ok(())
1257 }
1258
1259 #[test]
1260 fn test_insert_and_load_full_keyentry_from_grant() -> Result<()> {
1261 let mut db = new_test_db()?;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001262 let key_id = make_test_key_entry(&mut db, Domain::APP, 1, TEST_ALIAS)
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001263 .context("test_insert_and_load_full_keyentry_from_grant")?;
1264
1265 let granted_key = db.grant(
1266 KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001267 domain: Domain::APP,
1268 nspace: 0,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001269 alias: Some(TEST_ALIAS.to_string()),
1270 blob: None,
1271 },
1272 1,
1273 2,
1274 key_perm_set![KeyPerm::use_()],
1275 |_k, _av| Ok(()),
1276 )?;
1277
1278 debug_dump_grant_table(&mut db)?;
1279
1280 let key_entry = db.load_key_entry(granted_key, KeyEntryLoadBits::BOTH, 2, |k, av| {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001281 assert_eq!(Domain::GRANT, k.domain);
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001282 assert!(av.unwrap().includes(KeyPerm::use_()));
1283 Ok(())
1284 })?;
1285
1286 assert_eq!(
1287 key_entry,
1288 KeyEntry {
1289 id: key_id,
1290 km_blob: Some(TEST_KM_BLOB.to_vec()),
1291 cert: Some(TEST_CERT_BLOB.to_vec()),
1292 cert_chain: Some(TEST_CERT_CHAIN_BLOB.to_vec()),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001293 sec_level: SecurityLevel::TRUSTED_ENVIRONMENT,
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001294 parameters: make_test_params()
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001295 }
1296 );
1297 Ok(())
1298 }
1299
Joel Galenson0891bc12020-07-20 10:37:03 -07001300 // Helpers
1301
1302 // Checks that the given result is an error containing the given string.
1303 fn check_result_is_error_containing_string<T>(result: Result<T>, target: &str) {
1304 let error_str = format!(
1305 "{:#?}",
1306 result.err().unwrap_or_else(|| panic!("Expected the error: {}", target))
1307 );
1308 assert!(
1309 error_str.contains(target),
1310 "The string \"{}\" should contain \"{}\"",
1311 error_str,
1312 target
1313 );
1314 }
1315
Joel Galenson2aab4432020-07-22 15:27:57 -07001316 #[derive(Debug, PartialEq)]
Joel Galenson0891bc12020-07-20 10:37:03 -07001317 #[allow(dead_code)]
1318 struct KeyEntryRow {
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001319 id: i64,
Joel Galenson0891bc12020-07-20 10:37:03 -07001320 creation_date: String,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001321 domain: Option<Domain>,
Joel Galenson0891bc12020-07-20 10:37:03 -07001322 namespace: Option<i64>,
1323 alias: Option<String>,
1324 }
1325
1326 fn get_keyentry(db: &KeystoreDB) -> Result<Vec<KeyEntryRow>> {
1327 db.conn
Joel Galenson2aab4432020-07-22 15:27:57 -07001328 .prepare("SELECT * FROM persistent.keyentry;")?
Joel Galenson0891bc12020-07-20 10:37:03 -07001329 .query_map(NO_PARAMS, |row| {
Joel Galenson0891bc12020-07-20 10:37:03 -07001330 Ok(KeyEntryRow {
1331 id: row.get(0)?,
1332 creation_date: row.get(1)?,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001333 domain: match row.get(2)? {
1334 Some(i) => Some(Domain(i)),
1335 None => None,
1336 },
Joel Galenson0891bc12020-07-20 10:37:03 -07001337 namespace: row.get(3)?,
1338 alias: row.get(4)?,
1339 })
1340 })?
1341 .map(|r| r.context("Could not read keyentry row."))
1342 .collect::<Result<Vec<_>>>()
1343 }
1344
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001345 // Note: The parameters and SecurityLevel associations are nonsensical. This
1346 // collection is only used to check if the parameters are preserved as expected by the
1347 // database.
1348 fn make_test_params() -> Vec<KeyParameter> {
1349 vec![
1350 KeyParameter::new(KeyParameterValue::Invalid, SecurityLevel::TRUSTED_ENVIRONMENT),
1351 KeyParameter::new(
1352 KeyParameterValue::KeyPurpose(KeyPurpose::SIGN),
1353 SecurityLevel::TRUSTED_ENVIRONMENT,
1354 ),
1355 KeyParameter::new(
1356 KeyParameterValue::KeyPurpose(KeyPurpose::DECRYPT),
1357 SecurityLevel::TRUSTED_ENVIRONMENT,
1358 ),
1359 KeyParameter::new(
1360 KeyParameterValue::Algorithm(Algorithm::RSA),
1361 SecurityLevel::TRUSTED_ENVIRONMENT,
1362 ),
1363 KeyParameter::new(KeyParameterValue::KeySize(1024), SecurityLevel::TRUSTED_ENVIRONMENT),
1364 KeyParameter::new(
1365 KeyParameterValue::BlockMode(BlockMode::ECB),
1366 SecurityLevel::TRUSTED_ENVIRONMENT,
1367 ),
1368 KeyParameter::new(
1369 KeyParameterValue::BlockMode(BlockMode::GCM),
1370 SecurityLevel::TRUSTED_ENVIRONMENT,
1371 ),
1372 KeyParameter::new(KeyParameterValue::Digest(Digest::NONE), SecurityLevel::STRONGBOX),
1373 KeyParameter::new(
1374 KeyParameterValue::Digest(Digest::MD5),
1375 SecurityLevel::TRUSTED_ENVIRONMENT,
1376 ),
1377 KeyParameter::new(
1378 KeyParameterValue::Digest(Digest::SHA_2_224),
1379 SecurityLevel::TRUSTED_ENVIRONMENT,
1380 ),
1381 KeyParameter::new(
1382 KeyParameterValue::Digest(Digest::SHA_2_256),
1383 SecurityLevel::STRONGBOX,
1384 ),
1385 KeyParameter::new(
1386 KeyParameterValue::PaddingMode(PaddingMode::NONE),
1387 SecurityLevel::TRUSTED_ENVIRONMENT,
1388 ),
1389 KeyParameter::new(
1390 KeyParameterValue::PaddingMode(PaddingMode::RSA_OAEP),
1391 SecurityLevel::TRUSTED_ENVIRONMENT,
1392 ),
1393 KeyParameter::new(
1394 KeyParameterValue::PaddingMode(PaddingMode::RSA_PSS),
1395 SecurityLevel::STRONGBOX,
1396 ),
1397 KeyParameter::new(
1398 KeyParameterValue::PaddingMode(PaddingMode::RSA_PKCS1_1_5_SIGN),
1399 SecurityLevel::TRUSTED_ENVIRONMENT,
1400 ),
1401 KeyParameter::new(KeyParameterValue::CallerNonce, SecurityLevel::TRUSTED_ENVIRONMENT),
1402 KeyParameter::new(KeyParameterValue::MinMacLength(256), SecurityLevel::STRONGBOX),
1403 KeyParameter::new(
1404 KeyParameterValue::EcCurve(EcCurve::P_224),
1405 SecurityLevel::TRUSTED_ENVIRONMENT,
1406 ),
1407 KeyParameter::new(KeyParameterValue::EcCurve(EcCurve::P_256), SecurityLevel::STRONGBOX),
1408 KeyParameter::new(
1409 KeyParameterValue::EcCurve(EcCurve::P_384),
1410 SecurityLevel::TRUSTED_ENVIRONMENT,
1411 ),
1412 KeyParameter::new(
1413 KeyParameterValue::EcCurve(EcCurve::P_521),
1414 SecurityLevel::TRUSTED_ENVIRONMENT,
1415 ),
1416 KeyParameter::new(
1417 KeyParameterValue::RSAPublicExponent(3),
1418 SecurityLevel::TRUSTED_ENVIRONMENT,
1419 ),
1420 KeyParameter::new(
1421 KeyParameterValue::IncludeUniqueID,
1422 SecurityLevel::TRUSTED_ENVIRONMENT,
1423 ),
1424 KeyParameter::new(KeyParameterValue::BootLoaderOnly, SecurityLevel::STRONGBOX),
1425 KeyParameter::new(KeyParameterValue::RollbackResistance, SecurityLevel::STRONGBOX),
1426 KeyParameter::new(
1427 KeyParameterValue::ActiveDateTime(1234567890),
1428 SecurityLevel::STRONGBOX,
1429 ),
1430 KeyParameter::new(
1431 KeyParameterValue::OriginationExpireDateTime(1234567890),
1432 SecurityLevel::TRUSTED_ENVIRONMENT,
1433 ),
1434 KeyParameter::new(
1435 KeyParameterValue::UsageExpireDateTime(1234567890),
1436 SecurityLevel::TRUSTED_ENVIRONMENT,
1437 ),
1438 KeyParameter::new(
1439 KeyParameterValue::MinSecondsBetweenOps(1234567890),
1440 SecurityLevel::TRUSTED_ENVIRONMENT,
1441 ),
1442 KeyParameter::new(
1443 KeyParameterValue::MaxUsesPerBoot(1234567890),
1444 SecurityLevel::TRUSTED_ENVIRONMENT,
1445 ),
1446 KeyParameter::new(KeyParameterValue::UserID(1), SecurityLevel::STRONGBOX),
1447 KeyParameter::new(KeyParameterValue::UserSecureID(42), SecurityLevel::STRONGBOX),
1448 KeyParameter::new(
1449 KeyParameterValue::NoAuthRequired,
1450 SecurityLevel::TRUSTED_ENVIRONMENT,
1451 ),
1452 KeyParameter::new(
1453 KeyParameterValue::HardwareAuthenticatorType(HardwareAuthenticatorType::PASSWORD),
1454 SecurityLevel::TRUSTED_ENVIRONMENT,
1455 ),
1456 KeyParameter::new(KeyParameterValue::AuthTimeout(1234567890), SecurityLevel::SOFTWARE),
1457 KeyParameter::new(KeyParameterValue::AllowWhileOnBody, SecurityLevel::SOFTWARE),
1458 KeyParameter::new(
1459 KeyParameterValue::TrustedUserPresenceRequired,
1460 SecurityLevel::TRUSTED_ENVIRONMENT,
1461 ),
1462 KeyParameter::new(
1463 KeyParameterValue::TrustedConfirmationRequired,
1464 SecurityLevel::TRUSTED_ENVIRONMENT,
1465 ),
1466 KeyParameter::new(
1467 KeyParameterValue::UnlockedDeviceRequired,
1468 SecurityLevel::TRUSTED_ENVIRONMENT,
1469 ),
1470 KeyParameter::new(
1471 KeyParameterValue::ApplicationID(vec![1u8, 2u8, 3u8, 4u8]),
1472 SecurityLevel::SOFTWARE,
1473 ),
1474 KeyParameter::new(
1475 KeyParameterValue::ApplicationData(vec![4u8, 3u8, 2u8, 1u8]),
1476 SecurityLevel::SOFTWARE,
1477 ),
1478 KeyParameter::new(
1479 KeyParameterValue::CreationDateTime(12345677890),
1480 SecurityLevel::SOFTWARE,
1481 ),
1482 KeyParameter::new(
1483 KeyParameterValue::KeyOrigin(KeyOrigin::GENERATED),
1484 SecurityLevel::TRUSTED_ENVIRONMENT,
1485 ),
1486 KeyParameter::new(
1487 KeyParameterValue::RootOfTrust(vec![3u8, 2u8, 1u8, 4u8]),
1488 SecurityLevel::TRUSTED_ENVIRONMENT,
1489 ),
1490 KeyParameter::new(KeyParameterValue::OSVersion(1), SecurityLevel::TRUSTED_ENVIRONMENT),
1491 KeyParameter::new(KeyParameterValue::OSPatchLevel(2), SecurityLevel::SOFTWARE),
1492 KeyParameter::new(
1493 KeyParameterValue::UniqueID(vec![4u8, 3u8, 1u8, 2u8]),
1494 SecurityLevel::SOFTWARE,
1495 ),
1496 KeyParameter::new(
1497 KeyParameterValue::AttestationChallenge(vec![4u8, 3u8, 1u8, 2u8]),
1498 SecurityLevel::TRUSTED_ENVIRONMENT,
1499 ),
1500 KeyParameter::new(
1501 KeyParameterValue::AttestationApplicationID(vec![4u8, 3u8, 1u8, 2u8]),
1502 SecurityLevel::TRUSTED_ENVIRONMENT,
1503 ),
1504 KeyParameter::new(
1505 KeyParameterValue::AttestationIdBrand(vec![4u8, 3u8, 1u8, 2u8]),
1506 SecurityLevel::TRUSTED_ENVIRONMENT,
1507 ),
1508 KeyParameter::new(
1509 KeyParameterValue::AttestationIdDevice(vec![4u8, 3u8, 1u8, 2u8]),
1510 SecurityLevel::TRUSTED_ENVIRONMENT,
1511 ),
1512 KeyParameter::new(
1513 KeyParameterValue::AttestationIdProduct(vec![4u8, 3u8, 1u8, 2u8]),
1514 SecurityLevel::TRUSTED_ENVIRONMENT,
1515 ),
1516 KeyParameter::new(
1517 KeyParameterValue::AttestationIdSerial(vec![4u8, 3u8, 1u8, 2u8]),
1518 SecurityLevel::TRUSTED_ENVIRONMENT,
1519 ),
1520 KeyParameter::new(
1521 KeyParameterValue::AttestationIdIMEI(vec![4u8, 3u8, 1u8, 2u8]),
1522 SecurityLevel::TRUSTED_ENVIRONMENT,
1523 ),
1524 KeyParameter::new(
1525 KeyParameterValue::AttestationIdMEID(vec![4u8, 3u8, 1u8, 2u8]),
1526 SecurityLevel::TRUSTED_ENVIRONMENT,
1527 ),
1528 KeyParameter::new(
1529 KeyParameterValue::AttestationIdManufacturer(vec![4u8, 3u8, 1u8, 2u8]),
1530 SecurityLevel::TRUSTED_ENVIRONMENT,
1531 ),
1532 KeyParameter::new(
1533 KeyParameterValue::AttestationIdModel(vec![4u8, 3u8, 1u8, 2u8]),
1534 SecurityLevel::TRUSTED_ENVIRONMENT,
1535 ),
1536 KeyParameter::new(
1537 KeyParameterValue::VendorPatchLevel(3),
1538 SecurityLevel::TRUSTED_ENVIRONMENT,
1539 ),
1540 KeyParameter::new(
1541 KeyParameterValue::BootPatchLevel(4),
1542 SecurityLevel::TRUSTED_ENVIRONMENT,
1543 ),
1544 KeyParameter::new(
1545 KeyParameterValue::AssociatedData(vec![4u8, 3u8, 1u8, 2u8]),
1546 SecurityLevel::TRUSTED_ENVIRONMENT,
1547 ),
1548 KeyParameter::new(
1549 KeyParameterValue::Nonce(vec![4u8, 3u8, 1u8, 2u8]),
1550 SecurityLevel::TRUSTED_ENVIRONMENT,
1551 ),
1552 KeyParameter::new(
1553 KeyParameterValue::MacLength(256),
1554 SecurityLevel::TRUSTED_ENVIRONMENT,
1555 ),
1556 KeyParameter::new(
1557 KeyParameterValue::ResetSinceIdRotation,
1558 SecurityLevel::TRUSTED_ENVIRONMENT,
1559 ),
1560 KeyParameter::new(
1561 KeyParameterValue::ConfirmationToken(vec![5u8, 5u8, 5u8, 5u8]),
1562 SecurityLevel::TRUSTED_ENVIRONMENT,
1563 ),
1564 ]
1565 }
1566
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001567 fn make_test_key_entry(
1568 db: &mut KeystoreDB,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001569 domain: Domain,
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001570 namespace: i64,
1571 alias: &str,
1572 ) -> Result<i64> {
1573 let key_id = db.create_key_entry(domain, namespace)?;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001574 db.insert_blob(
1575 key_id,
1576 SubComponentType::KM_BLOB,
1577 TEST_KM_BLOB,
1578 SecurityLevel::TRUSTED_ENVIRONMENT,
1579 )?;
1580 db.insert_blob(
1581 key_id,
1582 SubComponentType::CERT,
1583 TEST_CERT_BLOB,
1584 SecurityLevel::TRUSTED_ENVIRONMENT,
1585 )?;
1586 db.insert_blob(
1587 key_id,
1588 SubComponentType::CERT_CHAIN,
1589 TEST_CERT_CHAIN_BLOB,
1590 SecurityLevel::TRUSTED_ENVIRONMENT,
1591 )?;
Janis Danisevskis3f322cb2020-09-03 14:46:22 -07001592 db.insert_keyparameter(key_id, &make_test_params())?;
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001593 db.rebind_alias(key_id, alias, domain, namespace)?;
1594 Ok(key_id)
1595 }
1596
1597 fn debug_dump_keyentry_table(db: &mut KeystoreDB) -> Result<()> {
1598 let mut stmt = db.conn.prepare(
1599 "SELECT id, creation_date, domain, namespace, alias FROM persistent.keyentry;",
1600 )?;
1601 let rows = stmt.query_map::<(i64, i64, i32, i64, String), _, _>(NO_PARAMS, |row| {
1602 Ok((row.get(0)?, row.get(1)?, row.get(2)?, row.get(3)?, row.get(4)?))
1603 })?;
1604
1605 println!("Key entry table rows:");
1606 for r in rows {
1607 let (id, cdate, domain, namespace, alias) = r.unwrap();
1608 println!(
1609 " id: {} Creation date: {} Domain: {} Namespace: {} Alias: {}",
1610 id, cdate, domain, namespace, alias
1611 );
1612 }
1613 Ok(())
1614 }
1615
1616 fn debug_dump_grant_table(db: &mut KeystoreDB) -> Result<()> {
1617 let mut stmt =
1618 db.conn.prepare("SELECT id, grantee, keyentryid, access_vector FROM perboot.grant;")?;
1619 let rows = stmt.query_map::<(i64, i64, i64, i64), _, _>(NO_PARAMS, |row| {
1620 Ok((row.get(0)?, row.get(1)?, row.get(2)?, row.get(3)?))
1621 })?;
1622
1623 println!("Grant table rows:");
1624 for r in rows {
1625 let (id, gt, ki, av) = r.unwrap();
1626 println!(" id: {} grantee: {} key_id: {} access_vector: {}", id, gt, ki, av);
1627 }
1628 Ok(())
1629 }
1630
Joel Galenson2aab4432020-07-22 15:27:57 -07001631 // A class that deletes a file when it is dropped.
1632 // TODO: If we ever add a crate that does this, we can use it instead.
1633 struct TempFile {
1634 filename: &'static str,
1635 }
1636
1637 impl Drop for TempFile {
1638 fn drop(&mut self) {
1639 std::fs::remove_file(self.filename).expect("Cannot delete temporary file");
1640 }
1641 }
1642
Joel Galenson0891bc12020-07-20 10:37:03 -07001643 // Use a custom random number generator that repeats each number once.
1644 // This allows us to test repeated elements.
1645
1646 thread_local! {
1647 static RANDOM_COUNTER: RefCell<i64> = RefCell::new(0);
1648 }
1649
Janis Danisevskis63f7bc82020-09-03 10:12:56 -07001650 fn reset_random() {
1651 RANDOM_COUNTER.with(|counter| {
1652 *counter.borrow_mut() = 0;
1653 })
1654 }
1655
Joel Galenson0891bc12020-07-20 10:37:03 -07001656 pub fn random() -> i64 {
1657 RANDOM_COUNTER.with(|counter| {
1658 let result = *counter.borrow() / 2;
1659 *counter.borrow_mut() += 1;
1660 result
1661 })
1662 }
Joel Galenson26f4d012020-07-17 14:57:21 -07001663}