Enhance code safety and readability in SSL_get_shared_ciphers()
[openssl.git] / ssl / ssl_lib.c
index a143dbf3179f40c529b9ccf2b60e230d444750a8..fdc8b6b82410d9c22a32c7494bc95c2f6fc77836 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 1995-2022 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2023 The OpenSSL Project Authors. All Rights Reserved.
  * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved
  * Copyright 2005 Nokia. All rights reserved.
  *
 #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"
-
-static int ssl_undefined_function_1(SSL_CONNECTION *sc, SSL3_RECORD *r, size_t s,
-                                    int t, SSL_MAC_BUF *mac, size_t macsize)
-{
-    return ssl_undefined_function(SSL_CONNECTION_GET_SSL(sc));
-}
-
-static int ssl_undefined_function_2(SSL_CONNECTION *sc, SSL3_RECORD *r,
-                                    unsigned char *s, int t)
-{
-    return ssl_undefined_function(SSL_CONNECTION_GET_SSL(sc));
-}
+#include "quic/quic_local.h"
 
 static int ssl_undefined_function_3(SSL_CONNECTION *sc, unsigned char *r,
                                     unsigned char *s, size_t t, size_t *u)
@@ -73,8 +63,6 @@ static int ssl_undefined_function_8(SSL_CONNECTION *sc)
 }
 
 SSL3_ENC_METHOD ssl3_undef_enc_method = {
-    ssl_undefined_function_1,
-    ssl_undefined_function_2,
     ssl_undefined_function_8,
     ssl_undefined_function_3,
     ssl_undefined_function_4,
@@ -132,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;
     }
 
@@ -206,7 +193,7 @@ static int ssl_dane_dup(SSL_CONNECTION *to, SSL_CONNECTION *from)
     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;
     }
 
@@ -236,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 */
@@ -320,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;
@@ -331,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);
@@ -372,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;
@@ -433,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);
@@ -563,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_CONNECTION *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)
@@ -598,7 +595,7 @@ int ossl_ssl_connection_reset(SSL *s)
     OPENSSL_free(sc->psksession_id);
     sc->psksession_id = NULL;
     sc->psksession_id_len = 0;
-    sc->hello_retry_request = 0;
+    sc->hello_retry_request = SSL_HRR_NONE;
     sc->sent_tickets = 0;
 
     sc->error = 0;
@@ -612,17 +609,18 @@ int ossl_ssl_connection_reset(SSL *s)
 
     ossl_statem_clear(sc);
 
-    /* TODO(QUIC): Version handling not yet clear */
     sc->version = s->method->version;
     sc->client_version = sc->version;
     sc->rwstate = SSL_NOTHING;
 
     BUF_MEM_free(sc->init_buf);
     sc->init_buf = NULL;
-    clear_ciphers(sc);
     sc->first_packet = 0;
 
     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(sc->pha_dgst);
     sc->pha_dgst = NULL;
@@ -646,9 +644,9 @@ int ossl_ssl_connection_reset(SSL *s)
      * Check to see if we were changed into a different method, if so, revert
      * back.
      */
