Keystore 2.0: Implement clear namespace.

Implements the clearing of a specific namespace. This is requered for
uninstalling an app.

Test: Uninstall an app and check that all its keys get deleted.
Bug: 176123105
Change-Id: I519519f9381ee70a3dd2a93d77db92a510aa8427
diff --git a/keystore2/aidl/Android.bp b/keystore2/aidl/Android.bp
index d529fa9..c92417b 100644
--- a/keystore2/aidl/Android.bp
+++ b/keystore2/aidl/Android.bp
@@ -118,6 +118,9 @@
 aidl_interface {
     name: "android.security.usermanager",
     srcs: [ "android/security/usermanager/*.aidl" ],
+    imports: [
+        "android.system.keystore2",
+    ],
     unstable: true,
     backend: {
         java: {
diff --git a/keystore2/aidl/android/security/usermanager/IKeystoreUserManager.aidl b/keystore2/aidl/android/security/usermanager/IKeystoreUserManager.aidl
index 3690b1c..83edb1a 100644
--- a/keystore2/aidl/android/security/usermanager/IKeystoreUserManager.aidl
+++ b/keystore2/aidl/android/security/usermanager/IKeystoreUserManager.aidl
@@ -14,11 +14,14 @@
 
 package android.security.usermanager;
 
+import android.system.keystore2.Domain;
+
 // TODO: mark the interface with @SensitiveData when the annotation is ready (b/176110256).
 
 /**
  * IKeystoreUserManager interface exposes the methods for adding/removing users and changing the
  * user's password.
+ * @hide
  */
 interface IKeystoreUserManager {
 
@@ -31,6 +34,7 @@
      * user id.
      *
      * @param userId - Android user id
+     * @hide
      */
     void onUserAdded(in int userId);
 
@@ -42,6 +46,7 @@
      * `ResponseCode::SYSTEM_ERROR` - if failed to delete the keys of the user being deleted.
      *
      * @param userId - Android user id
+     * @hide
      */
     void onUserRemoved(in int userId);
 
@@ -56,6 +61,18 @@
      *
      * @param userId - Android user id
      * @param password - a secret derived from the synthetic password of the user
+     * @hide
      */
     void onUserPasswordChanged(in int userId, in @nullable byte[] password);
+
+    /**
+     * This function deletes all keys within a namespace. It mainly gets called when an app gets
+     * removed and all resources of this app need to be cleaned up.
+     *
+     * @param domain - One of Domain.APP or Domain.SELINUX.
+     * @param nspace - The UID of the app that is to be cleared if domain is Domain.APP or
+     *                 the SEPolicy namespace if domain is Domain.SELINUX.
+     * @hide
+     */
+     void clearNamespace(Domain domain, long nspace);
 }
diff --git a/keystore2/src/database.rs b/keystore2/src/database.rs
index db06bff..40860be 100644
--- a/keystore2/src/database.rs
+++ b/keystore2/src/database.rs
@@ -2522,6 +2522,51 @@
         .context("In get_key_km_uuid.")
     }
 
+    /// Delete all artifacts belonging to the namespace given by the domain-namespace tuple.
+    /// This leaves all of the blob entries orphaned for subsequent garbage collection.
+    pub fn unbind_keys_for_namespace(&mut self, domain: Domain, namespace: i64) -> Result<()> {
+        if !(domain == Domain::APP || domain == Domain::SELINUX) {
+            return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT))
+                .context("In unbind_keys_for_namespace.");
+        }
+        self.with_transaction(TransactionBehavior::Immediate, |tx| {
+            tx.execute(
+                "DELETE FROM persistent.keymetadata
+                WHERE keyentryid IN (
+                    SELECT id FROM persistent.keyentry
+                    WHERE domain = ? AND namespace = ?
+                );",
+                params![domain.0, namespace],
+            )
+            .context("Trying to delete keymetadata.")?;
+            tx.execute(
+                "DELETE FROM persistent.keyparameter
+                WHERE keyentryid IN (
+                    SELECT id FROM persistent.keyentry
+                    WHERE domain = ? AND namespace = ?
+                );",
+                params![domain.0, namespace],
+            )
+            .context("Trying to delete keyparameters.")?;
+            tx.execute(
+                "DELETE FROM persistent.grant
+                WHERE keyentryid IN (
+                    SELECT id FROM persistent.keyentry
+                    WHERE domain = ? AND namespace = ?
+                );",
+                params![domain.0, namespace],
+            )
+            .context("Trying to delete grants.")?;
+            tx.execute(
+                "DELETE FROM persistent.keyentry WHERE domain = ? AND namespace = ?;",
+                params![domain.0, namespace],
+            )
+            .context("Trying to delete keyentry.")?;
+            Ok(()).need_gc()
+        })
+        .context("In unbind_keys_for_namespace")
+    }
+
     /// Delete the keys created on behalf of the user, denoted by the user id.
     /// Delete all the keys unless 'keep_non_super_encrypted_keys' set to true.
     /// Returned boolean is to hint the garbage collector to delete the unbound keys.
