Implement onLockScreenEvent method of IKeystoreAuthorization AIDL interface.
In addition, this CL creates a global instance of LegacyBlobLoader.
Bug: 159475191,166672367
Test: TBD
Change-Id: I04005238f973b5eae98a07400688ea17edba80f8
diff --git a/keystore2/src/authorization.rs b/keystore2/src/authorization.rs
index 409feba..ba27df8 100644
--- a/keystore2/src/authorization.rs
+++ b/keystore2/src/authorization.rs
@@ -14,8 +14,9 @@
//! This module implements IKeyAuthorization AIDL interface.
+use crate::error::Error as KeystoreError;
use crate::error::map_or_log_err;
-use crate::globals::ENFORCEMENTS;
+use crate::globals::{DB, ENFORCEMENTS, LEGACY_BLOB_LOADER, SUPER_KEY};
use crate::permission::KeystorePerm;
use crate::utils::check_keystore_permission;
use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
@@ -28,6 +29,8 @@
use android_security_authorization:: aidl::android::security::authorization::IKeystoreAuthorization::{
BnKeystoreAuthorization, IKeystoreAuthorization,
};
+use android_security_authorization:: aidl::android::security::authorization::LockScreenEvent::LockScreenEvent;
+use android_system_keystore2::aidl::android::system::keystore2::ResponseCode::ResponseCode;
use anyhow::{Context, Result};
use binder::IBinder;
@@ -59,6 +62,59 @@
ENFORCEMENTS.add_auth_token(auth_token_copy)?;
Ok(())
}
+
+ fn on_lock_screen_event(
+ &self,
+ lock_screen_event: LockScreenEvent,
+ user_id: i32,
+ password: Option<&[u8]>,
+ ) -> Result<()> {
+ match (lock_screen_event, password) {
+ (LockScreenEvent::UNLOCK, Some(user_password)) => {
+ //This corresponds to the unlock() method in legacy keystore API.
+ //check permission
+ check_keystore_permission(KeystorePerm::unlock())
+ .context("In on_lock_screen_event: Unlock with password.")?;
+ ENFORCEMENTS.set_device_locked(user_id, false);
+ // Unlock super key.
+ DB.with::<_, Result<()>>(|db| {
+ let mut db = db.borrow_mut();
+ //TODO - b/176123105 - Once the user management API is implemented, unlock is
+ //allowed only if the user is added. Then the two tasks handled by the
+ //unlock_user_key will be split into two methods. For now, unlock_user_key
+ //method is used as it is, which created a super key for the user if one does
+ //not exists, in addition to unlocking the existing super key of the user/
+ SUPER_KEY.unlock_user_key(
+ user_id as u32,
+ user_password,
+ &mut db,
+ &LEGACY_BLOB_LOADER,
+ )?;
+ Ok(())
+ })
+ .context("In on_lock_screen_event.")?;
+
+ Ok(())
+ }
+ (LockScreenEvent::UNLOCK, None) => {
+ check_keystore_permission(KeystorePerm::unlock())
+ .context("In on_lock_screen_event: Unlock.")?;
+ ENFORCEMENTS.set_device_locked(user_id, false);
+ Ok(())
+ }
+ (LockScreenEvent::LOCK, None) => {
+ check_keystore_permission(KeystorePerm::lock())
+ .context("In on_lock_screen_event: Lock")?;
+ ENFORCEMENTS.set_device_locked(user_id, true);
+ Ok(())
+ }
+ _ => {
+ // Any other combination is not supported.
+ Err(KeystoreError::Rc(ResponseCode::INVALID_ARGUMENT))
+ .context("In on_lock_screen_event: Unknown event.")
+ }
+ }
+ }
}
impl Interface for AuthorizationManager {}
@@ -67,4 +123,13 @@
fn addAuthToken(&self, auth_token: &HardwareAuthToken) -> BinderResult<()> {
map_or_log_err(self.add_auth_token(auth_token), Ok)
}
+
+ fn onLockScreenEvent(
+ &self,
+ lock_screen_event: LockScreenEvent,
+ user_id: i32,
+ password: Option<&[u8]>,
+ ) -> BinderResult<()> {
+ map_or_log_err(self.on_lock_screen_event(lock_screen_event, user_id, password), Ok)
+ }
}
diff --git a/keystore2/src/enforcements.rs b/keystore2/src/enforcements.rs
index 93e077c..4ff3950 100644
--- a/keystore2/src/enforcements.rs
+++ b/keystore2/src/enforcements.rs
@@ -211,6 +211,7 @@
let mut user_secure_ids = Vec::<i64>::new();
let mut key_time_out: Option<i64> = None;
let mut allow_while_on_body = false;
+ let mut unlocked_device_required = false;
// iterate through key parameters, recording information we need for authorization
// enforcements later, or enforcing authorizations in place, where applicable
@@ -267,12 +268,7 @@
user_id = *u;
}
KeyParameterValue::UnlockedDeviceRequired => {
- // check the device locked status. If locked, operations on the key are not
- // allowed.
- if self.is_device_locked(user_id) {
- return Err(KeystoreError::Km(Ec::DEVICE_LOCKED))
- .context("In authorize_create: device is locked.");
- }
+ unlocked_device_required = true;
}
KeyParameterValue::AllowWhileOnBody => {
allow_while_on_body = true;
@@ -320,6 +316,16 @@
);
}
+ if unlocked_device_required {
+ // check the device locked status. If locked, operations on the key are not
+ // allowed.
+ log::info!("Checking for lockd device of user {}.", user_id);
+ if self.is_device_locked(user_id) {
+ return Err(KeystoreError::Km(Ec::DEVICE_LOCKED))
+ .context("In authorize_create: device is locked.");
+ }
+ }
+
if !user_secure_ids.is_empty() {
// key requiring authentication per operation
if !is_time_out_key {
diff --git a/keystore2/src/globals.rs b/keystore2/src/globals.rs
index 3c79eed..7ceff26 100644
--- a/keystore2/src/globals.rs
+++ b/keystore2/src/globals.rs
@@ -20,6 +20,7 @@
use crate::background_task_handler::BackgroundTaskHandler;
use crate::enforcements::Enforcements;
use crate::gc::Gc;
+use crate::legacy_blob::LegacyBlobLoader;
use crate::super_key::SuperKeyManager;
use crate::utils::Asp;
use crate::{
@@ -91,6 +92,10 @@
/// The other modules (e.g. enforcements) communicate with it via a channel initialized during
/// keystore startup.
pub static ref BACKGROUND_TASK_HANDLER: BackgroundTaskHandler = BackgroundTaskHandler::new();
+ /// LegacyBlobLoader is initialized and exists globally.
+ /// The same directory used by the database is used by the LegacyBlobLoader as well.
+ pub static ref LEGACY_BLOB_LOADER: LegacyBlobLoader = LegacyBlobLoader::new(
+ &std::env::current_dir().expect("Could not get the current working directory."));
}
static KEYMINT_SERVICE_NAME: &str = "android.hardware.security.keymint.IKeyMintDevice";
diff --git a/keystore2/src/security_level.rs b/keystore2/src/security_level.rs
index 7a87e8d..943f69f 100644
--- a/keystore2/src/security_level.rs
+++ b/keystore2/src/security_level.rs
@@ -33,6 +33,7 @@
use crate::auth_token_handler::AuthTokenHandler;
use crate::globals::ENFORCEMENTS;
use crate::key_parameter::KeyParameter as KsKeyParam;
+use crate::key_parameter::KeyParameterValue as KsKeyParamValue;
use crate::utils::{check_key_permission, Asp};
use crate::{database::KeyIdGuard, globals::DB};
use crate::{
@@ -47,6 +48,7 @@
use crate::{
error::{self, map_km_error, map_or_log_err, Error, ErrorCode},
utils::key_characteristics_to_internal,
+ utils::uid_to_android_user,
};
use anyhow::{Context, Result};
use binder::{IBinder, Interface, ThreadState};
@@ -83,6 +85,7 @@
&self,
key: KeyDescriptor,
creation_result: KeyCreationResult,
+ user_id: u32,
) -> Result<KeyMetadata> {
let KeyCreationResult {
keyBlob: key_blob,
@@ -108,7 +111,12 @@
},
);
- let key_parameters = key_characteristics_to_internal(key_characteristics);
+ let mut key_parameters = key_characteristics_to_internal(key_characteristics);
+
+ key_parameters.push(KsKeyParam::new(
+ KsKeyParamValue::UserID(user_id as i32),
+ SecurityLevel::SOFTWARE,
+ ));
let creation_date = DateTime::now().context("Trying to make creation time.")?;
@@ -335,11 +343,12 @@
return Err(error::Error::Km(ErrorCode::INVALID_ARGUMENT))
.context("In generate_key: Alias must be specified");
}
+ let caller_uid = ThreadState::get_calling_uid();
let key = match key.domain {
Domain::APP => KeyDescriptor {
domain: key.domain,
- nspace: ThreadState::get_calling_uid() as i64,
+ nspace: caller_uid as i64,
alias: key.alias.clone(),
blob: None,
},
@@ -353,7 +362,8 @@
map_km_error(km_dev.addRngEntropy(entropy))?;
let creation_result = map_km_error(km_dev.generateKey(¶ms))?;
- self.store_new_key(key, creation_result).context("In generate_key.")
+ let user_id = uid_to_android_user(caller_uid);
+ self.store_new_key(key, creation_result, user_id).context("In generate_key.")
}
fn import_key(
@@ -368,11 +378,12 @@
return Err(error::Error::Km(ErrorCode::INVALID_ARGUMENT))
.context("In import_key: Alias must be specified");
}
+ let caller_uid = ThreadState::get_calling_uid();
let key = match key.domain {
Domain::APP => KeyDescriptor {
domain: key.domain,
- nspace: ThreadState::get_calling_uid() as i64,
+ nspace: caller_uid as i64,
alias: key.alias.clone(),
blob: None,
},
@@ -401,7 +412,8 @@
let km_dev: Box<dyn IKeyMintDevice> = self.keymint.get_interface()?;
let creation_result = map_km_error(km_dev.importKey(¶ms, format, key_data))?;
- self.store_new_key(key, creation_result).context("In import_key.")
+ let user_id = uid_to_android_user(caller_uid);
+ self.store_new_key(key, creation_result, user_id).context("In import_key.")
}
fn import_wrapped_key(
@@ -432,10 +444,11 @@
}
};
+ let caller_uid = ThreadState::get_calling_uid();
let key = match key.domain {
Domain::APP => KeyDescriptor {
domain: key.domain,
- nspace: ThreadState::get_calling_uid() as i64,
+ nspace: caller_uid as i64,
alias: key.alias.clone(),
blob: None,
},
@@ -451,7 +464,7 @@
wrapping_key.clone(),
KeyType::Client,
KeyEntryLoadBits::KM,
- ThreadState::get_calling_uid(),
+ caller_uid,
|k, av| check_key_permission(KeyPerm::use_(), k, &av),
)
})
@@ -509,7 +522,8 @@
},
)?;
- self.store_new_key(key, creation_result).context("In import_wrapped_key.")
+ let user_id = uid_to_android_user(caller_uid);
+ self.store_new_key(key, creation_result, user_id).context("In import_wrapped_key.")
}
fn upgrade_keyblob_if_required_with<T, F>(