diff options
Diffstat (limited to 'ssl/statem/extensions_srvr.c')
-rw-r--r-- | ssl/statem/extensions_srvr.c | 882 |
1 files changed, 691 insertions, 191 deletions
diff --git a/ssl/statem/extensions_srvr.c b/ssl/statem/extensions_srvr.c index 72c00574be68..1a09913ad63f 100644 --- a/ssl/statem/extensions_srvr.c +++ b/ssl/statem/extensions_srvr.c @@ -1,5 +1,5 @@ /* - * Copyright 2016-2024 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2016-2025 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -11,6 +11,7 @@ #include "../ssl_local.h" #include "statem_local.h" #include "internal/cryptlib.h" +#include "internal/ssl_unwrap.h" #define COOKIE_STATE_FORMAT_VERSION 1 @@ -38,11 +39,13 @@ /* * Parse the client's renegotiation binding and abort if it's not right */ -int tls_parse_ctos_renegotiate(SSL *s, PACKET *pkt, unsigned int context, +int tls_parse_ctos_renegotiate(SSL_CONNECTION *s, PACKET *pkt, + unsigned int context, X509 *x, size_t chainidx) { unsigned int ilen; const unsigned char *data; + int ok; /* Parse the length byte */ if (!PACKET_get_1(pkt, &ilen) @@ -57,8 +60,16 @@ int tls_parse_ctos_renegotiate(SSL *s, PACKET *pkt, unsigned int context, return 0; } - if (memcmp(data, s->s3.previous_client_finished, - s->s3.previous_client_finished_len)) { + ok = memcmp(data, s->s3.previous_client_finished, + s->s3.previous_client_finished_len); +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + if (ok) { + if ((data[0] ^ s->s3.previous_client_finished[0]) != 0xFF) { + ok = 0; + } + } +#endif + if (ok) { SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE, SSL_R_RENEGOTIATION_MISMATCH); return 0; } @@ -91,8 +102,8 @@ int tls_parse_ctos_renegotiate(SSL *s, PACKET *pkt, unsigned int context, * extension. * - On session reconnect, the servername extension may be absent. */ -int tls_parse_ctos_server_name(SSL *s, PACKET *pkt, unsigned int context, - X509 *x, size_t chainidx) +int tls_parse_ctos_server_name(SSL_CONNECTION *s, PACKET *pkt, + unsigned int context, X509 *x, size_t chainidx) { unsigned int servname_type; PACKET sni, hostname; @@ -126,7 +137,7 @@ int tls_parse_ctos_server_name(SSL *s, PACKET *pkt, unsigned int context, * In TLSv1.2 and below the SNI is associated with the session. In TLSv1.3 * we always use the SNI value from the handshake. */ - if (!s->hit || SSL_IS_TLS13(s)) { + if (!s->hit || SSL_CONNECTION_IS_TLS13(s)) { if (PACKET_remaining(&hostname) > TLSEXT_MAXLEN_host_name) { SSLfatal(s, SSL_AD_UNRECOGNIZED_NAME, SSL_R_BAD_EXTENSION); return 0; @@ -163,7 +174,8 @@ int tls_parse_ctos_server_name(SSL *s, PACKET *pkt, unsigned int context, return 1; } -int tls_parse_ctos_maxfragmentlen(SSL *s, PACKET *pkt, unsigned int context, +int tls_parse_ctos_maxfragmentlen(SSL_CONNECTION *s, PACKET *pkt, + unsigned int context, X509 *x, size_t chainidx) { unsigned int value; @@ -205,8 +217,8 @@ int tls_parse_ctos_maxfragmentlen(SSL *s, PACKET *pkt, unsigned int context, } #ifndef OPENSSL_NO_SRP -int tls_parse_ctos_srp(SSL *s, PACKET *pkt, unsigned int context, X509 *x, - size_t chainidx) +int tls_parse_ctos_srp(SSL_CONNECTION *s, PACKET *pkt, unsigned int context, + X509 *x, size_t chainidx) { PACKET srp_I; @@ -225,7 +237,8 @@ int tls_parse_ctos_srp(SSL *s, PACKET *pkt, unsigned int context, X509 *x, } #endif -int tls_parse_ctos_ec_pt_formats(SSL *s, PACKET *pkt, unsigned int context, +int tls_parse_ctos_ec_pt_formats(SSL_CONNECTION *s, PACKET *pkt, + unsigned int context, X509 *x, size_t chainidx) { PACKET ec_point_format_list; @@ -248,13 +261,14 @@ int tls_parse_ctos_ec_pt_formats(SSL *s, PACKET *pkt, unsigned int context, return 1; } -int tls_parse_ctos_session_ticket(SSL *s, PACKET *pkt, unsigned int context, +int tls_parse_ctos_session_ticket(SSL_CONNECTION *s, PACKET *pkt, + unsigned int context, X509 *x, size_t chainidx) { if (s->ext.session_ticket_cb && - !s->ext.session_ticket_cb(s, PACKET_data(pkt), - PACKET_remaining(pkt), - s->ext.session_ticket_cb_arg)) { + !s->ext.session_ticket_cb(SSL_CONNECTION_GET_USER_SSL(s), + PACKET_data(pkt), PACKET_remaining(pkt), + s->ext.session_ticket_cb_arg)) { SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); return 0; } @@ -262,7 +276,7 @@ int tls_parse_ctos_session_ticket(SSL *s, PACKET *pkt, unsigned int context, return 1; } -int tls_parse_ctos_sig_algs_cert(SSL *s, PACKET *pkt, +int tls_parse_ctos_sig_algs_cert(SSL_CONNECTION *s, PACKET *pkt, ossl_unused unsigned int context, ossl_unused X509 *x, ossl_unused size_t chainidx) @@ -275,7 +289,13 @@ int tls_parse_ctos_sig_algs_cert(SSL *s, PACKET *pkt, return 0; } - if (!s->hit && !tls1_save_sigalgs(s, &supported_sig_algs, 1)) { + /* + * We use this routine on both clients and servers, and when clients + * get asked for PHA we need to always save the sigalgs regardless + * of whether it was a resumption or not. + */ + if ((!s->server || (s->server && !s->hit)) + && !tls1_save_sigalgs(s, &supported_sig_algs, 1)) { SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_R_BAD_EXTENSION); return 0; } @@ -283,8 +303,8 @@ int tls_parse_ctos_sig_algs_cert(SSL *s, PACKET *pkt, return 1; } -int tls_parse_ctos_sig_algs(SSL *s, PACKET *pkt, unsigned int context, X509 *x, - size_t chainidx) +int tls_parse_ctos_sig_algs(SSL_CONNECTION *s, PACKET *pkt, + unsigned int context, X509 *x, size_t chainidx) { PACKET supported_sig_algs; @@ -294,7 +314,13 @@ int tls_parse_ctos_sig_algs(SSL *s, PACKET *pkt, unsigned int context, X509 *x, return 0; } - if (!s->hit && !tls1_save_sigalgs(s, &supported_sig_algs, 0)) { + /* + * We use this routine on both clients and servers, and when clients + * get asked for PHA we need to always save the sigalgs regardless + * of whether it was a resumption or not. + */ + if ((!s->server || (s->server && !s->hit)) + && !tls1_save_sigalgs(s, &supported_sig_algs, 0)) { SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_R_BAD_EXTENSION); return 0; } @@ -303,7 +329,8 @@ int tls_parse_ctos_sig_algs(SSL *s, PACKET *pkt, unsigned int context, X509 *x, } #ifndef OPENSSL_NO_OCSP -int tls_parse_ctos_status_request(SSL *s, PACKET *pkt, unsigned int context, +int tls_parse_ctos_status_request(SSL_CONNECTION *s, PACKET *pkt, + unsigned int context, X509 *x, size_t chainidx) { PACKET responder_id_list, exts; @@ -342,7 +369,7 @@ int tls_parse_ctos_status_request(SSL *s, PACKET *pkt, unsigned int context, if (PACKET_remaining(&responder_id_list) > 0) { s->ext.ocsp.ids = sk_OCSP_RESPID_new_null(); if (s->ext.ocsp.ids == NULL) { - SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_MALLOC_FAILURE); + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_CRYPTO_LIB); return 0; } } else { @@ -407,8 +434,8 @@ int tls_parse_ctos_status_request(SSL *s, PACKET *pkt, unsigned int context, #endif #ifndef OPENSSL_NO_NEXTPROTONEG -int tls_parse_ctos_npn(SSL *s, PACKET *pkt, unsigned int context, X509 *x, - size_t chainidx) +int tls_parse_ctos_npn(SSL_CONNECTION *s, PACKET *pkt, unsigned int context, + X509 *x, size_t chainidx) { /* * We shouldn't accept this extension on a @@ -425,8 +452,8 @@ int tls_parse_ctos_npn(SSL *s, PACKET *pkt, unsigned int context, X509 *x, * Save the ALPN extension in a ClientHello.|pkt| holds the contents of the ALPN * extension, not including type and length. Returns: 1 on success, 0 on error. */ -int tls_parse_ctos_alpn(SSL *s, PACKET *pkt, unsigned int context, X509 *x, - size_t chainidx) +int tls_parse_ctos_alpn(SSL_CONNECTION *s, PACKET *pkt, unsigned int context, + X509 *x, size_t chainidx) { PACKET protocol_list, save_protocol_list, protocol; @@ -462,16 +489,17 @@ int tls_parse_ctos_alpn(SSL *s, PACKET *pkt, unsigned int context, X509 *x, } #ifndef OPENSSL_NO_SRTP -int tls_parse_ctos_use_srtp(SSL *s, PACKET *pkt, unsigned int context, X509 *x, - size_t chainidx) +int tls_parse_ctos_use_srtp(SSL_CONNECTION *s, PACKET *pkt, + unsigned int context, X509 *x, size_t chainidx) { STACK_OF(SRTP_PROTECTION_PROFILE) *srvr; unsigned int ct, mki_len, id; int i, srtp_pref; PACKET subpkt; + SSL *ssl = SSL_CONNECTION_GET_SSL(s); /* Ignore this if we have no SRTP profiles */ - if (SSL_get_srtp_profiles(s) == NULL) + if (SSL_get_srtp_profiles(ssl) == NULL) return 1; /* Pull off the length of the cipher suite list and check it is even */ @@ -482,7 +510,7 @@ int tls_parse_ctos_use_srtp(SSL *s, PACKET *pkt, unsigned int context, X509 *x, return 0; } - srvr = SSL_get_srtp_profiles(s); + srvr = SSL_get_srtp_profiles(ssl); s->srtp_profile = NULL; /* Search all profiles for a match initially */ srtp_pref = sk_SRTP_PROTECTION_PROFILE_num(srvr); @@ -529,8 +557,8 @@ int tls_parse_ctos_use_srtp(SSL *s, PACKET *pkt, unsigned int context, X509 *x, } #endif -int tls_parse_ctos_etm(SSL *s, PACKET *pkt, unsigned int context, X509 *x, - size_t chainidx) +int tls_parse_ctos_etm(SSL_CONNECTION *s, PACKET *pkt, unsigned int context, + X509 *x, size_t chainidx) { if (!(s->options & SSL_OP_NO_ENCRYPT_THEN_MAC)) s->ext.use_etm = 1; @@ -542,7 +570,8 @@ int tls_parse_ctos_etm(SSL *s, PACKET *pkt, unsigned int context, X509 *x, * Process a psk_kex_modes extension received in the ClientHello. |pkt| contains * the raw PACKET data for the extension. Returns 1 on success or 0 on failure. */ -int tls_parse_ctos_psk_kex_modes(SSL *s, PACKET *pkt, unsigned int context, +int tls_parse_ctos_psk_kex_modes(SSL_CONNECTION *s, PACKET *pkt, + unsigned int context, X509 *x, size_t chainidx) { #ifndef OPENSSL_NO_TLS1_3 @@ -562,25 +591,258 @@ int tls_parse_ctos_psk_kex_modes(SSL *s, PACKET *pkt, unsigned int context, && (s->options & SSL_OP_ALLOW_NO_DHE_KEX) != 0) s->ext.psk_kex_mode |= TLSEXT_KEX_MODE_FLAG_KE; } + + if (((s->ext.psk_kex_mode & TLSEXT_KEX_MODE_FLAG_KE) != 0) + && (s->options & SSL_OP_PREFER_NO_DHE_KEX) != 0) { + + /* + * If NO_DHE is supported and preferred, then we only remember this + * mode. DHE PSK will not be used for sure, because in any case where + * it would be supported (i.e. if a key share is present), NO_DHE would + * be supported as well. As the latter is preferred it would be + * chosen. By removing DHE PSK here, we don't have to deal with the + * SSL_OP_PREFER_NO_DHE_KEX option in any other place. + */ + s->ext.psk_kex_mode = TLSEXT_KEX_MODE_FLAG_KE; + } + #endif return 1; } /* - * Process a key_share extension received in the ClientHello. |pkt| contains - * the raw PACKET data for the extension. Returns 1 on success or 0 on failure. + * Use function tls_parse_ctos_key_share with helper functions extract_keyshares, + * check_overlap and tls_accept_ksgroup to parse the key_share extension(s) + * received in the ClientHello and to select the group used of the key exchange */ -int tls_parse_ctos_key_share(SSL *s, PACKET *pkt, unsigned int context, X509 *x, - size_t chainidx) + +#ifndef OPENSSL_NO_TLS1_3 +/* + * Accept a key share group by setting the related variables in s->s3 and + * by generating a pubkey for this group + */ +static int tls_accept_ksgroup(SSL_CONNECTION *s, uint16_t ksgroup, PACKET *encoded_pubkey) +{ + /* Accept the key share group */ + s->s3.group_id = ksgroup; + s->s3.group_id_candidate = ksgroup; + /* Cache the selected group ID in the SSL_SESSION */ + s->session->kex_group = ksgroup; + if ((s->s3.peer_tmp = ssl_generate_param_group(s, ksgroup)) == NULL) { + SSLfatal(s, + SSL_AD_INTERNAL_ERROR, + SSL_R_UNABLE_TO_FIND_ECDH_PARAMETERS); + return 0; + } + if (tls13_set_encoded_pub_key(s->s3.peer_tmp, + PACKET_data(encoded_pubkey), + PACKET_remaining(encoded_pubkey)) <= 0) { + SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_R_BAD_ECPOINT); + return 0; + } + return 1; +} + +# define GROUPLIST_INCREMENT 32 /* Memory allocation chunk size (nominally 64 Bytes chunks) */ + +typedef enum KS_EXTRACTION_RESULT { + EXTRACTION_FAILURE, + EXTRACTION_SUCCESS, + EXTRACTION_SUCCESS_HRR +} KS_EXTRACTION_RESULT; + +static KS_EXTRACTION_RESULT extract_keyshares(SSL_CONNECTION *s, PACKET *key_share_list, + const uint16_t *clntgroups, size_t clnt_num_groups, + const uint16_t *srvrgroups, size_t srvr_num_groups, + uint16_t **keyshares_arr, PACKET **encoded_pubkey_arr, + size_t *keyshares_cnt, size_t *keyshares_max) { + PACKET encoded_pubkey; + size_t key_share_pos = 0; + size_t previous_key_share_pos = 0; + unsigned int group_id = 0; + + /* Prepare memory to hold the extracted key share groups and related pubkeys */ + *keyshares_arr = OPENSSL_malloc(*keyshares_max * sizeof(**keyshares_arr)); + if (*keyshares_arr == NULL) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + goto failure; + } + *encoded_pubkey_arr = OPENSSL_malloc(*keyshares_max * sizeof(**encoded_pubkey_arr)); + if (*encoded_pubkey_arr == NULL) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + goto failure; + } + + while (PACKET_remaining(key_share_list) > 0) { + /* Get the group_id for the current share and its encoded_pubkey */ + if (!PACKET_get_net_2(key_share_list, &group_id) + || !PACKET_get_length_prefixed_2(key_share_list, &encoded_pubkey) + || PACKET_remaining(&encoded_pubkey) == 0) { + SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_R_LENGTH_MISMATCH); + goto failure; + } + + /* + * If we sent an HRR then the key_share sent back MUST be for the group + * we requested, and must be the only key_share sent. + */ + if (s->s3.group_id != 0 + && (group_id != s->s3.group_id + || PACKET_remaining(key_share_list) != 0)) { + SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_R_BAD_KEY_SHARE); + goto failure; + } + + /* + * Check if this share is in supported_groups sent from client + * RFC 8446 also mandates that clients send keyshares in the same + * order as listed in the supported groups extension, but its not + * required that the server check that, and some clients violate this + * so instead of failing the connection when that occurs, log a trace + * message indicating the client discrepancy. + */ + if (!check_in_list(s, group_id, clntgroups, clnt_num_groups, 0, &key_share_pos)) { + SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_R_BAD_KEY_SHARE); + goto failure; + } + + if (key_share_pos < previous_key_share_pos) + OSSL_TRACE1(TLS, "key share group id %d is out of RFC 8446 order\n", group_id); + + previous_key_share_pos = key_share_pos; + + if (s->s3.group_id != 0) { + /* + * We have sent a HRR, and the key share we got back is + * the one we expected and is the only key share and is + * in the list of supported_groups (checked + * above already), hence we accept this key share group + */ + if (!tls_accept_ksgroup(s, s->s3.group_id, &encoded_pubkey)) + goto failure; /* SSLfatal already called */ + /* We have selected a key share group via HRR, hence we're done here */ + return EXTRACTION_SUCCESS_HRR; + } + + /* + * We tolerate but ignore a group id that we don't think is + * suitable for TLSv1.3 or which is not supported by the server + */ + if (!check_in_list(s, group_id, srvrgroups, srvr_num_groups, 1, NULL) + || !tls_group_allowed(s, group_id, SSL_SECOP_CURVE_SUPPORTED) + || !tls_valid_group(s, group_id, TLS1_3_VERSION, TLS1_3_VERSION, + 0, NULL)) { + /* Share not suitable or not supported, check next share */ + continue; + } + + /* Memorize this key share group ID and its encoded point */ + (*keyshares_arr)[*keyshares_cnt] = group_id; + (*encoded_pubkey_arr)[(*keyshares_cnt)++] = encoded_pubkey; + + /* + * Memory management (remark: While limiting the client to only allow + * a maximum of OPENSSL_CLIENT_MAX_KEY_SHARES to be sent, the server can + * handle any number of key shares) + */ + if (*keyshares_cnt == *keyshares_max) { + PACKET *tmp_pkt; + uint16_t *tmp = + OPENSSL_realloc(*keyshares_arr, + (*keyshares_max + GROUPLIST_INCREMENT) * sizeof(**keyshares_arr)); + + if (tmp == NULL) + goto failure; + *keyshares_arr = tmp; + tmp_pkt = + OPENSSL_realloc(*encoded_pubkey_arr, + (*keyshares_max + GROUPLIST_INCREMENT) * + sizeof(**encoded_pubkey_arr)); + if (tmp_pkt == NULL) + goto failure; + *encoded_pubkey_arr = tmp_pkt; + *keyshares_max += GROUPLIST_INCREMENT; + } + + } + + return EXTRACTION_SUCCESS; + +failure: + /* Fatal error -> free any allocated memory and return 0 */ + OPENSSL_free(*keyshares_arr); + OPENSSL_free(*encoded_pubkey_arr); + return EXTRACTION_FAILURE; +} +#endif + +/* + * For each group in the priority list of groups, check if that group is + * also present in the secondary list; if so, select the first overlap and + * assign to selected_group and also set the related index in the candidate group list, + * or set selected_group to 0 if no overlap + */ #ifndef OPENSSL_NO_TLS1_3 - unsigned int group_id; - PACKET key_share_list, encoded_pt; - const uint16_t *clntgroups, *srvrgroups; - size_t clnt_num_groups, srvr_num_groups; - int found = 0; +static void check_overlap(SSL_CONNECTION *s, + const uint16_t *prio_groups, size_t prio_num_groups, + const uint16_t *candidate_groups, size_t candidate_num_groups, + int *prio_group_idx, int *candidate_group_idx, + uint16_t *selected_group) +{ + uint16_t current_group; + size_t group_idx = prio_num_groups; + size_t new_group_idx = 0; + + *candidate_group_idx = 0; + *prio_group_idx = 0; + *selected_group = 0; + + for (current_group = 0; current_group < candidate_num_groups; current_group++) { + if (!check_in_list(s, candidate_groups[current_group], prio_groups, + prio_num_groups, 1, &new_group_idx) + || !tls_group_allowed(s, candidate_groups[current_group], + SSL_SECOP_CURVE_SUPPORTED) + || !tls_valid_group(s, candidate_groups[current_group], TLS1_3_VERSION, + TLS1_3_VERSION, 0, NULL)) + /* No overlap or group not suitable, check next group */ + continue; + /* + * is the found new_group_idx earlier in the priority list than + * initial or last group_idx? + */ + if (new_group_idx < group_idx) { + group_idx = new_group_idx; + *candidate_group_idx = current_group; + *prio_group_idx = group_idx; + *selected_group = prio_groups[group_idx]; + } + } +} +#endif + +int tls_parse_ctos_key_share(SSL_CONNECTION *s, PACKET *pkt, + unsigned int context, X509 *x, size_t chainidx) +{ +#ifndef OPENSSL_NO_TLS1_3 + PACKET key_share_list; + const uint16_t *clntgroups, *srvrgroups; + const size_t *srvrtuples; + uint16_t *first_group_in_tuple; + size_t clnt_num_groups, srvr_num_groups, srvr_num_tuples; + PACKET *encoded_pubkey_arr = NULL; + uint16_t *keyshares_arr = NULL; + size_t keyshares_cnt = 0; + size_t keyshares_max = GROUPLIST_INCREMENT; + /* We conservatively assume that we did not find a suitable group */ + uint16_t group_id_candidate = 0; + KS_EXTRACTION_RESULT ks_extraction_result; + size_t current_tuple; + int ret = 0; + + s->s3.group_id_candidate = 0; if (s->hit && (s->ext.psk_kex_mode & TLSEXT_KEX_MODE_FLAG_KE_DHE) == 0) return 1; @@ -595,10 +857,12 @@ int tls_parse_ctos_key_share(SSL *s, PACKET *pkt, unsigned int context, X509 *x, return 0; } - /* Get our list of supported groups */ + /* Get list of server supported groups and the group tuples */ tls1_get_supported_groups(s, &srvrgroups, &srvr_num_groups); + tls1_get_group_tuples(s, &srvrtuples, &srvr_num_tuples); /* Get the clients list of supported groups. */ tls1_get_peer_groups(s, &clntgroups, &clnt_num_groups); + if (clnt_num_groups == 0) { /* * This can only happen if the supported_groups extension was not sent, @@ -620,77 +884,126 @@ int tls_parse_ctos_key_share(SSL *s, PACKET *pkt, unsigned int context, X509 *x, return 0; } - while (PACKET_remaining(&key_share_list) > 0) { - if (!PACKET_get_net_2(&key_share_list, &group_id) - || !PACKET_get_length_prefixed_2(&key_share_list, &encoded_pt) - || PACKET_remaining(&encoded_pt) == 0) { - SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_R_LENGTH_MISMATCH); - return 0; - } + /* We parse the key share extension and memorize the entries (after some checks) */ + ks_extraction_result = extract_keyshares(s, + &key_share_list, + clntgroups, clnt_num_groups, + srvrgroups, srvr_num_groups, + &keyshares_arr, &encoded_pubkey_arr, + &keyshares_cnt, &keyshares_max); - /* - * If we already found a suitable key_share we loop through the - * rest to verify the structure, but don't process them. - */ - if (found) - continue; + if (ks_extraction_result == EXTRACTION_FAILURE) /* Fatal error during tests */ + return 0; /* Memory already freed and SSLfatal already called */ + if (ks_extraction_result == EXTRACTION_SUCCESS_HRR) /* Successful HRR */ + goto end; - /* - * If we sent an HRR then the key_share sent back MUST be for the group - * we requested, and must be the only key_share sent. - */ - if (s->s3.group_id != 0 - && (group_id != s->s3.group_id - || PACKET_remaining(&key_share_list) != 0)) { - SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_R_BAD_KEY_SHARE); - return 0; - } - - /* Check if this share is in supported_groups sent from client */ - if (!check_in_list(s, group_id, clntgroups, clnt_num_groups, 0)) { - SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_R_BAD_KEY_SHARE); - return 0; - } - - /* Check if this share is for a group we can use */ - if (!check_in_list(s, group_id, srvrgroups, srvr_num_groups, 1) - || !tls_group_allowed(s, group_id, SSL_SECOP_CURVE_SUPPORTED) - /* - * We tolerate but ignore a group id that we don't think is - * suitable for TLSv1.3 - */ - || !tls_valid_group(s, group_id, TLS1_3_VERSION, TLS1_3_VERSION, - 0, NULL)) { - /* Share not suitable */ - continue; - } + /* + * We now have the folowing lists available to make a decision for + * which group the server should use for key exchange : + * From client: clntgroups[clnt_num_groups], + * keyshares_arr[keyshares_cnt], encoded_pubkey_arr[keyshares_cnt] + * From server: srvrgroups[srvr_num_groups], srvrtuples[srvr_num_tuples] + * + * Group selection algorithm: + * For all tuples do: + * key share group(s) overlapping with current tuple? + * --> Yes: accept group_id for SH + * --> No: is any of the client supported_groups overlapping with current tuple? + * --> Yes: memorize group_id for HRR, break + * --> No: continue to check next tuple + * + * Remark: Selection priority different for client- or server-preference + */ + first_group_in_tuple = (uint16_t *)srvrgroups; + for (current_tuple = 0; current_tuple < srvr_num_tuples; current_tuple++) { + size_t number_of_groups_in_tuple = srvrtuples[current_tuple]; + int prio_group_idx = 0, candidate_group_idx = 0; + + /* Server or client preference ? */ + if (s->options & SSL_OP_CIPHER_SERVER_PREFERENCE) { + /* Server preference */ + /* Is there overlap with a key share group? */ + check_overlap(s, + first_group_in_tuple, number_of_groups_in_tuple, + keyshares_arr, keyshares_cnt, + &prio_group_idx, &candidate_group_idx, + &group_id_candidate); + if (group_id_candidate > 0) { /* Overlap found -> accept the key share group */ + if (!tls_accept_ksgroup(s, group_id_candidate, + &encoded_pubkey_arr[candidate_group_idx])) + goto err; /* SSLfatal already called */ + /* We have all info for a SH, hence we're done here */ + goto end; + } else { + /* + * There's no overlap with a key share, but is there at least a client + * supported_group overlapping with the current tuple? + */ + check_overlap(s, + first_group_in_tuple, number_of_groups_in_tuple, + clntgroups, clnt_num_groups, + &prio_group_idx, &candidate_group_idx, + &group_id_candidate); + if (group_id_candidate > 0) { + /* + * We did not have a key share overlap, but at least the supported + * groups overlap hence we can stop searching + * (and report group_id_candidate 'upward' for HRR) + */ + s->s3.group_id_candidate = group_id_candidate; + goto end; + } else { + /* + * Neither key share nor supported_groups overlap current + * tuple, hence we try the next tuple + */ + first_group_in_tuple = &first_group_in_tuple[number_of_groups_in_tuple]; + continue; + } + } - if ((s->s3.peer_tmp = ssl_generate_param_group(s, group_id)) == NULL) { - SSLfatal(s, SSL_AD_INTERNAL_ERROR, - SSL_R_UNABLE_TO_FIND_ECDH_PARAMETERS); - return 0; + } else { /* We have client preference */ + check_overlap(s, + keyshares_arr, keyshares_cnt, + first_group_in_tuple, number_of_groups_in_tuple, + &prio_group_idx, &candidate_group_idx, + &group_id_candidate); + if (group_id_candidate > 0) { + if (!tls_accept_ksgroup(s, group_id_candidate, &encoded_pubkey_arr[prio_group_idx])) + goto err; + goto end; + } else { + check_overlap(s, + clntgroups, clnt_num_groups, + first_group_in_tuple, number_of_groups_in_tuple, + &prio_group_idx, &candidate_group_idx, + &group_id_candidate); + if (group_id_candidate > 0) { + s->s3.group_id_candidate = group_id_candidate; + goto end; + } else { + first_group_in_tuple = &first_group_in_tuple[number_of_groups_in_tuple]; + continue; + } + } } + } - s->s3.group_id = group_id; - /* Cache the selected group ID in the SSL_SESSION */ - s->session->kex_group = group_id; +end: + ret = 1; - if (tls13_set_encoded_pub_key(s->s3.peer_tmp, - PACKET_data(&encoded_pt), - PACKET_remaining(&encoded_pt)) <= 0) { - SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_R_BAD_ECPOINT); - return 0; - } +err: + OPENSSL_free(keyshares_arr); + OPENSSL_free(encoded_pubkey_arr); + return ret; - found = 1; - } #endif return 1; } -int tls_parse_ctos_cookie(SSL *s, PACKET *pkt, unsigned int context, X509 *x, - size_t chainidx) +int tls_parse_ctos_cookie(SSL_CONNECTION *s, PACKET *pkt, unsigned int context, + X509 *x, size_t chainidx) { #ifndef OPENSSL_NO_TLS1_3 unsigned int format, version, key_share, group_id; @@ -703,9 +1016,11 @@ int tls_parse_ctos_cookie(SSL *s, PACKET *pkt, unsigned int context, X509 *x, unsigned char hrr[MAX_HRR_SIZE]; size_t rawlen, hmaclen, hrrlen, ciphlen; uint64_t tm, now; + SSL *ssl = SSL_CONNECTION_GET_SSL(s); + SSL_CTX *sctx = SSL_CONNECTION_GET_CTX(s); /* Ignore any cookie if we're not set up to verify it */ - if (s->ctx->verify_stateless_cookie_cb == NULL + if (sctx->verify_stateless_cookie_cb == NULL || (s->s3.flags & TLS1_FLAGS_STATELESS) == 0) return 1; @@ -726,20 +1041,20 @@ int tls_parse_ctos_cookie(SSL *s, PACKET *pkt, unsigned int context, X509 *x, /* Verify the HMAC of the cookie */ hctx = EVP_MD_CTX_create(); - pkey = EVP_PKEY_new_raw_private_key_ex(s->ctx->libctx, "HMAC", - s->ctx->propq, + pkey = EVP_PKEY_new_raw_private_key_ex(sctx->libctx, "HMAC", + sctx->propq, s->session_ctx->ext.cookie_hmac_key, sizeof(s->session_ctx->ext.cookie_hmac_key)); if (hctx == NULL || pkey == NULL) { EVP_MD_CTX_free(hctx); EVP_PKEY_free(pkey); - SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_MALLOC_FAILURE); + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_EVP_LIB); return 0; } hmaclen = SHA256_DIGEST_LENGTH; - if (EVP_DigestSignInit_ex(hctx, NULL, "SHA2-256", s->ctx->libctx, - s->ctx->propq, pkey, NULL) <= 0 + if (EVP_DigestSignInit_ex(hctx, NULL, "SHA2-256", sctx->libctx, + sctx->propq, pkey, NULL) <= 0 || EVP_DigestSign(hctx, hmac, &hmaclen, data, rawlen - SHA256_DIGEST_LENGTH) <= 0 || hmaclen != SHA256_DIGEST_LENGTH) { @@ -819,8 +1134,9 @@ int tls_parse_ctos_cookie(SSL *s, PACKET *pkt, unsigned int context, X509 *x, } /* Verify the app cookie */ - if (s->ctx->verify_stateless_cookie_cb(s, PACKET_data(&appcookie), - PACKET_remaining(&appcookie)) == 0) { + if (sctx->verify_stateless_cookie_cb(SSL_CONNECTION_GET_USER_SSL(s), + PACKET_data(&appcookie), + PACKET_remaining(&appcookie)) == 0) { SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_R_COOKIE_MISMATCH); return 0; } @@ -840,8 +1156,8 @@ int tls_parse_ctos_cookie(SSL *s, PACKET *pkt, unsigned int context, X509 *x, || !WPACKET_memcpy(&hrrpkt, hrrrandom, SSL3_RANDOM_SIZE) || !WPACKET_sub_memcpy_u8(&hrrpkt, s->tmp_session_id, s->tmp_session_id_len) - || !s->method->put_cipher_by_char(s->s3.tmp.new_cipher, &hrrpkt, - &ciphlen) + || !ssl->method->put_cipher_by_char(s->s3.tmp.new_cipher, &hrrpkt, + &ciphlen) || !WPACKET_put_bytes_u8(&hrrpkt, 0) || !WPACKET_start_sub_packet_u16(&hrrpkt)) { WPACKET_cleanup(&hrrpkt); @@ -896,7 +1212,8 @@ int tls_parse_ctos_cookie(SSL *s, PACKET *pkt, unsigned int context, X509 *x, return 1; } -int tls_parse_ctos_supported_groups(SSL *s, PACKET *pkt, unsigned int context, +int tls_parse_ctos_supported_groups(SSL_CONNECTION *s, PACKET *pkt, + unsigned int context, X509 *x, size_t chainidx) { PACKET supported_groups_list; @@ -909,7 +1226,7 @@ int tls_parse_ctos_supported_groups(SSL *s, PACKET *pkt, unsigned int context, return 0; } - if (!s->hit || SSL_IS_TLS13(s)) { + if (!s->hit || SSL_CONNECTION_IS_TLS13(s)) { OPENSSL_free(s->ext.peer_supportedgroups); s->ext.peer_supportedgroups = NULL; s->ext.peer_supportedgroups_len = 0; @@ -924,8 +1241,8 @@ int tls_parse_ctos_supported_groups(SSL *s, PACKET *pkt, unsigned int context, return 1; } -int tls_parse_ctos_ems(SSL *s, PACKET *pkt, unsigned int context, X509 *x, - size_t chainidx) +int tls_parse_ctos_ems(SSL_CONNECTION *s, PACKET *pkt, unsigned int context, + X509 *x, size_t chainidx) { /* The extension must always be empty */ if (PACKET_remaining(pkt) != 0) { @@ -942,7 +1259,7 @@ int tls_parse_ctos_ems(SSL *s, PACKET *pkt, unsigned int context, X509 *x, } -int tls_parse_ctos_early_data(SSL *s, PACKET *pkt, unsigned int context, +int tls_parse_ctos_early_data(SSL_CONNECTION *s, PACKET *pkt, unsigned int context, X509 *x, size_t chainidx) { if (PACKET_remaining(pkt) != 0) { @@ -958,7 +1275,7 @@ int tls_parse_ctos_early_data(SSL *s, PACKET *pkt, unsigned int context, return 1; } -static SSL_TICKET_STATUS tls_get_stateful_ticket(SSL *s, PACKET *tick, +static SSL_TICKET_STATUS tls_get_stateful_ticket(SSL_CONNECTION *s, PACKET *tick, SSL_SESSION **sess) { SSL_SESSION *tmpsess = NULL; @@ -986,14 +1303,17 @@ static SSL_TICKET_STATUS tls_get_stateful_ticket(SSL *s, PACKET *tick, return SSL_TICKET_SUCCESS; } -int tls_parse_ctos_psk(SSL *s, PACKET *pkt, unsigned int context, X509 *x, - size_t chainidx) +int tls_parse_ctos_psk(SSL_CONNECTION *s, PACKET *pkt, unsigned int context, + X509 *x, size_t chainidx) { PACKET identities, binders, binder; - size_t binderoffset, hashsize; + size_t binderoffset; + int hashsize; SSL_SESSION *sess = NULL; unsigned int id, i, ext = 0; const EVP_MD *md = NULL; + SSL_CTX *sctx = SSL_CONNECTION_GET_CTX(s); + SSL *ussl = SSL_CONNECTION_GET_USER_SSL(s); /* * If we have no PSK kex mode that we recognise then we can't resume so @@ -1022,14 +1342,14 @@ int tls_parse_ctos_psk(SSL *s, PACKET *pkt, unsigned int context, X509 *x, idlen = PACKET_remaining(&identity); if (s->psk_find_session_cb != NULL - && !s->psk_find_session_cb(s, PACKET_data(&identity), idlen, + && !s->psk_find_session_cb(ussl, PACKET_data(&identity), idlen, &sess)) { SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_R_BAD_EXTENSION); return 0; } #ifndef OPENSSL_NO_PSK - if(sess == NULL + if (sess == NULL && s->psk_server_callback != NULL && idlen <= PSK_MAX_IDENTITY_LEN) { char *pskid = NULL; @@ -1040,7 +1360,7 @@ int tls_parse_ctos_psk(SSL *s, PACKET *pkt, unsigned int context, X509 *x, SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); return 0; } - pskdatalen = s->psk_server_callback(s, pskid, pskdata, + pskdatalen = s->psk_server_callback(ussl, pskid, pskdata, sizeof(pskdata)); OPENSSL_free(pskid); if (pskdatalen > PSK_MAX_PSK_LEN) { @@ -1054,7 +1374,8 @@ int tls_parse_ctos_psk(SSL *s, PACKET *pkt, unsigned int context, X509 *x, * We found a PSK using an old style callback. We don't know * the digest so we default to SHA256 as per the TLSv1.3 spec */ - cipher = SSL_CIPHER_find(s, tls13_aes128gcmsha256_id); + cipher = SSL_CIPHER_find(SSL_CONNECTION_GET_SSL(s), + tls13_aes128gcmsha256_id); if (cipher == NULL) { OPENSSL_cleanse(pskdata, pskdatalen); SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); @@ -1099,7 +1420,7 @@ int tls_parse_ctos_psk(SSL *s, PACKET *pkt, unsigned int context, X509 *x, s->ext.early_data_ok = 1; s->ext.ticket_expected = 1; } else { - uint32_t ticket_age = 0, agesec, agems; + OSSL_TIME t, age, expire; int ret; /* @@ -1138,24 +1459,26 @@ int tls_parse_ctos_psk(SSL *s, PACKET *pkt, unsigned int context, X509 *x, continue; } - ticket_age = (uint32_t)ticket_agel; - agesec = (uint32_t)(time(NULL) - sess->time); - agems = agesec * (uint32_t)1000; - ticket_age -= sess->ext.tick_age_add; + age = ossl_time_subtract(ossl_ms2time(ticket_agel), + ossl_ms2time(sess->ext.tick_age_add)); + t = ossl_time_subtract(ossl_time_now(), sess->time); /* - * For simplicity we do our age calculations in seconds. If the - * client does it in ms then it could appear that their ticket age - * is longer than ours (our ticket age calculation should always be - * slightly longer than the client's due to the network latency). - * Therefore we add 1000ms to our age calculation to adjust for - * rounding errors. + * Although internally we use OSS_TIME which has ns granularity, + * when SSL_SESSION structures are serialised/deserialised we use + * second granularity for the sess->time field. Therefore it could + * appear that the client's ticket age is longer than ours (our + * ticket age calculation should always be slightly longer than the + * client's due to the network latency). Therefore we add 1000ms to + * our age calculation to adjust for rounding errors. */ + expire = ossl_time_add(t, ossl_ms2time(1000)); + if (id == 0 - && sess->timeout >= (long)agesec - && agems / (uint32_t)1000 == agesec - && ticket_age <= agems + 1000 - && ticket_age + TICKET_AGE_ALLOWANCE >= agems + 1000) { + && ossl_time_compare(sess->timeout, t) >= 0 + && ossl_time_compare(age, expire) <= 0 + && ossl_time_compare(ossl_time_add(age, TICKET_AGE_ALLOWANCE), + expire) >= 0) { /* * Ticket age is within tolerance and not expired. We allow it * for early data @@ -1164,13 +1487,13 @@ int tls_parse_ctos_psk(SSL *s, PACKET *pkt, unsigned int context, X509 *x, } } - md = ssl_md(s->ctx, sess->cipher->algorithm2); + md = ssl_md(sctx, sess->cipher->algorithm2); if (md == NULL) { SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); goto err; } if (!EVP_MD_is_a(md, - EVP_MD_get0_name(ssl_md(s->ctx, + EVP_MD_get0_name(ssl_md(sctx, s->s3.tmp.new_cipher->algorithm2)))) { /* The ciphersuite is not compatible with this session. */ SSL_SESSION_free(sess); @@ -1187,6 +1510,8 @@ int tls_parse_ctos_psk(SSL *s, PACKET *pkt, unsigned int context, X509 *x, binderoffset = PACKET_data(pkt) - (const unsigned char *)s->init_buf->data; hashsize = EVP_MD_get_size(md); + if (hashsize <= 0) + goto err; if (!PACKET_get_length_prefixed_2(pkt, &binders)) { SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_R_BAD_EXTENSION); @@ -1200,7 +1525,7 @@ int tls_parse_ctos_psk(SSL *s, PACKET *pkt, unsigned int context, X509 *x, } } - if (PACKET_remaining(&binder) != hashsize) { + if (PACKET_remaining(&binder) != (size_t)hashsize) { SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_R_BAD_EXTENSION); goto err; } @@ -1221,7 +1546,7 @@ err: return 0; } -int tls_parse_ctos_post_handshake_auth(SSL *s, PACKET *pkt, +int tls_parse_ctos_post_handshake_auth(SSL_CONNECTION *s, PACKET *pkt, ossl_unused unsigned int context, ossl_unused X509 *x, ossl_unused size_t chainidx) @@ -1240,7 +1565,7 @@ int tls_parse_ctos_post_handshake_auth(SSL *s, PACKET *pkt, /* * Add the server's renegotiation binding */ -EXT_RETURN tls_construct_stoc_renegotiate(SSL *s, WPACKET *pkt, +EXT_RETURN tls_construct_stoc_renegotiate(SSL_CONNECTION *s, WPACKET *pkt, unsigned int context, X509 *x, size_t chainidx) { @@ -1264,7 +1589,7 @@ EXT_RETURN tls_construct_stoc_renegotiate(SSL *s, WPACKET *pkt, return EXT_RETURN_SENT; } -EXT_RETURN tls_construct_stoc_server_name(SSL *s, WPACKET *pkt, +EXT_RETURN tls_construct_stoc_server_name(SSL_CONNECTION *s, WPACKET *pkt, unsigned int context, X509 *x, size_t chainidx) { @@ -1275,7 +1600,7 @@ EXT_RETURN tls_construct_stoc_server_name(SSL *s, WPACKET *pkt, * Prior to TLSv1.3 we ignore any SNI in the current handshake if resuming. * We just use the servername from the initial handshake. */ - if (s->hit && !SSL_IS_TLS13(s)) + if (s->hit && !SSL_CONNECTION_IS_TLS13(s)) return EXT_RETURN_NOT_SENT; if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_server_name) @@ -1288,7 +1613,7 @@ EXT_RETURN tls_construct_stoc_server_name(SSL *s, WPACKET *pkt, } /* Add/include the server's max fragment len extension into ServerHello */ -EXT_RETURN tls_construct_stoc_maxfragmentlen(SSL *s, WPACKET *pkt, +EXT_RETURN tls_construct_stoc_maxfragmentlen(SSL_CONNECTION *s, WPACKET *pkt, unsigned int context, X509 *x, size_t chainidx) { @@ -1310,7 +1635,7 @@ EXT_RETURN tls_construct_stoc_maxfragmentlen(SSL *s, WPACKET *pkt, return EXT_RETURN_SENT; } -EXT_RETURN tls_construct_stoc_ec_pt_formats(SSL *s, WPACKET *pkt, +EXT_RETURN tls_construct_stoc_ec_pt_formats(SSL_CONNECTION *s, WPACKET *pkt, unsigned int context, X509 *x, size_t chainidx) { @@ -1336,7 +1661,7 @@ EXT_RETURN tls_construct_stoc_ec_pt_formats(SSL *s, WPACKET *pkt, return EXT_RETURN_SENT; } -EXT_RETURN tls_construct_stoc_supported_groups(SSL *s, WPACKET *pkt, +EXT_RETURN tls_construct_stoc_supported_groups(SSL_CONNECTION *s, WPACKET *pkt, unsigned int context, X509 *x, size_t chainidx) { @@ -1356,7 +1681,7 @@ EXT_RETURN tls_construct_stoc_supported_groups(SSL *s, WPACKET *pkt, } /* Copy group ID if supported */ - version = SSL_version(s); + version = SSL_version(SSL_CONNECTION_GET_SSL(s)); for (i = 0; i < numgroups; i++) { uint16_t group = groups[i]; @@ -1396,7 +1721,7 @@ EXT_RETURN tls_construct_stoc_supported_groups(SSL *s, WPACKET *pkt, return EXT_RETURN_SENT; } -EXT_RETURN tls_construct_stoc_session_ticket(SSL *s, WPACKET *pkt, +EXT_RETURN tls_construct_stoc_session_ticket(SSL_CONNECTION *s, WPACKET *pkt, unsigned int context, X509 *x, size_t chainidx) { @@ -1415,7 +1740,7 @@ EXT_RETURN tls_construct_stoc_session_ticket(SSL *s, WPACKET *pkt, } #ifndef OPENSSL_NO_OCSP -EXT_RETURN tls_construct_stoc_status_request(SSL *s, WPACKET *pkt, +EXT_RETURN tls_construct_stoc_status_request(SSL_CONNECTION *s, WPACKET *pkt, unsigned int context, X509 *x, size_t chainidx) { @@ -1426,7 +1751,7 @@ EXT_RETURN tls_construct_stoc_status_request(SSL *s, WPACKET *pkt, if (!s->ext.status_expected) return EXT_RETURN_NOT_SENT; - if (SSL_IS_TLS13(s) && chainidx != 0) + if (SSL_CONNECTION_IS_TLS13(s) && chainidx != 0) return EXT_RETURN_NOT_SENT; if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_status_request) @@ -1440,7 +1765,7 @@ EXT_RETURN tls_construct_stoc_status_request(SSL *s, WPACKET *pkt, * send back an empty extension, with the certificate status appearing as a * separate message */ - if (SSL_IS_TLS13(s) && !tls_construct_cert_status_body(s, pkt)) { + if (SSL_CONNECTION_IS_TLS13(s) && !tls_construct_cert_status_body(s, pkt)) { /* SSLfatal() already called */ return EXT_RETURN_FAIL; } @@ -1454,7 +1779,7 @@ EXT_RETURN tls_construct_stoc_status_request(SSL *s, WPACKET *pkt, #endif #ifndef OPENSSL_NO_NEXTPROTONEG -EXT_RETURN tls_construct_stoc_next_proto_neg(SSL *s, WPACKET *pkt, +EXT_RETURN tls_construct_stoc_next_proto_neg(SSL_CONNECTION *s, WPACKET *pkt, unsigned int context, X509 *x, size_t chainidx) { @@ -1462,13 +1787,14 @@ EXT_RETURN tls_construct_stoc_next_proto_neg(SSL *s, WPACKET *pkt, unsigned int npalen; int ret; int npn_seen = s->s3.npn_seen; + SSL_CTX *sctx = SSL_CONNECTION_GET_CTX(s); s->s3.npn_seen = 0; - if (!npn_seen || s->ctx->ext.npn_advertised_cb == NULL) + if (!npn_seen || sctx->ext.npn_advertised_cb == NULL) return EXT_RETURN_NOT_SENT; - ret = s->ctx->ext.npn_advertised_cb(s, &npa, &npalen, - s->ctx->ext.npn_advertised_cb_arg); + ret = sctx->ext.npn_advertised_cb(SSL_CONNECTION_GET_USER_SSL(s), &npa, + &npalen, sctx->ext.npn_advertised_cb_arg); if (ret == SSL_TLSEXT_ERR_OK) { if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_next_proto_neg) || !WPACKET_sub_memcpy_u16(pkt, npa, npalen)) { @@ -1483,7 +1809,7 @@ EXT_RETURN tls_construct_stoc_next_proto_neg(SSL *s, WPACKET *pkt, } #endif -EXT_RETURN tls_construct_stoc_alpn(SSL *s, WPACKET *pkt, unsigned int context, +EXT_RETURN tls_construct_stoc_alpn(SSL_CONNECTION *s, WPACKET *pkt, unsigned int context, X509 *x, size_t chainidx) { if (s->s3.alpn_selected == NULL) @@ -1505,7 +1831,7 @@ EXT_RETURN tls_construct_stoc_alpn(SSL *s, WPACKET *pkt, unsigned int context, } #ifndef OPENSSL_NO_SRTP -EXT_RETURN tls_construct_stoc_use_srtp(SSL *s, WPACKET *pkt, +EXT_RETURN tls_construct_stoc_use_srtp(SSL_CONNECTION *s, WPACKET *pkt, unsigned int context, X509 *x, size_t chainidx) { @@ -1526,7 +1852,8 @@ EXT_RETURN tls_construct_stoc_use_srtp(SSL *s, WPACKET *pkt, } #endif -EXT_RETURN tls_construct_stoc_etm(SSL *s, WPACKET *pkt, unsigned int context, +EXT_RETURN tls_construct_stoc_etm(SSL_CONNECTION *s, WPACKET *pkt, + unsigned int context, X509 *x, size_t chainidx) { if (!s->ext.use_etm) @@ -1555,7 +1882,8 @@ EXT_RETURN tls_construct_stoc_etm(SSL *s, WPACKET *pkt, unsigned int context, return EXT_RETURN_SENT; } -EXT_RETURN tls_construct_stoc_ems(SSL *s, WPACKET *pkt, unsigned int context, +EXT_RETURN tls_construct_stoc_ems(SSL_CONNECTION *s, WPACKET *pkt, + unsigned int context, X509 *x, size_t chainidx) { if ((s->s3.flags & TLS1_FLAGS_RECEIVED_EXTMS) == 0) @@ -1570,11 +1898,11 @@ EXT_RETURN tls_construct_stoc_ems(SSL *s, WPACKET *pkt, unsigned int context, return EXT_RETURN_SENT; } -EXT_RETURN tls_construct_stoc_supported_versions(SSL *s, WPACKET *pkt, +EXT_RETURN tls_construct_stoc_supported_versions(SSL_CONNECTION *s, WPACKET *pkt, unsigned int context, X509 *x, size_t chainidx) { - if (!ossl_assert(SSL_IS_TLS13(s))) { + if (!ossl_assert(SSL_CONNECTION_IS_TLS13(s))) { SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); return EXT_RETURN_FAIL; } @@ -1590,13 +1918,13 @@ EXT_RETURN tls_construct_stoc_supported_versions(SSL *s, WPACKET *pkt, return EXT_RETURN_SENT; } -EXT_RETURN tls_construct_stoc_key_share(SSL *s, WPACKET *pkt, +EXT_RETURN tls_construct_stoc_key_share(SSL_CONNECTION *s, WPACKET *pkt, unsigned int context, X509 *x, size_t chainidx) { #ifndef OPENSSL_NO_TLS1_3 - unsigned char *encodedPoint; - size_t encoded_pt_len = 0; + unsigned char *encoded_pubkey; + size_t encoded_pubkey_len = 0; EVP_PKEY *ckey = s->s3.peer_tmp, *skey = NULL; const TLS_GROUP_INFO *ginf = NULL; @@ -1624,10 +1952,13 @@ EXT_RETURN tls_construct_stoc_key_share(SSL *s, WPACKET *pkt, } return EXT_RETURN_NOT_SENT; } + if (s->hit && (s->ext.psk_kex_mode & TLSEXT_KEX_MODE_FLAG_KE_DHE) == 0) { /* - * PSK ('hit') and explicitly not doing DHE (if the client sent the - * DHE option we always take it); don't send key share. + * PSK ('hit') and explicitly not doing DHE. If the client sent the + * DHE option, we take it by default, except if non-DHE would be + * preferred by config, but this case would have been handled in + * tls_parse_ctos_psk_kex_modes(). */ return EXT_RETURN_NOT_SENT; } @@ -1639,7 +1970,8 @@ EXT_RETURN tls_construct_stoc_key_share(SSL *s, WPACKET *pkt, return EXT_RETURN_FAIL; } - if ((ginf = tls1_group_id_lookup(s->ctx, s->s3.group_id)) == NULL) { + if ((ginf = tls1_group_id_lookup(SSL_CONNECTION_GET_CTX(s), + s->s3.group_id)) == NULL) { SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); return EXT_RETURN_FAIL; } @@ -1648,26 +1980,26 @@ EXT_RETURN tls_construct_stoc_key_share(SSL *s, WPACKET *pkt, /* Regular KEX */ skey = ssl_generate_pkey(s, ckey); if (skey == NULL) { - SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_MALLOC_FAILURE); + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_SSL_LIB); return EXT_RETURN_FAIL; } /* Generate encoding of server key */ - encoded_pt_len = EVP_PKEY_get1_encoded_public_key(skey, &encodedPoint); - if (encoded_pt_len == 0) { + encoded_pubkey_len = EVP_PKEY_get1_encoded_public_key(skey, &encoded_pubkey); + if (encoded_pubkey_len == 0) { SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_EC_LIB); EVP_PKEY_free(skey); return EXT_RETURN_FAIL; } - if (!WPACKET_sub_memcpy_u16(pkt, encodedPoint, encoded_pt_len) + if (!WPACKET_sub_memcpy_u16(pkt, encoded_pubkey, encoded_pubkey_len) || !WPACKET_close(pkt)) { SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); EVP_PKEY_free(skey); - OPENSSL_free(encodedPoint); + OPENSSL_free(encoded_pubkey); return EXT_RETURN_FAIL; } - OPENSSL_free(encodedPoint); + OPENSSL_free(encoded_pubkey); /* * This causes the crypto state to be updated based on the derived keys @@ -1722,7 +2054,8 @@ EXT_RETURN tls_construct_stoc_key_share(SSL *s, WPACKET *pkt, #endif } -EXT_RETURN tls_construct_stoc_cookie(SSL *s, WPACKET *pkt, unsigned int context, +EXT_RETURN tls_construct_stoc_cookie(SSL_CONNECTION *s, WPACKET *pkt, + unsigned int context, X509 *x, size_t chainidx) { #ifndef OPENSSL_NO_TLS1_3 @@ -1732,11 +2065,14 @@ EXT_RETURN tls_construct_stoc_cookie(SSL *s, WPACKET *pkt, unsigned int context, EVP_MD_CTX *hctx; EVP_PKEY *pkey; int ret = EXT_RETURN_FAIL; + SSL_CTX *sctx = SSL_CONNECTION_GET_CTX(s); + SSL *ssl = SSL_CONNECTION_GET_SSL(s); + SSL *ussl = SSL_CONNECTION_GET_USER_SSL(s); if ((s->s3.flags & TLS1_FLAGS_STATELESS) == 0) return EXT_RETURN_NOT_SENT; - if (s->ctx->gen_stateless_cookie_cb == NULL) { + if (sctx->gen_stateless_cookie_cb == NULL) { SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_R_NO_COOKIE_CALLBACK_SET); return EXT_RETURN_FAIL; } @@ -1749,8 +2085,8 @@ EXT_RETURN tls_construct_stoc_cookie(SSL *s, WPACKET *pkt, unsigned int context, || !WPACKET_put_bytes_u16(pkt, COOKIE_STATE_FORMAT_VERSION) || !WPACKET_put_bytes_u16(pkt, TLS1_3_VERSION) || !WPACKET_put_bytes_u16(pkt, s->s3.group_id) - || !s->method->put_cipher_by_char(s->s3.tmp.new_cipher, pkt, - &ciphlen) + || !ssl->method->put_cipher_by_char(s->s3.tmp.new_cipher, pkt, + &ciphlen) /* Is there a key_share extension present in this HRR? */ || !WPACKET_put_bytes_u8(pkt, s->s3.peer_tmp == NULL) || !WPACKET_put_bytes_u64(pkt, time(NULL)) @@ -1781,7 +2117,8 @@ EXT_RETURN tls_construct_stoc_cookie(SSL *s, WPACKET *pkt, unsigned int context, } /* Generate the application cookie */ - if (s->ctx->gen_stateless_cookie_cb(s, appcookie1, &appcookielen) == 0) { + if (sctx->gen_stateless_cookie_cb(ussl, appcookie1, + &appcookielen) == 0) { SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_R_COOKIE_GEN_CALLBACK_FAILURE); return EXT_RETURN_FAIL; } @@ -1804,17 +2141,17 @@ EXT_RETURN tls_construct_stoc_cookie(SSL *s, WPACKET *pkt, unsigned int context, /* HMAC the cookie */ hctx = EVP_MD_CTX_create(); - pkey = EVP_PKEY_new_raw_private_key_ex(s->ctx->libctx, "HMAC", - s->ctx->propq, + pkey = EVP_PKEY_new_raw_private_key_ex(sctx->libctx, "HMAC", + sctx->propq, s->session_ctx->ext.cookie_hmac_key, sizeof(s->session_ctx->ext.cookie_hmac_key)); if (hctx == NULL || pkey == NULL) { - SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_MALLOC_FAILURE); + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_EVP_LIB); goto err; } - if (EVP_DigestSignInit_ex(hctx, NULL, "SHA2-256", s->ctx->libctx, - s->ctx->propq, pkey, NULL) <= 0 + if (EVP_DigestSignInit_ex(hctx, NULL, "SHA2-256", sctx->libctx, + sctx->propq, pkey, NULL) <= 0 || EVP_DigestSign(hctx, hmac, &hmaclen, cookie, totcookielen) <= 0) { SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); @@ -1846,7 +2183,7 @@ EXT_RETURN tls_construct_stoc_cookie(SSL *s, WPACKET *pkt, unsigned int context, #endif } -EXT_RETURN tls_construct_stoc_cryptopro_bug(SSL *s, WPACKET *pkt, +EXT_RETURN tls_construct_stoc_cryptopro_bug(SSL_CONNECTION *s, WPACKET *pkt, unsigned int context, X509 *x, size_t chainidx) { @@ -1861,7 +2198,8 @@ EXT_RETURN tls_construct_stoc_cryptopro_bug(SSL *s, WPACKET *pkt, if (((s->s3.tmp.new_cipher->id & 0xFFFF) != 0x80 && (s->s3.tmp.new_cipher->id & 0xFFFF) != 0x81) - || (SSL_get_options(s) & SSL_OP_CRYPTOPRO_TLSEXT_BUG) == 0) + || (SSL_get_options(SSL_CONNECTION_GET_SSL(s)) + & SSL_OP_CRYPTOPRO_TLSEXT_BUG) == 0) return EXT_RETURN_NOT_SENT; if (!WPACKET_memcpy(pkt, cryptopro_ext, sizeof(cryptopro_ext))) { @@ -1872,7 +2210,7 @@ EXT_RETURN tls_construct_stoc_cryptopro_bug(SSL *s, WPACKET *pkt, return EXT_RETURN_SENT; } -EXT_RETURN tls_construct_stoc_early_data(SSL *s, WPACKET *pkt, +EXT_RETURN tls_construct_stoc_early_data(SSL_CONNECTION *s, WPACKET *pkt, unsigned int context, X509 *x, size_t chainidx) { @@ -1904,7 +2242,8 @@ EXT_RETURN tls_construct_stoc_early_data(SSL *s, WPACKET *pkt, return EXT_RETURN_SENT; } -EXT_RETURN tls_construct_stoc_psk(SSL *s, WPACKET *pkt, unsigned int context, +EXT_RETURN tls_construct_stoc_psk(SSL_CONNECTION *s, WPACKET *pkt, + unsigned int context, X509 *x, size_t chainidx) { if (!s->hit) @@ -1920,3 +2259,164 @@ EXT_RETURN tls_construct_stoc_psk(SSL *s, WPACKET *pkt, unsigned int context, return EXT_RETURN_SENT; } + +EXT_RETURN tls_construct_stoc_client_cert_type(SSL_CONNECTION *sc, WPACKET *pkt, + unsigned int context, + X509 *x, size_t chainidx) +{ + if (sc->ext.client_cert_type_ctos == OSSL_CERT_TYPE_CTOS_ERROR + && (send_certificate_request(sc) + || sc->post_handshake_auth == SSL_PHA_EXT_RECEIVED)) { + /* Did not receive an acceptable cert type - and doing client auth */ + SSLfatal(sc, SSL_AD_UNSUPPORTED_CERTIFICATE, SSL_R_BAD_EXTENSION); + return EXT_RETURN_FAIL; + } + + if (sc->ext.client_cert_type == TLSEXT_cert_type_x509) { + sc->ext.client_cert_type_ctos = OSSL_CERT_TYPE_CTOS_NONE; + return EXT_RETURN_NOT_SENT; + } + + /* + * Note: only supposed to send this if we are going to do a cert request, + * but TLSv1.3 could do a PHA request if the client supports it + */ + if ((!send_certificate_request(sc) && sc->post_handshake_auth != SSL_PHA_EXT_RECEIVED) + || sc->ext.client_cert_type_ctos != OSSL_CERT_TYPE_CTOS_GOOD + || sc->client_cert_type == NULL) { + /* if we don't send it, reset to TLSEXT_cert_type_x509 */ + sc->ext.client_cert_type_ctos = OSSL_CERT_TYPE_CTOS_NONE; + sc->ext.client_cert_type = TLSEXT_cert_type_x509; + return EXT_RETURN_NOT_SENT; + } + + if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_client_cert_type) + || !WPACKET_start_sub_packet_u16(pkt) + || !WPACKET_put_bytes_u8(pkt, sc->ext.client_cert_type) + || !WPACKET_close(pkt)) { + SSLfatal(sc, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + return EXT_RETURN_FAIL; + } + return EXT_RETURN_SENT; +} + +/* One of |pref|, |other| is configured and the values are sanitized */ +static int reconcile_cert_type(const unsigned char *pref, size_t pref_len, + const unsigned char *other, size_t other_len, + uint8_t *chosen_cert_type) +{ + size_t i; + + for (i = 0; i < pref_len; i++) { + if (memchr(other, pref[i], other_len) != NULL) { + *chosen_cert_type = pref[i]; + return OSSL_CERT_TYPE_CTOS_GOOD; + } + } + return OSSL_CERT_TYPE_CTOS_ERROR; +} + +int tls_parse_ctos_client_cert_type(SSL_CONNECTION *sc, PACKET *pkt, + unsigned int context, + X509 *x, size_t chainidx) +{ + PACKET supported_cert_types; + const unsigned char *data; + size_t len; + + /* Ignore the extension */ + if (sc->client_cert_type == NULL) { + sc->ext.client_cert_type_ctos = OSSL_CERT_TYPE_CTOS_NONE; + sc->ext.client_cert_type = TLSEXT_cert_type_x509; + return 1; + } + + if (!PACKET_as_length_prefixed_1(pkt, &supported_cert_types)) { + sc->ext.client_cert_type_ctos = OSSL_CERT_TYPE_CTOS_ERROR; + SSLfatal(sc, SSL_AD_DECODE_ERROR, SSL_R_BAD_EXTENSION); + return 0; + } + if ((len = PACKET_remaining(&supported_cert_types)) == 0) { + sc->ext.client_cert_type_ctos = OSSL_CERT_TYPE_CTOS_ERROR; + SSLfatal(sc, SSL_AD_DECODE_ERROR, SSL_R_BAD_EXTENSION); + return 0; + } + if (!PACKET_get_bytes(&supported_cert_types, &data, len)) { + sc->ext.client_cert_type_ctos = OSSL_CERT_TYPE_CTOS_ERROR; + SSLfatal(sc, SSL_AD_DECODE_ERROR, SSL_R_BAD_EXTENSION); + return 0; + } + /* client_cert_type: client (peer) has priority */ + sc->ext.client_cert_type_ctos = reconcile_cert_type(data, len, + sc->client_cert_type, sc->client_cert_type_len, + &sc->ext.client_cert_type); + + /* Ignore the error until sending - so we can check cert auth*/ + return 1; +} + +EXT_RETURN tls_construct_stoc_server_cert_type(SSL_CONNECTION *sc, WPACKET *pkt, + unsigned int context, + X509 *x, size_t chainidx) +{ + if (sc->ext.server_cert_type == TLSEXT_cert_type_x509) { + sc->ext.server_cert_type_ctos = OSSL_CERT_TYPE_CTOS_NONE; + return EXT_RETURN_NOT_SENT; + } + if (sc->ext.server_cert_type_ctos != OSSL_CERT_TYPE_CTOS_GOOD + || sc->server_cert_type == NULL) { + /* if we don't send it, reset to TLSEXT_cert_type_x509 */ + sc->ext.server_cert_type_ctos = OSSL_CERT_TYPE_CTOS_NONE; + sc->ext.server_cert_type = TLSEXT_cert_type_x509; + return EXT_RETURN_NOT_SENT; + } + + if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_server_cert_type) + || !WPACKET_start_sub_packet_u16(pkt) + || !WPACKET_put_bytes_u8(pkt, sc->ext.server_cert_type) + || !WPACKET_close(pkt)) { + SSLfatal(sc, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + return EXT_RETURN_FAIL; + } + return EXT_RETURN_SENT; +} + +int tls_parse_ctos_server_cert_type(SSL_CONNECTION *sc, PACKET *pkt, + unsigned int context, + X509 *x, size_t chainidx) +{ + PACKET supported_cert_types; + const unsigned char *data; + size_t len; + + /* Ignore the extension */ + if (sc->server_cert_type == NULL) { + sc->ext.server_cert_type_ctos = OSSL_CERT_TYPE_CTOS_NONE; + sc->ext.server_cert_type = TLSEXT_cert_type_x509; + return 1; + } + + if (!PACKET_as_length_prefixed_1(pkt, &supported_cert_types)) { + SSLfatal(sc, SSL_AD_DECODE_ERROR, SSL_R_BAD_EXTENSION); + return 0; + } + + if ((len = PACKET_remaining(&supported_cert_types)) == 0) { + SSLfatal(sc, SSL_AD_DECODE_ERROR, SSL_R_BAD_EXTENSION); + return 0; + } + if (!PACKET_get_bytes(&supported_cert_types, &data, len)) { + SSLfatal(sc, SSL_AD_DECODE_ERROR, SSL_R_BAD_EXTENSION); + return 0; + } + /* server_cert_type: server (this) has priority */ + sc->ext.server_cert_type_ctos = reconcile_cert_type(sc->server_cert_type, sc->server_cert_type_len, + data, len, + &sc->ext.server_cert_type); + if (sc->ext.server_cert_type_ctos == OSSL_CERT_TYPE_CTOS_GOOD) + return 1; + + /* Did not receive an acceptable cert type */ + SSLfatal(sc, SSL_AD_UNSUPPORTED_CERTIFICATE, SSL_R_BAD_EXTENSION); + return 0; +} |