feat(trust): wire Phase 0 signed-catalog verification + pin release-root KAT
Completes the parked trust module and wires it into the live build: - main.rs: register `mod trust` - app_catalog::fetch_one: verify the release-root detached signature when present (verify against raw JSON so forward-compat fields stay in the signed preimage); accept unsigned during the migration window, hard-reject a present-but-bad signature so a tampering mirror can't pass altered bytes - seed: pin release-root Ed25519 known-answer test (priv+pub) for the signing ceremony / pinned-anchor / external-verifier cross-check - signed_doc: drop unused import 20/20 Phase 0 unit tests pass (trust::canonical/did/signed_doc/anchor, seed release-root, app_catalog). Crate compiles clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
0fef808671
commit
27f11bf85a
@ -268,9 +268,32 @@ async fn fetch_one(client: &reqwest::Client, url: &str) -> anyhow::Result<AppCat
|
|||||||
}
|
}
|
||||||
let body = resp.text().await?;
|
let body = resp.text().await?;
|
||||||
let catalog: AppCatalog = serde_json::from_str(&body)?;
|
let catalog: AppCatalog = serde_json::from_str(&body)?;
|
||||||
// NOTE (DHT Phase 0): when `catalog.signature` is present, verify it against
|
|
||||||
// the seed-derived release-root pubkey here before accepting. Until signing
|
// DHT Phase 0 authenticity: verify the release-root signature when present.
|
||||||
// ships we accept unsigned catalogs (same trust level as today's manifest).
|
// We verify against the raw JSON (the exact bytes the publisher signed),
|
||||||
|
// not a re-serialization of the typed struct, so unknown forward-compat
|
||||||
|
// fields stay part of the signed preimage. Unsigned catalogs are still
|
||||||
|
// accepted during the migration window — same trust level as today's
|
||||||
|
// manifest — but a *present* signature that fails is a hard reject so a
|
||||||
|
// tampering mirror cannot pass off altered bytes.
|
||||||
|
let raw: serde_json::Value = serde_json::from_str(&body)?;
|
||||||
|
match crate::trust::verify_detached(&raw)? {
|
||||||
|
crate::trust::SignatureStatus::Unsigned => {
|
||||||
|
debug!("app-catalog: unsigned (accepted during migration window)");
|
||||||
|
}
|
||||||
|
crate::trust::SignatureStatus::Verified { signer_did, anchored } => {
|
||||||
|
if anchored {
|
||||||
|
info!("app-catalog: release-root signature verified ({})", signer_did);
|
||||||
|
} else {
|
||||||
|
warn!(
|
||||||
|
"app-catalog: signature self-consistent but release-root anchor \
|
||||||
|
not pinned ({}); cannot confirm signer identity",
|
||||||
|
signer_did
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Ok(catalog)
|
Ok(catalog)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -68,6 +68,7 @@ mod storage_crypto;
|
|||||||
mod streaming;
|
mod streaming;
|
||||||
mod totp;
|
mod totp;
|
||||||
mod transport;
|
mod transport;
|
||||||
|
mod trust;
|
||||||
mod update;
|
mod update;
|
||||||
mod vpn;
|
mod vpn;
|
||||||
mod wallet;
|
mod wallet;
|
||||||
|
|||||||
@ -606,12 +606,12 @@ mod tests {
|
|||||||
let key = derive_release_root_ed25519(&seed).unwrap();
|
let key = derive_release_root_ed25519(&seed).unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
hex::encode(key.to_bytes()),
|
hex::encode(key.to_bytes()),
|
||||||
"__RELEASE_ROOT_PRIV_HEX__",
|
"613ab879e5fbd4fcded32bc7ffad662fff1ce0f744c69baa63e7416ffabe7b71",
|
||||||
"release-root private key KAT"
|
"release-root private key KAT"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
hex::encode(key.verifying_key().to_bytes()),
|
hex::encode(key.verifying_key().to_bytes()),
|
||||||
"__RELEASE_ROOT_PUB_HEX__",
|
"995eaf9188617f0ecbcff9cd44d57adb9aa7dd5f34db2733e97f3e317fb0aba2",
|
||||||
"release-root public key KAT"
|
"release-root public key KAT"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,7 +16,7 @@
|
|||||||
//! them*. The DHT plan requires both.
|
//! them*. The DHT plan requires both.
|
||||||
|
|
||||||
use anyhow::{anyhow, bail, Context, Result};
|
use anyhow::{anyhow, bail, Context, Result};
|
||||||
use ed25519_dalek::{Signature, Signer, SigningKey, VerifyingKey};
|
use ed25519_dalek::{Signature, Signer, SigningKey};
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
|
|
||||||
use super::anchor;
|
use super::anchor;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user