v1.0.1: audit fixes — fetchCertRaw status check, .part cleanup, AVK guards, strict merkle, JSON error envelope
Independent code audit (in-repo, fresh-eyes pass) flagged 0 critical, 4
high, 8 medium, 7 low. This commit addresses all 4 highs + the JSON
error-path inconsistency + the vestigial verify.STM stub.
HIGH fixes:
- cmd/mithril-go/main.go fetchCertRaw: missing status check let HTML 4xx/5xx
bodies fall through to confusing JSON-decode errors. Added explicit
StatusCode>=400 check + 16 MiB response body cap + Accept header.
- internal/artifact/download.go: SHA mismatch left .part on disk, causing
every retry to resume the corrupted bytes and fail SHA forever. Now
removes .part on hash mismatch so the next attempt starts clean.
- internal/stm/types.go DecodeAVK: rejects total_stake=0 and nr_leaves=0
at decode-time. internal/stm/lottery.go adds defensive guard for
stake==0 || totalStake==0 to prevent big.Rat.SetFrac panic (DoS vector
for the MCP server when fed crafted AVK).
- internal/stm/merkle.go: now requires (a) every proof value is exactly
32 bytes, (b) indices are STRICTLY ascending (no duplicates),
(c) every index is < nr_leaves, (d) all proof values are consumed by
the algorithm. Prevents parser-differential bugs vs upstream Rust.
JSON error-path wiring:
- cmd/mithril-go/json.go: replaced unused emitJSONErr with failure() helper
that routes errors to stdout-as-JSON when -json is set, else stderr-as-text.
Error envelope shape: {error: {code, kind, message}} where 'kind' is a
stable short string (network/integrity/verify/usage/internal) for agents
to branch on without parsing human text.
- All -json-supporting commands (info, list, show, cert, verify+subcommands)
now use failure() in error paths instead of bare fmt.Fprintln(stderr).
- Verified: 'verify -json deadbeef' on a bogus hash now emits valid JSON
to stdout with exit=3, instead of empty stdout + text on stderr.
Vestigial code:
- internal/verify/verify.go: removed STM() stub + ErrSTMNotImplemented.
Real STM verification has lived in internal/stm/verify.go since the
crypto sprint; the stub was dead code from milestone-by-milestone work.
Verification (still all green):
- preprod chain: 90 certs, 1124 wins ✓
- mainnet head: 59 signers, 1972 wins ✓
- preprod head: 2 signers, 11 wins ✓
- preprod genesis: Ed25519 ✓
- JSON error envelope on bogus hash: well-formed JSON, exit=3
- internal/stm unit test: PASS
Audit findings deferred to v1.0.2+: bubble-sort in stm.Verify (medium,
perf only at scale); int-vs-uint64 truncation guards on 32-bit targets
(medium, won't bite on 64-bit); tar mode-bit masking (medium, low impact
since archives are from trusted aggregator); no User-Agent header on
aggregator requests (low, op nicety); MCP scanner silent stop on >10 MiB
line (low, defensive).
This commit is contained in:
parent
a66c51bdb8
commit
ee76a48e47
7 changed files with 123 additions and 82 deletions
|
|
@ -27,7 +27,6 @@ var (
|
|||
ErrNotGenesis = errors.New("certificate is not a genesis certificate")
|
||||
ErrBadSignature = errors.New("genesis signature verification failed")
|
||||
ErrSignedMessageHash = errors.New("signed_message does not match SHA256(protocol_message)")
|
||||
ErrSTMNotImplemented = errors.New("STM signature verification not implemented yet")
|
||||
)
|
||||
|
||||
// The Mithril enum order on ProtocolMessagePartKey — BTreeMap iteration
|
||||
|
|
@ -182,9 +181,5 @@ func GenesisFromJSON(verifyKey ed25519.PublicKey, signedMessageHex, genesisSigna
|
|||
return Genesis(verifyKey, signedMessageHex, genesisSignatureHex, pm)
|
||||
}
|
||||
|
||||
// STM verifies a non-genesis certificate's aggregate BLS signature.
|
||||
// Stub — target is Mithril STM paper §5 (signing) + §6 (aggregation)
|
||||
// using gnark-crypto's bls12-381 primitives.
|
||||
func STM(protocolMessageJSON, multiSignature []byte, avk any) error {
|
||||
return ErrSTMNotImplemented
|
||||
}
|
||||
// STM verification lives in the sibling internal/stm package — see
|
||||
// stm.Verify(). This file is genesis-Ed25519-only.
|
||||
|
|
|
|||
Reference in a new issue