diff options
author | James Willcox <jwillcox@google.com> | 2023-10-03 21:31:31 +0000 |
---|---|---|
committer | James Willcox <jwillcox@google.com> | 2023-10-31 20:30:50 +0000 |
commit | d215da817ad9e1e42473e48416afb3fb11d85b54 (patch) | |
tree | 0cbf8a96ec27afaecb598824b540aec4bf49ac55 /keystore2 | |
parent | 449c3b2cec7fbd0feac97aad4949c9fab1282069 (diff) | |
download | security-d215da817ad9e1e42473e48416afb3fb11d85b54.tar.gz |
Add getLastAuthTime() to IKeystoreAuthorization
This returns the time (from CLOCK_MONOTONIC_RAW) that the specified user
last authenticated using the given authenticator.
Bug: 303839446
Test: atest keystore2_client_tests
Change-Id: Idd4c477365ffa556b7985d1d926dfa554680ff28
Diffstat (limited to 'keystore2')
-rw-r--r-- | keystore2/Android.bp | 7 | ||||
-rw-r--r-- | keystore2/aidl/android/security/authorization/IKeystoreAuthorization.aidl | 10 | ||||
-rw-r--r-- | keystore2/src/authorization.rs | 63 | ||||
-rw-r--r-- | keystore2/src/enforcements.rs | 18 | ||||
-rw-r--r-- | keystore2/src/permission.rs | 3 | ||||
-rw-r--r-- | keystore2/test_utils/Android.bp | 1 | ||||
-rw-r--r-- | keystore2/test_utils/lib.rs | 7 | ||||
-rw-r--r-- | keystore2/tests/Android.bp | 3 | ||||
-rw-r--r-- | keystore2/tests/keystore2_client_authorizations_tests.rs | 64 |
9 files changed, 165 insertions, 11 deletions
diff --git a/keystore2/Android.bp b/keystore2/Android.bp index 1c7eebe1..271f94df 100644 --- a/keystore2/Android.bp +++ b/keystore2/Android.bp @@ -41,6 +41,7 @@ rust_defaults { "android.security.maintenance-rust", "android.security.metrics-rust", "android.security.rkp_aidl-rust", + "libaconfig_android_hardware_biometrics_rust", "libanyhow", "libbinder_rs", "libkeystore2_aaid-rust", @@ -161,3 +162,9 @@ rust_aconfig_library { crate_name: "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", +} diff --git a/keystore2/aidl/android/security/authorization/IKeystoreAuthorization.aidl b/keystore2/aidl/android/security/authorization/IKeystoreAuthorization.aidl index e3b7d11d..b31a51e2 100644 --- a/keystore2/aidl/android/security/authorization/IKeystoreAuthorization.aidl +++ b/keystore2/aidl/android/security/authorization/IKeystoreAuthorization.aidl @@ -15,6 +15,7 @@ package android.security.authorization; import android.hardware.security.keymint.HardwareAuthToken; +import android.hardware.security.keymint.HardwareAuthenticatorType; import android.security.authorization.LockScreenEvent; import android.security.authorization.AuthorizationTokens; @@ -108,4 +109,13 @@ interface IKeystoreAuthorization { */ AuthorizationTokens getAuthTokensForCredStore(in long challenge, in long secureUserId, 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); } diff --git a/keystore2/src/authorization.rs b/keystore2/src/authorization.rs index f840189e..7416b7f2 100644 --- a/keystore2/src/authorization.rs +++ b/keystore2/src/authorization.rs @@ -14,27 +14,30 @@ //! 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::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::utils::{check_keystore_permission, watchdog as wd}; +use aconfig_android_hardware_biometrics_rust; 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::{ - IKeystoreAuthorization::BnKeystoreAuthorization, IKeystoreAuthorization::IKeystoreAuthorization, - LockScreenEvent::LockScreenEvent, AuthorizationTokens::AuthorizationTokens, + AuthorizationTokens::AuthorizationTokens, IKeystoreAuthorization::BnKeystoreAuthorization, + IKeystoreAuthorization::IKeystoreAuthorization, LockScreenEvent::LockScreenEvent, ResponseCode::ResponseCode, }; -use android_system_keystore2::aidl::android::system::keystore2::{ - ResponseCode::ResponseCode as KsResponseCode}; +use android_security_authorization::binder::{ + 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 keystore2_crypto::Password; use keystore2_selinux as selinux; +use std::ffi::CString; /// This is the Authorization error type, it wraps binder exceptions and the /// Authorization ResponseCode @@ -226,6 +229,31 @@ impl AuthorizationManager { ENFORCEMENTS.get_auth_tokens(challenge, secure_user_id, auth_token_max_age_millis)?; 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 {} @@ -274,4 +302,19 @@ impl IKeystoreAuthorization for AuthorizationManager { 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()), + )) + } + } } diff --git a/keystore2/src/enforcements.rs b/keystore2/src/enforcements.rs index bb23b82e..95e88373 100644 --- a/keystore2/src/enforcements.rs +++ b/keystore2/src/enforcements.rs @@ -845,6 +845,24 @@ impl Enforcements { get_timestamp_token(challenge).context(ks_err!("Error in getting timestamp token."))?; 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). diff --git a/keystore2/src/permission.rs b/keystore2/src/permission.rs index 35d69883..bc73744f 100644 --- a/keystore2/src/permission.rs +++ b/keystore2/src/permission.rs @@ -149,6 +149,9 @@ implement_class!( /// Checked on calls to IRemotelyProvisionedKeyPool::getAttestationKey #[selinux(name = get_attestation_key)] GetAttestationKey, + /// Checked on IKeystoreAuthorization::getLastAuthTime() is called. + #[selinux(name = get_last_auth_time)] + GetLastAuthTime, } ); diff --git a/keystore2/test_utils/Android.bp b/keystore2/test_utils/Android.bp index a3c40cb4..c16aa124 100644 --- a/keystore2/test_utils/Android.bp +++ b/keystore2/test_utils/Android.bp @@ -39,6 +39,7 @@ rust_defaults { "libserde", "libserde_cbor", "libthiserror", + "android.security.authorization-rust", ], static_libs: [ "libkeystore2_ffi_test_utils", diff --git a/keystore2/test_utils/lib.rs b/keystore2/test_utils/lib.rs index a373a2fa..8394ca1c 100644 --- a/keystore2/test_utils/lib.rs +++ b/keystore2/test_utils/lib.rs @@ -20,6 +20,7 @@ use std::path::{Path, PathBuf}; use std::{env::temp_dir, ops::Deref}; 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 ffi_test_utils; @@ -27,6 +28,7 @@ pub mod key_generations; pub mod run_as; 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. #[derive(Debug)] @@ -116,3 +118,8 @@ impl Deref for PathBuilder { pub fn get_keystore_service() -> binder::Strong<dyn IKeystoreService> { 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() +} diff --git a/keystore2/tests/Android.bp b/keystore2/tests/Android.bp index d33bf9f8..e09b224a 100644 --- a/keystore2/tests/Android.bp +++ b/keystore2/tests/Android.bp @@ -35,6 +35,9 @@ rust_test { test_config: "AndroidTest.xml", rustlibs: [ + "android.hardware.security.secureclock-V1-rust", + "android.security.authorization-rust", + "libaconfig_android_hardware_biometrics_rust", "libbinder_rs", "libkeystore2_test_utils", "libnix", diff --git a/keystore2/tests/keystore2_client_authorizations_tests.rs b/keystore2/tests/keystore2_client_authorizations_tests.rs index 22a23c8f..279ecd7b 100644 --- a/keystore2/tests/keystore2_client_authorizations_tests.rs +++ b/keystore2/tests/keystore2_client_authorizations_tests.rs @@ -25,8 +25,16 @@ use android_system_keystore2::aidl::android::system::keystore2::{ 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::{ - 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::{ @@ -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()); 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 + ); +} |