Added tests to attest keys with attestation id.

- Generate an RSA/EC attested keys with attestation of the device's
  identifiers. Test should succeed in generatating a attested key with
  attestation of device identifier. Test might fail on devices which
  doesn't support device id attestation with error response code
  `CANNOT_ATTEST_IDS or INVALID_TAG`.

- Try to generate an attested key with attestation of invalid device's
  identifiers. Test should fail with error response `CANNOT_ATTEST_IDS`

- Test to make sure `CANNOT_ATTEST_IDS` error code is returned while
  trying to generate a key on a device which doesn't support
  `FEATURE_DEVICE_ID_ATTESTATION`.

Bug: 194359114
Test: atest keystore2_client_test
Change-Id: Ib57c58d3ea89279eb69db342c3343b8d99ddc639
diff --git a/keystore2/test_utils/authorizations.rs b/keystore2/test_utils/authorizations.rs
index 4608bc5..514cbd3 100644
--- a/keystore2/test_utils/authorizations.rs
+++ b/keystore2/test_utils/authorizations.rs
@@ -161,6 +161,87 @@
             .push(KeyParameter { tag: Tag::MIN_MAC_LENGTH, value: KeyParameterValue::Integer(l) });
         self
     }
+
+    /// Add Attestation-Device-Brand.
+    pub fn attestation_device_brand(mut self, b: Vec<u8>) -> Self {
+        self.0.push(KeyParameter {
+            tag: Tag::ATTESTATION_ID_BRAND,
+            value: KeyParameterValue::Blob(b),
+        });
+        self
+    }
+
+    /// Add Attestation-Device-name.
+    pub fn attestation_device_name(mut self, b: Vec<u8>) -> Self {
+        self.0.push(KeyParameter {
+            tag: Tag::ATTESTATION_ID_DEVICE,
+            value: KeyParameterValue::Blob(b),
+        });
+        self
+    }
+
+    /// Add Attestation-Device-Product-Name.
+    pub fn attestation_device_product_name(mut self, b: Vec<u8>) -> Self {
+        self.0.push(KeyParameter {
+            tag: Tag::ATTESTATION_ID_PRODUCT,
+            value: KeyParameterValue::Blob(b),
+        });
+        self
+    }
+
+    /// Add Attestation-Device-Serial.
+    pub fn attestation_device_serial(mut self, b: Vec<u8>) -> Self {
+        self.0.push(KeyParameter {
+            tag: Tag::ATTESTATION_ID_SERIAL,
+            value: KeyParameterValue::Blob(b),
+        });
+        self
+    }
+
+    /// Add Attestation-Device-IMEI.
+    pub fn attestation_device_imei(mut self, b: Vec<u8>) -> Self {
+        self.0.push(KeyParameter {
+            tag: Tag::ATTESTATION_ID_IMEI,
+            value: KeyParameterValue::Blob(b),
+        });
+        self
+    }
+
+    /// Add Attestation-Device-IMEI.
+    pub fn attestation_device_second_imei(mut self, b: Vec<u8>) -> Self {
+        self.0.push(KeyParameter {
+            tag: Tag::ATTESTATION_ID_SECOND_IMEI,
+            value: KeyParameterValue::Blob(b),
+        });
+        self
+    }
+
+    /// Add Attestation-Device-MEID.
+    pub fn attestation_device_meid(mut self, b: Vec<u8>) -> Self {
+        self.0.push(KeyParameter {
+            tag: Tag::ATTESTATION_ID_MEID,
+            value: KeyParameterValue::Blob(b),
+        });
+        self
+    }
+
+    /// Add Attestation-Device-Manufacturer.
+    pub fn attestation_device_manufacturer(mut self, b: Vec<u8>) -> Self {
+        self.0.push(KeyParameter {
+            tag: Tag::ATTESTATION_ID_MANUFACTURER,
+            value: KeyParameterValue::Blob(b),
+        });
+        self
+    }
+
+    /// Add Attestation-Device-Model.
+    pub fn attestation_device_model(mut self, b: Vec<u8>) -> Self {
+        self.0.push(KeyParameter {
+            tag: Tag::ATTESTATION_ID_MODEL,
+            value: KeyParameterValue::Blob(b),
+        });
+        self
+    }
 }
 
 impl Deref for AuthSetBuilder {
diff --git a/keystore2/test_utils/key_generations.rs b/keystore2/test_utils/key_generations.rs
index ff40aa1..0a1ffb1 100644
--- a/keystore2/test_utils/key_generations.rs
+++ b/keystore2/test_utils/key_generations.rs
@@ -306,6 +306,12 @@
     /// Error code to indicate error while using keystore-engine API.
     #[error("Failed to perform crypto op using keystore-engine APIs.")]
     Keystore2EngineOpFailed,
+    /// Error code to indicate error in attestation-id validation.
+    #[error("Failed to validate attestation-id.")]
+    ValidateAttestIdFailed,
+    /// Error code to indicate error in getting value from attest record.
+    #[error("Failed to get value from attest record.")]
+    AttestRecordGetValueFailed,
 }
 
 /// Keystore2 error mapping.
