Adding tests using `MAX_USES_PER_BOOT`, `EARLY_BOOT_ONLY`, `BOOTLOADER_ONLY` and `USAGE_COUNT_LIMIT`

1. Generate a key with `BOOTLOADER_ONLY` tag. Test should successfully
   generate a key and verify the key characteristics. Test should fail
   with error code `INVALID_KEY_BLOB` during creation of an operation
   using this key.

2. Generate a key with `EARLY_BOOT_ONLY` tag. Test should successfully
   generate a key and verify the key characteristics. Test should fail
   with error code `EARLY_BOOT_ENDED` during creation of an operation
   using this key.

3. Generate a key with `MAX_USES_PER_BOOT` tag. Test should successfully
   generate a key and verify the key characteristics. Test should be
   able to use the key successfully `MAX_USES_COUNT` times. After
   exceeding key usage `MAX_USES_COUNT` times subsequent attempts to use
   the key in test should fail with error code `MAX_OPS_EXCEEDED`.

4. Generate a key with `USAGE_COUNT_LIMIT` tag. Test should successfully
   generate a key and verify the key characteristics. Test should be
   able to use the key successfully `MAX_USES_COUNT` times. After
   exceeding key usage `MAX_USES_COUNT` times subsequent attempts to use
   the key in test should fail with error code `KEY_NOT_FOUND`. Test
   should also check attest record for attested keys that
   `USAGE_COUNT_LIMIT` is included in attest record.

Bug: 279721870
Test: atest keystore2_client_tests
Change-Id: I205964b571d92dc0fcbd11b1f6d45bc3aea7c050
diff --git a/keystore2/test_utils/authorizations.rs b/keystore2/test_utils/authorizations.rs
index aa75982..b73aab5 100644
--- a/keystore2/test_utils/authorizations.rs
+++ b/keystore2/test_utils/authorizations.rs
@@ -269,6 +269,42 @@
         });
         self
     }
+
+    /// Set boot loader only.
+    pub fn boot_loader_only(mut self) -> Self {
+        self.0.push(KeyParameter {
+            tag: Tag::BOOTLOADER_ONLY,
+            value: KeyParameterValue::BoolValue(true),
+        });
+        self
+    }
+
+    /// Set early boot only.
+    pub fn early_boot_only(mut self) -> Self {
+        self.0.push(KeyParameter {
+            tag: Tag::EARLY_BOOT_ONLY,
+            value: KeyParameterValue::BoolValue(true),
+        });
+        self
+    }
+
+    /// Set max uses per boot.
+    pub fn max_uses_per_boot(mut self, max_uses: i32) -> Self {
+        self.0.push(KeyParameter {
+            tag: Tag::MAX_USES_PER_BOOT,
+            value: KeyParameterValue::Integer(max_uses),
+        });
+        self
+    }
+
+    /// Set max usage count.
+    pub fn usage_count_limit(mut self, usage_count: i32) -> Self {
+        self.0.push(KeyParameter {
+            tag: Tag::USAGE_COUNT_LIMIT,
+            value: KeyParameterValue::Integer(usage_count),
+        });
+        self
+    }
 }
 
 impl Deref for AuthSetBuilder {
diff --git a/keystore2/test_utils/ffi_test_utils.cpp b/keystore2/test_utils/ffi_test_utils.cpp
index 0740804..4e781d1 100644
--- a/keystore2/test_utils/ffi_test_utils.cpp
+++ b/keystore2/test_utils/ffi_test_utils.cpp
@@ -601,7 +601,8 @@
     return result;
 }
 
