Updated `listEntries` API response code with invalid domain field.

Updated to return `INVALID_ARGUMENT` instead of `PERMISSION_DENIED`
response code when domain is other than `APP` or `SELINUX`.

Added tests to validate `listEntries` API with valid domains `APP and
SELINUX` and invalid domains like `BLOB`.

Bug: 239719010
Test: atest CtsKeystoreTestCases; atest keystore2_client_tests;
Change-Id: I7d10c13342ca5719682e371e428fa42f992ba07d
diff --git a/keystore2/src/service.rs b/keystore2/src/service.rs
index d634e0c..8d2e5ad 100644
--- a/keystore2/src/service.rs
+++ b/keystore2/src/service.rs
@@ -266,7 +266,7 @@
                 ..Default::default()
             },
             Domain::SELINUX => KeyDescriptor{domain, nspace: namespace, ..Default::default()},
-            _ => return Err(Error::perm()).context(
+            _ => return Err(Error::Rc(ResponseCode::INVALID_ARGUMENT)).context(
                 "In list_entries: List entries is only supported for Domain::APP and Domain::SELINUX."
             ),
         };
@@ -278,8 +278,8 @@
         // selected.
         if let Err(e) = check_key_permission(KeyPerm::GetInfo, &k, &None) {
             if let Some(selinux::Error::PermissionDenied) =
-                e.root_cause().downcast_ref::<selinux::Error>() {
-
+                e.root_cause().downcast_ref::<selinux::Error>()
+            {
                 check_keystore_permission(KeystorePerm::List)
                     .context("In list_entries: While checking keystore permission.")?;
                 if namespace != -1 {
diff --git a/keystore2/tests/keystore2_client_list_entries_tests.rs b/keystore2/tests/keystore2_client_list_entries_tests.rs
new file mode 100644
index 0000000..d50ef5c
--- /dev/null
+++ b/keystore2/tests/keystore2_client_list_entries_tests.rs
@@ -0,0 +1,187 @@
+// Copyright 2022, 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::{getuid, Gid, Uid};
+use rustutils::users::AID_USER_OFFSET;
+
+use android_hardware_security_keymint::aidl::android::hardware::security::keymint::SecurityLevel::SecurityLevel;
+use android_system_keystore2::aidl::android::system::keystore2::{
+    Domain::Domain, IKeystoreService::IKeystoreService, KeyDescriptor::KeyDescriptor,
+    KeyPermission::KeyPermission, ResponseCode::ResponseCode,
+};
+
+use keystore2_test_utils::{get_keystore_service, key_generations, key_generations::Error, run_as};
+
+/// Try to find a key with given key parameters using `listEntries` API.
+fn is_key_alias_exist(
+    keystore2: &binder::Strong<dyn IKeystoreService>,
+    domain: Domain,
+    nspace: i64,
+    alias: String,
+) -> bool {
+    let key_descriptors = keystore2.listEntries(domain, nspace).unwrap();
+    let alias_count = key_descriptors
+        .into_iter()
+        .map(|key| key.alias.unwrap())
+        .filter(|key_alias| *key_alias == alias)
+        .count();
+
+    alias_count != 0
+}
+
+/// List key entries with domain as SELINUX and APP.
+/// 1. Generate a key with domain as SELINUX and find this key entry in list of keys retrieved from
+///    `listEntries` with domain SELINUX. Test should be able find this key entry successfully.
+/// 2. Grant above generated Key to a user.
+/// 3. In a user context, generate a new key with domain as APP. Try to list the key entries with
+///    domain APP. Test should find only one key entry that should be the key generated in user
+///    context. GRANT keys shouldn't be part of this list.
+#[test]
+fn keystore2_list_entries_success() {
+    static GRANTOR_SU_CTX: &str = "u:r:su:s0";
+    static GRANTEE_CTX: &str = "u:r:untrusted_app:s0:c91,c256,c10,c20";
+
+    const USER_ID: u32 = 91;
+    const APPLICATION_ID: u32 = 10006;
+    static GRANTEE_UID: u32 = USER_ID * AID_USER_OFFSET + APPLICATION_ID;
+    static GRANTEE_GID: u32 = GRANTEE_UID;
+
+    unsafe {
+        run_as::run_as(GRANTOR_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 = format!("list_entries_grant_key1_{}", getuid());
+
+            // Make sure there is no key exist with this `alias` in `SELINUX` domain and
+            // `SELINUX_SHELL_NAMESPACE` namespace.
+            if is_key_alias_exist(
+                &keystore2,
+                Domain::SELINUX,
+                key_generations::SELINUX_SHELL_NAMESPACE,
+                alias.to_string(),
+            ) {
+                keystore2
+                    .deleteKey(&KeyDescriptor {
+                        domain: Domain::SELINUX,
+                        nspace: key_generations::SELINUX_SHELL_NAMESPACE,
+                        alias: Some(alias.to_string()),
+                        blob: None,
+                    })
+                    .unwrap();
+            }
+
+            // Generate a key with above defined `alias`.
+            let key_metadata = key_generations::generate_ec_p256_signing_key(
+                &sec_level,
+                Domain::SELINUX,
+                key_generations::SELINUX_SHELL_NAMESPACE,
+                Some(alias.to_string()),
+                None,
+                None,
+            )
+            .unwrap();
+
+            // Verify that above generated key entry is listed with domain SELINUX and
+            // namespace SELINUX_SHELL_NAMESPACE
+            assert!(is_key_alias_exist(
+                &keystore2,
+                Domain::SELINUX,
+                key_generations::SELINUX_SHELL_NAMESPACE,
+                alias,
+            ));
+
+            // Grant a key with GET_INFO permission.
+            let access_vector = KeyPermission::GET_INFO.0;
+            keystore2
+                .grant(&key_metadata.key, GRANTEE_UID.try_into().unwrap(), access_vector)
+                .unwrap();
+        })
+    };
+
+    // In user context validate list of key entries associated with it.
+    unsafe {
+        run_as::run_as(
+            GRANTEE_CTX,
+            Uid::from_raw(GRANTEE_UID),
+            Gid::from_raw(GRANTEE_GID),
+            move || {
+                let keystore2 = get_keystore_service();
+                let sec_level =
+                    keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+                let alias = format!("list_entries_success_key{}", getuid());
+
+                let key_metadata = key_generations::generate_ec_p256_signing_key(
+                    &sec_level,
+                    Domain::APP,
+                    -1,
+                    Some(alias.to_string()),
+                    None,
+                    None,
+                )
+                .unwrap();
+
+                // Make sure there is only one key entry exist and that should be the same key
+                // generated in this user context. Granted key shouldn't be included in this list.
+                let key_descriptors = keystore2.listEntries(Domain::APP, -1).unwrap();
+                assert_eq!(1, key_descriptors.len());
+
+                let key = key_descriptors.get(0).unwrap();
+                assert_eq!(key.alias, Some(alias));
+                assert_eq!(key.nspace, GRANTEE_UID.try_into().unwrap());
+                assert_eq!(key.domain, Domain::APP);
+
+                keystore2.deleteKey(&key_metadata.key).unwrap();
+
+                let key_descriptors = keystore2.listEntries(Domain::APP, -1).unwrap();
+                assert_eq!(0, key_descriptors.len());
+            },
+        )
+    };
+}
+
+/// Try to list the key entries with domain SELINUX from user context where user doesn't possesses
+/// `GET_INFO` permission for specified namespace. Test should fail to list key entries with error
+/// response code `PERMISSION_DENIED`.
+#[test]
+fn keystore2_list_entries_fails_perm_denied() {
+    let auid = 91 * AID_USER_OFFSET + 10001;
+    let agid = 91 * AID_USER_OFFSET + 10001;
+    static TARGET_CTX: &str = "u:r:untrusted_app:s0:c91,c256,c10,c20";
+
+    unsafe {
+        run_as::run_as(TARGET_CTX, Uid::from_raw(auid), Gid::from_raw(agid), move || {
+            let keystore2 = get_keystore_service();
+
+            let result = key_generations::map_ks_error(
+                keystore2.listEntries(Domain::SELINUX, key_generations::SELINUX_SHELL_NAMESPACE),
+            );
+            assert!(result.is_err());
+            assert_eq!(Error::Rc(ResponseCode::PERMISSION_DENIED), result.unwrap_err());
+        })
+    };
+}
+
+/// Try to list key entries with domain BLOB. Test should fail with error repose code
+/// `INVALID_ARGUMENT`.
+#[test]
+fn keystore2_list_entries_fails_invalid_arg() {
+    let keystore2 = get_keystore_service();
+
+    let result = key_generations::map_ks_error(
+        keystore2.listEntries(Domain::BLOB, key_generations::SELINUX_SHELL_NAMESPACE),
+    );
+    assert!(result.is_err());
+    assert_eq!(Error::Rc(ResponseCode::INVALID_ARGUMENT), result.unwrap_err());
+}
diff --git a/keystore2/tests/keystore2_client_tests.rs b/keystore2/tests/keystore2_client_tests.rs
index 3fb3e15..1cda123 100644
--- a/keystore2/tests/keystore2_client_tests.rs
+++ b/keystore2/tests/keystore2_client_tests.rs
@@ -16,6 +16,7 @@
 pub mod keystore2_client_ec_key_tests;
 pub mod keystore2_client_grant_key_tests;
 pub mod keystore2_client_key_id_domain_tests;
+pub mod keystore2_client_list_entries_tests;
 pub mod keystore2_client_operation_tests;
 pub mod keystore2_client_rsa_key_tests;
 pub mod keystore2_client_test_utils;