@@ -1109,3 +1115,77 @@
 
     Ok(imported_key_aliases)
 }
+
+/// Generate attested EC-P_256 key with device id attestation.
+pub fn generate_key_with_attest_id(
+    sec_level: &binder::Strong<dyn IKeystoreSecurityLevel>,
+    algorithm: Algorithm,
+    alias: Option<String>,
+    att_challenge: &[u8],
+    attest_key: &KeyDescriptor,
+    attest_id: Tag,
+    value: Vec<u8>,
+) -> binder::Result<KeyMetadata> {
+    assert!(algorithm == Algorithm::RSA || algorithm == Algorithm::EC);
+
+    let mut ec_gen_params;
+    if algorithm == Algorithm::EC {
+        ec_gen_params = 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(att_challenge.to_vec());
+    } else {
+        ec_gen_params = AuthSetBuilder::new()
+            .no_auth_required()
+            .algorithm(Algorithm::RSA)
+            .rsa_public_exponent(65537)
+            .key_size(2048)
+            .purpose(KeyPurpose::SIGN)
+            .purpose(KeyPurpose::VERIFY)
+            .digest(Digest::SHA_2_256)
+            .padding_mode(PaddingMode::RSA_PKCS1_1_5_SIGN)
+            .attestation_challenge(att_challenge.to_vec());
+    }
+
+    match attest_id {
+        Tag::ATTESTATION_ID_BRAND => {
+            ec_gen_params = ec_gen_params.attestation_device_brand(value);
+        }
+        Tag::ATTESTATION_ID_DEVICE => {
+            ec_gen_params = ec_gen_params.attestation_device_name(value);
+        }
+        Tag::ATTESTATION_ID_PRODUCT => {
+            ec_gen_params = ec_gen_params.attestation_device_product_name(value);
+        }
+        Tag::ATTESTATION_ID_SERIAL => {
+            ec_gen_params = ec_gen_params.attestation_device_serial(value);
+        }
+        Tag::ATTESTATION_ID_MANUFACTURER => {
+            ec_gen_params = ec_gen_params.attestation_device_manufacturer(value);
+        }
+        Tag::ATTESTATION_ID_MODEL => {
+            ec_gen_params = ec_gen_params.attestation_device_model(value);
+        }
+        Tag::ATTESTATION_ID_IMEI => {
+            ec_gen_params = ec_gen_params.attestation_device_imei(value);
+        }
+        Tag::ATTESTATION_ID_SECOND_IMEI => {
+            ec_gen_params = ec_gen_params.attestation_device_second_imei(value);
+        }
+        _ => {
+            panic!("Unknown attestation id");
+        }
+    }
+
+    sec_level.generateKey(
+        &KeyDescriptor { domain: Domain::APP, nspace: -1, alias, blob: None },
+        Some(attest_key),
+        &ec_gen_params,
+        0,
+        b"entropy",
+    )
+}
diff --git a/keystore2/tests/Android.bp b/keystore2/tests/Android.bp
index 0c8b0c8..32c39dc 100644
--- a/keystore2/tests/Android.bp
+++ b/keystore2/tests/Android.bp
@@ -58,6 +58,7 @@
         "libkeymaster_messages",
         "libcppbor_external",
         "libkeystore-engine",
+        "libkeymint_support",
     ],
     require_root: true,
 }
