QUIC: Refine SSL_shutdown and begin to implement SSL_shutdown_ex
[openssl.git] / ssl / ssl_lib.c
index c8ab4a66a0ec0bdaadd9ba0443182deb0427618f..b927e283fee8357b3900b2da478e19727c9a59a3 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2022 The OpenSSL Project Authors. All Rights Reserved.
  * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved
  * Copyright 2005 Nokia. All rights reserved.
  *
@@ -11,7 +11,7 @@
 
 #include <stdio.h>
 #include "ssl_local.h"
-#include "e_os.h"
+#include "internal/e_os.h"
 #include <openssl/objects.h>
 #include <openssl/x509v3.h>
 #include <openssl/rand.h>
 #include <openssl/async.h>
 #include <openssl/ct.h>
 #include <openssl/trace.h>
+#include <openssl/core_names.h>
 #include "internal/cryptlib.h"
+#include "internal/nelem.h"
 #include "internal/refcount.h"
 #include "internal/ktls.h"
+#include "quic/quic_local.h"
 
-static int ssl_undefined_function_1(SSL *ssl, SSL3_RECORD *r, size_t s, int t,
-                                    SSL_MAC_BUF *mac, size_t macsize)
-{
-    return ssl_undefined_function(ssl);
-}
-
-static int ssl_undefined_function_2(SSL *ssl, SSL3_RECORD *r, unsigned char *s,
-                                    int t)
-{
-    return ssl_undefined_function(ssl);
-}
-
-static int ssl_undefined_function_3(SSL *ssl, unsigned char *r,
+static int ssl_undefined_function_3(SSL_CONNECTION *sc, unsigned char *r,
                                     unsigned char *s, size_t t, size_t *u)
 {
-    return ssl_undefined_function(ssl);
+    return ssl_undefined_function(SSL_CONNECTION_GET_SSL(sc));
 }
 
-static int ssl_undefined_function_4(SSL *ssl, int r)
+static int ssl_undefined_function_4(SSL_CONNECTION *sc, int r)
 {
-    return ssl_undefined_function(ssl);
+    return ssl_undefined_function(SSL_CONNECTION_GET_SSL(sc));
 }
 
-static size_t ssl_undefined_function_5(SSL *ssl, const char *r, size_t s,
-                                       unsigned char *t)
+static size_t ssl_undefined_function_5(SSL_CONNECTION *sc, const char *r,
+                                       size_t s, unsigned char *t)
 {
-    return ssl_undefined_function(ssl);
+    return ssl_undefined_function(SSL_CONNECTION_GET_SSL(sc));
 }
 
 static int ssl_undefined_function_6(int r)
@@ -59,17 +50,20 @@ static int ssl_undefined_function_6(int r)
     return ssl_undefined_function(NULL);
 }
 
