Skip to content
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

TLS 1.3: Refine and test client early data status #8755

Merged

Conversation

ronald-cron-arm
Copy link
Contributor

@ronald-cron-arm ronald-cron-arm commented Jan 26, 2024

Description

First PR of two addressing #6340.

PR checklist

  • changelog not required, will add one for TLS 1.3 early data feature as a whole
  • backport not required, new feature
  • tests provided

@ronald-cron-arm ronald-cron-arm added enhancement needs-ci Needs to pass CI tests needs-preceding-pr Requires another PR to be merged first component-tls13 labels Jan 26, 2024
@ronald-cron-arm ronald-cron-arm force-pushed the tls13-client-early-data-status branch from 80120b7 to 60c27aa Compare January 26, 2024 18:51
@ronald-cron-arm ronald-cron-arm added needs-review Every commit must be reviewed by at least two team members, needs-reviewer This PR needs someone to pick it up for review priority-high High priority - will be reviewed soon and removed needs-ci Needs to pass CI tests labels Jan 29, 2024
@ronald-cron-arm ronald-cron-arm force-pushed the tls13-client-early-data-status branch from 60c27aa to 90f50c4 Compare February 5, 2024 07:53
@ronald-cron-arm ronald-cron-arm added needs-ci Needs to pass CI tests and removed needs-preceding-pr Requires another PR to be merged first labels Feb 5, 2024
@ronald-cron-arm ronald-cron-arm force-pushed the tls13-client-early-data-status branch 2 times, most recently from 5ca8eae to b9127dc Compare February 6, 2024 08:14
@mpg mpg self-requested a review February 6, 2024 11:09
@mpg mpg removed the needs-ci Needs to pass CI tests label Feb 6, 2024
@mpg mpg requested a review from tom-cosgrove-arm February 6, 2024 11:11
@mpg mpg removed the needs-reviewer This PR needs someone to pick it up for review label Feb 6, 2024
Signed-off-by: Ronald Cron <ronald.cron@arm.com>
Signed-off-by: Ronald Cron <ronald.cron@arm.com>
Signed-off-by: Ronald Cron <ronald.cron@arm.com>
Signed-off-by: Ronald Cron <ronald.cron@arm.com>
Signed-off-by: Ronald Cron <ronald.cron@arm.com>
Fix cases where the client was sending
two CCS, no harm but better to send only one.

Prevent to send even more CCS when early data
are involved without having to add conditional
state transitions.

Signed-off-by: Ronald Cron <ronald.cron@arm.com>
The main purpose of the change is to
know from the status, at any point in
the handshake, if early data can be
sent or not and why.

Signed-off-by: Ronald Cron <ronald.cron@arm.com>
Signed-off-by: Ronald Cron <ronald.cron@arm.com>
Signed-off-by: Ronald Cron <ronald.cron@arm.com>
Signed-off-by: Ronald Cron <ronald.cron@arm.com>
Signed-off-by: Ronald Cron <ronald.cron@arm.com>
Signed-off-by: Ronald Cron <ronald.cron@arm.com>
@ronald-cron-arm ronald-cron-arm force-pushed the tls13-client-early-data-status branch from b9127dc to 2261ab2 Compare February 6, 2024 15:44
@ronald-cron-arm ronald-cron-arm linked an issue Feb 6, 2024 that may be closed by this pull request
1 task
Copy link
Contributor

@mpg mpg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks pretty good to me! I only have minor suggestions for improvements (mostly comments, naming, etc.) but everything looks correct and well-tested to me.

if (ret == 0) {
mbedtls_ssl_handshake_set_state(ssl, MBEDTLS_SSL_CLIENT_HELLO);
ret = 0;
if (ssl->handshake->ccs_count == 0) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: I think we could put that check inside mbedtls_ssl_tls13_write_change_cipher_spec() (which would do nothing and return 0 if CCS has already been sent). This would avoid having to repeat this at each call site, saving a few bytes of code size but more importantly making sure we don't forget the check.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in #8760 commit "tls13: client: Improve CCS handling"

* one CCS per handshake without having to complicate the handshake state
* transitions.
*/
uint8_t ccs_count;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find the name slightly misleading, since we expect to send no more than once. I'd prefer ccs_sent. (Said otherwise, if an integer variable's only legal values are 0 and 1, I prefer to think of it as a boolean rather than a counter.)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with Manuel, but minor, can be done in a follow-up PR

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree as well, done in #8760 commit "tls13: Use a flag not a counter for CCS and HRR handling".

