fix(multi-sig): sign_partial blind-signing oracle — verify bundle bytes against the event#358
Draft
bordumb wants to merge 1 commit into
Draft
fix(multi-sig): sign_partial blind-signing oracle — verify bundle bytes against the event#358bordumb wants to merge 1 commit into
bordumb wants to merge 1 commit into
Conversation
… blindly `sign_partial` signed the bundle's stored `canonical_bytes` directly, without checking they match `serialize_for_signing(bundle.event)`. A tampered bundle — a benign event shown to the operator, but `canonical_bytes` belonging to a malicious event — could harvest a valid signature over an event the signer never approved: a blind-signing oracle on KEL events (key rotation, device addition). `combine` / `validate_signed_event` already re-derive the canonical bytes from the event; `sign_partial` did not, so what was signed and what was verified could diverge. Fix: `bundle_canonical` recomputes the canonical bytes from the event (the source of truth) and refuses a bundle whose stored bytes disagree (typed `BundleMismatch`, fail-closed, before any key is loaded). `sign_partial` signs the recomputed bytes. Found by adversarial review. Two other threshold bypasses on `combine` were raised and REFUTED: `Threshold::is_satisfied` dedupes indices (no duplicate-signer quorum) and `validate_signed_event` enforces the event's own `kt` over verified indices (a loose caller-supplied `expected_kt` cannot widen it). Tests: bundle_canonical_rejects_a_tampered_bundle (the defense) + bundle_canonical_accepts_a_consistent_bundle; 5/5 multi_sig tests pass. Auths-Id: did:keri:EB5cPHY0t-ejNC_rUzPS1dclTvd6kG-R9mQzjozCuGgd Auths-Device: did:keri:EB5cPHY0t-ejNC_rUzPS1dclTvd6kG-R9mQzjozCuGgd Auths-Anchor-Seq: 1
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Auths Commit Verification
Result: ❌ 0/1 commits verified How to fixCommit 1. Install auths macOS: 2. One-time setup (creates your identity and configures Git) auths init3. Sign this branch and push auths sign origin/main..HEAD
git push --force-with-leaseFor CI to verify the signer, commit an identity bundle: auths id export-bundle --alias main --output .auths/ci-bundle.json --max-age-secs 31536000 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Multi-sig:
sign_partialwas a blind-signing oracleFound by adversarial review of the matrix's untested-sensitive backlog (
multi_sig::sign_partialhad zero test coverage).The bug
sign_partialsigned the bundle's storedcanonical_bytes(read from disk) directly, without verifying they equalserialize_for_signing(bundle.event):Meanwhile
combine/validate_signed_eventre-derive the canonical bytes from the event. So the bytes a signer signs and the bytes a verifier checks could diverge. A tampered bundle —event= a benign event shown to the operator,canonical_bytes= the canonicalization of a malicious event (e.g. a rotation adding the attacker's key) — yields a valid signature the attacker assembles into the malicious event. The signer approves X, signs Y. For a multi-sig whose whole point is independent per-signer approval, that breaks the guarantee.The fix (fail-closed)
bundle_canonical(bundle)recomputes the canonical bytes from the event (the source of truth) and returns a typedMultiSigError::BundleMismatchif the stored bytes disagree — before any key is loaded.sign_partialsigns the recomputed bytes. Legitimate bundles (wherebegin_multi_sig_eventwrote consistent bytes) are unaffected; tampered ones are refused loudly. This also bringssign_partialinto line withcombine, which already trusts only the event.Adversarially verified — two findings refuted
The same review raised two threshold bypasses on
combineand refuted both (kept honest):Threshold::is_satisfieddedupes indices via aHashSet, so[idx 0, idx 0]counts as one signer.expected_kt— refuted:validate_signed_eventenforces the event's ownktover verified indices, so a caller's looser expectation can't widen the real threshold.Tests
bundle_canonical_rejects_a_tampered_bundle— the defense (would not have rejected before this change).bundle_canonical_accepts_a_consistent_bundle— legitimate path unaffected.multi_sigtests pass (3 pre-existingcombinetests still green).Note: the gate is wired into
sign_partial(let canonical = bundle_canonical(&bundle)?;) before any key access; the unit tests exercise the check directly.Part of matrix ROADMAP_2 R2 (adversarial coverage of untested operations).