Merge "Add getLastAuthTime() to IKeystoreAuthorization" into main am: 855f233004
am: 703e6f78d5
am: 02b555a220
Original change: https://android-review.googlesource.com/c/platform/system/security/+/2770182 Change-Id: I9671a4d0782eb8e44ded4c5bfd5961387f874645 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
commit
d5091d289e
9 changed files with 165 additions and 11 deletions
|
@ -41,6 +41,7 @@ rust_defaults {
|
||||||
"android.security.maintenance-rust",
|
"android.security.maintenance-rust",
|
||||||
"android.security.metrics-rust",
|
"android.security.metrics-rust",
|
||||||
"android.security.rkp_aidl-rust",
|
"android.security.rkp_aidl-rust",
|
||||||
|
"libaconfig_android_hardware_biometrics_rust",
|
||||||
"libanyhow",
|
"libanyhow",
|
||||||
"libbinder_rs",
|
"libbinder_rs",
|
||||||
"libkeystore2_aaid-rust",
|
"libkeystore2_aaid-rust",
|
||||||
|
@ -161,3 +162,9 @@ rust_aconfig_library {
|
||||||
crate_name: "keystore2_flags",
|
crate_name: "keystore2_flags",
|
||||||
aconfig_declarations: "keystore2_flags",
|
aconfig_declarations: "keystore2_flags",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rust_aconfig_library {
|
||||||
|
name: "libaconfig_android_hardware_biometrics_rust",
|
||||||
|
crate_name: "aconfig_android_hardware_biometrics_rust",
|
||||||
|
aconfig_declarations: "android.hardware.biometrics.flags-aconfig",
|
||||||
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
package android.security.authorization;
|
package android.security.authorization;
|
||||||
|
|
||||||
import android.hardware.security.keymint.HardwareAuthToken;
|
import android.hardware.security.keymint.HardwareAuthToken;
|
||||||
|
import android.hardware.security.keymint.HardwareAuthenticatorType;
|
||||||
import android.security.authorization.LockScreenEvent;
|
import android.security.authorization.LockScreenEvent;
|
||||||
import android.security.authorization.AuthorizationTokens;
|
import android.security.authorization.AuthorizationTokens;
|
||||||
|
|
||||||
|
@ -108,4 +109,13 @@ interface IKeystoreAuthorization {
|
||||||
*/
|
*/
|
||||||
AuthorizationTokens getAuthTokensForCredStore(in long challenge, in long secureUserId,
|
AuthorizationTokens getAuthTokensForCredStore(in long challenge, in long secureUserId,
|
||||||
in long authTokenMaxAgeMillis);
|
in long authTokenMaxAgeMillis);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the last successful authentication time since boot for the given user with any of the
|
||||||
|
* given authenticator types. This is determined by inspecting the cached auth tokens.
|
||||||
|
*
|
||||||
|
* ## Error conditions:
|
||||||
|
* `ResponseCode::NO_AUTH_TOKEN_FOUND` - if there is no matching authentication token found
|
||||||
|
*/
|
||||||
|
long getLastAuthTime(in long secureUserId, in HardwareAuthenticatorType[] authTypes);
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,27 +14,30 @@
|
||||||
|
|
||||||
//! This module implements IKeystoreAuthorization AIDL interface.
|
//! This module implements IKeystoreAuthorization AIDL interface.
|
||||||
|
|
||||||
use crate::ks_err;
|
|
||||||
use crate::error::Error as KeystoreError;
|
|
||||||
use crate::error::anyhow_error_to_cstring;
|
use crate::error::anyhow_error_to_cstring;
|
||||||
use crate::globals::{ENFORCEMENTS, SUPER_KEY, DB, LEGACY_IMPORTER};
|
use crate::error::Error as KeystoreError;
|
||||||
|
use crate::globals::{DB, ENFORCEMENTS, LEGACY_IMPORTER, SUPER_KEY};
|
||||||
|
use crate::ks_err;
|
||||||
use crate::permission::KeystorePerm;
|
use crate::permission::KeystorePerm;
|
||||||
use crate::utils::{check_keystore_permission, watchdog as wd};
|
use crate::utils::{check_keystore_permission, watchdog as wd};
|
||||||
|
use aconfig_android_hardware_biometrics_rust;
|
||||||
use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
|
use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
|
||||||
HardwareAuthToken::HardwareAuthToken,
|
HardwareAuthToken::HardwareAuthToken, HardwareAuthenticatorType::HardwareAuthenticatorType,
|
||||||
};
|
};
|
||||||
use android_security_authorization::binder::{BinderFeatures, ExceptionCode, Interface, Result as BinderResult,
|
|
||||||
Strong, Status as BinderStatus};
|
|
||||||
use android_security_authorization::aidl::android::security::authorization::{
|
use android_security_authorization::aidl::android::security::authorization::{
|
||||||
IKeystoreAuthorization::BnKeystoreAuthorization, IKeystoreAuthorization::IKeystoreAuthorization,
|
AuthorizationTokens::AuthorizationTokens, IKeystoreAuthorization::BnKeystoreAuthorization,
|
||||||
LockScreenEvent::LockScreenEvent, AuthorizationTokens::AuthorizationTokens,
|
IKeystoreAuthorization::IKeystoreAuthorization, LockScreenEvent::LockScreenEvent,
|
||||||
ResponseCode::ResponseCode,
|
ResponseCode::ResponseCode,
|
||||||
};
|
};
|
||||||
use android_system_keystore2::aidl::android::system::keystore2::{
|
use android_security_authorization::binder::{
|
||||||
ResponseCode::ResponseCode as KsResponseCode};
|
BinderFeatures, ExceptionCode, Interface, Result as BinderResult, Status as BinderStatus,
|
||||||
|
Strong,
|
||||||
|
};
|
||||||
|
use android_system_keystore2::aidl::android::system::keystore2::ResponseCode::ResponseCode as KsResponseCode;
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
use keystore2_crypto::Password;
|
use keystore2_crypto::Password;
|
||||||
use keystore2_selinux as selinux;
|
use keystore2_selinux as selinux;
|
||||||
|
use std::ffi::CString;
|
||||||
|
|
||||||
/// This is the Authorization error type, it wraps binder exceptions and the
|
/// This is the Authorization error type, it wraps binder exceptions and the
|
||||||
/// Authorization ResponseCode
|
/// Authorization ResponseCode
|
||||||
|
@ -226,6 +229,31 @@ impl AuthorizationManager {
|
||||||
ENFORCEMENTS.get_auth_tokens(challenge, secure_user_id, auth_token_max_age_millis)?;
|
ENFORCEMENTS.get_auth_tokens(challenge, secure_user_id, auth_token_max_age_millis)?;
|
||||||
Ok(AuthorizationTokens { authToken: auth_token, timestampToken: ts_token })
|
Ok(AuthorizationTokens { authToken: auth_token, timestampToken: ts_token })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_last_auth_time(
|
||||||
|
&self,
|
||||||
|
secure_user_id: i64,
|
||||||
|
auth_types: &[HardwareAuthenticatorType],
|
||||||
|
) -> Result<i64> {
|
||||||
|
// Check keystore permission.
|
||||||
|
check_keystore_permission(KeystorePerm::GetLastAuthTime).context(ks_err!())?;
|
||||||
|
|
||||||
|
let mut max_time: i64 = -1;
|
||||||
|
for auth_type in auth_types.iter() {
|
||||||
|
if let Some(time) = ENFORCEMENTS.get_last_auth_time(secure_user_id, *auth_type) {
|
||||||
|
if time.milliseconds() > max_time {
|
||||||
|
max_time = time.milliseconds();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if max_time >= 0 {
|
||||||
|
Ok(max_time)
|
||||||
|
} else {
|
||||||
|
Err(Error::Rc(ResponseCode::NO_AUTH_TOKEN_FOUND))
|
||||||
|
.context(ks_err!("No auth token found"))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Interface for AuthorizationManager {}
|
impl Interface for AuthorizationManager {}
|
||||||
|
@ -274,4 +302,19 @@ impl IKeystoreAuthorization for AuthorizationManager {
|
||||||
Ok,
|
Ok,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn getLastAuthTime(
|
||||||
|
&self,
|
||||||
|
secure_user_id: i64,
|
||||||
|
auth_types: &[HardwareAuthenticatorType],
|
||||||
|
) -> binder::Result<i64> {
|
||||||
|
if aconfig_android_hardware_biometrics_rust::last_authentication_time() {
|
||||||
|
map_or_log_err(self.get_last_auth_time(secure_user_id, auth_types), Ok)
|
||||||
|
} else {
|
||||||
|
Err(BinderStatus::new_service_specific_error(
|
||||||
|
ResponseCode::PERMISSION_DENIED.0,
|
||||||
|
Some(CString::new("Feature is not enabled.").unwrap().as_c_str()),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -845,6 +845,24 @@ impl Enforcements {
|
||||||
get_timestamp_token(challenge).context(ks_err!("Error in getting timestamp token."))?;
|
get_timestamp_token(challenge).context(ks_err!("Error in getting timestamp token."))?;
|
||||||
Ok((auth_token, tst))
|
Ok((auth_token, tst))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Finds the most recent received time for an auth token that matches the given secure user id and authenticator
|
||||||
|
pub fn get_last_auth_time(
|
||||||
|
&self,
|
||||||
|
secure_user_id: i64,
|
||||||
|
auth_type: HardwareAuthenticatorType,
|
||||||
|
) -> Option<MonotonicRawTime> {
|
||||||
|
let sids: Vec<i64> = vec![secure_user_id];
|
||||||
|
|
||||||
|
let result =
|
||||||
|
Self::find_auth_token(|entry: &AuthTokenEntry| entry.satisfies(&sids, auth_type));
|
||||||
|
|
||||||
|
if let Some((auth_token_entry, _)) = result {
|
||||||
|
Some(auth_token_entry.time_received())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Add tests to enforcement module (b/175578618).
|
// TODO: Add tests to enforcement module (b/175578618).
|
||||||
|
|
|
@ -149,6 +149,9 @@ implement_class!(
|
||||||
/// Checked on calls to IRemotelyProvisionedKeyPool::getAttestationKey
|
/// Checked on calls to IRemotelyProvisionedKeyPool::getAttestationKey
|
||||||
#[selinux(name = get_attestation_key)]
|
#[selinux(name = get_attestation_key)]
|
||||||
GetAttestationKey,
|
GetAttestationKey,
|
||||||
|
/// Checked on IKeystoreAuthorization::getLastAuthTime() is called.
|
||||||
|
#[selinux(name = get_last_auth_time)]
|
||||||
|
GetLastAuthTime,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -39,6 +39,7 @@ rust_defaults {
|
||||||
"libserde",
|
"libserde",
|
||||||
"libserde_cbor",
|
"libserde_cbor",
|
||||||
"libthiserror",
|
"libthiserror",
|
||||||
|
"android.security.authorization-rust",
|
||||||
],
|
],
|
||||||
static_libs: [
|
static_libs: [
|
||||||
"libkeystore2_ffi_test_utils",
|
"libkeystore2_ffi_test_utils",
|
||||||
|
|
|
@ -20,6 +20,7 @@ use std::path::{Path, PathBuf};
|
||||||
use std::{env::temp_dir, ops::Deref};
|
use std::{env::temp_dir, ops::Deref};
|
||||||
|
|
||||||
use android_system_keystore2::aidl::android::system::keystore2::IKeystoreService::IKeystoreService;
|
use android_system_keystore2::aidl::android::system::keystore2::IKeystoreService::IKeystoreService;
|
||||||
|
use android_security_authorization::aidl::android::security::authorization::IKeystoreAuthorization::IKeystoreAuthorization;
|
||||||
|
|
||||||
pub mod authorizations;
|
pub mod authorizations;
|
||||||
pub mod ffi_test_utils;
|
pub mod ffi_test_utils;
|
||||||
|
@ -27,6 +28,7 @@ pub mod key_generations;
|
||||||
pub mod run_as;
|
pub mod run_as;
|
||||||
|
|
||||||
static KS2_SERVICE_NAME: &str = "android.system.keystore2.IKeystoreService/default";
|
static KS2_SERVICE_NAME: &str = "android.system.keystore2.IKeystoreService/default";
|
||||||
|
static AUTH_SERVICE_NAME: &str = "android.security.authorization";
|
||||||
|
|
||||||
/// Represents the lifecycle of a temporary directory for testing.
|
/// Represents the lifecycle of a temporary directory for testing.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -116,3 +118,8 @@ impl Deref for PathBuilder {
|
||||||
pub fn get_keystore_service() -> binder::Strong<dyn IKeystoreService> {
|
pub fn get_keystore_service() -> binder::Strong<dyn IKeystoreService> {
|
||||||
binder::get_interface(KS2_SERVICE_NAME).unwrap()
|
binder::get_interface(KS2_SERVICE_NAME).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get Keystore auth service.
|
||||||
|
pub fn get_keystore_auth_service() -> binder::Strong<dyn IKeystoreAuthorization> {
|
||||||
|
binder::get_interface(AUTH_SERVICE_NAME).unwrap()
|
||||||
|
}
|
||||||
|
|
|
@ -35,6 +35,9 @@ rust_test {
|
||||||
test_config: "AndroidTest.xml",
|
test_config: "AndroidTest.xml",
|
||||||
|
|
||||||
rustlibs: [
|
rustlibs: [
|
||||||
|
"android.hardware.security.secureclock-V1-rust",
|
||||||
|
"android.security.authorization-rust",
|
||||||
|
"libaconfig_android_hardware_biometrics_rust",
|
||||||
"libbinder_rs",
|
"libbinder_rs",
|
||||||
"libkeystore2_test_utils",
|
"libkeystore2_test_utils",
|
||||||
"libnix",
|
"libnix",
|
||||||
|
|
|
@ -25,8 +25,16 @@ use android_system_keystore2::aidl::android::system::keystore2::{
|
||||||
KeyMetadata::KeyMetadata, ResponseCode::ResponseCode,
|
KeyMetadata::KeyMetadata, ResponseCode::ResponseCode,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use aconfig_android_hardware_biometrics_rust;
|
||||||
|
use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
|
||||||
|
HardwareAuthToken::HardwareAuthToken,
|
||||||
|
HardwareAuthenticatorType::HardwareAuthenticatorType
|
||||||
|
};
|
||||||
|
use android_hardware_security_secureclock::aidl::android::hardware::security::secureclock::Timestamp::Timestamp;
|
||||||
|
|
||||||
use keystore2_test_utils::{
|
use keystore2_test_utils::{
|
||||||
authorizations, get_keystore_service, key_generations, key_generations::Error,
|
authorizations, get_keystore_auth_service, get_keystore_service, key_generations,
|
||||||
|
key_generations::Error,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::keystore2_client_test_utils::{
|
use crate::keystore2_client_test_utils::{
|
||||||
|
@ -902,3 +910,57 @@ fn keystore2_gen_attestation_key_with_auth_app_id_app_data_test_fail() {
|
||||||
assert_eq!(Error::Km(ErrorCode::INVALID_KEY_BLOB), result.unwrap_err());
|
assert_eq!(Error::Km(ErrorCode::INVALID_KEY_BLOB), result.unwrap_err());
|
||||||
delete_app_key(&keystore2, attest_alias).unwrap();
|
delete_app_key(&keystore2, attest_alias).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn add_hardware_token(auth_type: HardwareAuthenticatorType) {
|
||||||
|
let keystore_auth = get_keystore_auth_service();
|
||||||
|
|
||||||
|
let token = HardwareAuthToken {
|
||||||
|
challenge: 0,
|
||||||
|
userId: 0,
|
||||||
|
authenticatorId: 0,
|
||||||
|
authenticatorType: auth_type,
|
||||||
|
timestamp: Timestamp { milliSeconds: 500 },
|
||||||
|
mac: vec![],
|
||||||
|
};
|
||||||
|
keystore_auth.addAuthToken(&token).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn keystore2_flagged_off_get_last_auth_password_permission_denied() {
|
||||||
|
if aconfig_android_hardware_biometrics_rust::last_authentication_time() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let keystore_auth = get_keystore_auth_service();
|
||||||
|
|
||||||
|
let result = keystore_auth.getLastAuthTime(0, &[HardwareAuthenticatorType::PASSWORD]);
|
||||||
|
|
||||||
|
assert!(result.is_err());
|
||||||
|
assert_eq!(result.unwrap_err().service_specific_error(), ResponseCode::PERMISSION_DENIED.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn keystore2_flagged_on_get_last_auth_password_success() {
|
||||||
|
if !aconfig_android_hardware_biometrics_rust::last_authentication_time() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let keystore_auth = get_keystore_auth_service();
|
||||||
|
|
||||||
|
add_hardware_token(HardwareAuthenticatorType::PASSWORD);
|
||||||
|
assert!(keystore_auth.getLastAuthTime(0, &[HardwareAuthenticatorType::PASSWORD]).unwrap() > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn keystore2_flagged_on_get_last_auth_fingerprint_success() {
|
||||||
|
if !aconfig_android_hardware_biometrics_rust::last_authentication_time() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let keystore_auth = get_keystore_auth_service();
|
||||||
|
|
||||||
|
add_hardware_token(HardwareAuthenticatorType::FINGERPRINT);
|
||||||
|
assert!(
|
||||||
|
keystore_auth.getLastAuthTime(0, &[HardwareAuthenticatorType::FINGERPRINT]).unwrap() > 0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue