keystore2: make UnlockedDeviceRequired fix unconditional
Make the fix unconditional and remove all superseded code.
Bug: 299298338
Test: atest -p --include-subdirs system/security/keystore2
Test: atest CtsKeystoreTestCases
Test: atest com.android.server.locksettings
Test: atest TrustManagerServiceTest
Test: atest TrustTests
Change-Id: I99ae3b3ab9fd2dff54793ba455110612d2bd0345
diff --git a/keystore2/aidl/android/security/maintenance/IKeystoreMaintenance.aidl b/keystore2/aidl/android/security/maintenance/IKeystoreMaintenance.aidl
index 50e9828..ecc1f4b 100644
--- a/keystore2/aidl/android/security/maintenance/IKeystoreMaintenance.aidl
+++ b/keystore2/aidl/android/security/maintenance/IKeystoreMaintenance.aidl
@@ -77,21 +77,6 @@
void onUserLskfRemoved(in int userId);
/**
- * Allows LockSettingsService to inform keystore about password change of a user.
- * Callers require 'ChangePassword' permission.
- *
- * ## Error conditions:
- * `ResponseCode::PERMISSION_DENIED` - if the callers does not have the 'ChangePassword'
- * permission.
- * `ResponseCode::SYSTEM_ERROR` - if failed to delete the super encrypted keys of the user.
- * `ResponseCode::Locked' - if the keystore is locked for the given user.
- *
- * @param userId - Android user id
- * @param password - a secret derived from the synthetic password of the user
- */
- void onUserPasswordChanged(in int userId, in @nullable byte[] password);
-
- /**
* This function deletes all keys within a namespace. It mainly gets called when an app gets
* removed and all resources of this app need to be cleaned up.
*
diff --git a/keystore2/src/authorization.rs b/keystore2/src/authorization.rs
index 5a3fdbc..c76f86b 100644
--- a/keystore2/src/authorization.rs
+++ b/keystore2/src/authorization.rs
@@ -150,7 +150,7 @@
&self,
user_id: i32,
unlocking_sids: &[i64],
- mut weak_unlock_enabled: bool,
+ weak_unlock_enabled: bool,
) -> Result<()> {
log::info!(
"on_device_locked(user_id={}, unlocking_sids={:?}, weak_unlock_enabled={})",
@@ -158,9 +158,6 @@
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!("caller missing Lock permission"))?;
ENFORCEMENTS.set_device_locked(user_id, true);
@@ -178,9 +175,6 @@
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!("caller missing Lock permission"))?;
SUPER_KEY.write().unwrap().wipe_plaintext_unlocked_device_required_keys(user_id as u32);
@@ -189,9 +183,6 @@
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!("caller missing Lock permission"))?;
SUPER_KEY.write().unwrap().wipe_all_unlocked_device_required_keys(user_id as u32);
diff --git a/keystore2/src/database.rs b/keystore2/src/database.rs
index a7f6a22..ffc80c9 100644
--- a/keystore2/src/database.rs
+++ b/keystore2/src/database.rs
@@ -2371,15 +2371,8 @@
.context(ks_err!())
}
- /// Delete the keys created on behalf of the user, denoted by the user id.
- /// Delete all the keys unless 'keep_non_super_encrypted_keys' set to true.
- /// Returned boolean is to hint the garbage collector to delete the unbound keys.
- /// The caller of this function should notify the gc if the returned value is true.
- pub fn unbind_keys_for_user(
- &mut self,
- user_id: u32,
- keep_non_super_encrypted_keys: bool,
- ) -> Result<()> {
+ /// Deletes all keys for the given user, including both client keys and super keys.
+ pub fn unbind_keys_for_user(&mut self, user_id: u32) -> Result<()> {
let _wp = wd::watch("KeystoreDB::unbind_keys_for_user");
self.with_transaction(Immediate("TX_unbind_keys_for_user"), |tx| {
@@ -2427,17 +2420,6 @@
let mut notify_gc = false;
for key_id in key_ids {
- if keep_non_super_encrypted_keys {
- // Load metadata and filter out non-super-encrypted keys.
- if let (_, Some((_, blob_metadata)), _, _) =
- Self::load_blob_components(key_id, KeyEntryLoadBits::KM, tx)
- .context(ks_err!("Trying to load blob info."))?
- {
- if blob_metadata.encrypted_by().is_none() {
- continue;
- }
- }
- }
notify_gc = Self::mark_unreferenced(tx, key_id)
.context("In unbind_keys_for_user.")?
|| notify_gc;
@@ -4946,16 +4928,16 @@
#[test]
fn test_unbind_keys_for_user() -> Result<()> {
let mut db = new_test_db()?;
- db.unbind_keys_for_user(1, false)?;
+ db.unbind_keys_for_user(1)?;
make_test_key_entry(&mut db, Domain::APP, 210000, TEST_ALIAS, None)?;
make_test_key_entry(&mut db, Domain::APP, 110000, TEST_ALIAS, None)?;
- db.unbind_keys_for_user(2, false)?;
+ db.unbind_keys_for_user(2)?;
assert_eq!(1, db.list_past_alias(Domain::APP, 110000, KeyType::Client, None)?.len());
assert_eq!(0, db.list_past_alias(Domain::APP, 210000, KeyType::Client, None)?.len());
- db.unbind_keys_for_user(1, true)?;
+ db.unbind_keys_for_user(1)?;
assert_eq!(0, db.list_past_alias(Domain::APP, 110000, KeyType::Client, None)?.len());
Ok(())
@@ -5009,28 +4991,14 @@
assert!(db.load_super_key(&key_name_enc, 2)?.is_some());
assert!(db.load_super_key(&key_name_nonenc, 2)?.is_some());
- // Delete only encrypted keys.
- db.unbind_keys_for_user(1, true)?;
+ // Delete all keys for user 1.
+ db.unbind_keys_for_user(1)?;
- // The encrypted superkey should be gone now.
- assert!(db.load_super_key(&key_name_enc, 1)?.is_none());
- assert!(db.load_super_key(&key_name_nonenc, 1)?.is_some());
-
- // Reinsert the encrypted key.
- db.store_super_key(1, &key_name_enc, &encrypted_super_key, &metadata, &KeyMetaData::new())?;
-
- // Check that both can be found in the database, again..
- assert!(db.load_super_key(&key_name_enc, 1)?.is_some());
- assert!(db.load_super_key(&key_name_nonenc, 1)?.is_some());
-
- // Delete all even unencrypted keys.
- db.unbind_keys_for_user(1, false)?;
-
- // Both should be gone now.
+ // All of user 1's keys should be gone.
assert!(db.load_super_key(&key_name_enc, 1)?.is_none());
assert!(db.load_super_key(&key_name_nonenc, 1)?.is_none());
- // Check that the second pair of keys was untouched.
+ // User 2's keys should not have been touched.
assert!(db.load_super_key(&key_name_enc, 2)?.is_some());
assert!(db.load_super_key(&key_name_nonenc, 2)?.is_some());
diff --git a/keystore2/src/enforcements.rs b/keystore2/src/enforcements.rs
index 95dd026..7038323 100644
--- a/keystore2/src/enforcements.rs
+++ b/keystore2/src/enforcements.rs
@@ -50,8 +50,6 @@
enum AuthRequestState {
/// An outstanding per operation authorization request.
OpAuth,
- /// An outstanding request for per operation authorization and secure timestamp.
- TimeStampedOpAuth(Mutex<Receiver<Result<TimeStampToken, Error>>>),
/// An outstanding request for a timestamp token.
TimeStamp(Mutex<Receiver<Result<TimeStampToken, Error>>>),
}
@@ -59,8 +57,7 @@
#[derive(Debug)]
struct AuthRequest {
state: AuthRequestState,
- /// This need to be set to Some to fulfill a AuthRequestState::OpAuth or
- /// AuthRequestState::TimeStampedOpAuth.
+ /// This need to be set to Some to fulfill an AuthRequestState::OpAuth.
hat: Mutex<Option<HardwareAuthToken>>,
}
@@ -69,13 +66,6 @@
Arc::new(Self { state: AuthRequestState::OpAuth, hat: Mutex::new(None) })
}
- fn timestamped_op_auth(receiver: Receiver<Result<TimeStampToken, Error>>) -> Arc<Self> {
- Arc::new(Self {
- state: AuthRequestState::TimeStampedOpAuth(Mutex::new(receiver)),
- hat: Mutex::new(None),
- })
- }
-
fn timestamp(
hat: HardwareAuthToken,
receiver: Receiver<Result<TimeStampToken, Error>>,
@@ -100,7 +90,7 @@
.context(ks_err!("No operation auth token received."))?;
let tst = match &self.state {
- AuthRequestState::TimeStampedOpAuth(recv) | AuthRequestState::TimeStamp(recv) => {
+ AuthRequestState::TimeStamp(recv) => {
let result = recv
.lock()
.unwrap()
@@ -132,9 +122,6 @@
/// loaded from the database, but it has to be accompanied by a time stamp token to inform
/// the target KM with a different clock about the time on the authenticators.
TimeStampRequired(HardwareAuthToken),
- /// Indicates that both an operation bound auth token and a verification token are
- /// before the operation can commence.
- TimeStampedOpAuthRequired,
/// In this state the auth info is waiting for the deferred authorizations to come in.
/// We block on timestamp tokens, because we can always make progress on these requests.
/// The per-op auth tokens might never come, which means we fail if the client calls
@@ -254,16 +241,6 @@
self.state = DeferredAuthState::Waiting(auth_request);
Some(OperationChallenge { challenge })
}
- DeferredAuthState::TimeStampedOpAuthRequired => {
- let (sender, receiver) = channel::<Result<TimeStampToken, Error>>();
- let auth_request = AuthRequest::timestamped_op_auth(receiver);
- let token_receiver = TokenReceiver(Arc::downgrade(&auth_request));
- ENFORCEMENTS.register_op_auth_receiver(challenge, token_receiver);
-
- ASYNC_TASK.queue_hi(move |_| timestamp_token_request(challenge, sender));
- self.state = DeferredAuthState::Waiting(auth_request);
- Some(OperationChallenge { challenge })
- }
DeferredAuthState::TimeStampRequired(hat) => {
let hat = (*hat).clone();
let (sender, receiver) = channel::<Result<TimeStampToken, Error>>();
@@ -349,9 +326,7 @@
match &self.state {
DeferredAuthState::NoAuthRequired => Ok((None, None)),
DeferredAuthState::Token(hat, tst) => Ok((Some((*hat).clone()), (*tst).clone())),
- DeferredAuthState::OpAuthRequired
- | DeferredAuthState::TimeStampedOpAuthRequired
- | DeferredAuthState::TimeStampRequired(_) => {
+ DeferredAuthState::OpAuthRequired | DeferredAuthState::TimeStampRequired(_) => {
Err(Error::Km(ErrorCode::KEY_USER_NOT_AUTHENTICATED)).context(ks_err!(
"No operation auth token requested??? \
This should not happen."
@@ -599,123 +574,36 @@
}
}
- if android_security_flags::fix_unlocked_device_required_keys_v2() {
- let (hat, state) = if user_secure_ids.is_empty() {
- (None, DeferredAuthState::NoAuthRequired)
- } else if let Some(key_time_out) = key_time_out {
- let hat = Self::find_auth_token(|hat: &AuthTokenEntry| match user_auth_type {
- Some(auth_type) => hat.satisfies(&user_secure_ids, auth_type),
- None => false, // not reachable due to earlier check
- })
- .ok_or(Error::Km(Ec::KEY_USER_NOT_AUTHENTICATED))
- .context(ks_err!("No suitable auth token found."))?;
- let now = BootTime::now();
- let token_age = now
- .checked_sub(&hat.time_received())
- .ok_or_else(Error::sys)
- .context(ks_err!(
- "Overflow while computing Auth token validity. \
- Validity cannot be established."
- ))?;
+ let (hat, state) = if user_secure_ids.is_empty() {
+ (None, DeferredAuthState::NoAuthRequired)
+ } else if let Some(key_time_out) = key_time_out {
+ let hat = Self::find_auth_token(|hat: &AuthTokenEntry| match user_auth_type {
+ Some(auth_type) => hat.satisfies(&user_secure_ids, auth_type),
+ None => false, // not reachable due to earlier check
+ })
+ .ok_or(Error::Km(Ec::KEY_USER_NOT_AUTHENTICATED))
+ .context(ks_err!("No suitable auth token found."))?;
+ let now = BootTime::now();
+ let token_age =
+ now.checked_sub(&hat.time_received()).ok_or_else(Error::sys).context(ks_err!(
+ "Overflow while computing Auth token validity. \
+ Validity cannot be established."
+ ))?;
- if token_age.seconds() > key_time_out {
- return Err(Error::Km(Ec::KEY_USER_NOT_AUTHENTICATED))
- .context(ks_err!("matching auth token is expired."));
- }
- let state = if requires_timestamp {
- DeferredAuthState::TimeStampRequired(hat.auth_token().clone())
- } else {
- DeferredAuthState::NoAuthRequired
- };
- (Some(hat.take_auth_token()), state)
+ if token_age.seconds() > key_time_out {
+ return Err(Error::Km(Ec::KEY_USER_NOT_AUTHENTICATED))
+ .context(ks_err!("matching auth token is expired."));
+ }
+ let state = if requires_timestamp {
+ DeferredAuthState::TimeStampRequired(hat.auth_token().clone())
} else {
- (None, DeferredAuthState::OpAuthRequired)
+ DeferredAuthState::NoAuthRequired
};
- return Ok((hat, AuthInfo { state, key_usage_limited, confirmation_token_receiver }));
- }
-
- if !unlocked_device_required && no_auth_required {
- return Ok((
- None,
- AuthInfo {
- state: DeferredAuthState::NoAuthRequired,
- key_usage_limited,
- confirmation_token_receiver,
- },
- ));
- }
-
- let has_sids = !user_secure_ids.is_empty();
-
- let timeout_bound = key_time_out.is_some() && has_sids;
-
- let per_op_bound = key_time_out.is_none() && has_sids;
-
- let need_auth_token = timeout_bound || unlocked_device_required;
-
- let hat = if need_auth_token {
- let hat = Self::find_auth_token(|hat: &AuthTokenEntry| {
- if let (Some(auth_type), true) = (user_auth_type, timeout_bound) {
- hat.satisfies(&user_secure_ids, auth_type)
- } else {
- unlocked_device_required
- }
- });
- Some(
- hat.ok_or(Error::Km(Ec::KEY_USER_NOT_AUTHENTICATED))
- .context(ks_err!("No suitable auth token found."))?,
- )
+ (Some(hat.take_auth_token()), state)
} else {
- None
+ (None, DeferredAuthState::OpAuthRequired)
};
-
- // Now check the validity of the auth token if the key is timeout bound.
- let hat = match (hat, key_time_out) {
- (Some(hat), Some(key_time_out)) => {
- let now = BootTime::now();
- let token_age = now
- .checked_sub(&hat.time_received())
- .ok_or_else(Error::sys)
- .context(ks_err!(
- "Overflow while computing Auth token validity. \
- Validity cannot be established."
- ))?;
-
- if token_age.seconds() > key_time_out {
- return Err(Error::Km(Ec::KEY_USER_NOT_AUTHENTICATED))
- .context(ks_err!("matching auth token is expired."));
- }
- Some(hat)
- }
- (Some(hat), None) => Some(hat),
- // If timeout_bound is true, above code must have retrieved a HAT or returned with
- // KEY_USER_NOT_AUTHENTICATED. This arm should not be reachable.
- (None, Some(_)) => panic!("Logical error."),
- _ => None,
- };
-
- Ok(match (hat, requires_timestamp, per_op_bound) {
- // Per-op-bound and Some(hat) can only happen if we are both per-op bound and unlocked
- // device required. In addition, this KM instance needs a timestamp token.
- // So the HAT cannot be presented on create. So on update/finish we present both
- // an per-op-bound auth token and a timestamp token.
- (Some(_), true, true) => (None, DeferredAuthState::TimeStampedOpAuthRequired),
- (Some(hat), true, false) => (
- Some(hat.auth_token().clone()),
- DeferredAuthState::TimeStampRequired(hat.take_auth_token()),
- ),
- (Some(hat), false, true) => {
- (Some(hat.take_auth_token()), DeferredAuthState::OpAuthRequired)
- }
- (Some(hat), false, false) => {
- (Some(hat.take_auth_token()), DeferredAuthState::NoAuthRequired)
- }
- (None, _, true) => (None, DeferredAuthState::OpAuthRequired),
- (None, _, false) => (None, DeferredAuthState::NoAuthRequired),
- })
- .map(|(hat, state)| {
- (hat, AuthInfo { state, key_usage_limited, confirmation_token_receiver })
- })
+ Ok((hat, AuthInfo { state, key_usage_limited, confirmation_token_receiver }))
}
fn find_auth_token<F>(p: F) -> Option<AuthTokenEntry>
diff --git a/keystore2/src/maintenance.rs b/keystore2/src/maintenance.rs
index 6c07f0c..43d99d1 100644
--- a/keystore2/src/maintenance.rs
+++ b/keystore2/src/maintenance.rs
@@ -22,7 +22,7 @@
use crate::globals::{DB, LEGACY_IMPORTER, SUPER_KEY};
use crate::ks_err;
use crate::permission::{KeyPerm, KeystorePerm};
-use crate::super_key::{SuperKeyManager, UserState};
+use crate::super_key::SuperKeyManager;
use crate::utils::{
check_get_app_uids_affected_by_sid_permissions, check_key_permission,
check_keystore_permission, uid_to_android_user, watchdog as wd,
@@ -69,40 +69,6 @@
))
}
- 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_keystore_permission(KeystorePerm::ChangePassword).context(ks_err!())?;
-
- let mut skm = SUPER_KEY.write().unwrap();
-
- if let Some(pw) = password.as_ref() {
- DB.with(|db| {
- skm.unlock_unlocked_device_required_keys(&mut db.borrow_mut(), user_id as u32, pw)
- })
- .context(ks_err!("unlock_unlocked_device_required_keys failed"))?;
- }
-
- if let UserState::BeforeFirstUnlock = DB
- .with(|db| skm.get_user_state(&mut db.borrow_mut(), &LEGACY_IMPORTER, user_id as u32))
- .context(ks_err!("Could not get user state while changing password!"))?
- {
- // Error - password can not be changed when the device is locked
- return Err(Error::Rc(ResponseCode::LOCKED)).context(ks_err!("Device is locked."));
- }
-
- DB.with(|db| match password {
- Some(pass) => {
- skm.init_user(&mut db.borrow_mut(), &LEGACY_IMPORTER, user_id as u32, &pass)
- }
- None => {
- // User transitioned to swipe.
- skm.reset_user(&mut db.borrow_mut(), &LEGACY_IMPORTER, user_id as u32)
- }
- })
- .context(ks_err!("Failed to change user password!"))
- }
-
fn add_or_remove_user(&self, user_id: i32) -> Result<()> {
// Check permission. Function should return if this failed. Therefore having '?' at the end
// is very important.
@@ -294,17 +260,6 @@
impl Interface for Maintenance {}
impl IKeystoreMaintenance for Maintenance {
- fn onUserPasswordChanged(&self, user_id: i32, password: Option<&[u8]>) -> BinderResult<()> {
- log::info!(
- "onUserPasswordChanged(user={}, password.is_some()={})",
- user_id,
- password.is_some()
- );
- let _wp = wd::watch("IKeystoreMaintenance::onUserPasswordChanged");
- Self::on_user_password_changed(user_id, password.map(|pw| pw.into()))
- .map_err(into_logged_binder)
- }
-
fn onUserAdded(&self, user_id: i32) -> BinderResult<()> {
log::info!("onUserAdded(user={user_id})");
let _wp = wd::watch("IKeystoreMaintenance::onUserAdded");
diff --git a/keystore2/src/super_key.rs b/keystore2/src/super_key.rs
index 1f9f5f8..706a255 100644
--- a/keystore2/src/super_key.rs
+++ b/keystore2/src/super_key.rs
@@ -576,13 +576,9 @@
pw: &Password,
) -> Result<(Vec<u8>, BlobMetaData)> {
let salt = generate_salt().context("In encrypt_with_password: Failed to generate salt.")?;
- let derived_key = if android_security_flags::fix_unlocked_device_required_keys_v2() {
- pw.derive_key_hkdf(&salt, AES_256_KEY_LENGTH)
- .context(ks_err!("Failed to derive key from password."))?
- } else {
- pw.derive_key_pbkdf2(&salt, AES_256_KEY_LENGTH)
- .context(ks_err!("Failed to derive password."))?
- };
+ let derived_key = pw
+ .derive_key_hkdf(&salt, AES_256_KEY_LENGTH)
+ .context(ks_err!("Failed to derive key from password."))?;
let mut metadata = BlobMetaData::new();
metadata.add(BlobMetaEntry::EncryptedBy(EncryptedBy::Password));
metadata.add(BlobMetaEntry::Salt(salt));
@@ -879,9 +875,7 @@
) {
let entry = self.data.user_keys.entry(user_id).or_default();
if unlocking_sids.is_empty() {
- if android_security_flags::fix_unlocked_device_required_keys_v2() {
- entry.biometric_unlock = None;
- }
+ entry.biometric_unlock = None;
} else if let (Some(aes), Some(ecdh)) = (
entry.unlocked_device_required_symmetric.as_ref().cloned(),
entry.unlocked_device_required_private.as_ref().cloned(),
@@ -984,8 +978,7 @@
user_id: UserId,
) -> Result<()> {
let entry = self.data.user_keys.entry(user_id).or_default();
- if android_security_flags::fix_unlocked_device_required_keys_v2()
- && entry.unlocked_device_required_symmetric.is_some()
+ if entry.unlocked_device_required_symmetric.is_some()
&& entry.unlocked_device_required_private.is_some()
{
// If the keys are already cached in plaintext, then there is no need to decrypt the
@@ -1096,92 +1089,13 @@
legacy_importer
.bulk_delete_user(user_id, false)
.context(ks_err!("Trying to delete legacy keys."))?;
- db.unbind_keys_for_user(user_id, false).context(ks_err!("Error in unbinding keys."))?;
+ db.unbind_keys_for_user(user_id).context(ks_err!("Error in unbinding keys."))?;
// Delete super key in cache, if exists.
self.forget_all_keys_for_user(user_id);
Ok(())
}
- /// Deletes all authentication bound keys and super keys for the given user. The user must be
- /// unlocked before this function is called. This function is used to transition a user to
- /// swipe.
- pub fn reset_user(
- &mut self,
- db: &mut KeystoreDB,
- legacy_importer: &LegacyImporter,
- user_id: UserId,
- ) -> Result<()> {
- log::info!("reset_user(user={user_id})");
- match self.get_user_state(db, legacy_importer, user_id)? {
- UserState::Uninitialized => {
- Err(Error::sys()).context(ks_err!("Tried to reset an uninitialized user!"))
- }
- UserState::BeforeFirstUnlock => {
- Err(Error::sys()).context(ks_err!("Tried to reset a locked user's password!"))
- }
- UserState::AfterFirstUnlock(_) => {
- // Mark keys created on behalf of the user as unreferenced.
- legacy_importer
- .bulk_delete_user(user_id, true)
- .context(ks_err!("Trying to delete legacy keys."))?;
- db.unbind_keys_for_user(user_id, true)
- .context(ks_err!("Error in unbinding keys."))?;
-
- // Delete super key in cache, if exists.
- self.forget_all_keys_for_user(user_id);
- Ok(())
- }
- }
- }
-
- /// If the user hasn't been initialized yet, then this function generates the user's
- /// AfterFirstUnlock super key and sets the user's state to AfterFirstUnlock. Otherwise this
- /// function returns an error.
- pub fn init_user(
- &mut self,
- db: &mut KeystoreDB,
- legacy_importer: &LegacyImporter,
- user_id: UserId,
- password: &Password,
- ) -> Result<()> {
- log::info!("init_user(user={user_id})");
- match self.get_user_state(db, legacy_importer, user_id)? {
- UserState::AfterFirstUnlock(_) | UserState::BeforeFirstUnlock => {
- Err(Error::sys()).context(ks_err!("Tried to re-init an initialized user!"))
- }
- UserState::Uninitialized => {
- // Generate a new super key.
- let super_key =
- generate_aes256_key().context(ks_err!("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.
- let (encrypted_super_key, blob_metadata) =
- Self::encrypt_with_password(&super_key, password)
- .context(ks_err!("Failed to encrypt super key with password!"))?;
-
- let key_entry = db
- .store_super_key(
- user_id,
- &USER_AFTER_FIRST_UNLOCK_SUPER_KEY,
- &encrypted_super_key,
- &blob_metadata,
- &KeyMetaData::new(),
- )
- .context(ks_err!("Failed to store super key."))?;
-
- self.populate_cache_from_super_key_blob(
- user_id,
- USER_AFTER_FIRST_UNLOCK_SUPER_KEY.algorithm,
- key_entry,
- password,
- )
- .context(ks_err!("Failed to initialize user!"))?;
- Ok(())
- }
- }
- }
-
/// Initializes the given user by creating their super keys, both AfterFirstUnlock and
/// UnlockedDeviceRequired. If allow_existing is true, then the user already being initialized
/// is not considered an error.
@@ -1354,7 +1268,7 @@
assert!(skm
.write()
.unwrap()
- .init_user(&mut keystore_db, &legacy_importer, USER_ID, pw)
+ .initialize_user(&mut keystore_db, &legacy_importer, USER_ID, pw, false)
.is_ok());
(skm, keystore_db, legacy_importer)
}
@@ -1405,7 +1319,7 @@
}
#[test]
- fn test_init_user() {
+ fn test_initialize_user() {
let pw: Password = generate_password_blob();
let (skm, mut keystore_db, legacy_importer) = setup_test(&pw);
assert_unlocked(
@@ -1598,98 +1512,6 @@
.unwrap());
}
- fn test_user_reset(locked: bool) {
- let pw: Password = generate_password_blob();
- let (skm, mut keystore_db, legacy_importer) = setup_test(&pw);
- assert_unlocked(
- &skm,
- &mut keystore_db,
- &legacy_importer,
- USER_ID,
- "The user was not unlocked after initialization!",
- );
-
- assert!(make_test_key_entry(
- &mut keystore_db,
- Domain::APP,
- USER_ID.into(),
- TEST_KEY_ALIAS,
- None
- )
- .is_ok());
- assert!(make_bootlevel_key_entry(
- &mut keystore_db,
- Domain::APP,
- USER_ID.into(),
- TEST_BOOT_KEY_ALIAS,
- false
- )
- .is_ok());
- assert!(keystore_db
- .key_exists(Domain::APP, USER_ID.into(), TEST_KEY_ALIAS, KeyType::Client)
- .unwrap());
- assert!(keystore_db
- .key_exists(Domain::APP, USER_ID.into(), TEST_BOOT_KEY_ALIAS, KeyType::Client)
- .unwrap());
-
- if locked {
- skm.write().unwrap().data.user_keys.clear();
- assert_locked(
- &skm,
- &mut keystore_db,
- &legacy_importer,
- USER_ID,
- "Clearing the cache did not lock the user!",
- );
- assert!(skm
- .write()
- .unwrap()
- .reset_user(&mut keystore_db, &legacy_importer, USER_ID)
- .is_err());
- assert_locked(
- &skm,
- &mut keystore_db,
- &legacy_importer,
- USER_ID,
- "User state should not have changed!",
- );
-
- // Keys should still exist.
- assert!(keystore_db
- .key_exists(Domain::APP, USER_ID.into(), TEST_KEY_ALIAS, KeyType::Client)
- .unwrap());
- assert!(keystore_db
- .key_exists(Domain::APP, USER_ID.into(), TEST_BOOT_KEY_ALIAS, KeyType::Client)
- .unwrap());
- } else {
- assert!(skm
- .write()
- .unwrap()
- .reset_user(&mut keystore_db, &legacy_importer, USER_ID)
- .is_ok());
- assert_uninitialized(
- &skm,
- &mut keystore_db,
- &legacy_importer,
- USER_ID,
- "The user was not reset!",
- );
- assert!(!skm
- .write()
- .unwrap()
- .super_key_exists_in_db_for_user(&mut keystore_db, &legacy_importer, USER_ID)
- .unwrap());
-
- // Auth bound key should no longer exist.
- assert!(!keystore_db
- .key_exists(Domain::APP, USER_ID.into(), TEST_KEY_ALIAS, KeyType::Client)
- .unwrap());
- assert!(keystore_db
- .key_exists(Domain::APP, USER_ID.into(), TEST_BOOT_KEY_ALIAS, KeyType::Client)
- .unwrap());
- }
- }
-
#[test]
fn test_remove_unlocked_user() {
test_user_removal(false);
@@ -1699,14 +1521,4 @@
fn test_remove_locked_user() {
test_user_removal(true);
}
-
- #[test]
- fn test_reset_unlocked_user() {
- test_user_reset(false);
- }
-
- #[test]
- fn test_reset_locked_user() {
- test_user_reset(true);
- }
}