Simplify control flow for user unlocking.
Keystore2 super key handling is being refactored in preparation for
Unlocked-Only Storage.
Currently, super_key.rs exposes two functions to authorization.rs for
key unlocking:
- unlock_screen_lock_bound_key
- unlock_and_get_user_state
This change simplifies the key_unlocking logic to a single function,
unlock_user. This new function handles all of the unlocking logic and
functions more like a state machine than the previous code.
This change mainly improves readability. It tries not to change
functionality.
Bug: 280502317
Bug: 277798192
Test: Wiped device. Setup user with PIN. Ensured unlock works. Remove
PIN. Ensured unlock works. Added pin and biometric. Ensured unlock
works. Rebooted device. Ensured unlock works.
Change-Id: Ib9a3e907cd40d34c5ecf2a869a65e403deda0254
diff --git a/keystore2/src/authorization.rs b/keystore2/src/authorization.rs
index 1953920..4f2c7bd 100644
--- a/keystore2/src/authorization.rs
+++ b/keystore2/src/authorization.rs
@@ -19,7 +19,6 @@
use crate::error::anyhow_error_to_cstring;
use crate::globals::{ENFORCEMENTS, SUPER_KEY, DB, LEGACY_IMPORTER};
use crate::permission::KeystorePerm;
-use crate::super_key::UserState;
use crate::utils::{check_keystore_permission, watchdog as wd};
use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
HardwareAuthToken::HardwareAuthToken,
@@ -158,31 +157,14 @@
let mut skm = SUPER_KEY.write().unwrap();
DB.with(|db| {
- skm.unlock_screen_lock_bound_key(
+ skm.unlock_user(
&mut db.borrow_mut(),
+ &LEGACY_IMPORTER,
user_id as u32,
&password,
)
})
- .context(ks_err!("unlock_screen_lock_bound_key failed"))?;
-
- // Unlock super key.
- if let UserState::Uninitialized = DB
- .with(|db| {
- skm.unlock_and_get_user_state(
- &mut db.borrow_mut(),
- &LEGACY_IMPORTER,
- user_id as u32,
- &password,
- )
- })
- .context(ks_err!("Unlock with password."))?
- {
- log::info!(
- "In on_lock_screen_event. Trying to unlock when LSKF is uninitialized."
- );
- }
-
+ .context(ks_err!("Unlock with password."))?;
Ok(())
}
(LockScreenEvent::UNLOCK, None) => {
diff --git a/keystore2/src/super_key.rs b/keystore2/src/super_key.rs
index b155349..fc82538 100644
--- a/keystore2/src/super_key.rs
+++ b/keystore2/src/super_key.rs
@@ -480,32 +480,6 @@
}
}
- /// Checks if user has already setup LSKF (i.e. a super key is persisted in the database or the
- /// 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(
- &mut self,
- db: &mut KeystoreDB,
- legacy_importer: &LegacyImporter,
- user_id: UserId,
- pw: &Password,
- ) -> Result<UserState> {
- let alias = &USER_SUPER_KEY;
- let result = legacy_importer
- .with_try_import_super_key(user_id, pw, || db.load_super_key(alias, user_id))
- .context(ks_err!("Failed to load super key"))?;
-
- match result {
- Some((_, entry)) => {
- let super_key = self
- .populate_cache_from_super_key_blob(user_id, alias.algorithm, entry, pw)
- .context(ks_err!())?;
- Ok(UserState::LskfUnlocked(super_key))
- }
- None => Ok(UserState::Uninitialized),
- }
- }
-
// Helper function to populate super key cache from the super key blob loaded from the database.
fn populate_cache_from_super_key_blob(
&mut self,
@@ -665,9 +639,8 @@
match Enforcements::super_encryption_required(domain, key_parameters, flags) {
SuperEncryptionType::None => Ok((key_blob.to_vec(), BlobMetaData::new())),
SuperEncryptionType::LskfBound => {
- // Encrypt the given key blob with the user's per-boot super key, if the per-boot
- // super key is available. If the device is boot-locked or the LSKF is not setup,
- // an error is returned.
+ // Encrypt the given key blob with the user's per-boot super key. If the per-boot
+ // super key is not unlocked or the LSKF is not setup, an error is returned.
match self
.get_user_state(db, legacy_importer, user_id)
.context(ks_err!("Failed to get user state."))?
@@ -1101,28 +1074,50 @@
}
}
- /// 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(
+ /// Unlocks the given user with the given password.
+ ///
+ /// If the user is LskfLocked:
+ /// - Unlock the per_boot super key
+ /// - Unlock the screen_lock_bound super key
+ ///
+ /// If the user is LskfUnlocked:
+ /// - Unlock the screen_lock_bound super key only
+ ///
+ pub fn unlock_user(
&mut self,
db: &mut KeystoreDB,
legacy_importer: &LegacyImporter,
user_id: UserId,
password: &Password,
- ) -> Result<UserState> {
- match self.get_per_boot_key_by_user_id_internal(user_id) {
- Some(super_key) => {
- log::info!("Trying to unlock when already unlocked.");
- Ok(UserState::LskfUnlocked(super_key))
+ ) -> Result<()> {
+ match self.get_user_state(db, legacy_importer, user_id)? {
+ UserState::LskfUnlocked(_) => self.unlock_screen_lock_bound_key(db, user_id, password),
+ UserState::Uninitialized => {
+ Err(Error::sys()).context(ks_err!("Tried to unlock an uninitialized user!"))
}
- 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_importer, user_id, password)
- .context(ks_err!("Failed to unlock super key."))
+ UserState::LskfLocked => {
+ let alias = &USER_SUPER_KEY;
+ let result = legacy_importer
+ .with_try_import_super_key(user_id, password, || {
+ db.load_super_key(alias, user_id)
+ })
+ .context(ks_err!("Failed to load super key"))?;
+
+ match result {
+ Some((_, entry)) => {
+ self.populate_cache_from_super_key_blob(
+ user_id,
+ alias.algorithm,
+ entry,
+ password,
+ )
+ .context(ks_err!("Failed when unlocking user."))?;
+ self.unlock_screen_lock_bound_key(db, user_id, password)
+ }
+ None => {
+ Err(Error::sys()).context(ks_err!("Locked user does not have a super key!"))
+ }
+ }
}
}
}