Merge "Remove microdroid build of keystore2"
diff --git a/identity/Android.bp b/identity/Android.bp
index 7b0503a..790a731 100644
--- a/identity/Android.bp
+++ b/identity/Android.bp
@@ -27,6 +27,7 @@
defaults: [
"identity_defaults",
"keymint_use_latest_hal_aidl_ndk_shared",
+ "keymint_use_latest_hal_aidl_cpp_static",
],
srcs: [
diff --git a/keystore2/aidl/Android.bp b/keystore2/aidl/Android.bp
index 7eb2b83..ae08567 100644
--- a/keystore2/aidl/Android.bp
+++ b/keystore2/aidl/Android.bp
@@ -29,7 +29,6 @@
backend: {
java: {
platform_apis: true,
- srcs_available: true,
},
rust: {
enabled: true,
@@ -52,7 +51,6 @@
backend: {
java: {
platform_apis: true,
- srcs_available: true,
},
rust: {
enabled: true,
@@ -71,7 +69,6 @@
backend: {
java: {
enabled: true,
- srcs_available: true,
},
rust: {
enabled: true,
@@ -94,7 +91,6 @@
backend: {
java: {
platform_apis: true,
- srcs_available: true,
},
rust: {
enabled: true,
@@ -116,7 +112,6 @@
backend: {
java: {
platform_apis: true,
- srcs_available: true,
},
ndk: {
enabled: true,
@@ -138,7 +133,6 @@
backend: {
java: {
platform_apis: true,
- srcs_available: true,
},
rust: {
enabled: true,
@@ -157,7 +151,6 @@
backend: {
java: {
platform_apis: true,
- srcs_available: true,
},
rust: {
enabled: true,
@@ -179,7 +172,6 @@
backend: {
java: {
platform_apis: true,
- srcs_available: true,
},
rust: {
enabled: true,
diff --git a/keystore2/src/authorization.rs b/keystore2/src/authorization.rs
index 64b498f..81790af 100644
--- a/keystore2/src/authorization.rs
+++ b/keystore2/src/authorization.rs
@@ -154,8 +154,10 @@
.context("In on_lock_screen_event: Unlock with password.")?;
ENFORCEMENTS.set_device_locked(user_id, false);
+ let mut skm = SUPER_KEY.write().unwrap();
+
DB.with(|db| {
- SUPER_KEY.unlock_screen_lock_bound_key(
+ skm.unlock_screen_lock_bound_key(
&mut db.borrow_mut(),
user_id as u32,
&password,
@@ -166,10 +168,9 @@
// Unlock super key.
if let UserState::Uninitialized = DB
.with(|db| {
- UserState::get_with_password_unlock(
+ skm.unlock_and_get_user_state(
&mut db.borrow_mut(),
&LEGACY_MIGRATOR,
- &SUPER_KEY,
user_id as u32,
&password,
)
@@ -187,8 +188,9 @@
check_keystore_permission(KeystorePerm::Unlock)
.context("In on_lock_screen_event: Unlock.")?;
ENFORCEMENTS.set_device_locked(user_id, false);
+ let mut skm = SUPER_KEY.write().unwrap();
DB.with(|db| {
- SUPER_KEY.try_unlock_user_with_biometric(&mut db.borrow_mut(), user_id as u32)
+ skm.try_unlock_user_with_biometric(&mut db.borrow_mut(), user_id as u32)
})
.context("In on_lock_screen_event: try_unlock_user_with_biometric failed")?;
Ok(())
@@ -197,8 +199,9 @@
check_keystore_permission(KeystorePerm::Lock)
.context("In on_lock_screen_event: Lock")?;
ENFORCEMENTS.set_device_locked(user_id, true);
+ let mut skm = SUPER_KEY.write().unwrap();
DB.with(|db| {
- SUPER_KEY.lock_screen_lock_bound_key(
+ skm.lock_screen_lock_bound_key(
&mut db.borrow_mut(),
user_id as u32,
unlocking_sids.unwrap_or(&[]),
diff --git a/keystore2/src/database.rs b/keystore2/src/database.rs
index 133a926..e68b0fd 100644
--- a/keystore2/src/database.rs
+++ b/keystore2/src/database.rs
@@ -3231,7 +3231,7 @@
use std::collections::BTreeMap;
use std::fmt::Write;
use std::sync::atomic::{AtomicU8, Ordering};
- use std::sync::Arc;
+ use std::sync::{Arc, RwLock};
use std::thread;
use std::time::{Duration, SystemTime};
#[cfg(disabled)]
@@ -3251,7 +3251,7 @@
where
F: Fn(&Uuid, &[u8]) -> Result<()> + Send + 'static,
{
- let super_key: Arc<SuperKeyManager> = Default::default();
+ let super_key: Arc<RwLock<SuperKeyManager>> = Default::default();
let gc_db = KeystoreDB::new(path, None).expect("Failed to open test gc db_connection.");
let gc = Gc::new_init_with(Default::default(), move || (Box::new(cb), gc_db, super_key));
diff --git a/keystore2/src/enforcements.rs b/keystore2/src/enforcements.rs
index 2407525..ade4751 100644
--- a/keystore2/src/enforcements.rs
+++ b/keystore2/src/enforcements.rs
@@ -602,7 +602,7 @@
}
if let Some(level) = max_boot_level {
- if !SUPER_KEY.level_accessible(level) {
+ if !SUPER_KEY.read().unwrap().level_accessible(level) {
return Err(Error::Km(Ec::BOOT_LEVEL_EXCEEDED))
.context("In authorize_create: boot level is too late.");
}
diff --git a/keystore2/src/gc.rs b/keystore2/src/gc.rs
index 25f08c8..341aa0a 100644
--- a/keystore2/src/gc.rs
+++ b/keystore2/src/gc.rs
@@ -27,7 +27,7 @@
use async_task::AsyncTask;
use std::sync::{
atomic::{AtomicU8, Ordering},
- Arc,
+ Arc, RwLock,
};
pub struct Gc {
@@ -47,7 +47,7 @@
F: FnOnce() -> (
Box<dyn Fn(&Uuid, &[u8]) -> Result<()> + Send + 'static>,
KeystoreDB,
- Arc<SuperKeyManager>,
+ Arc<RwLock<SuperKeyManager>>,
) + Send
+ 'static,
{
@@ -87,7 +87,7 @@
invalidate_key: Box<dyn Fn(&Uuid, &[u8]) -> Result<()> + Send + 'static>,
db: KeystoreDB,
async_task: std::sync::Weak<AsyncTask>,
- super_key: Arc<SuperKeyManager>,
+ super_key: Arc<RwLock<SuperKeyManager>>,
notified: Arc<AtomicU8>,
}
@@ -121,6 +121,8 @@
if let Some(uuid) = blob_metadata.km_uuid() {
let blob = self
.super_key
+ .read()
+ .unwrap()
.unwrap_key_if_required(&blob_metadata, &blob)
.context("In process_one_key: Trying to unwrap to-be-deleted blob.")?;
(self.invalidate_key)(uuid, &*blob)
diff --git a/keystore2/src/globals.rs b/keystore2/src/globals.rs
index 7028aae..2819314 100644
--- a/keystore2/src/globals.rs
+++ b/keystore2/src/globals.rs
@@ -156,7 +156,7 @@
pub static ref DB_PATH: RwLock<PathBuf> = RwLock::new(
Path::new("/data/misc/keystore").to_path_buf());
/// Runtime database of unwrapped super keys.
- pub static ref SUPER_KEY: Arc<SuperKeyManager> = Default::default();
+ pub static ref SUPER_KEY: Arc<RwLock<SuperKeyManager>> = Default::default();
/// Map of KeyMint devices.
static ref KEY_MINT_DEVICES: Mutex<DevicesMap<dyn IKeyMintDevice>> = Default::default();
/// Timestamp service.
diff --git a/keystore2/src/legacy_blob.rs b/keystore2/src/legacy_blob.rs
index 7454cca..b801ed3 100644
--- a/keystore2/src/legacy_blob.rs
+++ b/keystore2/src/legacy_blob.rs
@@ -1340,7 +1340,7 @@
CACERT_NON_AUTHBOUND,
)?;
- let key_manager: SuperKeyManager = Default::default();
+ let mut key_manager: SuperKeyManager = Default::default();
let mut db = crate::database::KeystoreDB::new(temp_dir.path(), None)?;
let legacy_blob_loader = LegacyBlobLoader::new(temp_dir.path());
diff --git a/keystore2/src/lib.rs b/keystore2/src/lib.rs
index 8b629b1..134f707 100644
--- a/keystore2/src/lib.rs
+++ b/keystore2/src/lib.rs
@@ -40,7 +40,6 @@
pub mod security_level;
pub mod service;
pub mod shared_secret_negotiation;
-pub mod try_insert;
pub mod utils;
mod attestation_key_utils;
diff --git a/keystore2/src/maintenance.rs b/keystore2/src/maintenance.rs
index d5feee1..9925e42 100644
--- a/keystore2/src/maintenance.rs
+++ b/keystore2/src/maintenance.rs
@@ -21,7 +21,7 @@
use crate::globals::get_keymint_device;
use crate::globals::{DB, LEGACY_MIGRATOR, SUPER_KEY};
use crate::permission::{KeyPerm, KeystorePerm};
-use crate::super_key::UserState;
+use crate::super_key::{SuperKeyManager, UserState};
use crate::utils::{
check_key_permission, check_keystore_permission, list_key_entries, watchdog as wd,
};
@@ -70,24 +70,25 @@
}
fn on_user_password_changed(user_id: i32, password: Option<Password>) -> Result<()> {
- //Check permission. Function should return if this failed. Therefore having '?' at the end
- //is very important.
+ // Check permission. Function should return if this failed. Therefore having '?' at the end
+ // is very important.
check_keystore_permission(KeystorePerm::ChangePassword)
.context("In on_user_password_changed.")?;
+ let mut skm = SUPER_KEY.write().unwrap();
+
if let Some(pw) = password.as_ref() {
DB.with(|db| {
- SUPER_KEY.unlock_screen_lock_bound_key(&mut db.borrow_mut(), user_id as u32, pw)
+ skm.unlock_screen_lock_bound_key(&mut db.borrow_mut(), user_id as u32, pw)
})
.context("In on_user_password_changed: unlock_screen_lock_bound_key failed")?;
}
match DB
.with(|db| {
- UserState::get_with_password_changed(
+ skm.reset_or_init_user_and_get_user_state(
&mut db.borrow_mut(),
&LEGACY_MIGRATOR,
- &SUPER_KEY,
user_id as u32,
password.as_ref(),
)
@@ -110,10 +111,10 @@
// Check permission. Function should return if this failed. Therefore having '?' at the end
// is very important.
check_keystore_permission(KeystorePerm::ChangeUser).context("In add_or_remove_user.")?;
+
DB.with(|db| {
- UserState::reset_user(
+ SUPER_KEY.write().unwrap().reset_user(
&mut db.borrow_mut(),
- &SUPER_KEY,
&LEGACY_MIGRATOR,
user_id as u32,
false,
@@ -145,7 +146,11 @@
check_keystore_permission(KeystorePerm::GetState).context("In get_state.")?;
let state = DB
.with(|db| {
- UserState::get(&mut db.borrow_mut(), &LEGACY_MIGRATOR, &SUPER_KEY, user_id as u32)
+ SUPER_KEY.read().unwrap().get_user_state(
+ &mut db.borrow_mut(),
+ &LEGACY_MIGRATOR,
+ user_id as u32,
+ )
})
.context("In get_state. Trying to get UserState.")?;
@@ -202,7 +207,9 @@
.context("In early_boot_ended. Checking permission")?;
log::info!("In early_boot_ended.");
- if let Err(e) = DB.with(|db| SUPER_KEY.set_up_boot_level_cache(&mut db.borrow_mut())) {
+ if let Err(e) =
+ DB.with(|db| SuperKeyManager::set_up_boot_level_cache(&SUPER_KEY, &mut db.borrow_mut()))
+ {
log::error!("SUPER_KEY.set_up_boot_level_cache failed:\n{:?}\n:(", e);
}
Maintenance::call_on_all_security_levels("earlyBootEnded", |dev| dev.earlyBootEnded())
diff --git a/keystore2/src/security_level.rs b/keystore2/src/security_level.rs
index 9334930..83f0bee 100644
--- a/keystore2/src/security_level.rs
+++ b/keystore2/src/security_level.rs
@@ -160,6 +160,8 @@
let mut db = db.borrow_mut();
let (key_blob, mut blob_metadata) = SUPER_KEY
+ .read()
+ .unwrap()
.handle_super_encryption_on_key_init(
&mut db,
&LEGACY_MIGRATOR,
@@ -303,6 +305,8 @@
.context("In create_operation.")?;
let km_blob = SUPER_KEY
+ .read()
+ .unwrap()
.unwrap_key_if_required(&blob_metadata, km_blob)
.context("In create_operation. Failed to handle super encryption.")?;
@@ -736,8 +740,11 @@
.ok_or_else(error::Error::sys)
.context("No km_blob after successfully loading key. This should never happen.")?;
- let wrapping_key_blob =
- SUPER_KEY.unwrap_key_if_required(&wrapping_blob_metadata, &wrapping_key_blob).context(
+ let wrapping_key_blob = SUPER_KEY
+ .read()
+ .unwrap()
+ .unwrap_key_if_required(&wrapping_blob_metadata, &wrapping_key_blob)
+ .context(
"In import_wrapped_key. Failed to handle super encryption for wrapping key.",
)?;
diff --git a/keystore2/src/super_key.rs b/keystore2/src/super_key.rs
index ca5e593..6862011 100644
--- a/keystore2/src/super_key.rs
+++ b/keystore2/src/super_key.rs
@@ -28,7 +28,6 @@
legacy_blob::LegacyBlobLoader,
legacy_migrator::LegacyMigrator,
raw_device::KeyMintDevice,
- try_insert::TryInsert,
utils::watchdog as wd,
utils::AID_KEYSTORE,
};
@@ -50,7 +49,7 @@
use std::{
collections::HashMap,
sync::Arc,
- sync::{Mutex, Weak},
+ sync::{Mutex, RwLock, Weak},
};
use std::{convert::TryFrom, ops::Deref};
@@ -76,7 +75,7 @@
/// different purpose, distinguished by alias. Each is associated with a static
/// constant of this type.
pub struct SuperKeyType<'a> {
- /// Alias used to look the key up in the `persistent.keyentry` table.
+ /// Alias used to look up the key in the `persistent.keyentry` table.
pub alias: &'a str,
/// Encryption algorithm
pub algorithm: SuperEncryptionAlgorithm,
@@ -256,7 +255,7 @@
struct SkmState {
user_keys: HashMap<UserId, UserSuperKeys>,
key_index: HashMap<i64, Weak<SuperKey>>,
- boot_level_key_cache: Option<BootLevelKeyCache>,
+ boot_level_key_cache: Option<Mutex<BootLevelKeyCache>>,
}
impl SkmState {
@@ -275,24 +274,24 @@
#[derive(Default)]
pub struct SuperKeyManager {
- data: Mutex<SkmState>,
+ data: SkmState,
}
impl SuperKeyManager {
- pub fn set_up_boot_level_cache(self: &Arc<Self>, db: &mut KeystoreDB) -> Result<()> {
- let mut data = self.data.lock().unwrap();
- if data.boot_level_key_cache.is_some() {
+ pub fn set_up_boot_level_cache(skm: &Arc<RwLock<Self>>, db: &mut KeystoreDB) -> Result<()> {
+ let mut skm_guard = skm.write().unwrap();
+ if skm_guard.data.boot_level_key_cache.is_some() {
log::info!("In set_up_boot_level_cache: called for a second time");
return Ok(());
}
let level_zero_key = get_level_zero_key(db)
.context("In set_up_boot_level_cache: get_level_zero_key failed")?;
- data.boot_level_key_cache = Some(BootLevelKeyCache::new(level_zero_key));
+ skm_guard.data.boot_level_key_cache =
+ Some(Mutex::new(BootLevelKeyCache::new(level_zero_key)));
log::info!("Starting boot level watcher.");
- let clone = self.clone();
+ let clone = skm.clone();
std::thread::spawn(move || {
- clone
- .watch_boot_level()
+ Self::watch_boot_level(clone)
.unwrap_or_else(|e| log::error!("watch_boot_level failed:\n{:?}", e));
});
Ok(())
@@ -300,32 +299,40 @@
/// Watch the `keystore.boot_level` system property, and keep boot level up to date.
/// Blocks waiting for system property changes, so must be run in its own thread.
- fn watch_boot_level(&self) -> Result<()> {
+ fn watch_boot_level(skm: Arc<RwLock<Self>>) -> Result<()> {
let mut w = PropertyWatcher::new("keystore.boot_level")
.context("In watch_boot_level: PropertyWatcher::new failed")?;
loop {
let level = w
.read(|_n, v| v.parse::<usize>().map_err(std::convert::Into::into))
.context("In watch_boot_level: read of property failed")?;
- // watch_boot_level should only be called once data.boot_level_key_cache is Some,
- // so it's safe to unwrap in the branches below.
- if level < MAX_MAX_BOOT_LEVEL {
- log::info!("Read keystore.boot_level value {}", level);
- let mut data = self.data.lock().unwrap();
- data.boot_level_key_cache
+
+ // This scope limits the skm_guard life, so we don't hold the skm_guard while
+ // waiting.
+ {
+ let mut skm_guard = skm.write().unwrap();
+ let boot_level_key_cache = skm_guard
+ .data
+ .boot_level_key_cache
.as_mut()
- .unwrap()
- .advance_boot_level(level)
- .context("In watch_boot_level: advance_boot_level failed")?;
- } else {
- log::info!(
- "keystore.boot_level {} hits maximum {}, finishing.",
- level,
- MAX_MAX_BOOT_LEVEL
- );
- let mut data = self.data.lock().unwrap();
- data.boot_level_key_cache.as_mut().unwrap().finish();
- break;
+ .ok_or_else(Error::sys)
+ .context("In watch_boot_level: Boot level cache not initialized")?
+ .get_mut()
+ .unwrap();
+ if level < MAX_MAX_BOOT_LEVEL {
+ log::info!("Read keystore.boot_level value {}", level);
+ boot_level_key_cache
+ .advance_boot_level(level)
+ .context("In watch_boot_level: advance_boot_level failed")?;
+ } else {
+ log::info!(
+ "keystore.boot_level {} hits maximum {}, finishing.",
+ level,
+ MAX_MAX_BOOT_LEVEL
+ );
+ boot_level_key_cache.finish();
+ break;
+ }
}
w.wait().context("In watch_boot_level: property wait failed")?;
}
@@ -334,34 +341,37 @@
pub fn level_accessible(&self, boot_level: i32) -> bool {
self.data
- .lock()
- .unwrap()
.boot_level_key_cache
.as_ref()
- .map_or(false, |c| c.level_accessible(boot_level as usize))
+ .map_or(false, |c| c.lock().unwrap().level_accessible(boot_level as usize))
}
- pub fn forget_all_keys_for_user(&self, user: UserId) {
- let mut data = self.data.lock().unwrap();
- data.user_keys.remove(&user);
+ pub fn forget_all_keys_for_user(&mut self, user: UserId) {
+ self.data.user_keys.remove(&user);
}
- fn install_per_boot_key_for_user(&self, user: UserId, super_key: Arc<SuperKey>) -> Result<()> {
- let mut data = self.data.lock().unwrap();
- data.add_key_to_key_index(&super_key)
+ fn install_per_boot_key_for_user(
+ &mut self,
+ user: UserId,
+ super_key: Arc<SuperKey>,
+ ) -> Result<()> {
+ self.data
+ .add_key_to_key_index(&super_key)
.context("In install_per_boot_key_for_user: add_key_to_key_index failed")?;
- data.user_keys.entry(user).or_default().per_boot = Some(super_key);
+ self.data.user_keys.entry(user).or_default().per_boot = Some(super_key);
Ok(())
}
fn lookup_key(&self, key_id: &SuperKeyIdentifier) -> Result<Option<Arc<SuperKey>>> {
- let mut data = self.data.lock().unwrap();
Ok(match key_id {
- SuperKeyIdentifier::DatabaseId(id) => data.key_index.get(id).and_then(|k| k.upgrade()),
- SuperKeyIdentifier::BootLevel(level) => data
+ SuperKeyIdentifier::DatabaseId(id) => {
+ self.data.key_index.get(id).and_then(|k| k.upgrade())
+ }
+ SuperKeyIdentifier::BootLevel(level) => self
+ .data
.boot_level_key_cache
- .as_mut()
- .map(|b| b.aes_key(*level as usize))
+ .as_ref()
+ .map(|b| b.lock().unwrap().aes_key(*level as usize))
.transpose()
.context("In lookup_key: aes_key failed")?
.flatten()
@@ -377,8 +387,7 @@
}
pub fn get_per_boot_key_by_user_id(&self, user_id: UserId) -> Option<Arc<SuperKey>> {
- let data = self.data.lock().unwrap();
- data.user_keys.get(&user_id).and_then(|e| e.per_boot.as_ref().cloned())
+ self.data.user_keys.get(&user_id).and_then(|e| e.per_boot.as_ref().cloned())
}
/// This function unlocks the super keys for a given user.
@@ -386,7 +395,7 @@
/// super key cache. If there is no such key a new key is created, encrypted with
/// a key derived from the given password and stored in the database.
pub fn unlock_user_key(
- &self,
+ &mut self,
db: &mut KeystoreDB,
user: UserId,
pw: &Password,
@@ -493,7 +502,10 @@
}
/// Checks if user has setup LSKF, even when super key cache is empty for the user.
- pub fn super_key_exists_in_db_for_user(
+ /// The reference to self is unused but it is required to prevent calling this function
+ /// concurrently with skm state database changes.
+ fn super_key_exists_in_db_for_user(
+ &self,
db: &mut KeystoreDB,
legacy_migrator: &LegacyMigrator,
user_id: UserId,
@@ -515,7 +527,7 @@
/// legacy database). If not, return Uninitialized state.
/// Otherwise, decrypt the super key from the password and return LskfUnlocked state.
pub fn check_and_unlock_super_key(
- &self,
+ &mut self,
db: &mut KeystoreDB,
legacy_migrator: &LegacyMigrator,
user_id: UserId,
@@ -544,24 +556,23 @@
/// and return LskfUnlocked state.
/// If the password is not provided, return Uninitialized state.
pub fn check_and_initialize_super_key(
- &self,
+ &mut self,
db: &mut KeystoreDB,
legacy_migrator: &LegacyMigrator,
user_id: UserId,
pw: Option<&Password>,
) -> Result<UserState> {
- let super_key_exists_in_db =
- Self::super_key_exists_in_db_for_user(db, legacy_migrator, user_id).context(
- "In check_and_initialize_super_key. Failed to check if super key exists.",
- )?;
+ let super_key_exists_in_db = self
+ .super_key_exists_in_db_for_user(db, legacy_migrator, user_id)
+ .context("In check_and_initialize_super_key. Failed to check if super key exists.")?;
if super_key_exists_in_db {
Ok(UserState::LskfLocked)
} else if let Some(pw) = pw {
- //generate a new super key.
+ // Generate a new super key.
let super_key = generate_aes256_key()
.context("In check_and_initialize_super_key: Failed to generate AES 256 key.")?;
- //derive an AES256 key from the password and re-encrypt the super key
- //before we insert it in the database.
+ // Derive an AES256 key from the password and re-encrypt the super key
+ // before we insert it in the database.
let (encrypted_super_key, blob_metadata) = Self::encrypt_with_password(&super_key, pw)
.context("In check_and_initialize_super_key.")?;
@@ -589,9 +600,9 @@
}
}
- //helper function to populate super key cache from the super key blob loaded from the database
+ // Helper function to populate super key cache from the super key blob loaded from the database.
fn populate_cache_from_super_key_blob(
- &self,
+ &mut self,
user_id: UserId,
algorithm: SuperEncryptionAlgorithm,
entry: KeyEntry,
@@ -605,7 +616,7 @@
Ok(super_key)
}
- /// Extracts super key from the entry loaded from the database
+ /// Extracts super key from the entry loaded from the database.
pub fn extract_super_key_from_key_entry(
algorithm: SuperEncryptionAlgorithm,
entry: KeyEntry,
@@ -620,7 +631,7 @@
metadata.aead_tag(),
) {
(Some(&EncryptedBy::Password), Some(salt), Some(iv), Some(tag)) => {
- // Note that password encryption is AES no matter the value of algorithm
+ // Note that password encryption is AES no matter the value of algorithm.
let key = pw.derive_key(Some(salt), AES_256_KEY_LENGTH).context(
"In extract_super_key_from_key_entry: Failed to generate key from password.",
)?;
@@ -684,7 +695,8 @@
user_id: UserId,
key_blob: &[u8],
) -> Result<(Vec<u8>, BlobMetaData)> {
- match UserState::get(db, legacy_migrator, self, user_id)
+ match self
+ .get_user_state(db, legacy_migrator, user_id)
.context("In super_encrypt. Failed to get user state.")?
{
UserState::LskfUnlocked(super_key) => {
@@ -699,9 +711,9 @@
}
}
- //Helper function to encrypt a key with the given super key. Callers should select which super
- //key to be used. This is called when a key is super encrypted at its creation as well as at its
- //upgrade.
+ // Helper function to encrypt a key with the given super key. Callers should select which super
+ // key to be used. This is called when a key is super encrypted at its creation as well as at
+ // its upgrade.
fn encrypt_with_aes_super_key(
key_blob: &[u8],
super_key: &SuperKey,
@@ -741,9 +753,13 @@
"Failed to super encrypt with LskfBound key."
)),
SuperEncryptionType::ScreenLockBound => {
- let mut data = self.data.lock().unwrap();
- let entry = data.user_keys.entry(user_id).or_default();
- if let Some(super_key) = entry.screen_lock_bound.as_ref() {
+ let entry = self
+ .data
+ .user_keys
+ .get(&user_id)
+ .map(|e| e.screen_lock_bound.as_ref())
+ .flatten();
+ if let Some(super_key) = entry {
Self::encrypt_with_aes_super_key(key_blob, super_key).context(concat!(
"In handle_super_encryption_on_key_init. ",
"Failed to encrypt with ScreenLockBound key."
@@ -813,6 +829,7 @@
/// When this is called, the caller must hold the lock on the SuperKeyManager.
/// So it's OK that the check and creation are different DB transactions.
fn get_or_create_super_key(
+ &mut self,
db: &mut KeystoreDB,
user_id: UserId,
key_type: &SuperKeyType,
@@ -847,8 +864,8 @@
)
}
};
- //derive an AES256 key from the password and re-encrypt the super key
- //before we insert it in the database.
+ // Derive an AES256 key from the password and re-encrypt the super key
+ // before we insert it in the database.
let (encrypted_super_key, blob_metadata) =
Self::encrypt_with_password(&super_key, password)
.context("In get_or_create_super_key.")?;
@@ -876,52 +893,64 @@
/// Decrypt the screen-lock bound keys for this user using the password and store in memory.
pub fn unlock_screen_lock_bound_key(
- &self,
+ &mut self,
db: &mut KeystoreDB,
user_id: UserId,
password: &Password,
) -> Result<()> {
- let mut data = self.data.lock().unwrap();
- let entry = data.user_keys.entry(user_id).or_default();
- let aes = entry
- .screen_lock_bound
- .get_or_try_to_insert_with(|| {
- Self::get_or_create_super_key(
- db,
- user_id,
- &USER_SCREEN_LOCK_BOUND_KEY,
- password,
- None,
- )
- })?
- .clone();
- let ecdh = entry
- .screen_lock_bound_private
- .get_or_try_to_insert_with(|| {
- Self::get_or_create_super_key(
- db,
- user_id,
- &USER_SCREEN_LOCK_BOUND_P521_KEY,
- password,
- Some(aes.clone()),
- )
- })?
- .clone();
- data.add_key_to_key_index(&aes)?;
- data.add_key_to_key_index(&ecdh)?;
+ let (screen_lock_bound, screen_lock_bound_private) = self
+ .data
+ .user_keys
+ .get(&user_id)
+ .map(|e| (e.screen_lock_bound.clone(), e.screen_lock_bound_private.clone()))
+ .unwrap_or((None, None));
+
+ if screen_lock_bound.is_some() && screen_lock_bound_private.is_some() {
+ // Already unlocked.
+ return Ok(());
+ }
+
+ let aes = if let Some(screen_lock_bound) = screen_lock_bound {
+ // This is weird. If this point is reached only one of the screen locked keys was
+ // initialized. This should never happen.
+ screen_lock_bound
+ } else {
+ self.get_or_create_super_key(db, user_id, &USER_SCREEN_LOCK_BOUND_KEY, password, None)
+ .context("In unlock_screen_lock_bound_key: Trying to get or create symmetric key.")?
+ };
+
+ let ecdh = if let Some(screen_lock_bound_private) = screen_lock_bound_private {
+ // This is weird. If this point is reached only one of the screen locked keys was
+ // initialized. This should never happen.
+ screen_lock_bound_private
+ } else {
+ self.get_or_create_super_key(
+ db,
+ user_id,
+ &USER_SCREEN_LOCK_BOUND_P521_KEY,
+ password,
+ Some(aes.clone()),
+ )
+ .context("In unlock_screen_lock_bound_key: Trying to get or create asymmetric key.")?
+ };
+
+ self.data.add_key_to_key_index(&aes)?;
+ self.data.add_key_to_key_index(&ecdh)?;
+ let entry = self.data.user_keys.entry(user_id).or_default();
+ entry.screen_lock_bound = Some(aes);
+ entry.screen_lock_bound_private = Some(ecdh);
Ok(())
}
/// Wipe the screen-lock bound keys for this user from memory.
pub fn lock_screen_lock_bound_key(
- &self,
+ &mut self,
db: &mut KeystoreDB,
user_id: UserId,
unlocking_sids: &[i64],
) {
log::info!("Locking screen bound for user {} sids {:?}", user_id, unlocking_sids);
- let mut data = self.data.lock().unwrap();
- let mut entry = data.user_keys.entry(user_id).or_default();
+ let mut entry = self.data.user_keys.entry(user_id).or_default();
if !unlocking_sids.is_empty() {
if let (Some(aes), Some(ecdh)) = (
entry.screen_lock_bound.as_ref().cloned(),
@@ -993,12 +1022,11 @@
/// User has unlocked, not using a password. See if any of our stored auth tokens can be used
/// to unlock the keys protecting UNLOCKED_DEVICE_REQUIRED keys.
pub fn try_unlock_user_with_biometric(
- &self,
+ &mut self,
db: &mut KeystoreDB,
user_id: UserId,
) -> Result<()> {
- let mut data = self.data.lock().unwrap();
- let mut entry = data.user_keys.entry(user_id).or_default();
+ let mut entry = self.data.user_keys.entry(user_id).or_default();
if let Some(biometric) = entry.biometric_unlock.as_ref() {
let (key_id_guard, key_entry) = db
.load_key_entry(
@@ -1038,8 +1066,8 @@
Ok((slb, slbp)) => {
entry.screen_lock_bound = Some(slb.clone());
entry.screen_lock_bound_private = Some(slbp.clone());
- data.add_key_to_key_index(&slb)?;
- data.add_key_to_key_index(&slbp)?;
+ self.data.add_key_to_key_index(&slb)?;
+ self.data.add_key_to_key_index(&slbp)?;
log::info!(concat!(
"In try_unlock_user_with_biometric: ",
"Successfully unlocked with biometric"
@@ -1055,6 +1083,122 @@
}
Ok(())
}
+
+ /// Returns the keystore locked state of the given user. It requires the thread local
+ /// keystore database and a reference to the legacy migrator because it may need to
+ /// migrate the super key from the legacy blob database to the keystore database.
+ pub fn get_user_state(
+ &self,
+ db: &mut KeystoreDB,
+ legacy_migrator: &LegacyMigrator,
+ user_id: UserId,
+ ) -> Result<UserState> {
+ match self.get_per_boot_key_by_user_id(user_id) {
+ Some(super_key) => Ok(UserState::LskfUnlocked(super_key)),
+ None => {
+ // Check if a super key exists in the database or legacy database.
+ // If so, return locked user state.
+ if self
+ .super_key_exists_in_db_for_user(db, legacy_migrator, user_id)
+ .context("In get_user_state.")?
+ {
+ Ok(UserState::LskfLocked)
+ } else {
+ Ok(UserState::Uninitialized)
+ }
+ }
+ }
+ }
+
+ /// If the given user is unlocked:
+ /// * and `password` is None, the user is reset, all authentication bound keys are deleted and
+ /// `Ok(UserState::Uninitialized)` is returned.
+ /// * and `password` is Some, `Ok(UserState::LskfUnlocked)` is returned.
+ /// If the given user is locked:
+ /// * and the user was initialized before, `Ok(UserState::Locked)` is returned.
+ /// * and the user was not initialized before:
+ /// * and `password` is None, `Ok(Uninitialized)` is returned.
+ /// * and `password` is Some, super keys are generated and `Ok(UserState::LskfUnlocked)` is
+ /// returned.
+ pub fn reset_or_init_user_and_get_user_state(
+ &mut self,
+ db: &mut KeystoreDB,
+ legacy_migrator: &LegacyMigrator,
+ user_id: UserId,
+ password: Option<&Password>,
+ ) -> Result<UserState> {
+ match self.get_per_boot_key_by_user_id(user_id) {
+ Some(_) if password.is_none() => {
+ // Transitioning to swiping, delete only the super key in database and cache,
+ // and super-encrypted keys in database (and in KM).
+ self.reset_user(db, legacy_migrator, user_id, true).context(
+ "In reset_or_init_user_and_get_user_state: Trying to delete keys from the db.",
+ )?;
+ // Lskf is now removed in Keystore.
+ Ok(UserState::Uninitialized)
+ }
+ Some(super_key) => {
+ // Keystore won't be notified when changing to a new password when LSKF is
+ // already setup. Therefore, ideally this path wouldn't be reached.
+ Ok(UserState::LskfUnlocked(super_key))
+ }
+ None => {
+ // Check if a super key exists in the database or legacy database.
+ // If so, return LskfLocked state.
+ // Otherwise, i) if the password is provided, initialize the super key and return
+ // LskfUnlocked state ii) if password is not provided, return Uninitialized state.
+ self.check_and_initialize_super_key(db, legacy_migrator, user_id, password)
+ }
+ }
+ }
+
+ /// Unlocks the given user with the given password. If the key was already unlocked or unlocking
+ /// was successful, `Ok(UserState::LskfUnlocked)` is returned.
+ /// If the user was never initialized `Ok(UserState::Uninitialized)` is returned.
+ pub fn unlock_and_get_user_state(
+ &mut self,
+ db: &mut KeystoreDB,
+ legacy_migrator: &LegacyMigrator,
+ user_id: UserId,
+ password: &Password,
+ ) -> Result<UserState> {
+ match self.get_per_boot_key_by_user_id(user_id) {
+ Some(super_key) => {
+ log::info!("In unlock_and_get_user_state. Trying to unlock when already unlocked.");
+ Ok(UserState::LskfUnlocked(super_key))
+ }
+ None => {
+ // Check if a super key exists in the database or legacy database.
+ // If not, return Uninitialized state.
+ // Otherwise, try to unlock the super key and if successful,
+ // return LskfUnlocked.
+ self.check_and_unlock_super_key(db, legacy_migrator, user_id, password)
+ .context("In unlock_and_get_user_state. Failed to unlock super key.")
+ }
+ }
+ }
+
+ /// Delete all the keys created on behalf of the user.
+ /// If 'keep_non_super_encrypted_keys' is set to true, delete only the super key and super
+ /// encrypted keys.
+ pub fn reset_user(
+ &mut self,
+ db: &mut KeystoreDB,
+ legacy_migrator: &LegacyMigrator,
+ user_id: UserId,
+ keep_non_super_encrypted_keys: bool,
+ ) -> Result<()> {
+ // Mark keys created on behalf of the user as unreferenced.
+ legacy_migrator
+ .bulk_delete_user(user_id, keep_non_super_encrypted_keys)
+ .context("In reset_user: Trying to delete legacy keys.")?;
+ db.unbind_keys_for_user(user_id, keep_non_super_encrypted_keys)
+ .context("In reset user. Error in unbinding keys.")?;
+
+ // Delete super key in cache, if exists.
+ self.forget_all_keys_for_user(user_id);
+ Ok(())
+ }
}
/// This enum represents different states of the user's life cycle in the device.
@@ -1072,110 +1216,6 @@
Uninitialized,
}
-impl UserState {
- pub fn get(
- db: &mut KeystoreDB,
- legacy_migrator: &LegacyMigrator,
- skm: &SuperKeyManager,
- user_id: UserId,
- ) -> Result<UserState> {
- match skm.get_per_boot_key_by_user_id(user_id) {
- Some(super_key) => Ok(UserState::LskfUnlocked(super_key)),
- None => {
- //Check if a super key exists in the database or legacy database.
- //If so, return locked user state.
- if SuperKeyManager::super_key_exists_in_db_for_user(db, legacy_migrator, user_id)
- .context("In get.")?
- {
- Ok(UserState::LskfLocked)
- } else {
- Ok(UserState::Uninitialized)
- }
- }
- }
- }
-
- /// Queries user state when serving password change requests.
- pub fn get_with_password_changed(
- db: &mut KeystoreDB,
- legacy_migrator: &LegacyMigrator,
- skm: &SuperKeyManager,
- user_id: UserId,
- password: Option<&Password>,
- ) -> Result<UserState> {
- match skm.get_per_boot_key_by_user_id(user_id) {
- Some(super_key) => {
- if password.is_none() {
- //transitioning to swiping, delete only the super key in database and cache, and
- //super-encrypted keys in database (and in KM)
- Self::reset_user(db, skm, legacy_migrator, user_id, true).context(
- "In get_with_password_changed: Trying to delete keys from the db.",
- )?;
- //Lskf is now removed in Keystore
- Ok(UserState::Uninitialized)
- } else {
- //Keystore won't be notified when changing to a new password when LSKF is
- //already setup. Therefore, ideally this path wouldn't be reached.
- Ok(UserState::LskfUnlocked(super_key))
- }
- }
- None => {
- //Check if a super key exists in the database or legacy database.
- //If so, return LskfLocked state.
- //Otherwise, i) if the password is provided, initialize the super key and return
- //LskfUnlocked state ii) if password is not provided, return Uninitialized state.
- skm.check_and_initialize_super_key(db, legacy_migrator, user_id, password)
- }
- }
- }
-
- /// Queries user state when serving password unlock requests.
- pub fn get_with_password_unlock(
- db: &mut KeystoreDB,
- legacy_migrator: &LegacyMigrator,
- skm: &SuperKeyManager,
- user_id: UserId,
- password: &Password,
- ) -> Result<UserState> {
- match skm.get_per_boot_key_by_user_id(user_id) {
- Some(super_key) => {
- log::info!("In get_with_password_unlock. Trying to unlock when already unlocked.");
- Ok(UserState::LskfUnlocked(super_key))
- }
- None => {
- //Check if a super key exists in the database or legacy database.
- //If not, return Uninitialized state.
- //Otherwise, try to unlock the super key and if successful,
- //return LskfUnlocked state
- skm.check_and_unlock_super_key(db, legacy_migrator, user_id, password)
- .context("In get_with_password_unlock. Failed to unlock super key.")
- }
- }
- }
-
- /// Delete all the keys created on behalf of the user.
- /// If 'keep_non_super_encrypted_keys' is set to true, delete only the super key and super
- /// encrypted keys.
- pub fn reset_user(
- db: &mut KeystoreDB,
- skm: &SuperKeyManager,
- legacy_migrator: &LegacyMigrator,
- user_id: UserId,
- keep_non_super_encrypted_keys: bool,
- ) -> Result<()> {
- // mark keys created on behalf of the user as unreferenced.
- legacy_migrator
- .bulk_delete_user(user_id, keep_non_super_encrypted_keys)
- .context("In reset_user: Trying to delete legacy keys.")?;
- db.unbind_keys_for_user(user_id, keep_non_super_encrypted_keys)
- .context("In reset user. Error in unbinding keys.")?;
-
- //delete super key in cache, if exists
- skm.forget_all_keys_for_user(user_id);
- Ok(())
- }
-}
-
/// This enum represents three states a KeyMint Blob can be in, w.r.t super encryption.
/// `Sensitive` holds the non encrypted key and a reference to its super key.
/// `NonSensitive` holds a non encrypted key that is never supposed to be encrypted.
diff --git a/keystore2/src/try_insert.rs b/keystore2/src/try_insert.rs
deleted file mode 100644
index 6dd3962..0000000
--- a/keystore2/src/try_insert.rs
+++ /dev/null
@@ -1,100 +0,0 @@
-// Copyright 2021, The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-//! The TryInsert trait adds to Option<T> the method
-//! get_or_try_to_insert_with, which is analogous to
-//! get_or_insert_with, but allows the called function to fail and propagates the failure.
-
-/// The TryInsert trait adds to Option<T> the method
-/// get_or_try_to_insert_with, which is analogous to
-/// get_or_insert_with, but allows the called function to fail and propagates the failure.
-pub trait TryInsert {
- /// Type of the Ok branch of the Result
- type Item;
- /// Inserts a value computed from `f` into the option if it is [`None`],
- /// then returns a mutable reference to the contained value. If `f`
- /// returns Err, the Option is unchanged.
- ///
- /// # Examples
- ///
- /// ```
- /// let mut x = None;
- /// assert_eq!(x.get_or_try_to_insert_with(Err("oops".to_string())), Err("oops".to_string()))
- /// {
- /// let y: &mut u32 = x.get_or_try_to_insert_with(|| Ok(5))?;
- /// assert_eq!(y, &5);
- ///
- /// *y = 7;
- /// }
- ///
- /// assert_eq!(x, Some(7));
- /// ```
- fn get_or_try_to_insert_with<E, F: FnOnce() -> Result<Self::Item, E>>(
- &mut self,
- f: F,
- ) -> Result<&mut Self::Item, E>;
-}
-
-impl<T> TryInsert for Option<T> {
- type Item = T;
- fn get_or_try_to_insert_with<E, F: FnOnce() -> Result<Self::Item, E>>(
- &mut self,
- f: F,
- ) -> Result<&mut Self::Item, E> {
- if self.is_none() {
- *self = Some(f()?);
- }
-
- match self {
- Some(v) => Ok(v),
- // SAFETY: a `None` variant for `self` would have been replaced by a `Some`
- // variant in the code above.
- None => unsafe { std::hint::unreachable_unchecked() },
- }
- }
-}
-
-#[cfg(test)]
-mod test {
- use super::*;
-
- fn fails() -> Result<i32, String> {
- Err("fail".to_string())
- }
-
- fn succeeds() -> Result<i32, String> {
- Ok(99)
- }
-
- #[test]
- fn test() {
- let mut x = None;
- assert_eq!(x.get_or_try_to_insert_with(fails), Err("fail".to_string()));
- assert_eq!(x, None);
- assert_eq!(*x.get_or_try_to_insert_with(succeeds).unwrap(), 99);
- assert_eq!(x, Some(99));
- x = Some(42);
- assert_eq!(*x.get_or_try_to_insert_with(fails).unwrap(), 42);
- assert_eq!(x, Some(42));
- assert_eq!(*x.get_or_try_to_insert_with(succeeds).unwrap(), 42);
- assert_eq!(x, Some(42));
- *x.get_or_try_to_insert_with(fails).unwrap() = 2;
- assert_eq!(x, Some(2));
- *x.get_or_try_to_insert_with(succeeds).unwrap() = 3;
- assert_eq!(x, Some(3));
- x = None;
- *x.get_or_try_to_insert_with(succeeds).unwrap() = 5;
- assert_eq!(x, Some(5));
- }
-}