diff --git a/keystore2/tests/ffi_test_utils.cpp b/keystore2/tests/ffi_test_utils.cpp
index 47dd7a4..7fbfb8b 100644
--- a/keystore2/tests/ffi_test_utils.cpp
+++ b/keystore2/tests/ffi_test_utils.cpp
@@ -18,6 +18,8 @@
 #include <keymaster/km_openssl/openssl_err.h>
 #include <keymaster/km_openssl/openssl_utils.h>
 
+#include <android-base/logging.h>
+
 using aidl::android::hardware::security::keymint::ErrorCode;
 
 #define TAG_SEQUENCE 0x30
@@ -503,3 +505,94 @@
 #endif
     return result;
 }
+
+CxxResult getValueFromAttestRecord(rust::Vec<rust::u8> cert_buf, int32_t tag) {
+    CxxResult cxx_result{};
+    cxx_result.error = KM_ERROR_OK;
+
+    uint8_t* cert_data = cert_buf.data();
+    int cert_data_size = cert_buf.size();
+
+    std::vector<uint8_t> cert_bytes;
+    cert_bytes.insert(cert_bytes.end(), cert_data, (cert_data + cert_data_size));
+
+    aidl::android::hardware::security::keymint::X509_Ptr cert(
+        aidl::android::hardware::security::keymint::test::parse_cert_blob(cert_bytes));
+    if (!cert.get()) {
+        cxx_result.error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+        return cxx_result;
+    }
+
+    ASN1_OCTET_STRING* attest_rec =
+        aidl::android::hardware::security::keymint::test::get_attestation_record(cert.get());
+    if (!attest_rec) {
+        cxx_result.error = keymaster::TranslateLastOpenSslError();
+        return cxx_result;
+    }
+
+    aidl::android::hardware::security::keymint::AuthorizationSet att_sw_enforced;
+    aidl::android::hardware::security::keymint::AuthorizationSet att_hw_enforced;
+    uint32_t att_attestation_version;
+    uint32_t att_keymint_version;
+    aidl::android::hardware::security::keymint::SecurityLevel att_attestation_security_level;
+    aidl::android::hardware::security::keymint::SecurityLevel att_keymint_security_level;
+    std::vector<uint8_t> att_challenge;
+    std::vector<uint8_t> att_unique_id;
+    std::vector<uint8_t> att_app_id;
+
+    auto error = aidl::android::hardware::security::keymint::parse_attestation_record(
+        attest_rec->data, attest_rec->length, &att_attestation_version,
+        &att_attestation_security_level, &att_keymint_version, &att_keymint_security_level,
+        &att_challenge, &att_sw_enforced, &att_hw_enforced, &att_unique_id);
+    EXPECT_EQ(ErrorCode::OK, error);
+    if (error != ErrorCode::OK) {
+        cxx_result.error = static_cast<int32_t>(error);
+        return cxx_result;
+    }
+
+    aidl::android::hardware::security::keymint::Tag auth_tag =
+        static_cast<aidl::android::hardware::security::keymint::Tag>(tag);
+
+    if (auth_tag == aidl::android::hardware::security::keymint::Tag::ATTESTATION_APPLICATION_ID) {
+        int pos = att_sw_enforced.find(
+            aidl::android::hardware::security::keymint::Tag::ATTESTATION_APPLICATION_ID);
+        if (pos == -1) {
+            cxx_result.error = KM_ERROR_ATTESTATION_APPLICATION_ID_MISSING;
+            return cxx_result;
+        }
+        aidl::android::hardware::security::keymint::KeyParameter param = att_sw_enforced[pos];
+        std::vector<uint8_t> val =
+            param.value.get<aidl::android::hardware::security::keymint::KeyParameterValue::blob>();
+        std::move(val.begin(), val.end(), std::back_inserter(cxx_result.data));
+        return cxx_result;
+    }
+
+    if (auth_tag == aidl::android::hardware::security::keymint::Tag::ATTESTATION_CHALLENGE) {
+        if (att_challenge.size() == 0) {
+            cxx_result.error = KM_ERROR_ATTESTATION_CHALLENGE_MISSING;
+            return cxx_result;
+        }
+        std::move(att_challenge.begin(), att_challenge.end(), std::back_inserter(cxx_result.data));
+        return cxx_result;
+    }
+
+    if (auth_tag == aidl::android::hardware::security::keymint::Tag::UNIQUE_ID) {
+        if (att_unique_id.size() == 0) {
+            cxx_result.error = KM_ERROR_UNSUPPORTED_TAG;
+            return cxx_result;
+        }
+        std::move(att_unique_id.begin(), att_unique_id.end(), std::back_inserter(cxx_result.data));
+        return cxx_result;
+    }
+
+    int pos = att_hw_enforced.find(auth_tag);
+    if (pos == -1) {
+        cxx_result.error = KM_ERROR_UNSUPPORTED_TAG;
+        return cxx_result;
+    }
+    aidl::android::hardware::security::keymint::KeyParameter param = att_hw_enforced[pos];
+    std::vector<uint8_t> val =
+        param.value.get<aidl::android::hardware::security::keymint::KeyParameterValue::blob>();
+    std::move(val.begin(), val.end(), std::back_inserter(cxx_result.data));
+    return cxx_result;
+}
diff --git a/keystore2/tests/ffi_test_utils.hpp b/keystore2/tests/ffi_test_utils.hpp
index 32f29f4..3ed7edc 100644
--- a/keystore2/tests/ffi_test_utils.hpp
+++ b/keystore2/tests/ffi_test_utils.hpp
@@ -10,3 +10,4 @@
                               rust::Vec<rust::u8> tag);
 CxxResult buildAsn1DerEncodedWrappedKeyDescription();
 bool performCryptoOpUsingKeystoreEngine(int64_t grant_id);
