SEC-2276: integrity confidence signals + structured observability#162
Conversation
Add new fields to KeyDescription for integrity confidence analysis: verified_boot_key, verified_boot_hash, device_unique_attestation, device identity fields, module_hash, purpose, and creation_date_time. Introduce extraction macros to reduce duplication across the five attestation version parsers (v1, v2, v3, v300, v400).
Expose the new KeyDescription integrity fields through DeviceCertificate accessor methods: verified_boot_key, verified_boot_hash, device_unique_attestation, attestation_id_* fields, module_hash, purpose, and creation_date_time.
Distinguish legacy attestation root certificates from RKP (Remote Key Provisioning) roots. Add rkp_public_keys tracking, optional loading of attestation_root_rkp.pem, and is_rkp_root() method to detect chains that bypass keybox leakage risk.
Introduce IntegrityConfidence struct capturing informational signals about attestation chain trustworthiness: rkp_rooted, device_unique, has_id_attestation, unexpected_purpose, boot key/hash, batch serial, module hash, creation time delta, and device identity fields. Emit metrics counter and structured tracing log for every attestation. Make android_attestation_service module public for downstream use.
Plumb IntegrityConfidence into IntegrityTokenPayload and serialize it as a JSON claim in the issued JWS token for Android attestations. Downstream consumers can now apply custom risk policies based on attestation chain strength signals.
This is the consolidated follow-up to the closed PRs #154-#158 (SEC-2307 through SEC-2311) plus the local additions, rebased on the trust-anchor enforcement from SEC-2314 and stripped of: * the keybox-defense rate limiter (lands separately as SEC-2275) * the Protected Confirmation experiment What it does: * `key_description`: ASN.1 parser now extracts every field we care about for risk scoring -- purpose, creation date, verified-boot key/hash, batch-cert serial, module hash, every `attestation_id_*`, plus `unique_id`, `attestation_version`, `os/vendor/boot_patch_level`, `usage_count_limit`, `algorithm`, `key_size`, `ec_curve`. * `device_certificate`: pub accessors for each new field. * `android_ca_registry`: tracks the subset of roots that issue keys via Remote Key Provisioning (`is_rkp_root`) so we can mark RKP-rooted chains as keybox-bypass-impossible. * `android_attestation_service`: new `IntegrityConfidence` aggregate exposing all signals (boot state, RKP, identity diversity, patch level staleness, batch-cert serial, etc.); structured `tracing::info!`/`warn!` events at every verification step so we can feed Datadog with what we accepted and why. * `routes/a.rs`: 5 optional informational request fields (`security_level`, `os_api_level`, `device_properties_included`, `integrity_signature`, `device_key_expires_at`) that the World App already sends on staging; structured per-request logging; embeds `IntegrityConfidence` in the issued integrity-token JWT under the `integrity_confidence` claim and in the `/a` response so verifying parties can do their own risk scoring. * `utils`: optional alt signing-cert digest, gated behind `ATTESTATION_GATEWAY_ACCEPT_ALT_SIGNING_CERT=1` so the staging gateway can accept dev/test World App builds without re-signing. Off by default, has no effect on production bundles. * `main.rs` / `Cargo.toml`: `tracing-subscriber` now reads `RUST_LOG` via `EnvFilter`, so we can flip verbosity without redeploying. No behavior change for accepted attestations: signals are additive and always-on logs. Untrusted attestations still get rejected at the same points they did before. Maps to https://linear.app/worldcoin/issue/SEC-2276
|
Warning Review the following alerts detected in dependencies. According to your organization's Security Policy, it is recommended to resolve "Warn" alerts. Learn more about Socket for GitHub.
|
Per request, this PR is now telemetry-only: no modifications to the
issued JWT. The structured logs, metrics, and IntegrityConfidence
struct are kept (they let us observe and dashboard the signals). The
`integrity_confidence` field on `IntegrityTokenPayload` and the
corresponding `set_claim("integrity_confidence", ...)` block are
removed, along with the now-unused `android_confidence` plumbing in
`/a` handler.
If/when downstream verifiers want these signals in the token, we can
add them in a separate, focused PR with explicit consumer alignment.
Summary
Consolidated follow-up to the closed PRs #154 through #158 (SEC-2307 through SEC-2311) plus local additions, rebased on top of the trust-anchor enforcement from #161 (SEC-2314). The Protected Confirmation experiment and the keybox-defense rate limiter have been removed from this PR; the latter lands separately as SEC-2275.
Stacks on top of #161.
Changes
key_description: ASN.1 parser now extracts every field we care about for risk scoring -- purpose, creation date, verified-boot key/hash, batch-cert serial, module hash, everyattestation_id_*, plusunique_id,attestation_version,os_version,vendor_patch_level,boot_patch_level,usage_count_limit,algorithm,key_size,ec_curve.device_certificate: pub accessors for each new field.android_ca_registry: tracks the subset of roots that issue keys via Remote Key Provisioning (is_rkp_root) so we can mark RKP-rooted chains as keybox-bypass-impossible.android_attestation_service: newIntegrityConfidenceaggregate exposing all signals (boot state, RKP, identity diversity, patch-level staleness, batch-cert serial, etc.); structuredtracing::info!/warn!events at every verification step so we can feed Datadog with what we accepted and why.routes/a.rs: 5 optional informational request fields (security_level,os_api_level,device_properties_included,integrity_signature,device_key_expires_at) that the World App already sends on staging; structured per-request logging; embedsIntegrityConfidencein the issued integrity-token JWT under theintegrity_confidenceclaim and in the/aresponse so verifying parties can do their own risk scoring.utils: optional alt signing-cert digest, gated behindATTESTATION_GATEWAY_ACCEPT_ALT_SIGNING_CERT=1so the staging gateway can accept dev/test World App builds without re-signing. Off by default; production bundles unaffected.main.rs/Cargo.toml:tracing-subscribernow readsRUST_LOGviaEnvFilter, so verbosity can be flipped without redeploying.Compatibility
No behavior change for accepted attestations: signals are additive and always-on logs. Untrusted attestations still get rejected at the same points they did before.
Linear
SEC-2276 -- Harden Android attested key generation
Test plan
integrity_confidenceintegrity_confidenceclaimRUST_LOG=traceand confirm verbosity actually changesATTESTATION_GATEWAY_ACCEPT_ALT_SIGNING_CERT=1on staging, attest from a dev-signed World App build, confirm acceptance