Keystore 2.0: Teach keystore to decrypt generic blobs.

This CL addresses various gaps in legacy support.
* Encrypted legacy blobs.
* Encrypted key characteristics files (pre Android Q).
* Encrypted certificate and certificate chain entries
  (pre Android R).

To support key migration even when the corresponding user is locked,
keys can now be migrated in the legacy database by renaming files.
In order to construct a complete a key characteristics cache from old
characteristics files the information must be augmented with the
characteristics that can be extracted from the key blob by calling
KeyMintDevice::getKeyCharacteristics. For this to work, the blob
may need to be decrypted, upgraded, and reencrypted. The crypto steps
may fail with ResponseCode::LOCKED though if the user is locked.
If the key was upgraded in the process both the old and the new key
blob must be inserted into the database in order for the garbage
collector to reap and invalidate the superseded blob correctly.
At the time APPLICATION_ID and APPLICATION_DATA are usually not
available. This would cause such bound keys to fail with
ErrorCode::INVALID_KEY_BLOB. However, APPLICATION_ID/DATA were
never exposed to applications though, so this should be acceptable
for now.

Bug: 213173772
Bug: 213172664
Bug: 203101472
Test: keystore2_test
Change-Id: Id8561d3f98d53182709d9f4feeeecda3b1535077
diff --git a/keystore2/legacykeystore/lib.rs b/keystore2/legacykeystore/lib.rs
index 13a9143..e2d952d 100644
--- a/keystore2/legacykeystore/lib.rs
+++ b/keystore2/legacykeystore/lib.rs
@@ -25,8 +25,9 @@
 };
 use anyhow::{Context, Result};
 use keystore2::{
-    async_task::AsyncTask, error::anyhow_error_to_cstring, legacy_blob::LegacyBlobLoader,
-    maintenance::DeleteListener, maintenance::Domain, utils::watchdog as wd,
+    async_task::AsyncTask, error::anyhow_error_to_cstring, globals::SUPER_KEY,
+    legacy_blob::LegacyBlobLoader, maintenance::DeleteListener, maintenance::Domain,
+    utils::uid_to_android_user, utils::watchdog as wd,
 };
 use rusqlite::{
     params, Connection, OptionalExtension, Transaction, TransactionBehavior, NO_PARAMS,
@@ -315,8 +316,8 @@
         if let Some(entry) = db.get(uid, alias).context("In get: Trying to load entry from DB.")? {
             return Ok(entry);
         }
-        if self.get_legacy(uid, alias).context("In get: Trying to migrate legacy blob.")? {
-            // If we were able to migrate a legacy blob try again.
+        if self.get_legacy(uid, alias).context("In get: Trying to import legacy blob.")? {
+            // If we were able to import a legacy blob try again.
             if let Some(entry) =
                 db.get(uid, alias).context("In get: Trying to load entry from DB.")?
             {
@@ -328,19 +329,20 @@
 
     fn put(&self, alias: &str, uid: i32, entry: &[u8]) -> Result<()> {
         let uid = Self::get_effective_uid(uid).context("In put.")?;
-        // In order to make sure that we don't have stale legacy entries, make sure they are
-        // migrated before replacing them.
-        let _ = self.get_legacy(uid, alias);
         let mut db = self.open_db().context("In put.")?;
-        db.put(uid, alias, entry).context("In put: Trying to insert entry into DB.")
+        db.put(uid, alias, entry).context("In put: Trying to insert entry into DB.")?;
+        // When replacing an entry, make sure that there is no stale legacy file entry.
+        let _ = self.remove_legacy(uid, alias);
+        Ok(())
     }
 
     fn remove(&self, alias: &str, uid: i32) -> Result<()> {
         let uid = Self::get_effective_uid(uid).context("In remove.")?;
         let mut db = self.open_db().context("In remove.")?;
-        // In order to make sure that we don't have stale legacy entries, make sure they are
-        // migrated before removing them.
-        let _ = self.get_legacy(uid, alias);
+
+        if self.remove_legacy(uid, alias).context("In remove: trying to remove legacy entry")? {
+            return Ok(());
+        }
         let removed =
             db.remove(uid, alias).context("In remove: Trying to remove entry from DB.")?;
         if removed {
@@ -430,17 +432,30 @@
                 return Ok(true);
             }
             let mut db = DB::new(&state.db_path).context("In open_db: Failed to open db.")?;
-            let migrated =
-                Self::migrate_one_legacy_entry(uid, &alias, &state.legacy_loader, &mut db)
-                    .context("Trying to migrate legacy keystore entries.")?;
-            if migrated {
+            let imported =
+                Self::import_one_legacy_entry(uid, &alias, &state.legacy_loader, &mut db)
+                    .context("Trying to import legacy keystore entries.")?;
+            if imported {
                 state.recently_imported.insert((uid, alias));
             }
-            Ok(migrated)
+            Ok(imported)
         })
         .context("In get_legacy.")
     }
 
+    fn remove_legacy(&self, uid: u32, alias: &str) -> Result<bool> {
+        let alias = alias.to_string();
+        self.do_serialized(move |state| {
+            if state.recently_imported.contains(&(uid, alias.clone())) {
+                return Ok(false);
+            }
+            state
+                .legacy_loader
+                .remove_legacy_keystore_entry(uid, &alias)
+                .context("Trying to remove legacy entry.")
+        })
+    }
+
     fn bulk_delete_uid(&self, uid: u32) -> Result<()> {
         self.do_serialized(move |state| {
             let entries = state
@@ -473,21 +488,31 @@
         })
     }
 
-    fn migrate_one_legacy_entry(
+    fn import_one_legacy_entry(
         uid: u32,
         alias: &str,
         legacy_loader: &LegacyBlobLoader,
         db: &mut DB,
     ) -> Result<bool> {
         let blob = legacy_loader
-            .read_legacy_keystore_entry(uid, alias)
-            .context("In migrate_one_legacy_entry: Trying to read legacy keystore entry.")?;
+            .read_legacy_keystore_entry(uid, alias, |ciphertext, iv, tag, _salt, _key_size| {
+                if let Some(key) = SUPER_KEY
+                    .read()
+                    .unwrap()
+                    .get_per_boot_key_by_user_id(uid_to_android_user(uid as u32))
+                {
+                    key.decrypt(ciphertext, iv, tag)
+                } else {
+                    Err(Error::sys()).context("No key found for user. Device may be locked.")
+                }
+            })
+            .context("In import_one_legacy_entry: Trying to read legacy keystore entry.")?;
         if let Some(entry) = blob {
             db.put(uid, alias, &entry)
-                .context("In migrate_one_legacy_entry: Trying to insert entry into DB.")?;
+                .context("In import_one_legacy_entry: Trying to insert entry into DB.")?;
             legacy_loader
                 .remove_legacy_keystore_entry(uid, alias)
-                .context("In migrate_one_legacy_entry: Trying to delete legacy keystore entry.")?;
+                .context("In import_one_legacy_entry: Trying to delete legacy keystore entry.")?;
             Ok(true)
         } else {
             Ok(false)