+CxxResult getValueFromAttestRecord(rust::Vec<rust::u8> cert_buf, int32_t tag);
diff --git a/keystore2/tests/ffi_test_utils.rs b/keystore2/tests/ffi_test_utils.rs
index 689713a..c652174 100644
--- a/keystore2/tests/ffi_test_utils.rs
+++ b/keystore2/tests/ffi_test_utils.rs
@@ -12,6 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+use android_hardware_security_keymint::aidl::android::hardware::security::keymint::Tag::Tag;
 use keystore2_test_utils::key_generations::Error;
 
 #[cxx::bridge]
@@ -32,6 +33,7 @@
         ) -> CxxResult;
         fn buildAsn1DerEncodedWrappedKeyDescription() -> CxxResult;
         fn performCryptoOpUsingKeystoreEngine(grant_id: i64) -> bool;
+        fn getValueFromAttestRecord(cert_buf: Vec<u8>, tag: i32) -> CxxResult;
     }
 }
 
@@ -87,3 +89,11 @@
 
     Err(Error::Keystore2EngineOpFailed)
 }
+
+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);
+    if result.error == 0 && !result.data.is_empty() {
+        return Ok(result.data);
+    }
+    Err(Error::AttestRecordGetValueFailed)
+}
diff --git a/keystore2/tests/keystore2_client_attest_key_tests.rs b/keystore2/tests/keystore2_client_attest_key_tests.rs
index 4febd9b..b8ad90d 100644
--- a/keystore2/tests/keystore2_client_attest_key_tests.rs
+++ b/keystore2/tests/keystore2_client_attest_key_tests.rs
@@ -17,21 +17,26 @@
 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::{
-    Domain::Domain, KeyDescriptor::KeyDescriptor, ResponseCode::ResponseCode,
+    Domain::Domain, IKeystoreService::IKeystoreService, KeyDescriptor::KeyDescriptor,
+    ResponseCode::ResponseCode,
 };
 
 use keystore2_test_utils::{
     authorizations, get_keystore_service, key_generations, key_generations::Error,
 };
 
-use crate::ffi_test_utils::validate_certchain;
+use crate::ffi_test_utils::{get_value_from_attest_record, validate_certchain};
 
 use crate::{
-    keystore2_client_test_utils::app_attest_key_feature_exists,
-    skip_test_if_no_app_attest_key_feature,
+    skip_test_if_no_app_attest_key_feature, skip_test_if_no_device_id_attestation_feature,
+};
+
+use crate::keystore2_client_test_utils::{
+    app_attest_key_feature_exists, device_id_attestation_feature_exists, get_attest_id_value,
+    is_second_imei_id_attestation_required,
 };
 
 /// Generate RSA and EC attestation keys and use them for signing RSA-signing keys.
@@ -480,3 +485,178 @@
     // Should not have an attestation record.
     assert!(aes_key_metadata.certificateChain.is_none());
 }
