Simplify TLS extension parsing and processing.
authorjsing <jsing@openbsd.org>
Mon, 25 Mar 2024 10:18:13 +0000 (10:18 +0000)
committerjsing <jsing@openbsd.org>
Mon, 25 Mar 2024 10:18:13 +0000 (10:18 +0000)
Rather than having a separate parse and process step for each TLS
extension, do a first pass that parses all of the TLS outer extensions and
retains the extension data, before running a second pass that calls the TLS
extension processing code.

ok beck@ tb@

lib/libssl/ssl_tlsext.c

index ff13808..26bd0c5 100644 (file)
@@ -1,4 +1,4 @@
-/* $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
  */
@@ -102,31 +86,16 @@ tlsext_alpn_check_format(CBS *cbs)
 }
 
 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)
@@ -139,8 +108,7 @@ tlsext_alpn_server_process(SSL *s, struct tlsext_data *td, uint16_t msg_type,
         * 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);
@@ -192,8 +160,7 @@ tlsext_alpn_server_build(SSL *s, uint16_t msg_type, CBB *cbb)
 }
 
 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;
 
@@ -213,18 +180,7 @@ tlsext_alpn_client_parse(SSL *s, struct tlsext_data *td, uint16_t msg_type,
        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;
@@ -271,8 +227,8 @@ tlsext_supportedgroups_client_build(SSL *s, uint16_t msg_type, CBB *cbb)
 }
 
 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;
@@ -344,8 +300,8 @@ tlsext_supportedgroups_server_build(SSL *s, uint16_t msg_type, CBB *cbb)
 }
 
 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.
@@ -393,8 +349,7 @@ tlsext_ecpf_build(SSL *s, uint16_t msg_type, CBB *cbb)
 }
 
 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;
 
@@ -434,10 +389,9 @@ tlsext_ecpf_client_build(SSL *s, uint16_t msg_type, CBB *cbb)
 }
 
 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
@@ -453,10 +407,9 @@ tlsext_ecpf_server_build(SSL *s, uint16_t msg_type, CBB *cbb)
 }
 
 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);
 }
 
 /*
@@ -485,8 +438,7 @@ tlsext_ri_client_build(SSL *s, uint16_t msg_type, CBB *cbb)
 }
 
 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;
 
@@ -535,8 +487,7 @@ tlsext_ri_server_build(SSL *s, uint16_t msg_type, CBB *cbb)
 }
 
 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;
 
@@ -619,8 +570,7 @@ tlsext_sigalgs_client_build(SSL *s, uint16_t msg_type, CBB *cbb)
 }
 
 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;
 
@@ -657,8 +607,7 @@ tlsext_sigalgs_server_build(SSL *s, uint16_t msg_type, CBB *cbb)
 }
 
 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;
 
@@ -785,8 +734,7 @@ tlsext_sni_is_valid_hostname(CBS *cbs, int *is_ip)
 }
 
 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;
@@ -882,8 +830,7 @@ tlsext_sni_server_build(SSL *s, uint16_t msg_type, CBB *cbb)
 }
 
 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;
@@ -971,8 +918,7 @@ tlsext_ocsp_client_build(SSL *s, uint16_t msg_type, CBB *cbb)
 }
 
 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;
@@ -1080,8 +1026,7 @@ tlsext_ocsp_server_build(SSL *s, uint16_t msg_type, CBB *cbb)
 }
 
 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;
@@ -1201,8 +1146,8 @@ tlsext_sessionticket_client_build(SSL *s, uint16_t msg_type, CBB *cbb)
 }
 
 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),
@@ -1238,8 +1183,8 @@ tlsext_sessionticket_server_build(SSL *s, uint16_t msg_type, CBB *cbb)
 }
 
 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),
@@ -1310,8 +1255,7 @@ tlsext_srtp_client_build(SSL *s, uint16_t msg_type, CBB *cbb)
 }
 
 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;
@@ -1416,8 +1360,7 @@ tlsext_srtp_server_build(SSL *s, uint16_t msg_type, CBB *cbb)
 }
 
 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;
@@ -1498,8 +1441,7 @@ tlsext_keyshare_client_build(SSL *s, uint16_t msg_type, CBB *cbb)
 }
 
 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;
@@ -1586,8 +1528,7 @@ tlsext_keyshare_server_build(SSL *s, uint16_t msg_type, CBB *cbb)
 }
 
 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;
@@ -1662,8 +1603,7 @@ tlsext_versions_client_build(SSL *s, uint16_t msg_type, CBB *cbb)
 }
 
 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;
@@ -1710,8 +1650,7 @@ tlsext_versions_server_build(SSL *s, uint16_t msg_type, CBB *cbb)
 }
 
 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;
 
@@ -1761,8 +1700,7 @@ tlsext_cookie_client_build(SSL *s, uint16_t msg_type, CBB *cbb)
 }
 
 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;
 
@@ -1819,8 +1757,7 @@ tlsext_cookie_server_build(SSL *s, uint16_t msg_type, CBB *cbb)
 }
 
 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;
 
@@ -1875,8 +1812,8 @@ tlsext_psk_kex_modes_client_build(SSL *s, uint16_t msg_type, CBB *cbb)
 }
 
 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;
@@ -1909,8 +1846,8 @@ tlsext_psk_kex_modes_server_build(SSL *s, uint16_t msg_type, CBB *cbb)
 }
 
 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;
 }
@@ -1932,8 +1869,7 @@ tlsext_psk_client_build(SSL *s, uint16_t msg_type, CBB *cbb)
 }
 
 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));
 }
@@ -1951,8 +1887,7 @@ tlsext_psk_server_build(SSL *s, uint16_t msg_type, CBB *cbb)
 }
 
 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));
 }
@@ -1979,8 +1914,8 @@ tlsext_quic_transport_parameters_client_build(SSL *s, uint16_t msg_type,
 }
 
 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;
@@ -2014,8 +1949,8 @@ tlsext_quic_transport_parameters_server_build(SSL *s, uint16_t msg_type,
 }
 
 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;
@@ -2034,10 +1969,7 @@ tlsext_quic_transport_parameters_server_parse(SSL *s, struct tlsext_data *td,
 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 {
@@ -2058,12 +1990,12 @@ static const struct tls_extension tls_extensions[] = {
                .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,
                },
        },
        {
@@ -2073,12 +2005,12 @@ static const struct tls_extension tls_extensions[] = {
                .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,
                },
        },
        {
@@ -2087,12 +2019,12 @@ static const struct tls_extension tls_extensions[] = {
                .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,
                },
        },
        {
@@ -2101,12 +2033,12 @@ static const struct tls_extension tls_extensions[] = {
                .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,
                },
        },
        {
@@ -2116,12 +2048,12 @@ static const struct tls_extension tls_extensions[] = {
                .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,
                },
        },
        {
@@ -2130,12 +2062,12 @@ static const struct tls_extension tls_extensions[] = {
                .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,
                },
        },
        {
@@ -2144,12 +2076,12 @@ static const struct tls_extension tls_extensions[] = {
                .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,
                },
        },
        {
@@ -2158,12 +2090,12 @@ static const struct tls_extension tls_extensions[] = {
                .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,
                },
        },
        {
@@ -2172,12 +2104,12 @@ static const struct tls_extension tls_extensions[] = {
                .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,
                },
        },
        {
@@ -2186,13 +2118,11 @@ static const struct tls_extension tls_extensions[] = {
                .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,
                },
        },
@@ -2202,12 +2132,12 @@ static const struct tls_extension tls_extensions[] = {
                .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
@@ -2218,12 +2148,12 @@ static const struct tls_extension tls_extensions[] = {
                .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 */
@@ -2233,12 +2163,12 @@ static const struct tls_extension tls_extensions[] = {
                .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,
                },
        },
        {
@@ -2247,12 +2177,12 @@ static const struct tls_extension tls_extensions[] = {
                .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,
                },
        },
        {
@@ -2261,12 +2191,12 @@ static const struct tls_extension tls_extensions[] = {
                .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,
                },
        },
 };
@@ -2276,6 +2206,22 @@ static const struct tls_extension tls_extensions[] = {
 /* 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)
 {
@@ -2467,7 +2413,6 @@ static int
 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;
@@ -2523,12 +2468,7 @@ tlsext_parse(SSL *s, struct tlsext_data *td, int is_server, uint16_t msg_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;
@@ -2558,7 +2498,10 @@ tlsext_process(SSL *s, struct tlsext_data *td, int is_server, uint16_t msg_type,
                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;
        }