keystore2 support for app UID migration

- Update migrate_key_namespace to accept specific UIDs for APP domain
  source and destination key descriptors
- Add new API to maintenance service to query a list of aliases for
  specified app UIDs

Test: atest SharedUserMigrationTest#testDataMigration (in internal)
Bug: 211665859
Change-Id: Ica06a8cd7c3f7b85f58d5953a22231cf7e9a1d7f
diff --git a/keystore2/aidl/android/security/maintenance/IKeystoreMaintenance.aidl b/keystore2/aidl/android/security/maintenance/IKeystoreMaintenance.aidl
index 6a37c78..3df5936 100644
--- a/keystore2/aidl/android/security/maintenance/IKeystoreMaintenance.aidl
+++ b/keystore2/aidl/android/security/maintenance/IKeystoreMaintenance.aidl
@@ -23,10 +23,15 @@
  * user's password.
  * @hide
  */
- @SensitiveData
+@SensitiveData
 interface IKeystoreMaintenance {
 
     /**
+     * Special value indicating the callers uid.
+     */
+    const int UID_SELF = -1;
+
+    /**
      * Allows LockSettingsService to inform keystore about adding a new user.
      * Callers require 'AddUser' permission.
      *
@@ -115,6 +120,10 @@
      * The source may be specified by Domain::APP, Domain::SELINUX, or Domain::KEY_ID. The target
      * may be specified by Domain::APP or Domain::SELINUX.
      *
+     * If Domain::APP is selected in either source or destination, nspace must be set to UID_SELF,
+     * implying the caller's UID. If the caller has the MIGRATE_ANY_KEY permission, Domain::APP may
+     * be used with other nspace values which then indicates the UID of a different application.
+     *
      * ## Error conditions:
      * `ResponseCode::PERMISSION_DENIED` - If the caller lacks any of the required permissions.
      * `ResponseCode::KEY_NOT_FOUND` - If the source did not exist.
@@ -131,4 +140,22 @@
      * Tag::ROLLBACK_RESISTANCE may or may not be rendered unusable.
      */
     void deleteAllKeys();
+
+    /**
+     * List all entries accessible by the caller in the given `domain` and `nspace`.
+     *
+     * Callers either has to have the `GET_INFO` permission for the requested namespace or `LIST`
+     * permission to list all the entries.
+     *
+     * ## Error conditions
+     * `ResponseCode::INVALID_ARGUMENT` if `domain` is other than `Domain::APP` or `Domain::SELINUX`
+     * `ResponseCode::PERMISSION_DENIED` if the caller does not have the permission
+     *
+     * @param domain `Domain::APP` or `Domain::SELINUX`.
+     *
+     * @param nspace The SELinux keystore2_key namespace.
+     *
+     * @return List of KeyDescriptors.
+     */
+    KeyDescriptor[] listEntries(in Domain domain, in long nspace);
 }
diff --git a/keystore2/src/maintenance.rs b/keystore2/src/maintenance.rs
index 57abc26..39958a3 100644
--- a/keystore2/src/maintenance.rs
+++ b/keystore2/src/maintenance.rs
@@ -22,12 +22,14 @@
 use crate::globals::{DB, LEGACY_MIGRATOR, SUPER_KEY};
 use crate::permission::{KeyPerm, KeystorePerm};
 use crate::super_key::UserState;
