]> git.ipfire.org Git - thirdparty/openssl.git/blobdiff - ssl/statem/extensions.c
RFC7250 (RPK) support
[thirdparty/openssl.git] / ssl / statem / extensions.c
index 1c3414127a330f4de50e4c779df078627af5125b..3bb7c4af2625beabb3a9844bdd0ba16051947684 100644 (file)
@@ -1,61 +1,76 @@
 /*
- * Copyright 2016-2017 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2016-2023 The OpenSSL Project Authors. All Rights Reserved.
  *
- * Licensed under the OpenSSL license (the "License").  You may not use
+ * 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
  * in the file LICENSE in the source distribution or at
  * https://www.openssl.org/source/license.html
  */
 
+#if defined(__TANDEM) && defined(_SPT_MODEL_)
+# include <spthread.h>
+# include <spt_extensions.h> /* timeval */
+#endif
+
 #include <string.h>
 #include "internal/nelem.h"
-#include "../ssl_locl.h"
-#include "statem_locl.h"
-
-static int final_renegotiate(SSL *s, unsigned int context, int sent,
-                                     int *al);
-static int init_server_name(SSL *s, unsigned int context);
-static int final_server_name(SSL *s, unsigned int context, int sent,
-                                     int *al);
-#ifndef OPENSSL_NO_EC
-static int final_ec_pt_formats(SSL *s, unsigned int context, int sent,
-                                       int *al);
-#endif
-static int init_session_ticket(SSL *s, unsigned int context);
+#include "internal/cryptlib.h"
+#include "../ssl_local.h"
+#include "statem_local.h"
+
+static int final_renegotiate(SSL_CONNECTION *s, unsigned int context, int sent);
+static int init_server_name(SSL_CONNECTION *s, unsigned int context);
+static int final_server_name(SSL_CONNECTION *s, unsigned int context, int sent);
+static int final_ec_pt_formats(SSL_CONNECTION *s, unsigned int context,
+                               int sent);
+static int init_session_ticket(SSL_CONNECTION *s, unsigned int context);
 #ifndef OPENSSL_NO_OCSP
-static int init_status_request(SSL *s, unsigned int context);
+static int init_status_request(SSL_CONNECTION *s, unsigned int context);
 #endif
 #ifndef OPENSSL_NO_NEXTPROTONEG
-static int init_npn(SSL *s, unsigned int context);
+static int init_npn(SSL_CONNECTION *s, unsigned int context);
 #endif
-static int init_alpn(SSL *s, unsigned int context);
-static int final_alpn(SSL *s, unsigned int context, int sent, int *al);
-static int init_sig_algs(SSL *s, unsigned int context);
-static int init_certificate_authorities(SSL *s, unsigned int context);
-static EXT_RETURN tls_construct_certificate_authorities(SSL *s, WPACKET *pkt,
+static int init_alpn(SSL_CONNECTION *s, unsigned int context);
+static int final_alpn(SSL_CONNECTION *s, unsigned int context, int sent);
+static int init_sig_algs_cert(SSL_CONNECTION *s, unsigned int context);
+static int init_sig_algs(SSL_CONNECTION *s, unsigned int context);
+static int init_server_cert_type(SSL_CONNECTION *sc, unsigned int context);
+static int init_client_cert_type(SSL_CONNECTION *sc, unsigned int context);
+static int init_certificate_authorities(SSL_CONNECTION *s,
+                                        unsigned int context);
+static EXT_RETURN tls_construct_certificate_authorities(SSL_CONNECTION *s,
+                                                        WPACKET *pkt,
                                                         unsigned int context,
                                                         X509 *x,
-                                                        size_t chainidx,
-                                                        int *al);
-static int tls_parse_certificate_authorities(SSL *s, PACKET *pkt,
+                                                        size_t chainidx);
+static int tls_parse_certificate_authorities(SSL_CONNECTION *s, PACKET *pkt,
                                              unsigned int context, X509 *x,
-                                             size_t chainidx, int *al);
+                                             size_t chainidx);
 #ifndef OPENSSL_NO_SRP
-static int init_srp(SSL *s, unsigned int context);
-#endif
-static int init_etm(SSL *s, unsigned int context);
-static int init_ems(SSL *s, unsigned int context);
-static int final_ems(SSL *s, unsigned int context, int sent, int *al);
-static int init_psk_kex_modes(SSL *s, unsigned int context);
-#ifndef OPENSSL_NO_EC
-static int final_key_share(SSL *s, unsigned int context, int sent, int *al);
+static int init_srp(SSL_CONNECTION *s, unsigned int context);
 #endif
+static int init_ec_point_formats(SSL_CONNECTION *s, unsigned int context);
+static int init_etm(SSL_CONNECTION *s, unsigned int context);
+static int init_ems(SSL_CONNECTION *s, unsigned int context);
+static int final_ems(SSL_CONNECTION *s, unsigned int context, int sent);
+static int init_psk_kex_modes(SSL_CONNECTION *s, unsigned int context);
+static int final_key_share(SSL_CONNECTION *s, unsigned int context, int sent);
 #ifndef OPENSSL_NO_SRTP
-static int init_srtp(SSL *s, unsigned int context);
+static int init_srtp(SSL_CONNECTION *s, unsigned int context);
 #endif
