Adding tests to verify `EVP_PKEY_from_keystore2` API [Keystore2-engine].

1. Generate RSA key and grant it to a user. In user context load the
   key using `EVP_PKEY_from_keystore` and perform sign and verify
   opeearions.
   [keystore2_perofrm_crypto_op_using_keystore2_engine_rsa_key_success]

2. Generate EC key and grant it to a user. In user context load the
   key using `EVP_PKEY_from_keystore` and perform sign and verify
   operations.
   [keystore2_perofrm_crypto_op_using_keystore2_engine_ec_key_success]

3. Generate RSA key and grant it to a user. Re-encode the certificate
   as PEM and update the certificate using `updateSubcomponents`.
   In user context load the key using `EVP_PKEY_from_keystore` and
   perform sign and verify operations.

Bug: 201343811
Test: atest keystore2_client_tests
Change-Id: I7dafd598f4198e11103cd11695b2f67636f24755
diff --git a/keystore-engine/Android.bp b/keystore-engine/Android.bp
index cb75cde..52a2aef 100644
--- a/keystore-engine/Android.bp
+++ b/keystore-engine/Android.bp
@@ -36,7 +36,7 @@
     ],
 
     shared_libs: [
-        "android.system.keystore2-V1-ndk",
+        "android.system.keystore2-V3-ndk",
         "libbinder_ndk",
         "libcrypto",
         "libcutils",
diff --git a/keystore2/test_utils/key_generations.rs b/keystore2/test_utils/key_generations.rs
index e4c4968..3422ce8 100644
--- a/keystore2/test_utils/key_generations.rs
+++ b/keystore2/test_utils/key_generations.rs
@@ -299,6 +299,9 @@
     /// Error code to indicate error in ASN.1 DER-encoded data creation.
     #[error("Failed to create and encode ASN.1 data.")]
     DerEncodeFailed,
+    /// Error code to indicate error while using keystore-engine API.
+    #[error("Failed to perform crypto op using keystore-engine APIs.")]
+    Keystore2EngineOpFailed,
 }
 
 /// Keystore2 error mapping.
diff --git a/keystore2/tests/Android.bp b/keystore2/tests/Android.bp
index 78dd2d7..0c8b0c8 100644
--- a/keystore2/tests/Android.bp
+++ b/keystore2/tests/Android.bp
@@ -57,6 +57,7 @@
         "libkeymaster_portable",
         "libkeymaster_messages",
         "libcppbor_external",
+        "libkeystore-engine",
     ],
     require_root: true,
 }
@@ -80,6 +81,7 @@
         "libkeymaster_portable",
         "libkeymaster_messages",
         "libcppbor_external",
+        "libkeystore-engine",
     ],
 }
 
diff --git a/keystore2/tests/ffi_test_utils.cpp b/keystore2/tests/ffi_test_utils.cpp
index de20d83..47dd7a4 100644
--- a/keystore2/tests/ffi_test_utils.cpp
+++ b/keystore2/tests/ffi_test_utils.cpp
@@ -2,11 +2,12 @@
 
 #include <iostream>
 
+#include <android-base/logging.h>
+
 #include <KeyMintAidlTestBase.h>
 #include <aidl/android/hardware/security/keymint/ErrorCode.h>
 #include <keymaster/UniquePtr.h>
 
-#include <memory>
 #include <vector>
 
 #include <hardware/keymaster_defs.h>
@@ -16,7 +17,6 @@
 #include <keymaster/km_openssl/attestation_record.h>
 #include <keymaster/km_openssl/openssl_err.h>
 #include <keymaster/km_openssl/openssl_utils.h>
-#include <openssl/asn1t.h>
 
 using aidl::android::hardware::security::keymint::ErrorCode;
 
@@ -24,6 +24,9 @@
 #define LENGTH_MASK 0x80
 #define LENGTH_VALUE_MASK 0x7F
 
