aboutsummaryrefslogtreecommitdiff
path: root/ssl/statem/extensions_clnt.c
diff options
context:
space:
mode:
Diffstat (limited to 'ssl/statem/extensions_clnt.c')
-rw-r--r--ssl/statem/extensions_clnt.c520
1 files changed, 390 insertions, 130 deletions
diff --git a/ssl/statem/extensions_clnt.c b/ssl/statem/extensions_clnt.c
index ced88f77ba3c..baa7c47b3cd9 100644
--- a/ssl/statem/extensions_clnt.c
+++ b/ssl/statem/extensions_clnt.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
@@ -10,16 +10,44 @@
#include <openssl/ocsp.h>
#include "../ssl_local.h"
#include "internal/cryptlib.h"
+#include "internal/ssl_unwrap.h"
#include "statem_local.h"
-EXT_RETURN tls_construct_ctos_renegotiate(SSL *s, WPACKET *pkt,
+EXT_RETURN tls_construct_ctos_renegotiate(SSL_CONNECTION *s, WPACKET *pkt,
unsigned int context, X509 *x,
size_t chainidx)
{
- /* Add RI if renegotiating */
- if (!s->renegotiate)
- return EXT_RETURN_NOT_SENT;
+ if (!s->renegotiate) {
+ /* If not renegotiating, send an empty RI extension to indicate support */
+
+#if DTLS_MAX_VERSION_INTERNAL != DTLS1_2_VERSION
+# error Internal DTLS version error
+#endif
+
+ if (!SSL_CONNECTION_IS_DTLS(s)
+ && (s->min_proto_version >= TLS1_3_VERSION
+ || (ssl_security(s, SSL_SECOP_VERSION, 0, TLS1_VERSION, NULL)
+ && s->min_proto_version <= TLS1_VERSION))) {
+ /*
+ * For TLS <= 1.0 SCSV is used instead, and for TLS 1.3 this
+ * extension isn't used at all.
+ */
+ return EXT_RETURN_NOT_SENT;
+ }
+
+
+ if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_renegotiate)
+ || !WPACKET_start_sub_packet_u16(pkt)
+ || !WPACKET_put_bytes_u8(pkt, 0)
+ || !WPACKET_close(pkt)) {
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+ return EXT_RETURN_FAIL;
+ }
+
+ return EXT_RETURN_SENT;
+ }
+ /* Add a complete RI extension if renegotiating */
if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_renegotiate)
|| !WPACKET_start_sub_packet_u16(pkt)
|| !WPACKET_sub_memcpy_u8(pkt, s->s3.previous_client_finished,
@@ -32,7 +60,7 @@ EXT_RETURN tls_construct_ctos_renegotiate(SSL *s, WPACKET *pkt,
return EXT_RETURN_SENT;
}
-EXT_RETURN tls_construct_ctos_server_name(SSL *s, WPACKET *pkt,
+EXT_RETURN tls_construct_ctos_server_name(SSL_CONNECTION *s, WPACKET *pkt,
unsigned int context, X509 *x,
size_t chainidx)
{
@@ -58,7 +86,7 @@ EXT_RETURN tls_construct_ctos_server_name(SSL *s, WPACKET *pkt,
}
/* Push a Max Fragment Len extension into ClientHello */
-EXT_RETURN tls_construct_ctos_maxfragmentlen(SSL *s, WPACKET *pkt,
+EXT_RETURN tls_construct_ctos_maxfragmentlen(SSL_CONNECTION *s, WPACKET *pkt,
unsigned int context, X509 *x,
size_t chainidx)
{
@@ -83,7 +111,8 @@ EXT_RETURN tls_construct_ctos_maxfragmentlen(SSL *s, WPACKET *pkt,
}
#ifndef OPENSSL_NO_SRP
-EXT_RETURN tls_construct_ctos_srp(SSL *s, WPACKET *pkt, unsigned int context,
+EXT_RETURN tls_construct_ctos_srp(SSL_CONNECTION *s, WPACKET *pkt,
+ unsigned int context,
X509 *x, size_t chainidx)
{
/* Add SRP username if there is one */
@@ -108,19 +137,20 @@ EXT_RETURN tls_construct_ctos_srp(SSL *s, WPACKET *pkt, unsigned int context,
}
#endif
-static int use_ecc(SSL *s, int min_version, int max_version)
+static int use_ecc(SSL_CONNECTION *s, int min_version, int max_version)
{
int i, end, ret = 0;
unsigned long alg_k, alg_a;
STACK_OF(SSL_CIPHER) *cipher_stack = NULL;
const uint16_t *pgroups = NULL;
size_t num_groups, j;
+ SSL *ssl = SSL_CONNECTION_GET_SSL(s);
/* See if we support any ECC ciphersuites */
if (s->version == SSL3_VERSION)
return 0;
- cipher_stack = SSL_get1_supported_ciphers(s);
+ cipher_stack = SSL_get1_supported_ciphers(ssl);
end = sk_SSL_CIPHER_num(cipher_stack);
for (i = 0; i < end; i++) {
const SSL_CIPHER *c = sk_SSL_CIPHER_value(cipher_stack, i);
@@ -151,7 +181,7 @@ static int use_ecc(SSL *s, int min_version, int max_version)
return 0;
}
-EXT_RETURN tls_construct_ctos_ec_pt_formats(SSL *s, WPACKET *pkt,
+EXT_RETURN tls_construct_ctos_ec_pt_formats(SSL_CONNECTION *s, WPACKET *pkt,
unsigned int context, X509 *x,
size_t chainidx)
{
@@ -182,7 +212,7 @@ EXT_RETURN tls_construct_ctos_ec_pt_formats(SSL *s, WPACKET *pkt,
return EXT_RETURN_SENT;
}
-EXT_RETURN tls_construct_ctos_supported_groups(SSL *s, WPACKET *pkt,
+EXT_RETURN tls_construct_ctos_supported_groups(SSL_CONNECTION *s, WPACKET *pkt,
unsigned int context, X509 *x,
size_t chainidx)
{
@@ -201,7 +231,7 @@ EXT_RETURN tls_construct_ctos_supported_groups(SSL *s, WPACKET *pkt,
* if we don't have EC support then we don't send this extension.
*/
if (!use_ecc(s, min_version, max_version)
- && (SSL_IS_DTLS(s) || max_version < TLS1_3_VERSION))
+ && (SSL_CONNECTION_IS_DTLS(s) || max_version < TLS1_3_VERSION))
return EXT_RETURN_NOT_SENT;
/*
@@ -251,7 +281,7 @@ EXT_RETURN tls_construct_ctos_supported_groups(SSL *s, WPACKET *pkt,
return EXT_RETURN_SENT;
}
-EXT_RETURN tls_construct_ctos_session_ticket(SSL *s, WPACKET *pkt,
+EXT_RETURN tls_construct_ctos_session_ticket(SSL_CONNECTION *s, WPACKET *pkt,
unsigned int context, X509 *x,
size_t chainidx)
{
@@ -292,15 +322,29 @@ EXT_RETURN tls_construct_ctos_session_ticket(SSL *s, WPACKET *pkt,
return EXT_RETURN_SENT;
}
-EXT_RETURN tls_construct_ctos_sig_algs(SSL *s, WPACKET *pkt,
+EXT_RETURN tls_construct_ctos_sig_algs(SSL_CONNECTION *s, WPACKET *pkt,
unsigned int context, X509 *x,
size_t chainidx)
{
size_t salglen;
const uint16_t *salg;
- if (!SSL_CLIENT_USE_SIGALGS(s))
+ /*
+ * This used both in the initial hello and as part of renegotiation,
+ * in the latter case, the client version may be already set and may
+ * be lower than that initially offered in `client_version`.
+ */
+ if (!SSL_CONNECTION_IS_DTLS(s)) {
+ if (s->client_version < TLS1_2_VERSION
+ || (s->ssl.method->version != TLS_ANY_VERSION
+ && s->version < TLS1_2_VERSION))
+ return EXT_RETURN_NOT_SENT;
+ } else {
+ if (DTLS_VERSION_LT(s->client_version, DTLS1_2_VERSION)
+ || (s->ssl.method->version != DTLS_ANY_VERSION
+ && DTLS_VERSION_LT(s->version, DTLS1_2_VERSION)))
return EXT_RETURN_NOT_SENT;
+ }
salglen = tls12_get_psigalgs(s, 1, &salg);
if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_signature_algorithms)
@@ -319,7 +363,7 @@ EXT_RETURN tls_construct_ctos_sig_algs(SSL *s, WPACKET *pkt,
}
#ifndef OPENSSL_NO_OCSP
-EXT_RETURN tls_construct_ctos_status_request(SSL *s, WPACKET *pkt,
+EXT_RETURN tls_construct_ctos_status_request(SSL_CONNECTION *s, WPACKET *pkt,
unsigned int context, X509 *x,
size_t chainidx)
{
@@ -384,10 +428,12 @@ EXT_RETURN tls_construct_ctos_status_request(SSL *s, WPACKET *pkt,
#endif
#ifndef OPENSSL_NO_NEXTPROTONEG
-EXT_RETURN tls_construct_ctos_npn(SSL *s, WPACKET *pkt, unsigned int context,
+EXT_RETURN tls_construct_ctos_npn(SSL_CONNECTION *s, WPACKET *pkt,
+ unsigned int context,
X509 *x, size_t chainidx)
{
- if (s->ctx->ext.npn_select_cb == NULL || !SSL_IS_FIRST_HANDSHAKE(s))
+ if (SSL_CONNECTION_GET_CTX(s)->ext.npn_select_cb == NULL
+ || !SSL_IS_FIRST_HANDSHAKE(s))
return EXT_RETURN_NOT_SENT;
/*
@@ -404,7 +450,8 @@ EXT_RETURN tls_construct_ctos_npn(SSL *s, WPACKET *pkt, unsigned int context,
}
#endif
-EXT_RETURN tls_construct_ctos_alpn(SSL *s, WPACKET *pkt, unsigned int context,
+EXT_RETURN tls_construct_ctos_alpn(SSL_CONNECTION *s, WPACKET *pkt,
+ unsigned int context,
X509 *x, size_t chainidx)
{
s->s3.alpn_sent = 0;
@@ -428,11 +475,12 @@ EXT_RETURN tls_construct_ctos_alpn(SSL *s, WPACKET *pkt, unsigned int context,
#ifndef OPENSSL_NO_SRTP
-EXT_RETURN tls_construct_ctos_use_srtp(SSL *s, WPACKET *pkt,
+EXT_RETURN tls_construct_ctos_use_srtp(SSL_CONNECTION *s, WPACKET *pkt,
unsigned int context, X509 *x,
size_t chainidx)
{
- STACK_OF(SRTP_PROTECTION_PROFILE) *clnt = SSL_get_srtp_profiles(s);
+ SSL *ssl = SSL_CONNECTION_GET_SSL(s);
+ STACK_OF(SRTP_PROTECTION_PROFILE) *clnt = SSL_get_srtp_profiles(ssl);
int i, end;
if (clnt == NULL)
@@ -469,7 +517,8 @@ EXT_RETURN tls_construct_ctos_use_srtp(SSL *s, WPACKET *pkt,
}
#endif
-EXT_RETURN tls_construct_ctos_etm(SSL *s, WPACKET *pkt, unsigned int context,
+EXT_RETURN tls_construct_ctos_etm(SSL_CONNECTION *s, WPACKET *pkt,
+ unsigned int context,
X509 *x, size_t chainidx)
{
if (s->options & SSL_OP_NO_ENCRYPT_THEN_MAC)
@@ -485,7 +534,8 @@ EXT_RETURN tls_construct_ctos_etm(SSL *s, WPACKET *pkt, unsigned int context,
}
#ifndef OPENSSL_NO_CT
-EXT_RETURN tls_construct_ctos_sct(SSL *s, WPACKET *pkt, unsigned int context,
+EXT_RETURN tls_construct_ctos_sct(SSL_CONNECTION *s, WPACKET *pkt,
+ unsigned int context,
X509 *x, size_t chainidx)
{
if (s->ct_validation_callback == NULL)
@@ -505,7 +555,8 @@ EXT_RETURN tls_construct_ctos_sct(SSL *s, WPACKET *pkt, unsigned int context,
}
#endif
-EXT_RETURN tls_construct_ctos_ems(SSL *s, WPACKET *pkt, unsigned int context,
+EXT_RETURN tls_construct_ctos_ems(SSL_CONNECTION *s, WPACKET *pkt,
+ unsigned int context,
X509 *x, size_t chainidx)
{
if (s->options & SSL_OP_NO_EXTENDED_MASTER_SECRET)
@@ -520,7 +571,7 @@ EXT_RETURN tls_construct_ctos_ems(SSL *s, WPACKET *pkt, unsigned int context,
return EXT_RETURN_SENT;
}
-EXT_RETURN tls_construct_ctos_supported_versions(SSL *s, WPACKET *pkt,
+EXT_RETURN tls_construct_ctos_supported_versions(SSL_CONNECTION *s, WPACKET *pkt,
unsigned int context, X509 *x,
size_t chainidx)
{
@@ -563,7 +614,7 @@ EXT_RETURN tls_construct_ctos_supported_versions(SSL *s, WPACKET *pkt,
/*
* Construct a psk_kex_modes extension.
*/
-EXT_RETURN tls_construct_ctos_psk_kex_modes(SSL *s, WPACKET *pkt,
+EXT_RETURN tls_construct_ctos_psk_kex_modes(SSL_CONNECTION *s, WPACKET *pkt,
unsigned int context, X509 *x,
size_t chainidx)
{
@@ -590,23 +641,24 @@ EXT_RETURN tls_construct_ctos_psk_kex_modes(SSL *s, WPACKET *pkt,
}
#ifndef OPENSSL_NO_TLS1_3
-static int add_key_share(SSL *s, WPACKET *pkt, unsigned int curve_id)
+static int add_key_share(SSL_CONNECTION *s, WPACKET *pkt, unsigned int group_id, size_t loop_num)
{
- unsigned char *encoded_point = NULL;
+ unsigned char *encoded_pubkey = NULL;
EVP_PKEY *key_share_key = NULL;
size_t encodedlen;
- if (s->s3.tmp.pkey != NULL) {
- if (!ossl_assert(s->hello_retry_request == SSL_HRR_PENDING)) {
+ if (loop_num < s->s3.tmp.num_ks_pkey) {
+ if (!ossl_assert(s->hello_retry_request == SSL_HRR_PENDING)
+ || !ossl_assert(s->s3.tmp.ks_pkey[loop_num] != NULL)) {
SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
return 0;
}
/*
* Could happen if we got an HRR that wasn't requesting a new key_share
*/
- key_share_key = s->s3.tmp.pkey;
+ key_share_key = s->s3.tmp.ks_pkey[loop_num];
} else {
- key_share_key = ssl_generate_pkey_group(s, curve_id);
+ key_share_key = ssl_generate_pkey_group(s, group_id);
if (key_share_key == NULL) {
/* SSLfatal() already called */
return 0;
@@ -615,87 +667,110 @@ static int add_key_share(SSL *s, WPACKET *pkt, unsigned int curve_id)
/* Encode the public key. */
encodedlen = EVP_PKEY_get1_encoded_public_key(key_share_key,
- &encoded_point);
+ &encoded_pubkey);
if (encodedlen == 0) {
SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_EC_LIB);
goto err;
}
/* Create KeyShareEntry */
- if (!WPACKET_put_bytes_u16(pkt, curve_id)
- || !WPACKET_sub_memcpy_u16(pkt, encoded_point, encodedlen)) {
+ if (!WPACKET_put_bytes_u16(pkt, group_id)
+ || !WPACKET_sub_memcpy_u16(pkt, encoded_pubkey, encodedlen)) {
SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
goto err;
}
- /*
- * When changing to send more than one key_share we're
- * going to need to be able to save more than one EVP_PKEY. For now
- * we reuse the existing tmp.pkey
- */
- s->s3.tmp.pkey = key_share_key;
- s->s3.group_id = curve_id;
- OPENSSL_free(encoded_point);
+ /* For backward compatibility, we use the first valid group to add a key share */
+ if (loop_num == 0) {
+ s->s3.tmp.pkey = key_share_key;
+ s->s3.group_id = group_id;
+ }
+ /* We ensure in t1_lib.c that the loop number does not exceed OPENSSL_CLIENT_MAX_KEY_SHARES */
+ s->s3.tmp.ks_pkey[loop_num] = key_share_key;
+ s->s3.tmp.ks_group_id[loop_num] = group_id;
+ if (loop_num >= s->s3.tmp.num_ks_pkey)
+ s->s3.tmp.num_ks_pkey++;
+
+ OPENSSL_free(encoded_pubkey);
return 1;
err:
- if (s->s3.tmp.pkey == NULL)
+ if (key_share_key != s->s3.tmp.ks_pkey[loop_num])
EVP_PKEY_free(key_share_key);
- OPENSSL_free(encoded_point);
+ OPENSSL_free(encoded_pubkey);
return 0;
}
#endif
-EXT_RETURN tls_construct_ctos_key_share(SSL *s, WPACKET *pkt,
+EXT_RETURN tls_construct_ctos_key_share(SSL_CONNECTION *s, WPACKET *pkt,
unsigned int context, X509 *x,
size_t chainidx)
{
#ifndef OPENSSL_NO_TLS1_3
size_t i, num_groups = 0;
const uint16_t *pgroups = NULL;
- uint16_t curve_id = 0;
+ uint16_t group_id = 0;
+ int add_only_one = 0;
+ size_t valid_keyshare = 0;
/* key_share extension */
if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_key_share)
- /* Extension data sub-packet */
+ /* Extension data sub-packet */
|| !WPACKET_start_sub_packet_u16(pkt)
- /* KeyShare list sub-packet */
+ /* KeyShare list sub-packet */
|| !WPACKET_start_sub_packet_u16(pkt)) {
SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
return EXT_RETURN_FAIL;
}
- tls1_get_supported_groups(s, &pgroups, &num_groups);
+ tls1_get_requested_keyshare_groups(s, &pgroups, &num_groups);
+ if (num_groups == 1 && pgroups[0] == 0) { /* Indication that no * prefix was used */
+ tls1_get_supported_groups(s, &pgroups, &num_groups);
+ add_only_one = 1;
+ }
- /*
- * Make the number of key_shares sent configurable. For
- * now, we just send one
- */
- if (s->s3.group_id != 0) {
- curve_id = s->s3.group_id;
+ /* If neither the default nor the keyshares have any entry --> fatal */
+ if (num_groups == 0) {
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_R_NO_SUITABLE_KEY_SHARE);
+ return EXT_RETURN_FAIL;
+ }
+
+ /* Add key shares */
+
+ if (s->s3.group_id != 0 && s->s3.tmp.pkey == NULL) {
+ /* new, single key share */
+ group_id = s->s3.group_id;
+ s->s3.tmp.num_ks_pkey = 0;
+ if (!add_key_share(s, pkt, group_id, 0)) {
+ /* SSLfatal() already called */
+ return EXT_RETURN_FAIL;
+ }
} else {
- for (i = 0; i < num_groups; i++) {
+ if (s->ext.supportedgroups == NULL) /* use default */
+ add_only_one = 1;
+ for (i = 0; i < num_groups; i++) {
if (!tls_group_allowed(s, pgroups[i], SSL_SECOP_CURVE_SUPPORTED))
continue;
-
if (!tls_valid_group(s, pgroups[i], TLS1_3_VERSION, TLS1_3_VERSION,
0, NULL))
continue;
- curve_id = pgroups[i];
- break;
- }
- }
+ group_id = pgroups[i];
- if (curve_id == 0) {
- SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_R_NO_SUITABLE_KEY_SHARE);
- return EXT_RETURN_FAIL;
- }
+ if (group_id == 0) {
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_R_NO_SUITABLE_KEY_SHARE);
+ return EXT_RETURN_FAIL;
+ }
+ if (!add_key_share(s, pkt, group_id, valid_keyshare)) {
+ /* SSLfatal() already called */
+ return EXT_RETURN_FAIL;
+ }
+ if (add_only_one)
+ break;
- if (!add_key_share(s, pkt, curve_id)) {
- /* SSLfatal() already called */
- return EXT_RETURN_FAIL;
+ valid_keyshare++;
+ }
}
if (!WPACKET_close(pkt) || !WPACKET_close(pkt)) {
@@ -708,7 +783,8 @@ EXT_RETURN tls_construct_ctos_key_share(SSL *s, WPACKET *pkt,
#endif
}
-EXT_RETURN tls_construct_ctos_cookie(SSL *s, WPACKET *pkt, unsigned int context,
+EXT_RETURN tls_construct_ctos_cookie(SSL_CONNECTION *s, WPACKET *pkt,
+ unsigned int context,
X509 *x, size_t chainidx)
{
EXT_RETURN ret = EXT_RETURN_FAIL;
@@ -736,7 +812,7 @@ EXT_RETURN tls_construct_ctos_cookie(SSL *s, WPACKET *pkt, unsigned int context,
return ret;
}
-EXT_RETURN tls_construct_ctos_early_data(SSL *s, WPACKET *pkt,
+EXT_RETURN tls_construct_ctos_early_data(SSL_CONNECTION *s, WPACKET *pkt,
unsigned int context, X509 *x,
size_t chainidx)
{
@@ -748,12 +824,13 @@ EXT_RETURN tls_construct_ctos_early_data(SSL *s, WPACKET *pkt,
SSL_SESSION *psksess = NULL;
SSL_SESSION *edsess = NULL;
const EVP_MD *handmd = NULL;
+ SSL *ussl = SSL_CONNECTION_GET_USER_SSL(s);
if (s->hello_retry_request == SSL_HRR_PENDING)
handmd = ssl_handshake_md(s);
if (s->psk_use_session_cb != NULL
- && (!s->psk_use_session_cb(s, handmd, &id, &idlen, &psksess)
+ && (!s->psk_use_session_cb(ussl, handmd, &id, &idlen, &psksess)
|| (psksess != NULL
&& psksess->ssl_version != TLS1_3_VERSION))) {
SSL_SESSION_free(psksess);
@@ -767,7 +844,8 @@ EXT_RETURN tls_construct_ctos_early_data(SSL *s, WPACKET *pkt,
size_t psklen = 0;
memset(identity, 0, sizeof(identity));
- psklen = s->psk_client_callback(s, NULL, identity, sizeof(identity) - 1,
+ psklen = s->psk_client_callback(ussl, NULL,
+ identity, sizeof(identity) - 1,
psk, sizeof(psk));
if (psklen > PSK_MAX_PSK_LEN) {
@@ -788,7 +866,8 @@ EXT_RETURN tls_construct_ctos_early_data(SSL *s, WPACKET *pkt,
* 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) {
SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
return EXT_RETURN_FAIL;
@@ -905,7 +984,7 @@ EXT_RETURN tls_construct_ctos_early_data(SSL *s, WPACKET *pkt,
*/
#define PSK_PRE_BINDER_OVERHEAD (2 + 2 + 2 + 2 + 4 + 2 + 1)
-EXT_RETURN tls_construct_ctos_padding(SSL *s, WPACKET *pkt,
+EXT_RETURN tls_construct_ctos_padding(SSL_CONNECTION *s, WPACKET *pkt,
unsigned int context, X509 *x,
size_t chainidx)
{
@@ -933,15 +1012,20 @@ EXT_RETURN tls_construct_ctos_padding(SSL *s, WPACKET *pkt,
if (s->session->ssl_version == TLS1_3_VERSION
&& s->session->ext.ticklen != 0
&& s->session->cipher != NULL) {
- const EVP_MD *md = ssl_md(s->ctx, s->session->cipher->algorithm2);
+ const EVP_MD *md = ssl_md(SSL_CONNECTION_GET_CTX(s),
+ s->session->cipher->algorithm2);
if (md != NULL) {
/*
* Add the fixed PSK overhead, the identity length and the binder
* length.
*/
+ int md_size = EVP_MD_get_size(md);
+
+ if (md_size <= 0)
+ return EXT_RETURN_FAIL;
hlen += PSK_PRE_BINDER_OVERHEAD + s->session->ext.ticklen
- + EVP_MD_get_size(md);
+ + md_size;
}
}
@@ -974,15 +1058,19 @@ EXT_RETURN tls_construct_ctos_padding(SSL *s, WPACKET *pkt,
/*
* Construct the pre_shared_key extension
*/
-EXT_RETURN tls_construct_ctos_psk(SSL *s, WPACKET *pkt, unsigned int context,
+EXT_RETURN tls_construct_ctos_psk(SSL_CONNECTION *s, WPACKET *pkt,
+ unsigned int context,
X509 *x, size_t chainidx)
{
#ifndef OPENSSL_NO_TLS1_3
uint32_t agesec, agems = 0;
- size_t reshashsize = 0, pskhashsize = 0, binderoffset, msglen;
+ size_t binderoffset, msglen;
+ int reshashsize = 0, pskhashsize = 0;
unsigned char *resbinder = NULL, *pskbinder = NULL, *msgstart = NULL;
const EVP_MD *handmd = NULL, *mdres = NULL, *mdpsk = NULL;
int dores = 0;
+ SSL_CTX *sctx = SSL_CONNECTION_GET_CTX(s);
+ OSSL_TIME t;
s->ext.tick_identity = 0;
@@ -1009,7 +1097,7 @@ EXT_RETURN tls_construct_ctos_psk(SSL *s, WPACKET *pkt, unsigned int context,
SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
return EXT_RETURN_FAIL;
}
- mdres = ssl_md(s->ctx, s->session->cipher->algorithm2);
+ mdres = ssl_md(sctx, s->session->cipher->algorithm2);
if (mdres == NULL) {
/*
* Don't recognize this cipher so we can't use the session.
@@ -1034,7 +1122,8 @@ EXT_RETURN tls_construct_ctos_psk(SSL *s, WPACKET *pkt, unsigned int context,
* this in multiple places in the code, so portability shouldn't be an
* issue.
*/
- agesec = (uint32_t)(time(NULL) - s->session->time);
+ t = ossl_time_subtract(ossl_time_now(), s->session->time);
+ agesec = (uint32_t)ossl_time2seconds(t);
/*
* We calculate the age in seconds but the server may work in ms. Due to
* rounding errors we could overestimate the age by up to 1s. It is
@@ -1072,6 +1161,8 @@ EXT_RETURN tls_construct_ctos_psk(SSL *s, WPACKET *pkt, unsigned int context,
agems += s->session->ext.tick_age_add;
reshashsize = EVP_MD_get_size(mdres);
+ if (reshashsize <= 0)
+ goto dopsksess;
s->ext.tick_identity++;
dores = 1;
}
@@ -1081,7 +1172,7 @@ EXT_RETURN tls_construct_ctos_psk(SSL *s, WPACKET *pkt, unsigned int context,
return EXT_RETURN_NOT_SENT;
if (s->psksession != NULL) {
- mdpsk = ssl_md(s->ctx, s->psksession->cipher->algorithm2);
+ mdpsk = ssl_md(sctx, s->psksession->cipher->algorithm2);
if (mdpsk == NULL) {
/*
* Don't recognize this cipher so we can't use the session.
@@ -1101,6 +1192,10 @@ EXT_RETURN tls_construct_ctos_psk(SSL *s, WPACKET *pkt, unsigned int context,
}
pskhashsize = EVP_MD_get_size(mdpsk);
+ if (pskhashsize <= 0) {
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_R_BAD_PSK);
+ return EXT_RETURN_FAIL;
+ }
}
/* Create the extension, but skip over the binder for now */
@@ -1171,7 +1266,7 @@ EXT_RETURN tls_construct_ctos_psk(SSL *s, WPACKET *pkt, unsigned int context,
#endif
}
-EXT_RETURN tls_construct_ctos_post_handshake_auth(SSL *s, WPACKET *pkt,
+EXT_RETURN tls_construct_ctos_post_handshake_auth(SSL_CONNECTION *s, WPACKET *pkt,
ossl_unused unsigned int context,
ossl_unused X509 *x,
ossl_unused size_t chainidx)
@@ -1200,7 +1295,8 @@ EXT_RETURN tls_construct_ctos_post_handshake_auth(SSL *s, WPACKET *pkt,
/*
* Parse the server's renegotiation binding and abort if it's not right
*/
-int tls_parse_stoc_renegotiate(SSL *s, PACKET *pkt, unsigned int context,
+int tls_parse_stoc_renegotiate(SSL_CONNECTION *s, PACKET *pkt,
+ unsigned int context,
X509 *x, size_t chainidx)
{
size_t expected_len = s->s3.previous_client_finished_len
@@ -1254,7 +1350,8 @@ int tls_parse_stoc_renegotiate(SSL *s, PACKET *pkt, unsigned int context,
}
/* Parse the server's max fragment len extension packet */
-int tls_parse_stoc_maxfragmentlen(SSL *s, PACKET *pkt, unsigned int context,
+int tls_parse_stoc_maxfragmentlen(SSL_CONNECTION *s, PACKET *pkt,
+ unsigned int context,
X509 *x, size_t chainidx)
{
unsigned int value;
@@ -1292,7 +1389,8 @@ int tls_parse_stoc_maxfragmentlen(SSL *s, PACKET *pkt, unsigned int context,
return 1;
}
-int tls_parse_stoc_server_name(SSL *s, PACKET *pkt, unsigned int context,
+int tls_parse_stoc_server_name(SSL_CONNECTION *s, PACKET *pkt,
+ unsigned int context,
X509 *x, size_t chainidx)
{
if (s->ext.hostname == NULL) {
@@ -1320,7 +1418,8 @@ int tls_parse_stoc_server_name(SSL *s, PACKET *pkt, unsigned int context,
return 1;
}
-int tls_parse_stoc_ec_pt_formats(SSL *s, PACKET *pkt, unsigned int context,
+int tls_parse_stoc_ec_pt_formats(SSL_CONNECTION *s, PACKET *pkt,
+ unsigned int context,
X509 *x, size_t chainidx)
{
size_t ecpointformats_len;
@@ -1359,13 +1458,16 @@ int tls_parse_stoc_ec_pt_formats(SSL *s, PACKET *pkt, unsigned int context,
return 1;
}
-int tls_parse_stoc_session_ticket(SSL *s, PACKET *pkt, unsigned int context,
+int tls_parse_stoc_session_ticket(SSL_CONNECTION *s, PACKET *pkt,
+ unsigned int context,
X509 *x, size_t chainidx)
{
+ SSL *ssl = SSL_CONNECTION_GET_USER_SSL(s);
+
if (s->ext.session_ticket_cb != NULL &&
- !s->ext.session_ticket_cb(s, PACKET_data(pkt),
- PACKET_remaining(pkt),
- s->ext.session_ticket_cb_arg)) {
+ !s->ext.session_ticket_cb(ssl, PACKET_data(pkt),
+ PACKET_remaining(pkt),
+ s->ext.session_ticket_cb_arg)) {
SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE, SSL_R_BAD_EXTENSION);
return 0;
}
@@ -1385,7 +1487,8 @@ int tls_parse_stoc_session_ticket(SSL *s, PACKET *pkt, unsigned int context,
}
#ifndef OPENSSL_NO_OCSP
-int tls_parse_stoc_status_request(SSL *s, PACKET *pkt, unsigned int context,
+int tls_parse_stoc_status_request(SSL_CONNECTION *s, PACKET *pkt,
+ unsigned int context,
X509 *x, size_t chainidx)
{
if (context == SSL_EXT_TLS1_3_CERTIFICATE_REQUEST) {
@@ -1401,12 +1504,12 @@ int tls_parse_stoc_status_request(SSL *s, PACKET *pkt, unsigned int context,
SSLfatal(s, SSL_AD_UNSUPPORTED_EXTENSION, SSL_R_BAD_EXTENSION);
return 0;
}
- if (!SSL_IS_TLS13(s) && PACKET_remaining(pkt) > 0) {
+ if (!SSL_CONNECTION_IS_TLS13(s) && PACKET_remaining(pkt) > 0) {
SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_R_BAD_EXTENSION);
return 0;
}
- if (SSL_IS_TLS13(s)) {
+ if (SSL_CONNECTION_IS_TLS13(s)) {
/* We only know how to handle this if it's for the first Certificate in
* the chain. We ignore any other responses.
*/
@@ -1426,8 +1529,8 @@ int tls_parse_stoc_status_request(SSL *s, PACKET *pkt, unsigned int context,
#ifndef OPENSSL_NO_CT
-int tls_parse_stoc_sct(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
- size_t chainidx)
+int tls_parse_stoc_sct(SSL_CONNECTION *s, PACKET *pkt, unsigned int context,
+ X509 *x, size_t chainidx)
{
if (context == SSL_EXT_TLS1_3_CERTIFICATE_REQUEST) {
/* We ignore this if the server sends it in a CertificateRequest */
@@ -1451,7 +1554,7 @@ int tls_parse_stoc_sct(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
s->ext.scts = OPENSSL_malloc(size);
if (s->ext.scts == NULL) {
s->ext.scts_len = 0;
- SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_MALLOC_FAILURE);
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_CRYPTO_LIB);
return 0;
}
if (!PACKET_copy_bytes(pkt, s->ext.scts, size)) {
@@ -1494,7 +1597,7 @@ int tls_parse_stoc_sct(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
* elements of zero length are allowed and the set of elements must exactly
* fill the length of the block. Returns 1 on success or 0 on failure.
*/
-static int ssl_next_proto_validate(SSL *s, PACKET *pkt)
+static int ssl_next_proto_validate(SSL_CONNECTION *s, PACKET *pkt)
{
PACKET tmp_protocol;
@@ -1509,19 +1612,20 @@ static int ssl_next_proto_validate(SSL *s, PACKET *pkt)
return 1;
}
-int tls_parse_stoc_npn(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
- size_t chainidx)
+int tls_parse_stoc_npn(SSL_CONNECTION *s, PACKET *pkt, unsigned int context,
+ X509 *x, size_t chainidx)
{
unsigned char *selected;
unsigned char selected_len;
PACKET tmppkt;
+ SSL_CTX *sctx = SSL_CONNECTION_GET_CTX(s);
/* Check if we are in a renegotiation. If so ignore this extension */
if (!SSL_IS_FIRST_HANDSHAKE(s))
return 1;
/* We must have requested it. */
- if (s->ctx->ext.npn_select_cb == NULL) {
+ if (sctx->ext.npn_select_cb == NULL) {
SSLfatal(s, SSL_AD_UNSUPPORTED_EXTENSION, SSL_R_BAD_EXTENSION);
return 0;
}
@@ -1532,11 +1636,10 @@ int tls_parse_stoc_npn(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
/* SSLfatal() already called */
return 0;
}
- if (s->ctx->ext.npn_select_cb(s, &selected, &selected_len,
- PACKET_data(pkt),
- PACKET_remaining(pkt),
- s->ctx->ext.npn_select_cb_arg) !=
- SSL_TLSEXT_ERR_OK
+ if (sctx->ext.npn_select_cb(SSL_CONNECTION_GET_USER_SSL(s),
+ &selected, &selected_len,
+ PACKET_data(pkt), PACKET_remaining(pkt),
+ sctx->ext.npn_select_cb_arg) != SSL_TLSEXT_ERR_OK
|| selected_len == 0) {
SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE, SSL_R_BAD_EXTENSION);
return 0;
@@ -1562,8 +1665,8 @@ int tls_parse_stoc_npn(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
}
#endif
-int tls_parse_stoc_alpn(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
- size_t chainidx)
+int tls_parse_stoc_alpn(SSL_CONNECTION *s, PACKET *pkt, unsigned int context,
+ X509 *x, size_t chainidx)
{
size_t len;
PACKET confpkt, protpkt;
@@ -1651,8 +1754,8 @@ int tls_parse_stoc_alpn(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
}
#ifndef OPENSSL_NO_SRTP
-int tls_parse_stoc_use_srtp(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
- size_t chainidx)
+int tls_parse_stoc_use_srtp(SSL_CONNECTION *s, PACKET *pkt,
+ unsigned int context, X509 *x, size_t chainidx)
{
unsigned int id, ct, mki;
int i;
@@ -1675,7 +1778,7 @@ int tls_parse_stoc_use_srtp(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
}
/* Throw an error if the server gave us an unsolicited extension */
- clnt = SSL_get_srtp_profiles(s);
+ clnt = SSL_get_srtp_profiles(SSL_CONNECTION_GET_SSL(s));
if (clnt == NULL) {
SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_R_NO_SRTP_PROFILES);
return 0;
@@ -1700,8 +1803,8 @@ int tls_parse_stoc_use_srtp(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
}
#endif
-int tls_parse_stoc_etm(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
- size_t chainidx)
+int tls_parse_stoc_etm(SSL_CONNECTION *s, PACKET *pkt, unsigned int context,
+ X509 *x, size_t chainidx)
{
/* Ignore if inappropriate ciphersuite */
if (!(s->options & SSL_OP_NO_ENCRYPT_THEN_MAC)
@@ -1716,8 +1819,8 @@ int tls_parse_stoc_etm(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
return 1;
}
-int tls_parse_stoc_ems(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
- size_t chainidx)
+int tls_parse_stoc_ems(SSL_CONNECTION *s, PACKET *pkt, unsigned int context,
+ X509 *x, size_t chainidx)
{
if (s->options & SSL_OP_NO_EXTENDED_MASTER_SECRET)
return 1;
@@ -1728,7 +1831,8 @@ int tls_parse_stoc_ems(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
return 1;
}
-int tls_parse_stoc_supported_versions(SSL *s, PACKET *pkt, unsigned int context,
+int tls_parse_stoc_supported_versions(SSL_CONNECTION *s, PACKET *pkt,
+ unsigned int context,
X509 *x, size_t chainidx)
{
unsigned int version;
@@ -1755,11 +1859,16 @@ int tls_parse_stoc_supported_versions(SSL *s, PACKET *pkt, unsigned int context,
/* We just set it here. We validate it in ssl_choose_client_version */
s->version = version;
+ if (!ssl_set_record_protocol_version(s, version)) {
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
return 1;
}
-int tls_parse_stoc_key_share(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+int tls_parse_stoc_key_share(SSL_CONNECTION *s, PACKET *pkt,
+ unsigned int context, X509 *x,
size_t chainidx)
{
#ifndef OPENSSL_NO_TLS1_3
@@ -1767,6 +1876,8 @@ int tls_parse_stoc_key_share(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
PACKET encoded_pt;
EVP_PKEY *ckey = s->s3.tmp.pkey, *skey = NULL;
const TLS_GROUP_INFO *ginf = NULL;
+ uint16_t valid_ks_id = 0;
+ size_t i;
/* Sanity check */
if (ckey == NULL || s->s3.peer_tmp != NULL) {
@@ -1774,6 +1885,7 @@ int tls_parse_stoc_key_share(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
return 0;
}
+ /* Which group ID does the server want -> group_id */
if (!PACKET_get_net_2(pkt, &group_id)) {
SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_R_LENGTH_MISMATCH);
return 0;
@@ -1781,7 +1893,7 @@ int tls_parse_stoc_key_share(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
if ((context & SSL_EXT_TLS1_3_HELLO_RETRY_REQUEST) != 0) {
const uint16_t *pgroups = NULL;
- size_t i, num_groups;
+ size_t num_groups;
if (PACKET_remaining(pkt) != 0) {
SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_R_LENGTH_MISMATCH);
@@ -1792,9 +1904,11 @@ int tls_parse_stoc_key_share(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
* It is an error if the HelloRetryRequest wants a key_share that we
* already sent in the first ClientHello
*/
- if (group_id == s->s3.group_id) {
- SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_R_BAD_KEY_SHARE);
- return 0;
+ for (i = 0; i < s->s3.tmp.num_ks_pkey; i++) {
+ if (s->s3.tmp.ks_group_id[i] == group_id) {
+ SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_R_BAD_KEY_SHARE);
+ return 0;
+ }
}
/* Validate the selected group is one we support */
@@ -1811,13 +1925,36 @@ int tls_parse_stoc_key_share(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
return 0;
}
+ /* Memorize which groupID the server wants */
s->s3.group_id = group_id;
- EVP_PKEY_free(s->s3.tmp.pkey);
+
+ /* The initial keyshares are obsolete now, hence free memory */
+ for (i = 0; i < s->s3.tmp.num_ks_pkey; i++) {
+ if (s->s3.tmp.ks_pkey[i] != NULL) {
+ EVP_PKEY_free(s->s3.tmp.ks_pkey[i]);
+ s->s3.tmp.ks_pkey[i] = NULL;
+ }
+ }
+ s->s3.tmp.num_ks_pkey = 0;
s->s3.tmp.pkey = NULL;
+
return 1;
}
- if (group_id != s->s3.group_id) {
+ /*
+ * check that the group requested by the server is one we've
+ * sent a key share for, and if so: memorize which one
+ */
+ for (i = 0; i < s->s3.tmp.num_ks_pkey; i++) {
+ if (s->s3.tmp.ks_group_id[i] == group_id) {
+ valid_ks_id = group_id;
+ ckey = s->s3.tmp.ks_pkey[i];
+ s->s3.group_id = group_id;
+ s->s3.tmp.pkey = ckey;
+ break;
+ }
+ }
+ if (valid_ks_id == 0) {
/*
* This isn't for the group that we sent in the original
* key_share!
@@ -1840,7 +1977,7 @@ int tls_parse_stoc_key_share(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
SSL_SESSION *new_sess;
if ((new_sess = ssl_session_dup(s->session, 0)) == NULL) {
- SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_MALLOC_FAILURE);
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_SSL_LIB);
return 0;
}
SSL_SESSION_free(s->session);
@@ -1848,7 +1985,8 @@ int tls_parse_stoc_key_share(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
s->session->kex_group = group_id;
}
- if ((ginf = tls1_group_id_lookup(s->ctx, group_id)) == NULL) {
+ if ((ginf = tls1_group_id_lookup(SSL_CONNECTION_GET_CTX(s),
+ group_id)) == NULL) {
SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_R_BAD_KEY_SHARE);
return 0;
}
@@ -1897,8 +2035,8 @@ int tls_parse_stoc_key_share(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
return 1;
}
-int tls_parse_stoc_cookie(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
- size_t chainidx)
+int tls_parse_stoc_cookie(SSL_CONNECTION *s, PACKET *pkt, unsigned int context,
+ X509 *x, size_t chainidx)
{
PACKET cookie;
@@ -1912,7 +2050,8 @@ int tls_parse_stoc_cookie(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
return 1;
}
-int tls_parse_stoc_early_data(SSL *s, PACKET *pkt, unsigned int context,
+int tls_parse_stoc_early_data(SSL_CONNECTION *s, PACKET *pkt,
+ unsigned int context,
X509 *x, size_t chainidx)
{
if (context == SSL_EXT_TLS1_3_NEW_SESSION_TICKET) {
@@ -1926,6 +2065,22 @@ int tls_parse_stoc_early_data(SSL *s, PACKET *pkt, unsigned int context,
s->session->ext.max_early_data = max_early_data;
+ if (SSL_IS_QUIC_HANDSHAKE(s) && max_early_data != 0xffffffff) {
+ /*
+ * QUIC allows missing max_early_data, or a max_early_data value
+ * of 0xffffffff. Missing max_early_data is stored in the session
+ * as 0. This is indistinguishable in OpenSSL from a present
+ * max_early_data value that was 0. In order that later checks for
+ * invalid max_early_data correctly treat as an error the case where
+ * max_early_data is present and it is 0, we store any invalid
+ * value in the same (non-zero) way. Otherwise we would have to
+ * introduce a new flag just for this.
+ */
+ s->session->ext.max_early_data = 1;
+ SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_R_INVALID_MAX_EARLY_DATA);
+ return 0;
+ }
+
return 1;
}
@@ -1950,7 +2105,8 @@ int tls_parse_stoc_early_data(SSL *s, PACKET *pkt, unsigned int context,
return 1;
}
-int tls_parse_stoc_psk(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+int tls_parse_stoc_psk(SSL_CONNECTION *s, PACKET *pkt,
+ unsigned int context, X509 *x,
size_t chainidx)
{
#ifndef OPENSSL_NO_TLS1_3
@@ -2006,3 +2162,107 @@ int tls_parse_stoc_psk(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
return 1;
}
+
+EXT_RETURN tls_construct_ctos_client_cert_type(SSL_CONNECTION *sc, WPACKET *pkt,
+ unsigned int context,
+ X509 *x, size_t chainidx)
+{
+ sc->ext.client_cert_type_ctos = OSSL_CERT_TYPE_CTOS_NONE;
+ if (sc->client_cert_type == NULL)
+ return EXT_RETURN_NOT_SENT;
+
+ if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_client_cert_type)
+ || !WPACKET_start_sub_packet_u16(pkt)
+ || !WPACKET_sub_memcpy_u8(pkt, sc->client_cert_type, sc->client_cert_type_len)
+ || !WPACKET_close(pkt)) {
+ SSLfatal(sc, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+ return EXT_RETURN_FAIL;
+ }
+ sc->ext.client_cert_type_ctos = OSSL_CERT_TYPE_CTOS_GOOD;
+ return EXT_RETURN_SENT;
+}
+
+int tls_parse_stoc_client_cert_type(SSL_CONNECTION *sc, PACKET *pkt,
+ unsigned int context,
+ X509 *x, size_t chainidx)
+{
+ unsigned int type;
+
+ if (PACKET_remaining(pkt) != 1) {
+ SSLfatal(sc, SSL_AD_DECODE_ERROR, SSL_R_BAD_EXTENSION);
+ return 0;
+ }
+ if (!PACKET_get_1(pkt, &type)) {
+ SSLfatal(sc, SSL_AD_DECODE_ERROR, SSL_R_BAD_EXTENSION);
+ return 0;
+ }
+ /* We did not send/ask for this */
+ if (!ossl_assert(sc->ext.client_cert_type_ctos == OSSL_CERT_TYPE_CTOS_GOOD)) {
+ SSLfatal(sc, SSL_AD_DECODE_ERROR, SSL_R_BAD_EXTENSION);
+ return 0;
+ }
+ /* We don't have this enabled */
+ if (sc->client_cert_type == NULL) {
+ SSLfatal(sc, SSL_AD_DECODE_ERROR, SSL_R_BAD_EXTENSION);
+ return 0;
+ }
+ /* Given back a value we didn't configure */
+ if (memchr(sc->client_cert_type, type, sc->client_cert_type_len) == NULL) {
+ SSLfatal(sc, SSL_AD_DECODE_ERROR, SSL_R_BAD_VALUE);
+ return 0;
+ }
+ sc->ext.client_cert_type = type;
+ return 1;
+}
+
+EXT_RETURN tls_construct_ctos_server_cert_type(SSL_CONNECTION *sc, WPACKET *pkt,
+ unsigned int context,
+ X509 *x, size_t chainidx)
+{
+ sc->ext.server_cert_type_ctos = OSSL_CERT_TYPE_CTOS_NONE;
+ if (sc->server_cert_type == NULL)
+ return EXT_RETURN_NOT_SENT;
+
+ if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_server_cert_type)
+ || !WPACKET_start_sub_packet_u16(pkt)
+ || !WPACKET_sub_memcpy_u8(pkt, sc->server_cert_type, sc->server_cert_type_len)
+ || !WPACKET_close(pkt)) {
+ SSLfatal(sc, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+ return EXT_RETURN_FAIL;
+ }
+ sc->ext.server_cert_type_ctos = OSSL_CERT_TYPE_CTOS_GOOD;
+ return EXT_RETURN_SENT;
+}
+
+int tls_parse_stoc_server_cert_type(SSL_CONNECTION *sc, PACKET *pkt,
+ unsigned int context,
+ X509 *x, size_t chainidx)
+{
+ unsigned int type;
+
+ if (PACKET_remaining(pkt) != 1) {
+ SSLfatal(sc, SSL_AD_DECODE_ERROR, SSL_R_BAD_EXTENSION);
+ return 0;
+ }
+ if (!PACKET_get_1(pkt, &type)) {
+ SSLfatal(sc, SSL_AD_DECODE_ERROR, SSL_R_BAD_EXTENSION);
+ return 0;
+ }
+ /* We did not send/ask for this */
+ if (!ossl_assert(sc->ext.server_cert_type_ctos == OSSL_CERT_TYPE_CTOS_GOOD)) {
+ SSLfatal(sc, SSL_AD_DECODE_ERROR, SSL_R_BAD_EXTENSION);
+ return 0;
+ }
+ /* We don't have this enabled */
+ if (sc->server_cert_type == NULL) {
+ SSLfatal(sc, SSL_AD_DECODE_ERROR, SSL_R_BAD_EXTENSION);
+ return 0;
+ }
+ /* Given back a value we didn't configure */
+ if (memchr(sc->server_cert_type, type, sc->server_cert_type_len) == NULL) {
+ SSLfatal(sc, SSL_AD_DECODE_ERROR, SSL_R_BAD_VALUE);
+ return 0;
+ }
+ sc->ext.server_cert_type = type;
+ return 1;
+}