+
+fn get_attestation_ids(keystore2: &binder::Strong<dyn IKeystoreService>) -> Vec<(Tag, Vec<u8>)> {
+    let attest_ids = vec![
+        (Tag::ATTESTATION_ID_BRAND, "ro.product.brand_for_attestation"),
+        (Tag::ATTESTATION_ID_DEVICE, "ro.product.device"),
+        (Tag::ATTESTATION_ID_PRODUCT, "ro.product.name_for_attestation"),
+        (Tag::ATTESTATION_ID_SERIAL, "ro.serialno"),
+        (Tag::ATTESTATION_ID_MANUFACTURER, "ro.product.manufacturer"),
+        (Tag::ATTESTATION_ID_MODEL, "ro.product.model_for_attestation"),
+        (Tag::ATTESTATION_ID_IMEI, ""), //Get this value from Telephony service.
+        (Tag::ATTESTATION_ID_SECOND_IMEI, ""), //Get this value from Telephony service.
+    ];
+
+    let mut attest_id_params: Vec<(Tag, Vec<u8>)> = vec![];
+    for (attest_id, prop_name) in attest_ids {
+        if attest_id == Tag::ATTESTATION_ID_SECOND_IMEI
+            && !is_second_imei_id_attestation_required(keystore2)
+        {
+            continue;
+        }
+
+        if let Some(value) = get_attest_id_value(attest_id, prop_name) {
+            if !value.is_empty() {
+                attest_id_params.push((attest_id, value));
+            }
+        }
+    }
+
+    attest_id_params
+}
+
+/// Generate an attested key with attestation of the device's identifiers. Test should succeed in
+/// generating a attested key with attestation of device identifiers. Test might fail on devices
+/// which don't support device id attestation with error response code `CANNOT_ATTEST_IDS or
+/// INVALID_TAG`
+fn generate_attested_key_with_device_attest_ids(algorithm: Algorithm) {
+    skip_test_if_no_device_id_attestation_feature!();
+    let keystore2 = get_keystore_service();
+    let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+    let att_challenge: &[u8] = b"foo";
+
+    let attest_key_metadata =
+        key_generations::generate_attestation_key(&sec_level, algorithm, att_challenge).unwrap();
+
+    let attest_id_params = get_attestation_ids(&keystore2);
+
+    for (attest_id, value) in attest_id_params {
+        // Create RSA/EC key and use attestation key to sign it.
+        let key_alias = format!("ks_attested_test_key_{}", getuid());
+        let key_metadata =
+            key_generations::map_ks_error(key_generations::generate_key_with_attest_id(
+                &sec_level,
+                algorithm,
+                Some(key_alias),
+                att_challenge,
+                &attest_key_metadata.key,
+                attest_id,
+                value.clone(),
+            ))
+            .unwrap();
+
+        assert!(key_metadata.certificate.is_some());
+        assert!(key_metadata.certificateChain.is_none());
+
+        let mut cert_chain: Vec<u8> = Vec::new();
+        cert_chain.extend(key_metadata.certificate.as_ref().unwrap());
+        cert_chain.extend(attest_key_metadata.certificate.as_ref().unwrap());
+        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.");
+        assert_eq!(attest_id_value, value);
+    }
+}
+
+#[test]
+fn keystore2_attest_ecdsa_attestation_id() {
+    generate_attested_key_with_device_attest_ids(Algorithm::EC);
+}
+
+#[test]
+fn keystore2_attest_rsa_attestation_id() {
+    generate_attested_key_with_device_attest_ids(Algorithm::RSA);
+}
+
+/// Try to generate an attested key with attestation of invalid device's identifiers. Test should
+/// fail with error response code `CANNOT_ATTEST_IDS`.
+#[test]
+fn keystore2_attest_key_fails_with_invalid_attestation_id() {
+    skip_test_if_no_device_id_attestation_feature!();
+
+    let keystore2 = get_keystore_service();
+    let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+    let digest = Digest::SHA_2_256;
+    let att_challenge: &[u8] = b"foo";
+
+    // Create EC-Attestation key.
+    let attest_key_metadata = key_generations::generate_ec_attestation_key(
+        &sec_level,
+        att_challenge,
+        digest,
+        EcCurve::P_256,
+    )
+    .unwrap();
+
+    let attest_id_params = vec![
+        (Tag::ATTESTATION_ID_BRAND, b"invalid-brand".to_vec()),
+        (Tag::ATTESTATION_ID_DEVICE, b"invalid-device-name".to_vec()),
+        (Tag::ATTESTATION_ID_PRODUCT, b"invalid-product-name".to_vec()),
+        (Tag::ATTESTATION_ID_SERIAL, b"invalid-ro-serial".to_vec()),
+        (Tag::ATTESTATION_ID_MANUFACTURER, b"invalid-ro-product-manufacturer".to_vec()),
+        (Tag::ATTESTATION_ID_MODEL, b"invalid-ro-product-model".to_vec()),
+        (Tag::ATTESTATION_ID_IMEI, b"invalid-imei".to_vec()),
+    ];
+
+    for (attest_id, value) in attest_id_params {
+        // Create EC key and use attestation key to sign it.
+        let ec_key_alias = format!("ks_ec_attested_test_key_fail_{}{}", getuid(), digest.0);
+        let result = key_generations::map_ks_error(key_generations::generate_key_with_attest_id(
+            &sec_level,
+            Algorithm::EC,
+            Some(ec_key_alias),
+            att_challenge,
+            &attest_key_metadata.key,
+            attest_id,
+            value,
+        ));
+
+        assert!(result.is_err());
+        assert_eq!(result.unwrap_err(), Error::Km(ErrorCode::CANNOT_ATTEST_IDS));
+    }
+}
+
+///  If `DEVICE_ID_ATTESTATION_FEATURE` is not supported then test tries to generate an attested
+///  key with attestation of valid device's identifiers. Test should fail to generate key with
+///  error code `CANNOT_ATTEST_IDS`.
+#[test]
+fn keystore2_attest_key_without_attestation_id_support_fails_with_cannot_attest_id() {
+    if device_id_attestation_feature_exists() {
+        // Skip this test on device supporting `DEVICE_ID_ATTESTATION_FEATURE`.
+        return;
+    }
+
+    let keystore2 = get_keystore_service();
+    let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+    let att_challenge: &[u8] = b"foo";
+    let attest_key_metadata =
+        key_generations::generate_attestation_key(&sec_level, Algorithm::RSA, att_challenge)
+            .unwrap();
+
+    let attest_id_params = get_attestation_ids(&keystore2);
+    for (attest_id, value) in attest_id_params {
+        // Create RSA/EC key and use attestation key to sign it.
+        let key_alias = format!("ks_attested_test_key_{}", getuid());
+        let result = key_generations::map_ks_error(key_generations::generate_key_with_attest_id(
+            &sec_level,
+            Algorithm::RSA,
+            Some(key_alias),
+            att_challenge,
+            &attest_key_metadata.key,
+            attest_id,
+            value.clone(),
+        ));
+        assert!(
+            result.is_err(),
+            "Expected to fail as FEATURE_DEVICE_ID_ATTESTATION is not supported."
+        );
+        assert_eq!(result.unwrap_err(), Error::Km(ErrorCode::CANNOT_ATTEST_IDS));
+    }
+}
diff --git a/keystore2/tests/keystore2_client_test_utils.rs b/keystore2/tests/keystore2_client_test_utils.rs
index 07c2183..3354798 100644
--- a/keystore2/tests/keystore2_client_test_utils.rs
+++ b/keystore2/tests/keystore2_client_test_utils.rs
@@ -15,6 +15,8 @@
 use nix::unistd::{Gid, Uid};
 use serde::{Deserialize, Serialize};
 
