aboutsummaryrefslogtreecommitdiff
path: root/ssl/statem/extensions_srvr.c
diff options
context:
space:
mode:
Diffstat (limited to 'ssl/statem/extensions_srvr.c')
-rw-r--r--ssl/statem/extensions_srvr.c882
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;
+}