+/* EVP_PKEY_from_keystore is from system/security/keystore-engine. */
+extern "C" EVP_PKEY* EVP_PKEY_from_keystore(const char* key_id);
+
 /**
  * ASN.1 structure for `KeyDescription` Schema.
  * See `IKeyMintDevice.aidl` for documentation of the `KeyDescription` schema.
@@ -84,6 +87,8 @@
     void operator()(TEST_SECURE_KEY_WRAPPER* p) { TEST_SECURE_KEY_WRAPPER_free(p); }
 };
 
+const std::string keystore2_grant_id_prefix("ks2_keystore-engine_grant_id:");
+
 /* This function extracts a certificate from the certs_chain_buffer at the given
  * offset. Each DER encoded certificate starts with TAG_SEQUENCE followed by the
  * total length of the certificate. The length of the certificate is determined
@@ -364,3 +369,137 @@
 
     return cxx_result;
 }
+
+/**
+ * Perform EC/RSA sign operation using `EVP_PKEY`.
+ */
+bool performSignData(const char* data, size_t data_len, EVP_PKEY* pkey, unsigned char** signature,
+                     size_t* signature_len) {
+    // Create the signing context
+    EVP_MD_CTX* md_ctx = EVP_MD_CTX_new();
+    if (md_ctx == NULL) {
+        LOG(ERROR) << "Failed to create signing context";
+        return false;
+    }
+
+    // Initialize the signing operation
+    if (EVP_DigestSignInit(md_ctx, NULL, EVP_sha256(), NULL, pkey) != 1) {
+        LOG(ERROR) << "Failed to initialize signing operation";
+        EVP_MD_CTX_free(md_ctx);
+        return false;
+    }
+
+    // Sign the data
+    if (EVP_DigestSignUpdate(md_ctx, data, data_len) != 1) {
+        LOG(ERROR) << "Failed to sign data";
+        EVP_MD_CTX_free(md_ctx);
+        return false;
+    }
+
+    // Determine the length of the signature
+    if (EVP_DigestSignFinal(md_ctx, NULL, signature_len) != 1) {
+        LOG(ERROR) << "Failed to determine signature length";
+        EVP_MD_CTX_free(md_ctx);
+        return false;
+    }
+
+    // Allocate memory for the signature
+    *signature = (unsigned char*)malloc(*signature_len);
+    if (*signature == NULL) {
+        LOG(ERROR) << "Failed to allocate memory for the signature";
+        EVP_MD_CTX_free(md_ctx);
+        return false;
+    }
+
+    // Perform the final signing operation
+    if (EVP_DigestSignFinal(md_ctx, *signature, signature_len) != 1) {
+        LOG(ERROR) << "Failed to perform signing operation";
+        free(*signature);
+        EVP_MD_CTX_free(md_ctx);
+        return false;
+    }
+
+    EVP_MD_CTX_free(md_ctx);
+    return true;
+}
+
+/**
+ * Perform EC/RSA verify operation using `EVP_PKEY`.
+ */
+int performVerifySignature(const char* data, size_t data_len, EVP_PKEY* pkey,
+                           const unsigned char* signature, size_t signature_len) {
+    // Create the verification context
+    EVP_MD_CTX* md_ctx = EVP_MD_CTX_new();
+    if (md_ctx == NULL) {
+        LOG(ERROR) << "Failed to create verification context";
+        return false;
+    }
+
+    // Initialize the verification operation
+    if (EVP_DigestVerifyInit(md_ctx, NULL, EVP_sha256(), NULL, pkey) != 1) {
+        LOG(ERROR) << "Failed to initialize verification operation";
+        EVP_MD_CTX_free(md_ctx);
+        return false;
+    }
+
+    // Verify the data
+    if (EVP_DigestVerifyUpdate(md_ctx, data, data_len) != 1) {
+        LOG(ERROR) << "Failed to verify data";
+        EVP_MD_CTX_free(md_ctx);
+        return false;
+    }
+
+    // Perform the verification operation
+    int ret = EVP_DigestVerifyFinal(md_ctx, signature, signature_len);
+    EVP_MD_CTX_free(md_ctx);
+
+    return ret == 1;
+}
+
+/**
+ * Extract the `EVP_PKEY` for the given KeyMint Key and perform Sign/Verify operations
+ * using extracted `EVP_PKEY`.
+ */
+bool performCryptoOpUsingKeystoreEngine(int64_t grant_id) {
+    const int KEY_ID_LEN = 20;
+    char key_id[KEY_ID_LEN] = "";
+    snprintf(key_id, KEY_ID_LEN, "%" PRIx64, grant_id);
+    std::string str_key = std::string(keystore2_grant_id_prefix) + key_id;
+    bool result = false;
+
+#if defined(OPENSSL_IS_BORINGSSL)
+    EVP_PKEY* evp = EVP_PKEY_from_keystore(str_key.c_str());
+    if (!evp) {
+        LOG(ERROR) << "Error while loading a key from keystore-engine";
+        return false;
+    }
+
+    int algo_type = EVP_PKEY_id(evp);
+    if (algo_type != EVP_PKEY_RSA && algo_type != EVP_PKEY_EC) {
+        LOG(ERROR) << "Unsupported Algorithm. Only RSA and EC are allowed.";
+        EVP_PKEY_free(evp);
+        return false;
+    }
+
+    unsigned char* signature = NULL;
+    size_t signature_len = 0;
+    const char* INPUT_DATA = "MY MESSAGE FOR SIGN";
+    size_t data_len = strlen(INPUT_DATA);
+    if (!performSignData(INPUT_DATA, data_len, evp, &signature, &signature_len)) {
+        LOG(ERROR) << "Failed to sign data";
+        EVP_PKEY_free(evp);
+        return false;
+    }
+
+    result = performVerifySignature(INPUT_DATA, data_len, evp, signature, signature_len);
+    if (!result) {
+        LOG(ERROR) << "Signature verification failed";
+    } else {
+        LOG(INFO) << "Signature verification success";
+    }
+
+    free(signature);
+    EVP_PKEY_free(evp);
+#endif
+    return result;
+}
diff --git a/keystore2/tests/ffi_test_utils.hpp b/keystore2/tests/ffi_test_utils.hpp
index b8c7c48..32f29f4 100644
--- a/keystore2/tests/ffi_test_utils.hpp
+++ b/keystore2/tests/ffi_test_utils.hpp
@@ -9,3 +9,4 @@
                               rust::Vec<rust::u8> iv,
                               rust::Vec<rust::u8> tag);
 CxxResult buildAsn1DerEncodedWrappedKeyDescription();
