blob: 075a8014252701c3ebb08b0fad1662eade41e9a6 [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 Gunasinghe888dd352020-11-17 23:08:39 +000020use crate::enforcements::Enforcements;
Janis Danisevskis93927dd2020-12-23 12:23:08 -080021use crate::gc::Gc;
Janis Danisevskisb42fc182020-12-15 08:41:27 -080022use crate::super_key::SuperKeyManager;
Janis Danisevskisba998992020-12-29 16:08:40 -080023use crate::utils::Asp;
24use crate::{
25 database::KeystoreDB,
Janis Danisevskis8c6378e2021-01-01 09:30:37 -080026 error::{map_binder_status, map_binder_status_code, Error, ErrorCode},
Janis Danisevskisba998992020-12-29 16:08:40 -080027};
Janis Danisevskis8c6378e2021-01-01 09:30:37 -080028use android_hardware_security_keymint::aidl::android::hardware::security::keymint::SecurityLevel::SecurityLevel;
29use android_hardware_security_keymint::binder::StatusCode;
30use android_security_compat::aidl::android::security::compat::IKeystoreCompatService::IKeystoreCompatService;
Janis Danisevskisba998992020-12-29 16:08:40 -080031use anyhow::{Context, Result};
Janis Danisevskisb42fc182020-12-15 08:41:27 -080032use lazy_static::lazy_static;
Janis Danisevskisba998992020-12-29 16:08:40 -080033use std::collections::HashMap;
34use std::sync::Mutex;
Janis Danisevskis93927dd2020-12-23 12:23:08 -080035use std::{cell::RefCell, sync::Once};
36
37static DB_INIT: Once = Once::new();
38
39/// Open a connection to the Keystore 2.0 database. This is called during the initialization of
40/// the thread local DB field. It should never be called directly. The first time this is called
41/// we also call KeystoreDB::cleanup_leftovers to restore the key lifecycle invariant. See the
42/// documentation of cleanup_leftovers for more details.
43fn create_thread_local_db() -> KeystoreDB {
44 let mut db = KeystoreDB::new(
45 // Keystore changes to the database directory on startup
46 // (see keystore2_main.rs).
47 &std::env::current_dir().expect("Could not get the current working directory."),
48 )
49 .expect("Failed to open database.");
50 DB_INIT.call_once(|| {
51 log::info!("Touching Keystore 2.0 database for this first time since boot.");
52 log::info!("Calling cleanup leftovers.");
53 let n = db.cleanup_leftovers().expect("Failed to cleanup database on startup.");
54 if n != 0 {
55 log::info!(
56 concat!(
57 "Cleaned up {} failed entries. ",
58 "This indicates keystore crashed during key generation."
59 ),
60 n
61 );
62 }
63 Gc::notify_gc();
64 });
65 db
66}
Janis Danisevskisa75e2082020-10-07 16:44:26 -070067
68thread_local! {
69 /// Database connections are not thread safe, but connecting to the
70 /// same database multiple times is safe as long as each connection is
71 /// used by only one thread. So we store one database connection per
72 /// thread in this thread local key.
73 pub static DB: RefCell<KeystoreDB> =
Janis Danisevskis93927dd2020-12-23 12:23:08 -080074 RefCell::new(create_thread_local_db());
Janis Danisevskisa75e2082020-10-07 16:44:26 -070075}
Janis Danisevskisb42fc182020-12-15 08:41:27 -080076
77lazy_static! {
78 /// Runtime database of unwrapped super keys.
79 pub static ref SUPER_KEY: SuperKeyManager = Default::default();
Janis Danisevskisba998992020-12-29 16:08:40 -080080 /// Map of KeyMint devices.
81 static ref KEY_MINT_DEVICES: Mutex<HashMap<SecurityLevel, Asp>> = Default::default();
Janis Danisevskis93927dd2020-12-23 12:23:08 -080082 /// A single on-demand worker thread that handles deferred tasks with two different
83 /// priorities.
84 pub static ref ASYNC_TASK: AsyncTask = Default::default();
Hasini Gunasinghe888dd352020-11-17 23:08:39 +000085 /// Singeleton for enforcements.
86 /// It is safe for this enforcements object to be called by multiple threads because the two
87 /// data structures which maintain its state are protected by mutexes.
88 pub static ref ENFORCEMENTS: Enforcements = Enforcements::new();
Janis Danisevskisba998992020-12-29 16:08:40 -080089}
90
91static KEYMINT_SERVICE_NAME: &str = "android.hardware.security.keymint.IKeyMintDevice";
92
93/// Make a new connection to a KeyMint device of the given security level.
Janis Danisevskis8c6378e2021-01-01 09:30:37 -080094/// If no native KeyMint device can be found this function also brings
95/// up the compatibility service and attempts to connect to the legacy wrapper.
Janis Danisevskisba998992020-12-29 16:08:40 -080096fn connect_keymint(security_level: SecurityLevel) -> Result<Asp> {
97 let service_name = match security_level {
98 SecurityLevel::TRUSTED_ENVIRONMENT => format!("{}/default", KEYMINT_SERVICE_NAME),
99 SecurityLevel::STRONGBOX => format!("{}/strongbox", KEYMINT_SERVICE_NAME),
100 _ => {
101 return Err(Error::Km(ErrorCode::HARDWARE_TYPE_UNAVAILABLE))
102 .context("In connect_keymint.")
103 }
104 };
105
Janis Danisevskis8c6378e2021-01-01 09:30:37 -0800106 let keymint = map_binder_status_code(binder::get_interface(&service_name))
107 .context("In connect_keymint: Trying to connect to genuine KeyMint service.")
108 .or_else(|e| {
109 match e.root_cause().downcast_ref::<Error>() {
110 Some(Error::BinderTransaction(StatusCode::NAME_NOT_FOUND)) => {
111 // This is a no-op if it was called before.
112 keystore2_km_compat::add_keymint_device_service();
113
114 let keystore_compat_service: Box<dyn IKeystoreCompatService> =
115 map_binder_status_code(binder::get_interface("android.security.compat"))
116 .context("In connect_keymint: Trying to connect to compat service.")?;
117 map_binder_status(keystore_compat_service.getKeyMintDevice(security_level))
118 .map_err(|e| match e {
119 Error::BinderTransaction(StatusCode::NAME_NOT_FOUND) => {
120 Error::Km(ErrorCode::HARDWARE_TYPE_UNAVAILABLE)
121 }
122 e => e,
123 })
124 .context("In connext_keymint: Trying to get Legacy wrapper.")
125 }
126 _ => Err(e),
127 }
128 })?;
Janis Danisevskisba998992020-12-29 16:08:40 -0800129
130 Ok(Asp::new(keymint.as_binder()))
131}
132
133/// Get a keymint device for the given security level either from our cache or
134/// by making a new connection.
135pub fn get_keymint_device(security_level: SecurityLevel) -> Result<Asp> {
136 let mut devices_map = KEY_MINT_DEVICES.lock().unwrap();
137 if let Some(dev) = devices_map.get(&security_level) {
138 Ok(dev.clone())
139 } else {
140 let dev = connect_keymint(security_level).map_err(|e| {
141 anyhow::anyhow!(Error::Km(ErrorCode::HARDWARE_TYPE_UNAVAILABLE))
142 .context(format!("In get_keymint_device: {:?}", e))
143 })?;
144 devices_map.insert(security_level, dev.clone());
145 Ok(dev)
146 }
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800147}