-
Notifications
You must be signed in to change notification settings - Fork 724
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
fix: tainted handshake.io and add large client hello test #5208
base: main
Are you sure you want to change the base?
Conversation
crypto/s2n_ecc_evp.c
Outdated
|
||
POSIX_GUARD(s2n_alloc(&point_blob, point_len)); | ||
POSIX_GUARD(s2n_ecc_evp_write_point_data_snug(point, group, &point_blob)); | ||
POSIX_GUARD(s2n_stuffer_write(out, &point_blob)); | ||
POSIX_GUARD(s2n_free(&point_blob)); |
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.
Allocating and then immediately freeing is pretty inefficient. Can you figure out a way to do this without an allocation?
42dfff6
to
4aee908
Compare
4aee908
to
1f9a9c6
Compare
efda486
to
371ae42
Compare
* Fix typos for temporary * use s2n_stuffer_data_available * add GUARD to the s2n_negotiate to write Client Hello
5c29ebe
to
e38bd76
Compare
e138bfe
to
b9792f8
Compare
b9792f8
to
a0666a3
Compare
* Set out->tainted to false in s2n_extension_send.
POSIX_GUARD(s2n_stuffer_rewrite(out)); | ||
POSIX_GUARD(s2n_stuffer_skip_write(out, written_data_location)); | ||
POSIX_GUARD(s2n_stuffer_skip_read(out, read_cursor)); |
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.
This has the potential not to work. You can't read past where you've written, so this only works if read_cursor < written_data_location. I imagine it works bc read_cursor should be 0 here, but it's not technically correct.
It seems non-ideal to have to deal with the read_cursor at all. Can you figure out a less destructive way to handle this?
/* Test: Client Hello is slightly less than 64KB */ | ||
{ |
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.
If I see this test 6mo from now, I'm going to question why this needed to be tested :) I'd bundle these two tests together under the name "Test: very large client hellos" so that it's clear why you're doing <64KB / >64KB.
/* The size of Client Hello exceeds S2N_MAXIMUM_HANDSHAKE_MESSAGE_LENGTH */ | ||
EXPECT_TRUE(s2n_stuffer_data_available(&io_pair.server_in) > S2N_MAXIMUM_HANDSHAKE_MESSAGE_LENGTH); |
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.
You check s2n_client_hello_get_raw_message_length above, but server_in here. If these two tests are supposed to be analogous, we should make the same size assertion.
Also note that server_in isn't just the CH-- it's also the record, so an extra 5 bytes for the record header. If that matters, I'd probably note that in a comment rather than doing math to strip off the header.
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.
If these two tests are supposed to be analogous, we should make the same size assertion.
I will check server_in
for both for them to be analogous. The Client Hello will not be parsed into the server connection if the message itself is a bad message, so we can't get use s2n_client_hello_get_raw_mesage_length
for the second case.
I will put a comment mentioning the extra 5 bytes for record header. It shouldn't matter, since the handshake message from the first case is about 100 bytes less than S2N_MAXIMUM_HANDSHAKE_MESSAGE_LENGTH
, and the second case is about 300 bytes more than S2N_MAXIMUM_HANDSHAKE_MESSAGE_LENGTH
.
* Reset the tainted flag on the out stuffer (typically handshake.io). | ||
* The handshake.io stuffer is wiped after processing each handshake message, | ||
* which resets its state and marks it as not tainted. | ||
* No raw data from handshake.io is permanently stored in the connection during extension send. | ||
* Because of that, we can mark the out stuffer as not tainted which allows the stuffer to | ||
* continue growing after each extension send. |
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.
This comment assumes handshake.io, but you note only "typically handshake.io". That makes me question whether this is safe / correct.
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 will say reset the tainted flag on the out stuffer (handshake.io stuffer)
. It's always the handshake.io stuffer since I have checked the entire codebase for this function call.
/* Test: Client Hello is slightly less than 64KB */ | ||
{ |
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.
These tests require a lot of setup that should be the same. Can they share any setup, to better highlight the differences?
Release Summary:
Resolved issues:
related to aws/s2n-quic#332.
Description of changes:
Replace
s2n_stuffer_raw_write()
ins2n_ecc_evp_write_params()
. Use a stuffer copy to perform raw write, so that the original stuffer won't get tainted.s2n_stuffer_reserve_space()
before creating a copy, so that the copy stuffer won't realloc memory during the raw write operation.write_cursor
andhigh_water_mark
since they might get changed.s2n_ecc_evpo_write_params()
, but we don't reserve any additional space or updating any other stuffer's meta data, because thedata_len
is zero.Change cipher preferences count from uint8_t to uint16_t. The RFC specifies that the total cipher suites size can be (2^16 - 2).
Add two tests in
s2n_client_hello_test.c
. One to generate a Client Hello that's close the maximum handshake length and another to generate a Client Hello that's larger than the maximum length.Call-outs:
s2n_raw_write
ors2n_raw_read
unless we have no other ways. There are many other places inS2N-TLS
where we used those two functions. We should probably do a check for all of them in the future to see if we can change all of them.UINT16_MAX
cipher suites, then the total cipher suites length would be (2^17 - 2) bytes. Our Client Hello send function will error on that, since it only reserve 16 bytes to write all cipher suites information:s2n-tls/tls/s2n_client_hello.c
Lines 750 to 751 in 03a70fc
tests/unit/s2n_client_hello_test.c
. I would like some feedbacks on naming and how to make the math computations better.tls/extensions/s2n_extension_type.c
, I checked every time that we calls2n_extension_list_send
in our codebase (except testing), the out stuffer is alwayshandshake.io
ins2n_connection
struct.handshake.io
will always be wiped at the end of each handshake message. That means the data inhandshake.io
is temporary. Therefore, it is safe to mark the out stuffer as not tainted after the extension is sent.tls/extensions/s2n_extension_type.c
when I am resetingtainted
to false. Please let me know if the comment is not clear.Testing:
When the unit tests in the CI are testing with
openssl-1.1.1
andopenssl-3.0
,EVP_APIS_SUPPORTED
will be enabled. When the unit tests in CI are testing withopenssl-1.0.2
,EVP_APIS_SUPPORTED
will be disabled. Hence, the CI will test for changes for both situations.By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.