-
Notifications
You must be signed in to change notification settings - Fork 2.8k
Incremental TLS handshake defragmentation #10011
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Incremental TLS handshake defragmentation #10011
Conversation
06508ac to
c75da8b
Compare
129337e to
41e53cf
Compare
ae8c65b to
ce818da
Compare
minosgalanakis
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Revied the range of commits specific to the change of fragment's re-assemly.
Looks good overall
library/ssl_msg.c
Outdated
| #else | ||
| size_t const in_buf_len = MBEDTLS_SSL_IN_BUFFER_LEN; | ||
| #endif | ||
| if (payload_end + ssl->in_hsfraglen > ssl->in_buf + in_buf_len) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I assume that when MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH is enabled, a buffer can only expand when resized?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good question. A buffer can shrink when resized. But resizing only happens at the beginning and at the end of the handshake.
In any case, I don't think that matters here? We're checking whether the data fits now. If there's code that wants to resize the buffer, it would have to determine whether the data that's already in the buffer would still fit. Which, currently, is easy: resizing is only done at times when there's no data in the buffer.
|
Here's a final rebase now that #10021 is merged. |
ce818da to
e25976f
Compare
Pacify `clang -Wdocumentation`. Signed-off-by: Gilles Peskine <[email protected]>
In preparation for reworking mbedtls_ssl_prepare_handshake_record(), tweak the "waiting for more handshake fragments" log message in ssl_consume_current_message(), and add a similar one in mbedtls_ssl_prepare_handshake_record(). Assert both. Signed-off-by: Gilles Peskine <[email protected]>
In preparation for reworking mbedtls_ssl_prepare_handshake_record(), tweak the "handshake fragment:" log message. This changes what information is displayed when a record contains data beyond the expected end of the handshake message. This case is currently untested and its handling will change in a subsequent commit. Signed-off-by: Gilles Peskine <[email protected]>
Minor refactoring of the initial checks and preparation when receiving the first fragment. Use `ssl->in_hsfraglen` to determine whether there is a pending handshake fragment, for consistency, and possibly for more robustness in case handshake fragments are mixed with non-handshake records (although this is not currently supported anyway). Signed-off-by: Gilles Peskine <[email protected]>
Signed-off-by: Gilles Peskine <[email protected]>
Reassemble handshake fragments incrementally instead of all at the end. That is, every time we receive a non-initial handshake fragment, append it to the initial fragment. Since we only have to deal with at most two handshake fragments at the same time, this simplifies the code (no re-parsing of a record) and is a little more memory-efficient (no need to store one record header per record). This commit also fixes a bug. The previous code did not calculate offsets correctly when records use an explicit IV, which is the case in TLS 1.2 with CBC (encrypt-then-MAC or not), GCM and CCM encryption (i.e. all but null and ChachaPoly). This led to the wrong data when an encrypted handshake message was fragmented (Finished or renegotiation). The new code handles this correctly. Signed-off-by: Gilles Peskine <[email protected]>
Pacify `clang -Wformat-pedantic`. Signed-off-by: Gilles Peskine <[email protected]>
e25976f to
1051a2e
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
The pointer to the framework may need to be updated before merging, since we are failing component_test_tls13_only_psk because all tests are being skipped.
Changed log messages and added more tests in `tests/opt-testcases/handshake-generated.sh`. Signed-off-by: Gilles Peskine <[email protected]>
1051a2e to
e4a3fc2
Compare
|
I had missed some commits when rebasing the framework. I've updated the framework branch and the pointer again, should be good now. |
mpg
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking good overall, but:
- I'm afraid one of the bounds check is wrong (it's probably not needed anyway, but if we have it it should be correct).
- Unless I'm mistaken there's an uncommented limitation compared to what the standard allows, which should have a comment.
library/ssl_msg.c
Outdated
| ssl->in_hslen)); | ||
|
|
||
| const size_t hs_remain = ssl->in_hslen - ssl->in_hsfraglen; | ||
| if (ssl->in_msglen > hs_remain) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IIUC we're being stricter than the protocol here: this condition means that there's more data in the record after the rest of this handshake message, presumably the (beginning of) the next handshake message, which is allowed by the standard unless I'm mistaken.
I don't have an issue with rejecting it anyway, but I'd like a comment explaining that we are rejecting something the standard allows and why we're doing that. Also, that's a limitation we should document. And I find the current debug message a bit confusing.
(Unless I'm mistaken about what's happening here.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right.
I added this check because I believed that the old code silently ignored subsequent handshake messages if there is more than one in the same record. However, revisiting this, I'm not sure that was the case: here we do nothing, but ssl_consume_current_message handles it. So now I'm worried that I've broken some existing untested behavior. But if I remove the check here, I'm worried that the defragmentation code may be creating an unexpected state. I'll keep digging today.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Leveraging #9976, I've crafted a test case with ServerHello and ServerCertificate in the same message, and that test case passes before incremental defragmentation. So this check removes functionality, and I'm going to remove it.
library/ssl_msg.c
Outdated
| #else | ||
| size_t const in_buf_len = MBEDTLS_SSL_IN_BUFFER_LEN; | ||
| #endif | ||
| if (payload_end + ssl->in_hsfraglen > ssl->in_buf + in_buf_len) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you mean payload_end + ssl->in_msglen here, to protect the call to memmove() below.
Signed-off-by: Gilles Peskine <[email protected]>
A handshake record may contain multiple handshake messages, or multiple fragments (there can be the final fragment of a pending message, then zero or more whole messages, and an initial fragment of an incomplete message). This was previously untested, but supported, so don't break it. Signed-off-by: Gilles Peskine <[email protected]>
There is no longer any different processing at this point, just near-identical log messages. Signed-off-by: Gilles Peskine <[email protected]>
Signed-off-by: Gilles Peskine <[email protected]>
Signed-off-by: Gilles Peskine <[email protected]>
mpg
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking pretty good! Just one issue in a debug string, and a suggestion to avoid potentially adding useless memory accesses even in the non-fragmented case.
Signed-off-by: Gilles Peskine <[email protected]>
minosgalanakis
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
mpg
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, thanks!
723fec4
into
Mbed-TLS:features/tls-defragmentation/development
Defragment incoming TLS handshake messages incrementally, instead of all at the end. This makes the code simpler and a little more efficient.
Fixes defragmentation of encrypted messages with an explicit IV.
PR checklist