-/* $OpenBSD: ssl_tlsext.c,v 1.140 2024/03/25 05:48:39 tb Exp $ */
+/* $OpenBSD: ssl_tlsext.c,v 1.141 2024/03/25 10:18:13 jsing Exp $ */
/*
* Copyright (c) 2016, 2017, 2019 Joel Sing <jsing@openbsd.org>
* Copyright (c) 2017 Doug Hogan <doug@openbsd.org>
#define TLSEXT_TYPE_alpn TLSEXT_TYPE_application_layer_protocol_negotiation
-struct tlsext_data {
- CBS alpn;
-};
-
-static struct tlsext_data *
-tlsext_data_new(void)
-{
- return calloc(1, sizeof(struct tlsext_data));
-}
-
-static void
-tlsext_data_free(struct tlsext_data *td)
-{
- freezero(td, sizeof(*td));
-}
-
/*
* Supported Application-Layer Protocol Negotiation - RFC 7301
*/
}
static int
-tlsext_alpn_server_parse(SSL *s, struct tlsext_data *td, uint16_t msg_type,
- CBS *cbs, int *alert)
-{
- CBS alpn;
-
- if (!CBS_get_u16_length_prefixed(cbs, &alpn))
- return 0;
- if (!tlsext_alpn_check_format(&alpn))
- return 0;
-
- CBS_dup(&alpn, &td->alpn);
-
- return 1;
-}
-
-static int
-tlsext_alpn_server_process(SSL *s, struct tlsext_data *td, uint16_t msg_type,
- int *alert)
+tlsext_alpn_server_process(SSL *s, uint16_t msg_type, CBS *cbs, int *alert)
{
- CBS selected_cbs;
+ CBS alpn, selected_cbs;
const unsigned char *selected;
unsigned char selected_len;
int r;
- if (CBS_data(&td->alpn) == NULL)
+ if (!CBS_get_u16_length_prefixed(cbs, &alpn))
+ return 0;
+ if (!tlsext_alpn_check_format(&alpn))
return 0;
if (s->ctx->alpn_select_cb == NULL)
* 3. TLSv1.2 and earlier: ensure that SNI has already been processed.
*/
r = s->ctx->alpn_select_cb(s, &selected, &selected_len,
- CBS_data(&td->alpn), CBS_len(&td->alpn),
- s->ctx->alpn_select_cb_arg);
+ CBS_data(&alpn), CBS_len(&alpn), s->ctx->alpn_select_cb_arg);
if (r == SSL_TLSEXT_ERR_OK) {
CBS_init(&selected_cbs, selected, selected_len);
}
static int
-tlsext_alpn_client_parse(SSL *s, struct tlsext_data *td, uint16_t msg_type,
- CBS *cbs, int *alert)
+tlsext_alpn_client_process(SSL *s, uint16_t msg_type, CBS *cbs, int *alert)
{
CBS list, proto;
if (CBS_len(&proto) == 0)
return 0;
- CBS_dup(&proto, &td->alpn);
-
- return 1;
-}
-
-static int
-tlsext_alpn_client_process(SSL *s, struct tlsext_data *td, uint16_t msg_type,
- int *alert)
-{
- if (CBS_data(&td->alpn) == NULL)
- return 0;
- if (!CBS_stow(&td->alpn, &s->s3->alpn_selected, &s->s3->alpn_selected_len))
+ if (!CBS_stow(&proto, &s->s3->alpn_selected, &s->s3->alpn_selected_len))
return 0;
return 1;
}
static int
-tlsext_supportedgroups_server_parse(SSL *s, struct tlsext_data *td,
- uint16_t msg_type, CBS *cbs, int *alert)
+tlsext_supportedgroups_server_process(SSL *s, uint16_t msg_type, CBS *cbs,
+ int *alert)
{
CBS grouplist;
uint16_t *groups;
}
static int
-tlsext_supportedgroups_client_parse(SSL *s, struct tlsext_data *td,
- uint16_t msg_type, CBS *cbs, int *alert)
+tlsext_supportedgroups_client_process(SSL *s, uint16_t msg_type, CBS *cbs,
+ int *alert)
{
/*
* Servers should not send this extension per the RFC.
}
static int
-tlsext_ecpf_parse(SSL *s, struct tlsext_data *td, uint16_t msg_type, CBS *cbs,
- int *alert)
+tlsext_ecpf_process(SSL *s, uint16_t msg_type, CBS *cbs, int *alert)
{
CBS ecpf;
}
static int
-tlsext_ecpf_server_parse(SSL *s, struct tlsext_data *td, uint16_t msg_type,
- CBS *cbs, int *alert)
+tlsext_ecpf_server_process(SSL *s, uint16_t msg_type, CBS *cbs, int *alert)
{
- return tlsext_ecpf_parse(s, td, msg_type, cbs, alert);
+ return tlsext_ecpf_process(s, msg_type, cbs, alert);
}
static int
}
static int
-tlsext_ecpf_client_parse(SSL *s, struct tlsext_data *td, uint16_t msg_type,
- CBS *cbs, int *alert)
+tlsext_ecpf_client_process(SSL *s, uint16_t msg_type, CBS *cbs, int *alert)
{
- return tlsext_ecpf_parse(s, td, msg_type, cbs, alert);
+ return tlsext_ecpf_process(s, msg_type, cbs, alert);
}
/*
}
static int
-tlsext_ri_server_parse(SSL *s, struct tlsext_data *td, uint16_t msg_type,
- CBS *cbs, int *alert)
+tlsext_ri_server_process(SSL *s, uint16_t msg_type, CBS *cbs, int *alert)
{
CBS reneg;
}
static int
-tlsext_ri_client_parse(SSL *s, struct tlsext_data *td, uint16_t msg_type,
- CBS *cbs, int *alert)
+tlsext_ri_client_process(SSL *s, uint16_t msg_type, CBS *cbs, int *alert)
{
CBS reneg, prev_client, prev_server;
}
static int
-tlsext_sigalgs_server_parse(SSL *s, struct tlsext_data *td, uint16_t msg_type,
- CBS *cbs, int *alert)
+tlsext_sigalgs_server_process(SSL *s, uint16_t msg_type, CBS *cbs, int *alert)
{
CBS sigalgs;
}
static int
-tlsext_sigalgs_client_parse(SSL *s, struct tlsext_data *td, uint16_t msg_type,
- CBS *cbs, int *alert)
+tlsext_sigalgs_client_process(SSL *s, uint16_t msg_type, CBS *cbs, int *alert)
{
CBS sigalgs;
}
static int
-tlsext_sni_server_parse(SSL *s, struct tlsext_data *td, uint16_t msg_type,
- CBS *cbs, int *alert)
+tlsext_sni_server_process(SSL *s, uint16_t msg_type, CBS *cbs, int *alert)
{
CBS server_name_list, host_name;
uint8_t name_type;
}
static int
-tlsext_sni_client_parse(SSL *s, struct tlsext_data *td, uint16_t msg_type,
- CBS *cbs, int *alert)
+tlsext_sni_client_process(SSL *s, uint16_t msg_type, CBS *cbs, int *alert)
{
if (s->tlsext_hostname == NULL || CBS_len(cbs) != 0) {
*alert = SSL_AD_UNRECOGNIZED_NAME;
}
static int
-tlsext_ocsp_server_parse(SSL *s, struct tlsext_data *td, uint16_t msg_type,
- CBS *cbs, int *alert)
+tlsext_ocsp_server_process(SSL *s, uint16_t msg_type, CBS *cbs, int *alert)
{
int alert_desc = SSL_AD_DECODE_ERROR;
CBS respid_list, respid, exts;
}
static int
-tlsext_ocsp_client_parse(SSL *s, struct tlsext_data *td, uint16_t msg_type,
- CBS *cbs, int *alert)
+tlsext_ocsp_client_process(SSL *s, uint16_t msg_type, CBS *cbs, int *alert)
{
uint8_t status_type;
CBS response;
}
static int
-tlsext_sessionticket_server_parse(SSL *s, struct tlsext_data *td,
- uint16_t msg_type, CBS *cbs, int *alert)
+tlsext_sessionticket_server_process(SSL *s, uint16_t msg_type, CBS *cbs,
+ int *alert)
{
if (s->tls_session_ticket_ext_cb) {
if (!s->tls_session_ticket_ext_cb(s, CBS_data(cbs),
}
static int
-tlsext_sessionticket_client_parse(SSL *s, struct tlsext_data *td,
- uint16_t msg_type, CBS *cbs, int *alert)
+tlsext_sessionticket_client_process(SSL *s, uint16_t msg_type, CBS *cbs,
+ int *alert)
{
if (s->tls_session_ticket_ext_cb) {
if (!s->tls_session_ticket_ext_cb(s, CBS_data(cbs),
}
static int
-tlsext_srtp_server_parse(SSL *s, struct tlsext_data *td, uint16_t msg_type,
- CBS *cbs, int *alert)
+tlsext_srtp_server_process(SSL *s, uint16_t msg_type, CBS *cbs, int *alert)
{
const SRTP_PROTECTION_PROFILE *cprof, *sprof;
STACK_OF(SRTP_PROTECTION_PROFILE) *clnt = NULL, *srvr;
}
static int
-tlsext_srtp_client_parse(SSL *s, struct tlsext_data *td, uint16_t msg_type,
- CBS *cbs, int *alert)
+tlsext_srtp_client_process(SSL *s, uint16_t msg_type, CBS *cbs, int *alert)
{
STACK_OF(SRTP_PROTECTION_PROFILE) *clnt;
const SRTP_PROTECTION_PROFILE *prof;
}
static int
-tlsext_keyshare_server_parse(SSL *s, struct tlsext_data *td, uint16_t msg_type,
- CBS *cbs, int *alert)
+tlsext_keyshare_server_process(SSL *s, uint16_t msg_type, CBS *cbs, int *alert)
{
CBS client_shares, key_exchange;
int decode_error;
}
static int
-tlsext_keyshare_client_parse(SSL *s, struct tlsext_data *td, uint16_t msg_type,
- CBS *cbs, int *alert)
+tlsext_keyshare_client_process(SSL *s, uint16_t msg_type, CBS *cbs, int *alert)
{
CBS key_exchange;
int decode_error;
}
static int
-tlsext_versions_server_parse(SSL *s, struct tlsext_data *td, uint16_t msg_type,
- CBS *cbs, int *alert)
+tlsext_versions_server_process(SSL *s, uint16_t msg_type, CBS *cbs, int *alert)
{
CBS versions;
uint16_t version;
}
static int
-tlsext_versions_client_parse(SSL *s, struct tlsext_data *td, uint16_t msg_type,
- CBS *cbs, int *alert)
+tlsext_versions_client_process(SSL *s, uint16_t msg_type, CBS *cbs, int *alert)
{
uint16_t selected_version;
}
static int
-tlsext_cookie_server_parse(SSL *s, struct tlsext_data *td, uint16_t msg_type,
- CBS *cbs, int *alert)
+tlsext_cookie_server_process(SSL *s, uint16_t msg_type, CBS *cbs, int *alert)
{
CBS cookie;
}
static int
-tlsext_cookie_client_parse(SSL *s, struct tlsext_data *td, uint16_t msg_type,
- CBS *cbs, int *alert)
+tlsext_cookie_client_process(SSL *s, uint16_t msg_type, CBS *cbs, int *alert)
{
CBS cookie;
}
static int
-tlsext_psk_kex_modes_server_parse(SSL *s, struct tlsext_data *td,
- uint16_t msg_type, CBS *cbs, int *alert)
+tlsext_psk_kex_modes_server_process(SSL *s, uint16_t msg_type, CBS *cbs,
+ int *alert)
{
CBS ke_modes;
uint8_t ke_mode;
}
static int
-tlsext_psk_kex_modes_client_parse(SSL *s, struct tlsext_data *td,
- uint16_t msg_type, CBS *cbs, int *alert)
+tlsext_psk_kex_modes_client_process(SSL *s, uint16_t msg_type, CBS *cbs,
+ int *alert)
{
return 0;
}
}
static int
-tlsext_psk_client_parse(SSL *s, struct tlsext_data *td, uint16_t msg_type,
- CBS *cbs, int *alert)
+tlsext_psk_client_process(SSL *s, uint16_t msg_type, CBS *cbs, int *alert)
{
return CBS_skip(cbs, CBS_len(cbs));
}
}
static int
-tlsext_psk_server_parse(SSL *s, struct tlsext_data *td, uint16_t msg_type,
- CBS *cbs, int *alert)
+tlsext_psk_server_process(SSL *s, uint16_t msg_type, CBS *cbs, int *alert)
{
return CBS_skip(cbs, CBS_len(cbs));
}
}
static int
-tlsext_quic_transport_parameters_client_parse(SSL *s, struct tlsext_data *td,
- uint16_t msg_type, CBS *cbs, int *alert)
+tlsext_quic_transport_parameters_client_process(SSL *s, uint16_t msg_type,
+ CBS *cbs, int *alert)
{
if (!SSL_is_quic(s)) {
*alert = SSL_AD_UNSUPPORTED_EXTENSION;
}
static int
-tlsext_quic_transport_parameters_server_parse(SSL *s, struct tlsext_data *td,
- uint16_t msg_type, CBS *cbs, int *alert)
+tlsext_quic_transport_parameters_server_process(SSL *s, uint16_t msg_type,
+ CBS *cbs, int *alert)
{
if (!SSL_is_quic(s)) {
*alert = SSL_AD_UNSUPPORTED_EXTENSION;
struct tls_extension_funcs {
int (*needs)(SSL *s, uint16_t msg_type);
int (*build)(SSL *s, uint16_t msg_type, CBB *cbb);
- int (*parse)(SSL *s, struct tlsext_data *td, uint16_t msg_type,
- CBS *cbs, int *alert);
- int (*process)(SSL *s, struct tlsext_data *td, uint16_t msg_type,
- int *alert);
+ int (*process)(SSL *s, uint16_t msg_type, CBS *cbs, int *alert);
};
struct tls_extension {
.client = {
.needs = tlsext_versions_client_needs,
.build = tlsext_versions_client_build,
- .parse = tlsext_versions_client_parse,
+ .process = tlsext_versions_client_process,
},
.server = {
.needs = tlsext_versions_server_needs,
.build = tlsext_versions_server_build,
- .parse = tlsext_versions_server_parse,
+ .process = tlsext_versions_server_process,
},
},
{
.client = {
.needs = tlsext_keyshare_client_needs,
.build = tlsext_keyshare_client_build,
- .parse = tlsext_keyshare_client_parse,
+ .process = tlsext_keyshare_client_process,
},
.server = {
.needs = tlsext_keyshare_server_needs,
.build = tlsext_keyshare_server_build,
- .parse = tlsext_keyshare_server_parse,
+ .process = tlsext_keyshare_server_process,
},
},
{
.client = {
.needs = tlsext_sni_client_needs,
.build = tlsext_sni_client_build,
- .parse = tlsext_sni_client_parse,
+ .process = tlsext_sni_client_process,
},
.server = {
.needs = tlsext_sni_server_needs,
.build = tlsext_sni_server_build,
- .parse = tlsext_sni_server_parse,
+ .process = tlsext_sni_server_process,
},
},
{
.client = {
.needs = tlsext_ri_client_needs,
.build = tlsext_ri_client_build,
- .parse = tlsext_ri_client_parse,
+ .process = tlsext_ri_client_process,
},
.server = {
.needs = tlsext_ri_server_needs,
.build = tlsext_ri_server_build,
- .parse = tlsext_ri_server_parse,
+ .process = tlsext_ri_server_process,
},
},
{
.client = {
.needs = tlsext_ocsp_client_needs,
.build = tlsext_ocsp_client_build,
- .parse = tlsext_ocsp_client_parse,
+ .process = tlsext_ocsp_client_process,
},
.server = {
.needs = tlsext_ocsp_server_needs,
.build = tlsext_ocsp_server_build,
- .parse = tlsext_ocsp_server_parse,
+ .process = tlsext_ocsp_server_process,
},
},
{
.client = {
.needs = tlsext_ecpf_client_needs,
.build = tlsext_ecpf_client_build,
- .parse = tlsext_ecpf_client_parse,
+ .process = tlsext_ecpf_client_process,
},
.server = {
.needs = tlsext_ecpf_server_needs,
.build = tlsext_ecpf_server_build,
- .parse = tlsext_ecpf_server_parse,
+ .process = tlsext_ecpf_server_process,
},
},
{
.client = {
.needs = tlsext_supportedgroups_client_needs,
.build = tlsext_supportedgroups_client_build,
- .parse = tlsext_supportedgroups_client_parse,
+ .process = tlsext_supportedgroups_client_process,
},
.server = {
.needs = tlsext_supportedgroups_server_needs,
.build = tlsext_supportedgroups_server_build,
- .parse = tlsext_supportedgroups_server_parse,
+ .process = tlsext_supportedgroups_server_process,
},
},
{
.client = {
.needs = tlsext_sessionticket_client_needs,
.build = tlsext_sessionticket_client_build,
- .parse = tlsext_sessionticket_client_parse,
+ .process = tlsext_sessionticket_client_process,
},
.server = {
.needs = tlsext_sessionticket_server_needs,
.build = tlsext_sessionticket_server_build,
- .parse = tlsext_sessionticket_server_parse,
+ .process = tlsext_sessionticket_server_process,
},
},
{
.client = {
.needs = tlsext_sigalgs_client_needs,
.build = tlsext_sigalgs_client_build,
- .parse = tlsext_sigalgs_client_parse,
+ .process = tlsext_sigalgs_client_process,
},
.server = {
.needs = tlsext_sigalgs_server_needs,
.build = tlsext_sigalgs_server_build,
- .parse = tlsext_sigalgs_server_parse,
+ .process = tlsext_sigalgs_server_process,
},
},
{
.client = {
.needs = tlsext_alpn_client_needs,
.build = tlsext_alpn_client_build,
- .parse = tlsext_alpn_client_parse,
.process = tlsext_alpn_client_process,
},
.server = {
.needs = tlsext_alpn_server_needs,
.build = tlsext_alpn_server_build,
- .parse = tlsext_alpn_server_parse,
.process = tlsext_alpn_server_process,
},
},
.client = {
.needs = tlsext_cookie_client_needs,
.build = tlsext_cookie_client_build,
- .parse = tlsext_cookie_client_parse,
+ .process = tlsext_cookie_client_process,
},
.server = {
.needs = tlsext_cookie_server_needs,
.build = tlsext_cookie_server_build,
- .parse = tlsext_cookie_server_parse,
+ .process = tlsext_cookie_server_process,
},
},
#ifndef OPENSSL_NO_SRTP
.client = {
.needs = tlsext_srtp_client_needs,
.build = tlsext_srtp_client_build,
- .parse = tlsext_srtp_client_parse,
+ .process = tlsext_srtp_client_process,
},
.server = {
.needs = tlsext_srtp_server_needs,
.build = tlsext_srtp_server_build,
- .parse = tlsext_srtp_server_parse,
+ .process = tlsext_srtp_server_process,
},
},
#endif /* OPENSSL_NO_SRTP */
.client = {
.needs = tlsext_quic_transport_parameters_client_needs,
.build = tlsext_quic_transport_parameters_client_build,
- .parse = tlsext_quic_transport_parameters_client_parse,
+ .process = tlsext_quic_transport_parameters_client_process,
},
.server = {
.needs = tlsext_quic_transport_parameters_server_needs,
.build = tlsext_quic_transport_parameters_server_build,
- .parse = tlsext_quic_transport_parameters_server_parse,
+ .process = tlsext_quic_transport_parameters_server_process,
},
},
{
.client = {
.needs = tlsext_psk_kex_modes_client_needs,
.build = tlsext_psk_kex_modes_client_build,
- .parse = tlsext_psk_kex_modes_client_parse,
+ .process = tlsext_psk_kex_modes_client_process,
},
.server = {
.needs = tlsext_psk_kex_modes_server_needs,
.build = tlsext_psk_kex_modes_server_build,
- .parse = tlsext_psk_kex_modes_server_parse,
+ .process = tlsext_psk_kex_modes_server_process,
},
},
{
.client = {
.needs = tlsext_psk_client_needs,
.build = tlsext_psk_client_build,
- .parse = tlsext_psk_client_parse,
+ .process = tlsext_psk_client_process,
},
.server = {
.needs = tlsext_psk_server_needs,
.build = tlsext_psk_server_build,
- .parse = tlsext_psk_server_parse,
+ .process = tlsext_psk_server_process,
},
},
};
/* Ensure that extensions fit in a uint32_t bitmask. */
CTASSERT(N_TLS_EXTENSIONS <= (sizeof(uint32_t) * 8));
+struct tlsext_data {
+ CBS extensions[N_TLS_EXTENSIONS];
+};
+
+static struct tlsext_data *
+tlsext_data_new(void)
+{
+ return calloc(1, sizeof(struct tlsext_data));
+}
+
+static void
+tlsext_data_free(struct tlsext_data *td)
+{
+ freezero(td, sizeof(*td));
+}
+
uint16_t
tls_extension_type(const struct tls_extension *extension)
{
tlsext_parse(SSL *s, struct tlsext_data *td, int is_server, uint16_t msg_type,
CBS *cbs, int *alert)
{
- const struct tls_extension_funcs *ext;
const struct tls_extension *tlsext;
CBS extensions, extension_data;
uint16_t type;
goto err;
s->s3->hs.extensions_seen |= (1 << idx);
- ext = tlsext_funcs(tlsext, is_server);
- if (!ext->parse(s, td, msg_type, &extension_data, &alert_desc))
- goto err;
-
- if (CBS_len(&extension_data) != 0)
- goto err;
+ CBS_dup(&extension_data, &td->extensions[idx]);
}
return 1;
ext = tlsext_funcs(tlsext, is_server);
if (ext->process == NULL)
continue;
- if (!ext->process(s, td, msg_type, &alert_desc))
+ if (!ext->process(s, msg_type, &td->extensions[idx], &alert_desc))
+ goto err;
+
+ if (CBS_len(&td->extensions[idx]) != 0)
goto err;
}