+use std::process::{Command, Output};
+
 use openssl::encrypt::Encrypter;
 use openssl::error::ErrorStack;
 use openssl::hash::MessageDigest;
@@ -66,6 +68,7 @@
 
 pub const PACKAGE_MANAGER_NATIVE_SERVICE: &str = "package_native";
 pub const APP_ATTEST_KEY_FEATURE: &str = "android.hardware.keystore.app_attest_key";
+pub const DEVICE_ID_ATTESTATION_FEATURE: &str = "android.software.device_id_attestation";
 
 /// Determines whether app_attest_key_feature is supported or not.
 pub fn app_attest_key_feature_exists() -> bool {
@@ -75,6 +78,14 @@
     pm.hasSystemFeature(APP_ATTEST_KEY_FEATURE, 0).expect("hasSystemFeature failed.")
 }
 
+/// Determines whether device_id_attestation is supported or not.
+pub fn device_id_attestation_feature_exists() -> bool {
+    let pm = wait_for_interface::<dyn IPackageManagerNative>(PACKAGE_MANAGER_NATIVE_SERVICE)
+        .expect("Failed to get package manager native service.");
+
+    pm.hasSystemFeature(DEVICE_ID_ATTESTATION_FEATURE, 0).expect("hasSystemFeature failed.")
+}
+
 #[macro_export]
 macro_rules! skip_test_if_no_app_attest_key_feature {
     () => {
@@ -84,6 +95,15 @@
     };
 }
 
