Changes to strictly validate multiple `KeyPurpose` parameters
with KeyMint-V2 onward and to skip real key attestation using
emulated curve-25519 key on device with KeyMint V1 or Keymaster.

Bug: 353162976
Test: atest keystore2_client_tests
Change-Id: I95172afbf5cc351774447ba7bf430ceec9162a6b
diff --git a/keystore2/test_utils/lib.rs b/keystore2/test_utils/lib.rs
index 8b766dd..825657f 100644
--- a/keystore2/test_utils/lib.rs
+++ b/keystore2/test_utils/lib.rs
@@ -24,7 +24,7 @@
     IKeystoreSecurityLevel::IKeystoreSecurityLevel,
 };
 use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
-    ErrorCode::ErrorCode, SecurityLevel::SecurityLevel,
+    ErrorCode::ErrorCode, IKeyMintDevice::IKeyMintDevice, SecurityLevel::SecurityLevel,
 };
 use android_security_authorization::aidl::android::security::authorization::IKeystoreAuthorization::IKeystoreAuthorization;
 
@@ -176,4 +176,21 @@
     pub fn is_keymaster(&self) -> bool {
         !self.is_keymint()
     }
+
+    /// Get KeyMint version.
+    /// Returns 0 if the underlying device is Keymaster not KeyMint.
+    pub fn get_keymint_version(&self) -> i32 {
+        let instance = match self.level {
+            SecurityLevel::TRUSTED_ENVIRONMENT => "default",
+            SecurityLevel::STRONGBOX => "strongbox",
+            l => panic!("unexpected level {l:?}"),
+        };
+        let name = format!("android.hardware.security.keymint.IKeyMintDevice/{instance}");
+        if binder::is_declared(&name).expect("Could not check for declared keymint interface") {
+            let km: binder::Strong<dyn IKeyMintDevice> = binder::get_interface(&name).unwrap();
+            km.getInterfaceVersion().unwrap()
+        } else {
+            0
+        }
+    }
 }
diff --git a/keystore2/tests/keystore2_client_attest_key_tests.rs b/keystore2/tests/keystore2_client_attest_key_tests.rs
index b51896a..a303ee8 100644
--- a/keystore2/tests/keystore2_client_attest_key_tests.rs
+++ b/keystore2/tests/keystore2_client_attest_key_tests.rs
@@ -177,6 +177,13 @@
     skip_test_if_no_app_attest_key_feature!();
 
     let sl = SecLevel::tee();
+    if sl.get_keymint_version() < 2 {
+        // Curve 25519 was included in version 2 of the KeyMint interface.
+        // For device with KeyMint-V1 or Keymaster in backend, emulated Ed25519 key can't attest
+        // to a "real" RSA key.
+        return;
+    }
+
     let att_challenge: &[u8] = b"foo";
 
     // Create EcCurve::CURVE_25519 attestation key.
@@ -226,6 +233,13 @@
 fn keystore2_generate_rsa_attest_key_with_multi_purpose_fail() {
     skip_test_if_no_app_attest_key_feature!();
     let sl = SecLevel::tee();
+    if sl.get_keymint_version() < 2 {
+        // The KeyMint v1 spec required that KeyPurpose::ATTEST_KEY not be combined
+        // with other key purposes.  However, this was not checked at the time
+        // so we can only be strict about checking this for implementations of KeyMint
+        // version 2 and above.
+        return;
+    }
 
     let digest = Digest::SHA_2_256;
     let padding = PaddingMode::RSA_PKCS1_1_5_SIGN;
@@ -267,6 +281,13 @@
 fn keystore2_ec_attest_key_with_multi_purpose_fail() {
     skip_test_if_no_app_attest_key_feature!();
     let sl = SecLevel::tee();
+    if sl.get_keymint_version() < 2 {
+        // The KeyMint v1 spec required that KeyPurpose::ATTEST_KEY not be combined
+        // with other key purposes.  However, this was not checked at the time
+        // so we can only be strict about checking this for implementations of KeyMint
+        // version 2 and above.
+        return;
+    }
 
     let attest_key_alias = format!("ks_ec_attest_multipurpose_key_{}", getuid());
 
diff --git a/keystore2/tests/keystore2_client_import_keys_tests.rs b/keystore2/tests/keystore2_client_import_keys_tests.rs
index b06303e..f3a267b 100644
--- a/keystore2/tests/keystore2_client_import_keys_tests.rs
+++ b/keystore2/tests/keystore2_client_import_keys_tests.rs
@@ -247,8 +247,8 @@
 }
 
 /// Try to import a key with multiple purposes. Test should fail to import a key with
-/// `INCOMPATIBLE_PURPOSE` error code. If the backend is `keymaster` then `importKey` shall be
-/// successful.
+/// `INCOMPATIBLE_PURPOSE` error code. If the backend is `keymaster` or KeyMint-version-1 then
+/// `importKey` shall be successful.
 #[test]
 fn keystore2_rsa_import_key_with_multipurpose_fails_incompt_purpose_error() {
     let sl = SecLevel::tee();
@@ -276,8 +276,14 @@
     ));
 
     if sl.is_keymint() {
-        assert!(result.is_err());
-        assert_eq!(Error::Km(ErrorCode::INCOMPATIBLE_PURPOSE), result.unwrap_err());
+        if sl.get_keymint_version() >= 2 {
+            // The KeyMint v1 spec required that KeyPurpose::ATTEST_KEY not be combined
+            // with other key purposes.  However, this was not checked at the time
+            // so we can only be strict about checking this for implementations of KeyMint
+            // version 2 and above.
+            assert!(result.is_err());
+            assert_eq!(Error::Km(ErrorCode::INCOMPATIBLE_PURPOSE), result.unwrap_err());
+        }
     } else {
         assert!(result.is_ok());
     }
diff --git a/keystore2/tests/keystore2_client_key_agreement_tests.rs b/keystore2/tests/keystore2_client_key_agreement_tests.rs
index 19f6210..6744b60 100644
--- a/keystore2/tests/keystore2_client_key_agreement_tests.rs
+++ b/keystore2/tests/keystore2_client_key_agreement_tests.rs
@@ -112,7 +112,7 @@
 test_ec_key_agree!(test_ec_p384_key_agreement, EcCurve::P_384);
 test_ec_key_agree!(test_ec_p521_key_agreement, EcCurve::P_521);
 
-/// Generate two EC keys with curve `CURVE_25519` from KeyMint and OpeanSSL.
+/// Generate two EC keys with curve `CURVE_25519` from KeyMint and OpenSSL.
 /// Perform local ECDH between them and verify that the derived secrets are the same.
 #[test]
 fn keystore2_ec_25519_agree_key_success() {