Keystore 2.0: Implement list keys.

Test: keystore2_test
Change-Id: Id5b875adce95723cd837b22beca7af44621bb2cd
diff --git a/keystore2/src/database.rs b/keystore2/src/database.rs
index a2cd6cd..9086faf 100644
--- a/keystore2/src/database.rs
+++ b/keystore2/src/database.rs
@@ -390,24 +390,30 @@
         key_id: &KeyIdGuard,
         params: impl IntoIterator<Item = &'a KeyParameter>,
     ) -> Result<()> {
-        let mut stmt = self
+        let tx = self
             .conn
-            .prepare(
-                "INSERT into persistent.keyparameter (keyentryid, tag, data, security_level)
+            .transaction_with_behavior(TransactionBehavior::Immediate)
+            .context("In insert_keyparameter: Failed to start transaction.")?;
+        {
+            let mut stmt = tx
+                .prepare(
+                    "INSERT into persistent.keyparameter (keyentryid, tag, data, security_level)
                     VALUES (?, ?, ?, ?);",
-            )
-            .context("In insert_keyparameter: Failed to prepare statement.")?;
+                )
+                .context("In insert_keyparameter: Failed to prepare statement.")?;
 
-        let iter = params.into_iter();
-        for p in iter {
-            stmt.insert(params![
-                key_id.0,
-                p.get_tag().0,
-                p.key_parameter_value(),
-                p.security_level().0
-            ])
-            .with_context(|| format!("In insert_keyparameter: Failed to insert {:?}", p))?;
+            let iter = params.into_iter();
+            for p in iter {
+                stmt.insert(params![
+                    key_id.0,
+                    p.get_tag().0,
+                    p.key_parameter_value(),
+                    p.security_level().0
+                ])
+                .with_context(|| format!("In insert_keyparameter: Failed to insert {:?}", p))?;
+            }
         }
+        tx.commit().context("In insert_keyparameter: Failed to commit transaction.")?;
         Ok(())
     }
 
@@ -759,6 +765,35 @@
         ))
     }
 
+    /// Returns a list of KeyDescriptors in the selected domain/namespace.
+    /// The key descriptors will have the domain, nspace, and alias field set.
+    /// Domain must be APP or SELINUX, the caller must make sure of that.
+    pub fn list(&mut self, domain: Domain, namespace: i64) -> Result<Vec<KeyDescriptor>> {
+        let mut stmt = self
+            .conn
+            .prepare(
+                "SELECT alias FROM persistent.keyentry
+             WHERE domain = ? AND namespace = ? AND alias IS NOT NULL;",
+            )
+            .context("In list: Failed to prepare.")?;
+
+        let mut rows =
+            stmt.query(params![domain.0 as u32, namespace]).context("In list: Failed to query.")?;
+
+        let mut descriptors: Vec<KeyDescriptor> = Vec::new();
+        db_utils::with_rows_extract_all(&mut rows, |row| {
+            descriptors.push(KeyDescriptor {
+                domain,
+                nspace: namespace,
+                alias: Some(row.get(0).context("Trying to extract alias.")?),
+                blob: None,
+            });
+            Ok(())
+        })
+        .context("In list.")?;
+        Ok(descriptors)
+    }
+
     /// Adds a grant to the grant table.
     /// Like `load_key_entry` this function loads the access tuple before
     /// it uses the callback for a permission check. Upon success,
@@ -1465,6 +1500,90 @@
         Ok(())
     }
 
