Conversation
CertificateBundle::try_from(&[u8]) parsed concatenated DER with unchecked arithmetic: total_len = header_len + cert_len and offset + total_len. An attacker-controlled long-form DER length can reach ~usize::MAX (parse_der_length folds up to 8 bytes with no width cap), making offset + total_len wrap below data.len() after one valid certificate advances offset. The bounds guard reuses the wrapped value and passes, after which &data[offset..offset+total_len] is a start>end slice that panics -> process/wasm abort under panic=abort. Reachable from the WASM export X509Certificate::parseChain on caller-supplied hex-DER. Use checked_add for both sums and bail on overflow; also reject long-form lengths wider than size_of::<usize>() in parse_der_length. Co-authored-by: Ty Schenk <schenkty@users.noreply.github.com>
larseidsvoll
left a comment
There was a problem hiding this comment.
Overflow→slice panic path fixed with checked arithmetic and width cap. REQUEST_CHANGES: Lint red on this head — reformat (long if in utils.rs) and re-run. Draft + Ty lock — no merge.
…D warnings) The regression test discarded the Result returned by test_all_certificate_sets, tripping clippy's unused_must_use under -D warnings. Return it from the test so cargo clippy --all-targets --all-features -- -D warnings is clean. Co-authored-by: Ty Schenk <schenkty@users.noreply.github.com>
larseidsvoll
left a comment
There was a problem hiding this comment.
Prior REQUEST_CHANGES cleared — Lint green and checked-length fix intact. Draft + Ty lock — no merge.
larseidsvoll
left a comment
There was a problem hiding this comment.
Verdict: APPROVE (re-stamp after #45)
Tip moved for main merge. Diff unchanged: checked DER length arithmetic + width cap + overflow regression test.
Security Audit green. Lint green; Tests still running.
Review only — do not bot-merge. Humans merge. No @ humans.
|
|
No security issues found. Tip |



Summary
CertificateBundle::try_from(&[u8])parses concatenated DER certificates using hand-rolled length arithmetic with unchecked additions:parse_der_lengthfolds an attacker-chosen long-form DER length (up to 8 bytes) into ausizewith no width cap, socert_lencan be ≈usize::MAX. With the header30 88 FF FF FF FF FF FF FF F5,cert_len = 0xFFFFFFFFFFFFFFF5andheader_len = 10, sototal_len = usize::MAX(no overflow at that add). Onceoffsethas advanced past one valid certificate (offset ≥ 1),offset + total_lenwraps tooffset - 1, which satisfies the<= data.len()guard — and the following slice&data[offset..offset-1]hasstart > endand panics. Under the release profile'spanic = "abort"this aborts the whole process/wasm instance.Reachable from the WASM export
X509Certificate.parseChain(keetanetwork-client-wasm), which hex-decodes a caller-supplied string straight intoCertificateBundle::try_from.Reproduced arithmetic:
(No memory-safety corruption — Rust's bounds check catches the out-of-range slice before any read; the impact is a DoS abort.)
Fix
checked_addforheader_len + cert_lenandoffset + total_len;breakon overflow.parse_der_length: reject long-form lengths wider thansize_of::<usize>()(which would otherwise silently shift out high bits).Tests
cargo test -p keetanetwork-x509— all 71 pass, including:test_bundle_try_from_rejects_overflow_length_without_panic— a valid cert followed by the malicious length header parses without panicking and retains only the leading valid cert.test_parse_der_lengthstill passes.Severity: medium (DoS / process abort in a public decode path).
Draft — audit fix; do not merge without maintainer review.