From 4908d17c383a4894cc045cdaf12df0ae4dee5163 Mon Sep 17 00:00:00 2001 From: Transaction Science Date: Mon, 26 Oct 2026 08:32:31 -0400 Subject: [PATCH] sec: replace two allow-list reasons with what the call sites actually say MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The advisory gate's allow list is only worth what its reasons are worth, and two of mine were generalisations I had checked in one place and then written as if they held everywhere. Both happen to be correct; neither was verified where it mattered. Re-checked by call site: `rsa` RUSTSEC-2023-0071 (Marvin) — no fixed release exists, so this entry cannot be bumped away and the reason carries the whole weight. I had written "no private-key decryption here" after verifying it for openpay, whose dependency turned out to be unused and was removed. The two copies that remain were not checked at the time: - sandbox-rs: `sandbox-tee/src/amd_kds.rs` is the only direct user of `rsa` in the tree. It verifies AMD's KDS chain (ARK -> ASK -> VCEK, RSASSA-PSS / SHA-384) with `RsaPublicKey` + `pss::VerifyingKey` + `Verifier`. Public-key verification, no decryption, and `RsaPrivateKey` appears only inside `#[cfg(test)] mod tests`, minting throwaway keys for a synthetic chain. Marvin needs private-key PKCS#1 v1.5 decryption, which is absent. - wai-rs: reaches `rsa` only through `c2pa`, an optional dependency behind the `c2pa_emit` feature and off by default, so a default build never compiles it. `crypto-bigint` RUSTSEC-2026-0387 — I had recorded this as debt "on paths that sign and derive keys", which overstated it. `elliptic-curve` is the only dependent in all five lockfiles, and none of our own signing goes through it: WAI, sandbox and jouleclaw sign with Ed25519 (`ed25519_dalek` / curve25519-dalek, which does not use crypto-bigint). In wai-rs the elliptic-curve path is again under optional `c2pa`, where production callers supply their own signer and the in-tree `EphemeralSigner` holds a per-call key that reaches `ValidationState::Valid` and never `Trusted`. A timing attack of this class recovers a key by observing many operations under the same secret, so a per-call key bounds it. The 0.5 pin is still real debt — reaching >=0.7.6 means moving the p256/elliptic-curve stack — but it is not sitting under a long-lived key of ours. No behaviour change: 47 lockfiles, the same 15 allowances, self-test green on all six cases. This is the reasoning catching up with the gate. Co-Authored-By: Claude Opus 5 --- scripts/check-advisories.py | 51 ++++++++++++++++++++++++++++--------- 1 file changed, 39 insertions(+), 12 deletions(-) diff --git a/scripts/check-advisories.py b/scripts/check-advisories.py index 0800e2e47..f47fb0987 100755 --- a/scripts/check-advisories.py +++ b/scripts/check-advisories.py @@ -71,22 +71,49 @@ ALLOW = { "RUSTSEC-2026-0368": "zip: extract-only; nothing here extracts an archive", "RUSTSEC-2026-0369": "zip: extract-only; nothing here extracts an archive", "RUSTSEC-2025-0168": "zip: extract-only path canonicalization; nothing here extracts", - # The Marvin attack recovers an RSA key from the timing of private-key - # decryption. There is no fixed release of `rsa` at all. It reaches - # sandbox-rs and wai-rs transitively and neither holds an RSA private key - # nor decrypts: openpay's unused direct dependency was removed outright. - "RUSTSEC-2023-0071": "rsa: no fixed release; no private-key decryption here", + # The Marvin attack recovers an RSA key from the timing of **private-key + # decryption** (PKCS#1 v1.5). There is no fixed release of `rsa` at all, so + # this one cannot be bumped away and the reason has to carry it. Both + # remaining copies were checked by call site, not by assumption: + # + # sandbox-rs: `sandbox-tee/src/amd_kds.rs` is the only direct user in the + # tree. It verifies AMD's KDS chain (ARK -> ASK -> VCEK, RSASSA-PSS / + # SHA-384) with `RsaPublicKey` + `pss::VerifyingKey` + `Verifier`. + # Public-key verification only; there is no decryption anywhere, and + # `RsaPrivateKey` appears solely inside `#[cfg(test)] mod tests`, which + # mints throwaway keys to build a synthetic chain. + # wai-rs: reaches it only through `c2pa`, which is an optional dependency + # behind the `c2pa_emit` feature and off by default, so a default build + # does not compile it. WAI's own signing is Ed25519 (`ed25519_dalek`), + # which uses neither `rsa` nor `crypto-bigint`. + # + # openpay's copy is gone: the dependency was declared and never used, so it + # was removed outright rather than excused. + "RUSTSEC-2023-0071": "rsa: no fixed release; verification only, no decryption, private keys test-only", # ── Pinned by a dependency; needs an upstream release ────────────────── # Secret-dependent branches in operations meant to be constant-time # (subtraction, zero counting, division, Montgomery multiplication), so - # timing can leak intermediate arithmetic on secret integers. Fixed in - # >=0.7.6, and smart-byte's 0.7.x copy is patched. The 0.5.5 line is pinned - # by elliptic-curve 0.13, so reaching it means moving the whole - # p256/elliptic-curve stack — a real upgrade, not a bump, and this entry is - # that debt, recorded on paths that sign and derive keys. Version-pinned on - # purpose: a 0.7.x copy must never be excused by it. + # timing can leak intermediate arithmetic on a secret integer. Fixed in + # >=0.7.6, and smart-byte's 0.7.x copy is patched. + # + # Every remaining 0.5.5 copy arrives under `elliptic-curve` — it is the only + # dependent in all five lockfiles — which pins the 0.5 line, so reaching + # >=0.7.6 means moving the whole p256/elliptic-curve stack. That is an + # upgrade, not a bump, and this entry is that debt. + # + # What bounds it: a timing attack of this class recovers a key by observing + # many operations under the *same* secret, and none of our own signing runs + # through this crate. WAI, sandbox and jouleclaw sign with Ed25519 + # (`ed25519_dalek` / curve25519-dalek, which does not use crypto-bigint); + # in wai-rs the elliptic-curve path arrives under `c2pa`, optional and off + # by default, where production callers supply their own signer and the + # in-tree `EphemeralSigner` holds a per-call key that reaches + # `ValidationState::Valid` and never `Trusted`. So the debt is real but it + # is not sitting under a long-lived key of ours. + # + # Version-pinned on purpose: a 0.7.x copy must never be excused by it. "RUSTSEC-2026-0387": { - "why": "crypto-bigint 0.5.5 is pinned by elliptic-curve 0.13; 0.7.x is patched", + "why": "crypto-bigint 0.5.5 pinned by elliptic-curve 0.13; our signing is Ed25519; 0.7.x is patched", "only": ("crypto-bigint 0.5.5",), }, # hpke-rs-libcrux pins `=0.7.0`, which pins libcrux-kem 0.0.9. Both are -- 2.54.0 (Apple Git-157)