-static int final_sig_algs(SSL *s, unsigned int context, int sent, int *al);
-static int final_early_data(SSL *s, unsigned int context, int sent, int *al);
-static int final_maxfragmentlen(SSL *s, unsigned int context, int sent, int *al);
+static int final_sig_algs(SSL_CONNECTION *s, unsigned int context, int sent);
+static int final_early_data(SSL_CONNECTION *s, unsigned int context, int sent);
+static int final_maxfragmentlen(SSL_CONNECTION *s, unsigned int context,
+                                int sent);
+static int init_post_handshake_auth(SSL_CONNECTION *s, unsigned int context);
+static int final_psk(SSL_CONNECTION *s, unsigned int context, int sent);
+static int tls_init_compress_certificate(SSL_CONNECTION *sc, unsigned int context);
+static EXT_RETURN tls_construct_compress_certificate(SSL_CONNECTION *sc, WPACKET *pkt,
+                                                     unsigned int context,
+                                                     X509 *x, size_t chainidx);
+static int tls_parse_compress_certificate(SSL_CONNECTION *sc, PACKET *pkt,
+                                          unsigned int context,
+                                          X509 *x, size_t chainidx);
 
 /* Structure to define a built-in extension */
 typedef struct extensions_definition_st {
@@ -70,31 +85,36 @@ typedef struct extensions_definition_st {
      * Initialise extension before parsing. Always called for relevant contexts
      * even if extension not present
      */
-    int (*init)(SSL *s, unsigned int context);
+    int (*init)(SSL_CONNECTION *s, unsigned int context);
     /* Parse extension sent from client to server */
-    int (*parse_ctos)(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
-                      size_t chainidx, int *al);
+    int (*parse_ctos)(SSL_CONNECTION *s, PACKET *pkt, unsigned int context,
+                      X509 *x, size_t chainidx);
     /* Parse extension send from server to client */
-    int (*parse_stoc)(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
-                      size_t chainidx, int *al);
+    int (*parse_stoc)(SSL_CONNECTION *s, PACKET *pkt, unsigned int context,
+                      X509 *x, size_t chainidx);
     /* Construct extension sent from server to client */
-    EXT_RETURN (*construct_stoc)(SSL *s, WPACKET *pkt, unsigned int context,
-                                 X509 *x, size_t chainidx, int *al);
+    EXT_RETURN (*construct_stoc)(SSL_CONNECTION *s, WPACKET *pkt,
+                                 unsigned int context,
+                                 X509 *x, size_t chainidx);
     /* Construct extension sent from client to server */
-    EXT_RETURN (*construct_ctos)(SSL *s, WPACKET *pkt, unsigned int context,
-                                 X509 *x, size_t chainidx, int *al);
+    EXT_RETURN (*construct_ctos)(SSL_CONNECTION *s, WPACKET *pkt,
+                                 unsigned int context,
+                                 X509 *x, size_t chainidx);
     /*
      * Finalise extension after parsing. Always called where an extensions was
      * initialised even if the extension was not present. |sent| is set to 1 if
      * the extension was seen, or 0 otherwise.
      */
-    int (*final)(SSL *s, unsigned int context, int sent, int *al);
+    int (*final)(SSL_CONNECTION *s, unsigned int context, int sent);
 } EXTENSION_DEFINITION;
 
 /*
  * Definitions of all built-in extensions. NOTE: Changes in the number or order
  * of these extensions should be mirrored with equivalent changes to the
- * indexes ( TLSEXT_IDX_* ) defined in ssl_locl.h.
+ * indexes ( TLSEXT_IDX_* ) defined in ssl_local.h.
+ * Extensions should be added to test/ext_internal_test.c as well, as that
+ * tests the ordering of the extensions.
+ *
  * Each extension has an initialiser, a client and
  * server side parser and a finaliser. The initialiser is called (if the
  * extension is relevant to the given context) even if we did not see the
@@ -112,12 +132,10 @@ typedef struct extensions_definition_st {
  * messages the extension is relevant to. These flags also specify whether the
  * extension is relevant to a particular protocol or protocol version.
  *
- * TODO(TLS1.3): Make sure we have a test to check the consistency of these
- *
  * NOTE: WebSphere Application Server 7+ cannot handle empty extensions at
  * the end, keep these extensions before signature_algorithm.
  */
-#define INVALID_EXTENSION { 0x10000, 0, NULL, NULL, NULL, NULL, NULL, NULL }
+#define INVALID_EXTENSION { TLSEXT_TYPE_invalid, 0, NULL, NULL, NULL, NULL, NULL, NULL }
 static const EXTENSION_DEFINITION ext_defs[] = {
     {
         TLSEXT_TYPE_renegotiate,
@@ -153,26 +171,47 @@ static const EXTENSION_DEFINITION ext_defs[] = {
 #else
     INVALID_EXTENSION,
 #endif
-#ifndef OPENSSL_NO_EC
     {
         TLSEXT_TYPE_ec_point_formats,
         SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_2_SERVER_HELLO
         | SSL_EXT_TLS1_2_AND_BELOW_ONLY,
-        NULL, tls_parse_ctos_ec_pt_formats, tls_parse_stoc_ec_pt_formats,
+        init_ec_point_formats, tls_parse_ctos_ec_pt_formats, tls_parse_stoc_ec_pt_formats,
         tls_construct_stoc_ec_pt_formats, tls_construct_ctos_ec_pt_formats,
         final_ec_pt_formats
     },
     {
+        /*
+         * "supported_groups" is spread across several specifications.
+         * It was originally specified as "elliptic_curves" in RFC 4492,
+         * and broadened to include named FFDH groups by RFC 7919.
+         * Both RFCs 4492 and 7919 do not include a provision for the server
+         * to indicate to the client the complete list of groups supported
+         * by the server, with the server instead just indicating the
+         * selected group for this connection in the ServerKeyExchange
+         * message.  TLS 1.3 adds a scheme for the server to indicate
+         * to the client its list of supported groups in the
+         * EncryptedExtensions message, but none of the relevant
+         * specifications permit sending supported_groups in the ServerHello.
+         * Nonetheless (possibly due to the close proximity to the
+         * "ec_point_formats" extension, which is allowed in the ServerHello),
+         * there are several servers that send this extension in the
+         * ServerHello anyway.  Up to and including the 1.1.0 release,
+         * we did not check for the presence of nonpermitted extensions,
+         * so to avoid a regression, we must permit this extension in the
+         * TLS 1.2 ServerHello as well.
+         *
+         * Note that there is no tls_parse_stoc_supported_groups function,
+         * so we do not perform any additional parsing, validation, or
+         * processing on the server's group list -- this is just a minimal
+         * change to preserve compatibility with these misbehaving servers.
+         */
         TLSEXT_TYPE_supported_groups,
-        SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_3_ENCRYPTED_EXTENSIONS,
+        SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_3_ENCRYPTED_EXTENSIONS
+        | SSL_EXT_TLS1_2_SERVER_HELLO,
         NULL, tls_parse_ctos_supported_groups, NULL,
         tls_construct_stoc_supported_groups,
         tls_construct_ctos_supported_groups, NULL
     },
-#else
-    INVALID_EXTENSION,
-    INVALID_EXTENSION,
-#endif
     {
         TLSEXT_TYPE_session_ticket,
         SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_2_SERVER_HELLO
@@ -185,7 +224,7 @@ static const EXTENSION_DEFINITION ext_defs[] = {
     {
         TLSEXT_TYPE_status_request,
         SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_2_SERVER_HELLO
-        | SSL_EXT_TLS1_3_CERTIFICATE,
+        | SSL_EXT_TLS1_3_CERTIFICATE | SSL_EXT_TLS1_3_CERTIFICATE_REQUEST,
         init_status_request, tls_parse_ctos_status_request,
         tls_parse_stoc_status_request, tls_construct_stoc_status_request,
         tls_construct_ctos_status_request, NULL
@@ -237,7 +276,7 @@ static const EXTENSION_DEFINITION ext_defs[] = {
     {
         TLSEXT_TYPE_signed_certificate_timestamp,
         SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_2_SERVER_HELLO
-        | SSL_EXT_TLS1_3_CERTIFICATE,
+        | SSL_EXT_TLS1_3_CERTIFICATE | SSL_EXT_TLS1_3_CERTIFICATE_REQUEST,
         NULL,
         /*
          * No server side support for this, but can be provided by a custom
@@ -256,6 +295,40 @@ static const EXTENSION_DEFINITION ext_defs[] = {
         init_ems, tls_parse_ctos_ems, tls_parse_stoc_ems,
         tls_construct_stoc_ems, tls_construct_ctos_ems, final_ems
     },
+    {
+        TLSEXT_TYPE_signature_algorithms_cert,
+        SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_3_CERTIFICATE_REQUEST,
+        init_sig_algs_cert, tls_parse_ctos_sig_algs_cert,
+        tls_parse_ctos_sig_algs_cert,
+        /* We do not generate signature_algorithms_cert at present. */
+        NULL, NULL, NULL
+    },
+    {
+        TLSEXT_TYPE_post_handshake_auth,
+        SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_3_ONLY,
+        init_post_handshake_auth,
+        tls_parse_ctos_post_handshake_auth, NULL,
+        NULL, tls_construct_ctos_post_handshake_auth,
+        NULL,
+    },
+    {
+        TLSEXT_TYPE_client_cert_type,
+        SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_3_ENCRYPTED_EXTENSIONS
+        | SSL_EXT_TLS1_2_SERVER_HELLO,
+        init_client_cert_type,
+        tls_parse_ctos_client_cert_type, tls_parse_stoc_client_cert_type,
+        tls_construct_stoc_client_cert_type, tls_construct_ctos_client_cert_type,
+        NULL
+    },
+    {
+        TLSEXT_TYPE_server_cert_type,
+        SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_3_ENCRYPTED_EXTENSIONS
+        | SSL_EXT_TLS1_2_SERVER_HELLO,
+        init_server_cert_type,
+        tls_parse_ctos_server_cert_type, tls_parse_stoc_server_cert_type,
+        tls_construct_stoc_server_cert_type, tls_construct_ctos_server_cert_type,
+        NULL
+    },
     {
         TLSEXT_TYPE_signature_algorithms,
         SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_3_CERTIFICATE_REQUEST,
@@ -265,11 +338,13 @@ static const EXTENSION_DEFINITION ext_defs[] = {
     },
     {
         TLSEXT_TYPE_supported_versions,
-        SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS_IMPLEMENTATION_ONLY
-        | SSL_EXT_TLS1_3_ONLY,
+        SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_3_SERVER_HELLO
+        | SSL_EXT_TLS1_3_HELLO_RETRY_REQUEST | SSL_EXT_TLS_IMPLEMENTATION_ONLY,
         NULL,
         /* Processed inline as part of version selection */
-        NULL, NULL, NULL, tls_construct_ctos_supported_versions, NULL
+        NULL, tls_parse_stoc_supported_versions,
+        tls_construct_stoc_supported_versions,
+        tls_construct_ctos_supported_versions, NULL
     },
     {
         TLSEXT_TYPE_psk_kex_modes,
@@ -278,7 +353,6 @@ static const EXTENSION_DEFINITION ext_defs[] = {
         init_psk_kex_modes, tls_parse_ctos_psk_kex_modes, NULL, NULL,
         tls_construct_ctos_psk_kex_modes, NULL
     },
-#ifndef OPENSSL_NO_EC
     {
         /*
          * Must be in this list after supported_groups. We need that to have
@@ -292,27 +366,38 @@ static const EXTENSION_DEFINITION ext_defs[] = {
         tls_construct_stoc_key_share, tls_construct_ctos_key_share,
         final_key_share
     },
-#endif
     {
+        /* Must be after key_share */
         TLSEXT_TYPE_cookie,
         SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_3_HELLO_RETRY_REQUEST
         | SSL_EXT_TLS_IMPLEMENTATION_ONLY | SSL_EXT_TLS1_3_ONLY,
-        NULL, NULL, tls_parse_stoc_cookie, NULL, tls_construct_ctos_cookie,
-        NULL
+        NULL, tls_parse_ctos_cookie, tls_parse_stoc_cookie,
+        tls_construct_stoc_cookie, tls_construct_ctos_cookie, NULL
     },
     {
         /*
          * Special unsolicited ServerHello extension only used when
-         * SSL_OP_CRYPTOPRO_TLSEXT_BUG is set
+         * SSL_OP_CRYPTOPRO_TLSEXT_BUG is set. We allow it in a ClientHello but
+         * ignore it.
          */
         TLSEXT_TYPE_cryptopro_bug,
-        SSL_EXT_TLS1_2_SERVER_HELLO | SSL_EXT_TLS1_2_AND_BELOW_ONLY,
+        SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_2_SERVER_HELLO
+        | SSL_EXT_TLS1_2_AND_BELOW_ONLY,
         NULL, NULL, NULL, tls_construct_stoc_cryptopro_bug, NULL, NULL
     },
+    {
+        TLSEXT_TYPE_compress_certificate,
+        SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_3_CERTIFICATE_REQUEST
+        | SSL_EXT_TLS_IMPLEMENTATION_ONLY | SSL_EXT_TLS1_3_ONLY,
+        tls_init_compress_certificate,
+        tls_parse_compress_certificate, tls_parse_compress_certificate,
+        tls_construct_compress_certificate, tls_construct_compress_certificate,
+        NULL
+    },
     {
         TLSEXT_TYPE_early_data,
         SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_3_ENCRYPTED_EXTENSIONS
-        | SSL_EXT_TLS1_3_NEW_SESSION_TICKET,
+        | SSL_EXT_TLS1_3_NEW_SESSION_TICKET | SSL_EXT_TLS1_3_ONLY,
         NULL, tls_parse_ctos_early_data, tls_parse_stoc_early_data,
         tls_construct_stoc_early_data, tls_construct_ctos_early_data,
         final_early_data
@@ -340,18 +425,30 @@ static const EXTENSION_DEFINITION ext_defs[] = {
         SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_3_SERVER_HELLO
         | SSL_EXT_TLS_IMPLEMENTATION_ONLY | SSL_EXT_TLS1_3_ONLY,
         NULL, tls_parse_ctos_psk, tls_parse_stoc_psk, tls_construct_stoc_psk,
-        tls_construct_ctos_psk, NULL
+        tls_construct_ctos_psk, final_psk
     }
 };
 
+/* Returns a TLSEXT_TYPE for the given index */
+unsigned int ossl_get_extension_type(size_t idx)
+{
+    size_t num_exts = OSSL_NELEM(ext_defs);
+
+    if (idx >= num_exts)
+        return TLSEXT_TYPE_out_of_range;
+
+    return ext_defs[idx].type;
+}
+
 /* Check whether an extension's context matches the current context */
-static int validate_context(SSL *s, unsigned int extctx, unsigned int thisctx)
+static int validate_context(SSL_CONNECTION *s, unsigned int extctx,
+                            unsigned int thisctx)
 {
     /* Check we're allowed to use this extension in this context */
     if ((thisctx & extctx) == 0)
         return 0;
 
-    if (SSL_IS_DTLS(s)) {
+    if (SSL_CONNECTION_IS_DTLS(s)) {
         if ((extctx & SSL_EXT_TLS_ONLY) != 0)
             return 0;
     } else if ((extctx & SSL_EXT_DTLS_ONLY) != 0) {
@@ -361,15 +458,54 @@ static int validate_context(SSL *s, unsigned int extctx, unsigned int thisctx)
     return 1;
 }
 
+int tls_validate_all_contexts(SSL_CONNECTION *s, unsigned int thisctx,
+                              RAW_EXTENSION *exts)
+{
+    size_t i, num_exts, builtin_num = OSSL_NELEM(ext_defs), offset;
+    RAW_EXTENSION *thisext;
+    unsigned int context;
+    ENDPOINT role = ENDPOINT_BOTH;
+
+    if ((thisctx & SSL_EXT_CLIENT_HELLO) != 0)
+        role = ENDPOINT_SERVER;
+    else if ((thisctx & SSL_EXT_TLS1_2_SERVER_HELLO) != 0)
+        role = ENDPOINT_CLIENT;
+
+    /* Calculate the number of extensions in the extensions list */
+    num_exts = builtin_num + s->cert->custext.meths_count;
+
+    for (thisext = exts, i = 0; i < num_exts; i++, thisext++) {
+        if (!thisext->present)
+            continue;
+
+        if (i < builtin_num) {
+            context = ext_defs[i].context;
+        } else {
+            custom_ext_method *meth = NULL;
+
+            meth = custom_ext_find(&s->cert->custext, role, thisext->type,
+                                   &offset);
+            if (!ossl_assert(meth != NULL))
+                return 0;
+            context = meth->context;
+        }
+
+        if (!validate_context(s, context, thisctx))
+            return 0;
+    }
+
+    return 1;
+}
+
 /*
  * Verify whether we are allowed to use the extension |type| in the current
  * |context|. Returns 1 to indicate the extension is allowed or unknown or 0 to
  * indicate the extension is not allowed. If returning 1 then |*found| is set to
  * the definition for the extension we found.
  */
-static int verify_extension(SSL *s, unsigned int context, unsigned int type,
-                            custom_ext_methods *meths, RAW_EXTENSION *rawexlist,
-                            RAW_EXTENSION **found)
+static int verify_extension(SSL_CONNECTION *s, unsigned int context,
+                            unsigned int type, custom_ext_methods *meths,
+                            RAW_EXTENSION *rawexlist, RAW_EXTENSION **found)
 {
     size_t i;
     size_t builtin_num = OSSL_NELEM(ext_defs);
@@ -415,7 +551,8 @@ static int verify_extension(SSL *s, unsigned int context, unsigned int type,
  * the extension is relevant for the current context |thisctx| or not. Returns
  * 1 if the extension is relevant for this context, and 0 otherwise
  */
-int extension_is_relevant(SSL *s, unsigned int extctx, unsigned int thisctx)
+int extension_is_relevant(SSL_CONNECTION *s, unsigned int extctx,
+                          unsigned int thisctx)
 {
     int is_tls13;
 
@@ -426,29 +563,37 @@ int extension_is_relevant(SSL *s, unsigned int extctx, unsigned int thisctx)
     if ((thisctx & SSL_EXT_TLS1_3_HELLO_RETRY_REQUEST) != 0)
         is_tls13 = 1;
     else
-        is_tls13 = SSL_IS_TLS13(s);
+        is_tls13 = SSL_CONNECTION_IS_TLS13(s);
 
-    if ((SSL_IS_DTLS(s)
+    if ((SSL_CONNECTION_IS_DTLS(s)
                 && (extctx & SSL_EXT_TLS_IMPLEMENTATION_ONLY) != 0)
             || (s->version == SSL3_VERSION
                     && (extctx & SSL_EXT_SSL3_ALLOWED) == 0)
+            /*
+             * Note that SSL_IS_TLS13() means "TLS 1.3 has been negotiated",
+             * which is never true when generating the ClientHello.
+             * However, version negotiation *has* occurred by the time the
+             * ClientHello extensions are being parsed.
+             * Be careful to allow TLS 1.3-only extensions when generating
+             * the ClientHello.
+             */
             || (is_tls13 && (extctx & SSL_EXT_TLS1_2_AND_BELOW_ONLY) != 0)
-            || (!is_tls13 && (extctx & SSL_EXT_TLS1_3_ONLY) != 0)
+            || (!is_tls13 && (extctx & SSL_EXT_TLS1_3_ONLY) != 0
+                && (thisctx & SSL_EXT_CLIENT_HELLO) == 0)
+            || (s->server && !is_tls13 && (extctx & SSL_EXT_TLS1_3_ONLY) != 0)
             || (s->hit && (extctx & SSL_EXT_IGNORE_ON_RESUMPTION) != 0))
         return 0;
-
     return 1;
 }
 
 /*
  * Gather a list of all the extensions from the data in |packet]. |context|
  * tells us which message this extension is for. The raw extension data is
- * stored in |*res| on success. In the event of an error the alert type to use
- * is stored in |*al|. We don't actually process the content of the extensions
- * yet, except to check their types. This function also runs the initialiser
- * functions for all known extensions if |init| is nonzero (whether we have
- * collected them or not). If successful the caller is responsible for freeing
- * the contents of |*res|.
+ * stored in |*res| on success. We don't actually process the content of the
+ * extensions yet, except to check their types. This function also runs the
+ * initialiser functions for all known extensions if |init| is nonzero (whether
+ * we have collected them or not). If successful the caller is responsible for
+ * freeing the contents of |*res|.
  *
  * Per http://tools.ietf.org/html/rfc5246#section-7.4.1.4, there may not be
  * more than one extension of the same type in a ClientHello or ServerHello.
@@ -457,9 +602,9 @@ int extension_is_relevant(SSL *s, unsigned int extctx, unsigned int thisctx)
  * found, or an internal error occurred. We only check duplicates for
  * extensions that we know about. We ignore others.
  */
-int tls_collect_extensions(SSL *s, PACKET *packet, unsigned int context,
-                           RAW_EXTENSION **res, int *al, size_t *len,
-                           int init)
+int tls_collect_extensions(SSL_CONNECTION *s, PACKET *packet,
+                           unsigned int context,
+                           RAW_EXTENSION **res, size_t *len, int init)
 {
     PACKET extensions = *packet;
     size_t i = 0;
@@ -480,8 +625,7 @@ int tls_collect_extensions(SSL *s, PACKET *packet, unsigned int context,
     num_exts = OSSL_NELEM(ext_defs) + (exts != NULL ? exts->meths_count : 0);
     raw_extensions = OPENSSL_zalloc(num_exts * sizeof(*raw_extensions));
     if (raw_extensions == NULL) {
-        *al = SSL_AD_INTERNAL_ERROR;
-        SSLerr(SSL_F_TLS_COLLECT_EXTENSIONS, ERR_R_MALLOC_FAILURE);
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_CRYPTO_LIB);
         return 0;
     }
 
@@ -493,8 +637,7 @@ int tls_collect_extensions(SSL *s, PACKET *packet, unsigned int context,
 
         if (!PACKET_get_net_2(&extensions, &type) ||
             !PACKET_get_length_prefixed_2(&extensions, &extension)) {
-            SSLerr(SSL_F_TLS_COLLECT_EXTENSIONS, SSL_R_BAD_EXTENSION);
-            *al = SSL_AD_DECODE_ERROR;
+            SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_R_BAD_EXTENSION);
             goto err;
         }
         /*
@@ -507,8 +650,7 @@ int tls_collect_extensions(SSL *s, PACKET *packet, unsigned int context,
                 || (type == TLSEXT_TYPE_psk
                     && (context & SSL_EXT_CLIENT_HELLO) != 0
                     && PACKET_remaining(&extensions) != 0)) {
-            SSLerr(SSL_F_TLS_COLLECT_EXTENSIONS, SSL_R_BAD_EXTENSION);
-            *al = SSL_AD_ILLEGAL_PARAMETER;
+            SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_R_BAD_EXTENSION);
             goto err;
         }
         idx = thisex - raw_extensions;
@@ -533,9 +675,14 @@ int tls_collect_extensions(SSL *s, PACKET *packet, unsigned int context,
                 && type != TLSEXT_TYPE_cookie
                 && type != TLSEXT_TYPE_renegotiate
                 && type != TLSEXT_TYPE_signed_certificate_timestamp
-                && (s->ext.extflags[idx] & SSL_EXT_FLAG_SENT) == 0) {
-            SSLerr(SSL_F_TLS_COLLECT_EXTENSIONS, SSL_R_UNSOLICITED_EXTENSION);
-            *al = SSL_AD_UNSUPPORTED_EXTENSION;
+                && (s->ext.extflags[idx] & SSL_EXT_FLAG_SENT) == 0
+#ifndef OPENSSL_NO_GOST
+                && !((context & SSL_EXT_TLS1_2_SERVER_HELLO) != 0
+                     && type == TLSEXT_TYPE_cryptopro_bug)
+#endif
+                                                                ) {
+            SSLfatal(s, SSL_AD_UNSUPPORTED_EXTENSION,
+                     SSL_R_UNSOLICITED_EXTENSION);
             goto err;
         }
         if (thisex != NULL) {
@@ -544,8 +691,8 @@ int tls_collect_extensions(SSL *s, PACKET *packet, unsigned int context,
             thisex->type = type;
             thisex->received_order = i++;
             if (s->ext.debug_cb)
-                s->ext.debug_cb(s, !s->server, thisex->type,
-                                PACKET_data(&thisex->data),
+                s->ext.debug_cb(SSL_CONNECTION_GET_SSL(s), !s->server,
+                                thisex->type, PACKET_data(&thisex->data),
                                 PACKET_remaining(&thisex->data),
                                 s->ext.debug_arg);
         }
@@ -561,7 +708,7 @@ int tls_collect_extensions(SSL *s, PACKET *packet, unsigned int context,
             if (thisexd->init != NULL && (thisexd->context & context) != 0
                 && extension_is_relevant(s, thisexd->context, context)
                 && !thisexd->init(s, context)) {
-                *al = SSL_AD_INTERNAL_ERROR;
+                /* SSLfatal() already called */
                 goto err;
             }
         }
@@ -584,16 +731,15 @@ int tls_collect_extensions(SSL *s, PACKET *packet, unsigned int context,
  * given |context| and the parser has not already been run. If this is for a
  * Certificate message, then we also provide the parser with the relevant
  * Certificate |x| and its position in the |chainidx| with 0 being the first
- * Certificate. Returns 1 on success or 0 on failure. In the event of a failure
- * |*al| is populated with a suitable alert code. If an extension is not present
- * this counted as success.
+ * Certificate. Returns 1 on success or 0 on failure. If an extension is not
+ * present this counted as success.
  */
-int tls_parse_extension(SSL *s, TLSEXT_INDEX idx, int context,
-                        RAW_EXTENSION *exts, X509 *x, size_t chainidx, int *al)
+int tls_parse_extension(SSL_CONNECTION *s, TLSEXT_INDEX idx, int context,
+                        RAW_EXTENSION *exts, X509 *x, size_t chainidx)
 {
     RAW_EXTENSION *currext = &exts[idx];
-    int (*parser)(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
-                  size_t chainidx, int *al) = NULL;
+    int (*parser)(SSL_CONNECTION *s, PACKET *pkt, unsigned int context, X509 *x,
+                  size_t chainidx) = NULL;
 
     /* Skip if the extension is not present */
     if (!currext->present)
@@ -616,7 +762,7 @@ int tls_parse_extension(SSL *s, TLSEXT_INDEX idx, int context,
         parser = s->server ? extdef->parse_ctos : extdef->parse_stoc;
 
         if (parser != NULL)
-            return parser(s, &currext->data, context, x, chainidx, al);
+            return parser(s, &currext->data, context, x, chainidx);
 
         /*
          * If the parser is NULL we fall through to the custom extension
@@ -625,13 +771,10 @@ int tls_parse_extension(SSL *s, TLSEXT_INDEX idx, int context,
     }
 
     /* Parse custom extensions */
-    if (custom_ext_parse(s, context, currext->type,
-                         PACKET_data(&currext->data),
-                         PACKET_remaining(&currext->data),
-                         x, chainidx, al) <= 0)
-        return 0;
-
-    return 1;
+    return custom_ext_parse(s, context, currext->type,
+                            PACKET_data(&currext->data),
+                            PACKET_remaining(&currext->data),
+                            x, chainidx);
 }
 
 /*
@@ -639,11 +782,11 @@ int tls_parse_extension(SSL *s, TLSEXT_INDEX idx, int context,
  * finalisation for all extensions at the end if |fin| is nonzero, whether we
  * collected them or not. Returns 1 for success or 0 for failure. If we are
  * working on a Certificate message then we also pass the Certificate |x| and
- * its position in the |chainidx|, with 0 being the first certificate. On
- * failure, |*al| is populated with a suitable alert code.
+ * its position in the |chainidx|, with 0 being the first certificate.
  */
-int tls_parse_all_extensions(SSL *s, int context, RAW_EXTENSION *exts, X509 *x,
-                             size_t chainidx, int *al, int fin)
+int tls_parse_all_extensions(SSL_CONNECTION *s, int context,
+                             RAW_EXTENSION *exts, X509 *x,
+                             size_t chainidx, int fin)
 {
     size_t i, numexts = OSSL_NELEM(ext_defs);
     const EXTENSION_DEFINITION *thisexd;
@@ -653,8 +796,10 @@ int tls_parse_all_extensions(SSL *s, int context, RAW_EXTENSION *exts, X509 *x,
 
     /* Parse each extension in turn */
     for (i = 0; i < numexts; i++) {
-        if (!tls_parse_extension(s, i, context, exts, x, chainidx, al))
+        if (!tls_parse_extension(s, i, context, exts, x, chainidx)) {
+            /* SSLfatal() already called */
             return 0;
+        }
     }
 
     if (fin) {
@@ -665,33 +810,28 @@ int tls_parse_all_extensions(SSL *s, int context, RAW_EXTENSION *exts, X509 *x,
         for (i = 0, thisexd = ext_defs; i < OSSL_NELEM(ext_defs);
              i++, thisexd++) {
             if (thisexd->final != NULL && (thisexd->context & context) != 0
-                && !thisexd->final(s, context, exts[i].present, al))
+                && !thisexd->final(s, context, exts[i].present)) {
+                /* SSLfatal() already called */
                 return 0;
+            }
         }
     }
 
     return 1;
 }
 
-int should_add_extension(SSL *s, unsigned int extctx, unsigned int thisctx,
-                         int max_version)
+int should_add_extension(SSL_CONNECTION *s, unsigned int extctx,
+                         unsigned int thisctx, int max_version)
 {
     /* Skip if not relevant for our context */
     if ((extctx & thisctx) == 0)
         return 0;
 
     /* Check if this extension is defined for our protocol. If not, skip */
-    if ((SSL_IS_DTLS(s) && (extctx & SSL_EXT_TLS_IMPLEMENTATION_ONLY) != 0)
-            || (s->version == SSL3_VERSION
-                    && (extctx & SSL_EXT_SSL3_ALLOWED) == 0)
-            || (SSL_IS_TLS13(s)
-                && (extctx & SSL_EXT_TLS1_2_AND_BELOW_ONLY) != 0)
-            || (!SSL_IS_TLS13(s)
-                && (extctx & SSL_EXT_TLS1_3_ONLY) != 0
-                && (thisctx & SSL_EXT_CLIENT_HELLO) == 0)
+    if (!extension_is_relevant(s, extctx, thisctx)
             || ((extctx & SSL_EXT_TLS1_3_ONLY) != 0
                 && (thisctx & SSL_EXT_CLIENT_HELLO) != 0
-                && (SSL_IS_DTLS(s) || max_version < TLS1_3_VERSION)))
+                && (SSL_CONNECTION_IS_DTLS(s) || max_version < TLS1_3_VERSION)))
         return 0;
 
     return 1;
@@ -702,22 +842,17 @@ int should_add_extension(SSL *s, unsigned int extctx, unsigned int thisctx,
  * them to |pkt|. If this is an extension for a Certificate in a Certificate
  * message, then |x| will be set to the Certificate we are handling, and
  * |chainidx| will indicate the position in the chainidx we are processing (with
- * 0 being the first in the chain). Returns 1 on success or 0 on failure. If a
- * failure occurs then |al| is populated with a suitable alert code. On a
+ * 0 being the first in the chain). Returns 1 on success or 0 on failure. On a
  * failure construction stops at the first extension to fail to construct.
  */
-int tls_construct_extensions(SSL *s, WPACKET *pkt, unsigned int context,
-                             X509 *x, size_t chainidx, int *al)
+int tls_construct_extensions(SSL_CONNECTION *s, WPACKET *pkt,
+                             unsigned int context,
+                             X509 *x, size_t chainidx)
 {
     size_t i;
-    int min_version, max_version = 0, reason, tmpal;
+    int min_version, max_version = 0, reason;
     const EXTENSION_DEFINITION *thisexd;
-
-    /*
-     * Normally if something goes wrong during construction it's an internal
-     * error. We can always override this later.
-     */
-    tmpal = SSL_AD_INTERNAL_ERROR;
+    int for_comp = (context & SSL_EXT_TLS1_3_CERTIFICATE_COMPRESSION) != 0;
 
     if (!WPACKET_start_sub_packet_u16(pkt)
                /*
@@ -728,16 +863,18 @@ int tls_construct_extensions(SSL *s, WPACKET *pkt, unsigned int context,
             || ((context &
                  (SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_2_SERVER_HELLO)) != 0
                 && !WPACKET_set_flags(pkt,
-                                     WPACKET_FLAGS_ABANDON_ON_ZERO_LENGTH))) {
-        SSLerr(SSL_F_TLS_CONSTRUCT_EXTENSIONS, ERR_R_INTERNAL_ERROR);
-        goto err;
+                                      WPACKET_FLAGS_ABANDON_ON_ZERO_LENGTH))) {
+        if (!for_comp)
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+        return 0;
     }
 
     if ((context & SSL_EXT_CLIENT_HELLO) != 0) {
-        reason = ssl_get_min_max_version(s, &min_version, &max_version);
+        reason = ssl_get_min_max_version(s, &min_version, &max_version, NULL);
         if (reason != 0) {
-            SSLerr(SSL_F_TLS_CONSTRUCT_EXTENSIONS, reason);
-            goto err;
+            if (!for_comp)
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR, reason);
+            return 0;
         }
     }
 
@@ -746,14 +883,15 @@ int tls_construct_extensions(SSL *s, WPACKET *pkt, unsigned int context,
         /* On the server side with initialise during ClientHello parsing */
         custom_ext_init(&s->cert->custext);
     }
-    if (!custom_ext_add(s, context, pkt, x, chainidx, max_version, &tmpal)) {
-        SSLerr(SSL_F_TLS_CONSTRUCT_EXTENSIONS, ERR_R_INTERNAL_ERROR);
-        goto err;
+    if (!custom_ext_add(s, context, pkt, x, chainidx, max_version)) {
+        /* SSLfatal() already called */
+        return 0;
     }
 
     for (i = 0, thisexd = ext_defs; i < OSSL_NELEM(ext_defs); i++, thisexd++) {
-        EXT_RETURN (*construct)(SSL *s, WPACKET *pkt, unsigned int context,
-                                X509 *x, size_t chainidx, int *al);
+        EXT_RETURN (*construct)(SSL_CONNECTION *s, WPACKET *pkt,
+                                unsigned int context,
+                                X509 *x, size_t chainidx);
         EXT_RETURN ret;
 
         /* Skip if not relevant for our context */
@@ -766,9 +904,11 @@ int tls_construct_extensions(SSL *s, WPACKET *pkt, unsigned int context,
         if (construct == NULL)
             continue;
 
-        ret = construct(s, pkt, context, x, chainidx, &tmpal);
-        if (ret == EXT_RETURN_FAIL)
-            goto err;
+        ret = construct(s, pkt, context, x, chainidx);
+        if (ret == EXT_RETURN_FAIL) {
+            /* SSLfatal() already called */
+            return 0;
+        }
         if (ret == EXT_RETURN_SENT
                 && (context & (SSL_EXT_CLIENT_HELLO
                                | SSL_EXT_TLS1_3_CERTIFICATE_REQUEST
@@ -777,27 +917,22 @@ int tls_construct_extensions(SSL *s, WPACKET *pkt, unsigned int context,
     }
 
     if (!WPACKET_close(pkt)) {
-        SSLerr(SSL_F_TLS_CONSTRUCT_EXTENSIONS, ERR_R_INTERNAL_ERROR);
-        goto err;
+        if (!for_comp)
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+        return 0;
     }
 
     return 1;
-
- err:
-    *al = tmpal;
-    return 0;
 }
 
 /*
  * Built in extension finalisation and initialisation functions. All initialise
  * or finalise the associated extension type for the given |context|. For
  * finalisers |sent| is set to 1 if we saw the extension during parsing, and 0
- * otherwise. These functions return 1 on success or 0 on failure. In the event
- * of a failure then |*al| is populated with a suitable error code.
+ * otherwise. These functions return 1 on success or 0 on failure.
  */
 
-static int final_renegotiate(SSL *s, unsigned int context, int sent,
-                                     int *al)
+static int final_renegotiate(SSL_CONNECTION *s, unsigned int context, int sent)
 {
     if (!s->server) {
         /*
@@ -807,9 +942,8 @@ static int final_renegotiate(SSL *s, unsigned int context, int sent,
         if (!(s->options & SSL_OP_LEGACY_SERVER_CONNECT)
                 && !(s->options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION)
                 && !sent) {
-            *al = SSL_AD_HANDSHAKE_FAILURE;
-            SSLerr(SSL_F_FINAL_RENEGOTIATE,
-                   SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED);
+            SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE,
+                     SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED);
             return 0;
         }
 
@@ -820,9 +954,8 @@ static int final_renegotiate(SSL *s, unsigned int context, int sent,
     if (s->renegotiate
             && !(s->options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION)
             && !sent) {
-        *al = SSL_AD_HANDSHAKE_FAILURE;
-        SSLerr(SSL_F_FINAL_RENEGOTIATE,
-               SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED);
+        SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE,
+                 SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED);
         return 0;
     }
 
@@ -830,32 +963,64 @@ static int final_renegotiate(SSL *s, unsigned int context, int sent,
     return 1;
 }
 
-static int init_server_name(SSL *s, unsigned int context)
+static ossl_inline void ssl_tsan_decr(const SSL_CTX *ctx,
+                                      TSAN_QUALIFIER int *stat)
 {
-    if (s->server)
+    if (ssl_tsan_lock(ctx)) {
+        tsan_decr(stat);
+        ssl_tsan_unlock(ctx);
+    }
+}
+
+static int init_server_name(SSL_CONNECTION *s, unsigned int context)
+{
+    if (s->server) {
         s->servername_done = 0;
 
+        OPENSSL_free(s->ext.hostname);
+        s->ext.hostname = NULL;
+    }
+
     return 1;
 }
 
-static int final_server_name(SSL *s, unsigned int context, int sent,
-                                     int *al)
+static int final_server_name(SSL_CONNECTION *s, unsigned int context, int sent)
 {
-    int ret = SSL_TLSEXT_ERR_NOACK, discard;
+    int ret = SSL_TLSEXT_ERR_NOACK;
     int altmp = SSL_AD_UNRECOGNIZED_NAME;
-    int was_ticket = (SSL_get_options(s) & SSL_OP_NO_TICKET) == 0;
-
-    if (s->ctx != NULL && s->ctx->ext.servername_cb != 0)
-        ret = s->ctx->ext.servername_cb(s, &altmp,
-                                        s->ctx->ext.servername_arg);
-    else if (s->session_ctx != NULL
-             && s->session_ctx->ext.servername_cb != 0)
-        ret = s->session_ctx->ext.servername_cb(s, &altmp,
+    SSL *ssl = SSL_CONNECTION_GET_SSL(s);
+    SSL_CTX *sctx = SSL_CONNECTION_GET_CTX(s);
+    int was_ticket = (SSL_get_options(ssl) & SSL_OP_NO_TICKET) == 0;
+
+    if (!ossl_assert(sctx != NULL) || !ossl_assert(s->session_ctx != NULL)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    if (sctx->ext.servername_cb != NULL)
+        ret = sctx->ext.servername_cb(ssl, &altmp,
+                                      sctx->ext.servername_arg);
+    else if (s->session_ctx->ext.servername_cb != NULL)
+        ret = s->session_ctx->ext.servername_cb(ssl, &altmp,
                                        s->session_ctx->ext.servername_arg);
 
-    if (!sent) {
-        OPENSSL_free(s->session->ext.hostname);
-        s->session->ext.hostname = NULL;
+    /*
+     * For servers, propagate the SNI hostname from the temporary
+     * storage in the SSL to the persistent SSL_SESSION, now that we
+     * know we accepted it.
+     * Clients make this copy when parsing the server's response to
+     * the extension, which is when they find out that the negotiation
+     * was successful.
+     */
+    if (s->server) {
+        if (sent && ret == SSL_TLSEXT_ERR_OK && !s->hit) {
+            /* Only store the hostname in the session if we accepted it. */
+            OPENSSL_free(s->session->ext.hostname);
+            s->session->ext.hostname = OPENSSL_strdup(s->ext.hostname);
+            if (s->session->ext.hostname == NULL && s->ext.hostname != NULL) {
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+            }
+        }
     }
 
     /*
@@ -864,11 +1029,10 @@ static int final_server_name(SSL *s, unsigned int context, int sent,
      * context, to avoid the confusing situation of having sess_accept_good
      * exceed sess_accept (zero) for the new context.
      */
-    if (SSL_IS_FIRST_HANDSHAKE(s) && s->ctx != s->session_ctx) {
-        CRYPTO_atomic_add(&s->ctx->stats.sess_accept, 1, &discard,
-                          s->ctx->lock);
-        CRYPTO_atomic_add(&s->session_ctx->stats.sess_accept, -1, &discard,
-                          s->session_ctx->lock);
+    if (SSL_IS_FIRST_HANDSHAKE(s) && sctx != s->session_ctx
+            && s->hello_retry_request == SSL_HRR_NONE) {
+        ssl_tsan_counter(sctx, &sctx->stats.sess_accept);
+        ssl_tsan_decr(s->session_ctx, &s->session_ctx->stats.sess_accept);
     }
 
     /*
@@ -877,10 +1041,10 @@ static int final_server_name(SSL *s, unsigned int context, int sent,
      * Also, if this is not a resumption, create a new session ID
      */
     if (ret == SSL_TLSEXT_ERR_OK && s->ext.ticket_expected
-            && was_ticket && (SSL_get_options(s) & SSL_OP_NO_TICKET) != 0) {
+            && was_ticket && (SSL_get_options(ssl) & SSL_OP_NO_TICKET) != 0) {
         s->ext.ticket_expected = 0;
         if (!s->hit) {
-            SSL_SESSION* ss = SSL_get_session(s);
+            SSL_SESSION* ss = SSL_get_session(ssl);
 
             if (ss != NULL) {
                 OPENSSL_free(ss->ext.tick);
@@ -888,31 +1052,31 @@ static int final_server_name(SSL *s, unsigned int context, int sent,
                 ss->ext.ticklen = 0;
                 ss->ext.tick_lifetime_hint = 0;
                 ss->ext.tick_age_add = 0;
-                ss->ext.tick_identity = 0;
                 if (!ssl_generate_session_id(s, ss)) {
-                    ret = SSL_TLSEXT_ERR_ALERT_FATAL;
-                    altmp = SSL_AD_INTERNAL_ERROR;
+                    SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+                    return 0;
                 }
             } else {
-                ret = SSL_TLSEXT_ERR_ALERT_FATAL;
-                altmp = SSL_AD_INTERNAL_ERROR;
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+                return 0;
             }
         }
     }
 
     switch (ret) {
     case SSL_TLSEXT_ERR_ALERT_FATAL:
-        *al = altmp;
+        SSLfatal(s, altmp, SSL_R_CALLBACK_FAILED);
         return 0;
 
     case SSL_TLSEXT_ERR_ALERT_WARNING:
-        *al = altmp;
+        /* TLSv1.3 doesn't have warning alerts so we suppress this */
+        if (!SSL_CONNECTION_IS_TLS13(s))
+            ssl3_send_alert(s, SSL3_AL_WARNING, altmp);
+        s->servername_done = 0;
         return 1;
 
     case SSL_TLSEXT_ERR_NOACK:
         s->servername_done = 0;
-        if (s->server && s->session->ext.hostname != NULL)
-            s->ext.early_data_ok = 0;
         return 1;
 
     default:
@@ -920,17 +1084,16 @@ static int final_server_name(SSL *s, unsigned int context, int sent,
     }
 }
 
-#ifndef OPENSSL_NO_EC
-static int final_ec_pt_formats(SSL *s, unsigned int context, int sent,
-                                       int *al)
+static int final_ec_pt_formats(SSL_CONNECTION *s, unsigned int context,
+                               int sent)
 {
     unsigned long alg_k, alg_a;
 
     if (s->server)
         return 1;
 
-    alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
-    alg_a = s->s3->tmp.new_cipher->algorithm_auth;
+    alg_k = s->s3.tmp.new_cipher->algorithm_mkey;
+    alg_a = s->s3.tmp.new_cipher->algorithm_auth;
 
     /*
      * If we are client and using an elliptic curve cryptography cipher
@@ -939,29 +1102,28 @@ static int final_ec_pt_formats(SSL *s, unsigned int context, int sent,
      */
     if (s->ext.ecpointformats != NULL
             && s->ext.ecpointformats_len > 0
-            && s->session->ext.ecpointformats != NULL
-            && s->session->ext.ecpointformats_len > 0
+            && s->ext.peer_ecpointformats != NULL
+            && s->ext.peer_ecpointformats_len > 0
             && ((alg_k & SSL_kECDHE) || (alg_a & SSL_aECDSA))) {
         /* we are using an ECC cipher */
         size_t i;
-        unsigned char *list = s->session->ext.ecpointformats;
+        unsigned char *list = s->ext.peer_ecpointformats;
 
-        for (i = 0; i < s->session->ext.ecpointformats_len; i++) {
+        for (i = 0; i < s->ext.peer_ecpointformats_len; i++) {
             if (*list++ == TLSEXT_ECPOINTFORMAT_uncompressed)
                 break;
         }
-        if (i == s->session->ext.ecpointformats_len) {
-            SSLerr(SSL_F_FINAL_EC_PT_FORMATS,
-                   SSL_R_TLS_INVALID_ECPOINTFORMAT_LIST);
+        if (i == s->ext.peer_ecpointformats_len) {
+            SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER,
+                     SSL_R_TLS_INVALID_ECPOINTFORMAT_LIST);
             return 0;
         }
     }
 
     return 1;
 }
-#endif
 
-static int init_session_ticket(SSL *s, unsigned int context)
+static int init_session_ticket(SSL_CONNECTION *s, unsigned int context)
 {
     if (!s->server)
         s->ext.ticket_expected = 0;
@@ -970,7 +1132,7 @@ static int init_session_ticket(SSL *s, unsigned int context)
 }
 
 #ifndef OPENSSL_NO_OCSP
-static int init_status_request(SSL *s, unsigned int context)
+static int init_status_request(SSL_CONNECTION *s, unsigned int context)
 {
     if (s->server) {
         s->ext.status_type = TLSEXT_STATUSTYPE_nothing;
@@ -989,33 +1151,33 @@ static int init_status_request(SSL *s, unsigned int context)
 #endif
 
 #ifndef OPENSSL_NO_NEXTPROTONEG
-static int init_npn(SSL *s, unsigned int context)
+static int init_npn(SSL_CONNECTION *s, unsigned int context)
 {
-    s->s3->npn_seen = 0;
+    s->s3.npn_seen = 0;
 
     return 1;
 }
 #endif
 
-static int init_alpn(SSL *s, unsigned int context)
+static int init_alpn(SSL_CONNECTION *s, unsigned int context)
 {
-    OPENSSL_free(s->s3->alpn_selected);
-    s->s3->alpn_selected = NULL;
-    s->s3->alpn_selected_len = 0;
+    OPENSSL_free(s->s3.alpn_selected);
+    s->s3.alpn_selected = NULL;
+    s->s3.alpn_selected_len = 0;
     if (s->server) {
-        OPENSSL_free(s->s3->alpn_proposed);
-        s->s3->alpn_proposed = NULL;
-        s->s3->alpn_proposed_len = 0;
+        OPENSSL_free(s->s3.alpn_proposed);
+        s->s3.alpn_proposed = NULL;
+        s->s3.alpn_proposed_len = 0;
     }
     return 1;
 }
 
-static int final_alpn(SSL *s, unsigned int context, int sent, int *al)
+static int final_alpn(SSL_CONNECTION *s, unsigned int context, int sent)
 {
     if (!s->server && !sent && s->session->ext.alpn_selected != NULL)
             s->ext.early_data_ok = 0;
 
-    if (!s->server || !SSL_IS_TLS13(s))
+    if (!s->server || !SSL_CONNECTION_IS_TLS13(s))
         return 1;
 
     /*
@@ -1024,21 +1186,35 @@ static int final_alpn(SSL *s, unsigned int context, int sent, int *al)
      * we also have to do this before we decide whether to accept early_data.
      * In TLSv1.3 we've already negotiated our cipher so we do this call now.
      * For < TLSv1.3 we defer it until after cipher negotiation.
+     *
+     * On failure SSLfatal() already called.
      */
-    return tls_handle_alpn(s, al);
+    return tls_handle_alpn(s);
 }
 
-static int init_sig_algs(SSL *s, unsigned int context)
+static int init_sig_algs(SSL_CONNECTION *s, unsigned int context)
 {
     /* Clear any signature algorithms extension received */
-    OPENSSL_free(s->s3->tmp.peer_sigalgs);
-    s->s3->tmp.peer_sigalgs = NULL;
+    OPENSSL_free(s->s3.tmp.peer_sigalgs);
+    s->s3.tmp.peer_sigalgs = NULL;
+    s->s3.tmp.peer_sigalgslen = 0;
+
+    return 1;
+}
+
+static int init_sig_algs_cert(SSL_CONNECTION *s,
+                              ossl_unused unsigned int context)
+{
+    /* Clear any signature algorithms extension received */
+    OPENSSL_free(s->s3.tmp.peer_cert_sigalgs);
+    s->s3.tmp.peer_cert_sigalgs = NULL;
+    s->s3.tmp.peer_cert_sigalgslen = 0;
 
     return 1;
 }
 
 #ifndef OPENSSL_NO_SRP
-static int init_srp(SSL *s, unsigned int context)
+static int init_srp(SSL_CONNECTION *s, unsigned int context)
 {
     OPENSSL_free(s->srp_ctx.login);
     s->srp_ctx.login = NULL;
@@ -1047,32 +1223,51 @@ static int init_srp(SSL *s, unsigned int context)
 }
 #endif
 
-static int init_etm(SSL *s, unsigned int context)
+static int init_ec_point_formats(SSL_CONNECTION *s, unsigned int context)
+{
+    OPENSSL_free(s->ext.peer_ecpointformats);
+    s->ext.peer_ecpointformats = NULL;
+    s->ext.peer_ecpointformats_len = 0;
+
+    return 1;
+}
+
+static int init_etm(SSL_CONNECTION *s, unsigned int context)
 {
     s->ext.use_etm = 0;
 
     return 1;
 }
 
-static int init_ems(SSL *s, unsigned int context)
+static int init_ems(SSL_CONNECTION *s, unsigned int context)
 {
-    if (!s->server)
-        s->s3->flags &= ~TLS1_FLAGS_RECEIVED_EXTMS;
+    if (s->s3.flags & TLS1_FLAGS_RECEIVED_EXTMS) {
+        s->s3.flags &= ~TLS1_FLAGS_RECEIVED_EXTMS;
+        s->s3.flags |= TLS1_FLAGS_REQUIRED_EXTMS;
+    }
 
     return 1;
 }
 
-static int final_ems(SSL *s, unsigned int context, int sent, int *al)
+static int final_ems(SSL_CONNECTION *s, unsigned int context, int sent)
 {
+    /*
+     * Check extended master secret extension is not dropped on
+     * renegotiation.
+     */
+    if (!(s->s3.flags & TLS1_FLAGS_RECEIVED_EXTMS)
+        && (s->s3.flags & TLS1_FLAGS_REQUIRED_EXTMS)) {
+        SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE, SSL_R_INCONSISTENT_EXTMS);
+        return 0;
+    }
     if (!s->server && s->hit) {
         /*
          * Check extended master secret extension is consistent with
          * original session.
          */
-        if (!(s->s3->flags & TLS1_FLAGS_RECEIVED_EXTMS) !=
+        if (!(s->s3.flags & TLS1_FLAGS_RECEIVED_EXTMS) !=
             !(s->session->flags & SSL_SESS_FLAG_EXTMS)) {
-            *al = SSL_AD_HANDSHAKE_FAILURE;
-            SSLerr(SSL_F_FINAL_EMS, SSL_R_INCONSISTENT_EXTMS);
+            SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE, SSL_R_INCONSISTENT_EXTMS);
             return 0;
         }
     }
@@ -1080,51 +1275,58 @@ static int final_ems(SSL *s, unsigned int context, int sent, int *al)
     return 1;
 }
 
-static int init_certificate_authorities(SSL *s, unsigned int context)
+static int init_certificate_authorities(SSL_CONNECTION *s, unsigned int context)
 {
-    sk_X509_NAME_pop_free(s->s3->tmp.peer_ca_names, X509_NAME_free);
-    s->s3->tmp.peer_ca_names = NULL;
+    sk_X509_NAME_pop_free(s->s3.tmp.peer_ca_names, X509_NAME_free);
+    s->s3.tmp.peer_ca_names = NULL;
     return 1;
 }
 
-static EXT_RETURN tls_construct_certificate_authorities(SSL *s, WPACKET *pkt,
+static EXT_RETURN tls_construct_certificate_authorities(SSL_CONNECTION *s,
+                                                        WPACKET *pkt,
                                                         unsigned int context,
                                                         X509 *x,
-                                                        size_t chainidx,
-                                                        int *al)
+                                                        size_t chainidx)
 {
-    const STACK_OF(X509_NAME) *ca_sk = SSL_get0_CA_list(s);
+    const STACK_OF(X509_NAME) *ca_sk = get_ca_names(s);
 
     if (ca_sk == NULL || sk_X509_NAME_num(ca_sk) == 0)
         return EXT_RETURN_NOT_SENT;
 
     if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_certificate_authorities)
-        || !WPACKET_start_sub_packet_u16(pkt)
-        || !construct_ca_names(s, pkt)
-        || !WPACKET_close(pkt)) {
-        SSLerr(SSL_F_TLS_CONSTRUCT_CERTIFICATE_AUTHORITIES,
-               ERR_R_INTERNAL_ERROR);
+        || !WPACKET_start_sub_packet_u16(pkt)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+        return EXT_RETURN_FAIL;
+    }
+
+    if (!construct_ca_names(s, ca_sk, pkt)) {
+        /* SSLfatal() already called */
+        return EXT_RETURN_FAIL;
+    }
+
+    if (!WPACKET_close(pkt)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
         return EXT_RETURN_FAIL;
     }
 
     return EXT_RETURN_SENT;
 }
 
-static int tls_parse_certificate_authorities(SSL *s, PACKET *pkt,
+static int tls_parse_certificate_authorities(SSL_CONNECTION *s, PACKET *pkt,
                                              unsigned int context, X509 *x,
-                                             size_t chainidx, int *al)
+                                             size_t chainidx)
 {
-    if (!parse_ca_names(s, pkt, al))
+    if (!parse_ca_names(s, pkt))
         return 0;
     if (PACKET_remaining(pkt) != 0) {
-        *al = SSL_AD_DECODE_ERROR;
+        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_R_BAD_EXTENSION);
         return 0;
     }
     return 1;
 }
 
 #ifndef OPENSSL_NO_SRTP
-static int init_srtp(SSL *s, unsigned int context)
+static int init_srtp(SSL_CONNECTION *s, unsigned int context)
 {
     if (s->server)
         s->srtp_profile = NULL;
@@ -1133,21 +1335,21 @@ static int init_srtp(SSL *s, unsigned int context)
 }
 #endif
 
-static int final_sig_algs(SSL *s, unsigned int context, int sent, int *al)
+static int final_sig_algs(SSL_CONNECTION *s, unsigned int context, int sent)
 {
-    if (!sent && SSL_IS_TLS13(s) && !s->hit) {
-        *al = TLS13_AD_MISSING_EXTENSION;
-        SSLerr(SSL_F_FINAL_SIG_ALGS, SSL_R_MISSING_SIGALGS_EXTENSION);
+    if (!sent && SSL_CONNECTION_IS_TLS13(s) && !s->hit) {
+        SSLfatal(s, TLS13_AD_MISSING_EXTENSION,
+                 SSL_R_MISSING_SIGALGS_EXTENSION);
         return 0;
     }
 
     return 1;
 }
 
-#ifndef OPENSSL_NO_EC
-static int final_key_share(SSL *s, unsigned int context, int sent, int *al)
+static int final_key_share(SSL_CONNECTION *s, unsigned int context, int sent)
 {
-    if (!SSL_IS_TLS13(s))
+#if !defined(OPENSSL_NO_TLS1_3)
+    if (!SSL_CONNECTION_IS_TLS13(s))
         return 1;
 
     /* Nothing to do for key_share in an HRR */
@@ -1170,103 +1372,148 @@ static int final_key_share(SSL *s, unsigned int context, int sent, int *al)
             && (!s->hit
                 || (s->ext.psk_kex_mode & TLSEXT_KEX_MODE_FLAG_KE) == 0)) {
         /* Nothing left we can do - just fail */
-        *al = SSL_AD_MISSING_EXTENSION;
-        SSLerr(SSL_F_FINAL_KEY_SHARE, SSL_R_NO_SUITABLE_KEY_SHARE);
+        SSLfatal(s, SSL_AD_MISSING_EXTENSION, SSL_R_NO_SUITABLE_KEY_SHARE);
         return 0;
     }
     /*
-     * If
+     * IF
      *     we are a server
-     *     AND
-     *     we have no key_share
      * THEN
-     *     If
-     *         we didn't already send a HelloRetryRequest
-     *         AND
-     *         the client sent a key_share extension
-     *         AND
-     *         (we are not resuming
-     *          OR the kex_mode allows key_share resumes)
-     *         AND
-     *         a shared group exists
-     *     THEN
-     *         send a HelloRetryRequest
-     *     ELSE If
-     *         we are not resuming
-     *         OR
-     *         the kex_mode doesn't allow non key_share resumes
+     *     IF
+     *         we have a suitable key_share
      *     THEN
-     *         fail;
+     *         IF
+     *             we are stateless AND we have no cookie
+     *         THEN
+     *             send a HelloRetryRequest
+     *     ELSE
+     *         IF
+     *             we didn't already send a HelloRetryRequest
+     *             AND
+     *             the client sent a key_share extension
+     *             AND
+     *             (we are not resuming
+     *              OR the kex_mode allows key_share resumes)
+     *             AND
+     *             a shared group exists
+     *         THEN
+     *             send a HelloRetryRequest
+     *         ELSE IF
+     *             we are not resuming
+     *             OR
+     *             the kex_mode doesn't allow non key_share resumes
+     *         THEN
+     *             fail
+     *         ELSE IF
+     *             we are stateless AND we have no cookie
+     *         THEN
+     *             send a HelloRetryRequest
      */
-    if (s->server && s->s3->peer_tmp == NULL) {
-        /* No suitable share */
-        if (s->hello_retry_request == 0 && sent
-                && (!s->hit
-                    || (s->ext.psk_kex_mode & TLSEXT_KEX_MODE_FLAG_KE_DHE)
-                       != 0)) {
-            const uint16_t *pgroups, *clntgroups;
-            size_t num_groups, clnt_num_groups, i;
-            unsigned int group_id = 0;
-
-            /* Check if a shared group exists */
-
-            /* Get the clients list of supported groups. */
-            tls1_get_peer_groups(s, &clntgroups, &clnt_num_groups);
-            tls1_get_supported_groups(s, &pgroups, &num_groups);
-
-            /* Find the first group we allow that is also in client's list */
-            for (i = 0; i < num_groups; i++) {
-                group_id = pgroups[i];
-
-                if (check_in_list(s, group_id, clntgroups, clnt_num_groups, 1))
-                    break;
+    if (s->server) {
+        if (s->s3.peer_tmp != NULL) {
+            /* We have a suitable key_share */
+            if ((s->s3.flags & TLS1_FLAGS_STATELESS) != 0
+                    && !s->ext.cookieok) {
+                if (!ossl_assert(s->hello_retry_request == SSL_HRR_NONE)) {
+                    /*
+                     * If we are stateless then we wouldn't know about any
+                     * previously sent HRR - so how can this be anything other
+                     * than 0?
+                     */
+                    SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+                    return 0;
+                }
+                s->hello_retry_request = SSL_HRR_PENDING;
+                return 1;
             }
+        } else {
+            /* No suitable key_share */
+            if (s->hello_retry_request == SSL_HRR_NONE && sent
+                    && (!s->hit
+                        || (s->ext.psk_kex_mode & TLSEXT_KEX_MODE_FLAG_KE_DHE)
+                           != 0)) {
+                const uint16_t *pgroups, *clntgroups;
+                size_t num_groups, clnt_num_groups, i;
+                unsigned int group_id = 0;
+
+                /* Check if a shared group exists */
+
+                /* Get the clients list of supported groups. */
+                tls1_get_peer_groups(s, &clntgroups, &clnt_num_groups);
+                tls1_get_supported_groups(s, &pgroups, &num_groups);
+
+                /*
+                 * Find the first group we allow that is also in client's list
+                 */
+                for (i = 0; i < num_groups; i++) {
+                    group_id = pgroups[i];
+
+                    if (check_in_list(s, group_id, clntgroups, clnt_num_groups,
+                                      1))
+                        break;
+                }
 
-            if (i < num_groups) {
-                /* A shared group exists so send a HelloRetryRequest */
-                s->s3->group_id = group_id;
-                s->hello_retry_request = 1;
+                if (i < num_groups) {
+                    /* A shared group exists so send a HelloRetryRequest */
+                    s->s3.group_id = group_id;
+                    s->hello_retry_request = SSL_HRR_PENDING;
+                    return 1;
+                }
+            }
+            if (!s->hit
+                    || (s->ext.psk_kex_mode & TLSEXT_KEX_MODE_FLAG_KE) == 0) {
+                /* Nothing left we can do - just fail */
+                SSLfatal(s, sent ? SSL_AD_HANDSHAKE_FAILURE
+                                 : SSL_AD_MISSING_EXTENSION,
+                         SSL_R_NO_SUITABLE_KEY_SHARE);
+                return 0;
+            }
+
+            if ((s->s3.flags & TLS1_FLAGS_STATELESS) != 0
+                    && !s->ext.cookieok) {
+                if (!ossl_assert(s->hello_retry_request == SSL_HRR_NONE)) {
+                    /*
+                     * If we are stateless then we wouldn't know about any
+                     * previously sent HRR - so how can this be anything other
+                     * than 0?
+                     */
+                    SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+                    return 0;
+                }
+                s->hello_retry_request = SSL_HRR_PENDING;
                 return 1;
             }
         }
-        if (!s->hit
-                || (s->ext.psk_kex_mode & TLSEXT_KEX_MODE_FLAG_KE) == 0) {
-            /* Nothing left we can do - just fail */
-            if (!sent)
-                *al = SSL_AD_MISSING_EXTENSION;
-            else
-                *al = SSL_AD_HANDSHAKE_FAILURE;
-            SSLerr(SSL_F_FINAL_KEY_SHARE, SSL_R_NO_SUITABLE_KEY_SHARE);
+
+        /*
+         * We have a key_share so don't send any more HelloRetryRequest
+         * messages
+         */
+        if (s->hello_retry_request == SSL_HRR_PENDING)
+            s->hello_retry_request = SSL_HRR_COMPLETE;
+    } else {
+        /*
+         * For a client side resumption with no key_share we need to generate
+         * the handshake secret (otherwise this is done during key_share
+         * processing).
+         */
+        if (!sent && !tls13_generate_handshake_secret(s, NULL, 0)) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
             return 0;
         }
     }
-
-    /* We have a key_share so don't send any more HelloRetryRequest messages */
-    if (s->server)
-        s->hello_retry_request = 0;
-
-    /*
-     * For a client side resumption with no key_share we need to generate
-     * the handshake secret (otherwise this is done during key_share
-     * processing).
-     */
-    if (!sent && !s->server && !tls13_generate_handshake_secret(s, NULL, 0)) {
-        *al = SSL_AD_INTERNAL_ERROR;
-        SSLerr(SSL_F_FINAL_KEY_SHARE, ERR_R_INTERNAL_ERROR);
-        return 0;
-    }
-
+#endif /* !defined(OPENSSL_NO_TLS1_3) */
     return 1;
 }
-#endif
 
-static int init_psk_kex_modes(SSL *s, unsigned int context)
+static int init_psk_kex_modes(SSL_CONNECTION *s, unsigned int context)
 {
     s->ext.psk_kex_mode = TLSEXT_KEX_MODE_FLAG_NONE;
     return 1;
 }
 
-int tls_psk_do_binder(SSL *s, const EVP_MD *md, const unsigned char *msgstart,
+int tls_psk_do_binder(SSL_CONNECTION *s, const EVP_MD *md,
+                      const unsigned char *msgstart,
                       size_t binderoffset, const unsigned char *binderin,
                       unsigned char *binderout, SSL_SESSION *sess, int sign,
                       int external)
@@ -1275,15 +1522,24 @@ int tls_psk_do_binder(SSL *s, const EVP_MD *md, const unsigned char *msgstart,
     EVP_MD_CTX *mctx = NULL;
     unsigned char hash[EVP_MAX_MD_SIZE], binderkey[EVP_MAX_MD_SIZE];
     unsigned char finishedkey[EVP_MAX_MD_SIZE], tmpbinder[EVP_MAX_MD_SIZE];
-    unsigned char tmppsk[EVP_MAX_MD_SIZE];
-    unsigned char *early_secret, *psk;
-    const char resumption_label[] = "res binder";
-    const char external_label[] = "ext binder";
-    const char nonce_label[] = "resumption";
-    const char *label;
-    size_t bindersize, labelsize, hashsize = EVP_MD_size(md);
+    unsigned char *early_secret;
+    /* ASCII: "res binder", in hex for EBCDIC compatibility */
+    static const unsigned char resumption_label[] = "\x72\x65\x73\x20\x62\x69\x6E\x64\x65\x72";
+    /* ASCII: "ext binder", in hex for EBCDIC compatibility */
+    static const unsigned char external_label[] = "\x65\x78\x74\x20\x62\x69\x6E\x64\x65\x72";
+    const unsigned char *label;
+    size_t bindersize, labelsize, hashsize;
+    int hashsizei = EVP_MD_get_size(md);
     int ret = -1;
     int usepskfored = 0;
+    SSL_CTX *sctx = SSL_CONNECTION_GET_CTX(s);
+
+    /* Ensure cast to size_t is safe */
+    if (!ossl_assert(hashsizei >= 0)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+    hashsize = (size_t)hashsizei;
 
     if (external
             && s->early_data_state == SSL_EARLY_DATA_CONNECTING
@@ -1299,24 +1555,6 @@ int tls_psk_do_binder(SSL *s, const EVP_MD *md, const unsigned char *msgstart,
         labelsize = sizeof(resumption_label) - 1;
     }
 
-    if (sess->master_key_length != hashsize) {
-        SSLerr(SSL_F_TLS_PSK_DO_BINDER, SSL_R_BAD_PSK);
-        goto err;
-    }
-
-    if (external) {
-        psk = sess->master_key;
-    } else {
-        psk = tmppsk;
-        if (!tls13_hkdf_expand(s, md, sess->master_key,
-                               (const unsigned char *)nonce_label,
-                               sizeof(nonce_label) - 1, sess->ext.tick_nonce,
-                               sess->ext.tick_nonce_len, psk, hashsize)) {
-            SSLerr(SSL_F_TLS_PSK_DO_BINDER, ERR_R_INTERNAL_ERROR);
-            goto err;
-        }
-    }
-
     /*
      * Generate the early_secret. On the server side we've selected a PSK to
      * resume with (internal or external) so we always do this. On the client
@@ -1329,8 +1567,10 @@ int tls_psk_do_binder(SSL *s, const EVP_MD *md, const unsigned char *msgstart,
         early_secret = (unsigned char *)s->early_secret;
     else
         early_secret = (unsigned char *)sess->early_secret;
-    if (!tls13_generate_secret(s, md, NULL, psk, hashsize, early_secret)) {
-        SSLerr(SSL_F_TLS_PSK_DO_BINDER, ERR_R_INTERNAL_ERROR);
+
+    if (!tls13_generate_secret(s, md, NULL, sess->master_key,
+                               sess->master_key_length, early_secret)) {
+        /* SSLfatal() already called */
         goto err;
     }
 
@@ -1342,25 +1582,25 @@ int tls_psk_do_binder(SSL *s, const EVP_MD *md, const unsigned char *msgstart,
     if (mctx == NULL
             || EVP_DigestInit_ex(mctx, md, NULL) <= 0
             || EVP_DigestFinal_ex(mctx, hash, NULL) <= 0) {
-        SSLerr(SSL_F_TLS_PSK_DO_BINDER, ERR_R_INTERNAL_ERROR);
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
         goto err;
     }
 
     /* Generate the binder key */
-    if (!tls13_hkdf_expand(s, md, early_secret, (unsigned char *)label,
-                           labelsize, hash, hashsize, binderkey, hashsize)) {
-        SSLerr(SSL_F_TLS_PSK_DO_BINDER, ERR_R_INTERNAL_ERROR);
+    if (!tls13_hkdf_expand(s, md, early_secret, label, labelsize, hash,
+                           hashsize, binderkey, hashsize, 1)) {
+        /* SSLfatal() already called */
         goto err;
     }
 
     /* Generate the finished key */
     if (!tls13_derive_finishedkey(s, md, binderkey, finishedkey, hashsize)) {
-        SSLerr(SSL_F_TLS_PSK_DO_BINDER, ERR_R_INTERNAL_ERROR);
+        /* SSLfatal() already called */
         goto err;
     }
 
     if (EVP_DigestInit_ex(mctx, md, NULL) <= 0) {
-        SSLerr(SSL_F_TLS_PSK_DO_BINDER, ERR_R_INTERNAL_ERROR);
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
         goto err;
     }
 
@@ -1369,13 +1609,15 @@ int tls_psk_do_binder(SSL *s, const EVP_MD *md, const unsigned char *msgstart,
      * following a HelloRetryRequest then this includes the hash of the first
      * ClientHello and the HelloRetryRequest itself.
      */
-    if (s->hello_retry_request) {
+    if (s->hello_retry_request == SSL_HRR_PENDING) {
         size_t hdatalen;
+        long hdatalen_l;
         void *hdata;
 
-        hdatalen = BIO_get_mem_data(s->s3->handshake_buffer, &hdata);
-        if (hdatalen <= 0) {
-            SSLerr(SSL_F_TLS_PSK_DO_BINDER, SSL_R_BAD_HANDSHAKE_LENGTH);
+        hdatalen = hdatalen_l =
+            BIO_get_mem_data(s->s3.handshake_buffer, &hdata);
+        if (hdatalen_l <= 0) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_R_BAD_HANDSHAKE_LENGTH);
             goto err;
         }
 
@@ -1392,27 +1634,29 @@ int tls_psk_do_binder(SSL *s, const EVP_MD *md, const unsigned char *msgstart,
                     || !PACKET_get_length_prefixed_3(&hashprefix, &msg)
                     || !PACKET_forward(&hashprefix, 1)
                     || !PACKET_get_length_prefixed_3(&hashprefix, &msg)) {
-                SSLerr(SSL_F_TLS_PSK_DO_BINDER, ERR_R_INTERNAL_ERROR);
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
                 goto err;
             }
             hdatalen -= PACKET_remaining(&hashprefix);
         }
 
         if (EVP_DigestUpdate(mctx, hdata, hdatalen) <= 0) {
-            SSLerr(SSL_F_TLS_PSK_DO_BINDER, ERR_R_INTERNAL_ERROR);
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
             goto err;
         }
     }
 
     if (EVP_DigestUpdate(mctx, msgstart, binderoffset) <= 0
             || EVP_DigestFinal_ex(mctx, hash, NULL) <= 0) {
-        SSLerr(SSL_F_TLS_PSK_DO_BINDER, ERR_R_INTERNAL_ERROR);
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
         goto err;
     }
 
-    mackey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, NULL, finishedkey, hashsize);
+    mackey = EVP_PKEY_new_raw_private_key_ex(sctx->libctx, "HMAC",
+                                             sctx->propq, finishedkey,
+                                             hashsize);
     if (mackey == NULL) {
-        SSLerr(SSL_F_TLS_PSK_DO_BINDER, ERR_R_INTERNAL_ERROR);
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
         goto err;
     }
 
@@ -1420,11 +1664,12 @@ int tls_psk_do_binder(SSL *s, const EVP_MD *md, const unsigned char *msgstart,
         binderout = tmpbinder;
 
     bindersize = hashsize;
-    if (EVP_DigestSignInit(mctx, NULL, md, NULL, mackey) <= 0
+    if (EVP_DigestSignInit_ex(mctx, NULL, EVP_MD_get0_name(md), sctx->libctx,
+                              sctx->propq, mackey, NULL) <= 0
             || EVP_DigestSignUpdate(mctx, hash, hashsize) <= 0
             || EVP_DigestSignFinal(mctx, binderout, &bindersize) <= 0
             || bindersize != hashsize) {
-        SSLerr(SSL_F_TLS_PSK_DO_BINDER, ERR_R_INTERNAL_ERROR);
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
         goto err;
     }
 
@@ -1433,6 +1678,8 @@ int tls_psk_do_binder(SSL *s, const EVP_MD *md, const unsigned char *msgstart,
     } else {
         /* HMAC keys can't do EVP_DigestVerify* - use CRYPTO_memcmp instead */
         ret = (CRYPTO_memcmp(binderin, binderout, hashsize) == 0);
+        if (!ret)
+            SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_R_BINDER_DOES_NOT_VERIFY);
     }
 
  err:
@@ -1444,7 +1691,7 @@ int tls_psk_do_binder(SSL *s, const EVP_MD *md, const unsigned char *msgstart,
     return ret;
 }
 
-static int final_early_data(SSL *s, unsigned int context, int sent, int *al)
+static int final_early_data(SSL_CONNECTION *s, unsigned int context, int sent)
 {
     if (!sent)
         return 1;
@@ -1458,7 +1705,7 @@ static int final_early_data(SSL *s, unsigned int context, int sent, int *al)
              * later realised that it shouldn't have done (e.g. inconsistent
              * ALPN)
              */
-            *al = SSL_AD_ILLEGAL_PARAMETER;
+            SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_R_BAD_EARLY_DATA);
             return 0;
         }
 
@@ -1467,17 +1714,19 @@ static int final_early_data(SSL *s, unsigned int context, int sent, int *al)
 
     if (s->max_early_data == 0
             || !s->hit
-            || s->session->ext.tick_identity != 0
             || s->early_data_state != SSL_EARLY_DATA_ACCEPTING
             || !s->ext.early_data_ok
-            || s->hello_retry_request) {
+            || s->hello_retry_request != SSL_HRR_NONE
+            || (s->allow_early_data_cb != NULL
+                && !s->allow_early_data_cb(SSL_CONNECTION_GET_SSL(s),
+                                         s->allow_early_data_cb_data))) {
         s->ext.early_data = SSL_EARLY_DATA_REJECTED;
     } else {
         s->ext.early_data = SSL_EARLY_DATA_ACCEPTED;
 
         if (!tls13_change_cipher_state(s,
                     SSL3_CC_EARLY | SSL3_CHANGE_CIPHER_SERVER_READ)) {
-            *al = SSL_AD_INTERNAL_ERROR;
+            /* SSLfatal() already called */
             return 0;
         }
     }
@@ -1485,24 +1734,196 @@ static int final_early_data(SSL *s, unsigned int context, int sent, int *al)
     return 1;
 }
 
-static int final_maxfragmentlen(SSL *ssl, unsigned int context, int sent, int *al)
+static int final_maxfragmentlen(SSL_CONNECTION *s, unsigned int context,
+                                int sent)
 {
     /*
      * Session resumption on server-side with MFL extension active
      *  BUT MFL extension packet was not resent (i.e. sent == 0)
      */
-    if (ssl->server && ssl->hit && USE_MAX_FRAGMENT_LENGTH_EXT(ssl->session)
+    if (s->server && s->hit && USE_MAX_FRAGMENT_LENGTH_EXT(s->session)
             && !sent ) {
-        *al = SSL_AD_MISSING_EXTENSION;
+        SSLfatal(s, SSL_AD_MISSING_EXTENSION, SSL_R_BAD_EXTENSION);
         return 0;
     }
 
-    /* Current SSL buffer is lower than requested MFL */
-    if (ssl->session && USE_MAX_FRAGMENT_LENGTH_EXT(ssl->session)
-            && ssl->max_send_fragment < GET_MAX_FRAGMENT_LENGTH(ssl->session))
-        /* trigger a larger buffer reallocation */
-        if (!ssl3_setup_buffers(ssl))   
-            return 0;
+    if (s->session && USE_MAX_FRAGMENT_LENGTH_EXT(s->session)) {
+        s->rlayer.rrlmethod->set_max_frag_len(s->rlayer.rrl,
+                                              GET_MAX_FRAGMENT_LENGTH(s->session));
+        s->rlayer.wrlmethod->set_max_frag_len(s->rlayer.wrl,
+                                              ssl_get_max_send_fragment(s));
+    }
+
+    return 1;
+}
+
+static int init_post_handshake_auth(SSL_CONNECTION *s,
+                                    ossl_unused unsigned int context)
+{
+    s->post_handshake_auth = SSL_PHA_NONE;
+
+    return 1;
+}
+
+/*
+ * If clients offer "pre_shared_key" without a "psk_key_exchange_modes"
+ * extension, servers MUST abort the handshake.
+ */
+static int final_psk(SSL_CONNECTION *s, unsigned int context, int sent)
+{
+    if (s->server && sent && s->clienthello != NULL
+            && !s->clienthello->pre_proc_exts[TLSEXT_IDX_psk_kex_modes].present) {
+        SSLfatal(s, TLS13_AD_MISSING_EXTENSION,
+                 SSL_R_MISSING_PSK_KEX_MODES_EXTENSION);
+        return 0;
+    }
+
+    return 1;
+}
 
+static int tls_init_compress_certificate(SSL_CONNECTION *sc, unsigned int context)
+{
+    memset(sc->ext.compress_certificate_from_peer, 0,
+           sizeof(sc->ext.compress_certificate_from_peer));
+    return 1;
+}
+
+/* The order these are put into the packet imply a preference order: [brotli, zlib, zstd] */
+static EXT_RETURN tls_construct_compress_certificate(SSL_CONNECTION *sc, WPACKET *pkt,
+                                                     unsigned int context,
+                                                     X509 *x, size_t chainidx)
+{
+#ifndef OPENSSL_NO_COMP_ALG
+    int i;
+
+    if (!ossl_comp_has_alg(0))
+        return EXT_RETURN_NOT_SENT;
+
+    /* Server: Don't attempt to compress a non-X509 (i.e. an RPK) */
+    if (sc->server && sc->ext.server_cert_type != TLSEXT_cert_type_x509) {
+        sc->cert_comp_prefs[0] = TLSEXT_comp_cert_none;
+        return EXT_RETURN_NOT_SENT;
+    }
+
+    /* Client: If we sent a client cert-type extension, don't indicate compression */
+    if (!sc->server && sc->ext.client_cert_type_ctos) {
+        sc->cert_comp_prefs[0] = TLSEXT_comp_cert_none;
+        return EXT_RETURN_NOT_SENT;
+    }
+
+    /* Do not indicate we support receiving compressed certificates */
+    if ((sc->options & SSL_OP_NO_RX_CERTIFICATE_COMPRESSION) != 0)
+        return EXT_RETURN_NOT_SENT;
+
+    if (sc->cert_comp_prefs[0] == TLSEXT_comp_cert_none)
+        return EXT_RETURN_NOT_SENT;
+
+    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_compress_certificate)
+            || !WPACKET_start_sub_packet_u16(pkt)
+            || !WPACKET_start_sub_packet_u8(pkt))
+        goto err;
+
+    for (i = 0; sc->cert_comp_prefs[i] != TLSEXT_comp_cert_none; i++) {
+        if (!WPACKET_put_bytes_u16(pkt, sc->cert_comp_prefs[i]))
+            goto err;
+    }
+    if (!WPACKET_close(pkt) || !WPACKET_close(pkt))
+        goto err;
+
+    sc->ext.compress_certificate_sent = 1;
+    return EXT_RETURN_SENT;
+ err:
+    SSLfatal(sc, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+    return EXT_RETURN_FAIL;
+#else
+    return EXT_RETURN_NOT_SENT;
+#endif
+}
+
+#ifndef OPENSSL_NO_COMP_ALG
+static int tls_comp_in_pref(SSL_CONNECTION *sc, int alg)
+{
+    int i;
+
+    /* ossl_comp_has_alg() considers 0 as "any" */
+    if (alg == 0)
+        return 0;
+    /* Make sure algorithm is enabled */
+    if (!ossl_comp_has_alg(alg))
+        return 0;
+    /* If no preferences are set, it's ok */
+    if (sc->cert_comp_prefs[0] == TLSEXT_comp_cert_none)
+        return 1;
+    /* Find the algorithm */
+    for (i = 0; i < TLSEXT_comp_cert_limit; i++)
+        if (sc->cert_comp_prefs[i] == alg)
+            return 1;
+    return 0;
+}
+#endif
+
+int tls_parse_compress_certificate(SSL_CONNECTION *sc, PACKET *pkt, unsigned int context,
+                                   X509 *x, size_t chainidx)
+{
+#ifndef OPENSSL_NO_COMP_ALG
+    PACKET supported_comp_algs;
+    unsigned int comp;
+    int already_set[TLSEXT_comp_cert_limit];
+    int j = 0;
+
+    /* If no algorithms are available, ignore the extension */
+    if (!ossl_comp_has_alg(0))
+        return 1;
+
+    /* Don't attempt to compress a non-X509 (i.e. an RPK) */
+    if (sc->server && sc->ext.server_cert_type != TLSEXT_cert_type_x509)
+        return 1;
+    if (!sc->server && sc->ext.client_cert_type != TLSEXT_cert_type_x509)
+        return 1;
+
+    /* Ignore the extension and don't send compressed certificates */
+    if ((sc->options & SSL_OP_NO_TX_CERTIFICATE_COMPRESSION) != 0)
+        return 1;
+
+    if (!PACKET_as_length_prefixed_1(pkt, &supported_comp_algs)
+            || PACKET_remaining(&supported_comp_algs) == 0) {
+        SSLfatal(sc, SSL_AD_DECODE_ERROR, SSL_R_BAD_EXTENSION);
+        return 0;
+    }
+
+    memset(already_set, 0, sizeof(already_set));
+    /*
+     * The preference array has real values, so take a look at each
+     * value coming in, and make sure it's in our preference list
+     * The array is 0 (i.e. "none") terminated
+     * The preference list only contains supported algorithms
+     */
+    while (PACKET_get_net_2(&supported_comp_algs, &comp)) {
+        if (tls_comp_in_pref(sc, comp) && !already_set[comp]) {
+            sc->ext.compress_certificate_from_peer[j++] = comp;
+            already_set[comp] = 1;
+        }
+    }
+#endif
+    return 1;
+}
+
+static int init_server_cert_type(SSL_CONNECTION *sc, unsigned int context)
+{
+    /* Only reset when parsing client hello */
+    if (sc->server) {
+        sc->ext.server_cert_type_ctos = OSSL_CERT_TYPE_CTOS_NONE;
+        sc->ext.server_cert_type = TLSEXT_cert_type_x509;
+    }
+    return 1;
+}
+
+static int init_client_cert_type(SSL_CONNECTION *sc, unsigned int context)
+{
+    /* Only reset when parsing client hello */
+    if (sc->server) {
+        sc->ext.client_cert_type_ctos = OSSL_CERT_TYPE_CTOS_NONE;
+        sc->ext.client_cert_type = TLSEXT_cert_type_x509;
+    }
     return 1;
 }