-CxxResult getValueFromAttestRecord(rust::Vec<rust::u8> cert_buf, int32_t tag) {
+CxxResult getValueFromAttestRecord(rust::Vec<rust::u8> cert_buf, int32_t tag,
+                                   int32_t expected_sec_level) {
     CxxResult cxx_result{};
     cxx_result.error = false;
 
@@ -649,6 +650,8 @@
 
     aidl::android::hardware::security::keymint::Tag auth_tag =
         static_cast<aidl::android::hardware::security::keymint::Tag>(tag);
+    aidl::android::hardware::security::keymint::SecurityLevel tag_security_level =
+        static_cast<aidl::android::hardware::security::keymint::SecurityLevel>(expected_sec_level);
 
     if (auth_tag == aidl::android::hardware::security::keymint::Tag::ATTESTATION_APPLICATION_ID) {
         int pos = att_sw_enforced.find(
@@ -685,6 +688,36 @@
         return cxx_result;
     }
 
+    if (auth_tag == aidl::android::hardware::security::keymint::Tag::USAGE_COUNT_LIMIT) {
+        aidl::android::hardware::security::keymint::KeyParameter param;
+        int pos = att_hw_enforced.find(auth_tag);
+        if (tag_security_level ==
+                aidl::android::hardware::security::keymint::SecurityLevel::SOFTWARE ||
+            tag_security_level ==
+                aidl::android::hardware::security::keymint::SecurityLevel::KEYSTORE) {
+            pos = att_sw_enforced.find(auth_tag);
+            if (pos == -1) {
+                LOG(ERROR) << "USAGE_COUNT_LIMIT not found in software enforced auth list";
+                cxx_result.error = KM_ERROR_INVALID_TAG;
+                return cxx_result;
+            }
+            param = att_sw_enforced[pos];
+        } else {
+            pos = att_hw_enforced.find(auth_tag);
+            if (pos == -1) {
+                LOG(ERROR) << "USAGE_COUNT_LIMIT not found in hardware enforced auth list";
+                cxx_result.error = KM_ERROR_INVALID_TAG;
+                return cxx_result;
+            }
+            param = att_hw_enforced[pos];
+        }
+        std::string val = std::to_string(
+            param.value
+                .get<aidl::android::hardware::security::keymint::KeyParameterValue::integer>());
+        std::move(val.begin(), val.end(), std::back_inserter(cxx_result.data));
+        return cxx_result;
+    }
+
     int pos = att_hw_enforced.find(auth_tag);
     if (pos == -1) {
         LOG(ERROR) << "getValueFromAttestRecord - unsupported tag.";
diff --git a/keystore2/test_utils/ffi_test_utils.hpp b/keystore2/test_utils/ffi_test_utils.hpp
index 69f558a..c4db1ba 100644
--- a/keystore2/test_utils/ffi_test_utils.hpp
+++ b/keystore2/test_utils/ffi_test_utils.hpp
@@ -1,16 +1,16 @@
 #pragma once
 
-#include "rust/cxx.h"
 #include "ffi_test_utils.rs.h"
+#include "rust/cxx.h"
 
 bool validateCertChain(rust::Vec<rust::u8> cert_buf, uint32_t cert_len, bool strict_issuer_check);
 CxxResult createWrappedKey(rust::Vec<rust::u8> encrypted_secure_key,
-                              rust::Vec<rust::u8> encrypted_transport_key,
-                              rust::Vec<rust::u8> iv,
-                              rust::Vec<rust::u8> tag);
+                           rust::Vec<rust::u8> encrypted_transport_key, rust::Vec<rust::u8> iv,
+                           rust::Vec<rust::u8> tag);
 CxxResult buildAsn1DerEncodedWrappedKeyDescription();
 bool performCryptoOpUsingKeystoreEngine(int64_t grant_id);
-CxxResult getValueFromAttestRecord(rust::Vec<rust::u8> cert_buf, int32_t tag);
+CxxResult getValueFromAttestRecord(rust::Vec<rust::u8> cert_buf, int32_t tag,
+                                   int32_t expected_sec_level);
 uint32_t getOsVersion();
 uint32_t getOsPatchlevel();
 uint32_t getVendorPatchlevel();
diff --git a/keystore2/test_utils/ffi_test_utils.rs b/keystore2/test_utils/ffi_test_utils.rs
index 04d82f1..5d6bf46 100644
--- a/keystore2/test_utils/ffi_test_utils.rs
+++ b/keystore2/test_utils/ffi_test_utils.rs
@@ -15,7 +15,9 @@
 //! This module implements helper methods to access the functionalities implemented in CPP.
 
 use crate::key_generations::Error;
-use android_hardware_security_keymint::aidl::android::hardware::security::keymint::Tag::Tag;
+use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
+    SecurityLevel::SecurityLevel, Tag::Tag,
+};
 
 #[cxx::bridge]
 mod ffi {
@@ -35,7 +37,11 @@
         ) -> CxxResult;
         fn buildAsn1DerEncodedWrappedKeyDescription() -> CxxResult;
         fn performCryptoOpUsingKeystoreEngine(grant_id: i64) -> bool;
-        fn getValueFromAttestRecord(cert_buf: Vec<u8>, tag: i32) -> CxxResult;
+        fn getValueFromAttestRecord(
+            cert_buf: Vec<u8>,
+            tag: i32,
+            expected_sec_level: i32,
+        ) -> CxxResult;
         fn getOsVersion() -> u32;
         fn getOsPatchlevel() -> u32;
         fn getVendorPatchlevel() -> u32;
@@ -98,8 +104,12 @@
 }
 
 /// Get the value of the given `Tag` from attestation record.
-pub fn get_value_from_attest_record(cert_buf: &[u8], tag: Tag) -> Result<Vec<u8>, Error> {
-    let result = ffi::getValueFromAttestRecord(cert_buf.to_vec(), tag.0);
+pub fn get_value_from_attest_record(
+    cert_buf: &[u8],
+    tag: Tag,
+    expected_sec_level: SecurityLevel,
+) -> Result<Vec<u8>, Error> {
+    let result = ffi::getValueFromAttestRecord(cert_buf.to_vec(), tag.0, expected_sec_level.0);
     if !result.error && !result.data.is_empty() {
         return Ok(result.data);
     }
diff --git a/keystore2/test_utils/key_generations.rs b/keystore2/test_utils/key_generations.rs
index 24ce6e1..ccf27bc 100644
--- a/keystore2/test_utils/key_generations.rs
+++ b/keystore2/test_utils/key_generations.rs
@@ -470,6 +470,18 @@
     ));
 }
 
+/// Get the key `Authorization` for the given auth `Tag`.
+pub fn get_key_auth(authorizations: &[Authorization], tag: Tag) -> Option<&Authorization> {
+    let auths: Vec<&Authorization> =
+        authorizations.iter().filter(|auth| auth.keyParameter.tag == tag).collect();
+
+    if !auths.is_empty() {
+        Some(auths[0])
+    } else {
+        None
+    }
+}
+
 /// Generate EC Key using given security level and domain with below key parameters and
 /// optionally allow the generated key to be attested with factory provisioned attest key using
 /// given challenge and application id -
diff --git a/keystore2/tests/keystore2_client_attest_key_tests.rs b/keystore2/tests/keystore2_client_attest_key_tests.rs
index f3228ea..c9ef298 100644
--- a/keystore2/tests/keystore2_client_attest_key_tests.rs
+++ b/keystore2/tests/keystore2_client_attest_key_tests.rs
@@ -556,9 +556,12 @@
         cert_chain.extend(attest_key_metadata.certificateChain.as_ref().unwrap());
 
         validate_certchain(&cert_chain).expect("Error while validating cert chain");
-        let attest_id_value =
-            get_value_from_attest_record(key_metadata.certificate.as_ref().unwrap(), attest_id)
-                .expect("Attest id verification failed.");
+        let attest_id_value = get_value_from_attest_record(
+            key_metadata.certificate.as_ref().unwrap(),
+            attest_id,
+            SecurityLevel::TRUSTED_ENVIRONMENT,
+        )
+        .expect("Attest id verification failed.");
         assert_eq!(attest_id_value, value);
     }
 }
diff --git a/keystore2/tests/keystore2_client_authorizations_tests.rs b/keystore2/tests/keystore2_client_authorizations_tests.rs
index e518a1c..fe48acd 100644
--- a/keystore2/tests/keystore2_client_authorizations_tests.rs
+++ b/keystore2/tests/keystore2_client_authorizations_tests.rs
@@ -17,7 +17,12 @@
 use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
     Algorithm::Algorithm, BlockMode::BlockMode, Digest::Digest, EcCurve::EcCurve,
     ErrorCode::ErrorCode, KeyPurpose::KeyPurpose, PaddingMode::PaddingMode,
-    SecurityLevel::SecurityLevel,
+    SecurityLevel::SecurityLevel, Tag::Tag,
+};
+
+use android_system_keystore2::aidl::android::system::keystore2::{
+    IKeystoreSecurityLevel::IKeystoreSecurityLevel, KeyMetadata::KeyMetadata,
+    ResponseCode::ResponseCode,
 };
 
 use keystore2_test_utils::{
@@ -25,10 +30,85 @@
 };
 
 use crate::keystore2_client_test_utils::{
-    delete_app_key, perform_sample_hmac_sign_verify_op, perform_sample_sym_key_decrypt_op,
-    perform_sample_sym_key_encrypt_op, SAMPLE_PLAIN_TEXT,
+    delete_app_key, perform_sample_asym_sign_verify_op, perform_sample_hmac_sign_verify_op,
+    perform_sample_sym_key_decrypt_op, perform_sample_sym_key_encrypt_op, SAMPLE_PLAIN_TEXT,
 };
 