+    #[test]
+    fn list() -> Result<()> {
+        let temp_dir = TempDir::new("list_test")?;
+        let mut db = KeystoreDB::new(temp_dir.path())?;
+        static LIST_O_ENTRIES: &[(Domain, i64, &str)] = &[
+            (Domain::APP, 1, "test1"),
+            (Domain::APP, 1, "test2"),
+            (Domain::APP, 1, "test3"),
+            (Domain::APP, 1, "test4"),
+            (Domain::APP, 1, "test5"),
+            (Domain::APP, 1, "test6"),
+            (Domain::APP, 1, "test7"),
+            (Domain::APP, 2, "test1"),
+            (Domain::APP, 2, "test2"),
+            (Domain::APP, 2, "test3"),
+            (Domain::APP, 2, "test4"),
+            (Domain::APP, 2, "test5"),
+            (Domain::APP, 2, "test6"),
+            (Domain::APP, 2, "test8"),
+            (Domain::SELINUX, 100, "test1"),
+            (Domain::SELINUX, 100, "test2"),
+            (Domain::SELINUX, 100, "test3"),
+            (Domain::SELINUX, 100, "test4"),
+            (Domain::SELINUX, 100, "test5"),
+            (Domain::SELINUX, 100, "test6"),
+            (Domain::SELINUX, 100, "test9"),
+        ];
+
+        let list_o_keys: Vec<(i64, i64)> = LIST_O_ENTRIES
+            .iter()
+            .map(|(domain, ns, alias)| {
+                let entry =
+                    make_test_key_entry(&mut db, *domain, *ns, *alias).unwrap_or_else(|e| {
+                        panic!("Failed to insert {:?} {} {}. Error {:?}", domain, ns, alias, e)
+                    });
+                (entry.id(), *ns)
+            })
+            .collect();
+
+        for (domain, namespace) in
+            &[(Domain::APP, 1i64), (Domain::APP, 2i64), (Domain::SELINUX, 100i64)]
+        {
+            let mut list_o_descriptors: Vec<KeyDescriptor> = LIST_O_ENTRIES
+                .iter()
+                .filter_map(|(domain, ns, alias)| match ns {
+                    ns if *ns == *namespace => Some(KeyDescriptor {
+                        domain: *domain,
+                        nspace: *ns,
+                        alias: Some(alias.to_string()),
+                        blob: None,
+                    }),
+                    _ => None,
+                })
+                .collect();
+            list_o_descriptors.sort();
+            let mut list_result = db.list(*domain, *namespace)?;
+            list_result.sort();
+            assert_eq!(list_o_descriptors, list_result);
+
+            let mut list_o_ids: Vec<i64> = list_o_descriptors
+                .into_iter()
+                .map(|d| {
+                    let (_, entry) = db
+                        .load_key_entry(d, KeyEntryLoadBits::NONE, *namespace as u32, |_, _| Ok(()))
+                        .unwrap();
+                    entry.id()
+                })
+                .collect();
+            list_o_ids.sort_unstable();
+            let mut loaded_entries: Vec<i64> = list_o_keys
+                .iter()
+                .filter_map(|(id, ns)| match ns {
+                    ns if *ns == *namespace => Some(*id),
+                    _ => None,
+                })
+                .collect();
+            loaded_entries.sort_unstable();
+            assert_eq!(list_o_ids, loaded_entries);
+        }
+        assert_eq!(Vec::<KeyDescriptor>::new(), db.list(Domain::SELINUX, 101)?);
+
+        Ok(())
+    }
+
     // Helpers
 
     // Checks that the given result is an error containing the given string.
diff --git a/keystore2/src/service.rs b/keystore2/src/service.rs
index eb0d01b..cb04031 100644
--- a/keystore2/src/service.rs
+++ b/keystore2/src/service.rs
@@ -22,10 +22,11 @@
 use crate::error::{self, map_or_log_err, ErrorCode};
 use crate::globals::DB;
 use crate::permission;
-use crate::permission::KeyPerm;
+use crate::permission::{KeyPerm, KeystorePerm};
 use crate::security_level::KeystoreSecurityLevel;
 use crate::utils::{
-    check_grant_permission, check_key_permission, key_parameters_to_authorizations, Asp,
+    check_grant_permission, check_key_permission, check_keystore_permission,
+    key_parameters_to_authorizations, Asp,
 };
 use android_hardware_security_keymint::aidl::android::hardware::security::keymint::SecurityLevel::SecurityLevel;
 use android_system_keystore2::aidl::android::system::keystore2::{
@@ -35,6 +36,8 @@
 };
 use anyhow::{anyhow, Context, Result};
 use binder::{IBinder, Interface, ThreadState};
+use error::Error;
+use keystore2_selinux as selinux;
 
 /// Implementation of the IKeystoreService.
 pub struct KeystoreService {
@@ -146,8 +149,44 @@
     }
 
     fn list_entries(&self, domain: Domain, namespace: i64) -> Result<Vec<KeyDescriptor>> {
-        // TODO implement.
-        Err(anyhow!(error::Error::sys()))
+        let mut k = match domain {
+            Domain::APP => KeyDescriptor {
+                domain,
+                nspace: ThreadState::get_calling_uid() as u64 as i64,
+                ..Default::default()
+            },
+            Domain::SELINUX => KeyDescriptor{domain, nspace: namespace, ..Default::default()},
+            _ => return Err(Error::perm()).context(
+                "In list_entries: List entries is only supported for Domain::APP and Domain::SELINUX."
+            ),
+        };
+
+        // First we check if the caller has the info permission for the selected domain/namespace.
+        // By default we use the calling uid as namespace if domain is Domain::APP.
+        // If the first check fails we check if the caller has the list permission allowing to list
+        // any namespace. In that case we also adjust the queried namespace if a specific uid was
+        // selected.
+        match check_key_permission(KeyPerm::get_info(), &k, &None) {
+            Err(e) => {
+                if let Some(selinux::Error::PermissionDenied) =
+                    e.root_cause().downcast_ref::<selinux::Error>()
+                {
+                    check_keystore_permission(KeystorePerm::list())
+                        .context("In list_entries: While checking keystore permission.")?;
+                    if namespace != -1 {
+                        k.nspace = namespace;
+                    }
+                } else {
+                    return Err(e).context("In list_entries: While checking key permission.")?;
+                }
+            }
+            Ok(()) => {}
+        };
+
+        DB.with(|db| {
+            let mut db = db.borrow_mut();
+            db.list(k.domain, k.nspace)
+        })
     }
 
     fn delete_key(&self, key: &KeyDescriptor) -> Result<()> {