Add getSupplementaryAttestationInfo

Allows clients to retrieve information required to interpret certain
attested values found in the attestation certificate.

Currently only relevant for Tag::MODULE_HASH, for which it returns the
encoded structure whose hash ends up in the attestation certificate.

Bug: 369375199
Test: treehugger
Change-Id: Ida8c72fa262d13c01c22bd68fa0bd71b881b876b
diff --git a/keystore2/aconfig/flags.aconfig b/keystore2/aconfig/flags.aconfig
index 2e9659f..b15230e 100644
--- a/keystore2/aconfig/flags.aconfig
+++ b/keystore2/aconfig/flags.aconfig
@@ -48,3 +48,11 @@
   bug: "319563050"
   is_fixed_read_only: true
 }
+
+flag {
+  name: "attest_modules"
+  namespace: "hardware_backed_security"
+  description: "Support attestation of modules"
+  bug: "369375199"
+  is_fixed_read_only: true
+}
diff --git a/keystore2/src/globals.rs b/keystore2/src/globals.rs
index 0e8892b..3b9c631 100644
--- a/keystore2/src/globals.rs
+++ b/keystore2/src/globals.rs
@@ -165,6 +165,8 @@
     LazyLock::new(|| Arc::new(LegacyImporter::new(Arc::new(Default::default()))));
 /// Background thread which handles logging via statsd and logd
 pub static LOGS_HANDLER: LazyLock<Arc<AsyncTask>> = LazyLock::new(Default::default);
+/// DER-encoded module information returned by `getSupplementaryAttestationInfo(Tag.MODULE_HASH)`.
+pub static ENCODED_MODULE_INFO: RwLock<Option<Vec<u8>>> = RwLock::new(None);
 
 static GC: LazyLock<Arc<Gc>> = LazyLock::new(|| {
     Arc::new(Gc::new_init_with(ASYNC_TASK.clone(), || {
diff --git a/keystore2/src/service.rs b/keystore2/src/service.rs
index 95e1744..85ac7bc 100644
--- a/keystore2/src/service.rs
+++ b/keystore2/src/service.rs
@@ -27,7 +27,10 @@
 };
 use crate::{
     database::Uuid,
-    globals::{create_thread_local_db, DB, LEGACY_BLOB_LOADER, LEGACY_IMPORTER, SUPER_KEY},
+    globals::{
+        create_thread_local_db, DB, ENCODED_MODULE_INFO, LEGACY_BLOB_LOADER, LEGACY_IMPORTER,
+        SUPER_KEY,
+    },
 };
 use crate::{database::KEYSTORE_UUID, permission};
 use crate::{
@@ -39,6 +42,7 @@
     id_rotation::IdRotationState,
 };
 use android_hardware_security_keymint::aidl::android::hardware::security::keymint::SecurityLevel::SecurityLevel;
+use android_hardware_security_keymint::aidl::android::hardware::security::keymint::Tag::Tag;
 use android_hardware_security_keymint::binder::{BinderFeatures, Strong, ThreadState};
 use android_system_keystore2::aidl::android::system::keystore2::{
     Domain::Domain, IKeystoreSecurityLevel::IKeystoreSecurityLevel,
@@ -314,6 +318,20 @@
         DB.with(|db| count_key_entries(&mut db.borrow_mut(), k.domain, k.nspace))
     }
 
+    fn get_supplementary_attestation_info(&self, tag: Tag) -> Result<Vec<u8>> {
+        match tag {
+            Tag::MODULE_HASH => {
+                let info = ENCODED_MODULE_INFO.read().unwrap();
+                (*info)
+                    .clone()
+                    .ok_or(Error::Rc(ResponseCode::INFO_NOT_AVAILABLE))
+                    .context(ks_err!("Module info not received."))
+            }
+            _ => Err(Error::Rc(ResponseCode::INVALID_ARGUMENT))
+                .context(ks_err!("Tag {tag:?} not supported for getSupplementaryAttestationInfo.")),
+        }
+    }
+
     fn list_entries_batched(
         &self,
         domain: Domain,
@@ -441,4 +459,14 @@
         let _wp = wd::watch("IKeystoreService::getNumberOfEntries");
         self.count_num_entries(domain, namespace).map_err(into_logged_binder)
     }
+
+    fn getSupplementaryAttestationInfo(&self, tag: Tag) -> binder::Result<Vec<u8>> {
+        if keystore2_flags::attest_modules() {
+            let _wp = wd::watch("IKeystoreService::getSupplementaryAttestationInfo");
+            self.get_supplementary_attestation_info(tag).map_err(into_logged_binder)
+        } else {
+            log::error!("attest_modules flag is not toggled");
+            Err(binder::StatusCode::UNKNOWN_TRANSACTION.into())
+        }
+    }
 }