diff --git a/keystore2/src/legacy_migrator.rs b/keystore2/src/legacy_migrator.rs
index 9ffe86c..1ae8719 100644
--- a/keystore2/src/legacy_migrator.rs
+++ b/keystore2/src/legacy_migrator.rs
@@ -362,11 +362,18 @@
         }
     }
 
-    /// Deletes all keys belonging to the given uid, migrating them into the database
+    /// Deletes all keys belonging to the given namespace, migrating them into the database
     /// for subsequent garbage collection if necessary.
-    pub fn bulk_delete_uid(&self, uid: u32, keep_non_super_encrypted_keys: bool) -> Result<()> {
+    pub fn bulk_delete_uid(&self, domain: Domain, nspace: i64) -> Result<()> {
+        let uid = match (domain, nspace) {
+            (Domain::APP, nspace) => nspace as u32,
+            (Domain::SELINUX, Self::WIFI_NAMESPACE) => Self::AID_WIFI,
+            // Nothing to do.
+            _ => return Ok(()),
+        };
+
         let result = self.do_serialized(move |migrator_state| {
-            migrator_state.bulk_delete(BulkDeleteRequest::Uid(uid), keep_non_super_encrypted_keys)
+            migrator_state.bulk_delete(BulkDeleteRequest::Uid(uid), false)
         });
 
         result.unwrap_or(Ok(()))
diff --git a/keystore2/src/user_manager.rs b/keystore2/src/user_manager.rs
index 8e09144..3c393c5 100644
--- a/keystore2/src/user_manager.rs
+++ b/keystore2/src/user_manager.rs
@@ -24,6 +24,7 @@
     BnKeystoreUserManager, IKeystoreUserManager,
 };
 use android_security_usermanager::binder::{Interface, Result as BinderResult};
+use android_system_keystore2::aidl::android::system::keystore2::Domain::Domain;
 use android_system_keystore2::aidl::android::system::keystore2::ResponseCode::ResponseCode;
 use anyhow::{Context, Result};
 use binder::{IBinder, Strong};
@@ -85,6 +86,17 @@
         })
         .context("In add_or_remove_user: Trying to delete keys from db.")
     }
+
+    fn clear_namespace(domain: Domain, nspace: i64) -> Result<()> {
+        // Permission check. Must return on error. Do not touch the '?'.
+        check_keystore_permission(KeystorePerm::clear_uid()).context("In clear_namespace.")?;
+
+        LEGACY_MIGRATOR
+            .bulk_delete_uid(domain, nspace)
+            .context("In clear_namespace: Trying to delete legacy keys.")?;
+        DB.with(|db| db.borrow_mut().unbind_keys_for_namespace(domain, nspace))
+            .context("In clear_namespace: Trying to delete keys from db.")
+    }
 }
 
 impl Interface for UserManager {}
@@ -101,4 +113,8 @@
     fn onUserRemoved(&self, user_id: i32) -> BinderResult<()> {
         map_or_log_err(Self::add_or_remove_user(user_id), Ok)
     }
+
+    fn clearNamespace(&self, domain: Domain, nspace: i64) -> BinderResult<()> {
+        map_or_log_err(Self::clear_namespace(domain, nspace), Ok)
+    }
 }