blob: 36f3e9993e94220d66a6e68d86e8ed3bd844fa1f [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;
20use crate::gc::Gc;
Janis Danisevskisb42fc182020-12-15 08:41:27 -080021use crate::super_key::SuperKeyManager;
Janis Danisevskisba998992020-12-29 16:08:40 -080022use crate::utils::Asp;
23use crate::{
24 database::KeystoreDB,
25 error::{map_binder_status_code, Error, ErrorCode},
26};
27use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
28 IKeyMintDevice::IKeyMintDevice, SecurityLevel::SecurityLevel,
29};
30use anyhow::{Context, Result};
Janis Danisevskisb42fc182020-12-15 08:41:27 -080031use lazy_static::lazy_static;
Janis Danisevskisba998992020-12-29 16:08:40 -080032use std::collections::HashMap;
33use std::sync::Mutex;
Janis Danisevskis93927dd2020-12-23 12:23:08 -080034use std::{cell::RefCell, sync::Once};
35
36static DB_INIT: Once = Once::new();
37
38/// Open a connection to the Keystore 2.0 database. This is called during the initialization of
39/// the thread local DB field. It should never be called directly. The first time this is called
40/// we also call KeystoreDB::cleanup_leftovers to restore the key lifecycle invariant. See the
41/// documentation of cleanup_leftovers for more details.
42fn create_thread_local_db() -> KeystoreDB {
43 let mut db = KeystoreDB::new(
44 // Keystore changes to the database directory on startup
45 // (see keystore2_main.rs).
46 &std::env::current_dir().expect("Could not get the current working directory."),
47 )
48 .expect("Failed to open database.");
49 DB_INIT.call_once(|| {
50 log::info!("Touching Keystore 2.0 database for this first time since boot.");
51 log::info!("Calling cleanup leftovers.");
52 let n = db.cleanup_leftovers().expect("Failed to cleanup database on startup.");
53 if n != 0 {
54 log::info!(
55 concat!(
56 "Cleaned up {} failed entries. ",
57 "This indicates keystore crashed during key generation."
58 ),
59 n
60 );
61 }
62 Gc::notify_gc();
63 });
64 db
65}
Janis Danisevskisa75e2082020-10-07 16:44:26 -070066
67thread_local! {
68 /// Database connections are not thread safe, but connecting to the
69 /// same database multiple times is safe as long as each connection is
70 /// used by only one thread. So we store one database connection per
71 /// thread in this thread local key.
72 pub static DB: RefCell<KeystoreDB> =
Janis Danisevskis93927dd2020-12-23 12:23:08 -080073 RefCell::new(create_thread_local_db());
Janis Danisevskisa75e2082020-10-07 16:44:26 -070074}
Janis Danisevskisb42fc182020-12-15 08:41:27 -080075
76lazy_static! {
77 /// Runtime database of unwrapped super keys.
78 pub static ref SUPER_KEY: SuperKeyManager = Default::default();
Janis Danisevskisba998992020-12-29 16:08:40 -080079 /// Map of KeyMint devices.
80 static ref KEY_MINT_DEVICES: Mutex<HashMap<SecurityLevel, Asp>> = Default::default();
Janis Danisevskis93927dd2020-12-23 12:23:08 -080081 /// A single on-demand worker thread that handles deferred tasks with two different
82 /// priorities.
83 pub static ref ASYNC_TASK: AsyncTask = Default::default();
Janis Danisevskisba998992020-12-29 16:08:40 -080084}
85
86static KEYMINT_SERVICE_NAME: &str = "android.hardware.security.keymint.IKeyMintDevice";
87
88/// Make a new connection to a KeyMint device of the given security level.
89fn connect_keymint(security_level: SecurityLevel) -> Result<Asp> {
90 let service_name = match security_level {
91 SecurityLevel::TRUSTED_ENVIRONMENT => format!("{}/default", KEYMINT_SERVICE_NAME),
92 SecurityLevel::STRONGBOX => format!("{}/strongbox", KEYMINT_SERVICE_NAME),
93 _ => {
94 return Err(Error::Km(ErrorCode::HARDWARE_TYPE_UNAVAILABLE))
95 .context("In connect_keymint.")
96 }
97 };
98
99 let keymint: Box<dyn IKeyMintDevice> =
100 map_binder_status_code(binder::get_interface(&service_name))
101 .context("In connect_keymint: Trying to connect to genuine KeyMint service.")?;
102
103 Ok(Asp::new(keymint.as_binder()))
104}
105
106/// Get a keymint device for the given security level either from our cache or
107/// by making a new connection.
108pub fn get_keymint_device(security_level: SecurityLevel) -> Result<Asp> {
109 let mut devices_map = KEY_MINT_DEVICES.lock().unwrap();
110 if let Some(dev) = devices_map.get(&security_level) {
111 Ok(dev.clone())
112 } else {
113 let dev = connect_keymint(security_level).map_err(|e| {
114 anyhow::anyhow!(Error::Km(ErrorCode::HARDWARE_TYPE_UNAVAILABLE))
115 .context(format!("In get_keymint_device: {:?}", e))
116 })?;
117 devices_map.insert(security_level, dev.clone());
118 Ok(dev)
119 }
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800120}