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

Refactor TLS 1.3 cipher selection and fix SSL_get_ciphers #2092

Open
wants to merge 38 commits into
base: main
Choose a base branch
from

Conversation

smittals2
Copy link
Contributor

@smittals2 smittals2 commented Jan 2, 2025

Issues:

CryptoAlg-2559

Description of changes:

  1. SSL_CTX_new now configures ctx->tls13_cipher_suites with default TLS 1.3 ciphers (did not previously). The default preference order for TLS 1.3 ciphersuites differs based on whether AES Hardware acceleration is enabled in AWS-LC, we match this behavior in SSL_CTX_new.
  2. The SSL_CONFIG object holds it's own TLS 1.3 ciphersuites now
  3. Server side and client side cipher selection logic is modified to account for the new field in SSL_CONFIG
  4. Each time a cipher list is configured either on SSL_CTX or SSL_CONFIG, the main cipher_list is updated with values from its own tls13_cipher_suites via a new function update_cipher_list. This function also updates in_group_flags accordingly. This means, TLS 1.3 ciphersuites are stored seperately while the main cipher_list var holds ALL ciphersuites in both objects
  5. Outdated comments were updated

Call-outs:

Note SSL_CTX generally has a longer lifetime than an SSL object. SSL_CONFIG objects live on SSL objects. Both SSL_CTX and SSL_CONFIG have their own cipher_list and tls13_cipher_list fields. We support SSL_[CTX]_set_... APIs to set these fields.

In general, our TLS implementations pick cipher suites against the given connection constraints/parameters. Adding TLS 1.3 ciphersuites to ctx->cipher_list or config->cipher_list does not modify this behavior or introduce new problems.

Testing:

Added new testing to validate cipher selection behavior between SSL_CTX and SSL_CONFIG objects
Added change detection test for TLS 1.3 Client Hello
Updated old tests and to-do's regarding TLS 1.3
Testing to ensure SSL_get_ciphers returns ALL ciphersuites instead of TLS 1.2 and below.

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license and the ISC license.

@smittals2 smittals2 changed the title [DRAFT] Fix SSL_get_ciphers behavior to return TLS 1.3 ciphersuites Fix SSL_get_ciphers behavior to return TLS 1.3 ciphersuites Jan 2, 2025
@smittals2 smittals2 marked this pull request as ready for review January 2, 2025 23:55
@smittals2 smittals2 requested a review from a team as a code owner January 2, 2025 23:55
justsmth
justsmth previously approved these changes Jan 6, 2025
@codecov-commenter
Copy link

codecov-commenter commented Jan 6, 2025

Codecov Report

Attention: Patch coverage is 93.33333% with 9 lines in your changes missing coverage. Please review.

Project coverage is 78.98%. Comparing base (29be983) to head (2c6d018).
Report is 2 commits behind head on main.

Files with missing lines Patch % Lines
ssl/ssl_cipher.cc 88.09% 5 Missing ⚠️
ssl/ssl_lib.cc 93.93% 2 Missing ⚠️
ssl/ssl_test.cc 95.91% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2092      +/-   ##
==========================================
+ Coverage   78.95%   78.98%   +0.03%     
==========================================
  Files         610      610              
  Lines      105293   105381      +88     
  Branches    14911    14937      +26     
==========================================
+ Hits        83129    83231     +102     
+ Misses      21511    21499      -12     
+ Partials      653      651       -2     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@smittals2 smittals2 requested a review from justsmth January 6, 2025 20:48
include/openssl/ssl.h Outdated Show resolved Hide resolved
include/openssl/ssl.h Outdated Show resolved Hide resolved
ssl/ssl_lib.cc Show resolved Hide resolved
ssl/ssl_cipher.cc Outdated Show resolved Hide resolved
ssl/ssl_cipher.cc Show resolved Hide resolved
ssl/ssl_cipher.cc Outdated Show resolved Hide resolved
ssl/handshake_client.cc Outdated Show resolved Hide resolved
include/openssl/ssl.h Outdated Show resolved Hide resolved
ssl/ssl_cipher.cc Outdated Show resolved Hide resolved
@smittals2 smittals2 changed the title Fix SSL_get_ciphers behavior to return TLS 1.3 ciphersuites Refactor TLS 1.3 cipher selection and fix SSL_get_ciphers Jan 23, 2025
Comment on lines +1693 to +1695
// Note: TLS 1.3 ciphersuites are only configurable via
// |SSL_CTX_set_ciphersuites| or |SSL_set_ciphersuites|. Other setter functions have
// no impact on TLS 1.3 ciphersuites.
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we have tests that attempt to set 1.3 ciphers and ensure they are rejected?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Do you mean use the TLS 1.2 setter functions to set TLS 1.3 ciphers? If so yes you get a no cipher match error.