+use keystore2_test_utils::ffi_test_utils::get_value_from_attest_record;
+
+fn generate_key_and_perform_sign_verify_op_max_times(
+    sec_level: &binder::Strong<dyn IKeystoreSecurityLevel>,
+    gen_params: &authorizations::AuthSetBuilder,
+    alias: &str,
+    max_usage_count: i32,
+) -> binder::Result<KeyMetadata> {
+    let key_metadata = key_generations::generate_key(sec_level, gen_params, alias)?;
+
+    // Use above generated key `max_usage_count` times.
+    for _ in 0..max_usage_count {
+        perform_sample_asym_sign_verify_op(sec_level, &key_metadata, None, Some(Digest::SHA_2_256));
+    }
+
+    Ok(key_metadata)
+}
+
+/// Generate a key with `USAGE_COUNT_LIMIT` and verify the key characteristics. Test should be able
+/// to use the key successfully `max_usage_count` times. After exceeding key usage `max_usage_count`
+/// times subsequent attempts to use the key in test should fail with response code `KEY_NOT_FOUND`.
+/// Test should also verify that the attest record includes `USAGE_COUNT_LIMIT` for attested keys.
+fn generate_key_and_perform_op_with_max_usage_limit(
+    sec_level: &binder::Strong<dyn IKeystoreSecurityLevel>,
+    gen_params: &authorizations::AuthSetBuilder,
+    alias: &str,
+    max_usage_count: i32,
+    check_attestation: bool,
+) {
+    // Generate a key and use the key for `max_usage_count` times.
+    let key_metadata = generate_key_and_perform_sign_verify_op_max_times(
+        sec_level,
+        gen_params,
+        alias,
+        max_usage_count,
+    )
+    .unwrap();
+
+    let auth = key_generations::get_key_auth(&key_metadata.authorizations, Tag::USAGE_COUNT_LIMIT)
+        .unwrap();
+    if check_attestation {
+        // Check usage-count-limit is included in attest-record.
+        assert_ne!(
+            gen_params.iter().filter(|kp| kp.tag == Tag::ATTESTATION_CHALLENGE).count(),
+            0,
+            "Attestation challenge is missing in generated key parameters."
+        );
+        let result = get_value_from_attest_record(
+            key_metadata.certificate.as_ref().unwrap(),
+            Tag::USAGE_COUNT_LIMIT,
+            auth.securityLevel,
+        )
+        .expect("Attest id verification failed.");
+        let usage_count: i32 = std::str::from_utf8(&result).unwrap().parse().unwrap();
+        assert_eq!(usage_count, max_usage_count);
+    }
+    if max_usage_count == 1 {
+        assert!(matches!(
+            auth.securityLevel,
+            SecurityLevel::KEYSTORE | SecurityLevel::TRUSTED_ENVIRONMENT
+        ));
+    } else {
+        assert_eq!(auth.securityLevel, SecurityLevel::KEYSTORE);
+    }
+
+    // Try to use the key one more time.
+    let result = key_generations::map_ks_error(sec_level.createOperation(
+        &key_metadata.key,
+        &authorizations::AuthSetBuilder::new().purpose(KeyPurpose::SIGN).digest(Digest::SHA_2_256),
+        false,
+    ));
+    assert!(result.is_err());
+    assert_eq!(Error::Rc(ResponseCode::KEY_NOT_FOUND), result.unwrap_err());
+}
+
 /// Generate a key with `ACTIVE_DATETIME` set to current time. Test should successfully generate
 /// a key and verify the key characteristics. Test should be able to create a sign operation using
 /// the generated key successfully.
@@ -56,7 +136,6 @@
         &authorizations::AuthSetBuilder::new().purpose(KeyPurpose::SIGN).digest(Digest::SHA_2_256),
         alias,
     );
-
     assert!(result.is_ok());
     delete_app_key(&keystore2, alias).unwrap();
 }