+#[macro_export]
+macro_rules! skip_test_if_no_device_id_attestation_feature {
+    () => {
+        if !device_id_attestation_feature_exists() {
+            return;
+        }
+    };
+}
+
 /// Indicate whether the default device is KeyMint (rather than Keymaster).
 pub fn has_default_keymint() -> bool {
     binder::is_declared("android.hardware.security.keymint.IKeyMintDevice/default")
@@ -444,3 +464,84 @@
         .iter()
         .all(|key| expected_aliases.contains(key.alias.as_ref().unwrap())));
 }
+
+// Get the value of the given system property, if the given system property doesn't exist
+// then returns an empty byte vector.
+pub fn get_system_prop(name: &str) -> Vec<u8> {
+    match rustutils::system_properties::read(name) {
+        Ok(Some(value)) => {
+            return value.as_bytes().to_vec();
+        }
+        _ => {
+            vec![]
+        }
+    }
+}
+
+/// Determines whether the SECOND-IMEI can be used as device attest-id.
+pub fn is_second_imei_id_attestation_required(
+    keystore2: &binder::Strong<dyn IKeystoreService>,
+) -> bool {
+    let api_level = std::str::from_utf8(&get_system_prop("ro.vendor.api_level"))
+        .unwrap()
+        .parse::<i32>()
+        .unwrap();
+    keystore2.getInterfaceVersion().unwrap() >= 3 && api_level > 33
+}
+
+/// Run a service command and collect the output.
+pub fn run_service_command(command: &[&str]) -> std::io::Result<Output> {
+    Command::new("cmd").args(command).output()
+}
+
+/// Get IMEI from telephony service.
+pub fn get_imei(slot: i32) -> Option<Vec<u8>> {
+    let mut cmd = vec!["phone", "get-imei"];
+    let slot_str = slot.to_string();
+    cmd.push(slot_str.as_str());
+    let output = run_service_command(&cmd).unwrap();
+    if output.status.success() {
+        let stdout = String::from_utf8(output.stdout).unwrap();
+        let mut split_out = stdout.split_whitespace();
+        let imei = split_out.next_back().unwrap();
+        if imei == "null" {
+            return None;
+        }
+        return Some(imei.as_bytes().to_vec());
+    }
+
+    None
+}
+
+/// Get value of the given attestation id.
+pub fn get_attest_id_value(attest_id: Tag, prop_name: &str) -> Option<Vec<u8>> {
+    match attest_id {
+        Tag::ATTESTATION_ID_IMEI => get_imei(0),
+        Tag::ATTESTATION_ID_SECOND_IMEI => get_imei(1),
+        Tag::ATTESTATION_ID_BRAND => {
+            let prop_val = get_system_prop(prop_name);
+            if prop_val.is_empty() {
+                Some(get_system_prop("ro.product.brand"))
+            } else {
+                Some(prop_val)
+            }
+        }
+        Tag::ATTESTATION_ID_PRODUCT => {
+            let prop_val = get_system_prop(prop_name);
+            if prop_val.is_empty() {
+                Some(get_system_prop("ro.product.name"))
+            } else {
+                Some(prop_val)
+            }
+        }
+        Tag::ATTESTATION_ID_MODEL => {
+            let prop_val = get_system_prop(prop_name);
+            if prop_val.is_empty() {
+                Some(get_system_prop("ro.product.model"))
+            } else {
+                Some(prop_val)
+            }
+        }
+        _ => Some(get_system_prop(prop_name)),
+    }
+}