-use crate::utils::{check_key_permission, check_keystore_permission, watchdog as wd};
+use crate::utils::{
+    check_key_permission, check_keystore_permission, list_key_entries, watchdog as wd,
+};
 use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
     IKeyMintDevice::IKeyMintDevice, SecurityLevel::SecurityLevel,
 };
 use android_security_maintenance::aidl::android::security::maintenance::{
-    IKeystoreMaintenance::{BnKeystoreMaintenance, IKeystoreMaintenance},
+    IKeystoreMaintenance::{BnKeystoreMaintenance, IKeystoreMaintenance, UID_SELF},
     UserState::UserState as AidlUserState,
 };
 use android_security_maintenance::binder::{
@@ -37,6 +39,7 @@
 use android_system_keystore2::aidl::android::system::keystore2::ResponseCode::ResponseCode;
 use anyhow::{Context, Result};
 use keystore2_crypto::Password;
+use keystore2_selinux as selinux;
 
 /// Reexport Domain for the benefit of DeleteListener
 pub use android_system_keystore2::aidl::android::system::keystore2::Domain::Domain;
@@ -214,46 +217,64 @@
     }
 
     fn migrate_key_namespace(source: &KeyDescriptor, destination: &KeyDescriptor) -> Result<()> {
-        let caller_uid = ThreadState::get_calling_uid();
         let migrate_any_key_permission =
             check_keystore_permission(KeystorePerm::MigrateAnyKey).is_ok();
 
-        DB.with(|db| {
-            let key_id_guard = match source.domain {
-                Domain::APP | Domain::SELINUX | Domain::KEY_ID => {
-                    let (key_id_guard, _) = LEGACY_MIGRATOR
-                        .with_try_migrate(source, caller_uid, || {
-                            db.borrow_mut().load_key_entry(
-                                source,
-                                KeyType::Client,
-                                KeyEntryLoadBits::NONE,
-                                caller_uid,
-                                |k, av| {
-                                    if !migrate_any_key_permission {
-                                        check_key_permission(KeyPerm::Use, k, &av)?;
-                                        check_key_permission(KeyPerm::Delete, k, &av)?;
-                                        check_key_permission(KeyPerm::Grant, k, &av)?;
-                                    }
-                                    Ok(())
-                                },
-                            )
-                        })
-                        .context("In migrate_key_namespace: Failed to load key blob.")?;
-                    key_id_guard
-                }
-                _ => {
-                    return Err(Error::Rc(ResponseCode::INVALID_ARGUMENT)).context(concat!(
-                        "In migrate_key_namespace: ",
-                        "Source domain must be one of APP, SELINUX, or KEY_ID."
-                    ))
-                }
-            };
+        let src_uid = match source.domain {
+            Domain::SELINUX | Domain::KEY_ID => ThreadState::get_calling_uid(),
+            Domain::APP if source.nspace == UID_SELF.into() => ThreadState::get_calling_uid(),
+            Domain::APP if source.nspace != UID_SELF.into() && migrate_any_key_permission => {
+                source.nspace as u32
+            }
+            _ => {
+                return Err(Error::Rc(ResponseCode::INVALID_ARGUMENT)).context(
+                    "In migrate_key_namespace:
+                     Source domain must be one of APP, SELINUX, or KEY_ID.",
+                )
+            }
+        };
 
-            db.borrow_mut().migrate_key_namespace(key_id_guard, destination, caller_uid, |k| {
-                if !migrate_any_key_permission {
-                    check_key_permission(KeyPerm::Rebind, k, &None)?;
+        let dest_uid = match destination.domain {
+            Domain::SELINUX => ThreadState::get_calling_uid(),
+            Domain::APP if destination.nspace == UID_SELF.into() => ThreadState::get_calling_uid(),
+            Domain::APP if destination.nspace != UID_SELF.into() && migrate_any_key_permission => {
+                destination.nspace as u32
+            }
+            _ => {
+                return Err(Error::Rc(ResponseCode::INVALID_ARGUMENT)).context(
+                    "In migrate_key_namespace:
+                     Destination domain must be one of APP or SELINUX.",
+                )
+            }
+        };
+
+        DB.with(|db| {
+            let (key_id_guard, _) = LEGACY_MIGRATOR
+                .with_try_migrate(source, src_uid, || {
+                    db.borrow_mut().load_key_entry(
+                        source,
+                        KeyType::Client,
+                        KeyEntryLoadBits::NONE,
+                        src_uid,
+                        |k, av| {
+                            if migrate_any_key_permission {
+                                Ok(())
+                            } else {
+                                check_key_permission(KeyPerm::Use, k, &av)?;
+                                check_key_permission(KeyPerm::Delete, k, &av)?;
+                                check_key_permission(KeyPerm::Grant, k, &av)
+                            }
+                        },
+                    )
+                })
+                .context("In migrate_key_namespace: Failed to load key blob.")?;
+
+            db.borrow_mut().migrate_key_namespace(key_id_guard, destination, dest_uid, |k| {
+                if migrate_any_key_permission {
+                    Ok(())
+                } else {
+                    check_key_permission(KeyPerm::Rebind, k, &None)
                 }
-                Ok(())
             })
         })
     }
@@ -266,6 +287,30 @@
 
         Maintenance::call_on_all_security_levels("deleteAllKeys", |dev| dev.deleteAllKeys())
     }
+
+    fn list_entries(domain: Domain, nspace: i64) -> Result<Vec<KeyDescriptor>> {
+        let k = match domain {
+            Domain::APP | Domain::SELINUX => KeyDescriptor{domain, nspace, ..Default::default()},
+            _ => return Err(Error::perm()).context(
+                "In list_entries: List entries is only supported for Domain::APP and Domain::SELINUX."
+            ),
+        };
+
+        // The caller has to have either GetInfo for the namespace or List permission
+        check_key_permission(KeyPerm::GetInfo, &k, &None)
+            .or_else(|e| {
+                if Some(&selinux::Error::PermissionDenied)
+                    == e.root_cause().downcast_ref::<selinux::Error>()
+                {
+                    check_keystore_permission(KeystorePerm::List)
+                } else {
+                    Err(e)
+                }
+            })
+            .context("In list_entries: While checking key and keystore permission.")?;
+
+        DB.with(|db| list_key_entries(&mut db.borrow_mut(), domain, nspace))
+    }
 }
 
 impl Interface for Maintenance {}
@@ -315,6 +360,11 @@
         map_or_log_err(Self::migrate_key_namespace(source, destination), Ok)
     }
 
+    fn listEntries(&self, domain: Domain, namespace: i64) -> BinderResult<Vec<KeyDescriptor>> {
+        let _wp = wd::watch_millis("IKeystoreMaintenance::listEntries", 500);
+        map_or_log_err(Self::list_entries(domain, namespace), Ok)
+    }
+
     fn deleteAllKeys(&self) -> BinderResult<()> {
         let _wp = wd::watch_millis("IKeystoreMaintenance::deleteAllKeys", 500);
         map_or_log_err(Self::delete_all_keys(), Ok)
diff --git a/keystore2/src/service.rs b/keystore2/src/service.rs
index 70f5c71..13723f0 100644
--- a/keystore2/src/service.rs
+++ b/keystore2/src/service.rs
@@ -22,7 +22,7 @@
 use crate::security_level::KeystoreSecurityLevel;
 use crate::utils::{
     check_grant_permission, check_key_permission, check_keystore_permission,
-    key_parameters_to_authorizations, watchdog as wd,
+    key_parameters_to_authorizations, list_key_entries, watchdog as wd,
 };
 use crate::{
     database::Uuid,
@@ -286,22 +286,7 @@
             Ok(()) => {}
         };
 
-        let mut result = LEGACY_MIGRATOR
-            .list_uid(k.domain, k.nspace)
-            .context("In list_entries: Trying to list legacy keys.")?;
-
-        result.append(
-            &mut DB
-                .with(|db| {
-                    let mut db = db.borrow_mut();
-                    db.list(k.domain, k.nspace, KeyType::Client)
-                })
-                .context("In list_entries: Trying to list keystore database.")?,
-        );
-
-        result.sort_unstable();
-        result.dedup();
-        Ok(result)
+        DB.with(|db| list_key_entries(&mut db.borrow_mut(), k.domain, k.nspace))
     }
 
     fn delete_key(&self, key: &KeyDescriptor) -> Result<()> {
diff --git a/keystore2/src/utils.rs b/keystore2/src/utils.rs
index f6d92ee..82e6700 100644
--- a/keystore2/src/utils.rs
+++ b/keystore2/src/utils.rs
@@ -18,6 +18,10 @@
 use crate::error::{map_binder_status, Error, ErrorCode};
 use crate::permission;
 use crate::permission::{KeyPerm, KeyPermSet, KeystorePerm};
+use crate::{
+    database::{KeyType, KeystoreDB},
+    globals::LEGACY_MIGRATOR,
+};
 use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
     KeyCharacteristics::KeyCharacteristics, Tag::Tag,
 };
@@ -27,9 +31,9 @@
     ResponseCode::ResponseCode as ApcResponseCode,
 };
 use android_system_keystore2::aidl::android::system::keystore2::{
-    Authorization::Authorization, KeyDescriptor::KeyDescriptor,
+    Authorization::Authorization, Domain::Domain, KeyDescriptor::KeyDescriptor,
 };
-use anyhow::Context;
+use anyhow::{Context, Result};
 use binder::{Strong, ThreadState};
 use keystore2_apc_compat::{
     ApcCompatUiOptions, APC_COMPAT_ERROR_ABORTED, APC_COMPAT_ERROR_CANCELLED,
@@ -199,6 +203,28 @@
     rustutils::users::multiuser_get_user_id(uid)
 }
 
+/// List all key aliases for a given domain + namespace.
+pub fn list_key_entries(
+    db: &mut KeystoreDB,
+    domain: Domain,
+    namespace: i64,
+) -> Result<Vec<KeyDescriptor>> {
+    let mut result = Vec::new();
+    result.append(
+        &mut LEGACY_MIGRATOR
+            .list_uid(domain, namespace)
+            .context("In list_key_entries: Trying to list legacy keys.")?,
+    );
+    result.append(
+        &mut db
+            .list(domain, namespace, KeyType::Client)
+            .context("In list_key_entries: Trying to list keystore database.")?,
+    );
+    result.sort_unstable();
+    result.dedup();
+    Ok(result)
+}
+
 /// This module provides helpers for simplified use of the watchdog module.
 #[cfg(feature = "watchdog")]
 pub mod watchdog {