-static int ssl_undefined_function_7(SSL *ssl, unsigned char *r, size_t s,
-                                    const char *t, size_t u,
+static int ssl_undefined_function_7(SSL_CONNECTION *sc, unsigned char *r,
+                                    size_t s, const char *t, size_t u,
                                     const unsigned char *v, size_t w, int x)
 {
-    return ssl_undefined_function(ssl);
+    return ssl_undefined_function(SSL_CONNECTION_GET_SSL(sc));
+}
+
+static int ssl_undefined_function_8(SSL_CONNECTION *sc)
+{
+    return ssl_undefined_function(SSL_CONNECTION_GET_SSL(sc));
 }
 
 SSL3_ENC_METHOD ssl3_undef_enc_method = {
-    ssl_undefined_function_1,
-    ssl_undefined_function_2,
-    ssl_undefined_function,
+    ssl_undefined_function_8,
     ssl_undefined_function_3,
     ssl_undefined_function_4,
     ssl_undefined_function_5,
@@ -126,7 +120,6 @@ static int dane_ctx_enable(struct dane_ctx_st *dctx)
     if (mdord == NULL || mdevp == NULL) {
         OPENSSL_free(mdord);
         OPENSSL_free(mdevp);
-        ERR_raise(ERR_LIB_SSL, ERR_R_MALLOC_FAILURE);
         return 0;
     }
 
@@ -172,7 +165,7 @@ static void dane_final(SSL_DANE *dane)
     sk_danetls_record_pop_free(dane->trecs, tlsa_free);
     dane->trecs = NULL;
 
-    sk_X509_pop_free(dane->certs, X509_free);
+    OSSL_STACK_OF_X509_free(dane->certs);
     dane->certs = NULL;
 
     X509_free(dane->mcert);
@@ -185,7 +178,7 @@ static void dane_final(SSL_DANE *dane)
 /*
  * dane_copy - Copy dane configuration, sans verification state.
  */
-static int ssl_dane_dup(SSL *to, SSL *from)
+static int ssl_dane_dup(SSL_CONNECTION *to, SSL_CONNECTION *from)
 {
     int num;
     int i;
@@ -196,19 +189,19 @@ static int ssl_dane_dup(SSL *to, SSL *from)
     num = sk_danetls_record_num(from->dane.trecs);
     dane_final(&to->dane);
     to->dane.flags = from->dane.flags;
-    to->dane.dctx = &to->ctx->dane;
+    to->dane.dctx = &SSL_CONNECTION_GET_CTX(to)->dane;
     to->dane.trecs = sk_danetls_record_new_reserve(NULL, num);
 
     if (to->dane.trecs == NULL) {
-        ERR_raise(ERR_LIB_SSL, ERR_R_MALLOC_FAILURE);
+        ERR_raise(ERR_LIB_SSL, ERR_R_CRYPTO_LIB);
         return 0;
     }
 
     for (i = 0; i < num; ++i) {
         danetls_record *t = sk_danetls_record_value(from->dane.trecs, i);
 
-        if (SSL_dane_tlsa_add(to, t->usage, t->selector, t->mtype,
-                              t->data, t->dlen) <= 0)
+        if (SSL_dane_tlsa_add(SSL_CONNECTION_GET_SSL(to), t->usage,
+                              t->selector, t->mtype, t->data, t->dlen) <= 0)
             return 0;
     }
     return 1;
@@ -230,17 +223,13 @@ static int dane_mtype_set(struct dane_ctx_st *dctx,
         int n = ((int)mtype) + 1;
 
         mdevp = OPENSSL_realloc(dctx->mdevp, n * sizeof(*mdevp));
-        if (mdevp == NULL) {
-            ERR_raise(ERR_LIB_SSL, ERR_R_MALLOC_FAILURE);
+        if (mdevp == NULL)
             return -1;
-        }
         dctx->mdevp = mdevp;
 
         mdord = OPENSSL_realloc(dctx->mdord, n * sizeof(*mdord));
-        if (mdord == NULL) {
-            ERR_raise(ERR_LIB_SSL, ERR_R_MALLOC_FAILURE);
+        if (mdord == NULL)
             return -1;
-        }
         dctx->mdord = mdord;
 
         /* Zero-fill any gaps */
@@ -314,10 +303,8 @@ static int dane_tlsa_add(SSL_DANE *dane,
         return 0;
     }
 
-    if ((t = OPENSSL_zalloc(sizeof(*t))) == NULL) {
-        ERR_raise(ERR_LIB_SSL, ERR_R_MALLOC_FAILURE);
+    if ((t = OPENSSL_zalloc(sizeof(*t))) == NULL)
         return -1;
-    }
 
     t->usage = usage;
     t->selector = selector;
@@ -325,7 +312,6 @@ static int dane_tlsa_add(SSL_DANE *dane,
     t->data = OPENSSL_malloc(dlen);
     if (t->data == NULL) {
         tlsa_free(t);
-        ERR_raise(ERR_LIB_SSL, ERR_R_MALLOC_FAILURE);
         return -1;
     }
     memcpy(t->data, data, dlen);
@@ -366,7 +352,7 @@ static int dane_tlsa_add(SSL_DANE *dane,
             if ((dane->certs == NULL &&
                  (dane->certs = sk_X509_new_null()) == NULL) ||
                 !sk_X509_push(dane->certs, cert)) {
-                ERR_raise(ERR_LIB_SSL, ERR_R_MALLOC_FAILURE);
+                ERR_raise(ERR_LIB_SSL, ERR_R_CRYPTO_LIB);
                 X509_free(cert);
                 tlsa_free(t);
                 return -1;
@@ -427,7 +413,7 @@ static int dane_tlsa_add(SSL_DANE *dane,
 
     if (!sk_danetls_record_insert(dane->trecs, t, i)) {
         tlsa_free(t);
-        ERR_raise(ERR_LIB_SSL, ERR_R_MALLOC_FAILURE);
+        ERR_raise(ERR_LIB_SSL, ERR_R_CRYPTO_LIB);
         return -1;
     }
     dane->umask |= DANETLS_USAGE_BIT(usage);
@@ -557,13 +543,30 @@ static int ssl_check_allowed_versions(int min_version, int max_version)
 void OPENSSL_VPROC_FUNC(void) {}
 #endif
 
-
-static void clear_ciphers(SSL *s)
+static int clear_record_layer(SSL_CONNECTION *s)
 {
-    /* clear the current cipher */
-    ssl_clear_cipher_ctx(s);
-    ssl_clear_hash_ctx(&s->read_hash);
-    ssl_clear_hash_ctx(&s->write_hash);
+    int ret;
+
+    /* We try and reset both record layers even if one fails */
+
+    ret = ssl_set_new_record_layer(s,
+                                   SSL_CONNECTION_IS_DTLS(s) ? DTLS_ANY_VERSION
+                                                             : TLS_ANY_VERSION,
+                                   OSSL_RECORD_DIRECTION_READ,
+                                   OSSL_RECORD_PROTECTION_LEVEL_NONE, NULL, 0,
+                                   NULL, 0, NULL, 0, NULL,  0, NULL, 0,
+                                   NID_undef, NULL, NULL, NULL);
+
+    ret &= ssl_set_new_record_layer(s,
+                                    SSL_CONNECTION_IS_DTLS(s) ? DTLS_ANY_VERSION
+                                                              : TLS_ANY_VERSION,
+                                    OSSL_RECORD_DIRECTION_WRITE,
+                                    OSSL_RECORD_PROTECTION_LEVEL_NONE, NULL, 0,
+                                    NULL, 0, NULL, 0, NULL,  0, NULL, 0,
+                                    NID_undef, NULL, NULL, NULL);
+
+    /* SSLfatal already called in the event of failure */
+    return ret;
 }
 
 int SSL_clear(SSL *s)
@@ -573,73 +576,91 @@ int SSL_clear(SSL *s)
         return 0;
     }
 
-    if (ssl_clear_bad_session(s)) {
-        SSL_SESSION_free(s->session);
-        s->session = NULL;
+    return s->method->ssl_reset(s);
+}
+
+int ossl_ssl_connection_reset(SSL *s)
+{
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+
+    if (sc == NULL)
+        return 0;
+
+    if (ssl_clear_bad_session(sc)) {
+        SSL_SESSION_free(sc->session);
+        sc->session = NULL;
     }
-    SSL_SESSION_free(s->psksession);
-    s->psksession = NULL;
-    OPENSSL_free(s->psksession_id);
-    s->psksession_id = NULL;
-    s->psksession_id_len = 0;
-    s->hello_retry_request = 0;
-    s->sent_tickets = 0;
+    SSL_SESSION_free(sc->psksession);
+    sc->psksession = NULL;
+    OPENSSL_free(sc->psksession_id);
+    sc->psksession_id = NULL;
+    sc->psksession_id_len = 0;
+    sc->hello_retry_request = 0;
+    sc->sent_tickets = 0;
 
-    s->error = 0;
-    s->hit = 0;
-    s->shutdown = 0;
+    sc->error = 0;
+    sc->hit = 0;
+    sc->shutdown = 0;
 
-    if (s->renegotiate) {
+    if (sc->renegotiate) {
         ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR);
         return 0;
     }
 
-    ossl_statem_clear(s);
+    ossl_statem_clear(sc);
 
-    s->version = s->method->version;
-    s->client_version = s->version;
-    s->rwstate = SSL_NOTHING;
+    /* TODO(QUIC): Version handling not yet clear */
+    sc->version = s->method->version;
+    sc->client_version = sc->version;
+    sc->rwstate = SSL_NOTHING;
 
-    BUF_MEM_free(s->init_buf);
-    s->init_buf = NULL;
-    clear_ciphers(s);
-    s->first_packet = 0;
+    BUF_MEM_free(sc->init_buf);
+    sc->init_buf = NULL;
+    sc->first_packet = 0;
 
-    s->key_update = SSL_KEY_UPDATE_NONE;
+    sc->key_update = SSL_KEY_UPDATE_NONE;
+    memset(sc->ext.compress_certificate_from_peer, 0,
+           sizeof(sc->ext.compress_certificate_from_peer));
+    sc->ext.compress_certificate_sent = 0;
 
-    EVP_MD_CTX_free(s->pha_dgst);
-    s->pha_dgst = NULL;
+    EVP_MD_CTX_free(sc->pha_dgst);
+    sc->pha_dgst = NULL;
 
     /* Reset DANE verification result state */
-    s->dane.mdpth = -1;
-    s->dane.pdpth = -1;
-    X509_free(s->dane.mcert);
-    s->dane.mcert = NULL;
-    s->dane.mtlsa = NULL;
+    sc->dane.mdpth = -1;
+    sc->dane.pdpth = -1;
+    X509_free(sc->dane.mcert);
+    sc->dane.mcert = NULL;
+    sc->dane.mtlsa = NULL;
 
     /* Clear the verification result peername */
-    X509_VERIFY_PARAM_move_peername(s->param, NULL);
+    X509_VERIFY_PARAM_move_peername(sc->param, NULL);
 
     /* Clear any shared connection state */
-    OPENSSL_free(s->shared_sigalgs);
-    s->shared_sigalgs = NULL;
-    s->shared_sigalgslen = 0;
+    OPENSSL_free(sc->shared_sigalgs);
+    sc->shared_sigalgs = NULL;
+    sc->shared_sigalgslen = 0;
 
     /*
      * Check to see if we were changed into a different method, if so, revert
      * back.
      */
-    if (s->method != s->ctx->method) {
-        s->method->ssl_free(s);
-        s->method = s->ctx->method;
-        if (!s->method->ssl_new(s))
+    if (s->method != s->defltmeth) {
+        s->method->ssl_deinit(s);
+        s->method = s->defltmeth;
+        if (!s->method->ssl_init(s))
             return 0;
     } else {
         if (!s->method->ssl_clear(s))
             return 0;
     }
 
-    RECORD_LAYER_clear(&s->rlayer);
+    RECORD_LAYER_clear(&sc->rlayer);
+    BIO_free(sc->rlayer.rrlnext);
+    sc->rlayer.rrlnext = NULL;
+
+    if (!clear_record_layer(sc))
+        return 0;
 
     return 1;
 }
@@ -671,8 +692,6 @@ int SSL_CTX_set_ssl_version(SSL_CTX *ctx, const SSL_METHOD *meth)
 
 SSL *SSL_new(SSL_CTX *ctx)
 {
-    SSL *s;
-
     if (ctx == NULL) {
         ERR_raise(ERR_LIB_SSL, SSL_R_NULL_SSL_CTX);
         return NULL;
@@ -681,17 +700,43 @@ SSL *SSL_new(SSL_CTX *ctx)
         ERR_raise(ERR_LIB_SSL, SSL_R_SSL_CTX_HAS_NO_DEFAULT_SSL_VERSION);
         return NULL;
     }
+    return ctx->method->ssl_new(ctx);
+}
+
+int ossl_ssl_init(SSL *ssl, SSL_CTX *ctx, const SSL_METHOD *method, int type)
+{
+    ssl->type = type;
+
+    ssl->references = 1;
+    ssl->lock = CRYPTO_THREAD_lock_new();
+    if (ssl->lock == NULL)
+        return 0;
+
+    SSL_CTX_up_ref(ctx);
+    ssl->ctx = ctx;
+
+    ssl->defltmeth = ssl->method = method;
+
+    if (!CRYPTO_new_ex_data(CRYPTO_EX_INDEX_SSL, ssl, &ssl->ex_data))
+        return 0;
+
+    return 1;
+}
+
+SSL *ossl_ssl_connection_new_int(SSL_CTX *ctx, const SSL_METHOD *method)
+{
+    SSL_CONNECTION *s;
+    SSL *ssl;
 
     s = OPENSSL_zalloc(sizeof(*s));
     if (s == NULL)
-        goto err;
+        return NULL;
 
-    s->references = 1;
-    s->lock = CRYPTO_THREAD_lock_new();
-    if (s->lock == NULL) {
+    ssl = &s->ssl;
+    if (!ossl_ssl_init(ssl, ctx, method, SSL_TYPE_SSL_CONNECTION)) {
         OPENSSL_free(s);
         s = NULL;
-        goto err;
+        goto sslerr;
     }
 
     RECORD_LAYER_init(&s->rlayer, s);
@@ -710,7 +755,7 @@ SSL *SSL_new(SSL_CTX *ctx)
     /* Shallow copy of the ciphersuites stack */
     s->tls13_ciphersuites = sk_SSL_CIPHER_dup(ctx->tls13_ciphersuites);
     if (s->tls13_ciphersuites == NULL)
-        goto err;
+        goto cerr;
 
     /*
      * Earlier library versions used to copy the pointer to the CERT, not
@@ -723,16 +768,16 @@ SSL *SSL_new(SSL_CTX *ctx)
      */
     s->cert = ssl_cert_dup(ctx->cert);
     if (s->cert == NULL)
-        goto err;
+        goto sslerr;
 
     RECORD_LAYER_set_read_ahead(&s->rlayer, ctx->read_ahead);
     s->msg_callback = ctx->msg_callback;
     s->msg_callback_arg = ctx->msg_callback_arg;
     s->verify_mode = ctx->verify_mode;
     s->not_resumable_session_cb = ctx->not_resumable_session_cb;
-    s->record_padding_cb = ctx->record_padding_cb;
-    s->record_padding_arg = ctx->record_padding_arg;
-    s->block_padding = ctx->block_padding;
+    s->rlayer.record_padding_cb = ctx->record_padding_cb;
+    s->rlayer.record_padding_arg = ctx->record_padding_arg;
+    s->rlayer.block_padding = ctx->block_padding;
     s->sid_ctx_length = ctx->sid_ctx_length;
     if (!ossl_assert(s->sid_ctx_length <= sizeof(s->sid_ctx)))
         goto err;
@@ -742,7 +787,7 @@ SSL *SSL_new(SSL_CTX *ctx)
 
     s->param = X509_VERIFY_PARAM_new();
     if (s->param == NULL)
-        goto err;
+        goto asn1err;
     X509_VERIFY_PARAM_inherit(s->param, ctx->param);
     s->quiet_shutdown = ctx->quiet_shutdown;
 
@@ -750,13 +795,8 @@ SSL *SSL_new(SSL_CTX *ctx)
     s->max_send_fragment = ctx->max_send_fragment;
     s->split_send_fragment = ctx->split_send_fragment;
     s->max_pipelines = ctx->max_pipelines;
-    if (s->max_pipelines > 1)
-        RECORD_LAYER_set_read_ahead(&s->rlayer, 1);
-    if (ctx->default_read_buf_len > 0)
-        SSL_set_default_read_buffer_len(s, ctx->default_read_buf_len);
+    s->rlayer.default_read_buf_len = ctx->default_read_buf_len;
 
-    SSL_CTX_up_ref(ctx);
-    s->ctx = ctx;
     s->ext.debug_cb = 0;
     s->ext.debug_arg = NULL;
     s->ext.ticket_expected = 0;
@@ -795,14 +835,14 @@ SSL *SSL_new(SSL_CTX *ctx)
     s->ext.npn = NULL;
 #endif
 
-    if (s->ctx->ext.alpn) {
-        s->ext.alpn = OPENSSL_malloc(s->ctx->ext.alpn_len);
+    if (ctx->ext.alpn != NULL) {
+        s->ext.alpn = OPENSSL_malloc(ctx->ext.alpn_len);
         if (s->ext.alpn == NULL) {
             s->ext.alpn_len = 0;
             goto err;
         }
-        memcpy(s->ext.alpn, s->ctx->ext.alpn, s->ctx->ext.alpn_len);
-        s->ext.alpn_len = s->ctx->ext.alpn_len;
+        memcpy(s->ext.alpn, ctx->ext.alpn, ctx->ext.alpn_len);
+        s->ext.alpn_len = ctx->ext.alpn_len;
     }
 
     s->verified_chain = NULL;
@@ -811,23 +851,18 @@ SSL *SSL_new(SSL_CTX *ctx)
     s->default_passwd_callback = ctx->default_passwd_callback;
     s->default_passwd_callback_userdata = ctx->default_passwd_callback_userdata;
 
-    s->method = ctx->method;
-
     s->key_update = SSL_KEY_UPDATE_NONE;
 
     s->allow_early_data_cb = ctx->allow_early_data_cb;
     s->allow_early_data_cb_data = ctx->allow_early_data_cb_data;
 
-    if (!s->method->ssl_new(s))
-        goto err;
-
-    s->server = (ctx->method->ssl_accept == ssl_undefined_function) ? 0 : 1;
+    if (!method->ssl_init(ssl))
+        goto sslerr;
 
-    if (!SSL_clear(s))
-        goto err;
+    s->server = (method->ssl_accept == ssl_undefined_function) ? 0 : 1;
 
-    if (!CRYPTO_new_ex_data(CRYPTO_EX_INDEX_SSL, s, &s->ex_data))
-        goto err;
+    if (!method->ssl_reset(ssl))
+        goto sslerr;
 
 #ifndef OPENSSL_NO_PSK
     s->psk_client_callback = ctx->psk_client_callback;
@@ -841,22 +876,43 @@ SSL *SSL_new(SSL_CTX *ctx)
 
     s->job = NULL;
 
+#ifndef OPENSSL_NO_COMP_ALG
+    memcpy(s->cert_comp_prefs, ctx->cert_comp_prefs, sizeof(s->cert_comp_prefs));
+#endif
+
 #ifndef OPENSSL_NO_CT
-    if (!SSL_set_ct_validation_callback(s, ctx->ct_validation_callback,
+    if (!SSL_set_ct_validation_callback(ssl, ctx->ct_validation_callback,
                                         ctx->ct_validation_callback_arg))
-        goto err;
+        goto sslerr;
 #endif
 
-    return s;
+    return ssl;
+ cerr:
+    ERR_raise(ERR_LIB_SSL, ERR_R_CRYPTO_LIB);
+    goto err;
+ asn1err:
+    ERR_raise(ERR_LIB_SSL, ERR_R_ASN1_LIB);
+    goto err;
+ sslerr:
+    ERR_raise(ERR_LIB_SSL, ERR_R_SSL_LIB);
  err:
-    SSL_free(s);
-    ERR_raise(ERR_LIB_SSL, ERR_R_MALLOC_FAILURE);
+    SSL_free(ssl);
     return NULL;
 }
 
+SSL *ossl_ssl_connection_new(SSL_CTX *ctx)
+{
+    return ossl_ssl_connection_new_int(ctx, ctx->method);
+}
+
 int SSL_is_dtls(const SSL *s)
 {
-    return SSL_IS_DTLS(s) ? 1 : 0;
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+
+    if (sc == NULL)
+        return 0;
+
+    return SSL_CONNECTION_IS_DTLS(sc) ? 1 : 0;
 }
 
 int SSL_up_ref(SSL *s)
@@ -887,12 +943,17 @@ int SSL_CTX_set_session_id_context(SSL_CTX *ctx, const unsigned char *sid_ctx,
 int SSL_set_session_id_context(SSL *ssl, const unsigned char *sid_ctx,
                                unsigned int sid_ctx_len)
 {
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(ssl);
+
+    if (sc == NULL)
+        return 0;
+
     if (sid_ctx_len > SSL_MAX_SID_CTX_LENGTH) {
         ERR_raise(ERR_LIB_SSL, SSL_R_SSL_SESSION_ID_CONTEXT_TOO_LONG);
         return 0;
     }
-    ssl->sid_ctx_length = sid_ctx_len;
-    memcpy(ssl->sid_ctx, sid_ctx, sid_ctx_len);
+    sc->sid_ctx_length = sid_ctx_len;
+    memcpy(sc->sid_ctx, sid_ctx, sid_ctx_len);
 
     return 1;
 }
@@ -908,9 +969,11 @@ int SSL_CTX_set_generate_session_id(SSL_CTX *ctx, GEN_SESSION_CB cb)
 
 int SSL_set_generate_session_id(SSL *ssl, GEN_SESSION_CB cb)
 {
-    if (!CRYPTO_THREAD_write_lock(ssl->lock))
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(ssl);
+
+    if (sc == NULL || !CRYPTO_THREAD_write_lock(ssl->lock))
         return 0;
-    ssl->generate_session_id = cb;
+    sc->generate_session_id = cb;
     CRYPTO_THREAD_unlock(ssl->lock);
     return 1;
 }
@@ -926,18 +989,19 @@ int SSL_has_matching_session_id(const SSL *ssl, const unsigned char *id,
      * by this SSL.
      */
     SSL_SESSION r, *p;
+    const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_CONST_SSL(ssl);
 
-    if (id_len > sizeof(r.session_id))
+    if (sc == NULL || id_len > sizeof(r.session_id))
         return 0;
 
-    r.ssl_version = ssl->version;
+    r.ssl_version = sc->version;
     r.session_id_length = id_len;
     memcpy(r.session_id, id, id_len);
 
-    if (!CRYPTO_THREAD_read_lock(ssl->session_ctx->lock))
+    if (!CRYPTO_THREAD_read_lock(sc->session_ctx->lock))
         return 0;
-    p = lh_SSL_SESSION_retrieve(ssl->session_ctx->sessions, &r);
-    CRYPTO_THREAD_unlock(ssl->session_ctx->lock);
+    p = lh_SSL_SESSION_retrieve(sc->session_ctx->sessions, &r);
+    CRYPTO_THREAD_unlock(sc->session_ctx->lock);
     return (p != NULL);
 }
 
@@ -948,7 +1012,12 @@ int SSL_CTX_set_purpose(SSL_CTX *s, int purpose)
 
 int SSL_set_purpose(SSL *s, int purpose)
 {
-    return X509_VERIFY_PARAM_set_purpose(s->param, purpose);
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+
+    if (sc == NULL)
+        return 0;
+
+    return X509_VERIFY_PARAM_set_purpose(sc->param, purpose);
 }
 
 int SSL_CTX_set_trust(SSL_CTX *s, int trust)
@@ -958,21 +1027,37 @@ int SSL_CTX_set_trust(SSL_CTX *s, int trust)
 
 int SSL_set_trust(SSL *s, int trust)
 {
-    return X509_VERIFY_PARAM_set_trust(s->param, trust);
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+
+    if (sc == NULL)
+        return 0;
+
+    return X509_VERIFY_PARAM_set_trust(sc->param, trust);
 }
 
 int SSL_set1_host(SSL *s, const char *hostname)
 {
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+
+    if (sc == NULL)
+        return 0;
+
     /* If a hostname is provided and parses as an IP address,
      * treat it as such. */
-    if (hostname && X509_VERIFY_PARAM_set1_ip_asc(s->param, hostname) == 1)
+    if (hostname != NULL
+        && X509_VERIFY_PARAM_set1_ip_asc(sc->param, hostname) == 1)
         return 1;
 
-    return X509_VERIFY_PARAM_set1_host(s->param, hostname, 0);
+    return X509_VERIFY_PARAM_set1_host(sc->param, hostname, 0);
 }
 
 int SSL_add1_host(SSL *s, const char *hostname)
 {
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+
+    if (sc == NULL)
+        return 0;
+
     /* If a hostname is provided and parses as an IP address,
      * treat it as such. */
     if (hostname)
@@ -985,7 +1070,7 @@ int SSL_add1_host(SSL *s, const char *hostname)
             /* We didn't want it; only to check if it *is* an IP address */
             ASN1_OCTET_STRING_free(ip);
 
-            old_ip = X509_VERIFY_PARAM_get1_ip_asc(s->param);
+            old_ip = X509_VERIFY_PARAM_get1_ip_asc(sc->param);
             if (old_ip)
             {
                 OPENSSL_free(old_ip);
@@ -993,21 +1078,31 @@ int SSL_add1_host(SSL *s, const char *hostname)
                 return 0;
             }
 
-            return X509_VERIFY_PARAM_set1_ip_asc(s->param, hostname);
+            return X509_VERIFY_PARAM_set1_ip_asc(sc->param, hostname);
         }
     }
 
-    return X509_VERIFY_PARAM_add1_host(s->param, hostname, 0);
+    return X509_VERIFY_PARAM_add1_host(sc->param, hostname, 0);
 }
 
 void SSL_set_hostflags(SSL *s, unsigned int flags)
 {
-    X509_VERIFY_PARAM_set_hostflags(s->param, flags);
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+
+    if (sc == NULL)
+        return;
+
+    X509_VERIFY_PARAM_set_hostflags(sc->param, flags);
 }
 
 const char *SSL_get0_peername(SSL *s)
 {
-    return X509_VERIFY_PARAM_get0_peername(s->param);
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+
+    if (sc == NULL)
+        return NULL;
+
+    return X509_VERIFY_PARAM_get0_peername(sc->param);
 }
 
 int SSL_CTX_dane_enable(SSL_CTX *ctx)
@@ -1033,8 +1128,13 @@ unsigned long SSL_CTX_dane_clear_flags(SSL_CTX *ctx, unsigned long flags)
 
 int SSL_dane_enable(SSL *s, const char *basedomain)
 {
-    SSL_DANE *dane = &s->dane;
+    SSL_DANE *dane;
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+
+    if (sc == NULL)
+        return 0;
 
+    dane = &sc->dane;
     if (s->ctx->dane.mdmax == 0) {
         ERR_raise(ERR_LIB_SSL, SSL_R_CONTEXT_NOT_DANE_ENABLED);
         return 0;
@@ -1046,10 +1146,10 @@ int SSL_dane_enable(SSL *s, const char *basedomain)
 
     /*
      * Default SNI name.  This rejects empty names, while set1_host below
-     * accepts them and disables host name checks.  To avoid side-effects with
+     * accepts them and disables hostname checks.  To avoid side-effects with
      * invalid input, set the SNI name first.
      */
-    if (s->ext.hostname == NULL) {
+    if (sc->ext.hostname == NULL) {
         if (!SSL_set_tlsext_host_name(s, basedomain)) {
             ERR_raise(ERR_LIB_SSL, SSL_R_ERROR_SETTING_TLSA_BASE_DOMAIN);
             return -1;
@@ -1057,7 +1157,7 @@ int SSL_dane_enable(SSL *s, const char *basedomain)
     }
 
     /* Primary RFC6125 reference identifier */
-    if (!X509_VERIFY_PARAM_set1_host(s->param, basedomain, 0)) {
+    if (!X509_VERIFY_PARAM_set1_host(sc->param, basedomain, 0)) {
         ERR_raise(ERR_LIB_SSL, SSL_R_ERROR_SETTING_TLSA_BASE_DOMAIN);
         return -1;
     }
@@ -1068,7 +1168,7 @@ int SSL_dane_enable(SSL *s, const char *basedomain)
     dane->trecs = sk_danetls_record_new_null();
 
     if (dane->trecs == NULL) {
-        ERR_raise(ERR_LIB_SSL, ERR_R_MALLOC_FAILURE);
+        ERR_raise(ERR_LIB_SSL, ERR_R_CRYPTO_LIB);
         return -1;
     }
     return 1;
@@ -1076,25 +1176,43 @@ int SSL_dane_enable(SSL *s, const char *basedomain)
 
 unsigned long SSL_dane_set_flags(SSL *ssl, unsigned long flags)
 {
-    unsigned long orig = ssl->dane.flags;
+    unsigned long orig;
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(ssl);
 
-    ssl->dane.flags |= flags;
+    if (sc == NULL)
+        return 0;
+
+    orig = sc->dane.flags;
+
+    sc->dane.flags |= flags;
     return orig;
 }
 
 unsigned long SSL_dane_clear_flags(SSL *ssl, unsigned long flags)
 {
-    unsigned long orig = ssl->dane.flags;
+    unsigned long orig;
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(ssl);
+
+    if (sc == NULL)
+        return 0;
+
+    orig = sc->dane.flags;
 
-    ssl->dane.flags &= ~flags;
+    sc->dane.flags &= ~flags;
     return orig;
 }
 
 int SSL_get0_dane_authority(SSL *s, X509 **mcert, EVP_PKEY **mspki)
 {
-    SSL_DANE *dane = &s->dane;
+    SSL_DANE *dane;
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+
+    if (sc == NULL)
+        return -1;
+
+    dane = &sc->dane;
 
-    if (!DANETLS_ENABLED(dane) || s->verify_result != X509_V_OK)
+    if (!DANETLS_ENABLED(dane) || sc->verify_result != X509_V_OK)
         return -1;
     if (dane->mtlsa) {
         if (mcert)
@@ -1108,9 +1226,15 @@ int SSL_get0_dane_authority(SSL *s, X509 **mcert, EVP_PKEY **mspki)
 int SSL_get0_dane_tlsa(SSL *s, uint8_t *usage, uint8_t *selector,
                        uint8_t *mtype, const unsigned char **data, size_t *dlen)
 {
-    SSL_DANE *dane = &s->dane;
+    SSL_DANE *dane;
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+
+    if (sc == NULL)
+        return -1;
+
+    dane = &sc->dane;
 
-    if (!DANETLS_ENABLED(dane) || s->verify_result != X509_V_OK)
+    if (!DANETLS_ENABLED(dane) || sc->verify_result != X509_V_OK)
         return -1;
     if (dane->mtlsa) {
         if (usage)
@@ -1129,13 +1253,23 @@ int SSL_get0_dane_tlsa(SSL *s, uint8_t *usage, uint8_t *selector,
 
 SSL_DANE *SSL_get0_dane(SSL *s)
 {
-    return &s->dane;
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+
+    if (sc == NULL)
+        return NULL;
+
+    return &sc->dane;
 }
 
 int SSL_dane_tlsa_add(SSL *s, uint8_t usage, uint8_t selector,
                       uint8_t mtype, const unsigned char *data, size_t dlen)
 {
-    return dane_tlsa_add(&s->dane, usage, selector, mtype, data, dlen);
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+
+    if (sc == NULL)
+        return 0;
+
+    return dane_tlsa_add(&sc->dane, usage, selector, mtype, data, dlen);
 }
 
 int SSL_CTX_dane_mtype_set(SSL_CTX *ctx, const EVP_MD *md, uint8_t mtype,
@@ -1151,7 +1285,12 @@ int SSL_CTX_set1_param(SSL_CTX *ctx, X509_VERIFY_PARAM *vpm)
 
 int SSL_set1_param(SSL *ssl, X509_VERIFY_PARAM *vpm)
 {
-    return X509_VERIFY_PARAM_set1(ssl->param, vpm);
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(ssl);
+
+    if (sc == NULL)
+        return 0;
+
+    return X509_VERIFY_PARAM_set1(sc->param, vpm);
 }
 
 X509_VERIFY_PARAM *SSL_CTX_get0_param(SSL_CTX *ctx)
@@ -1161,12 +1300,22 @@ X509_VERIFY_PARAM *SSL_CTX_get0_param(SSL_CTX *ctx)
 
 X509_VERIFY_PARAM *SSL_get0_param(SSL *ssl)
 {
-    return ssl->param;
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(ssl);
+
+    if (sc == NULL)
+        return NULL;
+
+    return sc->param;
 }
 
 void SSL_certs_clear(SSL *s)
 {
-    ssl_cert_clear_certs(s->cert);
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+
+    if (sc == NULL)
+        return;
+
+    ssl_cert_clear_certs(sc->cert);
 }
 
 void SSL_free(SSL *s)
@@ -1181,19 +1330,32 @@ void SSL_free(SSL *s)
         return;
     REF_ASSERT_ISNT(i < 0);
 
-    X509_VERIFY_PARAM_free(s->param);
-    dane_final(&s->dane);
     CRYPTO_free_ex_data(CRYPTO_EX_INDEX_SSL, s, &s->ex_data);
 
-    RECORD_LAYER_release(&s->rlayer);
+    if (s->method != NULL)
+        s->method->ssl_free(s);
+
+    SSL_CTX_free(s->ctx);
+    CRYPTO_THREAD_lock_free(s->lock);
+
+    OPENSSL_free(s);
+}
+
+void ossl_ssl_connection_free(SSL *ssl)
+{
+    SSL_CONNECTION *s;
+
+    s = SSL_CONNECTION_FROM_SSL_ONLY(ssl);
+    if (s == NULL)
+        return;
+
+    X509_VERIFY_PARAM_free(s->param);
+    dane_final(&s->dane);
 
     /* Ignore return value */
     ssl_free_wbio_buffer(s);
 
-    BIO_free_all(s->wbio);
-    s->wbio = NULL;
-    BIO_free_all(s->rbio);
-    s->rbio = NULL;
+    RECORD_LAYER_clear(&s->rlayer);
 
     BUF_MEM_free(s->init_buf);
 
@@ -1211,8 +1373,6 @@ void SSL_free(SSL *s)
     SSL_SESSION_free(s->psksession);
     OPENSSL_free(s->psksession_id);
 
-    clear_ciphers(s);
-
     ssl_cert_free(s->cert);
     OPENSSL_free(s->shared_sigalgs);
     /* Free up if allocated */
@@ -1243,12 +1403,10 @@ void SSL_free(SSL *s)
     sk_X509_NAME_pop_free(s->ca_names, X509_NAME_free);
     sk_X509_NAME_pop_free(s->client_ca_names, X509_NAME_free);
 
-    sk_X509_pop_free(s->verified_chain, X509_free);
-
-    if (s->method != NULL)
-        s->method->ssl_free(s);
+    OSSL_STACK_OF_X509_free(s->verified_chain);
 
-    SSL_CTX_free(s->ctx);
+    if (ssl->method != NULL)
+        ssl->method->ssl_deinit(ssl);
 
     ASYNC_WAIT_CTX_free(s->waitctx);
 
@@ -1260,31 +1418,67 @@ void SSL_free(SSL *s)
     sk_SRTP_PROTECTION_PROFILE_free(s->srtp_profiles);
 #endif
 
-    CRYPTO_THREAD_lock_free(s->lock);
-
-    OPENSSL_free(s);
+    /*
+     * We do this late. We want to ensure that any other references we held to
+     * these BIOs are freed first *before* we call BIO_free_all(), because
+     * BIO_free_all() will only free each BIO in the chain if the number of
+     * references to the first BIO have dropped to 0
+     */
+    BIO_free_all(s->wbio);
+    s->wbio = NULL;
+    BIO_free_all(s->rbio);
+    s->rbio = NULL;
 }
 
 void SSL_set0_rbio(SSL *s, BIO *rbio)
 {
-    BIO_free_all(s->rbio);
-    s->rbio = rbio;
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+#ifndef OPENSSL_NO_QUIC
+    QUIC_CONNECTION *qc = QUIC_CONNECTION_FROM_SSL(s);
+
+    if (qc != NULL) {
+        ossl_quic_conn_set0_net_rbio(qc, rbio);
+        return;
+    }
+#endif
+
+    if (sc == NULL)
+        return;
+
+    BIO_free_all(sc->rbio);
+    sc->rbio = rbio;
+    sc->rlayer.rrlmethod->set1_bio(sc->rlayer.rrl, sc->rbio);
 }
 
 void SSL_set0_wbio(SSL *s, BIO *wbio)
 {
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+#ifndef OPENSSL_NO_QUIC
+    QUIC_CONNECTION *qc = QUIC_CONNECTION_FROM_SSL(s);
+
+    if (qc != NULL) {
+        ossl_quic_conn_set0_net_wbio(qc, wbio);
+        return;
+    }
+#endif
+
+    if (sc == NULL)
+        return;
+
     /*
      * If the output buffering BIO is still in place, remove it
      */
-    if (s->bbio != NULL)
-        s->wbio = BIO_pop(s->wbio);
+    if (sc->bbio != NULL)
+        sc->wbio = BIO_pop(sc->wbio);
 
-    BIO_free_all(s->wbio);
-    s->wbio = wbio;
+    BIO_free_all(sc->wbio);
+    sc->wbio = wbio;
 
     /* Re-attach |bbio| to the new |wbio|. */
-    if (s->bbio != NULL)
-        s->wbio = BIO_push(s->bbio, s->wbio);
+    if (sc->bbio != NULL)
+        sc->wbio = BIO_push(sc->bbio, sc->wbio);
+
+    sc->rlayer.wrlmethod->set1_bio(sc->rlayer.wrl, sc->wbio);
 }
 
 void SSL_set_bio(SSL *s, BIO *rbio, BIO *wbio)
@@ -1329,19 +1523,41 @@ void SSL_set_bio(SSL *s, BIO *rbio, BIO *wbio)
 
 BIO *SSL_get_rbio(const SSL *s)
 {
-    return s->rbio;
+    const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_CONST_SSL(s);
+#ifndef OPENSSL_NO_QUIC
+    const QUIC_CONNECTION *qc = QUIC_CONNECTION_FROM_CONST_SSL(s);
+
+    if (qc != NULL)
+        return ossl_quic_conn_get_net_rbio(qc);
+#endif
+
+    if (sc == NULL)
+        return NULL;
+
+    return sc->rbio;
 }
 
 BIO *SSL_get_wbio(const SSL *s)
 {
-    if (s->bbio != NULL) {
+    const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_CONST_SSL(s);
+#ifndef OPENSSL_NO_QUIC
+    const QUIC_CONNECTION *qc = QUIC_CONNECTION_FROM_CONST_SSL(s);
+
+    if (qc != NULL)
+        return ossl_quic_conn_get_net_rbio(qc);
+#endif
+
+    if (sc == NULL)
+        return NULL;
+
+    if (sc->bbio != NULL) {
         /*
          * If |bbio| is active, the true caller-configured BIO is its
          * |next_bio|.
          */
-        return BIO_next(s->bbio);
+        return BIO_next(sc->bbio);
     }
-    return s->wbio;
+    return sc->wbio;
 }
 
 int SSL_get_fd(const SSL *s)
@@ -1458,11 +1674,15 @@ int SSL_set_rfd(SSL *s, int fd)
 size_t SSL_get_finished(const SSL *s, void *buf, size_t count)
 {
     size_t ret = 0;
+    const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_CONST_SSL(s);
+
+    if (sc == NULL)
+        return 0;
 
-    ret = s->s3.tmp.finish_md_len;
+    ret = sc->s3.tmp.finish_md_len;
     if (count > ret)
         count = ret;
-    memcpy(buf, s->s3.tmp.finish_md, count);
+    memcpy(buf, sc->s3.tmp.finish_md, count);
     return ret;
 }
 
@@ -1470,26 +1690,45 @@ size_t SSL_get_finished(const SSL *s, void *buf, size_t count)
 size_t SSL_get_peer_finished(const SSL *s, void *buf, size_t count)
 {
     size_t ret = 0;
+    const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_CONST_SSL(s);
 
-    ret = s->s3.tmp.peer_finish_md_len;
+    if (sc == NULL)
+        return 0;
+
+    ret = sc->s3.tmp.peer_finish_md_len;
     if (count > ret)
         count = ret;
-    memcpy(buf, s->s3.tmp.peer_finish_md, count);
+    memcpy(buf, sc->s3.tmp.peer_finish_md, count);
     return ret;
 }
 
 int SSL_get_verify_mode(const SSL *s)
 {
-    return s->verify_mode;
+    const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_CONST_SSL(s);
+
+    if (sc == NULL)
+        return 0;
+
+    return sc->verify_mode;
 }
 
 int SSL_get_verify_depth(const SSL *s)
 {
-    return X509_VERIFY_PARAM_get_depth(s->param);
+    const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_CONST_SSL(s);
+
+    if (sc == NULL)
+        return 0;
+
+    return X509_VERIFY_PARAM_get_depth(sc->param);
 }
 
 int (*SSL_get_verify_callback(const SSL *s)) (int, X509_STORE_CTX *) {
-    return s->verify_callback;
+    const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_CONST_SSL(s);
+
+    if (sc == NULL)
+        return NULL;
+
+    return sc->verify_callback;
 }
 
 int SSL_CTX_get_verify_mode(const SSL_CTX *ctx)
@@ -1509,24 +1748,52 @@ int (*SSL_CTX_get_verify_callback(const SSL_CTX *ctx)) (int, X509_STORE_CTX *) {
 void SSL_set_verify(SSL *s, int mode,
                     int (*callback) (int ok, X509_STORE_CTX *ctx))
 {
-    s->verify_mode = mode;
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+
+    if (sc == NULL)
+        return;
+
+    sc->verify_mode = mode;
     if (callback != NULL)
-        s->verify_callback = callback;
+        sc->verify_callback = callback;
 }
 
 void SSL_set_verify_depth(SSL *s, int depth)
 {
-    X509_VERIFY_PARAM_set_depth(s->param, depth);
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+
+    if (sc == NULL)
+        return;
+
+    X509_VERIFY_PARAM_set_depth(sc->param, depth);
 }
 
 void SSL_set_read_ahead(SSL *s, int yes)
 {
-    RECORD_LAYER_set_read_ahead(&s->rlayer, yes);
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+    OSSL_PARAM options[2], *opts = options;
+
+    if (sc == NULL)
+        return;
+
+    RECORD_LAYER_set_read_ahead(&sc->rlayer, yes);
+
+    *opts++ = OSSL_PARAM_construct_int(OSSL_LIBSSL_RECORD_LAYER_PARAM_READ_AHEAD,
+                                       &sc->rlayer.read_ahead);
+    *opts = OSSL_PARAM_construct_end();
+
+    /* Ignore return value */
+    sc->rlayer.rrlmethod->set_options(sc->rlayer.rrl, options);
 }
 
 int SSL_get_read_ahead(const SSL *s)
 {
-    return RECORD_LAYER_get_read_ahead(&s->rlayer);
+    const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_CONST_SSL(s);
+
+    if (sc == NULL)
+        return 0;
+
+    return RECORD_LAYER_get_read_ahead(&sc->rlayer);
 }
 
 int SSL_pending(const SSL *s)
@@ -1550,16 +1817,31 @@ int SSL_has_pending(const SSL *s)
 {
     /*
      * Similar to SSL_pending() but returns a 1 to indicate that we have
-     * unprocessed data available or 0 otherwise (as opposed to the number of
-     * bytes available). Unlike SSL_pending() this will take into account
-     * read_ahead data. A 1 return simply indicates that we have unprocessed
-     * data. That data may not result in any application data, or we may fail
-     * to parse the records for some reason.
+     * processed or unprocessed data available or 0 otherwise (as opposed to the
+     * number of bytes available). Unlike SSL_pending() this will take into
+     * account read_ahead data. A 1 return simply indicates that we have data.
+     * That data may not result in any application data, or we may fail to parse
+     * the records for some reason.
      */
-    if (RECORD_LAYER_processed_read_pending(&s->rlayer))
+    const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_CONST_SSL(s);
+
+    /* Check buffered app data if any first */
+    if (SSL_CONNECTION_IS_DTLS(sc)) {
+        TLS_RECORD *rdata;
+        pitem *item, *iter;
+
+        iter = pqueue_iterator(sc->rlayer.d->buffered_app_data.q);
+        while ((item = pqueue_next(&iter)) != NULL) {
+            rdata = item->data;
+            if (rdata->length > 0)
+                return 1;
+        }
+    }
+
+    if (RECORD_LAYER_processed_read_pending(&sc->rlayer))
         return 1;
 
-    return RECORD_LAYER_read_pending(&s->rlayer);
+    return RECORD_LAYER_read_pending(&sc->rlayer);
 }
 
 X509 *SSL_get1_peer_certificate(const SSL *s)
@@ -1574,20 +1856,29 @@ X509 *SSL_get1_peer_certificate(const SSL *s)
 
 X509 *SSL_get0_peer_certificate(const SSL *s)
 {
-    if ((s == NULL) || (s->session == NULL))
+    const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_CONST_SSL(s);
+
+    if (sc == NULL)
+        return NULL;
+
+    if (sc->session == NULL)
         return NULL;
     else
-        return s->session->peer;
+        return sc->session->peer;
 }
 
 STACK_OF(X509) *SSL_get_peer_cert_chain(const SSL *s)
 {
     STACK_OF(X509) *r;
+    const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_CONST_SSL(s);
 
-    if ((s == NULL) || (s->session == NULL))
+    if (sc == NULL)
+        return NULL;
+
+    if (sc->session == NULL)
         r = NULL;
     else
-        r = s->session->peer_chain;
+        r = sc->session->peer_chain;
 
     /*
      * If we are a client, cert_chain includes the peer's own certificate; if
@@ -1604,6 +1895,13 @@ STACK_OF(X509) *SSL_get_peer_cert_chain(const SSL *s)
 int SSL_copy_session_id(SSL *t, const SSL *f)
 {
     int i;
+    /* TODO(QUIC): Do we want to support this for QUIC connections? */
+    SSL_CONNECTION *tsc = SSL_CONNECTION_FROM_SSL_ONLY(t);
+    const SSL_CONNECTION *fsc = SSL_CONNECTION_FROM_CONST_SSL_ONLY(f);
+
+    if (tsc == NULL || fsc == NULL)
+        return 0;
+
     /* Do we need to do SSL locking? */
     if (!SSL_set_session(t, SSL_get_session(f))) {
         return 0;
@@ -1613,16 +1911,16 @@ int SSL_copy_session_id(SSL *t, const SSL *f)
      * what if we are setup for one protocol version but want to talk another
      */
     if (t->method != f->method) {
-        t->method->ssl_free(t);
+        t->method->ssl_deinit(t);
         t->method = f->method;
-        if (t->method->ssl_new(t) == 0)
+        if (t->method->ssl_init(t) == 0)
             return 0;
     }
 
-    CRYPTO_UP_REF(&f->cert->references, &i, f->cert->lock);
-    ssl_cert_free(t->cert);
-    t->cert = f->cert;
-    if (!SSL_set_session_id_context(t, f->sid_ctx, (int)f->sid_ctx_length)) {
+    CRYPTO_UP_REF(&fsc->cert->references, &i, fsc->cert->lock);
+    ssl_cert_free(tsc->cert);
+    tsc->cert = fsc->cert;
+    if (!SSL_set_session_id_context(t, fsc->sid_ctx, (int)fsc->sid_ctx_length)) {
         return 0;
     }
 
@@ -1647,25 +1945,32 @@ int SSL_CTX_check_private_key(const SSL_CTX *ctx)
 /* Fix this function so that it takes an optional type parameter */
 int SSL_check_private_key(const SSL *ssl)
 {
-    if (ssl == NULL) {
+    const SSL_CONNECTION *sc;
+
+    if ((sc = SSL_CONNECTION_FROM_CONST_SSL(ssl)) == NULL) {
         ERR_raise(ERR_LIB_SSL, ERR_R_PASSED_NULL_PARAMETER);
         return 0;
     }
-    if (ssl->cert->key->x509 == NULL) {
+    if (sc->cert->key->x509 == NULL) {
         ERR_raise(ERR_LIB_SSL, SSL_R_NO_CERTIFICATE_ASSIGNED);
         return 0;
     }
-    if (ssl->cert->key->privatekey == NULL) {
+    if (sc->cert->key->privatekey == NULL) {
         ERR_raise(ERR_LIB_SSL, SSL_R_NO_PRIVATE_KEY_ASSIGNED);
         return 0;
     }
-    return X509_check_private_key(ssl->cert->key->x509,
-                                   ssl->cert->key->privatekey);
+    return X509_check_private_key(sc->cert->key->x509,
+                                   sc->cert->key->privatekey);
 }
 
 int SSL_waiting_for_async(SSL *s)
 {
-    if (s->job)
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+
+    if (sc == NULL)
+        return 0;
+
+    if (sc->job)
         return 1;
 
     return 0;
@@ -1673,9 +1978,13 @@ int SSL_waiting_for_async(SSL *s)
 
 int SSL_get_all_async_fds(SSL *s, OSSL_ASYNC_FD *fds, size_t *numfds)
 {
-    ASYNC_WAIT_CTX *ctx = s->waitctx;
+    ASYNC_WAIT_CTX *ctx;
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
 
-    if (ctx == NULL)
+    if (sc == NULL)
+        return 0;
+
+    if ((ctx = sc->waitctx) == NULL)
         return 0;
     return ASYNC_WAIT_CTX_get_all_fds(ctx, fds, numfds);
 }
@@ -1683,9 +1992,13 @@ int SSL_get_all_async_fds(SSL *s, OSSL_ASYNC_FD *fds, size_t *numfds)
 int SSL_get_changed_async_fds(SSL *s, OSSL_ASYNC_FD *addfd, size_t *numaddfds,
                               OSSL_ASYNC_FD *delfd, size_t *numdelfds)
 {
-    ASYNC_WAIT_CTX *ctx = s->waitctx;
+    ASYNC_WAIT_CTX *ctx;
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
 
-    if (ctx == NULL)
+    if (sc == NULL)
+        return 0;
+
+    if ((ctx = sc->waitctx) == NULL)
         return 0;
     return ASYNC_WAIT_CTX_get_changed_fds(ctx, addfd, numaddfds, delfd,
                                           numdelfds);
@@ -1705,21 +2018,35 @@ int SSL_CTX_set_async_callback_arg(SSL_CTX *ctx, void *arg)
 
 int SSL_set_async_callback(SSL *s, SSL_async_callback_fn callback)
 {
-    s->async_cb = callback;
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+
+    if (sc == NULL)
+        return 0;
+
+    sc->async_cb = callback;
     return 1;
 }
 
 int SSL_set_async_callback_arg(SSL *s, void *arg)
 {
-    s->async_cb_arg = arg;
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+
+    if (sc == NULL)
+        return 0;
+
+    sc->async_cb_arg = arg;
     return 1;
 }
 
 int SSL_get_async_status(SSL *s, int *status)
 {
-    ASYNC_WAIT_CTX *ctx = s->waitctx;
+    ASYNC_WAIT_CTX *ctx;
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
 
-    if (ctx == NULL)
+    if (sc == NULL)
+        return 0;
+
+    if ((ctx = sc->waitctx) == NULL)
         return 0;
     *status = ASYNC_WAIT_CTX_get_status(ctx);
     return 1;
@@ -1727,17 +2054,39 @@ int SSL_get_async_status(SSL *s, int *status)
 
 int SSL_accept(SSL *s)
 {
-    if (s->handshake_func == NULL) {
-        /* Not properly initialized yet */
-        SSL_set_accept_state(s);
-    }
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+#ifndef OPENSSL_NO_QUIC
+    QUIC_CONNECTION *qc = QUIC_CONNECTION_FROM_SSL(s);
 
-    return SSL_do_handshake(s);
+    if (qc != NULL)
+        return s->method->ssl_accept(s);
+#endif
+
+    if (sc == NULL)
+        return 0;
+
+    if (sc->handshake_func == NULL) {
+        /* Not properly initialized yet */
+        SSL_set_accept_state(s);
+    }
+
+    return SSL_do_handshake(s);
 }
 
 int SSL_connect(SSL *s)
 {
-    if (s->handshake_func == NULL) {
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+#ifndef OPENSSL_NO_QUIC
+    QUIC_CONNECTION *qc = QUIC_CONNECTION_FROM_SSL(s);
+
+    if (qc != NULL)
+        return s->method->ssl_connect(s);
+#endif
+
+    if (sc == NULL)
+        return 0;
+
+    if (sc->handshake_func == NULL) {
         /* Not properly initialized yet */
         SSL_set_connect_state(s);
     }
@@ -1747,46 +2096,57 @@ int SSL_connect(SSL *s)
 
 long SSL_get_default_timeout(const SSL *s)
 {
-    return s->method->get_timeout();
+    return (long int)ossl_time2seconds(s->method->get_timeout());
 }
 
 static int ssl_async_wait_ctx_cb(void *arg)
 {
     SSL *s = (SSL *)arg;
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+
+    if (sc == NULL)
+        return 0;
 
-    return s->async_cb(s, s->async_cb_arg);
+    return sc->async_cb(s, sc->async_cb_arg);
 }
 
 static int ssl_start_async_job(SSL *s, struct ssl_async_args *args,
                                int (*func) (void *))
 {
     int ret;
-    if (s->waitctx == NULL) {
-        s->waitctx = ASYNC_WAIT_CTX_new();
-        if (s->waitctx == NULL)
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+
+    if (sc == NULL)
+        return 0;
+
+    if (sc->waitctx == NULL) {
+        sc->waitctx = ASYNC_WAIT_CTX_new();
+        if (sc->waitctx == NULL)
             return -1;
-        if (s->async_cb != NULL
+        if (sc->async_cb != NULL
             && !ASYNC_WAIT_CTX_set_callback
-                 (s->waitctx, ssl_async_wait_ctx_cb, s))
+                 (sc->waitctx, ssl_async_wait_ctx_cb, s))
             return -1;
     }
-    switch (ASYNC_start_job(&s->job, s->waitctx, &ret, func, args,
+
+    sc->rwstate = SSL_NOTHING;
+    switch (ASYNC_start_job(&sc->job, sc->waitctx, &ret, func, args,
                             sizeof(struct ssl_async_args))) {
     case ASYNC_ERR:
-        s->rwstate = SSL_NOTHING;
+        sc->rwstate = SSL_NOTHING;
         ERR_raise(ERR_LIB_SSL, SSL_R_FAILED_TO_INIT_ASYNC);
         return -1;
     case ASYNC_PAUSE:
-        s->rwstate = SSL_ASYNC_PAUSED;
+        sc->rwstate = SSL_ASYNC_PAUSED;
         return -1;
     case ASYNC_NO_JOBS:
-        s->rwstate = SSL_ASYNC_NO_JOBS;
+        sc->rwstate = SSL_ASYNC_NO_JOBS;
         return -1;
     case ASYNC_FINISH:
-        s->job = NULL;
+        sc->job = NULL;
         return ret;
     default:
-        s->rwstate = SSL_NOTHING;
+        sc->rwstate = SSL_NOTHING;
         ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR);
         /* Shouldn't happen */
         return -1;
@@ -1799,16 +2159,20 @@ static int ssl_io_intern(void *vargs)
     SSL *s;
     void *buf;
     size_t num;
+    SSL_CONNECTION *sc;
 
     args = (struct ssl_async_args *)vargs;
     s = args->s;
     buf = args->buf;
     num = args->num;
+    if ((sc = SSL_CONNECTION_FROM_SSL(s)) == NULL)
+        return -1;
+
     switch (args->type) {
     case READFUNC:
-        return args->f.func_read(s, buf, num, &s->asyncrw);
+        return args->f.func_read(s, buf, num, &sc->asyncrw);
     case WRITEFUNC:
-        return args->f.func_write(s, buf, num, &s->asyncrw);
+        return args->f.func_write(s, buf, num, &sc->asyncrw);
     case OTHERFUNC:
         return args->f.func_other(s);
     }
@@ -1817,18 +2181,29 @@ static int ssl_io_intern(void *vargs)
 
 int ssl_read_internal(SSL *s, void *buf, size_t num, size_t *readbytes)
 {
-    if (s->handshake_func == NULL) {
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+#ifndef OPENSSL_NO_QUIC
+    QUIC_CONNECTION *qc = QUIC_CONNECTION_FROM_SSL(s);
+
+    if (qc != NULL)
+        return s->method->ssl_read(s, buf, num, readbytes);
+#endif
+
+    if (sc == NULL)
+        return -1;
+
+    if (sc->handshake_func == NULL) {
         ERR_raise(ERR_LIB_SSL, SSL_R_UNINITIALIZED);
         return -1;
     }
 
-    if (s->shutdown & SSL_RECEIVED_SHUTDOWN) {
-        s->rwstate = SSL_NOTHING;
+    if (sc->shutdown & SSL_RECEIVED_SHUTDOWN) {
+        sc->rwstate = SSL_NOTHING;
         return 0;
     }
 
-    if (s->early_data_state == SSL_EARLY_DATA_CONNECT_RETRY
-                || s->early_data_state == SSL_EARLY_DATA_ACCEPT_RETRY) {
+    if (sc->early_data_state == SSL_EARLY_DATA_CONNECT_RETRY
+                || sc->early_data_state == SSL_EARLY_DATA_ACCEPT_RETRY) {
         ERR_raise(ERR_LIB_SSL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
         return 0;
     }
@@ -1836,9 +2211,9 @@ int ssl_read_internal(SSL *s, void *buf, size_t num, size_t *readbytes)
      * If we are a client and haven't received the ServerHello etc then we
      * better do that
      */
-    ossl_statem_check_finish_init(s, 0);
+    ossl_statem_check_finish_init(sc, 0);
 
-    if ((s->mode & SSL_MODE_ASYNC) && ASYNC_get_current_job() == NULL) {
+    if ((sc->mode & SSL_MODE_ASYNC) && ASYNC_get_current_job() == NULL) {
         struct ssl_async_args args;
         int ret;
 
@@ -1849,7 +2224,7 @@ int ssl_read_internal(SSL *s, void *buf, size_t num, size_t *readbytes)
         args.f.func_read = s->method->ssl_read;
 
         ret = ssl_start_async_job(s, &args, ssl_io_intern);
-        *readbytes = s->asyncrw;
+        *readbytes = sc->asyncrw;
         return ret;
     } else {
         return s->method->ssl_read(s, buf, num, readbytes);
@@ -1890,13 +2265,18 @@ int SSL_read_ex(SSL *s, void *buf, size_t num, size_t *readbytes)
 int SSL_read_early_data(SSL *s, void *buf, size_t num, size_t *readbytes)
 {
     int ret;
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL_ONLY(s);
 
-    if (!s->server) {
+    /* TODO(QUIC): This will need special handling for QUIC */
+    if (sc == NULL)
+        return 0;
+
+    if (!sc->server) {
         ERR_raise(ERR_LIB_SSL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
         return SSL_READ_EARLY_DATA_ERROR;
     }
 
-    switch (s->early_data_state) {
+    switch (sc->early_data_state) {
     case SSL_EARLY_DATA_NONE:
         if (!SSL_in_before(s)) {
             ERR_raise(ERR_LIB_SSL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
@@ -1905,32 +2285,32 @@ int SSL_read_early_data(SSL *s, void *buf, size_t num, size_t *readbytes)
         /* fall through */
 
     case SSL_EARLY_DATA_ACCEPT_RETRY:
-        s->early_data_state = SSL_EARLY_DATA_ACCEPTING;
+        sc->early_data_state = SSL_EARLY_DATA_ACCEPTING;
         ret = SSL_accept(s);
         if (ret <= 0) {
             /* NBIO or error */
-            s->early_data_state = SSL_EARLY_DATA_ACCEPT_RETRY;
+            sc->early_data_state = SSL_EARLY_DATA_ACCEPT_RETRY;
             return SSL_READ_EARLY_DATA_ERROR;
         }
         /* fall through */
 
     case SSL_EARLY_DATA_READ_RETRY:
-        if (s->ext.early_data == SSL_EARLY_DATA_ACCEPTED) {
-            s->early_data_state = SSL_EARLY_DATA_READING;
+        if (sc->ext.early_data == SSL_EARLY_DATA_ACCEPTED) {
+            sc->early_data_state = SSL_EARLY_DATA_READING;
             ret = SSL_read_ex(s, buf, num, readbytes);
             /*
              * State machine will update early_data_state to
              * SSL_EARLY_DATA_FINISHED_READING if we get an EndOfEarlyData
              * message
              */
-            if (ret > 0 || (ret <= 0 && s->early_data_state
+            if (ret > 0 || (ret <= 0 && sc->early_data_state
                                         != SSL_EARLY_DATA_FINISHED_READING)) {
-                s->early_data_state = SSL_EARLY_DATA_READ_RETRY;
+                sc->early_data_state = SSL_EARLY_DATA_READ_RETRY;
                 return ret > 0 ? SSL_READ_EARLY_DATA_SUCCESS
                                : SSL_READ_EARLY_DATA_ERROR;
             }
         } else {
-            s->early_data_state = SSL_EARLY_DATA_FINISHED_READING;
+            sc->early_data_state = SSL_EARLY_DATA_FINISHED_READING;
         }
         *readbytes = 0;
         return SSL_READ_EARLY_DATA_FINISH;
@@ -1943,20 +2323,37 @@ int SSL_read_early_data(SSL *s, void *buf, size_t num, size_t *readbytes)
 
 int SSL_get_early_data_status(const SSL *s)
 {
-    return s->ext.early_data;
+    const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_CONST_SSL_ONLY(s);
+
+    /* TODO(QUIC): This will need special handling for QUIC */
+    if (sc == NULL)
+        return 0;
+
+    return sc->ext.early_data;
 }
 
 static int ssl_peek_internal(SSL *s, void *buf, size_t num, size_t *readbytes)
 {
-    if (s->handshake_func == NULL) {
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+#ifndef OPENSSL_NO_QUIC
+    QUIC_CONNECTION *qc = QUIC_CONNECTION_FROM_SSL(s);
+
+    if (qc != NULL)
+        return s->method->ssl_peek(s, buf, num, readbytes);
+#endif
+
+    if (sc == NULL)
+        return 0;
+
+    if (sc->handshake_func == NULL) {
         ERR_raise(ERR_LIB_SSL, SSL_R_UNINITIALIZED);
         return -1;
     }
 
-    if (s->shutdown & SSL_RECEIVED_SHUTDOWN) {
+    if (sc->shutdown & SSL_RECEIVED_SHUTDOWN) {
         return 0;
     }
-    if ((s->mode & SSL_MODE_ASYNC) && ASYNC_get_current_job() == NULL) {
+    if ((sc->mode & SSL_MODE_ASYNC) && ASYNC_get_current_job() == NULL) {
         struct ssl_async_args args;
         int ret;
 
@@ -1967,7 +2364,7 @@ static int ssl_peek_internal(SSL *s, void *buf, size_t num, size_t *readbytes)
         args.f.func_read = s->method->ssl_peek;
 
         ret = ssl_start_async_job(s, &args, ssl_io_intern);
-        *readbytes = s->asyncrw;
+        *readbytes = sc->asyncrw;
         return ret;
     } else {
         return s->method->ssl_peek(s, buf, num, readbytes);
@@ -2008,27 +2405,38 @@ int SSL_peek_ex(SSL *s, void *buf, size_t num, size_t *readbytes)
 
 int ssl_write_internal(SSL *s, const void *buf, size_t num, size_t *written)
 {
-    if (s->handshake_func == NULL) {
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+#ifndef OPENSSL_NO_QUIC
+    QUIC_CONNECTION *qc = QUIC_CONNECTION_FROM_SSL(s);
+
+    if (qc != NULL)
+        return s->method->ssl_write(s, buf, num, written);
+#endif
+
+    if (sc == NULL)
+        return 0;
+
+    if (sc->handshake_func == NULL) {
         ERR_raise(ERR_LIB_SSL, SSL_R_UNINITIALIZED);
         return -1;
     }
 
-    if (s->shutdown & SSL_SENT_SHUTDOWN) {
-        s->rwstate = SSL_NOTHING;
+    if (sc->shutdown & SSL_SENT_SHUTDOWN) {
+        sc->rwstate = SSL_NOTHING;
         ERR_raise(ERR_LIB_SSL, SSL_R_PROTOCOL_IS_SHUTDOWN);
         return -1;
     }
 
-    if (s->early_data_state == SSL_EARLY_DATA_CONNECT_RETRY
-                || s->early_data_state == SSL_EARLY_DATA_ACCEPT_RETRY
-                || s->early_data_state == SSL_EARLY_DATA_READ_RETRY) {
+    if (sc->early_data_state == SSL_EARLY_DATA_CONNECT_RETRY
+                || sc->early_data_state == SSL_EARLY_DATA_ACCEPT_RETRY
+                || sc->early_data_state == SSL_EARLY_DATA_READ_RETRY) {
         ERR_raise(ERR_LIB_SSL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
         return 0;
     }
     /* If we are a client and haven't sent the Finished we better do that */
-    ossl_statem_check_finish_init(s, 1);
+    ossl_statem_check_finish_init(sc, 1);
 
-    if ((s->mode & SSL_MODE_ASYNC) && ASYNC_get_current_job() == NULL) {
+    if ((sc->mode & SSL_MODE_ASYNC) && ASYNC_get_current_job() == NULL) {
         int ret;
         struct ssl_async_args args;
 
@@ -2039,7 +2447,7 @@ int ssl_write_internal(SSL *s, const void *buf, size_t num, size_t *written)
         args.f.func_write = s->method->ssl_write;
 
         ret = ssl_start_async_job(s, &args, ssl_io_intern);
-        *written = s->asyncrw;
+        *written = sc->asyncrw;
         return ret;
     } else {
         return s->method->ssl_write(s, buf, num, written);
@@ -2049,25 +2457,29 @@ int ssl_write_internal(SSL *s, const void *buf, size_t num, size_t *written)
 ossl_ssize_t SSL_sendfile(SSL *s, int fd, off_t offset, size_t size, int flags)
 {
     ossl_ssize_t ret;
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL_ONLY(s);
+
+    if (sc == NULL)
+        return 0;
 
-    if (s->handshake_func == NULL) {
+    if (sc->handshake_func == NULL) {
         ERR_raise(ERR_LIB_SSL, SSL_R_UNINITIALIZED);
         return -1;
     }
 
-    if (s->shutdown & SSL_SENT_SHUTDOWN) {
-        s->rwstate = SSL_NOTHING;
+    if (sc->shutdown & SSL_SENT_SHUTDOWN) {
+        sc->rwstate = SSL_NOTHING;
         ERR_raise(ERR_LIB_SSL, SSL_R_PROTOCOL_IS_SHUTDOWN);
         return -1;
     }
 
-    if (!BIO_get_ktls_send(s->wbio)) {
+    if (!BIO_get_ktls_send(sc->wbio)) {
         ERR_raise(ERR_LIB_SSL, SSL_R_UNINITIALIZED);
         return -1;
     }
 
     /* If we have an alert to send, lets send it */
-    if (s->s3.alert_dispatch) {
+    if (sc->s3.alert_dispatch > 0) {
         ret = (ossl_ssize_t)s->method->ssl_dispatch_alert(s);
         if (ret <= 0) {
             /* SSLfatal() already called if appropriate */
@@ -2076,10 +2488,10 @@ ossl_ssize_t SSL_sendfile(SSL *s, int fd, off_t offset, size_t size, int flags)
         /* if it went, fall through and send more stuff */
     }
 
-    s->rwstate = SSL_WRITING;
-    if (BIO_flush(s->wbio) <= 0) {
-        if (!BIO_should_retry(s->wbio)) {
-            s->rwstate = SSL_NOTHING;
+    sc->rwstate = SSL_WRITING;
+    if (BIO_flush(sc->wbio) <= 0) {
+        if (!BIO_should_retry(sc->wbio)) {
+            sc->rwstate = SSL_NOTHING;
         } else {
 #ifdef EAGAIN
             set_sys_error(EAGAIN);
@@ -2099,13 +2511,13 @@ ossl_ssize_t SSL_sendfile(SSL *s, int fd, off_t offset, size_t size, int flags)
         if ((get_last_sys_error() == EAGAIN) ||
             (get_last_sys_error() == EINTR) ||
             (get_last_sys_error() == EBUSY))
-            BIO_set_retry_write(s->wbio);
+            BIO_set_retry_write(sc->wbio);
         else
 #endif
             ERR_raise(ERR_LIB_SSL, SSL_R_UNINITIALIZED);
         return ret;
     }
-    s->rwstate = SSL_NOTHING;
+    sc->rwstate = SSL_NOTHING;
     return ret;
 #endif
 }
@@ -2146,64 +2558,69 @@ int SSL_write_early_data(SSL *s, const void *buf, size_t num, size_t *written)
     int ret, early_data_state;
     size_t writtmp;
     uint32_t partialwrite;
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL_ONLY(s);
+
+    /* TODO(QUIC): This will need special handling for QUIC */
+    if (sc == NULL)
+        return 0;
 
-    switch (s->early_data_state) {
+    switch (sc->early_data_state) {
     case SSL_EARLY_DATA_NONE:
-        if (s->server
+        if (sc->server
                 || !SSL_in_before(s)
-                || ((s->session == NULL || s->session->ext.max_early_data == 0)
-                     && (s->psk_use_session_cb == NULL))) {
+                || ((sc->session == NULL || sc->session->ext.max_early_data == 0)
+                     && (sc->psk_use_session_cb == NULL))) {
             ERR_raise(ERR_LIB_SSL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
             return 0;
         }
         /* fall through */
 
     case SSL_EARLY_DATA_CONNECT_RETRY:
-        s->early_data_state = SSL_EARLY_DATA_CONNECTING;
+        sc->early_data_state = SSL_EARLY_DATA_CONNECTING;
         ret = SSL_connect(s);
         if (ret <= 0) {
             /* NBIO or error */
-            s->early_data_state = SSL_EARLY_DATA_CONNECT_RETRY;
+            sc->early_data_state = SSL_EARLY_DATA_CONNECT_RETRY;
             return 0;
         }
         /* fall through */
 
     case SSL_EARLY_DATA_WRITE_RETRY:
-        s->early_data_state = SSL_EARLY_DATA_WRITING;
+        sc->early_data_state = SSL_EARLY_DATA_WRITING;
         /*
          * We disable partial write for early data because we don't keep track
          * of how many bytes we've written between the SSL_write_ex() call and
          * the flush if the flush needs to be retried)
          */
-        partialwrite = s->mode & SSL_MODE_ENABLE_PARTIAL_WRITE;
-        s->mode &= ~SSL_MODE_ENABLE_PARTIAL_WRITE;
+        partialwrite = sc->mode & SSL_MODE_ENABLE_PARTIAL_WRITE;
+        sc->mode &= ~SSL_MODE_ENABLE_PARTIAL_WRITE;
         ret = SSL_write_ex(s, buf, num, &writtmp);
-        s->mode |= partialwrite;
+        sc->mode |= partialwrite;
         if (!ret) {
-            s->early_data_state = SSL_EARLY_DATA_WRITE_RETRY;
+            sc->early_data_state = SSL_EARLY_DATA_WRITE_RETRY;
             return ret;
         }
-        s->early_data_state = SSL_EARLY_DATA_WRITE_FLUSH;
+        sc->early_data_state = SSL_EARLY_DATA_WRITE_FLUSH;
         /* fall through */
 
     case SSL_EARLY_DATA_WRITE_FLUSH:
         /* The buffering BIO is still in place so we need to flush it */
-        if (statem_flush(s) != 1)
+        if (statem_flush(sc) != 1)
             return 0;
         *written = num;
-        s->early_data_state = SSL_EARLY_DATA_WRITE_RETRY;
+        sc->early_data_state = SSL_EARLY_DATA_WRITE_RETRY;
         return 1;
 
     case SSL_EARLY_DATA_FINISHED_READING:
     case SSL_EARLY_DATA_READ_RETRY:
-        early_data_state = s->early_data_state;
+        early_data_state = sc->early_data_state;
         /* We are a server writing to an unauthenticated client */
-        s->early_data_state = SSL_EARLY_DATA_UNAUTH_WRITING;
+        sc->early_data_state = SSL_EARLY_DATA_UNAUTH_WRITING;
         ret = SSL_write_ex(s, buf, num, written);
         /* The buffering BIO is still in place */
         if (ret)
-            (void)BIO_flush(s->wbio);
-        s->early_data_state = early_data_state;
+            (void)BIO_flush(sc->wbio);
+        sc->early_data_state = early_data_state;
         return ret;
 
     default:
@@ -2220,16 +2637,27 @@ int SSL_shutdown(SSL *s)
      * calling it once is usually not enough, even if blocking I/O is used
      * (see ssl3_shutdown).
      */
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+#ifndef OPENSSL_NO_QUIC
+    QUIC_CONNECTION *qc = QUIC_CONNECTION_FROM_SSL(s);
+
+    if (qc != NULL)
+        return ossl_quic_conn_shutdown(qc, 0, NULL, 0);
+#endif
+
+    if (sc == NULL)
+        return -1;
 
-    if (s->handshake_func == NULL) {
+    if (sc->handshake_func == NULL) {
         ERR_raise(ERR_LIB_SSL, SSL_R_UNINITIALIZED);
         return -1;
     }
 
     if (!SSL_in_init(s)) {
-        if ((s->mode & SSL_MODE_ASYNC) && ASYNC_get_current_job() == NULL) {
+        if ((sc->mode & SSL_MODE_ASYNC) && ASYNC_get_current_job() == NULL) {
             struct ssl_async_args args;
 
+            memset(&args, 0, sizeof(args));
             args.s = s;
             args.type = OTHERFUNC;
             args.f.func_other = s->method->ssl_shutdown;
@@ -2246,12 +2674,12 @@ int SSL_shutdown(SSL *s)
 
 int SSL_key_update(SSL *s, int updatetype)
 {
-    /*
-     * TODO(TLS1.3): How will applications know whether TLSv1.3 has been
-     * negotiated, and that it is appropriate to call SSL_key_update() instead
-     * of SSL_renegotiate().
-     */
-    if (!SSL_IS_TLS13(s)) {
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+
+    if (sc == NULL)
+        return 0;
+
+    if (!SSL_CONNECTION_IS_TLS13(sc)) {
         ERR_raise(ERR_LIB_SSL, SSL_R_WRONG_SSL_VERSION);
         return 0;
     }
@@ -2267,28 +2695,38 @@ int SSL_key_update(SSL *s, int updatetype)
         return 0;
     }
 
-    ossl_statem_set_in_init(s, 1);
-    s->key_update = updatetype;
+    if (RECORD_LAYER_write_pending(&sc->rlayer)) {
+        ERR_raise(ERR_LIB_SSL, SSL_R_BAD_WRITE_RETRY);
+        return 0;
+    }
+
+    ossl_statem_set_in_init(sc, 1);
+    sc->key_update = updatetype;
     return 1;
 }
 
 int SSL_get_key_update_type(const SSL *s)
 {
-    return s->key_update;
+    const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_CONST_SSL(s);
+
+    if (sc == NULL)
+        return 0;
+
+    return sc->key_update;
 }
 
 /*
  * Can we accept a renegotiation request?  If yes, set the flag and
  * return 1 if yes. If not, raise error and return 0.
  */
-static int can_renegotiate(const SSL *s)
+static int can_renegotiate(const SSL_CONNECTION *sc)
 {
-    if (SSL_IS_TLS13(s)) {
+    if (SSL_CONNECTION_IS_TLS13(sc)) {
         ERR_raise(ERR_LIB_SSL, SSL_R_WRONG_SSL_VERSION);
         return 0;
     }
 
-    if ((s->options & SSL_OP_NO_RENEGOTIATION) != 0) {
+    if ((sc->options & SSL_OP_NO_RENEGOTIATION) != 0) {
         ERR_raise(ERR_LIB_SSL, SSL_R_NO_RENEGOTIATION);
         return 0;
     }
@@ -2298,132 +2736,174 @@ static int can_renegotiate(const SSL *s)
 
 int SSL_renegotiate(SSL *s)
 {
-    if (!can_renegotiate(s))
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL_ONLY(s);
+
+    if (sc == NULL)
+        return 0;
+
+    if (!can_renegotiate(sc))
         return 0;
 
-    s->renegotiate = 1;
-    s->new_session = 1;
+    sc->renegotiate = 1;
+    sc->new_session = 1;
     return s->method->ssl_renegotiate(s);
 }
 
 int SSL_renegotiate_abbreviated(SSL *s)
 {
-    if (!can_renegotiate(s))
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL_ONLY(s);
+
+    if (sc == NULL)
         return 0;
 
-    s->renegotiate = 1;
-    s->new_session = 0;
+    if (!can_renegotiate(sc))
+        return 0;
+
+    sc->renegotiate = 1;
+    sc->new_session = 0;
     return s->method->ssl_renegotiate(s);
 }
 
 int SSL_renegotiate_pending(const SSL *s)
 {
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL_ONLY(s);
+
+    if (sc == NULL)
+        return 0;
+
     /*
      * becomes true when negotiation is requested; false again once a
      * handshake has finished
      */
-    return (s->renegotiate != 0);
+    return (sc->renegotiate != 0);
 }
 
 int SSL_new_session_ticket(SSL *s)
 {
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+
+    if (sc == NULL)
+        return 0;
+
     /* If we are in init because we're sending tickets, okay to send more. */
-    if ((SSL_in_init(s) && s->ext.extra_tickets_expected == 0)
-            || SSL_IS_FIRST_HANDSHAKE(s) || !s->server
-            || !SSL_IS_TLS13(s))
+    if ((SSL_in_init(s) && sc->ext.extra_tickets_expected == 0)
+            || SSL_IS_FIRST_HANDSHAKE(sc) || !sc->server
+            || !SSL_CONNECTION_IS_TLS13(sc))
         return 0;
-    s->ext.extra_tickets_expected++;
-    if (s->rlayer.wbuf[0].left == 0 && !SSL_in_init(s))
-        ossl_statem_set_in_init(s, 1);
+    sc->ext.extra_tickets_expected++;
+    if (!RECORD_LAYER_write_pending(&sc->rlayer) && !SSL_in_init(s))
+        ossl_statem_set_in_init(sc, 1);
     return 1;
 }
 
 long SSL_ctrl(SSL *s, int cmd, long larg, void *parg)
 {
     long l;
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+
+    /* TODO(QUIC): Special handling for some ctrls will be needed */
+    if (sc == NULL)
+        return 0;
 
     switch (cmd) {
     case SSL_CTRL_GET_READ_AHEAD:
-        return RECORD_LAYER_get_read_ahead(&s->rlayer);
+        return RECORD_LAYER_get_read_ahead(&sc->rlayer);
     case SSL_CTRL_SET_READ_AHEAD:
-        l = RECORD_LAYER_get_read_ahead(&s->rlayer);
-        RECORD_LAYER_set_read_ahead(&s->rlayer, larg);
+        l = RECORD_LAYER_get_read_ahead(&sc->rlayer);
+        RECORD_LAYER_set_read_ahead(&sc->rlayer, larg);
         return l;
 
     case SSL_CTRL_SET_MSG_CALLBACK_ARG:
-        s->msg_callback_arg = parg;
+        sc->msg_callback_arg = parg;
         return 1;
 
     case SSL_CTRL_MODE:
-        return (s->mode |= larg);
+    {
+        OSSL_PARAM options[2], *opts = options;
+
+        sc->mode |= larg;
+
+        *opts++ = OSSL_PARAM_construct_uint32(OSSL_LIBSSL_RECORD_LAYER_PARAM_MODE,
+                                              &sc->mode);
+        *opts = OSSL_PARAM_construct_end();
+
+        /* Ignore return value */
+        sc->rlayer.rrlmethod->set_options(sc->rlayer.rrl, options);
+
+        return sc->mode;
+    }
     case SSL_CTRL_CLEAR_MODE:
-        return (s->mode &= ~larg);
+        return (sc->mode &= ~larg);
     case SSL_CTRL_GET_MAX_CERT_LIST:
-        return (long)s->max_cert_list;
+        return (long)sc->max_cert_list;
     case SSL_CTRL_SET_MAX_CERT_LIST:
         if (larg < 0)
             return 0;
-        l = (long)s->max_cert_list;
-        s->max_cert_list = (size_t)larg;
+        l = (long)sc->max_cert_list;
+        sc->max_cert_list = (size_t)larg;
         return l;
     case SSL_CTRL_SET_MAX_SEND_FRAGMENT:
         if (larg < 512 || larg > SSL3_RT_MAX_PLAIN_LENGTH)
             return 0;
 #ifndef OPENSSL_NO_KTLS
-        if (s->wbio != NULL && BIO_get_ktls_send(s->wbio))
+        if (sc->wbio != NULL && BIO_get_ktls_send(sc->wbio))
             return 0;
 #endif /* OPENSSL_NO_KTLS */
-        s->max_send_fragment = larg;
-        if (s->max_send_fragment < s->split_send_fragment)
-            s->split_send_fragment = s->max_send_fragment;
+        sc->max_send_fragment = larg;
+        if (sc->max_send_fragment < sc->split_send_fragment)
+            sc->split_send_fragment = sc->max_send_fragment;
+        sc->rlayer.wrlmethod->set_max_frag_len(sc->rlayer.wrl, larg);
         return 1;
     case SSL_CTRL_SET_SPLIT_SEND_FRAGMENT:
-        if ((size_t)larg > s->max_send_fragment || larg == 0)
+        if ((size_t)larg > sc->max_send_fragment || larg == 0)
             return 0;
-        s->split_send_fragment = larg;
+        sc->split_send_fragment = larg;
         return 1;
     case SSL_CTRL_SET_MAX_PIPELINES:
         if (larg < 1 || larg > SSL_MAX_PIPELINES)
             return 0;
-        s->max_pipelines = larg;
-        if (larg > 1)
-            RECORD_LAYER_set_read_ahead(&s->rlayer, 1);
+        sc->max_pipelines = larg;
+        if (sc->rlayer.rrlmethod->set_max_pipelines != NULL)
+            sc->rlayer.rrlmethod->set_max_pipelines(sc->rlayer.rrl, (size_t)larg);
         return 1;
     case SSL_CTRL_GET_RI_SUPPORT:
-        return s->s3.send_connection_binding;
+        return sc->s3.send_connection_binding;
+    case SSL_CTRL_SET_RETRY_VERIFY:
+        sc->rwstate = SSL_RETRY_VERIFY;
+        return 1;
     case SSL_CTRL_CERT_FLAGS:
-        return (s->cert->cert_flags |= larg);
+        return (sc->cert->cert_flags |= larg);
     case SSL_CTRL_CLEAR_CERT_FLAGS:
-        return (s->cert->cert_flags &= ~larg);
+        return (sc->cert->cert_flags &= ~larg);
 
     case SSL_CTRL_GET_RAW_CIPHERLIST:
         if (parg) {
-            if (s->s3.tmp.ciphers_raw == NULL)
+            if (sc->s3.tmp.ciphers_raw == NULL)
                 return 0;
-            *(unsigned char **)parg = s->s3.tmp.ciphers_raw;
-            return (int)s->s3.tmp.ciphers_rawlen;
+            *(unsigned char **)parg = sc->s3.tmp.ciphers_raw;
+            return (int)sc->s3.tmp.ciphers_rawlen;
         } else {
             return TLS_CIPHER_LEN;
         }
     case SSL_CTRL_GET_EXTMS_SUPPORT:
-        if (!s->session || SSL_in_init(s) || ossl_statem_get_in_handshake(s))
+        if (!sc->session || SSL_in_init(s) || ossl_statem_get_in_handshake(sc))
             return -1;
-        if (s->session->flags & SSL_SESS_FLAG_EXTMS)
+        if (sc->session->flags & SSL_SESS_FLAG_EXTMS)
             return 1;
         else
             return 0;
     case SSL_CTRL_SET_MIN_PROTO_VERSION:
-        return ssl_check_allowed_versions(larg, s->max_proto_version)
-               && ssl_set_version_bound(s->ctx->method->version, (int)larg,
-                                        &s->min_proto_version);
+        return ssl_check_allowed_versions(larg, sc->max_proto_version)
+               && ssl_set_version_bound(s->defltmeth->version, (int)larg,
+                                        &sc->min_proto_version);
     case SSL_CTRL_GET_MIN_PROTO_VERSION:
-        return s->min_proto_version;
+        return sc->min_proto_version;
     case SSL_CTRL_SET_MAX_PROTO_VERSION:
-        return ssl_check_allowed_versions(s->min_proto_version, larg)
-               && ssl_set_version_bound(s->ctx->method->version, (int)larg,
-                                        &s->max_proto_version);
+        return ssl_check_allowed_versions(sc->min_proto_version, larg)
+               && ssl_set_version_bound(s->defltmeth->version, (int)larg,
+                                        &sc->max_proto_version);
     case SSL_CTRL_GET_MAX_PROTO_VERSION:
-        return s->max_proto_version;
+        return sc->max_proto_version;
     default:
         return s->method->ssl_ctrl(s, cmd, larg, parg);
     }
@@ -2431,12 +2911,17 @@ long SSL_ctrl(SSL *s, int cmd, long larg, void *parg)
 
 long SSL_callback_ctrl(SSL *s, int cmd, void (*fp) (void))
 {
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+
+    if (sc == NULL)
+        return 0;
+
     switch (cmd) {
     case SSL_CTRL_SET_MSG_CALLBACK:
-        s->msg_callback = (void (*)
-                           (int write_p, int version, int content_type,
-                            const void *buf, size_t len, SSL *ssl,
-                            void *arg))(fp);
+        sc->msg_callback = (void (*)
+                            (int write_p, int version, int content_type,
+                             const void *buf, size_t len, SSL *ssl,
+                             void *arg))(fp);
         return 1;
 
     default:
@@ -2449,6 +2934,17 @@ LHASH_OF(SSL_SESSION) *SSL_CTX_sessions(SSL_CTX *ctx)
     return ctx->sessions;
 }
 
+static int ssl_tsan_load(SSL_CTX *ctx, TSAN_QUALIFIER int *stat)
+{
+    int res = 0;
+
+    if (ssl_tsan_lock(ctx)) {
+        res = tsan_load(stat);
+        ssl_tsan_unlock(ctx);
+    }
+    return res;
+}
+
 long SSL_CTX_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg)
 {
     long l;
@@ -2504,27 +3000,27 @@ long SSL_CTX_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg)
     case SSL_CTRL_SESS_NUMBER:
         return lh_SSL_SESSION_num_items(ctx->sessions);
     case SSL_CTRL_SESS_CONNECT:
-        return tsan_load(&ctx->stats.sess_connect);
+        return ssl_tsan_load(ctx, &ctx->stats.sess_connect);
     case SSL_CTRL_SESS_CONNECT_GOOD:
-        return tsan_load(&ctx->stats.sess_connect_good);
+        return ssl_tsan_load(ctx, &ctx->stats.sess_connect_good);
     case SSL_CTRL_SESS_CONNECT_RENEGOTIATE:
-        return tsan_load(&ctx->stats.sess_connect_renegotiate);
+        return ssl_tsan_load(ctx, &ctx->stats.sess_connect_renegotiate);
     case SSL_CTRL_SESS_ACCEPT:
-        return tsan_load(&ctx->stats.sess_accept);
+        return ssl_tsan_load(ctx, &ctx->stats.sess_accept);
     case SSL_CTRL_SESS_ACCEPT_GOOD:
-        return tsan_load(&ctx->stats.sess_accept_good);
+        return ssl_tsan_load(ctx, &ctx->stats.sess_accept_good);
     case SSL_CTRL_SESS_ACCEPT_RENEGOTIATE:
-        return tsan_load(&ctx->stats.sess_accept_renegotiate);
+        return ssl_tsan_load(ctx, &ctx->stats.sess_accept_renegotiate);
     case SSL_CTRL_SESS_HIT:
-        return tsan_load(&ctx->stats.sess_hit);
+        return ssl_tsan_load(ctx, &ctx->stats.sess_hit);
     case SSL_CTRL_SESS_CB_HIT:
-        return tsan_load(&ctx->stats.sess_cb_hit);
+        return ssl_tsan_load(ctx, &ctx->stats.sess_cb_hit);
     case SSL_CTRL_SESS_MISSES:
-        return tsan_load(&ctx->stats.sess_miss);
+        return ssl_tsan_load(ctx, &ctx->stats.sess_miss);
     case SSL_CTRL_SESS_TIMEOUTS:
-        return tsan_load(&ctx->stats.sess_timeout);
+        return ssl_tsan_load(ctx, &ctx->stats.sess_timeout);
     case SSL_CTRL_SESS_CACHE_FULL:
-        return tsan_load(&ctx->stats.sess_cache_full);
+        return ssl_tsan_load(ctx, &ctx->stats.sess_cache_full);
     case SSL_CTRL_MODE:
         return (ctx->mode |= larg);
     case SSL_CTRL_CLEAR_MODE:
@@ -2601,13 +3097,17 @@ int ssl_cipher_ptr_id_cmp(const SSL_CIPHER *const *ap,
     return 0;
 }
 
-/** return a STACK of the ciphers available for the SSL and in order of
- * preference */
+/*
+ * return a STACK of the ciphers available for the SSL and in order of
+ * preference
+ */
 STACK_OF(SSL_CIPHER) *SSL_get_ciphers(const SSL *s)
 {
-    if (s != NULL) {
-        if (s->cipher_list != NULL) {
-            return s->cipher_list;
+    const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_CONST_SSL(s);
+
+    if (sc != NULL) {
+        if (sc->cipher_list != NULL) {
+            return sc->cipher_list;
         } else if ((s->ctx != NULL) && (s->ctx->cipher_list != NULL)) {
             return s->ctx->cipher_list;
         }
@@ -2617,24 +3117,30 @@ STACK_OF(SSL_CIPHER) *SSL_get_ciphers(const SSL *s)
 
 STACK_OF(SSL_CIPHER) *SSL_get_client_ciphers(const SSL *s)
 {
-    if ((s == NULL) || !s->server)
+    const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_CONST_SSL(s);
+
+    if (sc == NULL || !sc->server)
         return NULL;
-    return s->peer_ciphers;
+    return sc->peer_ciphers;
 }
 
 STACK_OF(SSL_CIPHER) *SSL_get1_supported_ciphers(SSL *s)
 {
     STACK_OF(SSL_CIPHER) *sk = NULL, *ciphers;
     int i;
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+
+    if (sc == NULL)
+        return NULL;
 
     ciphers = SSL_get_ciphers(s);
     if (!ciphers)
         return NULL;
-    if (!ssl_set_client_disabled(s))
+    if (!ssl_set_client_disabled(sc))
         return NULL;
     for (i = 0; i < sk_SSL_CIPHER_num(ciphers); i++) {
         const SSL_CIPHER *c = sk_SSL_CIPHER_value(ciphers, i);
-        if (!ssl_cipher_disabled(s, c, SSL_SECOP_CIPHER_SUPPORTED, 0)) {
+        if (!ssl_cipher_disabled(sc, c, SSL_SECOP_CIPHER_SUPPORTED, 0)) {
             if (!sk)
                 sk = sk_SSL_CIPHER_new_null();
             if (!sk)
@@ -2650,14 +3156,14 @@ STACK_OF(SSL_CIPHER) *SSL_get1_supported_ciphers(SSL *s)
 
 /** return a STACK of the ciphers available for the SSL and in order of
  * algorithm id */
-STACK_OF(SSL_CIPHER) *ssl_get_ciphers_by_id(SSL *s)
+STACK_OF(SSL_CIPHER) *ssl_get_ciphers_by_id(SSL_CONNECTION *s)
 {
     if (s != NULL) {
-        if (s->cipher_list_by_id != NULL) {
+        if (s->cipher_list_by_id != NULL)
             return s->cipher_list_by_id;
-        } else if ((s->ctx != NULL) && (s->ctx->cipher_list_by_id != NULL)) {
-            return s->ctx->cipher_list_by_id;
-        }
+        else if (s->ssl.ctx != NULL
+                 && s->ssl.ctx->cipher_list_by_id != NULL)
+            return s->ssl.ctx->cipher_list_by_id;
     }
     return NULL;
 }
@@ -2736,10 +3242,14 @@ int SSL_CTX_set_cipher_list(SSL_CTX *ctx, const char *str)
 int SSL_set_cipher_list(SSL *s, const char *str)
 {
     STACK_OF(SSL_CIPHER) *sk;
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+
+    if (sc == NULL)
+        return 0;
 
-    sk = ssl_create_cipher_list(s->ctx, s->tls13_ciphersuites,
-                                &s->cipher_list, &s->cipher_list_by_id, str,
-                                s->cert);
+    sk = ssl_create_cipher_list(s->ctx, sc->tls13_ciphersuites,
+                                &sc->cipher_list, &sc->cipher_list_by_id, str,
+                                sc->cert);
     /* see comment in SSL_CTX_set_cipher_list */
     if (sk == NULL)
         return 0;
@@ -2756,14 +3266,18 @@ char *SSL_get_shared_ciphers(const SSL *s, char *buf, int size)
     STACK_OF(SSL_CIPHER) *clntsk, *srvrsk;
     const SSL_CIPHER *c;
     int i;
+    const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_CONST_SSL(s);
+
+    if (sc == NULL)
+        return NULL;
 
-    if (!s->server
-            || s->peer_ciphers == NULL
+    if (!sc->server
+            || sc->peer_ciphers == NULL
             || size < 2)
         return NULL;
 
     p = buf;
-    clntsk = s->peer_ciphers;
+    clntsk = sc->peer_ciphers;
     srvrsk = SSL_get_ciphers(s);
     if (clntsk == NULL || srvrsk == NULL)
         return NULL;
@@ -2801,16 +3315,23 @@ char *SSL_get_shared_ciphers(const SSL *s, char *buf, int size)
  * - if we are before or during/after the handshake,
  * - if a resumption or normal handshake is being attempted/has occurred
  * - whether we have negotiated TLSv1.2 (or below) or TLSv1.3
- * 
+ *
  * Note that only the host_name type is defined (RFC 3546).
  */
 const char *SSL_get_servername(const SSL *s, const int type)
 {
+    const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_CONST_SSL(s);
+    int server;
+
+    if (sc == NULL)
+        return NULL;
+
     /*
      * If we don't know if we are the client or the server yet then we assume
      * client.
      */
-    int server = s->handshake_func == NULL ? 0 : s->server;
+    server = sc->handshake_func == NULL ? 0 : sc->server;
+
     if (type != TLSEXT_NAMETYPE_host_name)
         return NULL;
 
@@ -2831,8 +3352,8 @@ const char *SSL_get_servername(const SSL *s, const int type)
          * - The function will return the servername requested by the client in
          *   this handshake or NULL if none was requested.
          */
-         if (s->hit && !SSL_IS_TLS13(s))
-            return s->session->ext.hostname;
+         if (sc->hit && !SSL_CONNECTION_IS_TLS13(sc))
+            return sc->session->ext.hostname;
     } else {
         /**
          * Client side
@@ -2857,17 +3378,18 @@ const char *SSL_get_servername(const SSL *s, const int type)
          *   (or NULL if it was not called).
          */
         if (SSL_in_before(s)) {
-            if (s->ext.hostname == NULL
-                    && s->session != NULL
-                    && s->session->ssl_version != TLS1_3_VERSION)
-                return s->session->ext.hostname;
+            if (sc->ext.hostname == NULL
+                    && sc->session != NULL
+                    && sc->session->ssl_version != TLS1_3_VERSION)
+                return sc->session->ext.hostname;
         } else {
-            if (!SSL_IS_TLS13(s) && s->hit && s->session->ext.hostname != NULL)
-                return s->session->ext.hostname;
+            if (!SSL_CONNECTION_IS_TLS13(sc) && sc->hit
+                && sc->session->ext.hostname != NULL)
+                return sc->session->ext.hostname;
         }
     }
 
-    return s->ext.hostname;
+    return sc->ext.hostname;
 }
 
 int SSL_get_servername_type(const SSL *s)
@@ -2947,11 +3469,20 @@ int SSL_select_next_proto(unsigned char **out, unsigned char *outlen,
 void SSL_get0_next_proto_negotiated(const SSL *s, const unsigned char **data,
                                     unsigned *len)
 {
-    *data = s->ext.npn;
+    const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_CONST_SSL(s);
+
+    if (sc == NULL) {
+        /* We have no other way to indicate error */
+        *data = NULL;
+        *len = 0;
+        return;
+    }
+
+    *data = sc->ext.npn;
     if (*data == NULL) {
         *len = 0;
     } else {
-        *len = (unsigned int)s->ext.npn_len;
+        *len = (unsigned int)sc->ext.npn_len;
     }
 }
 
@@ -3026,10 +3557,8 @@ int SSL_CTX_set_alpn_protos(SSL_CTX *ctx, const unsigned char *protos,
         return 1;
 
     alpn = OPENSSL_memdup(protos, protos_len);
-    if (alpn == NULL) {
-        ERR_raise(ERR_LIB_SSL, ERR_R_MALLOC_FAILURE);
+    if (alpn == NULL)
         return 1;
-    }
     OPENSSL_free(ctx->ext.alpn);
     ctx->ext.alpn = alpn;
     ctx->ext.alpn_len = protos_len;
@@ -3046,11 +3575,15 @@ int SSL_set_alpn_protos(SSL *ssl, const unsigned char *protos,
                         unsigned int protos_len)
 {
     unsigned char *alpn;
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(ssl);
+
+    if (sc == NULL)
+        return 1;
 
     if (protos_len == 0 || protos == NULL) {
-        OPENSSL_free(ssl->ext.alpn);
-        ssl->ext.alpn = NULL;
-        ssl->ext.alpn_len = 0;
+        OPENSSL_free(sc->ext.alpn);
+        sc->ext.alpn = NULL;
+        sc->ext.alpn_len = 0;
         return 0;
     }
     /* Not valid per RFC */
@@ -3058,13 +3591,11 @@ int SSL_set_alpn_protos(SSL *ssl, const unsigned char *protos,
         return 1;
 
     alpn = OPENSSL_memdup(protos, protos_len);
-    if (alpn == NULL) {
-        ERR_raise(ERR_LIB_SSL, ERR_R_MALLOC_FAILURE);
+    if (alpn == NULL)
         return 1;
-    }
-    OPENSSL_free(ssl->ext.alpn);
-    ssl->ext.alpn = alpn;
-    ssl->ext.alpn_len = protos_len;
+    OPENSSL_free(sc->ext.alpn);
+    sc->ext.alpn = alpn;
+    sc->ext.alpn_len = protos_len;
 
     return 0;
 }
@@ -3091,11 +3622,20 @@ void SSL_CTX_set_alpn_select_cb(SSL_CTX *ctx,
 void SSL_get0_alpn_selected(const SSL *ssl, const unsigned char **data,
                             unsigned int *len)
 {
-    *data = ssl->s3.alpn_selected;
+    const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_CONST_SSL(ssl);
+
+    if (sc == NULL) {
+        /* We have no other way to indicate error */
+        *data = NULL;
+        *len = 0;
+        return;
+    }
+
+    *data = sc->s3.alpn_selected;
     if (*data == NULL)
         *len = 0;
     else
-        *len = (unsigned int)ssl->s3.alpn_selected_len;
+        *len = (unsigned int)sc->s3.alpn_selected_len;
 }
 
 int SSL_export_keying_material(SSL *s, unsigned char *out, size_t olen,
@@ -3103,11 +3643,16 @@ int SSL_export_keying_material(SSL *s, unsigned char *out, size_t olen,
                                const unsigned char *context, size_t contextlen,
                                int use_context)
 {
-    if (s->session == NULL
-        || (s->version < TLS1_VERSION && s->version != DTLS1_BAD_VER))
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+
+    if (sc == NULL)
+        return -1;
+
+    if (sc->session == NULL
+        || (sc->version < TLS1_VERSION && sc->version != DTLS1_BAD_VER))
         return -1;
 
-    return s->method->ssl3_enc->export_keying_material(s, out, olen, label,
+    return s->method->ssl3_enc->export_keying_material(sc, out, olen, label,
                                                        llen, context,
                                                        contextlen, use_context);
 }
@@ -3117,10 +3662,15 @@ int SSL_export_keying_material_early(SSL *s, unsigned char *out, size_t olen,
                                      const unsigned char *context,
                                      size_t contextlen)
 {
-    if (s->version != TLS1_3_VERSION)
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+
+    if (sc == NULL)
+        return -1;
+
+    if (sc->version != TLS1_3_VERSION)
         return 0;
 
-    return tls13_export_keying_material_early(s, out, olen, label, llen,
+    return tls13_export_keying_material_early(sc, out, olen, label, llen,
                                               context, contextlen);
 }
 
@@ -3171,6 +3721,9 @@ SSL_CTX *SSL_CTX_new_ex(OSSL_LIB_CTX *libctx, const char *propq,
                         const SSL_METHOD *meth)
 {
     SSL_CTX *ret = NULL;
+#ifndef OPENSSL_NO_COMP_ALG
+    int i;
+#endif
 
     if (meth == NULL) {
         ERR_raise(ERR_LIB_SSL, SSL_R_NULL_SSL_METHOD_PASSED);
@@ -3192,11 +3745,18 @@ SSL_CTX *SSL_CTX_new_ex(OSSL_LIB_CTX *libctx, const char *propq,
     ret->references = 1;
     ret->lock = CRYPTO_THREAD_lock_new();
     if (ret->lock == NULL) {
-        ERR_raise(ERR_LIB_SSL, ERR_R_MALLOC_FAILURE);
-        OPENSSL_free(ret);
-        return NULL;
+        ERR_raise(ERR_LIB_SSL, ERR_R_CRYPTO_LIB);
+        goto err;
     }
 
+#ifdef TSAN_REQUIRES_LOCKING
+    ret->tsan_lock = CRYPTO_THREAD_lock_new();
+    if (ret->tsan_lock == NULL) {
+        ERR_raise(ERR_LIB_SSL, ERR_R_CRYPTO_LIB);
+        goto err;
+    }
+#endif
+
     ret->libctx = libctx;
     if (propq != NULL) {
         ret->propq = OPENSSL_strdup(propq);
@@ -3214,34 +3774,43 @@ SSL_CTX *SSL_CTX_new_ex(OSSL_LIB_CTX *libctx, const char *propq,
     ret->session_timeout = meth->get_timeout();
     ret->max_cert_list = SSL_MAX_CERT_LIST_DEFAULT;
     ret->verify_mode = SSL_VERIFY_NONE;
-    if ((ret->cert = ssl_cert_new()) == NULL)
+    if ((ret->cert = ssl_cert_new()) == NULL) {
+        ERR_raise(ERR_LIB_SSL, ERR_R_SSL_LIB);
         goto err;
+    }
 
     ret->sessions = lh_SSL_SESSION_new(ssl_session_hash, ssl_session_cmp);
-    if (ret->sessions == NULL)
+    if (ret->sessions == NULL) {
+        ERR_raise(ERR_LIB_SSL, ERR_R_CRYPTO_LIB);
         goto err;
+    }
     ret->cert_store = X509_STORE_new();
-    if (ret->cert_store == NULL)
+    if (ret->cert_store == NULL) {
+        ERR_raise(ERR_LIB_SSL, ERR_R_X509_LIB);
         goto err;
+    }
 #ifndef OPENSSL_NO_CT
     ret->ctlog_store = CTLOG_STORE_new_ex(libctx, propq);
-    if (ret->ctlog_store == NULL)
+    if (ret->ctlog_store == NULL) {
+        ERR_raise(ERR_LIB_SSL, ERR_R_CT_LIB);
         goto err;
+    }
 #endif
 
     /* initialize cipher/digest methods table */
     if (!ssl_load_ciphers(ret))
-        goto err2;
+        goto err;
     /* initialise sig algs */
     if (!ssl_setup_sig_algs(ret))
-        goto err2;
-
+        goto err;
 
     if (!ssl_load_groups(ret))
-        goto err2;
+        goto err;
 
-    if (!SSL_CTX_set_ciphersuites(ret, OSSL_default_ciphersuites()))
+    if (!SSL_CTX_set_ciphersuites(ret, OSSL_default_ciphersuites())) {
+        ERR_raise(ERR_LIB_SSL, ERR_R_SSL_LIB);
         goto err;
+    }
 
     if (!ssl_create_cipher_list(ret,
                                 ret->tls13_ciphersuites,
@@ -3249,12 +3818,14 @@ SSL_CTX *SSL_CTX_new_ex(OSSL_LIB_CTX *libctx, const char *propq,
                                 OSSL_default_cipher_list(), ret->cert)
         || sk_SSL_CIPHER_num(ret->cipher_list) <= 0) {
         ERR_raise(ERR_LIB_SSL, SSL_R_LIBRARY_HAS_NO_CIPHERS);
-        goto err2;
+        goto err;
     }
 
     ret->param = X509_VERIFY_PARAM_new();
-    if (ret->param == NULL)
+    if (ret->param == NULL) {
+        ERR_raise(ERR_LIB_SSL, ERR_R_X509_LIB);
         goto err;
+    }
 
     /*
      * If these aren't available from the provider we'll get NULL returns.
@@ -3263,14 +3834,20 @@ SSL_CTX *SSL_CTX_new_ex(OSSL_LIB_CTX *libctx, const char *propq,
     ret->md5 = ssl_evp_md_fetch(libctx, NID_md5, propq);
     ret->sha1 = ssl_evp_md_fetch(libctx, NID_sha1, propq);
 
-    if ((ret->ca_names = sk_X509_NAME_new_null()) == NULL)
+    if ((ret->ca_names = sk_X509_NAME_new_null()) == NULL) {
+        ERR_raise(ERR_LIB_SSL, ERR_R_CRYPTO_LIB);
         goto err;
+    }
 
-    if ((ret->client_ca_names = sk_X509_NAME_new_null()) == NULL)
+    if ((ret->client_ca_names = sk_X509_NAME_new_null()) == NULL) {
+        ERR_raise(ERR_LIB_SSL, ERR_R_CRYPTO_LIB);
         goto err;
+    }
 
-    if (!CRYPTO_new_ex_data(CRYPTO_EX_INDEX_SSL_CTX, ret, &ret->ex_data))
+    if (!CRYPTO_new_ex_data(CRYPTO_EX_INDEX_SSL_CTX, ret, &ret->ex_data)) {
+        ERR_raise(ERR_LIB_SSL, ERR_R_CRYPTO_LIB);
         goto err;
+    }
 
     if ((ret->ext.secure = OPENSSL_secure_zalloc(sizeof(*ret->ext.secure))) == NULL)
         goto err;
@@ -3292,12 +3869,16 @@ SSL_CTX *SSL_CTX_new_ex(OSSL_LIB_CTX *libctx, const char *propq,
         ret->options |= SSL_OP_NO_TICKET;
 
     if (RAND_priv_bytes_ex(libctx, ret->ext.cookie_hmac_key,
-                           sizeof(ret->ext.cookie_hmac_key), 0) <= 0)
+                           sizeof(ret->ext.cookie_hmac_key), 0) <= 0) {
+        ERR_raise(ERR_LIB_SSL, ERR_R_RAND_LIB);
         goto err;
+    }
 
 #ifndef OPENSSL_NO_SRP
-    if (!ssl_ctx_srp_ctx_init_intern(ret))
+    if (!ssl_ctx_srp_ctx_init_intern(ret)) {
+        ERR_raise(ERR_LIB_SSL, ERR_R_SSL_LIB);
         goto err;
+    }
 #endif
 #ifndef OPENSSL_NO_ENGINE
 # ifdef OPENSSL_SSL_CLIENT_ENGINE_AUTO
@@ -3316,6 +3897,21 @@ SSL_CTX *SSL_CTX_new_ex(OSSL_LIB_CTX *libctx, const char *propq,
             ERR_clear_error();
     }
 # endif
+#endif
+
+#ifndef OPENSSL_NO_COMP_ALG
+    /*
+     * Set the default order: brotli, zlib, zstd
+     * Including only those enabled algorithms
+     */
+    memset(ret->cert_comp_prefs, 0, sizeof(ret->cert_comp_prefs));
+    i = 0;
+    if (ossl_comp_has_alg(TLSEXT_comp_cert_brotli))
+        ret->cert_comp_prefs[i++] = TLSEXT_comp_cert_brotli;
+    if (ossl_comp_has_alg(TLSEXT_comp_cert_zlib))
+        ret->cert_comp_prefs[i++] = TLSEXT_comp_cert_zlib;
+    if (ossl_comp_has_alg(TLSEXT_comp_cert_zstd))
+        ret->cert_comp_prefs[i++] = TLSEXT_comp_cert_zstd;
 #endif
     /*
      * Disable compression by default to prevent CRIME. Applications can
@@ -3364,8 +3960,6 @@ SSL_CTX *SSL_CTX_new_ex(OSSL_LIB_CTX *libctx, const char *propq,
 
     return ret;
  err:
-    ERR_raise(ERR_LIB_SSL, ERR_R_MALLOC_FAILURE);
- err2:
     SSL_CTX_free(ret);
     return NULL;
 }
@@ -3428,7 +4022,7 @@ void SSL_CTX_free(SSL_CTX *a)
     ssl_cert_free(a->cert);
     sk_X509_NAME_pop_free(a->ca_names, X509_NAME_free);
     sk_X509_NAME_pop_free(a->client_ca_names, X509_NAME_free);
-    sk_X509_pop_free(a->extra_certs, X509_free);
+    OSSL_STACK_OF_X509_free(a->extra_certs);
     a->comp_methods = NULL;
 #ifndef OPENSSL_NO_SRTP
     sk_SRTP_PROTECTION_PROFILE_free(a->srtp_profiles);
@@ -3463,6 +4057,9 @@ void SSL_CTX_free(SSL_CTX *a)
     OPENSSL_free(a->sigalg_lookup_cache);
 
     CRYPTO_THREAD_lock_free(a->lock);
+#ifdef TSAN_REQUIRES_LOCKING
+    CRYPTO_THREAD_lock_free(a->tsan_lock);
+#endif
 
     OPENSSL_free(a->propq);
 
@@ -3491,22 +4088,42 @@ void *SSL_CTX_get_default_passwd_cb_userdata(SSL_CTX *ctx)
 
 void SSL_set_default_passwd_cb(SSL *s, pem_password_cb *cb)
 {
-    s->default_passwd_callback = cb;
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+
+    if (sc == NULL)
+        return;
+
+    sc->default_passwd_callback = cb;
 }
 
 void SSL_set_default_passwd_cb_userdata(SSL *s, void *u)
 {
-    s->default_passwd_callback_userdata = u;
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+
+    if (sc == NULL)
+        return;
+
+    sc->default_passwd_callback_userdata = u;
 }
 
 pem_password_cb *SSL_get_default_passwd_cb(SSL *s)
 {
-    return s->default_passwd_callback;
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+
+    if (sc == NULL)
+        return NULL;
+
+    return sc->default_passwd_callback;
 }
 
 void *SSL_get_default_passwd_cb_userdata(SSL *s)
 {
-    return s->default_passwd_callback_userdata;
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+
+    if (sc == NULL)
+        return NULL;
+
+    return sc->default_passwd_callback_userdata;
 }
 
 void SSL_CTX_set_cert_verify_callback(SSL_CTX *ctx,
@@ -3536,10 +4153,15 @@ void SSL_CTX_set_cert_cb(SSL_CTX *c, int (*cb) (SSL *ssl, void *arg), void *arg)
 
 void SSL_set_cert_cb(SSL *s, int (*cb) (SSL *ssl, void *arg), void *arg)
 {
-    ssl_cert_set_cert_cb(s->cert, cb, arg);
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+
+    if (sc == NULL)
+        return;
+
+    ssl_cert_set_cert_cb(sc->cert, cb, arg);
 }
 
-void ssl_set_masks(SSL *s)
+void ssl_set_masks(SSL_CONNECTION *s)
 {
     CERT *c = s->cert;
     uint32_t *pvalid = s->s3.tmp.valid_flags;
@@ -3592,7 +4214,7 @@ void ssl_set_masks(SSL *s)
 
     if (rsa_enc || rsa_sign || (ssl_has_cert(s, SSL_PKEY_RSA_PSS_SIGN)
                 && pvalid[SSL_PKEY_RSA_PSS_SIGN] & CERT_PKEY_EXPLICIT_SIGN
-                && TLS1_get_version(s) == TLS1_2_VERSION))
+                && TLS1_get_version(&s->ssl) == TLS1_2_VERSION))
         mask_a |= SSL_aRSA;
 
     if (dsa_sign) {
@@ -3617,13 +4239,13 @@ void ssl_set_masks(SSL *s)
     /* Allow Ed25519 for TLS 1.2 if peer supports it */
     if (!(mask_a & SSL_aECDSA) && ssl_has_cert(s, SSL_PKEY_ED25519)
             && pvalid[SSL_PKEY_ED25519] & CERT_PKEY_EXPLICIT_SIGN
-            && TLS1_get_version(s) == TLS1_2_VERSION)
+            && TLS1_get_version(&s->ssl) == TLS1_2_VERSION)
             mask_a |= SSL_aECDSA;
 
     /* Allow Ed448 for TLS 1.2 if peer supports it */
     if (!(mask_a & SSL_aECDSA) && ssl_has_cert(s, SSL_PKEY_ED448)
             && pvalid[SSL_PKEY_ED448] & CERT_PKEY_EXPLICIT_SIGN
-            && TLS1_get_version(s) == TLS1_2_VERSION)
+            && TLS1_get_version(&s->ssl) == TLS1_2_VERSION)
             mask_a |= SSL_aECDSA;
 
     mask_k |= SSL_kECDHE;
@@ -3643,7 +4265,7 @@ void ssl_set_masks(SSL *s)
     s->s3.tmp.mask_a = mask_a;
 }
 
-int ssl_check_srvr_ecc_cert_and_alg(X509 *x, SSL *s)
+int ssl_check_srvr_ecc_cert_and_alg(X509 *x, SSL_CONNECTION *s)
 {
     if (s->s3.tmp.new_cipher->algorithm_auth & SSL_aECDSA) {
         /* key usage, if present, must allow signing */
@@ -3655,7 +4277,8 @@ int ssl_check_srvr_ecc_cert_and_alg(X509 *x, SSL *s)
     return 1;                   /* all checks are ok */
 }
 
-int ssl_get_server_cert_serverinfo(SSL *s, const unsigned char **serverinfo,
+int ssl_get_server_cert_serverinfo(SSL_CONNECTION *s,
+                                   const unsigned char **serverinfo,
                                    size_t *serverinfo_length)
 {
     CERT_PKEY *cpk = s->s3.tmp.cert;
@@ -3669,7 +4292,7 @@ int ssl_get_server_cert_serverinfo(SSL *s, const unsigned char **serverinfo,
     return 1;
 }
 
-void ssl_update_cache(SSL *s, int mode)
+void ssl_update_cache(SSL_CONNECTION *s, int mode)
 {
     int i;
 
@@ -3695,7 +4318,7 @@ void ssl_update_cache(SSL *s, int mode)
 
     i = s->session_ctx->session_cache_mode;
     if ((i & mode) != 0
-        && (!s->hit || SSL_IS_TLS13(s))) {
+        && (!s->hit || SSL_CONNECTION_IS_TLS13(s))) {
         /*
          * Add the session to the internal cache. In server side TLSv1.3 we
          * normally don't do this because by default it's a full stateless ticket
@@ -3708,7 +4331,7 @@ void ssl_update_cache(SSL *s, int mode)
          * - SSL_OP_NO_TICKET is set in which case it is a stateful ticket
          */
         if ((i & SSL_SESS_CACHE_NO_INTERNAL_STORE) == 0
-                && (!SSL_IS_TLS13(s)
+                && (!SSL_CONNECTION_IS_TLS13(s)
                     || !s->server
                     || (s->max_early_data > 0
                         && (s->options & SSL_OP_NO_ANTI_REPLAY) == 0)
@@ -3723,7 +4346,8 @@ void ssl_update_cache(SSL *s, int mode)
          */
         if (s->session_ctx->new_session_cb != NULL) {
             SSL_SESSION_up_ref(s->session);
-            if (!s->session_ctx->new_session_cb(s, s->session))
+            if (!s->session_ctx->new_session_cb(SSL_CONNECTION_GET_SSL(s),
+                                                s->session))
                 SSL_SESSION_free(s->session);
         }
     }
@@ -3731,11 +4355,12 @@ void ssl_update_cache(SSL *s, int mode)
     /* auto flush every 255 connections */
     if ((!(i & SSL_SESS_CACHE_NO_AUTO_CLEAR)) && ((i & mode) == mode)) {
         TSAN_QUALIFIER int *stat;
+
         if (mode & SSL_SESS_CACHE_CLIENT)
             stat = &s->session_ctx->stats.sess_connect_good;
         else
             stat = &s->session_ctx->stats.sess_accept_good;
-        if ((tsan_load(stat) & 0xff) == 0xff)
+        if ((ssl_tsan_load(s->session_ctx, stat) & 0xff) == 0xff)
             SSL_CTX_flush_sessions(s->session_ctx, (unsigned long)time(NULL));
     }
 }
@@ -3753,23 +4378,29 @@ const SSL_METHOD *SSL_get_ssl_method(const SSL *s)
 int SSL_set_ssl_method(SSL *s, const SSL_METHOD *meth)
 {
     int ret = 1;
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+
+    /* TODO(QUIC): Do we want this for QUIC? */
+    if (sc == NULL
+        || (s->type != SSL_TYPE_SSL_CONNECTION && s->method != meth))
+        return 0;
 
     if (s->method != meth) {
         const SSL_METHOD *sm = s->method;
-        int (*hf) (SSL *) = s->handshake_func;
+        int (*hf) (SSL *) = sc->handshake_func;
 
         if (sm->version == meth->version)
             s->method = meth;
         else {
-            sm->ssl_free(s);
+            sm->ssl_deinit(s);
             s->method = meth;
-            ret = s->method->ssl_new(s);
+            ret = s->method->ssl_init(s);
         }
 
         if (hf == sm->ssl_connect)
-            s->handshake_func = meth->ssl_connect;
+            sc->handshake_func = meth->ssl_connect;
         else if (hf == sm->ssl_accept)
-            s->handshake_func = meth->ssl_accept;
+            sc->handshake_func = meth->ssl_accept;
     }
     return ret;
 }
@@ -3779,10 +4410,25 @@ int SSL_get_error(const SSL *s, int i)
     int reason;
     unsigned long l;
     BIO *bio;
+    const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_CONST_SSL(s);
+#ifndef OPENSSL_NO_QUIC
+    const QUIC_CONNECTION *qc = QUIC_CONNECTION_FROM_CONST_SSL(s);
+#endif
 
     if (i > 0)
         return SSL_ERROR_NONE;
 
+#ifndef OPENSSL_NO_QUIC
+    if (qc != NULL) {
+        reason = ossl_quic_get_error(qc, i);
+        if (reason != SSL_ERROR_NONE)
+            return reason;
+    }
+#endif
+
+    if (sc == NULL)
+        return SSL_ERROR_SSL;
+
     /*
      * Make things return SSL_ERROR_SYSCALL when doing SSL_do_handshake etc,
      * where we do encode the error
@@ -3794,52 +4440,61 @@ int SSL_get_error(const SSL *s, int i)
             return SSL_ERROR_SSL;
     }
 
-    if (SSL_want_read(s)) {
-        bio = SSL_get_rbio(s);
-        if (BIO_should_read(bio))
-            return SSL_ERROR_WANT_READ;
-        else if (BIO_should_write(bio))
-            /*
-             * This one doesn't make too much sense ... We never try to write
-             * to the rbio, and an application program where rbio and wbio
-             * are separate couldn't even know what it should wait for.
-             * However if we ever set s->rwstate incorrectly (so that we have
-             * SSL_want_read(s) instead of SSL_want_write(s)) and rbio and
-             * wbio *are* the same, this test works around that bug; so it
-             * might be safer to keep it.
-             */
-            return SSL_ERROR_WANT_WRITE;
-        else if (BIO_should_io_special(bio)) {
-            reason = BIO_get_retry_reason(bio);
-            if (reason == BIO_RR_CONNECT)
-                return SSL_ERROR_WANT_CONNECT;
-            else if (reason == BIO_RR_ACCEPT)
-                return SSL_ERROR_WANT_ACCEPT;
-            else
-                return SSL_ERROR_SYSCALL; /* unknown */
+#ifndef OPENSSL_NO_QUIC
+    if (qc == NULL)
+#endif
+    {
+        if (SSL_want_read(s)) {
+            bio = SSL_get_rbio(s);
+            if (BIO_should_read(bio))
+                return SSL_ERROR_WANT_READ;
+            else if (BIO_should_write(bio))
+                /*
+                 * This one doesn't make too much sense ... We never try to
+                 * write to the rbio, and an application program where rbio and
+                 * wbio are separate couldn't even know what it should wait for.
+                 * However if we ever set s->rwstate incorrectly (so that we
+                 * have SSL_want_read(s) instead of SSL_want_write(s)) and rbio
+                 * and wbio *are* the same, this test works around that bug; so
+                 * it might be safer to keep it.
+                 */
+                return SSL_ERROR_WANT_WRITE;
+            else if (BIO_should_io_special(bio)) {
+                reason = BIO_get_retry_reason(bio);
+                if (reason == BIO_RR_CONNECT)
+                    return SSL_ERROR_WANT_CONNECT;
+                else if (reason == BIO_RR_ACCEPT)
+                    return SSL_ERROR_WANT_ACCEPT;
+                else
+                    return SSL_ERROR_SYSCALL; /* unknown */
+            }
         }
-    }
 
-    if (SSL_want_write(s)) {
-        /* Access wbio directly - in order to use the buffered bio if present */
-        bio = s->wbio;
-        if (BIO_should_write(bio))
-            return SSL_ERROR_WANT_WRITE;
-        else if (BIO_should_read(bio))
+        if (SSL_want_write(s)) {
             /*
-             * See above (SSL_want_read(s) with BIO_should_write(bio))
+             * Access wbio directly - in order to use the buffered bio if
+             * present
              */
-            return SSL_ERROR_WANT_READ;
-        else if (BIO_should_io_special(bio)) {
-            reason = BIO_get_retry_reason(bio);
-            if (reason == BIO_RR_CONNECT)
-                return SSL_ERROR_WANT_CONNECT;
-            else if (reason == BIO_RR_ACCEPT)
-                return SSL_ERROR_WANT_ACCEPT;
-            else
-                return SSL_ERROR_SYSCALL;
+            bio = sc->wbio;
+            if (BIO_should_write(bio))
+                return SSL_ERROR_WANT_WRITE;
+            else if (BIO_should_read(bio))
+                /*
+                 * See above (SSL_want_read(s) with BIO_should_write(bio))
+                 */
+                return SSL_ERROR_WANT_READ;
+            else if (BIO_should_io_special(bio)) {
+                reason = BIO_get_retry_reason(bio);
+                if (reason == BIO_RR_CONNECT)
+                    return SSL_ERROR_WANT_CONNECT;
+                else if (reason == BIO_RR_ACCEPT)
+                    return SSL_ERROR_WANT_ACCEPT;
+                else
+                    return SSL_ERROR_SYSCALL;
+            }
         }
     }
+
     if (SSL_want_x509_lookup(s))
         return SSL_ERROR_WANT_X509_LOOKUP;
     if (SSL_want_retry_verify(s))
@@ -3851,8 +4506,8 @@ int SSL_get_error(const SSL *s, int i)
     if (SSL_want_client_hello_cb(s))
         return SSL_ERROR_WANT_CLIENT_HELLO_CB;
 
-    if ((s->shutdown & SSL_RECEIVED_SHUTDOWN) &&
-        (s->s3.warn_alert == SSL_AD_CLOSE_NOTIFY))
+    if ((sc->shutdown & SSL_RECEIVED_SHUTDOWN) &&
+        (sc->s3.warn_alert == SSL_AD_CLOSE_NOTIFY))
         return SSL_ERROR_ZERO_RETURN;
 
     return SSL_ERROR_SYSCALL;
@@ -3860,37 +4515,46 @@ int SSL_get_error(const SSL *s, int i)
 
 static int ssl_do_handshake_intern(void *vargs)
 {
-    struct ssl_async_args *args;
-    SSL *s;
+    struct ssl_async_args *args = (struct ssl_async_args *)vargs;
+    SSL *s = args->s;
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
 
-    args = (struct ssl_async_args *)vargs;
-    s = args->s;
+    if (sc == NULL)
+        return -1;
 
-    return s->handshake_func(s);
+    return sc->handshake_func(s);
 }
 
 int SSL_do_handshake(SSL *s)
 {
     int ret = 1;
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+#ifndef OPENSSL_NO_QUIC
+    QUIC_CONNECTION *qc = QUIC_CONNECTION_FROM_SSL(s);
+
+    if (qc != NULL)
+        return ossl_quic_do_handshake(qc);
+#endif
 
-    if (s->handshake_func == NULL) {
+    if (sc->handshake_func == NULL) {
         ERR_raise(ERR_LIB_SSL, SSL_R_CONNECTION_TYPE_NOT_SET);
         return -1;
     }
 
-    ossl_statem_check_finish_init(s, -1);
+    ossl_statem_check_finish_init(sc, -1);
 
     s->method->ssl_renegotiate_check(s, 0);
 
     if (SSL_in_init(s) || SSL_in_before(s)) {
-        if ((s->mode & SSL_MODE_ASYNC) && ASYNC_get_current_job() == NULL) {
+        if ((sc->mode & SSL_MODE_ASYNC) && ASYNC_get_current_job() == NULL) {
             struct ssl_async_args args;
 
+            memset(&args, 0, sizeof(args));
             args.s = s;
 
             ret = ssl_start_async_job(s, &args, ssl_do_handshake_intern);
         } else {
-            ret = s->handshake_func(s);
+            ret = sc->handshake_func(s);
         }
     }
     return ret;
@@ -3898,20 +4562,42 @@ int SSL_do_handshake(SSL *s)
 
 void SSL_set_accept_state(SSL *s)
 {
-    s->server = 1;
-    s->shutdown = 0;
-    ossl_statem_clear(s);
-    s->handshake_func = s->method->ssl_accept;
-    clear_ciphers(s);
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL_ONLY(s);
+#ifndef OPENSSL_NO_QUIC
+    QUIC_CONNECTION *qc = QUIC_CONNECTION_FROM_SSL(s);
+
+    if (qc != NULL) {
+        ossl_quic_set_accept_state(qc);
+        return;
+    }
+#endif
+
+    sc->server = 1;
+    sc->shutdown = 0;
+    ossl_statem_clear(sc);
+    sc->handshake_func = s->method->ssl_accept;
+    /* Ignore return value. Its a void public API function */
+    clear_record_layer(sc);
 }
 
 void SSL_set_connect_state(SSL *s)
 {
-    s->server = 0;
-    s->shutdown = 0;
-    ossl_statem_clear(s);
-    s->handshake_func = s->method->ssl_connect;
-    clear_ciphers(s);
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL_ONLY(s);
+#ifndef OPENSSL_NO_QUIC
+    QUIC_CONNECTION *qc = QUIC_CONNECTION_FROM_SSL(s);
+
+    if (qc != NULL) {
+        ossl_quic_set_connect_state(qc);
+        return;
+    }
+#endif
+
+    sc->server = 0;
+    sc->shutdown = 0;
+    ossl_statem_clear(sc);
+    sc->handshake_func = s->method->ssl_connect;
+    /* Ignore return value. Its a void public API function */
+    clear_record_layer(sc);
 }
 
 int ssl_undefined_function(SSL *s)
@@ -3939,7 +4625,7 @@ const SSL_METHOD *ssl_bad_method(int ver)
 
 const char *ssl_protocol_to_string(int version)
 {
-    switch(version)
+    switch (version)
     {
     case TLS1_3_VERSION:
         return "TLSv1.3";
@@ -3972,7 +4658,12 @@ const char *ssl_protocol_to_string(int version)
 
 const char *SSL_get_version(const SSL *s)
 {
-    return ssl_protocol_to_string(s->version);
+    const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_CONST_SSL(s);
+
+    if (sc == NULL)
+        return NULL;
+
+    return ssl_protocol_to_string(sc->version);
 }
 
 static int dup_ca_names(STACK_OF(X509_NAME) **dst, STACK_OF(X509_NAME) *src)
@@ -4009,6 +4700,12 @@ SSL *SSL_dup(SSL *s)
 {
     SSL *ret;
     int i;
+    /* TODO(QUIC): Add a SSL_METHOD function for duplication */
+    SSL_CONNECTION *retsc;
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL_ONLY(s);
+
+    if (sc == NULL)
+        return NULL;
 
     /* If we're not quiescent, just up_ref! */
     if (!SSL_in_init(s) || !SSL_in_before(s)) {
@@ -4021,8 +4718,10 @@ SSL *SSL_dup(SSL *s)
      */
     if ((ret = SSL_new(SSL_get_SSL_CTX(s))) == NULL)
         return NULL;
+    if ((retsc = SSL_CONNECTION_FROM_SSL_ONLY(ret)) == NULL)
+        goto err;
 
-    if (s->session != NULL) {
+    if (sc->session != NULL) {
         /*
          * Arranges to share the same session via up_ref.  This "copies"
          * session-id, SSL_METHOD, sid_ctx, and 'cert'
@@ -4039,32 +4738,32 @@ SSL *SSL_dup(SSL *s)
         if (!SSL_set_ssl_method(ret, s->method))
             goto err;
 
-        if (s->cert != NULL) {
-            ssl_cert_free(ret->cert);
-            ret->cert = ssl_cert_dup(s->cert);
-            if (ret->cert == NULL)
+        if (sc->cert != NULL) {
+            ssl_cert_free(retsc->cert);
+            retsc->cert = ssl_cert_dup(sc->cert);
+            if (retsc->cert == NULL)
                 goto err;
         }
 
-        if (!SSL_set_session_id_context(ret, s->sid_ctx,
-                                        (int)s->sid_ctx_length))
+        if (!SSL_set_session_id_context(ret, sc->sid_ctx,
+                                        (int)sc->sid_ctx_length))
             goto err;
     }
 
-    if (!ssl_dane_dup(ret, s))
+    if (!ssl_dane_dup(retsc, sc))
         goto err;
-    ret->version = s->version;
-    ret->options = s->options;
-    ret->min_proto_version = s->min_proto_version;
-    ret->max_proto_version = s->max_proto_version;
-    ret->mode = s->mode;
+    retsc->version = sc->version;
+    retsc->options = sc->options;
+    retsc->min_proto_version = sc->min_proto_version;
+    retsc->max_proto_version = sc->max_proto_version;
+    retsc->mode = sc->mode;
     SSL_set_max_cert_list(ret, SSL_get_max_cert_list(s));
     SSL_set_read_ahead(ret, SSL_get_read_ahead(s));
-    ret->msg_callback = s->msg_callback;
-    ret->msg_callback_arg = s->msg_callback_arg;
+    retsc->msg_callback = sc->msg_callback;
+    retsc->msg_callback_arg = sc->msg_callback_arg;
     SSL_set_verify(ret, SSL_get_verify_mode(s), SSL_get_verify_callback(s));
     SSL_set_verify_depth(ret, SSL_get_verify_depth(s));
-    ret->generate_session_id = s->generate_session_id;
+    retsc->generate_session_id = sc->generate_session_id;
 
     SSL_set_info_callback(ret, SSL_get_info_callback(s));
 
@@ -4072,34 +4771,34 @@ SSL *SSL_dup(SSL *s)
     if (!CRYPTO_dup_ex_data(CRYPTO_EX_INDEX_SSL, &ret->ex_data, &s->ex_data))
         goto err;
 
-    ret->server = s->server;
-    if (s->handshake_func) {
-        if (s->server)
+    retsc->server = sc->server;
+    if (sc->handshake_func) {
+        if (sc->server)
             SSL_set_accept_state(ret);
         else
             SSL_set_connect_state(ret);
     }
-    ret->shutdown = s->shutdown;
-    ret->hit = s->hit;
+    retsc->shutdown = sc->shutdown;
+    retsc->hit = sc->hit;
 
-    ret->default_passwd_callback = s->default_passwd_callback;
-    ret->default_passwd_callback_userdata = s->default_passwd_callback_userdata;
+    retsc->default_passwd_callback = sc->default_passwd_callback;
+    retsc->default_passwd_callback_userdata = sc->default_passwd_callback_userdata;
 
-    X509_VERIFY_PARAM_inherit(ret->param, s->param);
+    X509_VERIFY_PARAM_inherit(retsc->param, sc->param);
 
     /* dup the cipher_list and cipher_list_by_id stacks */
-    if (s->cipher_list != NULL) {
-        if ((ret->cipher_list = sk_SSL_CIPHER_dup(s->cipher_list)) == NULL)
+    if (sc->cipher_list != NULL) {
+        if ((retsc->cipher_list = sk_SSL_CIPHER_dup(sc->cipher_list)) == NULL)
             goto err;
     }
-    if (s->cipher_list_by_id != NULL)
-        if ((ret->cipher_list_by_id = sk_SSL_CIPHER_dup(s->cipher_list_by_id))
+    if (sc->cipher_list_by_id != NULL)
+        if ((retsc->cipher_list_by_id = sk_SSL_CIPHER_dup(sc->cipher_list_by_id))
             == NULL)
             goto err;
 
     /* Dup the client_CA list */
-    if (!dup_ca_names(&ret->ca_names, s->ca_names)
-            || !dup_ca_names(&ret->client_ca_names, s->client_ca_names))
+    if (!dup_ca_names(&retsc->ca_names, sc->ca_names)
+            || !dup_ca_names(&retsc->client_ca_names, sc->client_ca_names))
         goto err;
 
     return ret;
@@ -4109,36 +4808,28 @@ SSL *SSL_dup(SSL *s)
     return NULL;
 }
 
-void ssl_clear_cipher_ctx(SSL *s)
-{
-    if (s->enc_read_ctx != NULL) {
-        EVP_CIPHER_CTX_free(s->enc_read_ctx);
-        s->enc_read_ctx = NULL;
-    }
-    if (s->enc_write_ctx != NULL) {
-        EVP_CIPHER_CTX_free(s->enc_write_ctx);
-        s->enc_write_ctx = NULL;
-    }
-#ifndef OPENSSL_NO_COMP
-    COMP_CTX_free(s->expand);
-    s->expand = NULL;
-    COMP_CTX_free(s->compress);
-    s->compress = NULL;
-#endif
-}
-
 X509 *SSL_get_certificate(const SSL *s)
 {
-    if (s->cert != NULL)
-        return s->cert->key->x509;
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+
+    if (sc == NULL)
+        return NULL;
+
+    if (sc->cert != NULL)
+        return sc->cert->key->x509;
     else
         return NULL;
 }
 
 EVP_PKEY *SSL_get_privatekey(const SSL *s)
 {
-    if (s->cert != NULL)
-        return s->cert->key->privatekey;
+    const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_CONST_SSL(s);
+
+    if (sc == NULL)
+        return NULL;
+
+    if (sc->cert != NULL)
+        return sc->cert->key->privatekey;
     else
         return NULL;
 }
@@ -4161,20 +4852,35 @@ EVP_PKEY *SSL_CTX_get0_privatekey(const SSL_CTX *ctx)
 
 const SSL_CIPHER *SSL_get_current_cipher(const SSL *s)
 {
-    if ((s->session != NULL) && (s->session->cipher != NULL))
-        return s->session->cipher;
+    const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_CONST_SSL(s);
+
+    if (sc == NULL)
+        return NULL;
+
+    if ((sc->session != NULL) && (sc->session->cipher != NULL))
+        return sc->session->cipher;
     return NULL;
 }
 
 const SSL_CIPHER *SSL_get_pending_cipher(const SSL *s)
 {
-    return s->s3.tmp.new_cipher;
+    const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_CONST_SSL(s);
+
+    if (sc == NULL)
+        return NULL;
+
+    return sc->s3.tmp.new_cipher;
 }
 
 const COMP_METHOD *SSL_get_current_compression(const SSL *s)
 {
 #ifndef OPENSSL_NO_COMP
-    return s->compress ? COMP_CTX_get_method(s->compress) : NULL;
+    const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_CONST_SSL_ONLY(s);
+
+    if (sc == NULL)
+        return NULL;
+
+    return sc->rlayer.wrlmethod->get_compression(sc->rlayer.wrl);
 #else
     return NULL;
 #endif
@@ -4183,13 +4889,18 @@ const COMP_METHOD *SSL_get_current_compression(const SSL *s)
 const COMP_METHOD *SSL_get_current_expansion(const SSL *s)
 {
 #ifndef OPENSSL_NO_COMP
-    return s->expand ? COMP_CTX_get_method(s->expand) : NULL;
+    const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_CONST_SSL_ONLY(s);
+
+    if (sc == NULL)
+        return NULL;
+
+    return sc->rlayer.rrlmethod->get_compression(sc->rlayer.rrl);
 #else
     return NULL;
 #endif
 }
 
-int ssl_init_wbio_buffer(SSL *s)
+int ssl_init_wbio_buffer(SSL_CONNECTION *s)
 {
     BIO *bbio;
 
@@ -4199,7 +4910,7 @@ int ssl_init_wbio_buffer(SSL *s)
     }
 
     bbio = BIO_new(BIO_f_buffer());
-    if (bbio == NULL || !BIO_set_read_buffer_size(bbio, 1)) {
+    if (bbio == NULL || BIO_set_read_buffer_size(bbio, 1) <= 0) {
         BIO_free(bbio);
         ERR_raise(ERR_LIB_SSL, ERR_R_BUF_LIB);
         return 0;
@@ -4207,16 +4918,20 @@ int ssl_init_wbio_buffer(SSL *s)
     s->bbio = bbio;
     s->wbio = BIO_push(bbio, s->wbio);
 
+    s->rlayer.wrlmethod->set1_bio(s->rlayer.wrl, s->wbio);
+
     return 1;
 }
 
-int ssl_free_wbio_buffer(SSL *s)
+int ssl_free_wbio_buffer(SSL_CONNECTION *s)
 {
     /* callers ensure s is never null */
     if (s->bbio == NULL)
         return 1;
 
     s->wbio = BIO_pop(s->wbio);
+    s->rlayer.wrlmethod->set1_bio(s->rlayer.wrl, s->wbio);
+
     BIO_free(s->bbio);
     s->bbio = NULL;
 
@@ -4235,32 +4950,68 @@ int SSL_CTX_get_quiet_shutdown(const SSL_CTX *ctx)
 
 void SSL_set_quiet_shutdown(SSL *s, int mode)
 {
-    s->quiet_shutdown = mode;
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL_ONLY(s);
+
+    /* TODO(QUIC): Do we want this for QUIC? */
+    if (sc == NULL)
+        return;
+
+    sc->quiet_shutdown = mode;
 }
 
 int SSL_get_quiet_shutdown(const SSL *s)
 {
-    return s->quiet_shutdown;
+    const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_CONST_SSL_ONLY(s);
+
+    /* TODO(QUIC): Do we want this for QUIC? */
+    if (sc == NULL)
+        return 0;
+
+    return sc->quiet_shutdown;
 }
 
 void SSL_set_shutdown(SSL *s, int mode)
 {
-    s->shutdown = mode;
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL_ONLY(s);
+
+    /* TODO(QUIC): Do we want this for QUIC? */
+    if (sc == NULL)
+        return;
+
+    sc->shutdown = mode;
 }
 
 int SSL_get_shutdown(const SSL *s)
 {
-    return s->shutdown;
+    const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_CONST_SSL_ONLY(s);
+
+    /* TODO(QUIC): Do we want this for QUIC? */
+    if (sc == NULL)
+        return 0;
+
+    return sc->shutdown;
 }
 
 int SSL_version(const SSL *s)
 {
-    return s->version;
+    const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_CONST_SSL(s);
+
+    /* TODO(QUIC): Do we want to report QUIC version this way instead? */
+    if (sc == NULL)
+        return 0;
+
+    return sc->version;
 }
 
 int SSL_client_version(const SSL *s)
 {
-    return s->client_version;
+    const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_CONST_SSL(s);
+
+    /* TODO(QUIC): Do we want to report QUIC version this way instead? */
+    if (sc == NULL)
+        return 0;
+
+    return sc->client_version;
 }
 
 SSL_CTX *SSL_get_SSL_CTX(const SSL *ssl)
@@ -4271,28 +5022,34 @@ SSL_CTX *SSL_get_SSL_CTX(const SSL *ssl)
 SSL_CTX *SSL_set_SSL_CTX(SSL *ssl, SSL_CTX *ctx)
 {
     CERT *new_cert;
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL_ONLY(ssl);
+
+    /* TODO(QUIC): Do we need this for QUIC support? */
+    if (sc == NULL)
+        return NULL;
+
     if (ssl->ctx == ctx)
         return ssl->ctx;
     if (ctx == NULL)
-        ctx = ssl->session_ctx;
+        ctx = sc->session_ctx;
     new_cert = ssl_cert_dup(ctx->cert);
     if (new_cert == NULL) {
         return NULL;
     }
 
-    if (!custom_exts_copy_flags(&new_cert->custext, &ssl->cert->custext)) {
+    if (!custom_exts_copy_flags(&new_cert->custext, &sc->cert->custext)) {
         ssl_cert_free(new_cert);
         return NULL;
     }
 
-    ssl_cert_free(ssl->cert);
-    ssl->cert = new_cert;
+    ssl_cert_free(sc->cert);
+    sc->cert = new_cert;
 
     /*
      * Program invariant: |sid_ctx| has fixed size (SSL_MAX_SID_CTX_LENGTH),
      * so setter APIs must prevent invalid lengths from entering the system.
      */
-    if (!ossl_assert(ssl->sid_ctx_length <= sizeof(ssl->sid_ctx)))
+    if (!ossl_assert(sc->sid_ctx_length <= sizeof(sc->sid_ctx)))
         return NULL;
 
     /*
@@ -4302,10 +5059,10 @@ SSL_CTX *SSL_set_SSL_CTX(SSL *ssl, SSL_CTX *ctx)
      * leave it unchanged.
      */
     if ((ssl->ctx != NULL) &&
-        (ssl->sid_ctx_length == ssl->ctx->sid_ctx_length) &&
-        (memcmp(ssl->sid_ctx, ssl->ctx->sid_ctx, ssl->sid_ctx_length) == 0)) {
-        ssl->sid_ctx_length = ctx->sid_ctx_length;
-        memcpy(&ssl->sid_ctx, &ctx->sid_ctx, sizeof(ssl->sid_ctx));
+        (sc->sid_ctx_length == ssl->ctx->sid_ctx_length) &&
+        (memcmp(sc->sid_ctx, ssl->ctx->sid_ctx, sc->sid_ctx_length) == 0)) {
+        sc->sid_ctx_length = ctx->sid_ctx_length;
+        memcpy(&sc->sid_ctx, &ctx->sid_ctx, sizeof(sc->sid_ctx));
     }
 
     SSL_CTX_up_ref(ctx);
@@ -4408,7 +5165,12 @@ int SSL_CTX_load_verify_locations(SSL_CTX *ctx, const char *CAfile,
 void SSL_set_info_callback(SSL *ssl,
                            void (*cb) (const SSL *ssl, int type, int val))
 {
-    ssl->info_callback = cb;
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(ssl);
+
+    if (sc == NULL)
+        return;
+
+    sc->info_callback = cb;
 }
 
 /*
@@ -4418,36 +5180,61 @@ void SSL_set_info_callback(SSL *ssl,
 void (*SSL_get_info_callback(const SSL *ssl)) (const SSL * /* ssl */ ,
                                                int /* type */ ,
                                                int /* val */ ) {
-    return ssl->info_callback;
+    const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_CONST_SSL(ssl);
+
+    if (sc == NULL)
+        return NULL;
+
+    return sc->info_callback;
 }
 
 void SSL_set_verify_result(SSL *ssl, long arg)
 {
-    ssl->verify_result = arg;
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(ssl);
+
+    if (sc == NULL)
+        return;
+
+    sc->verify_result = arg;
 }
 
 long SSL_get_verify_result(const SSL *ssl)
 {
-    return ssl->verify_result;
+    const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_CONST_SSL(ssl);
+
+    if (sc == NULL)
+        return 0;
+
+    return sc->verify_result;
 }
 
 size_t SSL_get_client_random(const SSL *ssl, unsigned char *out, size_t outlen)
 {
+    const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_CONST_SSL(ssl);
+
+    if (sc == NULL)
+        return 0;
+
     if (outlen == 0)
-        return sizeof(ssl->s3.client_random);
-    if (outlen > sizeof(ssl->s3.client_random))
-        outlen = sizeof(ssl->s3.client_random);
-    memcpy(out, ssl->s3.client_random, outlen);
+        return sizeof(sc->s3.client_random);
+    if (outlen > sizeof(sc->s3.client_random))
+        outlen = sizeof(sc->s3.client_random);
+    memcpy(out, sc->s3.client_random, outlen);
     return outlen;
 }
 
 size_t SSL_get_server_random(const SSL *ssl, unsigned char *out, size_t outlen)
 {
+    const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_CONST_SSL(ssl);
+
+    if (sc == NULL)
+        return 0;
+
     if (outlen == 0)
-        return sizeof(ssl->s3.server_random);
-    if (outlen > sizeof(ssl->s3.server_random))
-        outlen = sizeof(ssl->s3.server_random);
-    memcpy(out, ssl->s3.server_random, outlen);
+        return sizeof(sc->s3.server_random);
+    if (outlen > sizeof(sc->s3.server_random))
+        outlen = sizeof(sc->s3.server_random);
+    memcpy(out, sc->s3.server_random, outlen);
     return outlen;
 }
 
@@ -4514,7 +5301,12 @@ void SSL_CTX_set1_cert_store(SSL_CTX *ctx, X509_STORE *store)
 
 int SSL_want(const SSL *s)
 {
-    return s->rwstate;
+    const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_CONST_SSL(s);
+
+    if (sc == NULL)
+        return SSL_NOTHING;
+
+    return sc->rwstate;
 }
 
 #ifndef OPENSSL_NO_PSK
@@ -4536,40 +5328,53 @@ int SSL_CTX_use_psk_identity_hint(SSL_CTX *ctx, const char *identity_hint)
 
 int SSL_use_psk_identity_hint(SSL *s, const char *identity_hint)
 {
-    if (s == NULL)
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+
+    if (sc == NULL)
         return 0;
 
     if (identity_hint != NULL && strlen(identity_hint) > PSK_MAX_IDENTITY_LEN) {
         ERR_raise(ERR_LIB_SSL, SSL_R_DATA_LENGTH_TOO_LONG);
         return 0;
     }
-    OPENSSL_free(s->cert->psk_identity_hint);
+    OPENSSL_free(sc->cert->psk_identity_hint);
     if (identity_hint != NULL) {
-        s->cert->psk_identity_hint = OPENSSL_strdup(identity_hint);
-        if (s->cert->psk_identity_hint == NULL)
+        sc->cert->psk_identity_hint = OPENSSL_strdup(identity_hint);
+        if (sc->cert->psk_identity_hint == NULL)
             return 0;
     } else
-        s->cert->psk_identity_hint = NULL;
+        sc->cert->psk_identity_hint = NULL;
     return 1;
 }
 
 const char *SSL_get_psk_identity_hint(const SSL *s)
 {
-    if (s == NULL || s->session == NULL)
+    const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_CONST_SSL(s);
+
+    if (sc == NULL || sc->session == NULL)
         return NULL;
-    return s->session->psk_identity_hint;
+
+    return sc->session->psk_identity_hint;
 }
 
 const char *SSL_get_psk_identity(const SSL *s)
 {
-    if (s == NULL || s->session == NULL)
+    const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_CONST_SSL(s);
+
+    if (sc == NULL || sc->session == NULL)
         return NULL;
-    return s->session->psk_identity;
+
+    return sc->session->psk_identity;
 }
 
 void SSL_set_psk_client_callback(SSL *s, SSL_psk_client_cb_func cb)
 {
-    s->psk_client_callback = cb;
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+
+    if (sc == NULL)
+        return;
+
+    sc->psk_client_callback = cb;
 }
 
 void SSL_CTX_set_psk_client_callback(SSL_CTX *ctx, SSL_psk_client_cb_func cb)
@@ -4579,7 +5384,12 @@ void SSL_CTX_set_psk_client_callback(SSL_CTX *ctx, SSL_psk_client_cb_func cb)
 
 void SSL_set_psk_server_callback(SSL *s, SSL_psk_server_cb_func cb)
 {
-    s->psk_server_callback = cb;
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+
+    if (sc == NULL)
+        return;
+
+    sc->psk_server_callback = cb;
 }
 
 void SSL_CTX_set_psk_server_callback(SSL_CTX *ctx, SSL_psk_server_cb_func cb)
@@ -4590,7 +5400,12 @@ void SSL_CTX_set_psk_server_callback(SSL_CTX *ctx, SSL_psk_server_cb_func cb)
 
 void SSL_set_psk_find_session_callback(SSL *s, SSL_psk_find_session_cb_func cb)
 {
-    s->psk_find_session_cb = cb;
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+
+    if (sc == NULL)
+        return;
+
+    sc->psk_find_session_cb = cb;
 }
 
 void SSL_CTX_set_psk_find_session_callback(SSL_CTX *ctx,
@@ -4601,7 +5416,12 @@ void SSL_CTX_set_psk_find_session_callback(SSL_CTX *ctx,
 
 void SSL_set_psk_use_session_callback(SSL *s, SSL_psk_use_session_cb_func cb)
 {
-    s->psk_use_session_cb = cb;
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+
+    if (sc == NULL)
+        return;
+
+    sc->psk_use_session_cb = cb;
 }
 
 void SSL_CTX_set_psk_use_session_callback(SSL_CTX *ctx,
@@ -4677,10 +5497,14 @@ int SSL_set_record_padding_callback(SSL *ssl,
                                                    size_t len, void *arg))
 {
     BIO *b;
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(ssl);
+
+    if (sc == NULL)
+        return 0;
 
     b = SSL_get_wbio(ssl);
     if (b == NULL || !BIO_get_ktls_send(b)) {
-        ssl->record_padding_cb = cb;
+        sc->rlayer.record_padding_cb = cb;
         return 1;
     }
     return 0;
@@ -4688,21 +5512,36 @@ int SSL_set_record_padding_callback(SSL *ssl,
 
 void SSL_set_record_padding_callback_arg(SSL *ssl, void *arg)
 {
-    ssl->record_padding_arg = arg;
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(ssl);
+
+    if (sc == NULL)
+        return;
+
+    sc->rlayer.record_padding_arg = arg;
 }
 
 void *SSL_get_record_padding_callback_arg(const SSL *ssl)
 {
-    return ssl->record_padding_arg;
+    const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_CONST_SSL(ssl);
+
+    if (sc == NULL)
+        return NULL;
+
+    return sc->rlayer.record_padding_arg;
 }
 
 int SSL_set_block_padding(SSL *ssl, size_t block_size)
 {
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(ssl);
+
+    if (sc == NULL)
+        return 0;
+
     /* block size of 0 or 1 is basically no padding */
     if (block_size == 1)
-        ssl->block_padding = 0;
+        sc->rlayer.block_padding = 0;
     else if (block_size <= SSL3_RT_MAX_PLAIN_LENGTH)
-        ssl->block_padding = block_size;
+        sc->rlayer.block_padding = block_size;
     else
         return 0;
     return 1;
@@ -4710,14 +5549,24 @@ int SSL_set_block_padding(SSL *ssl, size_t block_size)
 
 int SSL_set_num_tickets(SSL *s, size_t num_tickets)
 {
-    s->num_tickets = num_tickets;
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+
+    if (sc == NULL)
+        return 0;
+
+    sc->num_tickets = num_tickets;
 
     return 1;
 }
 
 size_t SSL_get_num_tickets(const SSL *s)
 {
-    return s->num_tickets;
+    const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_CONST_SSL(s);
+
+    if (sc == NULL)
+        return 0;
+
+    return sc->num_tickets;
 }
 
 int SSL_CTX_set_num_tickets(SSL_CTX *ctx, size_t num_tickets)
@@ -4732,34 +5581,9 @@ size_t SSL_CTX_get_num_tickets(const SSL_CTX *ctx)
     return ctx->num_tickets;
 }
 
-/*
- * Allocates new EVP_MD_CTX and sets pointer to it into given pointer
- * variable, freeing EVP_MD_CTX previously stored in that variable, if any.
- * If EVP_MD pointer is passed, initializes ctx with this |md|.
- * Returns the newly allocated ctx;
- */
-
-EVP_MD_CTX *ssl_replace_hash(EVP_MD_CTX **hash, const EVP_MD *md)
-{
-    ssl_clear_hash_ctx(hash);
-    *hash = EVP_MD_CTX_new();
-    if (*hash == NULL || (md && EVP_DigestInit_ex(*hash, md, NULL) <= 0)) {
-        EVP_MD_CTX_free(*hash);
-        *hash = NULL;
-        return NULL;
-    }
-    return *hash;
-}
-
-void ssl_clear_hash_ctx(EVP_MD_CTX **hash)
-{
-
-    EVP_MD_CTX_free(*hash);
-    *hash = NULL;
-}
-
 /* Retrieve handshake hashes */
-int ssl_handshake_hash(SSL *s, unsigned char *out, size_t outlen,
+int ssl_handshake_hash(SSL_CONNECTION *s,
+                       unsigned char *out, size_t outlen,
                        size_t *hashlen)
 {
     EVP_MD_CTX *ctx = NULL;
@@ -4773,8 +5597,10 @@ int ssl_handshake_hash(SSL *s, unsigned char *out, size_t outlen,
     }
 
     ctx = EVP_MD_CTX_new();
-    if (ctx == NULL)
+    if (ctx == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
         goto err;
+    }
 
     if (!EVP_MD_CTX_copy_ex(ctx, hdgst)
         || EVP_DigestFinal_ex(ctx, out, NULL) <= 0) {
@@ -4792,12 +5618,22 @@ int ssl_handshake_hash(SSL *s, unsigned char *out, size_t outlen,
 
 int SSL_session_reused(const SSL *s)
 {
-    return s->hit;
+    const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_CONST_SSL(s);
+
+    if (sc == NULL)
+        return 0;
+
+    return sc->hit;
 }
 
 int SSL_is_server(const SSL *s)
 {
-    return s->server;
+    const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_CONST_SSL(s);
+
+    if (sc == NULL)
+        return 0;
+
+    return sc->server;
 }
 
 #ifndef OPENSSL_NO_DEPRECATED_1_1_0
@@ -4811,12 +5647,22 @@ void SSL_set_debug(SSL *s, int debug)
 
 void SSL_set_security_level(SSL *s, int level)
 {
-    s->cert->sec_level = level;
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+
+    if (sc == NULL)
+        return;
+
+    sc->cert->sec_level = level;
 }
 
 int SSL_get_security_level(const SSL *s)
 {
-    return s->cert->sec_level;
+    const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_CONST_SSL(s);
+
+    if (sc == NULL)
+        return 0;
+
+    return sc->cert->sec_level;
 }
 
 void SSL_set_security_callback(SSL *s,
@@ -4824,24 +5670,44 @@ void SSL_set_security_callback(SSL *s,
                                           int op, int bits, int nid,
                                           void *other, void *ex))
 {
-    s->cert->sec_cb = cb;
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+
+    if (sc == NULL)
+        return;
+
+    sc->cert->sec_cb = cb;
 }
 
 int (*SSL_get_security_callback(const SSL *s)) (const SSL *s,
                                                 const SSL_CTX *ctx, int op,
                                                 int bits, int nid, void *other,
                                                 void *ex) {
-    return s->cert->sec_cb;
+    const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_CONST_SSL(s);
+
+    if (sc == NULL)
+        return NULL;
+
+    return sc->cert->sec_cb;
 }
 
 void SSL_set0_security_ex_data(SSL *s, void *ex)
 {
-    s->cert->sec_ex = ex;
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+
+    if (sc == NULL)
+        return;
+
+    sc->cert->sec_ex = ex;
 }
 
 void *SSL_get0_security_ex_data(const SSL *s)
 {
-    return s->cert->sec_ex;
+    const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_CONST_SSL(s);
+
+    if (sc == NULL)
+        return NULL;
+
+    return sc->cert->sec_ex;
 }
 
 void SSL_CTX_set_security_level(SSL_CTX *ctx, int level)
@@ -4888,7 +5754,12 @@ uint64_t SSL_CTX_get_options(const SSL_CTX *ctx)
 
 uint64_t SSL_get_options(const SSL *s)
 {
-    return s->options;
+    const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_CONST_SSL(s);
+
+    if (sc == NULL)
+        return 0;
+
+    return sc->options;
 }
 
 uint64_t SSL_CTX_set_options(SSL_CTX *ctx, uint64_t op)
@@ -4898,7 +5769,22 @@ uint64_t SSL_CTX_set_options(SSL_CTX *ctx, uint64_t op)
 
 uint64_t SSL_set_options(SSL *s, uint64_t op)
 {
-    return s->options |= op;
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+    OSSL_PARAM options[2], *opts = options;
+
+    if (sc == NULL)
+        return 0;
+
+    sc->options |= op;
+
+    *opts++ = OSSL_PARAM_construct_uint64(OSSL_LIBSSL_RECORD_LAYER_PARAM_OPTIONS,
+                                          &sc->options);
+    *opts = OSSL_PARAM_construct_end();
+
+    /* Ignore return value */
+    sc->rlayer.rrlmethod->set_options(sc->rlayer.rrl, options);
+
+    return sc->options;
 }
 
 uint64_t SSL_CTX_clear_options(SSL_CTX *ctx, uint64_t op)
@@ -4908,12 +5794,22 @@ uint64_t SSL_CTX_clear_options(SSL_CTX *ctx, uint64_t op)
 
 uint64_t SSL_clear_options(SSL *s, uint64_t op)
 {
-    return s->options &= ~op;
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+
+    if (sc == NULL)
+        return 0;
+
+    return sc->options &= ~op;
 }
 
 STACK_OF(X509) *SSL_get0_verified_chain(const SSL *s)
 {
-    return s->verified_chain;
+    const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_CONST_SSL(s);
+
+    if (sc == NULL)
+        return NULL;
+
+    return sc->verified_chain;
 }
 
 IMPLEMENT_OBJ_BSEARCH_GLOBAL_CMP_FN(SSL_CIPHER, SSL_CIPHER, ssl_cipher_id);
@@ -4936,7 +5832,7 @@ static int ct_move_scts(STACK_OF(SCT) **dst, STACK_OF(SCT) *src,
     if (*dst == NULL) {
         *dst = sk_SCT_new_null();
         if (*dst == NULL) {
-            ERR_raise(ERR_LIB_SSL, ERR_R_MALLOC_FAILURE);
+            ERR_raise(ERR_LIB_SSL, ERR_R_CRYPTO_LIB);
             goto err;
         }
     }
@@ -4961,7 +5857,7 @@ static int ct_move_scts(STACK_OF(SCT) **dst, STACK_OF(SCT) *src,
  * Look for data collected during ServerHello and parse if found.
  * Returns the number of SCTs extracted.
  */
-static int ct_extract_tls_extension_scts(SSL *s)
+static int ct_extract_tls_extension_scts(SSL_CONNECTION *s)
 {
     int scts_extracted = 0;
 
@@ -4985,7 +5881,7 @@ static int ct_extract_tls_extension_scts(SSL *s)
  * - 0 if no OCSP response exists or it contains no SCTs.
  * - A negative integer if an error occurs.
  */
-static int ct_extract_ocsp_response_scts(SSL *s)
+static int ct_extract_ocsp_response_scts(SSL_CONNECTION *s)
 {
 # ifndef OPENSSL_NO_OCSP
     int scts_extracted = 0;
@@ -5036,7 +5932,7 @@ static int ct_extract_ocsp_response_scts(SSL *s)
  * Return the number of SCTs extracted, or a negative integer if an error
  * occurs.
  */
-static int ct_extract_x509v3_extension_scts(SSL *s)
+static int ct_extract_x509v3_extension_scts(SSL_CONNECTION *s)
 {
     int scts_extracted = 0;
     X509 *cert = s->session != NULL ? s->session->peer : NULL;
@@ -5061,15 +5957,20 @@ static int ct_extract_x509v3_extension_scts(SSL *s)
  */
 const STACK_OF(SCT) *SSL_get0_peer_scts(SSL *s)
 {
-    if (!s->scts_parsed) {
-        if (ct_extract_tls_extension_scts(s) < 0 ||
-            ct_extract_ocsp_response_scts(s) < 0 ||
-            ct_extract_x509v3_extension_scts(s) < 0)
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+
+    if (sc == NULL)
+        return NULL;
+
+    if (!sc->scts_parsed) {
+        if (ct_extract_tls_extension_scts(sc) < 0 ||
+            ct_extract_ocsp_response_scts(sc) < 0 ||
+            ct_extract_x509v3_extension_scts(sc) < 0)
             goto err;
 
-        s->scts_parsed = 1;
+        sc->scts_parsed = 1;
     }
-    return s->scts;
+    return sc->scts;
  err:
     return NULL;
 }
@@ -5100,6 +6001,11 @@ static int ct_strict(const CT_POLICY_EVAL_CTX * ctx,
 int SSL_set_ct_validation_callback(SSL *s, ssl_ct_validation_cb callback,
                                    void *arg)
 {
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+
+    if (sc == NULL)
+        return 0;
+
     /*
      * Since code exists that uses the custom extension handler for CT, look
      * for this and throw an error if they have already registered to use CT.
@@ -5119,8 +6025,8 @@ int SSL_set_ct_validation_callback(SSL *s, ssl_ct_validation_cb callback,
             return 0;
     }
 
-    s->ct_validation_callback = callback;
-    s->ct_validation_callback_arg = arg;
+    sc->ct_validation_callback = callback;
+    sc->ct_validation_callback_arg = arg;
 
     return 1;
 }
@@ -5146,7 +6052,12 @@ int SSL_CTX_set_ct_validation_callback(SSL_CTX *ctx,
 
 int SSL_ct_is_enabled(const SSL *s)
 {
-    return s->ct_validation_callback != NULL;
+    const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_CONST_SSL(s);
+
+    if (sc == NULL)
+        return 0;
+
+    return sc->ct_validation_callback != NULL;
 }
 
 int SSL_CTX_ct_is_enabled(const SSL_CTX *ctx)
@@ -5154,7 +6065,7 @@ int SSL_CTX_ct_is_enabled(const SSL_CTX *ctx)
     return ctx->ct_validation_callback != NULL;
 }
 
-int ssl_validate_ct(SSL *s)
+int ssl_validate_ct(SSL_CONNECTION *s)
 {
     int ret = 0;
     X509 *cert = s->session != NULL ? s->session->peer : NULL;
@@ -5191,20 +6102,22 @@ int ssl_validate_ct(SSL *s)
         }
     }
 
-    ctx = CT_POLICY_EVAL_CTX_new_ex(s->ctx->libctx, s->ctx->propq);
+    ctx = CT_POLICY_EVAL_CTX_new_ex(SSL_CONNECTION_GET_CTX(s)->libctx,
+                                    SSL_CONNECTION_GET_CTX(s)->propq);
     if (ctx == NULL) {
-        SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_MALLOC_FAILURE);
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_CT_LIB);
         goto end;
     }
 
     issuer = sk_X509_value(s->verified_chain, 1);
     CT_POLICY_EVAL_CTX_set1_cert(ctx, cert);
     CT_POLICY_EVAL_CTX_set1_issuer(ctx, issuer);
-    CT_POLICY_EVAL_CTX_set_shared_CTLOG_STORE(ctx, s->ctx->ctlog_store);
+    CT_POLICY_EVAL_CTX_set_shared_CTLOG_STORE(ctx,
+            SSL_CONNECTION_GET_CTX(s)->ctlog_store);
     CT_POLICY_EVAL_CTX_set_time(
-            ctx, (uint64_t)SSL_SESSION_get_time(SSL_get0_session(s)) * 1000);
+            ctx, (uint64_t)SSL_SESSION_get_time(s->session) * 1000);
 
-    scts = SSL_get0_peer_scts(s);
+    scts = SSL_get0_peer_scts(SSL_CONNECTION_GET_SSL(s));
 
     /*
      * This function returns success (> 0) only when all the SCTs are valid, 0
@@ -5311,52 +6224,82 @@ void SSL_CTX_set_client_hello_cb(SSL_CTX *c, SSL_client_hello_cb_fn cb,
 
 int SSL_client_hello_isv2(SSL *s)
 {
-    if (s->clienthello == NULL)
+    const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+
+    if (sc == NULL)
         return 0;
-    return s->clienthello->isv2;
+
+    if (sc->clienthello == NULL)
+        return 0;
+    return sc->clienthello->isv2;
 }
 
 unsigned int SSL_client_hello_get0_legacy_version(SSL *s)
 {
-    if (s->clienthello == NULL)
+    const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+
+    if (sc == NULL)
+        return 0;
+
+    if (sc->clienthello == NULL)
         return 0;
-    return s->clienthello->legacy_version;
+    return sc->clienthello->legacy_version;
 }
 
 size_t SSL_client_hello_get0_random(SSL *s, const unsigned char **out)
 {
-    if (s->clienthello == NULL)
+    const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+
+    if (sc == NULL)
+        return 0;
+
+    if (sc->clienthello == NULL)
         return 0;
     if (out != NULL)
-        *out = s->clienthello->random;
+        *out = sc->clienthello->random;
     return SSL3_RANDOM_SIZE;
 }
 
 size_t SSL_client_hello_get0_session_id(SSL *s, const unsigned char **out)
 {
-    if (s->clienthello == NULL)
+    const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+
+    if (sc == NULL)
+        return 0;
+
+    if (sc->clienthello == NULL)
         return 0;
     if (out != NULL)
-        *out = s->clienthello->session_id;
-    return s->clienthello->session_id_len;
+        *out = sc->clienthello->session_id;
+    return sc->clienthello->session_id_len;
 }
 
 size_t SSL_client_hello_get0_ciphers(SSL *s, const unsigned char **out)
 {
-    if (s->clienthello == NULL)
+    const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+
+    if (sc == NULL)
+        return 0;
+
+    if (sc->clienthello == NULL)
         return 0;
     if (out != NULL)
-        *out = PACKET_data(&s->clienthello->ciphersuites);
-    return PACKET_remaining(&s->clienthello->ciphersuites);
+        *out = PACKET_data(&sc->clienthello->ciphersuites);
+    return PACKET_remaining(&sc->clienthello->ciphersuites);
 }
 
 size_t SSL_client_hello_get0_compression_methods(SSL *s, const unsigned char **out)
 {
-    if (s->clienthello == NULL)
+    const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+
+    if (sc == NULL)
+        return 0;
+
+    if (sc->clienthello == NULL)
         return 0;
     if (out != NULL)
-        *out = s->clienthello->compressions;
-    return s->clienthello->compressions_len;
+        *out = sc->clienthello->compressions;
+    return sc->clienthello->compressions_len;
 }
 
 int SSL_client_hello_get1_extensions_present(SSL *s, int **out, size_t *outlen)
@@ -5364,11 +6307,15 @@ int SSL_client_hello_get1_extensions_present(SSL *s, int **out, size_t *outlen)
     RAW_EXTENSION *ext;
     int *present;
     size_t num = 0, i;
+    const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+
+    if (sc == NULL)
+        return 0;
 
-    if (s->clienthello == NULL || out == NULL || outlen == NULL)
+    if (sc->clienthello == NULL || out == NULL || outlen == NULL)
         return 0;
-    for (i = 0; i < s->clienthello->pre_proc_exts_len; i++) {
-        ext = s->clienthello->pre_proc_exts + i;
+    for (i = 0; i < sc->clienthello->pre_proc_exts_len; i++) {
+        ext = sc->clienthello->pre_proc_exts + i;
         if (ext->present)
             num++;
     }
@@ -5377,12 +6324,10 @@ int SSL_client_hello_get1_extensions_present(SSL *s, int **out, size_t *outlen)
         *outlen = 0;
         return 1;
     }
-    if ((present = OPENSSL_malloc(sizeof(*present) * num)) == NULL) {
-        ERR_raise(ERR_LIB_SSL, ERR_R_MALLOC_FAILURE);
+    if ((present = OPENSSL_malloc(sizeof(*present) * num)) == NULL)
         return 0;
-    }
-    for (i = 0; i < s->clienthello->pre_proc_exts_len; i++) {
-        ext = s->clienthello->pre_proc_exts + i;
+    for (i = 0; i < sc->clienthello->pre_proc_exts_len; i++) {
+        ext = sc->clienthello->pre_proc_exts + i;
         if (ext->present) {
             if (ext->received_order >= num)
                 goto err;
@@ -5397,16 +6342,58 @@ int SSL_client_hello_get1_extensions_present(SSL *s, int **out, size_t *outlen)
     return 0;
 }
 
+int SSL_client_hello_get_extension_order(SSL *s, uint16_t *exts, size_t *num_exts)
+{
+    RAW_EXTENSION *ext;
+    size_t num = 0, i;
+    const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+
+    if (sc == NULL)
+        return 0;
+
+    if (sc->clienthello == NULL || num_exts == NULL)
+        return 0;
+    for (i = 0; i < sc->clienthello->pre_proc_exts_len; i++) {
+        ext = sc->clienthello->pre_proc_exts + i;
+        if (ext->present)
+            num++;
+    }
+    if (num == 0) {
+        *num_exts = 0;
+        return 1;
+    }
+    if (exts == NULL) {
+        *num_exts = num;
+        return 1;
+    }
+    if (*num_exts < num)
+        return 0;
+    for (i = 0; i < sc->clienthello->pre_proc_exts_len; i++) {
+        ext = sc->clienthello->pre_proc_exts + i;
+        if (ext->present) {
+            if (ext->received_order >= num)
+                return 0;
+            exts[ext->received_order] = ext->type;
+        }
+    }
+    *num_exts = num;
+    return 1;
+}
+
 int SSL_client_hello_get0_ext(SSL *s, unsigned int type, const unsigned char **out,
                        size_t *outlen)
 {
     size_t i;
     RAW_EXTENSION *r;
+    const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+
+    if (sc == NULL)
+        return 0;
 
-    if (s->clienthello == NULL)
+    if (sc->clienthello == NULL)
         return 0;
-    for (i = 0; i < s->clienthello->pre_proc_exts_len; ++i) {
-        r = s->clienthello->pre_proc_exts + i;
+    for (i = 0; i < sc->clienthello->pre_proc_exts_len; ++i) {
+        r = sc->clienthello->pre_proc_exts + i;
         if (r->present && r->type == type) {
             if (out != NULL)
                 *out = PACKET_data(&r->data);
@@ -5420,18 +6407,30 @@ int SSL_client_hello_get0_ext(SSL *s, unsigned int type, const unsigned char **o
 
 int SSL_free_buffers(SSL *ssl)
 {
-    RECORD_LAYER *rl = &ssl->rlayer;
+    RECORD_LAYER *rl;
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(ssl);
 
-    if (RECORD_LAYER_read_pending(rl) || RECORD_LAYER_write_pending(rl))
+    if (sc == NULL)
         return 0;
 
-    RECORD_LAYER_release(rl);
-    return 1;
+    rl = &sc->rlayer;
+
+    return rl->rrlmethod->free_buffers(rl->rrl)
+           && rl->wrlmethod->free_buffers(rl->wrl);
 }
 
 int SSL_alloc_buffers(SSL *ssl)
 {
-    return ssl3_setup_buffers(ssl);
+    RECORD_LAYER *rl;
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(ssl);
+
+    if (sc == NULL)
+        return 0;
+
+    rl = &sc->rlayer;
+
+    return rl->rrlmethod->alloc_buffers(rl->rrl)
+           && rl->wrlmethod->alloc_buffers(rl->wrl);
 }
 
 void SSL_CTX_set_keylog_callback(SSL_CTX *ctx, SSL_CTX_keylog_cb_func cb)
@@ -5445,7 +6444,7 @@ SSL_CTX_keylog_cb_func SSL_CTX_get_keylog_callback(const SSL_CTX *ctx)
 }
 
 static int nss_keylog_int(const char *prefix,
-                          SSL *ssl,
+                          SSL_CONNECTION *sc,
                           const uint8_t *parameter_1,
                           size_t parameter_1_len,
                           const uint8_t *parameter_2,
@@ -5456,8 +6455,9 @@ static int nss_keylog_int(const char *prefix,
     size_t out_len = 0;
     size_t i;
     size_t prefix_len;
+    SSL_CTX *sctx = SSL_CONNECTION_GET_CTX(sc);
 
-    if (ssl->ctx->keylog_callback == NULL)
+    if (sctx->keylog_callback == NULL)
         return 1;
 
     /*
@@ -5470,10 +6470,8 @@ static int nss_keylog_int(const char *prefix,
      */
     prefix_len = strlen(prefix);
     out_len = prefix_len + (2 * parameter_1_len) + (2 * parameter_2_len) + 3;
-    if ((out = cursor = OPENSSL_malloc(out_len)) == NULL) {
-        SSLfatal(ssl, SSL_AD_INTERNAL_ERROR, ERR_R_MALLOC_FAILURE);
+    if ((out = cursor = OPENSSL_malloc(out_len)) == NULL)
         return 0;
-    }
 
     strcpy(cursor, prefix);
     cursor += prefix_len;
@@ -5491,40 +6489,40 @@ static int nss_keylog_int(const char *prefix,
     }
     *cursor = '\0';
 
-    ssl->ctx->keylog_callback(ssl, (const char *)out);
+    sctx->keylog_callback(SSL_CONNECTION_GET_SSL(sc), (const char *)out);
     OPENSSL_clear_free(out, out_len);
     return 1;
 
 }
 
-int ssl_log_rsa_client_key_exchange(SSL *ssl,
+int ssl_log_rsa_client_key_exchange(SSL_CONNECTION *sc,
                                     const uint8_t *encrypted_premaster,
                                     size_t encrypted_premaster_len,
                                     const uint8_t *premaster,
                                     size_t premaster_len)
 {
     if (encrypted_premaster_len < 8) {
-        SSLfatal(ssl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+        SSLfatal(sc, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
         return 0;
     }
 
     /* We only want the first 8 bytes of the encrypted premaster as a tag. */
     return nss_keylog_int("RSA",
-                          ssl,
+                          sc,
                           encrypted_premaster,
                           8,
                           premaster,
                           premaster_len);
 }
 
-int ssl_log_secret(SSL *ssl,
+int ssl_log_secret(SSL_CONNECTION *sc,
                    const char *label,
                    const uint8_t *secret,
                    size_t secret_len)
 {
     return nss_keylog_int(label,
-                          ssl,
-                          ssl->s3.client_random,
+                          sc,
+                          sc->s3.client_random,
                           SSL3_RANDOM_SIZE,
                           secret,
                           secret_len);
@@ -5532,7 +6530,7 @@ int ssl_log_secret(SSL *ssl,
 
 #define SSLV2_CIPHER_LEN    3
 
-int ssl_cache_cipherlist(SSL *s, PACKET *cipher_suites, int sslv2format)
+int ssl_cache_cipherlist(SSL_CONNECTION *s, PACKET *cipher_suites, int sslv2format)
 {
     int n;
 
@@ -5568,7 +6566,7 @@ int ssl_cache_cipherlist(SSL *s, PACKET *cipher_suites, int sslv2format)
         raw = OPENSSL_malloc(numciphers * TLS_CIPHER_LEN);
         s->s3.tmp.ciphers_raw = raw;
         if (raw == NULL) {
-            SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_MALLOC_FAILURE);
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_CRYPTO_LIB);
             return 0;
         }
         for (s->s3.tmp.ciphers_rawlen = 0;
@@ -5602,16 +6600,20 @@ int SSL_bytes_to_cipher_list(SSL *s, const unsigned char *bytes, size_t len,
                              STACK_OF(SSL_CIPHER) **scsvs)
 {
     PACKET pkt;
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+
+    if (sc == NULL)
+        return 0;
 
     if (!PACKET_buf_init(&pkt, bytes, len))
         return 0;
-    return bytes_to_cipher_list(s, &pkt, sk, scsvs, isv2format, 0);
+    return ossl_bytes_to_cipher_list(sc, &pkt, sk, scsvs, isv2format, 0);
 }
 
-int bytes_to_cipher_list(SSL *s, PACKET *cipher_suites,
-                         STACK_OF(SSL_CIPHER) **skp,
-                         STACK_OF(SSL_CIPHER) **scsvs_out,
-                         int sslv2format, int fatal)
+int ossl_bytes_to_cipher_list(SSL_CONNECTION *s, PACKET *cipher_suites,
+                              STACK_OF(SSL_CIPHER) **skp,
+                              STACK_OF(SSL_CIPHER) **scsvs_out,
+                              int sslv2format, int fatal)
 {
     const SSL_CIPHER *c;
     STACK_OF(SSL_CIPHER) *sk = NULL;
@@ -5643,9 +6645,9 @@ int bytes_to_cipher_list(SSL *s, PACKET *cipher_suites,
     scsvs = sk_SSL_CIPHER_new_null();
     if (sk == NULL || scsvs == NULL) {
         if (fatal)
-            SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_MALLOC_FAILURE);
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_CRYPTO_LIB);
         else
-            ERR_raise(ERR_LIB_SSL, ERR_R_MALLOC_FAILURE);
+            ERR_raise(ERR_LIB_SSL, ERR_R_CRYPTO_LIB);
         goto err;
     }
 
@@ -5664,9 +6666,9 @@ int bytes_to_cipher_list(SSL *s, PACKET *cipher_suites,
             if ((c->valid && !sk_SSL_CIPHER_push(sk, c)) ||
                 (!c->valid && !sk_SSL_CIPHER_push(scsvs, c))) {
                 if (fatal)
-                    SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_MALLOC_FAILURE);
+                    SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_CRYPTO_LIB);
                 else
-                    ERR_raise(ERR_LIB_SSL, ERR_R_MALLOC_FAILURE);
+                    ERR_raise(ERR_LIB_SSL, ERR_R_CRYPTO_LIB);
                 goto err;
             }
         }
@@ -5708,14 +6710,24 @@ uint32_t SSL_CTX_get_max_early_data(const SSL_CTX *ctx)
 
 int SSL_set_max_early_data(SSL *s, uint32_t max_early_data)
 {
-    s->max_early_data = max_early_data;
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+
+    if (sc == NULL)
+        return 0;
+
+    sc->max_early_data = max_early_data;
 
     return 1;
 }
 
 uint32_t SSL_get_max_early_data(const SSL *s)
 {
-    return s->max_early_data;
+    const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_CONST_SSL(s);
+
+    if (sc == NULL)
+        return 0;
+
+    return sc->max_early_data;
 }
 
 int SSL_CTX_set_recv_max_early_data(SSL_CTX *ctx, uint32_t recv_max_early_data)
@@ -5732,44 +6744,59 @@ uint32_t SSL_CTX_get_recv_max_early_data(const SSL_CTX *ctx)
 
 int SSL_set_recv_max_early_data(SSL *s, uint32_t recv_max_early_data)
 {
-    s->recv_max_early_data = recv_max_early_data;
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+
+    if (sc == NULL)
+        return 0;
+
+    sc->recv_max_early_data = recv_max_early_data;
 
     return 1;
 }
 
 uint32_t SSL_get_recv_max_early_data(const SSL *s)
 {
-    return s->recv_max_early_data;
+    const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_CONST_SSL(s);
+
+    if (sc == NULL)
+        return 0;
+
+    return sc->recv_max_early_data;
 }
 
-__owur unsigned int ssl_get_max_send_fragment(const SSL *ssl)
+__owur unsigned int ssl_get_max_send_fragment(const SSL_CONNECTION *sc)
 {
     /* Return any active Max Fragment Len extension */
-    if (ssl->session != NULL && USE_MAX_FRAGMENT_LENGTH_EXT(ssl->session))
-        return GET_MAX_FRAGMENT_LENGTH(ssl->session);
+    if (sc->session != NULL && USE_MAX_FRAGMENT_LENGTH_EXT(sc->session))
+        return GET_MAX_FRAGMENT_LENGTH(sc->session);
 
     /* return current SSL connection setting */
-    return ssl->max_send_fragment;
+    return sc->max_send_fragment;
 }
 
-__owur unsigned int ssl_get_split_send_fragment(const SSL *ssl)
+__owur unsigned int ssl_get_split_send_fragment(const SSL_CONNECTION *sc)
 {
     /* Return a value regarding an active Max Fragment Len extension */
-    if (ssl->session != NULL && USE_MAX_FRAGMENT_LENGTH_EXT(ssl->session)
-        && ssl->split_send_fragment > GET_MAX_FRAGMENT_LENGTH(ssl->session))
-        return GET_MAX_FRAGMENT_LENGTH(ssl->session);
+    if (sc->session != NULL && USE_MAX_FRAGMENT_LENGTH_EXT(sc->session)
+        && sc->split_send_fragment > GET_MAX_FRAGMENT_LENGTH(sc->session))
+        return GET_MAX_FRAGMENT_LENGTH(sc->session);
 
     /* else limit |split_send_fragment| to current |max_send_fragment| */
-    if (ssl->split_send_fragment > ssl->max_send_fragment)
-        return ssl->max_send_fragment;
+    if (sc->split_send_fragment > sc->max_send_fragment)
+        return sc->max_send_fragment;
 
     /* return current SSL connection setting */
-    return ssl->split_send_fragment;
+    return sc->split_send_fragment;
 }
 
 int SSL_stateless(SSL *s)
 {
     int ret;
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+
+    /* TODO(QUIC): This will need further work. */
+    if (sc == NULL)
+        return 0;
 
     /* Ensure there is no state left over from a previous invocation */
     if (!SSL_clear(s))
@@ -5777,14 +6804,14 @@ int SSL_stateless(SSL *s)
 
     ERR_clear_error();
 
-    s->s3.flags |= TLS1_FLAGS_STATELESS;
+    sc->s3.flags |= TLS1_FLAGS_STATELESS;
     ret = SSL_accept(s);
-    s->s3.flags &= ~TLS1_FLAGS_STATELESS;
+    sc->s3.flags &= ~TLS1_FLAGS_STATELESS;
 
-    if (ret > 0 && s->ext.cookieok)
+    if (ret > 0 && sc->ext.cookieok)
         return 1;
 
-    if (s->hello_retry_request == SSL_HRR_PENDING && !ossl_statem_in_error(s))
+    if (sc->hello_retry_request == SSL_HRR_PENDING && !ossl_statem_in_error(sc))
         return 0;
 
     return -1;
@@ -5797,16 +6824,26 @@ void SSL_CTX_set_post_handshake_auth(SSL_CTX *ctx, int val)
 
 void SSL_set_post_handshake_auth(SSL *ssl, int val)
 {
-    ssl->pha_enabled = val;
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(ssl);
+
+    if (sc == NULL)
+        return;
+
+    sc->pha_enabled = val;
 }
 
 int SSL_verify_client_post_handshake(SSL *ssl)
 {
-    if (!SSL_IS_TLS13(ssl)) {
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(ssl);
+
+    if (sc == NULL)
+        return 0;
+
+    if (!SSL_CONNECTION_IS_TLS13(sc)) {
         ERR_raise(ERR_LIB_SSL, SSL_R_WRONG_SSL_VERSION);
         return 0;
     }
-    if (!ssl->server) {
+    if (!sc->server) {
         ERR_raise(ERR_LIB_SSL, SSL_R_NOT_SERVER);
         return 0;
     }
@@ -5816,7 +6853,7 @@ int SSL_verify_client_post_handshake(SSL *ssl)
         return 0;
     }
 
-    switch (ssl->post_handshake_auth) {
+    switch (sc->post_handshake_auth) {
     case SSL_PHA_NONE:
         ERR_raise(ERR_LIB_SSL, SSL_R_EXTENSION_NOT_RECEIVED);
         return 0;
@@ -5834,16 +6871,16 @@ int SSL_verify_client_post_handshake(SSL *ssl)
         return 0;
     }
 
-    ssl->post_handshake_auth = SSL_PHA_REQUEST_PENDING;
+    sc->post_handshake_auth = SSL_PHA_REQUEST_PENDING;
 
     /* checks verify_mode and algorithm_auth */
-    if (!send_certificate_request(ssl)) {
-        ssl->post_handshake_auth = SSL_PHA_EXT_RECEIVED; /* restore on error */
+    if (!send_certificate_request(sc)) {
+        sc->post_handshake_auth = SSL_PHA_EXT_RECEIVED; /* restore on error */
         ERR_raise(ERR_LIB_SSL, SSL_R_INVALID_CONFIG);
         return 0;
     }
 
-    ossl_statem_set_in_init(ssl, 1);
+    ossl_statem_set_in_init(sc, 1);
     return 1;
 }
 
@@ -5870,8 +6907,13 @@ void SSL_set_allow_early_data_cb(SSL *s,
                                  SSL_allow_early_data_cb_fn cb,
                                  void *arg)
 {
-    s->allow_early_data_cb = cb;
-    s->allow_early_data_cb_data = arg;
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+
+    if (sc == NULL)
+        return;
+
+    sc->allow_early_data_cb = cb;
+    sc->allow_early_data_cb_data = arg;
 }
 
 const EVP_CIPHER *ssl_evp_cipher_fetch(OSSL_LIB_CTX *libctx,
@@ -5968,14 +7010,18 @@ void ssl_evp_md_free(const EVP_MD *md)
 
 int SSL_set0_tmp_dh_pkey(SSL *s, EVP_PKEY *dhpkey)
 {
-    if (!ssl_security(s, SSL_SECOP_TMP_DH,
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+
+    if (sc == NULL)
+        return 0;
+
+    if (!ssl_security(sc, SSL_SECOP_TMP_DH,
                       EVP_PKEY_get_security_bits(dhpkey), 0, dhpkey)) {
         ERR_raise(ERR_LIB_SSL, SSL_R_DH_KEY_TOO_SMALL);
-        EVP_PKEY_free(dhpkey);
         return 0;
     }
-    EVP_PKEY_free(s->cert->dh_tmp);
-    s->cert->dh_tmp = dhpkey;
+    EVP_PKEY_free(sc->cert->dh_tmp);
+    sc->cert->dh_tmp = dhpkey;
     return 1;
 }
 
@@ -5984,10 +7030,170 @@ int SSL_CTX_set0_tmp_dh_pkey(SSL_CTX *ctx, EVP_PKEY *dhpkey)
     if (!ssl_ctx_security(ctx, SSL_SECOP_TMP_DH,
                           EVP_PKEY_get_security_bits(dhpkey), 0, dhpkey)) {
         ERR_raise(ERR_LIB_SSL, SSL_R_DH_KEY_TOO_SMALL);
-        EVP_PKEY_free(dhpkey);
         return 0;
     }
     EVP_PKEY_free(ctx->cert->dh_tmp);
     ctx->cert->dh_tmp = dhpkey;
     return 1;
 }
+
+/* QUIC-specific methods which are supported on QUIC connections only. */
+int SSL_tick(SSL *s)
+{
+    SSL_CONNECTION *sc;
+#ifndef OPENSSL_NO_QUIC
+    QUIC_CONNECTION *qc = QUIC_CONNECTION_FROM_SSL(s);
+
+    if (qc != NULL)
+        return ossl_quic_tick(qc);
+#endif
+
+    sc = SSL_CONNECTION_FROM_SSL_ONLY(s);
+    if (sc != NULL && SSL_CONNECTION_IS_DTLS(sc))
+        /*
+         * DTLSv1_handle_timeout returns 0 if the timer wasn't expired yet,
+         * which we consider a success case. Theoretically DTLSv1_handle_timeout
+         * can also return 0 if s is NULL or not a DTLS object, but we've
+         * already ruled out those possibilities above, so this is not possible
+         * here. Thus the only failure cases are where DTLSv1_handle_timeout
+         * returns -1.
+         */
+        return DTLSv1_handle_timeout(s) >= 0;
+
+    return 1;
+}
+
+int SSL_get_tick_timeout(SSL *s, struct timeval *tv)
+{
+    SSL_CONNECTION *sc;
+#ifndef OPENSSL_NO_QUIC
+    QUIC_CONNECTION *qc;
+
+    qc = QUIC_CONNECTION_FROM_SSL(s);
+    if (qc != NULL)
+        return ossl_quic_get_tick_timeout(qc, tv);
+#endif
+
+    sc = SSL_CONNECTION_FROM_SSL_ONLY(s);
+    if (sc != NULL && SSL_CONNECTION_IS_DTLS(sc)
+        && DTLSv1_get_timeout(s, tv))
+        return 1;
+
+    tv->tv_sec  = -1;
+    tv->tv_usec = 0;
+    return 1;
+}
+
+int SSL_get_rpoll_descriptor(SSL *s, BIO_POLL_DESCRIPTOR *desc)
+{
+#ifndef OPENSSL_NO_QUIC
+    QUIC_CONNECTION *qc = QUIC_CONNECTION_FROM_SSL(s);
+
+    if (qc == NULL)
+        return -1;
+
+    return ossl_quic_get_rpoll_descriptor(qc, desc);
+#else
+    return -1;
+#endif
+}
+
+int SSL_get_wpoll_descriptor(SSL *s, BIO_POLL_DESCRIPTOR *desc)
+{
+#ifndef OPENSSL_NO_QUIC
+    QUIC_CONNECTION *qc = QUIC_CONNECTION_FROM_SSL(s);
+
+    if (qc == NULL)
+        return -1;
+
+    return ossl_quic_get_wpoll_descriptor(qc, desc);
+#else
+    return -1;
+#endif
+}
+
+int SSL_net_read_desired(SSL *s)
+{
+#ifndef OPENSSL_NO_QUIC
+    QUIC_CONNECTION *qc = QUIC_CONNECTION_FROM_SSL(s);
+
+    if (qc == NULL)
+        return 0;
+
+    return ossl_quic_get_net_read_desired(qc);
+#else
+    return 0;
+#endif
+}
+
+int SSL_net_write_desired(SSL *s)
+{
+#ifndef OPENSSL_NO_QUIC
+    QUIC_CONNECTION *qc = QUIC_CONNECTION_FROM_SSL(s);
+
+    if (qc == NULL)
+        return 0;
+
+    return ossl_quic_get_net_write_desired(qc);
+#else
+    return 0;
+#endif
+}
+
+int SSL_set_blocking_mode(SSL *s, int blocking)
+{
+#ifndef OPENSSL_NO_QUIC
+    QUIC_CONNECTION *qc = QUIC_CONNECTION_FROM_SSL(s);
+
+    if (qc == NULL)
+        return 0;
+
+    return ossl_quic_conn_set_blocking_mode(qc, blocking);
+#else
+    return 0;
+#endif
+}
+
+int SSL_get_blocking_mode(SSL *s)
+{
+#ifndef OPENSSL_NO_QUIC
+    QUIC_CONNECTION *qc = QUIC_CONNECTION_FROM_SSL(s);
+
+    if (qc == NULL)
+        return -1;
+
+    return ossl_quic_conn_get_blocking_mode(qc);
+#else
+    return -1;
+#endif
+}
+
+int SSL_set_initial_peer_addr(SSL *s, const BIO_ADDR *peer_addr)
+{
+#ifndef OPENSSL_NO_QUIC
+    QUIC_CONNECTION *qc = QUIC_CONNECTION_FROM_SSL(s);
+
+    if (qc == NULL)
+        return 0;
+
+    return ossl_quic_conn_set_initial_peer_addr(qc, peer_addr);
+#else
+    return 0;
+#endif
+}
+
+int SSL_shutdown_ex(SSL *ssl, uint64_t flags,
+                    const SSL_SHUTDOWN_EX_ARGS *args,
+                    size_t args_len)
+{
+#ifndef OPENSSL_NO_QUIC
+    QUIC_CONNECTION *qc = QUIC_CONNECTION_FROM_SSL(ssl);
+
+    if (qc == NULL)
+        return SSL_shutdown(ssl);
+
+    return ossl_quic_conn_shutdown(qc, flags, args, args_len);
+#else
+    return SSL_shutdown(ssl);
+#endif
+}