-    if (s->method != SSL_CONNECTION_GET_CTX(sc)->method) {
+    if (s->method != s->defltmeth) {
         s->method->ssl_deinit(s);
-        s->method = SSL_CONNECTION_GET_CTX(sc)->method;
+        s->method = s->defltmeth;
         if (!s->method->ssl_init(s))
             return 0;
     } else {
@@ -660,15 +658,8 @@ int ossl_ssl_connection_reset(SSL *s)
     BIO_free(sc->rlayer.rrlnext);
     sc->rlayer.rrlnext = NULL;
 
-    if (!ssl_set_new_record_layer(sc,
-                                  SSL_CONNECTION_IS_DTLS(sc) ? DTLS_ANY_VERSION : TLS_ANY_VERSION,
-                                  OSSL_RECORD_DIRECTION_READ,
-                                  OSSL_RECORD_PROTECTION_LEVEL_NONE,
-                                  NULL, 0, NULL, 0, NULL,  0, NULL, 0,
-                                  NID_undef, NULL, NULL)) {
-        /* SSLfatal already called */
+    if (!clear_record_layer(sc))
         return 0;
-    }
 
     return 1;
 }
@@ -679,6 +670,11 @@ int SSL_CTX_set_ssl_version(SSL_CTX *ctx, const SSL_METHOD *meth)
 {
     STACK_OF(SSL_CIPHER) *sk;
 
+    if (IS_QUIC_CTX(ctx)) {
+        ERR_raise(ERR_LIB_SSL, SSL_R_WRONG_SSL_VERSION);
+        return 0;
+    }
+
     ctx->method = meth;
 
     if (!SSL_CTX_set_ciphersuites(ctx, OSSL_default_ciphersuites())) {
@@ -711,27 +707,35 @@ SSL *SSL_new(SSL_CTX *ctx)
     return ctx->method->ssl_new(ctx);
 }
 
-int ossl_ssl_init(SSL *ssl, SSL_CTX *ctx, int type)
+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;
 
+    if (!CRYPTO_NEW_REF(&ssl->references, 1)) {
+        CRYPTO_THREAD_lock_free(ssl->lock);
+        return 0;
+    }
+
+    if (!CRYPTO_new_ex_data(CRYPTO_EX_INDEX_SSL, ssl, &ssl->ex_data)) {
+        CRYPTO_THREAD_lock_free(ssl->lock);
+        CRYPTO_FREE_REF(&ssl->references);
+        ssl->lock = NULL;
+        return 0;
+    }
+
     SSL_CTX_up_ref(ctx);
     ssl->ctx = ctx;
 
-    ssl->method = ctx->method;
-
-    if (!CRYPTO_new_ex_data(CRYPTO_EX_INDEX_SSL, ssl, &ssl->ex_data))
-        return 0;
+    ssl->defltmeth = ssl->method = method;
 
     return 1;
 }
 
-SSL *ossl_ssl_connection_new(SSL_CTX *ctx)
+SSL *ossl_ssl_connection_new_int(SSL_CTX *ctx, const SSL_METHOD *method)
 {
     SSL_CONNECTION *s;
     SSL *ssl;
@@ -741,34 +745,35 @@ SSL *ossl_ssl_connection_new(SSL_CTX *ctx)
         return NULL;
 
     ssl = &s->ssl;
-    if (!ossl_ssl_init(ssl, ctx, SSL_TYPE_SSL_CONNECTION)) {
+    if (!ossl_ssl_init(ssl, ctx, method, SSL_TYPE_SSL_CONNECTION)) {
         OPENSSL_free(s);
         s = NULL;
-        goto err;
+        ssl = NULL;
+        goto sslerr;
     }
 
-#ifndef OPENSSL_NO_QUIC
-    /* set the parent (user visible) ssl to self */
-    s->user_ssl = ssl;
-#endif
-
     RECORD_LAYER_init(&s->rlayer, s);
 
     s->options = ctx->options;
+
     s->dane.flags = ctx->dane.flags;
-    s->min_proto_version = ctx->min_proto_version;
-    s->max_proto_version = ctx->max_proto_version;
+    if (method->version == ctx->method->version) {
+        s->min_proto_version = ctx->min_proto_version;
+        s->max_proto_version = ctx->max_proto_version;
+    }
+
     s->mode = ctx->mode;
     s->max_cert_list = ctx->max_cert_list;
     s->max_early_data = ctx->max_early_data;
     s->recv_max_early_data = ctx->recv_max_early_data;
+
     s->num_tickets = ctx->num_tickets;
     s->pha_enabled = ctx->pha_enabled;
 
     /* 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
@@ -781,16 +786,16 @@ SSL *ossl_ssl_connection_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;
@@ -800,11 +805,13 @@ SSL *ossl_ssl_connection_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;
+    s->quiet_shutdown = IS_QUIC_CTX(ctx) ? 0 : ctx->quiet_shutdown;
+
+    if (!IS_QUIC_CTX(ctx))
+        s->ext.max_fragment_len_mode = ctx->ext.max_fragment_len_mode;
 
-    s->ext.max_fragment_len_mode = ctx->ext.max_fragment_len_mode;
     s->max_send_fragment = ctx->max_send_fragment;
     s->split_send_fragment = ctx->split_send_fragment;
     s->max_pipelines = ctx->max_pipelines;
@@ -866,16 +873,18 @@ SSL *ossl_ssl_connection_new(SSL_CTX *ctx)
 
     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 (!IS_QUIC_CTX(ctx)) {
+        s->allow_early_data_cb = ctx->allow_early_data_cb;
+        s->allow_early_data_cb_data = ctx->allow_early_data_cb_data;
+    }
 
-    if (!ssl->method->ssl_init(ssl))
-        goto err;
+    if (!method->ssl_init(ssl))
+        goto sslerr;
 
-    s->server = (ctx->method->ssl_accept == ssl_undefined_function) ? 0 : 1;
+    s->server = (method->ssl_accept == ssl_undefined_function) ? 0 : 1;
 
-    if (!SSL_clear(ssl))
-        goto err;
+    if (!method->ssl_reset(ssl))
+        goto sslerr;
 
 #ifndef OPENSSL_NO_PSK
     s->psk_client_callback = ctx->psk_client_callback;
@@ -889,34 +898,94 @@ SSL *ossl_ssl_connection_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
+    if (ctx->client_cert_type != NULL) {
+        s->client_cert_type = OPENSSL_memdup(ctx->client_cert_type,
+                                             ctx->client_cert_type_len);
+        if (s->client_cert_type == NULL)
+            goto sslerr;
+        s->client_cert_type_len = ctx->client_cert_type_len;
+    }
+    if (ctx->server_cert_type != NULL) {
+        s->server_cert_type = OPENSSL_memdup(ctx->server_cert_type,
+                                             ctx->server_cert_type_len);
+        if (s->server_cert_type == NULL)
+            goto sslerr;
+        s->server_cert_type_len = ctx->server_cert_type_len;
+    }
+
 #ifndef OPENSSL_NO_CT
     if (!SSL_set_ct_validation_callback(ssl, ctx->ct_validation_callback,
                                         ctx->ct_validation_callback_arg))
-        goto err;
+        goto sslerr;
 #endif
 
+    s->ssl_pkey_num = SSL_PKEY_NUM + ctx->sigalg_list_len;
     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(ssl);
-    ERR_raise(ERR_LIB_SSL, ERR_R_MALLOC_FAILURE);
     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)
 {
     SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
 
+#ifndef OPENSSL_NO_QUIC
+    if (s->type == SSL_TYPE_QUIC_CONNECTION || s->type == SSL_TYPE_QUIC_XSO)
+        return 0;
+#endif
+
     if (sc == NULL)
         return 0;
 
     return SSL_CONNECTION_IS_DTLS(sc) ? 1 : 0;
 }
 
+int SSL_is_tls(const SSL *s)
+{
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+
+#ifndef OPENSSL_NO_QUIC
+    if (s->type == SSL_TYPE_QUIC_CONNECTION || s->type == SSL_TYPE_QUIC_XSO)
+        return 0;
+#endif
+
+    if (sc == NULL)
+        return 0;
+
+    return SSL_CONNECTION_IS_DTLS(sc) ? 0 : 1;
+}
+
+int SSL_is_quic(const SSL *s)
+{
+#ifndef OPENSSL_NO_QUIC
+    if (s->type == SSL_TYPE_QUIC_CONNECTION || s->type == SSL_TYPE_QUIC_XSO)
+        return 1;
+#endif
+    return 0;
+}
+
 int SSL_up_ref(SSL *s)
 {
     int i;
 
-    if (CRYPTO_UP_REF(&s->references, &i, s->lock) <= 0)
+    if (CRYPTO_UP_REF(&s->references, &i) <= 0)
         return 0;
 
     REF_PRINT_COUNT("SSL", s);
@@ -1143,7 +1212,7 @@ 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 (sc->ext.hostname == NULL) {
@@ -1165,7 +1234,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;
@@ -1321,7 +1390,7 @@ void SSL_free(SSL *s)
 
     if (s == NULL)
         return;
-    CRYPTO_DOWN_REF(&s->references, &i, s->lock);
+    CRYPTO_DOWN_REF(&s->references, &i);
     REF_PRINT_COUNT("SSL", s);
     if (i > 0)
         return;
@@ -1334,6 +1403,7 @@ void SSL_free(SSL *s)
 
     SSL_CTX_free(s->ctx);
     CRYPTO_THREAD_lock_free(s->lock);
+    CRYPTO_FREE_REF(&s->references);
 
     OPENSSL_free(s);
 }
@@ -1349,15 +1419,10 @@ void ossl_ssl_connection_free(SSL *ssl)
     X509_VERIFY_PARAM_free(s->param);
     dane_final(&s->dane);
 
-    RECORD_LAYER_clear(&s->rlayer);
-
     /* 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);
 
@@ -1375,8 +1440,6 @@ void ossl_ssl_connection_free(SSL *ssl)
     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 */
@@ -1407,6 +1470,9 @@ void ossl_ssl_connection_free(SSL *ssl)
     sk_X509_NAME_pop_free(s->ca_names, X509_NAME_free);
     sk_X509_NAME_pop_free(s->client_ca_names, X509_NAME_free);
 
+    OPENSSL_free(s->client_cert_type);
+    OPENSSL_free(s->server_cert_type);
+
     OSSL_STACK_OF_X509_free(s->verified_chain);
 
     if (ssl->method != NULL)
@@ -1421,12 +1487,31 @@ void ossl_ssl_connection_free(SSL *ssl)
 #ifndef OPENSSL_NO_SRTP
     sk_SRTP_PROTECTION_PROFILE_free(s->srtp_profiles);
 #endif
+
+    /*
+     * 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;
+    OPENSSL_free(s->s3.tmp.valid_flags);
 }
 
 void SSL_set0_rbio(SSL *s, BIO *rbio)
 {
     SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
 
+#ifndef OPENSSL_NO_QUIC
+    if (IS_QUIC(s)) {
+        ossl_quic_conn_set0_net_rbio(s, rbio);
+        return;
+    }
+#endif
+
     if (sc == NULL)
         return;
 
@@ -1439,6 +1524,13 @@ void SSL_set0_wbio(SSL *s, BIO *wbio)
 {
     SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
 
+#ifndef OPENSSL_NO_QUIC
+    if (IS_QUIC(s)) {
+        ossl_quic_conn_set0_net_wbio(s, wbio);
+        return;
+    }
+#endif
+
     if (sc == NULL)
         return;
 
@@ -1454,6 +1546,8 @@ void SSL_set0_wbio(SSL *s, BIO *wbio)
     /* Re-attach |bbio| to the new |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)
@@ -1500,6 +1594,11 @@ BIO *SSL_get_rbio(const SSL *s)
 {
     const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_CONST_SSL(s);
 
+#ifndef OPENSSL_NO_QUIC
+    if (IS_QUIC(s))
+        return ossl_quic_conn_get_net_rbio(s);
+#endif
+
     if (sc == NULL)
         return NULL;
 
@@ -1510,6 +1609,11 @@ BIO *SSL_get_wbio(const SSL *s)
 {
     const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_CONST_SSL(s);
 
+#ifndef OPENSSL_NO_QUIC
+    if (IS_QUIC(s))
+        return ossl_quic_conn_get_net_wbio(s);
+#endif
+
     if (sc == NULL)
         return NULL;
 
@@ -1553,12 +1657,27 @@ int SSL_get_wfd(const SSL *s)
 }
 
 #ifndef OPENSSL_NO_SOCK
+static const BIO_METHOD *fd_method(SSL *s)
+{
+#ifndef OPENSSL_NO_DGRAM
+    if (IS_QUIC(s))
+        return BIO_s_datagram();
+#endif
+
+    return BIO_s_socket();
+}
+
 int SSL_set_fd(SSL *s, int fd)
 {
     int ret = 0;
     BIO *bio = NULL;
 
-    bio = BIO_new(BIO_s_socket());
+    if (s->type == SSL_TYPE_QUIC_XSO) {
+        ERR_raise(ERR_LIB_SSL, SSL_R_CONN_USE_ONLY);
+        goto err;
+    }
+
+    bio = BIO_new(fd_method(s));
 
     if (bio == NULL) {
         ERR_raise(ERR_LIB_SSL, ERR_R_BUF_LIB);
@@ -1583,10 +1702,16 @@ int SSL_set_fd(SSL *s, int fd)
 int SSL_set_wfd(SSL *s, int fd)
 {
     BIO *rbio = SSL_get_rbio(s);
+    int desired_type = IS_QUIC(s) ? BIO_TYPE_DGRAM : BIO_TYPE_SOCKET;
+
+    if (s->type == SSL_TYPE_QUIC_XSO) {
+        ERR_raise(ERR_LIB_SSL, SSL_R_CONN_USE_ONLY);
+        return 0;
+    }
 
-    if (rbio == NULL || BIO_method_type(rbio) != BIO_TYPE_SOCKET
+    if (rbio == NULL || BIO_method_type(rbio) != desired_type
         || (int)BIO_get_fd(rbio, NULL) != fd) {
-        BIO *bio = BIO_new(BIO_s_socket());
+        BIO *bio = BIO_new(fd_method(s));
 
         if (bio == NULL) {
             ERR_raise(ERR_LIB_SSL, ERR_R_BUF_LIB);
@@ -1613,10 +1738,16 @@ int SSL_set_wfd(SSL *s, int fd)
 int SSL_set_rfd(SSL *s, int fd)
 {
     BIO *wbio = SSL_get_wbio(s);
+    int desired_type = IS_QUIC(s) ? BIO_TYPE_DGRAM : BIO_TYPE_SOCKET;
 
-    if (wbio == NULL || BIO_method_type(wbio) != BIO_TYPE_SOCKET
+    if (s->type == SSL_TYPE_QUIC_XSO) {
+        ERR_raise(ERR_LIB_SSL, SSL_R_CONN_USE_ONLY);
+        return 0;
+    }
+
+    if (wbio == NULL || BIO_method_type(wbio) != desired_type
         || ((int)BIO_get_fd(wbio, NULL) != fd)) {
-        BIO *bio = BIO_new(BIO_s_socket());
+        BIO *bio = BIO_new(fd_method(s));
 
         if (bio == NULL) {
             ERR_raise(ERR_LIB_SSL, ERR_R_BUF_LIB);
@@ -1733,7 +1864,7 @@ void SSL_set_verify_depth(SSL *s, int depth)
 
 void SSL_set_read_ahead(SSL *s, int yes)
 {
-    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL_ONLY(s);
     OSSL_PARAM options[2], *opts = options;
 
     if (sc == NULL)
@@ -1751,7 +1882,7 @@ void SSL_set_read_ahead(SSL *s, int yes)
 
 int SSL_get_read_ahead(const SSL *s)
 {
-    const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_CONST_SSL(s);
+    const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_CONST_SSL_ONLY(s);
 
     if (sc == NULL)
         return 0;
@@ -1786,7 +1917,14 @@ int SSL_has_pending(const SSL *s)
      * That data may not result in any application data, or we may fail to parse
      * the records for some reason.
      */
-    const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_CONST_SSL(s);
+    const SSL_CONNECTION *sc;
+
+#ifndef OPENSSL_NO_QUIC
+    if (IS_QUIC(s))
+        return ossl_quic_has_pending(s);
+#endif
+
+    sc = SSL_CONNECTION_FROM_CONST_SSL(s);
 
     /* Check buffered app data if any first */
     if (SSL_CONNECTION_IS_DTLS(sc)) {
@@ -1858,7 +1996,7 @@ 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? */
+    /* TODO(QUIC FUTURE): Not allowed for QUIC currently. */
     SSL_CONNECTION *tsc = SSL_CONNECTION_FROM_SSL_ONLY(t);
     const SSL_CONNECTION *fsc = SSL_CONNECTION_FROM_CONST_SSL_ONLY(f);
 
@@ -1880,7 +2018,7 @@ int SSL_copy_session_id(SSL *t, const SSL *f)
             return 0;
     }
 
-    CRYPTO_UP_REF(&fsc->cert->references, &i, fsc->cert->lock);
+    CRYPTO_UP_REF(&fsc->cert->references, &i);
     ssl_cert_free(tsc->cert);
     tsc->cert = fsc->cert;
     if (!SSL_set_session_id_context(t, fsc->sid_ctx, (int)fsc->sid_ctx_length)) {
@@ -2019,6 +2157,11 @@ int SSL_accept(SSL *s)
 {
     SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
 
+#ifndef OPENSSL_NO_QUIC
+    if (IS_QUIC(s))
+        return s->method->ssl_accept(s);
+#endif
+
     if (sc == NULL)
         return 0;
 
@@ -2034,6 +2177,11 @@ int SSL_connect(SSL *s)
 {
     SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
 
+#ifndef OPENSSL_NO_QUIC
+    if (IS_QUIC(s))
+        return s->method->ssl_connect(s);
+#endif
+
     if (sc == NULL)
         return 0;
 
@@ -2134,6 +2282,11 @@ int ssl_read_internal(SSL *s, void *buf, size_t num, size_t *readbytes)
 {
     SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
 
+#ifndef OPENSSL_NO_QUIC
+    if (IS_QUIC(s))
+        return s->method->ssl_read(s, buf, num, readbytes);
+#endif
+
     if (sc == NULL)
         return -1;
 
@@ -2212,11 +2365,8 @@ 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);
 
-    /* TODO(QUIC): This will need special handling for QUIC */
-    if (sc == NULL)
-        return 0;
-
-    if (!sc->server) {
+    /* TODO(QUIC 0RTT): 0-RTT support */
+    if (sc == NULL || !sc->server) {
         ERR_raise(ERR_LIB_SSL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
         return SSL_READ_EARLY_DATA_ERROR;
     }
@@ -2270,7 +2420,7 @@ int SSL_get_early_data_status(const SSL *s)
 {
     const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_CONST_SSL_ONLY(s);
 
-    /* TODO(QUIC): This will need special handling for QUIC */
+    /* TODO(QUIC 0RTT): 0-RTT support */
     if (sc == NULL)
         return 0;
 
@@ -2281,6 +2431,11 @@ static int ssl_peek_internal(SSL *s, void *buf, size_t num, size_t *readbytes)
 {
     SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
 
+#ifndef OPENSSL_NO_QUIC
+    if (IS_QUIC(s))
+        return s->method->ssl_peek(s, buf, num, readbytes);
+#endif
+
     if (sc == NULL)
         return 0;
 
@@ -2346,6 +2501,11 @@ int ssl_write_internal(SSL *s, const void *buf, size_t num, size_t *written)
 {
     SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
 
+#ifndef OPENSSL_NO_QUIC
+    if (IS_QUIC(s))
+        return s->method->ssl_write(s, buf, num, written);
+#endif
+
     if (sc == NULL)
         return 0;
 
@@ -2412,7 +2572,7 @@ ossl_ssize_t SSL_sendfile(SSL *s, int fd, off_t offset, size_t size, int flags)
     }
 
     /* If we have an alert to send, lets send it */
-    if (sc->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 */
@@ -2493,7 +2653,7 @@ int SSL_write_early_data(SSL *s, const void *buf, size_t num, size_t *written)
     uint32_t partialwrite;
     SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL_ONLY(s);
 
-    /* TODO(QUIC): This will need special handling for QUIC */
+    /* TODO(QUIC 0RTT): This will need special handling for QUIC */
     if (sc == NULL)
         return 0;
 
@@ -2572,6 +2732,11 @@ int SSL_shutdown(SSL *s)
      */
     SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
 
+#ifndef OPENSSL_NO_QUIC
+    if (IS_QUIC(s))
+        return ossl_quic_conn_shutdown(s, 0, NULL, 0);
+#endif
+
     if (sc == NULL)
         return -1;
 
@@ -2603,6 +2768,11 @@ int SSL_key_update(SSL *s, int updatetype)
 {
     SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
 
+#ifndef OPENSSL_NO_QUIC
+    if (IS_QUIC(s))
+        return ossl_quic_key_update(s, updatetype);
+#endif
+
     if (sc == NULL)
         return 0;
 
@@ -2636,6 +2806,11 @@ int SSL_get_key_update_type(const SSL *s)
 {
     const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_CONST_SSL(s);
 
+#ifndef OPENSSL_NO_QUIC
+    if (IS_QUIC(s))
+        return ossl_quic_get_key_update_type(s);
+#endif
+
     if (sc == NULL)
         return 0;
 
@@ -2724,13 +2899,32 @@ int SSL_new_session_ticket(SSL *s)
 }
 
 long SSL_ctrl(SSL *s, int cmd, long larg, void *parg)
+{
+    return ossl_ctrl_internal(s, cmd, larg, parg, /*no_quic=*/0);
+}
+
+long ossl_ctrl_internal(SSL *s, int cmd, long larg, void *parg, int no_quic)
 {
     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;
+    /*
+     * Routing of ctrl calls for QUIC is a little counterintuitive:
+     *
+     *   - Firstly (no_quic=0), we pass the ctrl directly to our QUIC
+     *     implementation in case it wants to handle the ctrl specially.
+     *
+     *   - If our QUIC implementation does not care about the ctrl, it
+     *     will reenter this function with no_quic=1 and we will try to handle
+     *     it directly using the QCSO SSL object stub (not the handshake layer
+     *     SSL object). This is important for e.g. the version configuration
+     *     ctrls below, which must use s->defltmeth (and not sc->defltmeth).
+     *
+     *   - If we don't handle a ctrl here specially, then processing is
+     *     redirected to the handshake layer SSL object.
+     */
+    if (!no_quic && IS_QUIC(s))
+        return s->method->ssl_ctrl(s, cmd, larg, parg);
 
     switch (cmd) {
     case SSL_CTRL_GET_READ_AHEAD:
@@ -2740,10 +2934,6 @@ long SSL_ctrl(SSL *s, int cmd, long larg, void *parg)
         RECORD_LAYER_set_read_ahead(&sc->rlayer, larg);
         return l;
 
-    case SSL_CTRL_SET_MSG_CALLBACK_ARG:
-        sc->msg_callback_arg = parg;
-        return 1;
-
     case SSL_CTRL_MODE:
     {
         OSSL_PARAM options[2], *opts = options;
@@ -2779,6 +2969,7 @@ long SSL_ctrl(SSL *s, int cmd, long larg, void *parg)
         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 > sc->max_send_fragment || larg == 0)
@@ -2820,39 +3011,27 @@ long SSL_ctrl(SSL *s, int cmd, long larg, void *parg)
             return 0;
     case SSL_CTRL_SET_MIN_PROTO_VERSION:
         return ssl_check_allowed_versions(larg, sc->max_proto_version)
-               && ssl_set_version_bound(s->ctx->method->version, (int)larg,
+               && ssl_set_version_bound(s->defltmeth->version, (int)larg,
                                         &sc->min_proto_version);
     case SSL_CTRL_GET_MIN_PROTO_VERSION:
         return sc->min_proto_version;
     case SSL_CTRL_SET_MAX_PROTO_VERSION:
         return ssl_check_allowed_versions(sc->min_proto_version, larg)
-               && ssl_set_version_bound(s->ctx->method->version, (int)larg,
+               && ssl_set_version_bound(s->defltmeth->version, (int)larg,
                                         &sc->max_proto_version);
     case SSL_CTRL_GET_MAX_PROTO_VERSION:
         return sc->max_proto_version;
     default:
-        return s->method->ssl_ctrl(s, cmd, larg, parg);
+        if (IS_QUIC(s))
+            return SSL_ctrl((SSL *)sc, cmd, larg, parg);
+        else
+            return s->method->ssl_ctrl(s, cmd, larg, 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:
-        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:
-        return s->method->ssl_callback_ctrl(s, cmd, fp);
-    }
+    return s->method->ssl_callback_ctrl(s, cmd, fp);
 }
 
 LHASH_OF(SSL_SESSION) *SSL_CTX_sessions(SSL_CTX *ctx)
@@ -3218,14 +3397,14 @@ char *SSL_get_shared_ciphers(const SSL *s, char *buf, int size)
         if (sk_SSL_CIPHER_find(srvrsk, c) < 0)
             continue;
 
-        n = strlen(c->name);
-        if (n + 1 > size) {
+        n = OPENSSL_strnlen(c->name, size);
+        if (n >= size) {
             if (p != buf)
                 --p;
             *p = '\0';
             return buf;
         }
-        strcpy(p, c->name);
+        memcpy(p, c->name, n);
         p += n;
         *(p++) = ':';
         size -= n + 1;
@@ -3426,6 +3605,10 @@ void SSL_CTX_set_npn_advertised_cb(SSL_CTX *ctx,
                                    SSL_CTX_npn_advertised_cb_func cb,
                                    void *arg)
 {
+    if (IS_QUIC_CTX(ctx))
+        /* NPN not allowed for QUIC */
+        return;
+
     ctx->ext.npn_advertised_cb = cb;
     ctx->ext.npn_advertised_cb_arg = arg;
 }
@@ -3444,6 +3627,10 @@ void SSL_CTX_set_npn_select_cb(SSL_CTX *ctx,
                                SSL_CTX_npn_select_cb_func cb,
                                void *arg)
 {
+    if (IS_QUIC_CTX(ctx))
+        /* NPN not allowed for QUIC */
+        return;
+
     ctx->ext.npn_select_cb = cb;
     ctx->ext.npn_select_cb_arg = arg;
 }
@@ -3483,10 +3670,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;
@@ -3519,10 +3704,8 @@ 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(sc->ext.alpn);
     sc->ext.alpn = alpn;
     sc->ext.alpn_len = protos_len;
@@ -3651,6 +3834,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);
@@ -3660,27 +3846,32 @@ SSL_CTX *SSL_CTX_new_ex(OSSL_LIB_CTX *libctx, const char *propq,
     if (!OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL))
         return NULL;
 
+    /* Doing this for the run once effect */
     if (SSL_get_ex_data_X509_STORE_CTX_idx() < 0) {
         ERR_raise(ERR_LIB_SSL, SSL_R_X509_VERIFICATION_SETUP_PROBLEMS);
         goto err;
     }
+
     ret = OPENSSL_zalloc(sizeof(*ret));
     if (ret == NULL)
-        goto err;
+        return NULL;
 
     /* Init the reference counting before any call to SSL_CTX_free */
-    ret->references = 1;
-    ret->lock = CRYPTO_THREAD_lock_new();
-    if (ret->lock == NULL) {
-        ERR_raise(ERR_LIB_SSL, ERR_R_MALLOC_FAILURE);
+    if (!CRYPTO_NEW_REF(&ret->references, 1)) {
         OPENSSL_free(ret);
         return NULL;
     }
 
+    ret->lock = CRYPTO_THREAD_lock_new();
+    if (ret->lock == 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_MALLOC_FAILURE);
+        ERR_raise(ERR_LIB_SSL, ERR_R_CRYPTO_LIB);
         goto err;
     }
 #endif
@@ -3702,34 +3893,57 @@ 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)
-        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;
-    /* initialise sig algs */
-    if (!ssl_setup_sig_algs(ret))
-        goto err2;
+    if (!ssl_load_ciphers(ret)) {
+        ERR_raise(ERR_LIB_SSL, ERR_R_SSL_LIB);
+        goto err;
+    }
 
+    if (!ssl_load_groups(ret)) {
+        ERR_raise(ERR_LIB_SSL, ERR_R_SSL_LIB);
+        goto err;
+    }
+
+    /* load provider sigalgs */
+    if (!ssl_load_sigalgs(ret)) {
+        ERR_raise(ERR_LIB_SSL, ERR_R_SSL_LIB);
+        goto err;
+    }
+
+    /* initialise sig algs */
+    if (!ssl_setup_sigalgs(ret)) {
+        ERR_raise(ERR_LIB_SSL, ERR_R_SSL_LIB);
+        goto err;
+    }
 
-    if (!ssl_load_groups(ret))
-        goto err2;
+    if (!SSL_CTX_set_ciphersuites(ret, OSSL_default_ciphersuites())) {
+        ERR_raise(ERR_LIB_SSL, ERR_R_SSL_LIB);
+        goto err;
+    }
 
-    if (!SSL_CTX_set_ciphersuites(ret, OSSL_default_ciphersuites()))
+    if ((ret->cert = ssl_cert_new(SSL_PKEY_NUM + ret->sigalg_list_len)) == NULL) {
+        ERR_raise(ERR_LIB_SSL, ERR_R_SSL_LIB);
         goto err;
+    }
 
     if (!ssl_create_cipher_list(ret,
                                 ret->tls13_ciphersuites,
@@ -3737,12 +3951,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.
@@ -3751,14 +3967,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;
@@ -3780,12 +4002,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
@@ -3804,6 +4030,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
@@ -3852,8 +4093,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;
 }
@@ -3867,7 +4106,7 @@ int SSL_CTX_up_ref(SSL_CTX *ctx)
 {
     int i;
 
-    if (CRYPTO_UP_REF(&ctx->references, &i, ctx->lock) <= 0)
+    if (CRYPTO_UP_REF(&ctx->references, &i) <= 0)
         return 0;
 
     REF_PRINT_COUNT("SSL_CTX", ctx);
@@ -3883,7 +4122,7 @@ void SSL_CTX_free(SSL_CTX *a)
     if (a == NULL)
         return;
 
-    CRYPTO_DOWN_REF(&a->references, &i, a->lock);
+    CRYPTO_DOWN_REF(&a->references, &i);
     REF_PRINT_COUNT("SSL_CTX", a);
     if (i > 0)
         return;
@@ -3947,10 +4186,28 @@ void SSL_CTX_free(SSL_CTX *a)
         OPENSSL_free(a->group_list[j].algorithm);
     }
     OPENSSL_free(a->group_list);
+    for (j = 0; j < a->sigalg_list_len; j++) {
+        OPENSSL_free(a->sigalg_list[j].name);
+        OPENSSL_free(a->sigalg_list[j].sigalg_name);
+        OPENSSL_free(a->sigalg_list[j].sigalg_oid);
+        OPENSSL_free(a->sigalg_list[j].sig_name);
+        OPENSSL_free(a->sigalg_list[j].sig_oid);
+        OPENSSL_free(a->sigalg_list[j].hash_name);
+        OPENSSL_free(a->sigalg_list[j].hash_oid);
+        OPENSSL_free(a->sigalg_list[j].keytype);
+        OPENSSL_free(a->sigalg_list[j].keytype_oid);
+    }
+    OPENSSL_free(a->sigalg_list);
+    OPENSSL_free(a->ssl_cert_info);
 
     OPENSSL_free(a->sigalg_lookup_cache);
+    OPENSSL_free(a->tls12_sigalgs);
+
+    OPENSSL_free(a->client_cert_type);
+    OPENSSL_free(a->server_cert_type);
 
     CRYPTO_THREAD_lock_free(a->lock);
+    CRYPTO_FREE_REF(&a->references);
 #ifdef TSAN_REQUIRES_LOCKING
     CRYPTO_THREAD_lock_free(a->tsan_lock);
 #endif
@@ -4117,6 +4374,24 @@ void ssl_set_masks(SSL_CONNECTION *s)
 
     mask_a |= SSL_aNULL;
 
+    /*
+     * You can do anything with an RPK key, since there's no cert to restrict it
+     * But we need to check for private keys
+     */
+    if (pvalid[SSL_PKEY_RSA] & CERT_PKEY_RPK) {
+        mask_a |= SSL_aRSA;
+        mask_k |= SSL_kRSA;
+    }
+    if (pvalid[SSL_PKEY_ECC] & CERT_PKEY_RPK)
+        mask_a |= SSL_aECDSA;
+    if (TLS1_get_version(&s->ssl) == TLS1_2_VERSION) {
+        if (pvalid[SSL_PKEY_RSA_PSS_SIGN] & CERT_PKEY_RPK)
+            mask_a |= SSL_aRSA;
+        if (pvalid[SSL_PKEY_ED25519] & CERT_PKEY_RPK
+                || pvalid[SSL_PKEY_ED448] & CERT_PKEY_RPK)
+            mask_a |= SSL_aECDSA;
+    }
+
     /*
      * An ECC certificate may be usable for ECDH and/or ECDSA cipher suites
      * depending on the key usage extension.
@@ -4274,9 +4549,10 @@ 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? */
+    /* Not allowed for QUIC */
     if (sc == NULL
-        || (s->type != SSL_TYPE_SSL_CONNECTION && s->method != meth))
+        || (s->type != SSL_TYPE_SSL_CONNECTION && s->method != meth)
+        || (s->type == SSL_TYPE_SSL_CONNECTION && IS_QUIC_METHOD(meth)))
         return 0;
 
     if (s->method != meth) {
@@ -4300,6 +4576,11 @@ int SSL_set_ssl_method(SSL *s, const SSL_METHOD *meth)
 }
 
 int SSL_get_error(const SSL *s, int i)
+{
+    return ossl_ssl_get_error(s, i, /*check_err=*/1);
+}
+
+int ossl_ssl_get_error(const SSL *s, int i, int check_err)
 {
     int reason;
     unsigned long l;
@@ -4309,7 +4590,14 @@ int SSL_get_error(const SSL *s, int i)
     if (i > 0)
         return SSL_ERROR_NONE;
 
-    /* TODO(QUIC): This will need more handling for QUIC_CONNECTIONs */
+#ifndef OPENSSL_NO_QUIC
+    if (IS_QUIC(s)) {
+        reason = ossl_quic_get_error(s, i);
+        if (reason != SSL_ERROR_NONE)
+            return reason;
+    }
+#endif
+
     if (sc == NULL)
         return SSL_ERROR_SSL;
 
@@ -4317,59 +4605,68 @@ int SSL_get_error(const SSL *s, int i)
      * Make things return SSL_ERROR_SYSCALL when doing SSL_do_handshake etc,
      * where we do encode the error
      */
-    if ((l = ERR_peek_error()) != 0) {
+    if (check_err && (l = ERR_peek_error()) != 0) {
         if (ERR_GET_LIB(l) == ERR_LIB_SYS)
             return SSL_ERROR_SYSCALL;
         else
             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 (!IS_QUIC(s))
+#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 = sc->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))
@@ -4405,9 +4702,10 @@ int SSL_do_handshake(SSL *s)
     int ret = 1;
     SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
 
-    /* TODO(QUIC): Special handling for QUIC will be needed */
-    if (sc == NULL)
-        return -1;
+#ifndef OPENSSL_NO_QUIC
+    if (IS_QUIC(s))
+        return ossl_quic_do_handshake(s);
+#endif
 
     if (sc->handshake_func == NULL) {
         ERR_raise(ERR_LIB_SSL, SSL_R_CONNECTION_TYPE_NOT_SET);
@@ -4435,32 +4733,40 @@ int SSL_do_handshake(SSL *s)
 
 void SSL_set_accept_state(SSL *s)
 {
-    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL_ONLY(s);
 
-    /* TODO(QUIC): Special handling for QUIC will be needed */
-    if (sc == NULL)
+#ifndef OPENSSL_NO_QUIC
+    if (IS_QUIC(s)) {
+        ossl_quic_set_accept_state(s);
         return;
+    }
+#endif
 
     sc->server = 1;
     sc->shutdown = 0;
     ossl_statem_clear(sc);
     sc->handshake_func = s->method->ssl_accept;
-    clear_ciphers(sc);
+    /* Ignore return value. Its a void public API function */
+    clear_record_layer(sc);
 }
 
 void SSL_set_connect_state(SSL *s)
 {
-    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL_ONLY(s);
 
-    /* TODO(QUIC): Special handling for QUIC will be needed */
-    if (sc == NULL)
+#ifndef OPENSSL_NO_QUIC
+    if (IS_QUIC(s)) {
+        ossl_quic_set_connect_state(s);
         return;
+    }
+#endif
 
     sc->server = 0;
     sc->shutdown = 0;
     ossl_statem_clear(sc);
     sc->handshake_func = s->method->ssl_connect;
-    clear_ciphers(sc);
+    /* Ignore return value. Its a void public API function */
+    clear_record_layer(sc);
 }
 
 int ssl_undefined_function(SSL *s)
@@ -4523,13 +4829,33 @@ const char *SSL_get_version(const SSL *s)
 {
     const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_CONST_SSL(s);
 
-    /* TODO(QUIC): Should QUIC return QUIC or TLSv1.3? */
+#ifndef OPENSSL_NO_QUIC
+    /* We only support QUICv1 - so if its QUIC its QUICv1 */
+    if (s->type == SSL_TYPE_QUIC_CONNECTION || s->type == SSL_TYPE_QUIC_XSO)
+        return "QUICv1";
+#endif
+
     if (sc == NULL)
         return NULL;
 
     return ssl_protocol_to_string(sc->version);
 }
 
+__owur int SSL_get_handshake_rtt(const SSL *s, uint64_t *rtt)
+{
+    const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_CONST_SSL(s);
+
+    if (sc == NULL)
+        return -1;
+    if (sc->ts_msg_write.t <= 0 || sc->ts_msg_read.t <= 0)
+        return 0; /* data not (yet) available */
+    if (sc->ts_msg_read.t < sc->ts_msg_write.t)
+        return -1;
+
+    *rtt = ossl_time2us(ossl_time_subtract(sc->ts_msg_read, sc->ts_msg_write));
+    return 1;
+}
+
 static int dup_ca_names(STACK_OF(X509_NAME) **dst, STACK_OF(X509_NAME) *src)
 {
     STACK_OF(X509_NAME) *sk;
@@ -4564,7 +4890,7 @@ SSL *SSL_dup(SSL *s)
 {
     SSL *ret;
     int i;
-    /* TODO(QUIC): Add a SSL_METHOD function for duplication */
+    /* TODO(QUIC FUTURE): Add a SSL_METHOD function for duplication */
     SSL_CONNECTION *retsc;
     SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL_ONLY(s);
 
@@ -4573,7 +4899,7 @@ SSL *SSL_dup(SSL *s)
 
     /* If we're not quiescent, just up_ref! */
     if (!SSL_in_init(s) || !SSL_in_before(s)) {
-        CRYPTO_UP_REF(&s->references, &i, s->lock);
+        CRYPTO_UP_REF(&s->references, &i);
         return s;
     }
 
@@ -4672,24 +4998,6 @@ SSL *SSL_dup(SSL *s)
     return NULL;
 }
 
-void ssl_clear_cipher_ctx(SSL_CONNECTION *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)
 {
     SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
@@ -4762,7 +5070,7 @@ const COMP_METHOD *SSL_get_current_compression(const SSL *s)
     if (sc == NULL)
         return NULL;
 
-    return sc->compress ? COMP_CTX_get_method(sc->compress) : NULL;
+    return sc->rlayer.wrlmethod->get_compression(sc->rlayer.wrl);
 #else
     return NULL;
 #endif
@@ -4776,7 +5084,7 @@ const COMP_METHOD *SSL_get_current_expansion(const SSL *s)
     if (sc == NULL)
         return NULL;
 
-    return sc->expand ? COMP_CTX_get_method(sc->expand) : NULL;
+    return sc->rlayer.rrlmethod->get_compression(sc->rlayer.rrl);
 #else
     return NULL;
 #endif
@@ -4792,7 +5100,7 @@ int ssl_init_wbio_buffer(SSL_CONNECTION *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;
@@ -4800,6 +5108,8 @@ int ssl_init_wbio_buffer(SSL_CONNECTION *s)
     s->bbio = bbio;
     s->wbio = BIO_push(bbio, s->wbio);
 
+    s->rlayer.wrlmethod->set1_bio(s->rlayer.wrl, s->wbio);
+
     return 1;
 }
 
@@ -4810,6 +5120,8 @@ int ssl_free_wbio_buffer(SSL_CONNECTION *s)
         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;
 
@@ -4830,7 +5142,7 @@ void SSL_set_quiet_shutdown(SSL *s, int mode)
 {
     SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL_ONLY(s);
 
-    /* TODO(QUIC): Do we want this for QUIC? */
+    /* TODO(QUIC): Currently not supported for QUIC. */
     if (sc == NULL)
         return;
 
@@ -4841,7 +5153,7 @@ int SSL_get_quiet_shutdown(const SSL *s)
 {
     const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_CONST_SSL_ONLY(s);
 
-    /* TODO(QUIC): Do we want this for QUIC? */
+    /* TODO(QUIC): Currently not supported for QUIC. */
     if (sc == NULL)
         return 0;
 
@@ -4874,7 +5186,11 @@ int SSL_version(const SSL *s)
 {
     const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_CONST_SSL(s);
 
-    /* TODO(QUIC): Do we want to report QUIC version this way instead? */
+#ifndef OPENSSL_NO_QUIC
+    /* We only support QUICv1 - so if its QUIC its QUICv1 */
+    if (s->type == SSL_TYPE_QUIC_CONNECTION || s->type == SSL_TYPE_QUIC_XSO)
+        return OSSL_QUIC1_VERSION;
+#endif
     if (sc == NULL)
         return 0;
 
@@ -4885,7 +5201,11 @@ int SSL_client_version(const SSL *s)
 {
     const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_CONST_SSL(s);
 
-    /* TODO(QUIC): Do we want to report QUIC version this way instead? */
+#ifndef OPENSSL_NO_QUIC
+    /* We only support QUICv1 - so if its QUIC its QUICv1 */
+    if (s->type == SSL_TYPE_QUIC_CONNECTION || s->type == SSL_TYPE_QUIC_XSO)
+        return OSSL_QUIC1_VERSION;
+#endif
     if (sc == NULL)
         return 0;
 
@@ -4902,7 +5222,7 @@ 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? */
+    /* TODO(QUIC FUTURE): Add support for QUIC */
     if (sc == NULL)
         return NULL;
 
@@ -5181,6 +5501,11 @@ int SSL_want(const SSL *s)
 {
     const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_CONST_SSL(s);
 
+#ifndef OPENSSL_NO_QUIC
+    if (IS_QUIC(s))
+        return ossl_quic_want(s);
+#endif
+
     if (sc == NULL)
         return SSL_NOTHING;
 
@@ -5360,6 +5685,9 @@ void *SSL_CTX_get_record_padding_callback_arg(const SSL_CTX *ctx)
 
 int SSL_CTX_set_block_padding(SSL_CTX *ctx, size_t block_size)
 {
+    if (IS_QUIC_CTX(ctx) && block_size > 1)
+        return 0;
+
     /* block size of 0 or 1 is basically no padding */
     if (block_size == 1)
         ctx->block_padding = 0;
@@ -5375,14 +5703,14 @@ int SSL_set_record_padding_callback(SSL *ssl,
                                                    size_t len, void *arg))
 {
     BIO *b;
-    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(ssl);
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL_ONLY(ssl);
 
     if (sc == NULL)
         return 0;
 
     b = SSL_get_wbio(ssl);
     if (b == NULL || !BIO_get_ktls_send(b)) {
-        sc->record_padding_cb = cb;
+        sc->rlayer.record_padding_cb = cb;
         return 1;
     }
     return 0;
@@ -5395,7 +5723,7 @@ void SSL_set_record_padding_callback_arg(SSL *ssl, void *arg)
     if (sc == NULL)
         return;
 
-    sc->record_padding_arg = arg;
+    sc->rlayer.record_padding_arg = arg;
 }
 
 void *SSL_get_record_padding_callback_arg(const SSL *ssl)
@@ -5405,21 +5733,21 @@ void *SSL_get_record_padding_callback_arg(const SSL *ssl)
     if (sc == NULL)
         return NULL;
 
-    return sc->record_padding_arg;
+    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)
+    if (sc == NULL || (IS_QUIC(ssl) && block_size > 1))
         return 0;
 
     /* block size of 0 or 1 is basically no padding */
     if (block_size == 1)
-        sc->block_padding = 0;
+        sc->rlayer.block_padding = 0;
     else if (block_size <= SSL3_RT_MAX_PLAIN_LENGTH)
-        sc->block_padding = block_size;
+        sc->rlayer.block_padding = block_size;
     else
         return 0;
     return 1;
@@ -5459,32 +5787,6 @@ 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_CONNECTION *s,
                        unsigned char *out, size_t outlen,
@@ -5660,6 +5962,11 @@ uint64_t SSL_get_options(const SSL *s)
 {
     const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_CONST_SSL(s);
 
+#ifndef OPENSSL_NO_QUIC
+    if (IS_QUIC(s))
+        return ossl_quic_get_options(s);
+#endif
+
     if (sc == NULL)
         return 0;
 
@@ -5673,9 +5980,15 @@ uint64_t SSL_CTX_set_options(SSL_CTX *ctx, uint64_t op)
 
 uint64_t SSL_set_options(SSL *s, uint64_t op)
 {
-    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+    SSL_CONNECTION *sc;
     OSSL_PARAM options[2], *opts = options;
 
+#ifndef OPENSSL_NO_QUIC
+    if (IS_QUIC(s))
+        return ossl_quic_set_options(s, op);
+#endif
+
+    sc = SSL_CONNECTION_FROM_SSL(s);
     if (sc == NULL)
         return 0;
 
@@ -5700,6 +6013,11 @@ uint64_t SSL_clear_options(SSL *s, uint64_t op)
 {
     SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
 
+#ifndef OPENSSL_NO_QUIC
+    if (IS_QUIC(s))
+        return ossl_quic_clear_options(s, op);
+#endif
+
     if (sc == NULL)
         return 0;
 
@@ -5736,13 +6054,12 @@ 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;
         }
     }
 
-    while (sk_SCT_num(src) > 0) {
-        sct = sk_SCT_pop(src);
+    while ((sct = sk_SCT_pop(src)) != NULL) {
         if (SCT_set_source(sct, origin) != 1)
             goto err;
 
@@ -5880,13 +6197,13 @@ const STACK_OF(SCT) *SSL_get0_peer_scts(SSL *s)
     return NULL;
 }
 
-static int ct_permissive(const CT_POLICY_EVAL_CTX * ctx,
+static int ct_permissive(const CT_POLICY_EVAL_CTX *ctx,
                          const STACK_OF(SCT) *scts, void *unused_arg)
 {
     return 1;
 }
 
-static int ct_strict(const CT_POLICY_EVAL_CTX * ctx,
+static int ct_strict(const CT_POLICY_EVAL_CTX *ctx,
                      const STACK_OF(SCT) *scts, void *unused_arg)
 {
     int count = scts != NULL ? sk_SCT_num(scts) : 0;
@@ -6010,7 +6327,7 @@ int ssl_validate_ct(SSL_CONNECTION *s)
     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;
     }
 
@@ -6107,7 +6424,7 @@ int SSL_CTX_set_ctlog_list_file(SSL_CTX *ctx, const char *path)
     return CTLOG_STORE_load_file(ctx->ctlog_store, path);
 }
 
-void SSL_CTX_set0_ctlog_store(SSL_CTX *ctx, CTLOG_STORE * logs)
+void SSL_CTX_set0_ctlog_store(SSL_CTX *ctx, CTLOG_STORE *logs)
 {
     CTLOG_STORE_free(ctx->ctlog_store);
     ctx->ctlog_store = logs;
@@ -6229,10 +6546,8 @@ 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 < sc->clienthello->pre_proc_exts_len; i++) {
         ext = sc->clienthello->pre_proc_exts + i;
         if (ext->present) {
@@ -6315,28 +6630,33 @@ 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_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(ssl);
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL_ONLY(ssl);
 
     if (sc == NULL)
         return 0;
 
     rl = &sc->rlayer;
 
-    if (RECORD_LAYER_read_pending(rl) || RECORD_LAYER_write_pending(rl))
-        return 0;
-
-    RECORD_LAYER_release(rl);
-    return 1;
+    return rl->rrlmethod->free_buffers(rl->rrl)
+           && rl->wrlmethod->free_buffers(rl->wrl);
 }
 
 int SSL_alloc_buffers(SSL *ssl)
 {
+    RECORD_LAYER *rl;
     SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(ssl);
 
     if (sc == NULL)
         return 0;
 
-    return ssl3_setup_buffers(sc);
+    /* QUIC always has buffers allocated. */
+    if (IS_QUIC(ssl))
+        return 1;
+
+    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)
@@ -6376,10 +6696,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(sc, SSL_AD_INTERNAL_ERROR, ERR_R_MALLOC_FAILURE);
+    if ((out = cursor = OPENSSL_malloc(out_len)) == NULL)
         return 0;
-    }
 
     strcpy(cursor, prefix);
     cursor += prefix_len;
@@ -6474,7 +6792,7 @@ int ssl_cache_cipherlist(SSL_CONNECTION *s, PACKET *cipher_suites, int sslv2form
         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;
@@ -6553,9 +6871,9 @@ int ossl_bytes_to_cipher_list(SSL_CONNECTION *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;
     }
 
@@ -6574,9 +6892,9 @@ int ossl_bytes_to_cipher_list(SSL_CONNECTION *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;
             }
         }
@@ -6618,7 +6936,7 @@ 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)
 {
-    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL_ONLY(s);
 
     if (sc == NULL)
         return 0;
@@ -6652,7 +6970,7 @@ 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)
 {
-    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL_ONLY(s);
 
     if (sc == NULL)
         return 0;
@@ -6700,9 +7018,8 @@ __owur unsigned int ssl_get_split_send_fragment(const SSL_CONNECTION *sc)
 int SSL_stateless(SSL *s)
 {
     int ret;
-    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL_ONLY(s);
 
-    /* TODO(QUIC): This will need further work. */
     if (sc == NULL)
         return 0;
 
@@ -6732,7 +7049,7 @@ void SSL_CTX_set_post_handshake_auth(SSL_CTX *ctx, int val)
 
 void SSL_set_post_handshake_auth(SSL *ssl, int val)
 {
-    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(ssl);
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL_ONLY(ssl);
 
     if (sc == NULL)
         return;
@@ -6744,6 +7061,13 @@ int SSL_verify_client_post_handshake(SSL *ssl)
 {
     SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(ssl);
 
+#ifndef OPENSSL_NO_QUIC
+    if (IS_QUIC(ssl)) {
+        ERR_raise(ERR_LIB_SSL, SSL_R_WRONG_SSL_VERSION);
+        return 0;
+    }
+#endif
+
     if (sc == NULL)
         return 0;
 
@@ -6815,7 +7139,7 @@ void SSL_set_allow_early_data_cb(SSL *s,
                                  SSL_allow_early_data_cb_fn cb,
                                  void *arg)
 {
-    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL_ONLY(s);
 
     if (sc == NULL)
         return;
@@ -6944,3 +7268,520 @@ int SSL_CTX_set0_tmp_dh_pkey(SSL_CTX *ctx, EVP_PKEY *dhpkey)
     ctx->cert->dh_tmp = dhpkey;
     return 1;
 }
+
+/* QUIC-specific methods which are supported on QUIC connections only. */
+int SSL_handle_events(SSL *s)
+{
+    SSL_CONNECTION *sc;
+
+#ifndef OPENSSL_NO_QUIC
+    if (IS_QUIC(s))
+        return ossl_quic_handle_events(s);
+#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_event_timeout(SSL *s, struct timeval *tv, int *is_infinite)
+{
+    SSL_CONNECTION *sc;
+
+#ifndef OPENSSL_NO_QUIC
+    if (IS_QUIC(s))
+        return ossl_quic_get_event_timeout(s, tv, is_infinite);
+#endif
+
+    sc = SSL_CONNECTION_FROM_SSL_ONLY(s);
+    if (sc != NULL && SSL_CONNECTION_IS_DTLS(sc)
+        && DTLSv1_get_timeout(s, tv)) {
+        *is_infinite = 0;
+        return 1;
+    }
+
+    tv->tv_sec  = 1000000;
+    tv->tv_usec = 0;
+    *is_infinite = 1;
+    return 1;
+}
+
+int SSL_get_rpoll_descriptor(SSL *s, BIO_POLL_DESCRIPTOR *desc)
+{
+#ifndef OPENSSL_NO_QUIC
+    if (!IS_QUIC(s))
+        return -1;
+
+    return ossl_quic_get_rpoll_descriptor(s, desc);
+#else
+    return -1;
+#endif
+}
+
+int SSL_get_wpoll_descriptor(SSL *s, BIO_POLL_DESCRIPTOR *desc)
+{
+#ifndef OPENSSL_NO_QUIC
+    if (!IS_QUIC(s))
+        return -1;
+
+    return ossl_quic_get_wpoll_descriptor(s, desc);
+#else
+    return -1;
+#endif
+}
+
+int SSL_net_read_desired(SSL *s)
+{
+#ifndef OPENSSL_NO_QUIC
+    if (!IS_QUIC(s))
+        return 0;
+
+    return ossl_quic_get_net_read_desired(s);
+#else
+    return 0;
+#endif
+}
+
+int SSL_net_write_desired(SSL *s)
+{
+#ifndef OPENSSL_NO_QUIC
+    if (!IS_QUIC(s))
+        return 0;
+
+    return ossl_quic_get_net_write_desired(s);
+#else
+    return 0;
+#endif
+}
+
+int SSL_set_blocking_mode(SSL *s, int blocking)
+{
+#ifndef OPENSSL_NO_QUIC
+    if (!IS_QUIC(s))
+        return 0;
+
+    return ossl_quic_conn_set_blocking_mode(s, blocking);
+#else
+    return 0;
+#endif
+}
+
+int SSL_get_blocking_mode(SSL *s)
+{
+#ifndef OPENSSL_NO_QUIC
+    if (!IS_QUIC(s))
+        return -1;
+
+    return ossl_quic_conn_get_blocking_mode(s);
+#else
+    return -1;
+#endif
+}
+
+int SSL_set1_initial_peer_addr(SSL *s, const BIO_ADDR *peer_addr)
+{
+#ifndef OPENSSL_NO_QUIC
+    if (!IS_QUIC(s))
+        return 0;
+
+    return ossl_quic_conn_set_initial_peer_addr(s, 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
+    if (!IS_QUIC(ssl))
+        return SSL_shutdown(ssl);
+
+    return ossl_quic_conn_shutdown(ssl, flags, args, args_len);
+#else
+    return SSL_shutdown(ssl);
+#endif
+}
+
+int SSL_stream_conclude(SSL *ssl, uint64_t flags)
+{
+#ifndef OPENSSL_NO_QUIC
+    if (!IS_QUIC(ssl))
+        return 0;
+
+    return ossl_quic_conn_stream_conclude(ssl);
+#else
+    return 0;
+#endif
+}
+
+SSL *SSL_new_stream(SSL *s, uint64_t flags)
+{
+#ifndef OPENSSL_NO_QUIC
+    if (!IS_QUIC(s))
+        return NULL;
+
+    return ossl_quic_conn_stream_new(s, flags);
+#else
+    return NULL;
+#endif
+}
+
+SSL *SSL_get0_connection(SSL *s)
+{
+#ifndef OPENSSL_NO_QUIC
+    if (!IS_QUIC(s))
+        return s;
+
+    return ossl_quic_get0_connection(s);
+#else
+    return s;
+#endif
+}
+
+int SSL_is_connection(SSL *s)
+{
+    return SSL_get0_connection(s) == s;
+}
+
+int SSL_get_stream_type(SSL *s)
+{
+#ifndef OPENSSL_NO_QUIC
+    if (!IS_QUIC(s))
+        return SSL_STREAM_TYPE_BIDI;
+
+    return ossl_quic_get_stream_type(s);
+#else
+    return SSL_STREAM_TYPE_BIDI;
+#endif
+}
+
+uint64_t SSL_get_stream_id(SSL *s)
+{
+#ifndef OPENSSL_NO_QUIC
+    if (!IS_QUIC(s))
+        return UINT64_MAX;
+
+    return ossl_quic_get_stream_id(s);
+#else
+    return UINT64_MAX;
+#endif
+}
+
+int SSL_is_stream_local(SSL *s)
+{
+#ifndef OPENSSL_NO_QUIC
+    if (!IS_QUIC(s))
+        return -1;
+
+    return ossl_quic_is_stream_local(s);
+#else
+    return -1;
+#endif
+}
+
+int SSL_set_default_stream_mode(SSL *s, uint32_t mode)
+{
+#ifndef OPENSSL_NO_QUIC
+    if (!IS_QUIC(s))
+        return 0;
+
+    return ossl_quic_set_default_stream_mode(s, mode);
+#else
+    return 0;
+#endif
+}
+
+int SSL_set_incoming_stream_policy(SSL *s, int policy, uint64_t aec)
+{
+#ifndef OPENSSL_NO_QUIC
+    if (!IS_QUIC(s))
+        return 0;
+
+    return ossl_quic_set_incoming_stream_policy(s, policy, aec);
+#else
+    return 0;
+#endif
+}
+
+SSL *SSL_accept_stream(SSL *s, uint64_t flags)
+{
+#ifndef OPENSSL_NO_QUIC
+    if (!IS_QUIC(s))
+        return NULL;
+
+    return ossl_quic_accept_stream(s, flags);
+#else
+    return NULL;
+#endif
+}
+
+size_t SSL_get_accept_stream_queue_len(SSL *s)
+{
+#ifndef OPENSSL_NO_QUIC
+    if (!IS_QUIC(s))
+        return 0;
+
+    return ossl_quic_get_accept_stream_queue_len(s);
+#else
+    return 0;
+#endif
+}
+
+int SSL_stream_reset(SSL *s,
+                     const SSL_STREAM_RESET_ARGS *args,
+                     size_t args_len)
+{
+#ifndef OPENSSL_NO_QUIC
+    if (!IS_QUIC(s))
+        return 0;
+
+    return ossl_quic_stream_reset(s, args, args_len);
+#else
+    return 0;
+#endif
+}
+
+int SSL_get_stream_read_state(SSL *s)
+{
+#ifndef OPENSSL_NO_QUIC
+    if (!IS_QUIC(s))
+        return SSL_STREAM_STATE_NONE;
+
+    return ossl_quic_get_stream_read_state(s);
+#else
+    return SSL_STREAM_STATE_NONE;
+#endif
+}
+
+int SSL_get_stream_write_state(SSL *s)
+{
+#ifndef OPENSSL_NO_QUIC
+    if (!IS_QUIC(s))
+        return SSL_STREAM_STATE_NONE;
+
+    return ossl_quic_get_stream_write_state(s);
+#else
+    return SSL_STREAM_STATE_NONE;
+#endif
+}
+
+int SSL_get_stream_read_error_code(SSL *s, uint64_t *app_error_code)
+{
+#ifndef OPENSSL_NO_QUIC
+    if (!IS_QUIC(s))
+        return -1;
+
+    return ossl_quic_get_stream_read_error_code(s, app_error_code);
+#else
+    return -1;
+#endif
+}
+
+int SSL_get_stream_write_error_code(SSL *s, uint64_t *app_error_code)
+{
+#ifndef OPENSSL_NO_QUIC
+    if (!IS_QUIC(s))
+        return -1;
+
+    return ossl_quic_get_stream_write_error_code(s, app_error_code);
+#else
+    return -1;
+#endif
+}
+
+int SSL_get_conn_close_info(SSL *s, SSL_CONN_CLOSE_INFO *info,
+                            size_t info_len)
+{
+#ifndef OPENSSL_NO_QUIC
+    if (!IS_QUIC(s))
+        return -1;
+
+    return ossl_quic_get_conn_close_info(s, info, info_len);
+#else
+    return -1;
+#endif
+}
+
+int SSL_add_expected_rpk(SSL *s, EVP_PKEY *rpk)
+{
+    unsigned char *data = NULL;
+    SSL_DANE *dane = SSL_get0_dane(s);
+    int ret;
+
+    if (dane == NULL || dane->dctx == NULL)
+        return 0;
+    if ((ret = i2d_PUBKEY(rpk, &data)) <= 0)
+        return 0;
+
+    ret = SSL_dane_tlsa_add(s, DANETLS_USAGE_DANE_EE,
+                            DANETLS_SELECTOR_SPKI,
+                            DANETLS_MATCHING_FULL,
+                            data, (size_t)ret) > 0;
+    OPENSSL_free(data);
+    return ret;
+}
+
+EVP_PKEY *SSL_get0_peer_rpk(const SSL *s)
+{
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+
+    if (sc == NULL || sc->session == NULL)
+        return NULL;
+    return sc->session->peer_rpk;
+}
+
+int SSL_get_negotiated_client_cert_type(const SSL *s)
+{
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+
+    if (sc == NULL)
+        return 0;
+
+    return sc->ext.client_cert_type;
+}
+
+int SSL_get_negotiated_server_cert_type(const SSL *s)
+{
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+
+    if (sc == NULL)
+        return 0;
+
+    return sc->ext.server_cert_type;
+}
+
+static int validate_cert_type(const unsigned char *val, size_t len)
+{
+    size_t i;
+    int saw_rpk = 0;
+    int saw_x509 = 0;
+
+    if (val == NULL && len == 0)
+        return 1;
+
+    if (val == NULL || len == 0)
+        return 0;
+
+    for (i = 0; i < len; i++) {
+        switch (val[i]) {
+        case TLSEXT_cert_type_rpk:
+            if (saw_rpk)
+                return 0;
+            saw_rpk = 1;
+            break;
+        case TLSEXT_cert_type_x509:
+            if (saw_x509)
+                return 0;
+            saw_x509 = 1;
+            break;
+        case TLSEXT_cert_type_pgp:
+        case TLSEXT_cert_type_1609dot2:
+        default:
+            return 0;
+        }
+    }
+    return 1;
+}
+
+static int set_cert_type(unsigned char **cert_type,
+                         size_t *cert_type_len,
+                         const unsigned char *val,
+                         size_t len)
+{
+    unsigned char *tmp = NULL;
+
+    if (!validate_cert_type(val, len))
+        return 0;
+
+    if (val != NULL && (tmp = OPENSSL_memdup(val, len)) == NULL)
+        return 0;
+
+    OPENSSL_free(*cert_type);
+    *cert_type = tmp;
+    *cert_type_len = len;
+    return 1;
+}
+
+int SSL_set1_client_cert_type(SSL *s, const unsigned char *val, size_t len)
+{
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+
+    return set_cert_type(&sc->client_cert_type, &sc->client_cert_type_len,
+                         val, len);
+}
+
+int SSL_set1_server_cert_type(SSL *s, const unsigned char *val, size_t len)
+{
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+
+    return set_cert_type(&sc->server_cert_type, &sc->server_cert_type_len,
+                         val, len);
+}
+
+int SSL_CTX_set1_client_cert_type(SSL_CTX *ctx, const unsigned char *val, size_t len)
+{
+    return set_cert_type(&ctx->client_cert_type, &ctx->client_cert_type_len,
+                         val, len);
+}
+
+int SSL_CTX_set1_server_cert_type(SSL_CTX *ctx, const unsigned char *val, size_t len)
+{
+    return set_cert_type(&ctx->server_cert_type, &ctx->server_cert_type_len,
+                         val, len);
+}
+
+int SSL_get0_client_cert_type(const SSL *s, unsigned char **t, size_t *len)
+{
+    const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_CONST_SSL(s);
+
+    if (t == NULL || len == NULL)
+        return 0;
+
+    *t = sc->client_cert_type;
+    *len = sc->client_cert_type_len;
+    return 1;
+}
+
+int SSL_get0_server_cert_type(const SSL *s, unsigned char **t, size_t *len)
+{
+    const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_CONST_SSL(s);
+
+    if (t == NULL || len == NULL)
+        return 0;
+
+    *t = sc->server_cert_type;
+    *len = sc->server_cert_type_len;
+    return 1;
+}
+
+int SSL_CTX_get0_client_cert_type(const SSL_CTX *ctx, unsigned char **t, size_t *len)
+{
+    if (t == NULL || len == NULL)
+        return 0;
+
+    *t = ctx->client_cert_type;
+    *len = ctx->client_cert_type_len;
+    return 1;
+}
+
+int SSL_CTX_get0_server_cert_type(const SSL_CTX *ctx, unsigned char **t, size_t *len)
+{
+    if (t == NULL || len == NULL)
+        return 0;
+
+    *t = ctx->server_cert_type;
+    *len = ctx->server_cert_type_len;
+    return 1;
+}