ssl/handshake_client.cc Show resolved Hide resolved
Comment on lines +280 to 284

if (!collect_cipher_protocol_ids(ciphers, &child, mask_k,
mask_a, hs->max_version, hs->min_version, &any_enabled)) {
return false;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Why are you filtering the TLS 1.3 ciphers again here? From line 276 we already know we want 1.3 ciphers and tls13_cipher_list only has 1.3 ciphers in it.

Copy link
Contributor

Choose a reason for hiding this comment

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

Actually can these two blocks be combined into a single flow:

  1. Call SSL_get_ciphers to get all 1.2 and 1.3 ciphers
  2. Filter that based on min/max
  3. Write that to the CBB

Copy link
Contributor Author

@smittals2 smittals2 Jan 24, 2025

Choose a reason for hiding this comment

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

Cannot combine the two blocks. Different cases for ECH (discussed offline)

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 you can't combine the two blocks into one shared block, but I'm still curious about the filtering, can this just use ciphers from up above which only includes 1.3 ciphers?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Are you saying use the same SSL_get_ciphers call below as well?

The reason we can't do this is if you are a ECH ClientHelloInner, and you support TLS versions less than 1.3, by RFC we still only send TLS 1.3 ciphersuites. Since collect_ciphers takes min max version from the handshake, using the above ciphers var would erroneously pull in TLS 1.2 and below ciphersuites. Therefore, we specifically pass in only the tls13_ciphersuites in the else block

Comment on lines +266 to 268
if (!collect_cipher_protocol_ids(SSL_get_ciphers(ssl), &child, mask_k,
mask_a, hs->max_version, hs->min_version, &any_enabled)) {
return false;
Copy link
Contributor

Choose a reason for hiding this comment

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

Double checking my understanding: this is in an if/else block so only hs->min_version < TLS1_3_VERSION or hs->max_version >= TLS1_3_VERSION will run. If min is less than 1.3 we want to add both, and SSL_get_ciphers returns both?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes if min is less than 1.3, we want to add min to max (where max could also be anything). We pass this in to collect_cipher_protocol_ids.

SSL_get_ciphers will return the SSL level (if configured) and otherwise SSL_CTX main cipher list which now holds all ciphersuites.

@@ -1690,10 +1690,9 @@ OPENSSL_EXPORT size_t SSL_get_all_standard_cipher_names(const char **out,
// Once an equal-preference group is used, future directives must be
Copy link
Contributor

Choose a reason for hiding this comment

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

Please update SSL_get_ciphers documentation to note it returns all ciphers 1.2 and 1.3

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The current documentation covers this case ("cipher list for |ssl|") but I'll make it more explicit. We just weren't living up to this contract initially.

ssl/ssl_cipher.cc Outdated Show resolved Hide resolved
}
std::fill(updated_in_group_flags.begin(), updated_in_group_flags.end(), false);

// Copy in_group_flags from |ctx->tls13_cipher_list|
Copy link
Contributor

Choose a reason for hiding this comment

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

What does in_group_flags do?

Copy link
Contributor Author

@smittals2 smittals2 Jan 24, 2025

Choose a reason for hiding this comment

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

Comment on lines +1289 to +1293
// Ensure value of last element in |in_group_flags| is 0. The last cipher
// in a list must be the end of any group in that list.
if (tls13_flags[num_added_tls13_ciphers - 1] != 0) {
tls13_flags[num_added_tls13_ciphers - 1] = false;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Should this fail here instead? If this happens does that mean something happened up above and the wrong number of things got added?

Copy link
Contributor

Choose a reason for hiding this comment

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

Can a group include a 1.3 and 1.2 cipher suite?

Copy link
Contributor Author

@smittals2 smittals2 Jan 24, 2025

Choose a reason for hiding this comment

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

No, you can only group ciphersuites within the same TLS version

Comment on lines +2190 to +2196
if (!ssl_create_cipher_list(&ctx->cipher_list, has_aes_hw, str,
false /* not strict */,
false /* don't configure TLSv1.3 ciphers */);
false /* don't configure TLSv1.3 ciphers */)) {
return 0;
}

return update_cipher_list(ctx->cipher_list, ctx->cipher_list, ctx->tls13_cipher_list);
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we just pass the 1.3 ciphers to ssl_create_cipher_list and have it put them at the beginning automatically?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The same ssl_create_cipher_list function is used to create tls13_cipher_lists and the main cipher_list. Therefore, I have chosen to do update's separately to properly distinguish what is being set.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants