Merge "Use CLOCK_BOOTTIME for keystore2 auth token received time" into main
diff --git a/keystore2/Android.bp b/keystore2/Android.bp
index 1c7eebe..03dfd45 100644
--- a/keystore2/Android.bp
+++ b/keystore2/Android.bp
@@ -41,6 +41,7 @@
         "android.security.maintenance-rust",
         "android.security.metrics-rust",
         "android.security.rkp_aidl-rust",
+        "libaconfig_android_hardware_biometrics_rust",
         "libanyhow",
         "libbinder_rs",
         "libkeystore2_aaid-rust",
@@ -54,12 +55,14 @@
         "liblibc",
         "liblog_event_list",
         "liblog_rust",
+        "libmessage_macro",
         "librand",
         "librustutils",
         "libserde",
         "libserde_cbor",
         "libthiserror",
         "libtokio",
+        "libwatchdog_rs",
     ],
     shared_libs: [
         "libcutils",
@@ -161,3 +164,9 @@
     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/TEST_MAPPING b/keystore2/TEST_MAPPING
index f8a1302..1038bea 100644
--- a/keystore2/TEST_MAPPING
+++ b/keystore2/TEST_MAPPING
@@ -33,6 +33,9 @@
     },
     {
       "name": "keystore2_client_tests"
+    },
+    {
+      "name": "libwatchdog_rs.test"
     }
   ]
 }
diff --git a/keystore2/aidl/android/security/authorization/IKeystoreAuthorization.aidl b/keystore2/aidl/android/security/authorization/IKeystoreAuthorization.aidl
index e3b7d11..b31a51e 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 @@
      */
     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/message_macro/Android.bp b/keystore2/message_macro/Android.bp
new file mode 100644
index 0000000..f1fbad7
--- /dev/null
+++ b/keystore2/message_macro/Android.bp
@@ -0,0 +1,37 @@
+// Copyright 2023, The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "system_security_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["system_security_license"],
+}
+
+rust_defaults {
+    name: "libmessage_macro_defaults",
+    crate_name: "message_macro",
+    srcs: ["src/lib.rs"],
+}
+
+rust_library {
+    name: "libmessage_macro",
+    defaults: ["libmessage_macro_defaults"],
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.virt",
+    ],
+}
diff --git a/keystore2/src/ks_err.rs b/keystore2/message_macro/src/lib.rs
similarity index 76%
rename from keystore2/src/ks_err.rs
rename to keystore2/message_macro/src/lib.rs
index c9c38c0..d8cfab0 100644
--- a/keystore2/src/ks_err.rs
+++ b/keystore2/message_macro/src/lib.rs
@@ -12,20 +12,20 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-//! A ks_err macro that expands error messages to include the file and line number
+//! A macro that generates a message containing the current source file name
+//! and line number.
 
+/// Generates a message containing the current source file name and line number.
 ///
 /// # Examples
 ///
 /// ```
-/// use crate::ks_err;
-///
-/// ks_err!("Key is expired.");
+/// source_location_msg!("Key is expired.");
 /// Result:
 /// "src/lib.rs:7 Key is expired."
 /// ```
 #[macro_export]
