blob: 7ceff26eab56d0892c6c3aff2914362d32b49af6 [file] [log] [blame]
Janis Danisevskisa75e2082020-10-07 16:44:26 -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
15//! This module holds global state of Keystore such as the thread local
16//! database connections and connections to services that Keystore needs
17//! to talk to.
18
Janis Danisevskis93927dd2020-12-23 12:23:08 -080019use crate::async_task::AsyncTask;
Hasini Gunasinghef04d07a2020-11-25 22:41:35 +000020use crate::background_task_handler::BackgroundTaskHandler;
Hasini Gunasinghe888dd352020-11-17 23:08:39 +000021use crate::enforcements::Enforcements;
Janis Danisevskis93927dd2020-12-23 12:23:08 -080022use crate::gc::Gc;
Hasini Gunasinghea020b532021-01-07 21:42:35 +000023use crate::legacy_blob::LegacyBlobLoader;
Janis Danisevskisb42fc182020-12-15 08:41:27 -080024use crate::super_key::SuperKeyManager;
Janis Danisevskisba998992020-12-29 16:08:40 -080025use crate::utils::Asp;
26use crate::{
27 database::KeystoreDB,
Janis Danisevskis8c6378e2021-01-01 09:30:37 -080028 error::{map_binder_status, map_binder_status_code, Error, ErrorCode},
Janis Danisevskisba998992020-12-29 16:08:40 -080029};
Janis Danisevskis8c6378e2021-01-01 09:30:37 -080030use android_hardware_security_keymint::aidl::android::hardware::security::keymint::SecurityLevel::SecurityLevel;
31use android_hardware_security_keymint::binder::StatusCode;
32use android_security_compat::aidl::android::security::compat::IKeystoreCompatService::IKeystoreCompatService;
Janis Danisevskisba998992020-12-29 16:08:40 -080033use anyhow::{Context, Result};
Janis Danisevskisb42fc182020-12-15 08:41:27 -080034use lazy_static::lazy_static;
Janis Danisevskisba998992020-12-29 16:08:40 -080035use std::collections::HashMap;
36use std::sync::Mutex;
Janis Danisevskis93927dd2020-12-23 12:23:08 -080037use std::{cell::RefCell, sync::Once};
38
39static DB_INIT: Once = Once::new();
40
41/// Open a connection to the Keystore 2.0 database. This is called during the initialization of
42/// the thread local DB field. It should never be called directly. The first time this is called
43/// we also call KeystoreDB::cleanup_leftovers to restore the key lifecycle invariant. See the
44/// documentation of cleanup_leftovers for more details.
45fn create_thread_local_db() -> KeystoreDB {
46 let mut db = KeystoreDB::new(
47 // Keystore changes to the database directory on startup
48 // (see keystore2_main.rs).
49 &std::env::current_dir().expect("Could not get the current working directory."),
50 )
51 .expect("Failed to open database.");
52 DB_INIT.call_once(|| {
53 log::info!("Touching Keystore 2.0 database for this first time since boot.");
54 log::info!("Calling cleanup leftovers.");
55 let n = db.cleanup_leftovers().expect("Failed to cleanup database on startup.");
56 if n != 0 {
57 log::info!(
58 concat!(
59 "Cleaned up {} failed entries. ",
60 "This indicates keystore crashed during key generation."
61 ),
62 n
63 );
64 }
65 Gc::notify_gc();
66 });
67 db
68}
Janis Danisevskisa75e2082020-10-07 16:44:26 -070069
70thread_local! {
71 /// Database connections are not thread safe, but connecting to the
72 /// same database multiple times is safe as long as each connection is
73 /// used by only one thread. So we store one database connection per
74 /// thread in this thread local key.
75 pub static DB: RefCell<KeystoreDB> =
Janis Danisevskis93927dd2020-12-23 12:23:08 -080076 RefCell::new(create_thread_local_db());
Janis Danisevskisa75e2082020-10-07 16:44:26 -070077}
Janis Danisevskisb42fc182020-12-15 08:41:27 -080078
79lazy_static! {
80 /// Runtime database of unwrapped super keys.
81 pub static ref SUPER_KEY: SuperKeyManager = Default::default();
Janis Danisevskisba998992020-12-29 16:08:40 -080082 /// Map of KeyMint devices.
83 static ref KEY_MINT_DEVICES: Mutex<HashMap<SecurityLevel, Asp>> = Default::default();
Janis Danisevskisc3a496b2021-01-05 10:37:22 -080084 /// Timestamp service.
85 static ref TIME_STAMP_DEVICE: Mutex<Option<Asp>> = Default::default();
Janis Danisevskis93927dd2020-12-23 12:23:08 -080086 /// A single on-demand worker thread that handles deferred tasks with two different
87 /// priorities.
88 pub static ref ASYNC_TASK: AsyncTask = Default::default();
Hasini Gunasinghe888dd352020-11-17 23:08:39 +000089 /// Singeleton for enforcements.
Hasini Gunasinghe888dd352020-11-17 23:08:39 +000090 pub static ref ENFORCEMENTS: Enforcements = Enforcements::new();
Hasini Gunasinghef04d07a2020-11-25 22:41:35 +000091 /// Background task handler is initialized and exists globally.
92 /// The other modules (e.g. enforcements) communicate with it via a channel initialized during
93 /// keystore startup.
94 pub static ref BACKGROUND_TASK_HANDLER: BackgroundTaskHandler = BackgroundTaskHandler::new();
Hasini Gunasinghea020b532021-01-07 21:42:35 +000095 /// LegacyBlobLoader is initialized and exists globally.
96 /// The same directory used by the database is used by the LegacyBlobLoader as well.
97 pub static ref LEGACY_BLOB_LOADER: LegacyBlobLoader = LegacyBlobLoader::new(
98 &std::env::current_dir().expect("Could not get the current working directory."));
Janis Danisevskisba998992020-12-29 16:08:40 -080099}
100
101static KEYMINT_SERVICE_NAME: &str = "android.hardware.security.keymint.IKeyMintDevice";
102
103/// Make a new connection to a KeyMint device of the given security level.
Janis Danisevskis8c6378e2021-01-01 09:30:37 -0800104/// If no native KeyMint device can be found this function also brings
105/// up the compatibility service and attempts to connect to the legacy wrapper.
Janis Danisevskisba998992020-12-29 16:08:40 -0800106fn connect_keymint(security_level: SecurityLevel) -> Result<Asp> {
107 let service_name = match security_level {
108 SecurityLevel::TRUSTED_ENVIRONMENT => format!("{}/default", KEYMINT_SERVICE_NAME),
109 SecurityLevel::STRONGBOX => format!("{}/strongbox", KEYMINT_SERVICE_NAME),
110 _ => {
111 return Err(Error::Km(ErrorCode::HARDWARE_TYPE_UNAVAILABLE))
112 .context("In connect_keymint.")
113 }
114 };
115
Janis Danisevskis8c6378e2021-01-01 09:30:37 -0800116 let keymint = map_binder_status_code(binder::get_interface(&service_name))
117 .context("In connect_keymint: Trying to connect to genuine KeyMint service.")
118 .or_else(|e| {
119 match e.root_cause().downcast_ref::<Error>() {
120 Some(Error::BinderTransaction(StatusCode::NAME_NOT_FOUND)) => {
121 // This is a no-op if it was called before.
122 keystore2_km_compat::add_keymint_device_service();
123
124 let keystore_compat_service: Box<dyn IKeystoreCompatService> =
125 map_binder_status_code(binder::get_interface("android.security.compat"))
126 .context("In connect_keymint: Trying to connect to compat service.")?;
127 map_binder_status(keystore_compat_service.getKeyMintDevice(security_level))
128 .map_err(|e| match e {
129 Error::BinderTransaction(StatusCode::NAME_NOT_FOUND) => {
130 Error::Km(ErrorCode::HARDWARE_TYPE_UNAVAILABLE)
131 }
132 e => e,
133 })
134 .context("In connext_keymint: Trying to get Legacy wrapper.")
135 }
136 _ => Err(e),
137 }
138 })?;
Janis Danisevskisba998992020-12-29 16:08:40 -0800139
140 Ok(Asp::new(keymint.as_binder()))
141}
142
143/// Get a keymint device for the given security level either from our cache or
144/// by making a new connection.
145pub fn get_keymint_device(security_level: SecurityLevel) -> Result<Asp> {
146 let mut devices_map = KEY_MINT_DEVICES.lock().unwrap();
147 if let Some(dev) = devices_map.get(&security_level) {
148 Ok(dev.clone())
149 } else {
Janis Danisevskisc3a496b2021-01-05 10:37:22 -0800150 let dev = connect_keymint(security_level).context("In get_keymint_device.")?;
Janis Danisevskisba998992020-12-29 16:08:40 -0800151 devices_map.insert(security_level, dev.clone());
152 Ok(dev)
153 }
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800154}
Janis Danisevskisc3a496b2021-01-05 10:37:22 -0800155
156static TIME_STAMP_SERVICE_NAME: &str = "android.hardware.security.secureclock.ISecureClock";
157
158/// Make a new connection to a secure clock service.
159/// If no native SecureClock device can be found brings up the compatibility service and attempts
160/// to connect to the legacy wrapper.
161fn connect_secureclock() -> Result<Asp> {
162 let secureclock = map_binder_status_code(binder::get_interface(TIME_STAMP_SERVICE_NAME))
163 .context("In connect_secureclock: Trying to connect to genuine secure clock service.")
164 .or_else(|e| {
165 match e.root_cause().downcast_ref::<Error>() {
166 Some(Error::BinderTransaction(StatusCode::NAME_NOT_FOUND)) => {
167 // This is a no-op if it was called before.
168 keystore2_km_compat::add_keymint_device_service();
169
170 let keystore_compat_service: Box<dyn IKeystoreCompatService> =
171 map_binder_status_code(binder::get_interface("android.security.compat"))
172 .context(
173 "In connect_secureclock: Trying to connect to compat service.",
174 )?;
175
176 // Legacy secure clock services were only implemented by TEE.
177 map_binder_status(keystore_compat_service.getSecureClock())
178 .map_err(|e| match e {
179 Error::BinderTransaction(StatusCode::NAME_NOT_FOUND) => {
180 Error::Km(ErrorCode::HARDWARE_TYPE_UNAVAILABLE)
181 }
182 e => e,
183 })
184 .context("In connect_secureclock: Trying to get Legacy wrapper.")
185 }
186 _ => Err(e),
187 }
188 })?;
189
190 Ok(Asp::new(secureclock.as_binder()))
191}
192
193/// Get the timestamp service that verifies auth token timeliness towards security levels with
194/// different clocks.
195pub fn get_timestamp_service() -> Result<Asp> {
196 let mut ts_device = TIME_STAMP_DEVICE.lock().unwrap();
197 if let Some(dev) = &*ts_device {
198 Ok(dev.clone())
199 } else {
200 let dev = connect_secureclock().context("In get_timestamp_service.")?;
201 *ts_device = Some(dev.clone());
202 Ok(dev)
203 }
204}