Cap the ohttp key body size from directory - #1846
Conversation
Coverage Report for CI Build 33902922471Coverage increased (+0.006%) to 86.646%Details
Uncovered Changes
Coverage Regressions1 previously-covered line in 1 file lost coverage.
Coverage Stats
💛 - Coveralls |
7d928e8 to
465c1dc
Compare
xstoicunicornx
left a comment
There was a problem hiding this comment.
Reviewed with Opus 4.8 and Sol 5.6, compiled and unslopped the feedback as best I could. Please let me know if any of it is not quite right/applicable.
CLI follow-up found during review - handle OhttpKeysBodyTooLarge as a directory failure instead of as a relay failure (see 199412b).
| } | ||
| } | ||
|
|
||
| let mut body = Vec::with_capacity(MAX_OHTTP_KEYS_BODY_LEN); |
There was a problem hiding this comment.
Vec::with_capacity(MAX_OHTTP_KEYS_BODY_LEN) is grabbing 64 KiB on every fetch when a real config is exactly 74 bytes making every client allocate ~886x what it needs.
| let mut body = Vec::with_capacity(MAX_OHTTP_KEYS_BODY_LEN); | |
| let mut body = Vec::new(); |
| /// the suite vector is u16-length-bounded (at most 65532 bytes of suites). Any | ||
| /// larger response cannot decode and is rejected before being fully buffered | ||
| /// to prevent memory exhaustion from a hostile payjoin directory. | ||
| pub const MAX_OHTTP_KEYS_BODY_LEN: usize = 1 + 2 + 65 + 2 + u16::MAX as usize - 3; |
There was a problem hiding this comment.
Perhaps pub(crate) is sufficient?
|
|
||
| let body = res.bytes().await?.to_vec(); | ||
| if let Some(len) = res.content_length() { | ||
| if len as usize > MAX_OHTTP_KEYS_BODY_LEN { |
There was a problem hiding this comment.
| if len as usize > MAX_OHTTP_KEYS_BODY_LEN { | |
| if len > MAX_OHTTP_KEYS_BODY_LEN as u64 { |
Converting it to usize could truncate large values on 32-bit systems.
| } | ||
|
|
||
| #[tokio::test] | ||
| async fn test_parse_oversized_body_without_content_length() { |
There was a problem hiding this comment.
Reqwest's content_length() reads the body's size hint, not a header, and for a Vec<u8>body that hint is exact. The test exits through the content_length branch and the chunk() loop is still not covered.
See 03b1b5f.
|
|
||
| /// Upper bound on the size of an OHTTP key configuration response body. | ||
| /// | ||
| /// Derived from the ECHKeyConfig wire format: `key_id(1) + kem_id(2) + |
There was a problem hiding this comment.
| /// Derived from the ECHKeyConfig wire format: `key_id(1) + kem_id(2) + | |
| /// Derived from the Ohttp Key Config (RFC 9458) format: `key_id(1) + kem_id(2) + |
465c1dc to
622f302
Compare
This caps the key cofig fetch size from the directory to limit any malicious directory from sending oversized data on key fetch. Treat oversized keys as directory failures An oversized OHTTP key response originates from the directory, not the CONNECT relay. Mark the directory as failed and return instead of excluding each relay while retrying the same response. Co-authored-by: xstoicunicornx <xstoicunicornx@users.noreply.github.com>
622f302 to
8fff253
Compare
This caps the key config fetch size from the directory to limit any malicious directory from sending oversized data on key fetch.
Coded with GLM-5.3
Pull Request Checklist
Please confirm the following before requesting review:
AI
in the body of this PR.