Fix off-by-one over-read in TLS 1.2 ClientHello and CertificateRequest - #10833
Fix off-by-one over-read in TLS 1.2 ClientHello and CertificateRequest#10833nvxbug wants to merge 2 commits into
Conversation
Signed-off-by: Naveed <naveed@bugqore.com>
|
any update? |
gilles-peskine-arm
left a comment
There was a problem hiding this comment.
Thank you for contributing this fix. I believe that it is functionally correct, but the code is giving me a headache, so I would prefer to fix the existing checks instead of adding another one.
Adding tests is entirely optional and I can propose something Codex wrote.
ClientHello: narrow the session-id check to the session id itself, check the cookie length byte before reading it, and let the ciphersuite-list length check cover both transports. CertificateRequest: make the signature-algorithms check also reserve the two certificate-authorities length bytes instead of adding a separate check, use the available < needed pattern throughout, and reject an odd-length signature-algorithms list. Add injected truncated-ClientHello test cases (TLS 1.2-only builds). Signed-off-by: Naveed <naveed@bugqore.com>
|
Pushed the rework, details in the inline replies. Short version: existing checks amended instead of adding new ones, odd sig_alg_len now rejected, and there are two injected truncated ClientHello tests for the server side. |
gilles-peskine-arm
left a comment
There was a problem hiding this comment.
Thank you for updating the hard-to-understand checks to classic if (read_length > available_size) return ERROR checks. Looks good to me.
Would you mind making pull requests for mbedtls-4.1 and mbedtls-3.6 as well?
|
mbedtls/library/ssl_tls12_client.c Line 2220 in 522e2e4 mbedtls/library/ssl_tls12_client.c Line 2239 in 522e2e4 What is the reason to change these conditions? The new conditions seems to be equivalent to the previous ones, but with unnecessary extra operation of addition. |
|
@irwir yes, those two are equivalent, it's deliberate. The check with the actual off-by-one was written in the @gilles-peskine-arm backports are up: #10929 for 4.1 and #10928 for 3.6. |
|
|
|
Right, with DTLS compiled in it's a runtime value. It's a static inline returning 4 or 12 though, so after inlining the literal offsets still fold and the operand count stays the same, e.g. |
Description
Repro: a TLS 1.2 ClientHello whose body ends right after the session id, i.e.
msg_len == 35 + sess_len + 1, passes the session-id length check but the parser then reads the two-byte ciphersuite-list length. A CertificateRequest that ends inside its distinguished-name length field behaves the same on the client side.Cause: in
ssl_parse_client_hellothe session-id check only guaranteessess_len + 36 <= msg_len, one byte short of thesess_len + 37needed forMBEDTLS_GET_UINT16_BE(buf, 35 + sess_len), so the second length byte is read one byte past the message body. The DTLS branch reserves those two bytes correctly through its cookie-length check; only the non-DTLS path is short. The same shortfall exists before thedn_lenread inssl_parse_certificate_request.Fix (reworked per review): amend the existing checks instead of adding new ones. In
ssl_parse_client_hellothe session-id check now covers just the session id, the cookie length byte is checked before it is read, and the ciphersuite-list length check covers both transports. Inssl_parse_certificate_requestthe signature-algorithms check also reserves the two certificate-authorities length bytes, the checks use theavailable < neededpattern, and an odd-length signature-algorithms list is rejected. Valid handshakes are unaffected; the truncated messages that hit this were already rejected by the consistency check that follows, so the only behavior change is that the over-read no longer happens.PR checklist