@@ -320,3 +399,194 @@
     assert_eq!(Error::Km(ErrorCode::KEY_EXPIRED), result.unwrap_err());
     delete_app_key(&keystore2, alias).unwrap();
 }
+
+/// Generate a key with `BOOTLOADER_ONLY`. Test should successfully generate
+/// a key and verify the key characteristics. Test should fail with error code `INVALID_KEY_BLOB`
+/// during creation of an operation using this key.
+#[test]
+fn keystore2_gen_key_auth_boot_loader_only_op_fail() {
+    let keystore2 = get_keystore_service();
+    let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+    let gen_params = authorizations::AuthSetBuilder::new()
+        .no_auth_required()
+        .algorithm(Algorithm::EC)
+        .purpose(KeyPurpose::SIGN)
+        .purpose(KeyPurpose::VERIFY)
+        .digest(Digest::SHA_2_256)
+        .ec_curve(EcCurve::P_256)
+        .attestation_challenge(b"foo".to_vec())
+        .boot_loader_only();
+
+    let alias = "ks_test_auth_tags_test";
+    let result = key_generations::map_ks_error(key_generations::create_key_and_operation(
+        &sec_level,
+        &gen_params,
+        &authorizations::AuthSetBuilder::new().purpose(KeyPurpose::SIGN).digest(Digest::SHA_2_256),
+        alias,
+    ));
+    assert!(result.is_err());
+    assert_eq!(Error::Km(ErrorCode::INVALID_KEY_BLOB), result.unwrap_err());
+}
+
+/// Generate a key with `EARLY_BOOT_ONLY`. Test should successfully generate
+/// a key and verify the key characteristics. Test should fail with error code `EARLY_BOOT_ENDED`
+/// during creation of an operation using this key.
+#[test]
+fn keystore2_gen_key_auth_early_boot_only_op_fail() {
+    let keystore2 = get_keystore_service();
+    let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+    let gen_params = authorizations::AuthSetBuilder::new()
+        .no_auth_required()
+        .algorithm(Algorithm::EC)
+        .purpose(KeyPurpose::SIGN)
+        .purpose(KeyPurpose::VERIFY)
+        .digest(Digest::SHA_2_256)
+        .ec_curve(EcCurve::P_256)
+        .attestation_challenge(b"foo".to_vec())
+        .early_boot_only();
+
+    let alias = "ks_test_auth_tags_test";
+    let result = key_generations::map_ks_error(key_generations::create_key_and_operation(
+        &sec_level,
+        &gen_params,
+        &authorizations::AuthSetBuilder::new().purpose(KeyPurpose::SIGN).digest(Digest::SHA_2_256),
+        alias,
+    ));
+    assert!(result.is_err());
+    assert_eq!(Error::Km(ErrorCode::EARLY_BOOT_ENDED), result.unwrap_err());
+    delete_app_key(&keystore2, alias).unwrap();
+}
+
+/// Generate a key with `MAX_USES_PER_BOOT`. Test should successfully generate
+/// a key and verify the key characteristics. Test should be able to use the key successfully
+/// `MAX_USES_COUNT` times. After exceeding key usage `MAX_USES_COUNT` times
+/// subsequent attempts to use the key in test should fail with error code MAX_OPS_EXCEEDED.
+#[test]
+fn keystore2_gen_key_auth_max_uses_per_boot() {
+    let keystore2 = get_keystore_service();
+    let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+    const MAX_USES_COUNT: i32 = 3;
+
+    let gen_params = authorizations::AuthSetBuilder::new()
+        .no_auth_required()
+        .algorithm(Algorithm::EC)
+        .purpose(KeyPurpose::SIGN)
+        .purpose(KeyPurpose::VERIFY)
+        .digest(Digest::SHA_2_256)
+        .ec_curve(EcCurve::P_256)
+        .attestation_challenge(b"foo".to_vec())
+        .max_uses_per_boot(MAX_USES_COUNT);
+
+    let alias = "ks_test_auth_tags_test";
+    // Generate a key and use the key for `MAX_USES_COUNT` times.
+    let key_metadata = generate_key_and_perform_sign_verify_op_max_times(
+        &sec_level,
+        &gen_params,
+        alias,
+        MAX_USES_COUNT,
+    )
+    .unwrap();
+
+    // Try to use the key one more time.
+    let result = key_generations::map_ks_error(sec_level.createOperation(
+        &key_metadata.key,
+        &authorizations::AuthSetBuilder::new().purpose(KeyPurpose::SIGN).digest(Digest::SHA_2_256),
+        false,
+    ));
+    assert!(result.is_err());
+    assert_eq!(Error::Km(ErrorCode::KEY_MAX_OPS_EXCEEDED), result.unwrap_err());
+    delete_app_key(&keystore2, alias).unwrap();
+}
+
+/// Generate a key with `USAGE_COUNT_LIMIT`. Test should successfully generate
+/// a key and verify the key characteristics. Test should be able to use the key successfully
+/// `MAX_USES_COUNT` times. After exceeding key usage `MAX_USES_COUNT` times
+/// subsequent attempts to use the key in test should fail with response code `KEY_NOT_FOUND`.
+/// Test should also verify that the attest record includes `USAGE_COUNT_LIMIT`.
+#[test]
+fn keystore2_gen_key_auth_usage_count_limit() {
+    let keystore2 = get_keystore_service();
+    let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+    const MAX_USES_COUNT: i32 = 3;
+
+    let gen_params = authorizations::AuthSetBuilder::new()
+        .no_auth_required()
+        .algorithm(Algorithm::EC)
+        .purpose(KeyPurpose::SIGN)
+        .purpose(KeyPurpose::VERIFY)
+        .digest(Digest::SHA_2_256)
+        .ec_curve(EcCurve::P_256)
+        .attestation_challenge(b"foo".to_vec())
+        .usage_count_limit(MAX_USES_COUNT);
+
+    let alias = "ks_test_auth_tags_test";
+    generate_key_and_perform_op_with_max_usage_limit(
+        &sec_level,
+        &gen_params,
+        alias,
+        MAX_USES_COUNT,
+        true,
+    );
+}
+
+/// Generate a key with `USAGE_COUNT_LIMIT`. Test should successfully generate
+/// a key and verify the key characteristics. Test should be able to use the key successfully
+/// `MAX_USES_COUNT` times. After exceeding key usage `MAX_USES_COUNT` times
+/// subsequent attempts to use the key in test should fail with response code `KEY_NOT_FOUND`.
+/// Test should also verify that the attest record includes `USAGE_COUNT_LIMIT`.
+#[test]
+fn keystore2_gen_key_auth_usage_count_limit_one() {
+    let keystore2 = get_keystore_service();
+    let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+    const MAX_USES_COUNT: i32 = 1;
+
+    let gen_params = authorizations::AuthSetBuilder::new()
+        .no_auth_required()
+        .algorithm(Algorithm::EC)
+        .purpose(KeyPurpose::SIGN)
+        .purpose(KeyPurpose::VERIFY)
+        .digest(Digest::SHA_2_256)
+        .ec_curve(EcCurve::P_256)
+        .attestation_challenge(b"foo".to_vec())
+        .usage_count_limit(MAX_USES_COUNT);
+
+    let alias = "ks_test_auth_tags_test";
+    generate_key_and_perform_op_with_max_usage_limit(
+        &sec_level,
+        &gen_params,
+        alias,
+        MAX_USES_COUNT,
+        true,
+    );
+}
+
+/// Generate a non-attested key with `USAGE_COUNT_LIMIT`. Test should successfully generate
+/// a key and verify the key characteristics. Test should be able to use the key successfully
+/// `MAX_USES_COUNT` times. After exceeding key usage `MAX_USES_COUNT` times
+/// subsequent attempts to use the key in test should fail with response code `KEY_NOT_FOUND`.
+#[test]
+fn keystore2_gen_non_attested_key_auth_usage_count_limit() {
+    let keystore2 = get_keystore_service();
+    let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+    const MAX_USES_COUNT: i32 = 2;
+
+    let gen_params = authorizations::AuthSetBuilder::new()
+        .no_auth_required()
+        .algorithm(Algorithm::EC)
+        .purpose(KeyPurpose::SIGN)
+        .purpose(KeyPurpose::VERIFY)
+        .digest(Digest::SHA_2_256)
+        .ec_curve(EcCurve::P_256)
+        .usage_count_limit(MAX_USES_COUNT);
+
+    let alias = "ks_test_auth_tags_test";
+    generate_key_and_perform_op_with_max_usage_limit(
+        &sec_level,
+        &gen_params,
+        alias,
+        MAX_USES_COUNT,
+        false,
+    );
+}