#define MBEDTLS_SSL_EARLY_DATA_STATUS_NOT_SENT 0
#define MBEDTLS_SSL_EARLY_DATA_STATUS_ACCEPTED 1
#define MBEDTLS_SSL_EARLY_DATA_STATUS_REJECTED 2
#define MBEDTLS_SSL_EARLY_DATA_STATUS_NOT_SENT 1
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pre-exisiting: it would be good to have comment here like we have for the other values defined in ssl_misc.h. In particular, out of context it might not be clear if STATUS_NOT_SENT means the extension has not been sent, or early data itself has not been sent.

Btw, maybe renaming to STATUS_NOT_OFFERED or STATUS_EXT_NOT_SENT would make that clearer? (In addition to comments I mean.)

Edit, after reading more of the code: IIUC this actually means "we decided not to send it" as opposed to "we haven't sent it yet but might send it in the future". This only strengthens my point about adding a comment to make that clear.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(pre-existing, minor) feels like this should be an enum

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ssl_tls13_early_data_has_valid_ticket(ssl) &&
ssl->conf->early_data_enabled == MBEDTLS_SSL_EARLY_DATA_ENABLED &&
ssl->handshake->hello_retry_request_count == 0) {
if (ssl->handshake->hello_retry_request_count == 0) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pre-existing, but: can there really be more that on HRR per handshake? If not, I'd also suggest making that a boolean instead as I think that count may mislead readers into thinking there may be more than one. (I'll agree if you say that's out of scope.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, done in #8760 commit "tls13: Use a flag not a counter for CCS and HRR handling".

ssl->conf->early_data_enabled == MBEDTLS_SSL_EARLY_DATA_ENABLED &&
ssl->handshake->hello_retry_request_count == 0) {
if (ssl->handshake->hello_retry_request_count == 0) {
if (mbedtls_ssl_conf_tls13_is_some_psk_enabled(ssl) &&
Copy link
Contributor

@mpg mpg Feb 13, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[edit: skip to last paragraph, only requesting adding a comment after all]

I'm not sure I understand or agree with the logic here:

if no_hrr:
   if other_conditions:
      send it and mark as sent
   else:
      mark as not sent

So, it there was an HRR in this handshake, we will not send the extension and not update the status to "not sent" either? Is that intentional? I'd have expected:

if no_hrr and other_conditions:
   send it and mark as sent
else:
   mark as not sent

What am I missing?

Edit, after reading more of the code: I think what I was missing is that if there was an HRR earlier, status has already been updated to "rejected" and we want to leave it at that. So, now I think I understand and agree with the logic here, but a comment would be welcome.

Copy link
Contributor Author

@ronald-cron-arm ronald-cron-arm Feb 15, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in #8760 commit "tls13: client: Add comment about early data in 2nd ClientHello".

* The client has not sent the first ClientHello yet, it is unknown if the
* client will send an early data indication extension or not.
*/
#define MBEDTLS_SSL_EARLY_DATA_STATUS_UNKNOWN 0
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: the documentation for the early_data_status field still says Reset to #MBEDTLS_SSL_EARLY_DATA_STATUS_NOT_SENT - does it need updating?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in #8760, commit "tls13: Fix/Improve comments"

@@ -2145,6 +2145,38 @@ int mbedtls_ssl_tls13_write_early_data_ext(mbedtls_ssl_context *ssl,
unsigned char *buf,
const unsigned char *end,
size_t *out_len);

#if defined(MBEDTLS_SSL_CLI_C)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: the definitions in ssl.h are not guarded by this, should they be?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(minor) I'd prefer to see them defined in one place, even if values are defined that aren't used under some circumstances - they are well-enough namespaced

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

@tom-cosgrove-arm tom-cosgrove-arm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM - I only have minor comments, and given @mpg's review is similar, and these commits are in another PR that is under review, it seems best to merge this as-is and address those comments in a follow-on PR

#define MBEDTLS_SSL_EARLY_DATA_STATUS_NOT_SENT 0
#define MBEDTLS_SSL_EARLY_DATA_STATUS_ACCEPTED 1
#define MBEDTLS_SSL_EARLY_DATA_STATUS_REJECTED 2
#define MBEDTLS_SSL_EARLY_DATA_STATUS_NOT_SENT 1
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(pre-existing, minor) feels like this should be an enum

* one CCS per handshake without having to complicate the handshake state
* transitions.
*/
uint8_t ccs_count;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with Manuel, but minor, can be done in a follow-up PR


#if defined(MBEDTLS_SSL_TLS1_3_COMPATIBILITY_MODE)
/**
* Number of dummy change_cipher_spec (CCS) record sent. Used to send only
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(minor, fix in follow-up) should be plural records sent. Also, there seem to be two spaces after the * on each line :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comment changed in #8760

* ClientHello, the server has accepted them and the client has received the
* server Finished message. It cannot send early data to the server anymore.
*/
#define MBEDTLS_SSL_EARLY_DATA_STATUS_SERVER_FINISHED_RECEIVED 6
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(for follow-up) If these are all possible values of early_data_status i.e. return values from mbedtls_ssl_get_early_data_status() could they be defined together, ideally in an enum?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mbedtls_ssl_get_early_data_status() returns only NOT_SENT or ACCEPTED or REJECTED. The other values are for internal use only. See also #8755 (comment).

@@ -2145,6 +2145,38 @@ int mbedtls_ssl_tls13_write_early_data_ext(mbedtls_ssl_context *ssl,
unsigned char *buf,
const unsigned char *end,
size_t *out_len);

#if defined(MBEDTLS_SSL_CLI_C)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(minor) I'd prefer to see them defined in one place, even if values are defined that aren't used under some circumstances - they are well-enough namespaced

mbedtls_test_handshake_test_options *client_options,
mbedtls_test_handshake_test_options *server_options,
mbedtls_ssl_session *session);
#endif /* MBEDTLS_SSL_CLI_C && MBEDTLS_SSL_SRV_C &&
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(minor) we don't really need the list of conditions in the #endif since it's so close to the #if - it clutters the text, and if the condition needs changing in the future it's an unnecessary thing to have to keep in sync

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in #8760, commit "tls13: Fix/Improve comments"

TEST_EQUAL(client_ep.ssl.early_data_status,
MBEDTLS_SSL_EARLY_DATA_STATUS_REJECTED);
}
break;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we should have default: TEST_FAIL("Missing scenario"); in these in case we extend the set of scenarios and forget to update one of the switches in the future?

Copy link
Contributor Author

@ronald-cron-arm ronald-cron-arm Feb 15, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes that should reduce the risk of missing something when adding a scenario. Done in #8760, last commit.

@mpg mpg added this pull request to the merge queue Feb 13, 2024
@tom-cosgrove-arm
Copy link
Contributor

Thank you @mpg!

Merged via the queue into Mbed-TLS:development with commit e6c80bc Feb 13, 2024
6 checks passed
@ronald-cron-arm
Copy link
Contributor Author

ronald-cron-arm commented Feb 15, 2024

@mpg and @tom-cosgrove-arm thanks for the review.

I have addressed your comments in five additional commits in #8760 (thanks for its rebase). Regarding the definition of MBEDTLS_SSL_EARLY_DATA_STATUS_xyz (various comments about it) I've tried to improve things (penultimate commit). MBEDTLS_SSL_EARLY_DATA_STATUS_NOT_SENT/ACCEPTED/REJECTED documentation is still in the documentation of mbedtls_ssl_get_early_data_status() as they are the possible values (apart from errors) returned by this API function. MBEDTLS_SSL_EARLY_DATA_STATUS_NOT_SENT/ACCEPTED/REJECTED are now defined in the mbedtls_ssl_early_data_status enum along with the other values that are for internal use only. The enum itself is also for internal use only.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
component-tls13 enhancement needs-review Every commit must be reviewed by at least two team members, priority-high High priority - will be reviewed soon
Projects
No open projects
Development

Successfully merging this pull request may close these issues.

TLS 1.3 client: Add support for early data writing
3 participants