Merge changes from topic "apex-aidl" into main
* changes:
Populate apex module info
Include module info in dump output
diff --git a/keystore2/Android.bp b/keystore2/Android.bp
index ef5111f..4878eb3 100644
--- a/keystore2/Android.bp
+++ b/keystore2/Android.bp
@@ -46,12 +46,14 @@
"android.security.maintenance-rust",
"android.security.metrics-rust",
"android.security.rkp_aidl-rust",
+ "apex_aidl_interface-rust",
"libaconfig_android_hardware_biometrics_rust",
"libandroid_security_flags_rust",
"libanyhow",
"libbinder_rs",
"libbssl_crypto",
"libder",
+ "libhex",
"libkeystore2_aaid-rust",
"libkeystore2_apc_compat-rust",
"libkeystore2_crypto_rust",
@@ -111,7 +113,6 @@
defaults: ["libkeystore2_defaults"],
rustlibs: [
"libandroid_logger",
- "libhex",
"libkeystore2_test_utils",
"libkeystore2_with_test_utils",
"liblibsqlite3_sys",
diff --git a/keystore2/src/maintenance.rs b/keystore2/src/maintenance.rs
index 54b5b44..acca942 100644
--- a/keystore2/src/maintenance.rs
+++ b/keystore2/src/maintenance.rs
@@ -19,7 +19,7 @@
use crate::error::map_km_error;
use crate::error::Error;
use crate::globals::get_keymint_device;
-use crate::globals::{DB, LEGACY_IMPORTER, SUPER_KEY, ENCODED_MODULE_INFO};
+use crate::globals::{DB, ENCODED_MODULE_INFO, LEGACY_IMPORTER, SUPER_KEY};
use crate::ks_err;
use crate::permission::{KeyPerm, KeystorePerm};
use crate::super_key::SuperKeyManager;
@@ -30,6 +30,9 @@
use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
ErrorCode::ErrorCode, IKeyMintDevice::IKeyMintDevice, KeyParameter::KeyParameter, KeyParameterValue::KeyParameterValue, SecurityLevel::SecurityLevel, Tag::Tag,
};
+use apex_aidl_interface::aidl::android::apex::{
+ IApexService::IApexService,
+};
use android_security_maintenance::aidl::android::security::maintenance::IKeystoreMaintenance::{
BnKeystoreMaintenance, IKeystoreMaintenance,
};
@@ -42,9 +45,11 @@
use android_system_keystore2::aidl::android::system::keystore2::KeyDescriptor::KeyDescriptor;
use android_system_keystore2::aidl::android::system::keystore2::ResponseCode::ResponseCode;
use anyhow::{anyhow, Context, Result};
+use binder::wait_for_interface;
use bssl_crypto::digest;
use der::{DerOrd, Encode, asn1::OctetString, asn1::SetOfVec, Sequence};
use keystore2_crypto::Password;
+use rustutils::system_properties::PropertyWatcher;
use std::cmp::Ordering;
/// Reexport Domain for the benefit of DeleteListener
@@ -57,10 +62,10 @@
pub const KEYMINT_V4: i32 = 400;
/// Module information structure for DER-encoding.
-#[derive(Sequence, Debug)]
+#[derive(Sequence, Debug, PartialEq, Eq)]
struct ModuleInfo {
name: OctetString,
- version: i32,
+ version: i64,
}
impl DerOrd for ModuleInfo {
@@ -242,9 +247,68 @@
log::error!("SUPER_KEY.set_up_boot_level_cache failed:\n{:?}\n:(", e);
}
+ if keystore2_flags::attest_modules() {
+ std::thread::spawn(move || {
+ Self::watch_apex_info()
+ .unwrap_or_else(|e| log::error!("watch_apex_info failed: {e:?}"));
+ });
+ }
Maintenance::call_on_all_security_levels("earlyBootEnded", |dev| dev.earlyBootEnded(), None)
}
+ /// Watch the `apexd.status` system property, and read apex module information once
+ /// it is `activated`.
+ ///
+ /// Blocks waiting for system property changes, so must be run in its own thread.
+ fn watch_apex_info() -> Result<()> {
+ let prop = "apexd.status";
+ log::info!("start monitoring '{prop}' property");
+ let mut w = PropertyWatcher::new(prop).context(ks_err!("PropertyWatcher::new failed"))?;
+ loop {
+ let value = w.read(|_name, value| Ok(value.to_string()));
+ // The status for apexd moves from "starting" to "activated" to "ready"; the apex
+ // info file should be populated for either of the latter two states, so cope with
+ // both in case we miss a state change.
+ log::info!("property '{prop}' is now '{value:?}'");
+ if matches!(value.as_deref(), Ok("activated") | Ok("ready")) {
+ match Self::read_apex_info() {
+ Ok(modules) => {
+ Self::set_module_info(modules)
+ .context(ks_err!("failed to set module info"))?;
+ break;
+ }
+ Err(e) => {
+ log::error!(
+ "failed to read apex info, try again on next state change: {e:?}"
+ );
+ }
+ }
+ }
+
+ log::info!("await a change to '{prop}'...");
+ w.wait(None).context(ks_err!("property wait failed"))?;
+ log::info!("await a change to '{prop}'...notified");
+ }
+ Ok(())
+ }
+
+ fn read_apex_info() -> Result<Vec<ModuleInfo>> {
+ let _wp = wd::watch("read_apex_info via IApexService.getActivePackages()");
+ let apexd: Strong<dyn IApexService> =
+ wait_for_interface("apexservice").context("failed to AIDL connect to apexd")?;
+ let packages = apexd.getActivePackages().context("failed to retrieve active packages")?;
+ packages
+ .into_iter()
+ .map(|pkg| {
+ log::info!("apex modules += {} version {}", pkg.moduleName, pkg.versionCode);
+ let name = OctetString::new(pkg.moduleName.as_bytes()).map_err(|e| {
+ anyhow!("failed to convert '{}' to OCTET_STRING: {e:?}", pkg.moduleName)
+ })?;
+ Ok(ModuleInfo { name, version: pkg.versionCode })
+ })
+ .collect()
+ }
+
fn migrate_key_namespace(source: &KeyDescriptor, destination: &KeyDescriptor) -> Result<()> {
let calling_uid = ThreadState::get_calling_uid();
@@ -329,6 +393,19 @@
}
writeln!(f)?;
+ // Display module attestation information
+ {
+ let info = ENCODED_MODULE_INFO.read().unwrap();
+ if let Some(info) = info.as_ref() {
+ writeln!(f, "Attested module information (DER-encoded):")?;
+ writeln!(f, " {}", hex::encode(info))?;
+ writeln!(f)?;
+ } else {
+ writeln!(f, "Attested module information not set")?;
+ writeln!(f)?;
+ }
+ }
+
// Display database size information.
match crate::metrics_store::pull_storage_stats() {
Ok(atoms) => {
@@ -394,8 +471,8 @@
Ok(())
}
- #[allow(dead_code)]
fn set_module_info(module_info: Vec<ModuleInfo>) -> Result<()> {
+ log::info!("set_module_info with {} modules", module_info.len());
let encoding = Self::encode_module_info(module_info)
.map_err(|e| anyhow!({ e }))
.context(ks_err!("Failed to encode module_info"))?;
@@ -427,7 +504,6 @@
)
}
- #[allow(dead_code)]
fn encode_module_info(module_info: Vec<ModuleInfo>) -> Result<Vec<u8>, der::Error> {
SetOfVec::<ModuleInfo>::from_iter(module_info.into_iter())?.to_der()
}