+bool performCryptoOpUsingKeystoreEngine(int64_t grant_id);
diff --git a/keystore2/tests/ffi_test_utils.rs b/keystore2/tests/ffi_test_utils.rs
index 066d4a1..689713a 100644
--- a/keystore2/tests/ffi_test_utils.rs
+++ b/keystore2/tests/ffi_test_utils.rs
@@ -31,6 +31,7 @@
             tag: Vec<u8>,
         ) -> CxxResult;
         fn buildAsn1DerEncodedWrappedKeyDescription() -> CxxResult;
+        fn performCryptoOpUsingKeystoreEngine(grant_id: i64) -> bool;
     }
 }
 
@@ -78,3 +79,11 @@
 pub fn create_wrapped_key_additional_auth_data() -> Result<Vec<u8>, Error> {
     get_result(ffi::buildAsn1DerEncodedWrappedKeyDescription())
 }
+
+pub fn perform_crypto_op_using_keystore_engine(grant_id: i64) -> Result<bool, Error> {
+    if ffi::performCryptoOpUsingKeystoreEngine(grant_id) {
+        return Ok(true);
+    }
+
+    Err(Error::Keystore2EngineOpFailed)
+}
diff --git a/keystore2/tests/keystore2_client_keystore_engine_tests.rs b/keystore2/tests/keystore2_client_keystore_engine_tests.rs
new file mode 100644
index 0000000..1aed8e6
--- /dev/null
+++ b/keystore2/tests/keystore2_client_keystore_engine_tests.rs
@@ -0,0 +1,299 @@
+// 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.
+
+use nix::unistd::{Gid, Uid};
+use rustutils::users::AID_USER_OFFSET;
+
+use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
+    Algorithm::Algorithm, Digest::Digest, EcCurve::EcCurve, KeyPurpose::KeyPurpose,
+    PaddingMode::PaddingMode, SecurityLevel::SecurityLevel,
+};
+use android_system_keystore2::aidl::android::system::keystore2::{
+    Domain::Domain, IKeystoreSecurityLevel::IKeystoreSecurityLevel,
+    IKeystoreService::IKeystoreService, KeyDescriptor::KeyDescriptor, KeyPermission::KeyPermission,
+};
+
+use keystore2_test_utils::{authorizations::AuthSetBuilder, get_keystore_service, run_as};
+
+use crate::ffi_test_utils::perform_crypto_op_using_keystore_engine;
+
+use openssl::x509::X509;
+
+fn generate_rsa_key_and_grant_to_user(
+    keystore2: &binder::Strong<dyn IKeystoreService>,
+    sec_level: &binder::Strong<dyn IKeystoreSecurityLevel>,
+    alias: &str,
+    grantee_uid: i32,
+    access_vector: i32,
+) -> binder::Result<KeyDescriptor> {
+    let gen_params = AuthSetBuilder::new()
+        .no_auth_required()
+        .algorithm(Algorithm::RSA)
+        .rsa_public_exponent(65537)
+        .key_size(2048)
+        .purpose(KeyPurpose::SIGN)
+        .purpose(KeyPurpose::VERIFY)
+        .padding_mode(PaddingMode::NONE)
+        .digest(Digest::NONE);
+
+    let key_metadata = sec_level
+        .generateKey(
+            &KeyDescriptor {
+                domain: Domain::APP,
+                nspace: -1,
+                alias: Some(alias.to_string()),
+                blob: None,
+            },
+            None,
+            &gen_params,
+            0,
+            b"entropy",
+        )
+        .expect("Failed to generate RSA Key.");
+
+    assert!(key_metadata.certificate.is_some());
+
+    keystore2.grant(&key_metadata.key, grantee_uid, access_vector)
+}
+
+fn generate_ec_key_and_grant_to_user(
+    keystore2: &binder::Strong<dyn IKeystoreService>,
+    sec_level: &binder::Strong<dyn IKeystoreSecurityLevel>,
+    alias: &str,
+    grantee_uid: i32,
+    access_vector: i32,
+) -> binder::Result<KeyDescriptor> {
+    let gen_params = AuthSetBuilder::new()
+        .no_auth_required()
+        .algorithm(Algorithm::EC)
+        .purpose(KeyPurpose::SIGN)
+        .purpose(KeyPurpose::VERIFY)
+        .digest(Digest::NONE)
+        .ec_curve(EcCurve::P_256);
+
+    let key_metadata = sec_level
+        .generateKey(
+            &KeyDescriptor {
+                domain: Domain::APP,
+                nspace: -1,
+                alias: Some(alias.to_string()),
+                blob: None,
+            },
+            None,
+            &gen_params,
+            0,
+            b"entropy",
+        )
+        .expect("Failed to generate EC Key.");
+
+    assert!(key_metadata.certificate.is_some());
+
+    keystore2.grant(&key_metadata.key, grantee_uid, access_vector)
+}
+
+fn generate_key_and_grant_to_user(
+    keystore2: &binder::Strong<dyn IKeystoreService>,
+    sec_level: &binder::Strong<dyn IKeystoreSecurityLevel>,
+    alias: &str,
+    grantee_uid: u32,
+    algo: Algorithm,
+) -> Result<i64, Box<dyn std::error::Error>> {
+    let access_vector = KeyPermission::GET_INFO.0 | KeyPermission::USE.0 | KeyPermission::DELETE.0;
+
+    assert!(matches!(algo, Algorithm::RSA | Algorithm::EC));
+
+    let grant_key = match algo {
+        Algorithm::RSA => generate_rsa_key_and_grant_to_user(
+            keystore2,
+            sec_level,
+            alias,
+            grantee_uid.try_into().unwrap(),
+            access_vector,
+        )
+        .unwrap(),
+        Algorithm::EC => generate_ec_key_and_grant_to_user(
+            keystore2,
+            sec_level,
+            alias,
+            grantee_uid.try_into().unwrap(),
+            access_vector,
+        )
+        .unwrap(),
+        _ => panic!("Unsupported algorithms"),
+    };
+
+    assert_eq!(grant_key.domain, Domain::GRANT);
+
+    Ok(grant_key.nspace)
+}
+
+fn perform_crypto_op_using_granted_key(
+    keystore2: &binder::Strong<dyn IKeystoreService>,
+    grant_key_nspace: i64,
+) {
+    // Load the granted key from Keystore2-Engine API and perform crypto operations.
+    assert!(perform_crypto_op_using_keystore_engine(grant_key_nspace).unwrap());
+
+    // Delete the granted key.
+    keystore2
+        .deleteKey(&KeyDescriptor {
+            domain: Domain::GRANT,
+            nspace: grant_key_nspace,
+            alias: None,
+            blob: None,
+        })
+        .unwrap();
+}
+
+#[test]
+fn keystore2_perofrm_crypto_op_using_keystore2_engine_rsa_key_success() {
+    static TARGET_SU_CTX: &str = "u:r:su:s0";
+
+    static GRANTEE_CTX: &str = "u:r:untrusted_app:s0:c91,c256,c10,c20";
+    const USER_ID: u32 = 99;
+    const APPLICATION_ID: u32 = 10001;
+    static GRANTEE_UID: u32 = USER_ID * AID_USER_OFFSET + APPLICATION_ID;
+    static GRANTEE_GID: u32 = GRANTEE_UID;
+
+    // Generate a key and grant it to a user with GET_INFO|USE|DELETE key permissions.
+    let grant_key_nspace = unsafe {
+        run_as::run_as(TARGET_SU_CTX, Uid::from_raw(0), Gid::from_raw(0), || {
+            let keystore2 = get_keystore_service();
+            let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+            let alias = "keystore2_engine_rsa_key";
+            generate_key_and_grant_to_user(
+                &keystore2,
+                &sec_level,
+                alias,
+                GRANTEE_UID,
+                Algorithm::RSA,
+            )
+            .unwrap()
+        })
+    };
+
+    // In grantee context load the key and try to perform crypto operation.
+    unsafe {
+        run_as::run_as(
+            GRANTEE_CTX,
+            Uid::from_raw(GRANTEE_UID),
+            Gid::from_raw(GRANTEE_GID),
+            move || {
+                let keystore2 = get_keystore_service();
+                perform_crypto_op_using_granted_key(&keystore2, grant_key_nspace);
+            },
+        )
+    };
+}
+
+#[test]
+fn keystore2_perofrm_crypto_op_using_keystore2_engine_ec_key_success() {
+    static TARGET_SU_CTX: &str = "u:r:su:s0";
+
+    static GRANTEE_CTX: &str = "u:r:untrusted_app:s0:c91,c256,c10,c20";
+    const USER_ID: u32 = 99;
+    const APPLICATION_ID: u32 = 10001;
+    static GRANTEE_UID: u32 = USER_ID * AID_USER_OFFSET + APPLICATION_ID;
+    static GRANTEE_GID: u32 = GRANTEE_UID;
+
+    // Generate a key and grant it to a user with GET_INFO|USE|DELETE key permissions.
+    let grant_key_nspace = unsafe {
+        run_as::run_as(TARGET_SU_CTX, Uid::from_raw(0), Gid::from_raw(0), || {
+            let keystore2 = get_keystore_service();
+            let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+            let alias = "keystore2_engine_ec_test_key";
+            generate_key_and_grant_to_user(
+                &keystore2,
+                &sec_level,
+                alias,
+                GRANTEE_UID,
+                Algorithm::EC,
+            )
+            .unwrap()
+        })
+    };
+
+    // In grantee context load the key and try to perform crypto operation.
+    unsafe {
+        run_as::run_as(
+            GRANTEE_CTX,
+            Uid::from_raw(GRANTEE_UID),
+            Gid::from_raw(GRANTEE_GID),
+            move || {
+                let keystore2 = get_keystore_service();
+                perform_crypto_op_using_granted_key(&keystore2, grant_key_nspace);
+            },
+        )
+    };
+}
+
+#[test]
+fn keystore2_perofrm_crypto_op_using_keystore2_engine_pem_pub_key_success() {
+    static TARGET_SU_CTX: &str = "u:r:su:s0";
+
+    static GRANTEE_CTX: &str = "u:r:untrusted_app:s0:c91,c256,c10,c20";
+    const USER_ID: u32 = 99;
+    const APPLICATION_ID: u32 = 10001;
+    static GRANTEE_UID: u32 = USER_ID * AID_USER_OFFSET + APPLICATION_ID;
+    static GRANTEE_GID: u32 = GRANTEE_UID;
+
+    // Generate a key and re-encode it's certificate as PEM and update it and
+    // grant it to a user with GET_INFO|USE|DELETE key permissions.
+    let grant_key_nspace = unsafe {
+        run_as::run_as(TARGET_SU_CTX, Uid::from_raw(0), Gid::from_raw(0), || {
+            let keystore2 = get_keystore_service();
+            let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+            let alias = "keystore2_engine_rsa_pem_pub_key";
+            let grant_key_nspace = generate_key_and_grant_to_user(
+                &keystore2,
+                &sec_level,
+                alias,
+                GRANTEE_UID,
+                Algorithm::RSA,
+            )
+            .unwrap();
+
+            // Update certificate with encodeed PEM data.
+            let key_entry_response = keystore2
+                .getKeyEntry(&KeyDescriptor {
+                    domain: Domain::APP,
+                    nspace: -1,
+                    alias: Some(alias.to_string()),
+                    blob: None,
+                })
+                .unwrap();
+            let cert_bytes = key_entry_response.metadata.certificate.as_ref().unwrap();
+            let cert = X509::from_der(cert_bytes.as_ref()).unwrap();
+            let cert_pem = cert.to_pem().unwrap();
+            keystore2
+                .updateSubcomponent(&key_entry_response.metadata.key, Some(&cert_pem), None)
+                .expect("updateSubcomponent failed.");
+
+            grant_key_nspace
+        })
+    };
+
+    // In grantee context load the key and try to perform crypto operation.
+    unsafe {
+        run_as::run_as(
+            GRANTEE_CTX,
+            Uid::from_raw(GRANTEE_UID),
+            Gid::from_raw(GRANTEE_GID),
+            move || {
+                let keystore2 = get_keystore_service();
+                perform_crypto_op_using_granted_key(&keystore2, grant_key_nspace);
+            },
+        )
+    };
+}
diff --git a/keystore2/tests/keystore2_client_tests.rs b/keystore2/tests/keystore2_client_tests.rs
index 07a298a..9be0bf8 100644
--- a/keystore2/tests/keystore2_client_tests.rs
+++ b/keystore2/tests/keystore2_client_tests.rs
@@ -23,6 +23,7 @@
 pub mod keystore2_client_import_keys_tests;
 pub mod keystore2_client_key_agreement_tests;
 pub mod keystore2_client_key_id_domain_tests;
+pub mod keystore2_client_keystore_engine_tests;
 pub mod keystore2_client_list_entries_tests;
 pub mod keystore2_client_operation_tests;
 pub mod keystore2_client_rsa_key_tests;