Fix UnlockedDeviceRequired with weak unlock methods
Starting in Android 12, unlocking the device with a class 1
("convenience") biometric, class 2 ("weak") biometric, or a trust agent
unexpectedly doesn't allow the use of UnlockedDeviceRequired keys. The
cause of this bug is that the cryptographic protection that Keystore now
applies to UnlockedDeviceRequired keys incorrectly assumes that the
device can only be unlocked using LSKF or via a biometric that
participates in Keystore (has a SID and uses HardwareAuthTokens).
Actually, Keyguard also allows the device to be unlocked using weaker
biometrics that do not particiate in Keystore, if they are enrolled.
Similarly, there are also cases where a trust agent can actively unlock
the device, e.g. unlocking a phone using a paired watch.
In combination with the system_server changes in
I34dc49f1338e94755e96c1cf84de0638dc70d311, this CL fixes the bug by
making Keystore retain the UnlockedDeviceRequired super keys in memory
if a weak unlock method is enabled at device lock time. This does mean
that UnlockedDeviceRequired is enforced only logically when a weak
unlock method is enabled, but this is the best we can do in this case.
This CL also adds methods by which Keystore can be notified of the
expiration of unlock methods, causing the security level of
UnlockedDeviceRequired keys to be upgraded. A future CL for
system_server is planned to use these.
Test: see I34dc49f1338e94755e96c1cf84de0638dc70d311
Bug: 296464083
Change-Id: I1b0d9ec4f9e31dc91642e865045766bd17e34cad
diff --git a/keystore2/src/authorization.rs b/keystore2/src/authorization.rs
index 36f94e9..f956787 100644
--- a/keystore2/src/authorization.rs
+++ b/keystore2/src/authorization.rs
@@ -164,9 +164,21 @@
}
}
- fn on_device_locked(&self, user_id: i32, unlocking_sids: &[i64]) -> Result<()> {
- log::info!("on_device_locked(user_id={}, unlocking_sids={:?})", user_id, unlocking_sids);
-
+ fn on_device_locked(
+ &self,
+ user_id: i32,
+ unlocking_sids: &[i64],
+ mut weak_unlock_enabled: bool,
+ ) -> Result<()> {
+ log::info!(
+ "on_device_locked(user_id={}, unlocking_sids={:?}, weak_unlock_enabled={})",
+ user_id,
+ unlocking_sids,
+ weak_unlock_enabled
+ );
+ if !android_security_flags::fix_unlocked_device_required_keys_v2() {
+ weak_unlock_enabled = false;
+ }
check_keystore_permission(KeystorePerm::Lock).context(ks_err!("Lock"))?;
ENFORCEMENTS.set_device_locked(user_id, true);
let mut skm = SUPER_KEY.write().unwrap();
@@ -175,11 +187,32 @@
&mut db.borrow_mut(),
user_id as u32,
unlocking_sids,
+ weak_unlock_enabled,
);
});
Ok(())
}
+ fn on_weak_unlock_methods_expired(&self, user_id: i32) -> Result<()> {
+ log::info!("on_weak_unlock_methods_expired(user_id={})", user_id);
+ if !android_security_flags::fix_unlocked_device_required_keys_v2() {
+ return Ok(());
+ }
+ check_keystore_permission(KeystorePerm::Lock).context(ks_err!("Lock"))?;
+ SUPER_KEY.write().unwrap().wipe_plaintext_unlocked_device_required_keys(user_id as u32);
+ Ok(())
+ }
+
+ fn on_non_lskf_unlock_methods_expired(&self, user_id: i32) -> Result<()> {
+ log::info!("on_non_lskf_unlock_methods_expired(user_id={})", user_id);
+ if !android_security_flags::fix_unlocked_device_required_keys_v2() {
+ return Ok(());
+ }
+ check_keystore_permission(KeystorePerm::Lock).context(ks_err!("Lock"))?;
+ SUPER_KEY.write().unwrap().wipe_all_unlocked_device_required_keys(user_id as u32);
+ Ok(())
+ }
+
fn get_auth_tokens_for_credstore(
&self,
challenge: i64,
@@ -240,9 +273,24 @@
map_or_log_err(self.on_device_unlocked(user_id, password.map(|pw| pw.into())), Ok)
}
- fn onDeviceLocked(&self, user_id: i32, unlocking_sids: &[i64]) -> BinderResult<()> {
+ fn onDeviceLocked(
+ &self,
+ user_id: i32,
+ unlocking_sids: &[i64],
+ weak_unlock_enabled: bool,
+ ) -> BinderResult<()> {
let _wp = wd::watch_millis("IKeystoreAuthorization::onDeviceLocked", 500);
- map_or_log_err(self.on_device_locked(user_id, unlocking_sids), Ok)
+ map_or_log_err(self.on_device_locked(user_id, unlocking_sids, weak_unlock_enabled), Ok)
+ }
+
+ fn onWeakUnlockMethodsExpired(&self, user_id: i32) -> BinderResult<()> {
+ let _wp = wd::watch_millis("IKeystoreAuthorization::onWeakUnlockMethodsExpired", 500);
+ map_or_log_err(self.on_weak_unlock_methods_expired(user_id), Ok)
+ }
+
+ fn onNonLskfUnlockMethodsExpired(&self, user_id: i32) -> BinderResult<()> {
+ let _wp = wd::watch_millis("IKeystoreAuthorization::onNonLskfUnlockMethodsExpired", 500);
+ map_or_log_err(self.on_non_lskf_unlock_methods_expired(user_id), Ok)
}
fn getAuthTokensForCredStore(