-macro_rules! ks_err {
+macro_rules! source_location_msg {
     { $($arg:tt)+ } => {
         format!("{}:{}: {}", file!(), line!(), format_args!($($arg)+))
     };
diff --git a/keystore2/src/authorization.rs b/keystore2/src/authorization.rs
index f840189..7416b7f 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 @@
             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 @@
             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/database.rs b/keystore2/src/database.rs
index 08361b1..9d2da8c 100644
--- a/keystore2/src/database.rs
+++ b/keystore2/src/database.rs
@@ -5049,7 +5049,6 @@
         for storage in increased_storage_types {
             // Verify the expected storage increased.
             let new = db.get_storage_stat(storage).unwrap();
-            let storage = storage;
             let old = &baseline[&storage.0];
             assert!(new.size >= old.size, "{}: {} >= {}", storage.0, new.size, old.size);
             assert!(
diff --git a/keystore2/src/enforcements.rs b/keystore2/src/enforcements.rs
index bb23b82..95e8837 100644
--- a/keystore2/src/enforcements.rs
+++ b/keystore2/src/enforcements.rs
@@ -845,6 +845,24 @@
             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/km_compat.rs b/keystore2/src/km_compat.rs
index f8673fb..cd58fe4 100644
--- a/keystore2/src/km_compat.rs
+++ b/keystore2/src/km_compat.rs
@@ -164,7 +164,7 @@
     }
 }
 
-impl<T> binder::Interface for BacklevelKeyMintWrapper<T> where T: EmulationDetector {}
+impl<T> binder::Interface for BacklevelKeyMintWrapper<T> where T: EmulationDetector + 'static {}
 
 impl<T> IKeyMintDevice for BacklevelKeyMintWrapper<T>
 where
diff --git a/keystore2/src/lib.rs b/keystore2/src/lib.rs
index 3233017..e51a319 100644
--- a/keystore2/src/lib.rs
+++ b/keystore2/src/lib.rs
@@ -28,7 +28,6 @@
 pub mod id_rotation;
 /// Internal Representation of Key Parameter and convenience functions.
 pub mod key_parameter;
-pub mod ks_err;
 pub mod legacy_blob;
 pub mod legacy_importer;
 pub mod maintenance;
@@ -50,6 +49,6 @@
 mod km_compat;
 mod super_key;
 mod sw_keyblob;
+mod watchdog_helper;
 
-#[cfg(feature = "watchdog")]
-mod watchdog;
+use message_macro::source_location_msg as ks_err;
diff --git a/keystore2/src/permission.rs b/keystore2/src/permission.rs
index 35d6988..bc73744 100644
--- a/keystore2/src/permission.rs
+++ b/keystore2/src/permission.rs
@@ -149,6 +149,9 @@
         /// 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/src/remote_provisioning.rs b/keystore2/src/remote_provisioning.rs
index 811ad98..1e33ef1 100644
--- a/keystore2/src/remote_provisioning.rs
+++ b/keystore2/src/remote_provisioning.rs
@@ -31,6 +31,7 @@
 use keystore2_crypto::parse_subject_from_certificate;
 
 use crate::database::Uuid;
+use crate::globals::get_remotely_provisioned_component_name;
 use crate::ks_err;
 use crate::metrics_store::log_rkp_error_stats;
 use crate::rkpd_client::get_rkpd_attestation_key;
@@ -93,7 +94,9 @@
         if !self.is_asymmetric_key(params) || key.domain != Domain::APP {
             Ok(None)
         } else {
-            match get_rkpd_attestation_key(&self.security_level, caller_uid) {
+            let rpc_name = get_remotely_provisioned_component_name(&self.security_level)
+                .context(ks_err!("Trying to get IRPC name."))?;
+            match get_rkpd_attestation_key(&rpc_name, caller_uid) {
                 Err(e) => {
                     if self.is_rkp_only() {
                         log::error!("Error occurred: {:?}", e);
diff --git a/keystore2/src/rkpd_client.rs b/keystore2/src/rkpd_client.rs
index 7b4131d..9317824 100644
--- a/keystore2/src/rkpd_client.rs
+++ b/keystore2/src/rkpd_client.rs
@@ -15,10 +15,7 @@
 //! Helper wrapper around RKPD interface.
 
 use crate::error::{map_binder_status_code, Error, ResponseCode};
-use crate::globals::get_remotely_provisioned_component_name;
-use crate::ks_err;
-use crate::utils::watchdog as wd;
-use android_hardware_security_keymint::aidl::android::hardware::security::keymint::SecurityLevel::SecurityLevel;
+use crate::watchdog_helper::watchdog as wd;
 use android_security_rkp_aidl::aidl::android::security::rkp::{
     IGetKeyCallback::BnGetKeyCallback, IGetKeyCallback::ErrorCode::ErrorCode as GetKeyErrorCode,
     IGetKeyCallback::IGetKeyCallback, IGetRegistrationCallback::BnGetRegistrationCallback,
@@ -30,6 +27,7 @@
 };
 use android_security_rkp_aidl::binder::{BinderFeatures, Interface, Strong};
 use anyhow::{Context, Result};
+use message_macro::source_location_msg;
 use std::sync::Mutex;
 use std::time::Duration;
 use tokio::sync::oneshot;
@@ -93,43 +91,37 @@
         log::warn!("IGetRegistrationCallback cancelled");
         self.registration_tx.send(
             Err(Error::Rc(ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR))
-                .context(ks_err!("GetRegistrationCallback cancelled.")),
+                .context(source_location_msg!("GetRegistrationCallback cancelled.")),
         );
         Ok(())
     }
     fn onError(&self, description: &str) -> binder::Result<()> {
         let _wp = wd::watch_millis("IGetRegistrationCallback::onError", 500);
         log::error!("IGetRegistrationCallback failed: '{description}'");
-        self.registration_tx.send(
-            Err(Error::Rc(ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR))
-                .context(ks_err!("GetRegistrationCallback failed: {:?}", description)),
-        );
+        self.registration_tx
+            .send(Err(Error::Rc(ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR)).context(
+                source_location_msg!("GetRegistrationCallback failed: {:?}", description),
+            ));
         Ok(())
     }
 }
 
 /// Make a new connection to a IRegistration service.
-async fn get_rkpd_registration(
-    security_level: &SecurityLevel,
-) -> Result<binder::Strong<dyn IRegistration>> {
+async fn get_rkpd_registration(rpc_name: &str) -> Result<binder::Strong<dyn IRegistration>> {
     let remote_provisioning: Strong<dyn IRemoteProvisioning> =
         map_binder_status_code(binder::get_interface("remote_provisioning"))
-            .context(ks_err!("Trying to connect to IRemoteProvisioning service."))?;
-
-    let rpc_name = get_remotely_provisioned_component_name(security_level)
-        .context(ks_err!("Trying to get IRPC name."))?;
+            .context(source_location_msg!("Trying to connect to IRemoteProvisioning service."))?;
 
     let (tx, rx) = oneshot::channel();
     let cb = GetRegistrationCallback::new_native_binder(tx);
 
     remote_provisioning
-        .getRegistration(&rpc_name, &cb)
-        .context(ks_err!("Trying to get registration."))?;
+        .getRegistration(rpc_name, &cb)
+        .context(source_location_msg!("Trying to get registration."))?;
 
     match timeout(RKPD_TIMEOUT, rx).await {
-        Err(e) => {
-            Err(Error::Rc(ResponseCode::SYSTEM_ERROR)).context(ks_err!("Waiting for RKPD: {:?}", e))
-        }
+        Err(e) => Err(Error::Rc(ResponseCode::SYSTEM_ERROR))
+            .context(source_location_msg!("Waiting for RKPD: {:?}", e)),
         Ok(v) => v.unwrap(),
     }
 }
@@ -163,7 +155,7 @@
         log::warn!("IGetKeyCallback cancelled");
         self.key_tx.send(
             Err(Error::Rc(ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR))
-                .context(ks_err!("GetKeyCallback cancelled.")),
+                .context(source_location_msg!("GetKeyCallback cancelled.")),
         );
         Ok(())
     }
@@ -184,7 +176,7 @@
                 ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR
             }
         };
-        self.key_tx.send(Err(Error::Rc(rc)).context(ks_err!(
+        self.key_tx.send(Err(Error::Rc(rc)).context(source_location_msg!(
             "GetKeyCallback failed: {:?} {:?}",
             error,
             description
@@ -202,7 +194,7 @@
 
     registration
         .getKey(caller_uid.try_into().unwrap(), &cb)
-        .context(ks_err!("Trying to get key."))?;
+        .context(source_location_msg!("Trying to get key."))?;
 
     match timeout(RKPD_TIMEOUT, rx).await {
         Err(e) => {
@@ -211,19 +203,19 @@
                 log::error!("IRegistration::cancelGetKey failed: {:?}", e);
             }
             Err(Error::Rc(ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR))
-                .context(ks_err!("Waiting for RKPD key timed out: {:?}", e))
+                .context(source_location_msg!("Waiting for RKPD key timed out: {:?}", e))
         }
         Ok(v) => v.unwrap(),
     }
 }
 
 async fn get_rkpd_attestation_key_async(
-    security_level: &SecurityLevel,
+    rpc_name: &str,
     caller_uid: u32,
 ) -> Result<RemotelyProvisionedKey> {
-    let registration = get_rkpd_registration(security_level)
+    let registration = get_rkpd_registration(rpc_name)
         .await
-        .context(ks_err!("Trying to get to IRegistration service."))?;
+        .context(source_location_msg!("Trying to get to IRegistration service."))?;
     get_rkpd_attestation_key_from_registration_async(&registration, caller_uid).await
 }
 
@@ -254,7 +246,7 @@
         log::error!("IGetRegistrationCallback failed: {error}");
         self.completer.send(
             Err(Error::Rc(ResponseCode::SYSTEM_ERROR))
-                .context(ks_err!("Failed to store upgraded key: {:?}", error)),
+                .context(source_location_msg!("Failed to store upgraded key: {:?}", error)),
         );
         Ok(())
     }
@@ -270,61 +262,53 @@
 
     registration
         .storeUpgradedKeyAsync(key_blob, upgraded_blob, &cb)
-        .context(ks_err!("Failed to store upgraded blob with RKPD."))?;
+        .context(source_location_msg!("Failed to store upgraded blob with RKPD."))?;
 
     match timeout(RKPD_TIMEOUT, rx).await {
         Err(e) => Err(Error::Rc(ResponseCode::SYSTEM_ERROR))
-            .context(ks_err!("Waiting for RKPD to complete storing key: {:?}", e)),
+            .context(source_location_msg!("Waiting for RKPD to complete storing key: {:?}", e)),
         Ok(v) => v.unwrap(),
     }
 }
 
 async fn store_rkpd_attestation_key_async(
-    security_level: &SecurityLevel,
+    rpc_name: &str,
     key_blob: &[u8],
     upgraded_blob: &[u8],
 ) -> Result<()> {
-    let registration = get_rkpd_registration(security_level)
+    let registration = get_rkpd_registration(rpc_name)
         .await
-        .context(ks_err!("Trying to get to IRegistration service."))?;
+        .context(source_location_msg!("Trying to get to IRegistration service."))?;
     store_rkpd_attestation_key_with_registration_async(&registration, key_blob, upgraded_blob).await
 }
 
 /// Get attestation key from RKPD.
-pub fn get_rkpd_attestation_key(
-    security_level: &SecurityLevel,
-    caller_uid: u32,
-) -> Result<RemotelyProvisionedKey> {
+pub fn get_rkpd_attestation_key(rpc_name: &str, caller_uid: u32) -> Result<RemotelyProvisionedKey> {
     let _wp = wd::watch_millis("Calling get_rkpd_attestation_key()", 500);
-    tokio_rt().block_on(get_rkpd_attestation_key_async(security_level, caller_uid))
+    tokio_rt().block_on(get_rkpd_attestation_key_async(rpc_name, caller_uid))
 }
 
 /// Store attestation key in RKPD.
 pub fn store_rkpd_attestation_key(
-    security_level: &SecurityLevel,
+    rpc_name: &str,
     key_blob: &[u8],
     upgraded_blob: &[u8],
 ) -> Result<()> {
     let _wp = wd::watch_millis("Calling store_rkpd_attestation_key()", 500);
-    tokio_rt().block_on(store_rkpd_attestation_key_async(security_level, key_blob, upgraded_blob))
+    tokio_rt().block_on(store_rkpd_attestation_key_async(rpc_name, key_blob, upgraded_blob))
 }
 
 #[cfg(test)]
 mod tests {
     use super::*;
-    use crate::error::map_km_error;
-    use crate::globals::get_keymint_device;
-    use crate::utils::upgrade_keyblob_if_required_with;
-    use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
-        Algorithm::Algorithm, AttestationKey::AttestationKey, KeyParameter::KeyParameter,
-        KeyParameterValue::KeyParameterValue, Tag::Tag,
-    };
     use android_security_rkp_aidl::aidl::android::security::rkp::IRegistration::BnRegistration;
-    use keystore2_crypto::parse_subject_from_certificate;
     use std::collections::HashMap;
     use std::sync::atomic::{AtomicU32, Ordering};
     use std::sync::{Arc, Mutex};
 
+    const DEFAULT_RPC_SERVICE_NAME: &str =
+        "android.hardware.security.keymint.IRemotelyProvisionedComponent/default";
+
     struct MockRegistrationValues {
         key: RemotelyProvisionedKey,
         latency: Option<Duration>,
@@ -597,7 +581,7 @@
     fn test_get_rkpd_attestation_key() {
         binder::ProcessState::start_thread_pool();
         let key_id = get_next_key_id();
-        let key = get_rkpd_attestation_key(&SecurityLevel::TRUSTED_ENVIRONMENT, key_id).unwrap();
+        let key = get_rkpd_attestation_key(DEFAULT_RPC_SERVICE_NAME, key_id).unwrap();
         assert!(!key.keyBlob.is_empty());
         assert!(!key.encodedCertChain.is_empty());
     }
@@ -605,12 +589,11 @@
     #[test]
     fn test_get_rkpd_attestation_key_same_caller() {
         binder::ProcessState::start_thread_pool();
-        let sec_level = SecurityLevel::TRUSTED_ENVIRONMENT;
         let key_id = get_next_key_id();
 
         // Multiple calls should return the same key.
-        let first_key = get_rkpd_attestation_key(&sec_level, key_id).unwrap();
-        let second_key = get_rkpd_attestation_key(&sec_level, key_id).unwrap();
+        let first_key = get_rkpd_attestation_key(DEFAULT_RPC_SERVICE_NAME, key_id).unwrap();
+        let second_key = get_rkpd_attestation_key(DEFAULT_RPC_SERVICE_NAME, key_id).unwrap();
 
         assert_eq!(first_key.keyBlob, second_key.keyBlob);
         assert_eq!(first_key.encodedCertChain, second_key.encodedCertChain);
@@ -619,13 +602,12 @@
     #[test]
     fn test_get_rkpd_attestation_key_different_caller() {
         binder::ProcessState::start_thread_pool();
-        let sec_level = SecurityLevel::TRUSTED_ENVIRONMENT;
         let first_key_id = get_next_key_id();
         let second_key_id = get_next_key_id();
 
         // Different callers should be getting different keys.
-        let first_key = get_rkpd_attestation_key(&sec_level, first_key_id).unwrap();
-        let second_key = get_rkpd_attestation_key(&sec_level, second_key_id).unwrap();
+        let first_key = get_rkpd_attestation_key(DEFAULT_RPC_SERVICE_NAME, first_key_id).unwrap();
+        let second_key = get_rkpd_attestation_key(DEFAULT_RPC_SERVICE_NAME, second_key_id).unwrap();
 
         assert_ne!(first_key.keyBlob, second_key.keyBlob);
         assert_ne!(first_key.encodedCertChain, second_key.encodedCertChain);
@@ -639,86 +621,24 @@
     //    test case.
     fn test_store_rkpd_attestation_key() {
         binder::ProcessState::start_thread_pool();
-        let sec_level = SecurityLevel::TRUSTED_ENVIRONMENT;
         let key_id = get_next_key_id();
-        let key = get_rkpd_attestation_key(&SecurityLevel::TRUSTED_ENVIRONMENT, key_id).unwrap();
+        let key = get_rkpd_attestation_key(DEFAULT_RPC_SERVICE_NAME, key_id).unwrap();
         let new_blob: [u8; 8] = rand::random();
 
-        assert!(store_rkpd_attestation_key(&sec_level, &key.keyBlob, &new_blob).is_ok());
+        assert!(
+            store_rkpd_attestation_key(DEFAULT_RPC_SERVICE_NAME, &key.keyBlob, &new_blob).is_ok()
+        );
 
-        let new_key =
-            get_rkpd_attestation_key(&SecurityLevel::TRUSTED_ENVIRONMENT, key_id).unwrap();
+        let new_key = get_rkpd_attestation_key(DEFAULT_RPC_SERVICE_NAME, key_id).unwrap();
 
         // Restore original key so that we don't leave RKPD with invalid blobs.
-        assert!(store_rkpd_attestation_key(&sec_level, &new_blob, &key.keyBlob).is_ok());
+        assert!(
+            store_rkpd_attestation_key(DEFAULT_RPC_SERVICE_NAME, &new_blob, &key.keyBlob).is_ok()
+        );
         assert_eq!(new_key.keyBlob, new_blob);
     }
 
     #[test]
-    // This is a helper for a manual test. We want to check that after a system upgrade RKPD
-    // attestation keys can also be upgraded and stored again with RKPD. The steps are:
-    // 1. Run this test and check in stdout that no key upgrade happened.
-    // 2. Perform a system upgrade.
-    // 3. Run this test and check in stdout that key upgrade did happen.
-    //
-    // Note that this test must be run with that same UID every time. Running as root, i.e. UID 0,
-    // should do the trick. Also, use "--nocapture" flag to get stdout.
-    fn test_rkpd_attestation_key_upgrade() {
-        binder::ProcessState::start_thread_pool();
-        let security_level = SecurityLevel::TRUSTED_ENVIRONMENT;
-        let (keymint, info, _) = get_keymint_device(&security_level).unwrap();
-        let key_id = get_next_key_id();
-        let mut key_upgraded = false;
-
-        let key = get_rkpd_attestation_key(&security_level, key_id).unwrap();
-        assert!(!key.keyBlob.is_empty());
-        assert!(!key.encodedCertChain.is_empty());
-
-        upgrade_keyblob_if_required_with(
-            &*keymint,
-            info.versionNumber,
-            &key.keyBlob,
-            /*upgrade_params=*/ &[],
-            /*km_op=*/
-            |blob| {
-                let params = vec![
-                    KeyParameter {
-                        tag: Tag::ALGORITHM,
-                        value: KeyParameterValue::Algorithm(Algorithm::AES),
-                    },
-                    KeyParameter {
-                        tag: Tag::ATTESTATION_CHALLENGE,
-                        value: KeyParameterValue::Blob(vec![0; 16]),
-                    },
-                    KeyParameter { tag: Tag::KEY_SIZE, value: KeyParameterValue::Integer(128) },
-                ];
-                let attestation_key = AttestationKey {
-                    keyBlob: blob.to_vec(),
-                    attestKeyParams: vec![],
-                    issuerSubjectName: parse_subject_from_certificate(&key.encodedCertChain)
-                        .unwrap(),
-                };
-
-                map_km_error(keymint.generateKey(&params, Some(&attestation_key)))
-            },
-            /*new_blob_handler=*/
-            |new_blob| {
-                // This handler is only executed if a key upgrade was performed.
-                key_upgraded = true;
-                store_rkpd_attestation_key(&security_level, &key.keyBlob, new_blob).unwrap();
-                Ok(())
-            },
-        )
-        .unwrap();
-
-        if key_upgraded {
-            println!("RKPD key was upgraded and stored with RKPD.");
-        } else {
-            println!("RKPD key was NOT upgraded.");
-        }
-    }
-
-    #[test]
     fn test_stress_get_rkpd_attestation_key() {
         binder::ProcessState::start_thread_pool();
         let key_id = get_next_key_id();
@@ -729,8 +649,7 @@
         for _ in 0..NTHREADS {
             threads.push(std::thread::spawn(move || {
                 for _ in 0..NCALLS {
-                    let key = get_rkpd_attestation_key(&SecurityLevel::TRUSTED_ENVIRONMENT, key_id)
-                        .unwrap();
+                    let key = get_rkpd_attestation_key(DEFAULT_RPC_SERVICE_NAME, key_id).unwrap();
                     assert!(!key.keyBlob.is_empty());
                     assert!(!key.encodedCertChain.is_empty());
                 }
diff --git a/keystore2/src/security_level.rs b/keystore2/src/security_level.rs
index 6696113..50ada74 100644
--- a/keystore2/src/security_level.rs
+++ b/keystore2/src/security_level.rs
@@ -20,7 +20,9 @@
 };
 use crate::database::{BlobInfo, CertificateInfo, KeyIdGuard};
 use crate::error::{self, map_km_error, map_or_log_err, Error, ErrorCode};
-use crate::globals::{DB, ENFORCEMENTS, LEGACY_IMPORTER, SUPER_KEY};
+use crate::globals::{
+    get_remotely_provisioned_component_name, DB, ENFORCEMENTS, LEGACY_IMPORTER, SUPER_KEY,
+};
 use crate::key_parameter::KeyParameter as KsKeyParam;
 use crate::key_parameter::KeyParameterValue as KsKeyParamValue;
 use crate::ks_err;
@@ -888,6 +890,8 @@
     where
         F: Fn(&[u8]) -> Result<T, Error>,
     {
+        let rpc_name = get_remotely_provisioned_component_name(&self.security_level)
+            .context(ks_err!("Trying to get IRPC name."))?;
         crate::utils::upgrade_keyblob_if_required_with(
             &*self.keymint,
             self.hw_info.versionNumber,
@@ -895,7 +899,7 @@
             params,
             f,
             |upgraded_blob| {
-                store_rkpd_attestation_key(&self.security_level, key_blob, upgraded_blob)
+                store_rkpd_attestation_key(&rpc_name, key_blob, upgraded_blob)
                     .context(ks_err!("Failed store_rkpd_attestation_key()."))
             },
         )
@@ -1057,3 +1061,82 @@
         map_or_log_err(result, Ok)
     }
 }
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use crate::error::map_km_error;
+    use crate::globals::get_keymint_device;
+    use crate::rkpd_client::{get_rkpd_attestation_key, store_rkpd_attestation_key};
+    use crate::utils::upgrade_keyblob_if_required_with;
+    use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
+        Algorithm::Algorithm, AttestationKey::AttestationKey, KeyParameter::KeyParameter,
+        KeyParameterValue::KeyParameterValue, Tag::Tag,
+    };
+    use keystore2_crypto::parse_subject_from_certificate;
+
+    #[test]
+    // This is a helper for a manual test. We want to check that after a system upgrade RKPD
+    // attestation keys can also be upgraded and stored again with RKPD. The steps are:
+    // 1. Run this test and check in stdout that no key upgrade happened.
+    // 2. Perform a system upgrade.
+    // 3. Run this test and check in stdout that key upgrade did happen.
+    //
+    // Note that this test must be run with that same UID every time. Running as root, i.e. UID 0,
+    // should do the trick. Also, use "--nocapture" flag to get stdout.
+    fn test_rkpd_attestation_key_upgrade() {
+        binder::ProcessState::start_thread_pool();
+        let security_level = SecurityLevel::TRUSTED_ENVIRONMENT;
+        let (keymint, info, _) = get_keymint_device(&security_level).unwrap();
+        let key_id = 0;
+        let mut key_upgraded = false;
+
+        let rpc_name = get_remotely_provisioned_component_name(&security_level).unwrap();
+        let key = get_rkpd_attestation_key(&rpc_name, key_id).unwrap();
+        assert!(!key.keyBlob.is_empty());
+        assert!(!key.encodedCertChain.is_empty());
+
+        upgrade_keyblob_if_required_with(
+            &*keymint,
+            info.versionNumber,
+            &key.keyBlob,
+            /*upgrade_params=*/ &[],
+            /*km_op=*/
+            |blob| {
+                let params = vec![
+                    KeyParameter {
+                        tag: Tag::ALGORITHM,
+                        value: KeyParameterValue::Algorithm(Algorithm::AES),
+                    },
+                    KeyParameter {
+                        tag: Tag::ATTESTATION_CHALLENGE,
+                        value: KeyParameterValue::Blob(vec![0; 16]),
+                    },
+                    KeyParameter { tag: Tag::KEY_SIZE, value: KeyParameterValue::Integer(128) },
+                ];
+                let attestation_key = AttestationKey {
+                    keyBlob: blob.to_vec(),
+                    attestKeyParams: vec![],
+                    issuerSubjectName: parse_subject_from_certificate(&key.encodedCertChain)
+                        .unwrap(),
+                };
+
+                map_km_error(keymint.generateKey(&params, Some(&attestation_key)))
+            },
+            /*new_blob_handler=*/
+            |new_blob| {
+                // This handler is only executed if a key upgrade was performed.
+                key_upgraded = true;
+                store_rkpd_attestation_key(&rpc_name, &key.keyBlob, new_blob).unwrap();
+                Ok(())
+            },
+        )
+        .unwrap();
+
+        if key_upgraded {
+            println!("RKPD key was upgraded and stored with RKPD.");
+        } else {
+            println!("RKPD key was NOT upgraded.");
+        }
+    }
+}
diff --git a/keystore2/src/utils.rs b/keystore2/src/utils.rs
index db2d0dc..4fd9c8d 100644
--- a/keystore2/src/utils.rs
+++ b/keystore2/src/utils.rs
@@ -20,6 +20,7 @@
 use crate::ks_err;
 use crate::permission;
 use crate::permission::{KeyPerm, KeyPermSet, KeystorePerm};
+pub use crate::watchdog_helper::watchdog;
 use crate::{
     database::{KeyType, KeystoreDB},
     globals::LEGACY_IMPORTER,
@@ -421,36 +422,6 @@
     Ok((legacy_keys.len() + num_keys_in_db) as i32)
 }
 
-/// This module provides helpers for simplified use of the watchdog module.
-#[cfg(feature = "watchdog")]
-pub mod watchdog {
-    pub use crate::watchdog::WatchPoint;
-    use crate::watchdog::Watchdog;
-    use lazy_static::lazy_static;
-    use std::sync::Arc;
-    use std::time::Duration;
-
-    lazy_static! {
-        /// A Watchdog thread, that can be used to create watch points.
-        static ref WD: Arc<Watchdog> = Watchdog::new(Duration::from_secs(10));
-    }
-
-    /// Sets a watch point with `id` and a timeout of `millis` milliseconds.
-    pub fn watch_millis(id: &'static str, millis: u64) -> Option<WatchPoint> {
-        Watchdog::watch(&WD, id, Duration::from_millis(millis))
-    }
-
-    /// Like `watch_millis` but with a callback that is called every time a report
-    /// is printed about this watch point.
-    pub fn watch_millis_with(
-        id: &'static str,
-        millis: u64,
-        callback: impl Fn() -> String + Send + 'static,
-    ) -> Option<WatchPoint> {
-        Watchdog::watch_with(&WD, id, Duration::from_millis(millis), callback)
-    }
-}
-
 /// Trait implemented by objects that can be used to decrypt cipher text using AES-GCM.
 pub trait AesGcm {
     /// Deciphers `data` using the initialization vector `iv` and AEAD tag `tag`
@@ -480,25 +451,6 @@
     }
 }
 
-/// This module provides empty/noop implementations of the watch dog utility functions.
-#[cfg(not(feature = "watchdog"))]
-pub mod watchdog {
-    /// Noop watch point.
-    pub struct WatchPoint();
-    /// Sets a Noop watch point.
-    fn watch_millis(_: &'static str, _: u64) -> Option<WatchPoint> {
-        None
-    }
-
-    pub fn watch_millis_with(
-        _: &'static str,
-        _: u64,
-        _: impl Fn() -> String + Send + 'static,
-    ) -> Option<WatchPoint> {
-        None
-    }
-}
-
 #[cfg(test)]
 mod tests {
     use super::*;
diff --git a/keystore2/src/watchdog_helper.rs b/keystore2/src/watchdog_helper.rs
new file mode 100644
index 0000000..92a0abc
--- /dev/null
+++ b/keystore2/src/watchdog_helper.rs
@@ -0,0 +1,64 @@
+// Copyright 2023, The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//! Helpers for the watchdog module.
+
+/// This module provides helpers for simplified use of the watchdog module.
+#[cfg(feature = "watchdog")]
+pub mod watchdog {
+    use lazy_static::lazy_static;
+    use std::sync::Arc;
+    use std::time::Duration;
+    pub use watchdog_rs::WatchPoint;
+    use watchdog_rs::Watchdog;
+
+    lazy_static! {
+        /// A Watchdog thread, that can be used to create watch points.
+        static ref WD: Arc<Watchdog> = Watchdog::new(Duration::from_secs(10));
+    }
+
+    /// Sets a watch point with `id` and a timeout of `millis` milliseconds.
+    pub fn watch_millis(id: &'static str, millis: u64) -> Option<WatchPoint> {
+        Watchdog::watch(&WD, id, Duration::from_millis(millis))
+    }
+
+    /// Like `watch_millis` but with a callback that is called every time a report
+    /// is printed about this watch point.
+    pub fn watch_millis_with(
+        id: &'static str,
+        millis: u64,
+        callback: impl Fn() -> String + Send + 'static,
+    ) -> Option<WatchPoint> {
+        Watchdog::watch_with(&WD, id, Duration::from_millis(millis), callback)
+    }
+}
+
+/// This module provides empty/noop implementations of the watch dog utility functions.
+#[cfg(not(feature = "watchdog"))]
+pub mod watchdog {
+    /// Noop watch point.
+    pub struct WatchPoint();
+    /// Sets a Noop watch point.
+    fn watch_millis(_: &'static str, _: u64) -> Option<WatchPoint> {
+        None
+    }
+
+    pub fn watch_millis_with(
+        _: &'static str,
+        _: u64,
+        _: impl Fn() -> String + Send + 'static,
+    ) -> Option<WatchPoint> {
+        None
+    }
+}
diff --git a/keystore2/test_utils/Android.bp b/keystore2/test_utils/Android.bp
index a3c40cb..c16aa12 100644
--- a/keystore2/test_utils/Android.bp
+++ b/keystore2/test_utils/Android.bp
@@ -39,6 +39,7 @@
         "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 a373a2f..8394ca1 100644
--- a/keystore2/test_utils/lib.rs
+++ b/keystore2/test_utils/lib.rs
@@ -20,6 +20,7 @@
 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 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 @@
 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 d33bf9f..e09b224 100644
--- a/keystore2/tests/Android.bp
+++ b/keystore2/tests/Android.bp
@@ -35,6 +35,9 @@
     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 22a23c8..279ecd7 100644
--- a/keystore2/tests/keystore2_client_authorizations_tests.rs
+++ b/keystore2/tests/keystore2_client_authorizations_tests.rs
@@ -25,8 +25,16 @@
     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 @@
     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
+    );
+}
diff --git a/keystore2/watchdog/Android.bp b/keystore2/watchdog/Android.bp
new file mode 100644
index 0000000..62ede89
--- /dev/null
+++ b/keystore2/watchdog/Android.bp
@@ -0,0 +1,49 @@
+// Copyright 2023, The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "system_security_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["system_security_license"],
+}
+
+rust_defaults {
+    name: "libwatchdog_defaults",
+    crate_name: "watchdog_rs",
+    srcs: ["src/lib.rs"],
+    rustlibs: [
+        "liblog_rust",
+    ]
+}
+
+rust_library {
+    name: "libwatchdog_rs",
+    defaults: ["libwatchdog_defaults"],
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.virt",
+    ],
+}
+
+rust_test {
+    name: "libwatchdog_rs.test",
+    defaults: ["libwatchdog_defaults"],
+    test_suites: ["general-tests"],
+    rustlibs: [
+        "libandroid_logger",
+    ]
+}
diff --git a/keystore2/src/watchdog.rs b/keystore2/watchdog/src/lib.rs
similarity index 100%
rename from keystore2/src/watchdog.rs
rename to keystore2/watchdog/src/lib.rs