feat(logging): UID-keyed attestation dossier

Add a debug-only per-UID diagnostic plane gated on BuildConfig.DEBUG.
For apps in target.txt it records every keystore interaction and the
forged attestation it produces to teesim-uid-<uid>.log: decoded cert
chain (FORGE and PATCH paths), key params, keybox, and prop sources,
with the calling UID threaded through the C++ binder hook and Rust
certgen. Release builds stay silent (R8 strips the write plane and the
runtime gate short-circuits). Adds --clear-logs to package.sh.
This commit is contained in:
Enginex0
2026-06-04 15:53:06 +01:00
parent f826312fc4
commit e5483afc70
14 changed files with 392 additions and 44 deletions
+28 -1
View File
@@ -64,18 +64,41 @@ fn generate_attested_inner(env: &mut JNIEnv, config: &JObject) -> Result<jbyteAr
let cert_chain = if params.attestation_challenge.is_some() {
let attest_ext = attestation::build_attestation_extension(&params)?;
// Ground truth of what the Rust forger emitted, keyed to the app. Gated on the APK debug
// variant so release builds never dump the extension.
if params.debug_logging {
tracing::info!(
uid = params.uid,
ext_hex = %hex_encode(&attest_ext),
"produced attestation extension"
);
}
certbuilder::build_certificate_chain(&key_pair, Some(&attest_ext), &keybox, &params)?
} else {
tracing::info!("no attestation challenge, generating self-signed cert (depth 1)");
tracing::info!(
uid = params.uid,
"no attestation challenge, generating self-signed cert (depth 1)"
);
certbuilder::build_self_signed_cert(&key_pair, &params)?
};
let blob = assemble_result(&key_pair.private_key_pkcs8, &cert_chain);
tracing::info!(uid = params.uid, certs = cert_chain.len(), "assembled native cert result");
let out = env.byte_array_from_slice(&blob)?;
Ok(out.into_raw())
}
/// Lowercase hex of a byte slice for diagnostic dumps; the crate has no `hex` dependency.
fn hex_encode(bytes: &[u8]) -> String {
use std::fmt::Write as _;
let mut out = String::with_capacity(bytes.len() * 2);
for b in bytes {
let _ = write!(out, "{:02x}", b);
}
out
}
// ---------------------------------------------------------------------------
// JNI entry: initLogging
// ---------------------------------------------------------------------------
@@ -205,6 +228,8 @@ fn extract_config(env: &mut JNIEnv, config: &JObject) -> Result<CertGenParams> {
let caller_nonce = get_boolean(env, config, "callerNonce")?;
let unlocked_device_required = get_boolean(env, config, "unlockedDeviceRequired")?;
let no_auth_required = get_boolean(env, config, "noAuthRequired")?;
let uid = get_int(env, config, "uid")?;
let debug_logging = get_boolean(env, config, "debugLogging")?;
Ok(CertGenParams {
algorithm: Algorithm::try_from(algorithm)?,
@@ -252,6 +277,8 @@ fn extract_config(env: &mut JNIEnv, config: &JObject) -> Result<CertGenParams> {
caller_nonce,
unlocked_device_required,
no_auth_required,
uid,
debug_logging,
})
}
+5
View File
@@ -93,6 +93,11 @@ pub struct CertGenParams {
pub caller_nonce: bool,
pub unlocked_device_required: bool,
pub no_auth_required: bool,
/// Calling app UID, used only to key diagnostic log lines to the requesting app.
pub uid: i32,
/// Mirrors the APK debug variant; gates the produced-extension dump so release stays quiet.
pub debug_logging: bool,
}
pub struct GeneratedKeyPair {